--- name: releasing-reactiveproperty description: > Release the ReactiveProperty NuGet package set from this repository. Use this skill whenever the user asks to release, publish, ship, pre-release/prerelease, stable release, tag v*, push NuGet packages, or mentions "リリース", "pre リリース", "正式リリース", "NuGet 公開", or "パッケージ公開" for ReactiveProperty, even if they do not use the skill name. Handles tag-driven releases, mode/version confirmation, GitHub Actions monitoring, NuGet/GitHub Release verification, and failure guardrails. Do not use for setting up NuGet OIDC/trusted publishing; use nuget-trusted-publishing instead. --- # Releasing ReactiveProperty Run the tag-driven release procedure for the ReactiveProperty NuGet package set. ## Prerequisites - **Repository access**: permission to push tags to `runceel/ReactiveProperty`. - **GitHub CLI**: authenticated with access to Actions and Releases (`gh auth status`). - **NuGet trusted publishing**: `.github/workflows/build-and-publish.yml` uses `NuGet/login@v1` and `secrets.NUGET_USER`; if this setup is broken or missing, use the `nuget-trusted-publishing` skill instead. - **Local validation environment**: Windows with the .NET 10 SDK (`10.0.x`) when running the full solution locally. ## Critical Rules - **Ask for release mode first when it is not specified.** Use `ask_user` with choices for `pre-release` and `stable release` before doing any release work. - **Never infer the target version from a single tag, release, or the repository `` property.** If the maintainer has not explicitly supplied the target version, ask for it and stop. - **Always distinguish version sources before confirming a release.** Report the newest tag, the newest GitHub Release by publication date, and the newest stable GitHub Release separately; do not call any one of them simply "the latest version". - **The current release workflow is tag-driven.** Do not update `Source/Directory.Build.props` or create a version bump PR unless the maintainer explicitly asks for repository version record-keeping. - **The tag is the package version source of truth.** `.github/workflows/build-and-publish.yml` rewrites `Source/Directory.Build.props` from the pushed `v*` tag inside the runner before build/test/package. - **Never overwrite or recreate a release tag.** If `v{version}` already exists locally or remotely, stop and ask the maintainer. - **Never publish manually as a fallback.** If OIDC/NuGet publish fails, diagnose the workflow; do not bypass it with a local `dotnet nuget push` or a long-lived API key. ## Release Modes and Version Rules Normalize a requested version by removing one leading `v` for validation, then add `v` back for the tag. | Mode | Required version shape | Example tag | Notes | |---|---|---|---| | Pre-release | SemVer prerelease containing `-pre` | `v9.4.0-pre.1` | The workflow marks GitHub Releases as prerelease only when the version contains `-pre`. Do not use `-alpha`, `-beta`, or `-rc` unless the maintainer accepts that the current workflow will not mark it as prerelease. | | Stable release | Plain SemVer | `v9.4.0` | Must not contain a prerelease suffix. | If the user supplies a version that does not match the selected mode, stop and ask for a corrected version. ## Package Set The normal `ReactiveProperty.slnx` release publishes these package IDs: | Package ID | Project | |---|---| | `ReactiveProperty.Core` | `Source/ReactiveProperty.Core/ReactiveProperty.Core.csproj` | | `ReactiveProperty` | `Source/ReactiveProperty.NETStandard/ReactiveProperty.NETStandard.csproj` | | `ReactiveProperty.Blazor` | `Source/ReactiveProperty.Platform.Blazor/ReactiveProperty.Platform.Blazor.csproj` | | `ReactiveProperty.WPF` | `Source/ReactiveProperty.Platform.WPF/ReactiveProperty.Platform.WPF.csproj` | | `ReactiveProperty.R3` | `Source/ReactiveProperty.R3/ReactiveProperty.R3.csproj` | | `ReactiveProperty.R3.WPF` | `Source/ReactiveProperty.R3.WPF/ReactiveProperty.R3.WPF.csproj` | `ReactiveProperty.UWP` is legacy and is not part of the normal `ReactiveProperty.slnx` release. ## Workflow ### 1. Resolve mode, version, and tag 1. Determine whether this is a **pre-release** or **stable release**. - If unspecified, call `ask_user` before proceeding. 2. Determine the target version. - Accept only a version explicitly supplied by the maintainer. - If unspecified, call `ask_user` and stop; do not propose or infer a version from tags, releases, package metadata, or `Source/Directory.Build.props`. 3. Validate the version against the selected mode. 4. Normalize the tag to `v{version}`. 5. Before presenting the confirmation, inspect all three version views: - newest tag by semantic version; - newest GitHub Release by publication date; - newest stable GitHub Release by semantic version. Report all three when they differ, especially when a pre-release is newer by date but lower by semantic version. ### 2. Preflight the target commit Fetch `main` and tags, then inspect the intended release commit: ```pwsh git fetch origin main --tags --prune git rev-parse origin/main git log --oneline -n 5 origin/main git tag --list v{version} ``` Stop if the tag already exists. Confirm that `origin/main` is the intended release commit; do not tag a feature/worktree branch by accident. ### 3. Run local validation before tagging Mirror the release workflow as closely as possible, passing the intended version without editing files: ```pwsh dotnet restore ReactiveProperty.slnx dotnet build ReactiveProperty.slnx -c Release --no-restore /p:Version={version} /p:ContinuousIntegrationBuild=True /p:EmbedUntrackedSources=True dotnet test ReactiveProperty.slnx --no-restore --verbosity normal ``` If validation fails, stop and fix the failure before tagging. Only skip local validation when the maintainer explicitly asks to rely on GitHub Actions. ### 4. Optional version record PR Do this only when the maintainer explicitly asks to record the release version in `main` before release. 1. Update `Source/Directory.Build.props` `` to the target version. 2. Create a PR and wait for CI/review. 3. Merge the PR. 4. Fetch `origin/main` again and tag the merged commit. This PR is optional for the current workflow because the package version is produced from the tag during the release run. ### 5. Confirm and push the release tag Before pushing, present a compact confirmation with: - release mode; - normalized version and tag; - target `origin/main` commit SHA; - package set; - whether local validation passed or was explicitly skipped. After explicit confirmation, create an annotated tag on `origin/main` and push it: ```pwsh git tag -a v{version} origin/main -m "Release {version}" git push origin v{version} ``` ### 6. Monitor GitHub Actions Find the tag-triggered run and watch it to completion: ```pwsh gh run list --workflow build-and-publish.yml --limit 10 --json databaseId,headBranch,headSha,status,conclusion,event,createdAt gh run watch {run-id} --exit-status ``` If the run fails, inspect failed logs: ```pwsh gh run view {run-id} --log-failed ``` Do not delete/recreate the tag. If the failure is transient and no version correction is needed, rerun the same workflow instead. ### 7. Verify published outputs Verify the GitHub Release: ```pwsh gh release view v{version} --json tagName,isPrerelease,assets,url,publishedAt ``` For pre-releases, `isPrerelease` must be `true`. If it is false, check whether the version contains `-pre`; the current workflow only uses that substring to set prerelease status. Verify NuGet indexing for every package ID. NuGet indexing can lag, so retry for a short period before reporting a delay: ```pwsh $version = "{version}".ToLowerInvariant() $packages = @( "ReactiveProperty", "ReactiveProperty.Core", "ReactiveProperty.Blazor", "ReactiveProperty.WPF", "ReactiveProperty.R3", "ReactiveProperty.R3.WPF" ) foreach ($package in $packages) { $id = $package.ToLowerInvariant() $index = Invoke-RestMethod "https://api.nuget.org/v3-flatcontainer/$id/index.json" [PSCustomObject]@{ Package = $package Published = $index.versions -contains $version } } ``` ## Error Handling | Problem | Likely cause | Recovery | |---|---|---| | Release mode is unclear | User asked for "release" without pre/stable detail | Ask `pre-release` vs `stable release` with `ask_user` before proceeding. | | Version does not match mode | Pre-release lacks `-pre`, or stable has a suffix | Stop and ask for a corrected version. | | `v{version}` already exists | Release was already attempted or completed | Stop. Inspect existing tag/release; never force-push or recreate it. | | Local validation fails | Build/test regression or environment issue | Fix the failure or ask whether to rely on Actions; do not tag by default. | | `NuGet/login@v1` fails | Trusted publishing policy, `NUGET_USER`, or OIDC permission issue | Use `nuget-trusted-publishing`; do not use a local API key fallback. | | Workflow fails after some packages publish | Partial publish or transient failure | Do not retag. Use the same workflow run/rerun; `--skip-duplicate` handles already-published packages. | | NuGet package is not visible immediately | NuGet indexing delay | Recheck flat-container indexes before declaring failure. | | GitHub Release is not marked prerelease | Version did not contain `-pre` or workflow changed | Report the mismatch; do not edit release metadata unless the maintainer asks. | ## Output Format Before tagging, show: ```text Release mode: pre-release|stable Version: {version} Tag: v{version} Newest tag: {tag} Newest GitHub Release: {tag} ({publishedAt}) Newest stable GitHub Release: {tag} Target commit: {short-sha} {subject} Packages: ReactiveProperty, ReactiveProperty.Core, ReactiveProperty.Blazor, ReactiveProperty.WPF, ReactiveProperty.R3, ReactiveProperty.R3.WPF Validation: passed|skipped by maintainer ``` After completion, show: ```text Release v{version}: succeeded|failed GitHub Actions: {run-url} GitHub Release: {release-url and prerelease status} NuGet: all package IDs visible|pending indexing|failed package list ``` ## References | Reference | Purpose | |---|---| | `.github/workflows/build-and-publish.yml` | Source of truth for tag trigger, package build, NuGet publish, and GitHub Release creation. | | `Source/Directory.Build.props` | Repository version property that the workflow rewrites from the tag during release. | | `ReactiveProperty.slnx` | Solution restored, built, tested, and packaged by the release workflow. | | `.agents/skills/nuget-trusted-publishing/SKILL.md` | Use when OIDC/trusted publishing setup needs to be created or repaired. | ## Post-Run Reflection After a release attempt, note any step that differed from this skill. If the repository workflow changed, update this skill in a follow-up PR so the next release runbook stays accurate.