release-testing

2
1
Source

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".

Install

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

Installs to .claude/skills/release-testing

About this skill

Release Testing Skill

Verify SkiaSharp packages work correctly before publishing.

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

CRITICAL: ANY FAIL IS TOTAL FAIL

  • Test fails → Release FAILS
  • Test times out → Release FAILS
  • Screenshot doesn't match → Release FAILS

Never rationalize failures. Fix the issue before proceeding.


⚠️ CRITICAL: Semver Version Ordering

When identifying which release branch to test, you MUST use semver ordering, NOT alphabetical or sort -V ordering.

In semver, a bare version is ALWAYS newer than its prerelease variants:

3.119.2-preview.1 < 3.119.2-preview.2 < 3.119.2-preview.3 < 3.119.2 (FINAL)

release/3.119.2 is the stable release and is NEWER than release/3.119.2-preview.3.

To find the latest release branch:

  1. List all release branches: git branch -r | grep "release/"
  2. Identify the highest base version (e.g., 3.119.2)
  3. Check if a bare version branch exists (e.g., release/3.119.2) — if so, that is the latest
  4. If only preview branches exist, the highest preview number is the latest

⚠️ Getting this wrong means testing the wrong version — wasting the entire process or shipping untested packages.


Step 1: Check CI Status

Before testing, verify CI builds have completed. Check commit statuses on the release branch head:

gh api "repos/mono/SkiaSharp/commits/{sha}/statuses" --jq '.[] | "\(.context) | \(.state) | \(.description // "no desc") | \(.created_at)"'

Required Pipelines

PipelineRequiredNotes
SkiaSharp-Native✅ Must passBuilds native binaries
SkiaSharp⚠️ May not exist publicallyBuilds managed code & publishes packages
SkiaSharp-Tests⚠️ May fail or not exist publicallySometimes flaky on release branches - warn user but don't block

Ignore: SkiaSharp (Public) — public CI, not used for releases.

Understanding Multiple Statuses

The API returns ALL statuses chronologically. A pipeline may have multiple entries due to retries/rebuilds. Always use the most recent status (newest timestamp) for each pipeline.

Extracting NuGet Version

The build description contains the internal version in format: #{base}-{label}.{build}+{branch}

Preview example: #3.119.2-preview.2.3+3.119.2-preview.2 succeeded

  • Internal version: 3.119.2-preview.2.3
  • NuGet version: 3.119.2-preview.2.3 (same — build number is part of the prerelease tag)

Stable example: #3.119.2-stable.3+3.119.2 succeeded

  • Internal version: 3.119.2-stable.3
  • NuGet version: 3.119.2 (base only — build number is NEVER appended to stable versions)

⚠️ Stable versions never include a build number. Each CI build of a stable release produces a different internal package (3.119.2-stable.1, 3.119.2-stable.2, etc.) but the published NuGet version is always just 3.119.2.


Step 2: Resolve Package Versions

DO NOT ask user for exact NuGet versions. Resolve automatically:

  1. Fetch release branch and read version files:

    # Read base versions (format: "PackageName  nuget  version")
    grep "^SkiaSharp\s" scripts/VERSIONS.txt | grep "nuget" | awk '{print $3}'
    grep "^HarfBuzzSharp\s" scripts/VERSIONS.txt | grep "nuget" | awk '{print $3}'
    
    # Read preview label (remove surrounding quotes)
    grep "PREVIEW_LABEL:" scripts/azure-templates-variables.yml | awk '{print $2}' | tr -d "'"
    
    • SkiaSharp ... nuget line → base version (e.g., 3.119.2)
    • HarfBuzzSharp ... nuget line → base version (e.g., 8.3.1.3)
    • PREVIEW_LABEL → label (e.g., preview.2 or stable)
  2. Search and filter for the SPECIFIC version:

    For preview releases (PREVIEW_LABEL is NOT stable):

    # Get ALL versions, then filter to match {base}-{label}.*
    dotnet package search SkiaSharp \
      --source "https://aka.ms/skiasharp-eap/index.json" \
      --exact-match --prerelease --format json \
      | jq -r '.searchResult[].packages[] | select(.id == "SkiaSharp") | .version' \
      | grep "^{base}-{label}\."
    
    # Example: Find 3.119.2-preview.3.* versions
    ... | grep "^3.119.2-preview.3\."
    

    Pick the highest build number (e.g., 3.119.2-preview.3.1). This IS the NuGet version.

    For stable releases (PREVIEW_LABEL is stable):

    # Verify a stable build exists on the internal feed
    dotnet package search SkiaSharp \
      --source "https://aka.ms/skiasharp-eap/index.json" \
      --exact-match --prerelease --format json \
      | jq -r '.searchResult[].packages[] | select(.id == "SkiaSharp") | .version' \
      | grep "^{base}-stable\."
    
    # Example: Find 3.119.2-stable.* internal packages
    ... | grep "^3.119.2-stable\."
    

    The internal feed has {base}-stable.{build} packages (e.g., 3.119.2-stable.3), but the NuGet version is just {base} (e.g., 3.119.2). The build number is never appended to stable versions.

    ⚠️ CRITICAL: Use .version to get ALL versions, NOT .latestVersion which only returns the newest. The feed contains multiple version streams (e.g., 3.119.2 AND 3.119.3), so you MUST filter by the base version and preview label from the release branch.

  3. Pick the NuGet version:

    • Preview: Highest build number from matching versions (e.g., 3.119.2-preview.3.1)
    • Stable: Just the base version (e.g., 3.119.2) — no build number appended
  4. Report to user:

    Preview:

    Resolved versions:
      SkiaSharp:     3.119.2-preview.3.1
      HarfBuzzSharp: 8.3.1.3-preview.3.1
      Build number:  1
    

    Stable:

    Resolved versions:
      SkiaSharp:     3.119.2
      HarfBuzzSharp: 8.3.1.3
      Internal build: 3.119.2-stable.3 (on feed)
    

No packages found? CI build hasn't completed. See troubleshooting.md.


Step 3: Confirm Test Matrix

Before running tests, determine and confirm the test matrix with the user.

Device Requirements

PlatformOld VersionNew Version
AndroidAPI 21-23 (5.0-6.0)API 35-36 (15-16)
iOSOldest available runtimeNewest available runtime

👉 See setup.md for device selection details and emulator creation.

Confirm with User

Planned test matrix:
  - iOS (old):     [device] ([oldest available iOS runtime])
  - iOS (new):     [device] ([newest available iOS runtime])
  - Android (old): [device] (Android 6.0 / API 23)
  - Android (new): [device] (Android 16 / API 36)
  - Mac Catalyst:  Current macOS
  - Blazor:        Chromium
  - Console:       .NET runtime
  - Linux (Docker): Docker container (mcr.microsoft.com/dotnet/sdk:8.0)

Proceed with this matrix?

Step 4: Run Integration Tests

Pre-Test Cleanup (REQUIRED)

⚠️ CRITICAL: These steps MUST be done before ANY integration tests:

# 1. Clear screenshot folder to ensure fresh results
rm -rf output/logs/testlogs/integration/*
mkdir -p output/logs/testlogs/integration

# 2. Kill any running Android emulators
adb devices | grep emulator | awk '{print $1}' | while read emu; do
  adb -s $emu emu kill 2>/dev/null
done
sleep 5

# 3. Verify clean state
adb devices -l  # Should show NO emulators
ls output/logs/testlogs/integration/  # Should be empty

Run Tests

cd tests/SkiaSharp.Tests.Integration
dotnet test -p:SkiaSharpVersion={version} -p:HarfBuzzSharpVersion={hb-version}

Test Commands

# Run by category
dotnet test --filter "FullyQualifiedName~SmokeTests" ...
dotnet test --filter "FullyQualifiedName~ConsoleTests" ...
dotnet test --filter "FullyQualifiedName~LinuxConsoleTests" ...
dotnet test --filter "FullyQualifiedName~BlazorTests" ...
dotnet test --filter "FullyQualifiedName~MauiiOSTests" ... -p:iOSDevice="iPhone 14 Pro" -p:iOSVersion="16.2"
dotnet test --filter "FullyQualifiedName~MauiMacCatalystTests" ...

# Android: specify device ID and expected API level for validation
dotnet test --filter "FullyQualifiedName~MauiAndroidTests" ... \
  -p:AndroidDeviceId="emulator-5554" \
  -p:AndroidApiLevel="23"

Android Emulator Workflow

⚠️ CRITICAL: Run only ONE Android emulator at a time to avoid device confusion.

  1. Verify no emulators running:

    adb devices -l  # Should show empty or only physical devices
    
  2. Start emulator with WIPE and boot verification:

    # Start emulator with -wipe-data to ensure clean state (use mode="async" to keep it running)
    emulator -avd Pixel_API_23 -wipe-data -no-snapshot -no-audio
    
    # Wait for boot (check every 10s until returns "1")
    # This can take 60-120s for a fresh wipe
    adb shell getprop sys.boot_completed
    
    # Verify correct API level
    adb shell getprop ro.build.version.sdk  # Should match expected (e.g., "23")
    

    ⚠️ The -wipe-data flag is REQUIRED to ensure a clean emulator state. Without it, cached apps or system state from previous runs may interfere with tests.

  3. Run tests with device validation:

    DEVICE_ID=$(adb devices | grep emulator | awk '{print $1}')
    API_LEVEL=$(adb -s $DEVICE_ID shell getprop ro.build.version.sdk | tr -d '\r')
    
    dotnet test --filter "FullyQualifiedName~MauiAndroidTests" \
      -p:AndroidDeviceId="$DEVICE_ID" \
      -p:AndroidApiLevel="$API_LEVEL" \
      -p:SkiaSharpVersion={version} \
      -p:HarfBuzzSharpVersion={hb-version}
    
  4. Shut down emulator before next test:

    adb -s $DEVICE_ID emu kill
    # Wait for it to stop
    sleep 5
    adb devices -l  # Verify empty
    
  5. Repeat for next API level (start from step 1)

Test Execution Order

TestRun on OldRun on NewTime
SmokeTestsOnce-~2s
ConsoleTestsOnce-~20s

Content truncated.

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"

76

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.

253

release-publish

mono

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".

81

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.

21

native-dependency-update

mono

Update native dependencies (libpng, libexpat, zlib, libwebp, harfbuzz, freetype, libjpeg-turbo, etc.) in SkiaSharp's Skia fork. Handles security CVE fixes, bug fixes, and version bumps. Use when user asks to: - Bump/update a native dependency (libpng, zlib, expat, webp, etc.) - Fix a CVE or security vulnerability in a native library - Update Skia's DEPS file - Check what version of a dependency is currently used - Analyze breaking changes between dependency versions Triggers: "bump libpng", "update zlib", "fix CVE in expat", "update native deps", "what version of libpng", "check for breaking changes". For security audits (finding CVEs, checking PR coverage), use the `security-audit` skill instead.

11

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.

51

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.

1,5541,368

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."

1,0721,159

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.

1,3991,101

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.

1,171737

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.

1,128677

pdf-to-markdown

aliceisjustplaying

Convert entire PDF documents to clean, structured Markdown for full context loading. Use this skill when the user wants to extract ALL text from a PDF into context (not grep/search), when discussing or analyzing PDF content in full, when the user mentions "load the whole PDF", "bring the PDF into context", "read the entire PDF", or when partial extraction/grepping would miss important context. This is the preferred method for PDF text extraction over page-by-page or grep approaches.

1,271599

Stay ahead of the MCP ecosystem

Get weekly updates on new skills and servers.