From fd73665dd33a87191759ac29059451b295c04faa Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 3 Nov 2026 18:27:39 +0000 Subject: [PATCH 1/2] Release and publish from CI when the version changes Add a release job to the CI workflow that runs on pushes to the default branch after build-and-test. It reads VersionPrefix from src/IPData/IPData.csproj and, when the tag vX.Y.Z does not exist yet, creates the tag and the GitHub release with generated notes. A release created with the workflow token does not trigger other workflows, so the NuGet publish workflow becomes callable with a tag input and runs in the same run when a release was created. Its release trigger stays, so a manually published release still publishes. Co-Authored-By: Claude Fable 5.1 --- .github/workflows/ci.yml | 56 +++++++++++++++++++++++++++++++++++ .github/workflows/publish.yml | 10 ++++++- 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index df80885..3448f5d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,3 +29,59 @@ jobs: - name: Pack run: dotnet pack src/IPData/IPData.csproj --configuration Release --no-build + + release: + needs: build-and-test + if: github.event_name == 'push' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch) + runs-on: ubuntu-latest + permissions: + contents: write + concurrency: + group: release + cancel-in-progress: false + outputs: + tag: ${{ steps.release.outputs.tag }} + created: ${{ steps.release.outputs.created }} + + steps: + - uses: actions/checkout@v4 + + - name: Tag and create the release when the version is new + id: release + env: + GH_TOKEN: ${{ github.token }} + GH_REPO: ${{ github.repository }} + run: | + VERSION=$(sed -nE 's/.*([^<]+)<.*/\1/p' src/IPData/IPData.csproj | head -1) + if [ -z "$VERSION" ]; then + echo "::error::VersionPrefix not found in src/IPData/IPData.csproj" + exit 1 + fi + TAG="v$VERSION" + echo "tag=$TAG" >> "$GITHUB_OUTPUT" + + status=0 + git ls-remote --exit-code --tags origin "refs/tags/$TAG" >/dev/null || status=$? + case "$status" in + 0) + echo "Tag $TAG already exists; nothing to release." + echo "created=false" >> "$GITHUB_OUTPUT" + ;; + 2) + gh release create "$TAG" --target "$GITHUB_SHA" --title "$TAG" --generate-notes + echo "Created tag and release $TAG." + echo "created=true" >> "$GITHUB_OUTPUT" + ;; + *) + echo "::error::Could not check whether tag $TAG exists (git ls-remote exit status $status)." + exit "$status" + ;; + esac + + publish: + needs: release + if: needs.release.outputs.created == 'true' + uses: ./.github/workflows/publish.yml + with: + tag: ${{ needs.release.outputs.tag }} + secrets: inherit diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index d05b076..65058c3 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -3,6 +3,12 @@ name: Publish to NuGet on: release: types: [published] + workflow_call: + inputs: + tag: + description: Release tag to publish, for example v3.1.0 + required: true + type: string jobs: publish: @@ -21,7 +27,9 @@ jobs: - name: Get version from tag id: version - run: echo "VERSION=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT" + env: + TAG: ${{ inputs.tag || github.ref_name }} + run: echo "VERSION=${TAG#v}" >> "$GITHUB_OUTPUT" - name: Build run: dotnet build --configuration Release --no-restore /p:Version=${{ steps.version.outputs.VERSION }} From 84ae2fba4f77eeef3ad8a61d201b5b0d2c513b36 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 3 Nov 2026 18:27:40 +0000 Subject: [PATCH 2/2] Document the release process Explain that merging a pull request that bumps VersionPrefix tags the merge commit, creates the GitHub release and publishes the package to NuGet, and that a version that is already tagged publishes nothing. Co-Authored-By: Claude Fable 5.1 --- .github/README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/README.md b/.github/README.md index 94dd3fe..14c7dcc 100644 --- a/.github/README.md +++ b/.github/README.md @@ -25,6 +25,7 @@ - [Migrating from v2 to v3](#migrating-from-v2-to-v3) - [Contributing](#contributing) - [Versioning](#versioning) +- [Releasing](#releasing) - [License](#license) ## Install @@ -271,6 +272,10 @@ Please read [CONTRIBUTING.md][CONTRIBUTING] for details on our code of conduct, We use [SemVer] for versioning. For the versions available, see the tags on this repository. +## Releasing + +Releases are cut by CI from the version in `src/IPData/IPData.csproj`. To ship a new version, bump `VersionPrefix` in a pull request and merge it: the CI run on `master` tags the merge commit `vX.Y.Z`, creates the GitHub release with generated notes and publishes the package to [NuGet](https://www.nuget.org/packages/IPData/). A merge whose version is already tagged publishes nothing. + ## License This project is licensed under the MIT License - see the [LICENSE.md][LICENSE] file for details