release-publish
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.zipInstalls 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
mainorskiasharpbranches. This is a policy violation.
| Repository | Protected Branches | Required Action |
|---|---|---|
| SkiaSharp (parent) | main | Tags/releases created from release branches, never modify main directly |
| externals/skia (submodule) | main, skiasharp | Never 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:
| Step | Preview | Stable |
|---|---|---|
| 1. NuGet version | X.Y.Z-preview.N.{build} | X.Y.Z (no build number) |
| 2. Pipeline checkbox | "Push Preview" | "Push Stable" |
| 4. Tag format | vX.Y.Z-preview.N.{build} | vX.Y.Z |
| 5. GitHub Release | --prerelease flag | No flag, attach samples |
| 7. Milestone | Skip | Close 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 than3.119.2-preview.3— it's the stable/final release- Always verify you are publishing from the correct branch
- If both
release/3.119.2andrelease/3.119.2-preview.3exist, 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
- Open the NuGet.org publish pipeline
- Click "Run pipeline"
- Select "SkiaSharp" from the radio buttons
- Check "Confirm push to NuGet.org" checkbox
- For stable releases ONLY: Check "Push stable packages" checkbox
- ⚠️ Do NOT check this for preview releases
- Click "Next: Resources"
- In "Pipeline artifacts", click the SkiaSharp artifact selector
- From the branch dropdown, select
release/{version}(the release branch) - From the pipeline runs list, select the correct build by checking the build number
- Click "Use selected run"
- Click "Run"
Verification During Pipeline Run
⚠️ Before approving the push step, verify BOTH:
- Run name — The pipeline run will rename itself to the version being released. Confirm this matches your expected version.
- 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 Type | Title Format | Example |
|---|---|---|
| Preview | Version X.Y.Z (Preview N) | Version 3.119.2 (Preview 2) |
| Stable | Version X.Y.Z | Version 3.119.2 |
| Hotfix Preview | Version X.Y.Z.F (Preview N) | Version 3.119.2.1 (Preview 1) |
| Hotfix Stable | Version X.Y.Z.F | Version 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 Release | Previous Tag (--notes-start-tag) |
|---|---|
v3.119.2-preview.2.3 | v3.119.2-preview.1.2 (previous preview) |
v3.119.2-preview.1.1 | v3.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
--titlesets the release title (use format above)--generate-notesauto-generates release notes from PRs/commits--notes-start-tagspecifies the previous release to diff from (required)--prereleasemarks as prerelease (preview only)--verify-tagensures 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:
- Get release body:
gh release view {tag} --json body -q '.body' > /tmp/skiasharp/release/release-body.md - For each PR: determine platform emoji, add ❤️ for non-mattleibow contributors
- Build sections: Breaking Changes (if any), New Features (if any), What's Changed (all)
- 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 Point | Recovery |
|---|---|
| Pipeline won't start | Verify branch name, check Azure DevOps permissions |
| Build fails mid-run | Check logs, fix issue on release branch, re-run pipeline |
| Approval rejected | Re-trigger pipeline with correct settings |
| Push step fails | Check NuGet.org status, retry pipeline |
NuGet.org Issues
| Issue | Recovery |
|---|---|
| Indexing takes >15 min | Normal for large packages. Keep polling. |
| Package shows 404 after publish | Wait up to 30 min. NuGet CDN propagation delay. |
| Wrong version published | Cannot unpublish. Release new corrected version. |
Git/GitHub Issues
| Issue | Recovery |
|---|---|
| Tag push rejected | Check if tag exists: git ls-remote --tags origin | grep {tag} |
| Tag already exists | Cannot delete. Must use different tag or release new version. |
| GitHub release fails | Re-run gh release create with --verify-tag |
| Release notes wrong | Edit with gh release edit {tag} --notes-file ... |
General Recovery
If you've partially completed and need to resume:
- Check what's done:
gh release view {tag}(release exists?),git ls-remote --tags origin(tag exists?) - Skip completed steps
- Continue from where you left off
Resources
- releasing.md — Version patterns, tag formats, workflow diagrams
- references/release-notes.md — Emoji annotation details
More by mono
View all →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.
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.
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.
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.
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."
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.
Stay ahead of the MCP ecosystem
Get weekly updates on new skills and servers.