release-publish

4
0
Source

Publish SkiaSharp packages and finalize the release. Use when user says "publish X", "finalize X", "tag X", or "finish release X". This is the FINAL step - after release-testing passes. Publishes to NuGet.org, creates tag, GitHub release, and closes milestone. Triggers: "publish the release", "push to nuget", "create github release", "tag the release", "close the milestone", "annotate release notes", "testing passed what's next", "finalize 3.119.2", "release is ready".

Install

mkdir -p .claude/skills/release-publish && curl -L -o skill.zip "https://mcp.directory/api/skills/download/2987" && unzip -o skill.zip -d .claude/skills/release-publish && rm skill.zip

Installs to .claude/skills/release-publish

About this skill

Release Publish Skill

Publish packages to NuGet.org and finalize releases.

⚠️ NO UNDO: This is step 3 of 3. See releasing.md for full workflow.

⚠️ Branch Protection (COMPLIANCE REQUIRED)

🛑 NEVER commit directly to main or skiasharp branches. This is a policy violation.

RepositoryProtected BranchesRequired Action
SkiaSharp (parent)mainTags/releases created from release branches, never modify main directly
externals/skia (submodule)main, skiasharpNever modify directly

Publishing creates tags on existing release branches — it does NOT modify protected branches.


Workflow Overview

┌────────────────────────────────────────────────────────────────────┐
│  1. Confirm Versions     → Verify packages exist on preview feed   │
│  2. Publish to NuGet.org → Trigger Azure pipeline (manual)         │
│  3. Verify Published     → Poll NuGet.org until indexed            │
│  4. Tag Release          → Push git tag (ask_user first!)          │
│  5. Create GitHub Release→ Generate notes, set prerelease flag     │
│  6. Annotate Notes       → Add platform/contributor emojis         │
│  7. Close Milestone      → Stable releases only                    │
└────────────────────────────────────────────────────────────────────┘

Preview vs Stable differences:

StepPreviewStable
1. NuGet versionX.Y.Z-preview.N.{build}X.Y.Z (no build number)
2. Pipeline checkbox"Push Preview""Push Stable"
4. Tag formatvX.Y.Z-preview.N.{build}vX.Y.Z
5. GitHub Release--prerelease flagNo flag, attach samples
7. MilestoneSkipClose milestone

Step 1: Confirm Versions

⚠️ Semver Version Ordering

When identifying which version to publish, use semver ordering, not alphabetical:

  • 3.119.2 (bare) is NEWER than 3.119.2-preview.3 — it's the stable/final release
  • Always verify you are publishing from the correct branch
  • If both release/3.119.2 and release/3.119.2-preview.3 exist, the bare version is the latest

Prerequisite: release-testing must have passed. Versions should be known from testing.

The user should provide:

  • Preview: SkiaSharp version with build number (e.g., 3.119.2-preview.2.3)
  • Stable: SkiaSharp base version only (e.g., 3.119.2) — no build number

⚠️ Stable versions never include a build number. The build number only appears in the prerelease component (e.g., 3.119.2-preview.2.3) or in the internal stable tag (e.g., 3.119.2-stable.3). It is never appended to the base version directly.

If not provided, ask for them using ask_user.

Quick verification — confirm packages exist on preview feed:

# Preview: search for the exact NuGet version
dotnet package search SkiaSharp --source "https://aka.ms/skiasharp-eap/index.json" --exact-match --prerelease --format json | jq -r '.searchResult[].packages[].version' | grep "{expected-version}"

# Stable: search for internal stable builds (NuGet version is just the base, e.g., 3.119.2)
dotnet package search SkiaSharp --source "https://aka.ms/skiasharp-eap/index.json" --exact-match --prerelease --format json | jq -r '.searchResult[].packages[].version' | grep "^{base}-stable\."

If missing, STOP and ask user to verify testing was completed.


Step 2: Publish to NuGet.org

Trigger the publish pipeline to push packages to NuGet.org.

Pipeline Steps

  1. Open the NuGet.org publish pipeline
  2. Click "Run pipeline"
  3. Select "SkiaSharp" from the radio buttons
  4. Check "Confirm push to NuGet.org" checkbox
  5. For stable releases ONLY: Check "Push stable packages" checkbox
    • ⚠️ Do NOT check this for preview releases
  6. Click "Next: Resources"
  7. In "Pipeline artifacts", click the SkiaSharp artifact selector
  8. From the branch dropdown, select release/{version} (the release branch)
  9. From the pipeline runs list, select the correct build by checking the build number
  10. Click "Use selected run"
  11. Click "Run"

Verification During Pipeline Run

⚠️ Before approving the push step, verify BOTH:

  1. Run name — The pipeline run will rename itself to the version being released. Confirm this matches your expected version.
  2. Push type — The publish step will indicate "Push Preview" or "Push Stable". Verify this matches your release type:
    • Preview release → should show "Push Preview"
    • Stable release → should show "Push Stable"

Only approve the push step when both are correct. Wait for pipeline completion (typically 5-10 minutes after approval).

Ask user to follow these steps and wait for completion.


Step 3: Verify Packages Published

Use curl to verify (more reliable than dotnet package search which has version limits):

# Check if packages exist - HTTP 200 = success
curl -s -o /dev/null -w "%{http_code}" "https://api.nuget.org/v3-flatcontainer/skiasharp/{version}/skiasharp.nuspec"
curl -s -o /dev/null -w "%{http_code}" "https://api.nuget.org/v3-flatcontainer/harfbuzzsharp/{version}/harfbuzzsharp.nuspec"

If packages not yet indexed, poll until available (NuGet.org can take 5-15 minutes):

# Poll every 30 seconds, max 10 minutes
for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20; do
  skia=$(curl -s -o /dev/null -w "%{http_code}" "https://api.nuget.org/v3-flatcontainer/skiasharp/{version}/skiasharp.nuspec")
  hb=$(curl -s -o /dev/null -w "%{http_code}" "https://api.nuget.org/v3-flatcontainer/harfbuzzsharp/{version}/harfbuzzsharp.nuspec")
  echo "$(date +%H:%M:%S) - SkiaSharp: $skia, HarfBuzzSharp: $hb"
  if [ "$skia" = "200" ] && [ "$hb" = "200" ]; then
    echo "✅ Both packages available on NuGet.org!"
    break
  fi
  sleep 30
done

Note: Use explicit list 1 2 3... instead of {1..20} brace expansion for better compatibility with async shell execution.

Or manually check: https://www.nuget.org/packages/SkiaSharp/{version}


Step 4: Tag Release

Tag formats:

  • Preview: vX.Y.Z-preview.N.{build} (e.g., v3.119.2-preview.2.5)
  • Stable: vX.Y.Z (e.g., v3.119.2)
git fetch origin
git checkout release/{branch-version}
git pull
git tag {tag}

Confirm with ask_user before pushing tag (cannot be undone):

git push origin {tag}

Step 5: Create GitHub Release

Title Format

Release TypeTitle FormatExample
PreviewVersion X.Y.Z (Preview N)Version 3.119.2 (Preview 2)
StableVersion X.Y.ZVersion 3.119.2
Hotfix PreviewVersion X.Y.Z.F (Preview N)Version 3.119.2.1 (Preview 1)
Hotfix StableVersion X.Y.Z.FVersion 3.119.2.1

Finding the Previous Release Tag

Always use --notes-start-tag to explicitly specify the previous release. The auto-selection may pick the wrong tag.

# List recent tags to find the previous release
git tag -l "v3.119*" --sort=-v:refname | head -10
Current ReleasePrevious Tag (--notes-start-tag)
v3.119.2-preview.2.3v3.119.2-preview.1.2 (previous preview)
v3.119.2-preview.1.1v3.119.1 (last stable)
v3.119.2 (stable)v3.119.2-preview.N.X (last preview of this version)
v3.119.2.1-preview.1.1 (hotfix)v3.119.2 (stable being hotfixed)

Commands

# Preview (e.g., v3.119.2-preview.2.3)
gh release create {tag} \
  --title "Version {X.Y.Z} (Preview {N})" \
  --generate-notes \
  --notes-start-tag {previous-tag} \
  --prerelease \
  --verify-tag

# Stable (e.g., v3.119.2)
gh release create {tag} \
  --title "Version {X.Y.Z}" \
  --generate-notes \
  --notes-start-tag {previous-tag} \
  --verify-tag

# Upload samples for stable releases (if available)
gh release upload {tag} samples.zip
  • --title sets the release title (use format above)
  • --generate-notes auto-generates release notes from PRs/commits
  • --notes-start-tag specifies the previous release to diff from (required)
  • --prerelease marks as prerelease (preview only)
  • --verify-tag ensures the tag exists before creating the release

Step 6: Annotate Release Notes with Emojis

After creating the release, annotate each PR line with platform and community emojis.

👉 See references/release-notes.md for:

  • Complete emoji reference (platform + contributor)
  • Label-to-platform mapping
  • Title keyword detection
  • Full annotation process and examples

Quick summary:

  1. Get release body: gh release view {tag} --json body -q '.body' > /tmp/skiasharp/release/release-body.md
  2. For each PR: determine platform emoji, add ❤️ for non-mattleibow contributors
  3. Build sections: Breaking Changes (if any), New Features (if any), What's Changed (all)
  4. Update release: gh release edit {tag} --notes-file /tmp/skiasharp/release/release-body.md

Step 7: Close Milestone (Stable only)

Skip for preview releases.

gh api repos/:owner/:repo/milestones --jq '.[] | "\(.number): \(.title)"'
gh api repos/:owner/:repo/milestones/{number} -X PATCH -f state=closed

Error Recovery

Pipeline Fails

Failure PointRecovery
Pipeline won't startVerify branch name, check Azure DevOps permissions
Build fails mid-runCheck logs, fix issue on release branch, re-run pipeline
Approval rejectedRe-trigger pipeline with correct settings
Push step failsCheck NuGet.org status, retry pipeline

NuGet.org Issues

IssueRecovery
Indexing takes >15 minNormal for large packages. Keep polling.
Package shows 404 after publishWait up to 30 min. NuGet CDN propagation delay.
Wrong version publishedCannot unpublish. Release new corrected version.

Git/GitHub Issues

IssueRecovery
Tag push rejectedCheck if tag exists: git ls-remote --tags origin | grep {tag}
Tag already existsCannot delete. Must use different tag or release new version.
GitHub release failsRe-run gh release create with --verify-tag
Release notes wrongEdit with gh release edit {tag} --notes-file ...

General Recovery

If you've partially completed and need to resume:

  1. Check what's done: gh release view {tag} (release exists?), git ls-remote --tags origin (tag exists?)
  2. Skip completed steps
  3. Continue from where you left off

Resources

More by mono

View all →

release-testing

mono

Run integration tests to verify SkiaSharp NuGet packages work correctly before publishing. Use when user asks to: - Test/verify packages before release - Run integration tests - Test on specific device (iPad, iPhone, Android emulator, Mac, Windows) - Verify SkiaSharp rendering works - Check if packages are ready for publishing - Run smoke/console/blazor/maui tests - Continue with release - Test version X Triggers: "test the release", "verify packages", "run tests on iPad", "check ios tests", "test mac catalyst", "run android tests", "continue", "test 3.119.2-preview.2".

00

release-branch

mono

Create a release branch for SkiaSharp. Use when user says "release X", "start release X", "create release branch for X", "I want to release", or "release now". This is the FIRST step of releasing - creates branch and pushes to trigger CI. Can auto-detect next preview version from main branch.

10

bug-fix

mono

Fix bugs in SkiaSharp C# bindings. Structured workflow for investigating, fixing, and testing bug reports. Triggers: Crash, exception, AccessViolationException, incorrect output, wrong behavior, memory leak, disposal issues, "fails", "broken", "doesn't work", "investigate issue", "fix issue", "look at #NNNN", any GitHub issue number referencing a bug. For adding new APIs, use `add-api` skill instead.

200

api-docs

mono

Write and review XML API documentation for SkiaSharp following .NET guidelines. Triggers: "document class", "add XML docs", "write XML documentation", "add triple-slash comments", "review documentation quality", "check docs for errors", "fix doc issues", "fill in missing docs", "remove To be added placeholders", API documentation requests.

30

add-api

mono

Add new C# APIs to SkiaSharp by wrapping Skia C++ functionality. Structured 6-phase workflow: C++ analysis → C API creation → submodule commits → binding generation → C# wrapper → testing. Triggers: - Issue classified as "New API" (after fetching and classification) - Direct request: "add DrawFoo method", "expose SkSurface::draw", "wrap sk_foo_bar" - Keywords: "add API", "expose function", "wrap method", "create binding for"

50

You might also like

flutter-development

aj-geddes

Build beautiful cross-platform mobile apps with Flutter and Dart. Covers widgets, state management with Provider/BLoC, navigation, API integration, and material design.

239775

drawio-diagrams-enhanced

jgtolentino

Create professional draw.io (diagrams.net) diagrams in XML format (.drawio files) with integrated PMP/PMBOK methodologies, extensive visual asset libraries, and industry-standard professional templates. Use this skill when users ask to create flowcharts, swimlane diagrams, cross-functional flowcharts, org charts, network diagrams, UML diagrams, BPMN, project management diagrams (WBS, Gantt, PERT, RACI), risk matrices, stakeholder maps, or any other visual diagram in draw.io format. This skill includes access to custom shape libraries for icons, clipart, and professional symbols.

182404

godot

bfollington

This skill should be used when working on Godot Engine projects. It provides specialized knowledge of Godot's file formats (.gd, .tscn, .tres), architecture patterns (component-based, signal-driven, resource-based), common pitfalls, validation tools, code templates, and CLI workflows. The `godot` command is available for running the game, validating scripts, importing resources, and exporting builds. Use this skill for tasks involving Godot game development, debugging scene/resource files, implementing game systems, or creating new Godot components.

170268

nano-banana-pro

garg-aayush

Generate and edit images using Google's Nano Banana Pro (Gemini 3 Pro Image) API. Use when the user asks to generate, create, edit, modify, change, alter, or update images. Also use when user references an existing image file and asks to modify it in any way (e.g., "modify this image", "change the background", "replace X with Y"). Supports both text-to-image generation and image-to-image editing with configurable resolution (1K default, 2K, or 4K for high resolution). DO NOT read the image file first - use this skill directly with the --input-image parameter.

195225

ui-ux-pro-max

nextlevelbuilder

"UI/UX design intelligence. 50 styles, 21 palettes, 50 font pairings, 20 charts, 8 stacks (React, Next.js, Vue, Svelte, SwiftUI, React Native, Flutter, Tailwind). Actions: plan, build, create, design, implement, review, fix, improve, optimize, enhance, refactor, check UI/UX code. Projects: website, landing page, dashboard, admin panel, e-commerce, SaaS, portfolio, blog, mobile app, .html, .tsx, .vue, .svelte. Elements: button, modal, navbar, sidebar, card, table, form, chart. Styles: glassmorphism, claymorphism, minimalism, brutalism, neumorphism, bento grid, dark mode, responsive, skeuomorphism, flat design. Topics: color palette, accessibility, animation, layout, typography, font pairing, spacing, hover, shadow, gradient."

154189

rust-coding-skill

UtakataKyosui

Guides Claude in writing idiomatic, efficient, well-structured Rust code using proper data modeling, traits, impl organization, macros, and build-speed best practices.

157171

Stay ahead of the MCP ecosystem

Get weekly updates on new skills and servers.