This repository uses one long-lived branch: master. All development happens on short-lived
feature branches and reaches master through pull requests with passing CI. Release branches are
not part of the workflow, and work must not be implemented directly on release/*.
The publish workflow has three modes:
| Trigger | Version | Destination | Required source provenance |
|---|---|---|---|
Push vX.Y.Z-rc.N |
X.Y.Z-rc.N |
NuGet.org | Tag target is reachable from origin/master |
Push vX.Y.Z |
X.Y.Z |
NuGet.org | Tag target is reachable from origin/master |
Manual, no manual_version |
<base>-preview.<run>.<sha> |
GitHub Packages | Trigger commit, or an explicit reachable source_ref |
Manual, with manual_version |
manual_version |
NuGet.org | Dispatch from master; source commit is reachable from origin/master |
NuGet.org versions must use X.Y.Z or X.Y.Z-rc.N. The project <Version> is only the base for
automatically named previews; a release version comes from the tag or the explicit manual input.
The workflow queries the official NuGet V3 flat-container index before any NuGet.org push. If the
version already exists, the workflow stops. It does not use --skip-duplicate, so an immutable
version can never be treated as a successful republish.
-
Merge the release changes to
masterand wait for theciworkflow on the merged commit. -
Fetch and verify the exact source:
git fetch --prune origin git switch master git merge --ff-only origin/master git status --short --branch
-
Check that the intended version is absent from
https://api.nuget.org/v3-flatcontainer/kapusch.storekit2.ios/index.json. -
Create a new annotated
vX.Y.Z-rc.NorvX.Y.Ztag on the selectedmastercommit and push the new tag. Never reuse or move an existing tag. -
Verify the publish run. Its artifact contains the
.nupkgandpackage-provenance.jsonwith the source SHA, trigger ref, destination, workflow run URL, and package SHA-256.
Dispatch publish without manual_version to create a GitHub Packages preview. Preview versions
include the workflow run number and source commit abbreviation so they are unique.
A manual NuGet.org version is an explicit recovery or operator workflow, not a way to bypass tags:
- dispatch the workflow from
master; - supply an unused
manual_version; - leave
source_refempty to package the selectedmastercommit; or - supply
source_refto package a historical commit already reachable fromorigin/master.
The workflow never creates or moves a tag. If v<manual_version> already exists, its target must
match the resolved package source exactly.
Use source_ref only when the current workflow source is not the code that must be packaged. Prefer
an immutable full commit SHA or an existing tag. The workflow resolves the input, logs the checked-out
commit, and requires it to be an ancestor of origin/master. A deleted release branch name is not
durable provenance; its retained commit or tag is.
The already-published Kapusch.StoreKit2.iOS 1.0.0-rc.1 package predates this workflow and has two
immutable historical records that do not point to the same commit:
- the package nuspec records repository commit
f453c9da75a99e3d2ea45de9b78314afd332ebdaand branchrefs/heads/release/1.0.0; - the annotated
v1.0.0-rc.1tag objectfcef88b6b576c3349c6bc39c02a38150ee9df735targets commit27cc3daaa47a45f80399736880bef4df9f6d025e; - the immutable NuGet downloaded from the official V3 flat container has SHA-256
3597ea716e0bcdbcca6942e66bd5348589d9422affab0992eda7814c1f3311cb.
Both commits are reachable from master. Preserve the mismatch: do not move the tag and do not
republish 1.0.0-rc.1. For this legacy version, the nuspec commit is the package build provenance;
the existing tag is a separate retained source milestone.
Run these commands on macOS with Xcode 26.3 selected before release work is merged:
dotnet workload install ios --version 10.0.202
bash src/Kapusch.StoreKit2ApisForiOSComponents/Native/iOS/build.sh
dotnet build src/Kapusch.StoreKit2ApisForiOSComponents/Kapusch.StoreKit2ApisForiOSComponents.csproj -c Release
dotnet build samples/Kapusch.StoreKit2.iOS.Sample/Kapusch.StoreKit2.iOS.Sample.csproj -c Release
dotnet pack src/Kapusch.StoreKit2ApisForiOSComponents/Kapusch.StoreKit2ApisForiOSComponents.csproj -c Release -o artifacts/nuget
python3 scripts/validate-nupkg.py artifacts/nuget/Kapusch.StoreKit2.iOS.0.1.0.nupkg
ruby -e 'require "yaml"; Dir[".github/workflows/*.{yml,yaml}"].each { |path| YAML.parse_file(path); puts "OK: #{path}" }'CI repeats the native build, managed build, sample build, pack, and package-layout validation on pull
requests and on pushes to master.
Preserve recovery refs locally, merge all retained commits through a pull request to master, and
wait for both PR CI and post-merge master CI. After fetching the merged state, the following must
report zero commits before deleting the legacy remote branch:
git fetch --prune origin
git rev-list --count origin/master..origin/release/1.0.0Only then may release/1.0.0 be deleted remotely and locally. Branch deletion must not delete or
retarget any historical tag. Tags remain permanent source records, while published package metadata
and recorded hashes remain the authoritative package build provenance.