From b2b34b084a48547c7ffb9201b67ecb741a91f360 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Otte=20S=C3=B8rensen?= Date: Wed, 12 Aug 2026 20:27:33 +0200 Subject: [PATCH 1/2] feat: Version the package with MinVer instead of a manual CI step. MinVer computes Version from the nearest git tag (v-prefixed, per Directory.Build.props) plus commit height, so packing by hand and CI publishing can no longer disagree, and the workflow's own "take the version from the tag" step is now unnecessary. verify-package.sh switches from -p:Version to -p:MinVerVersionOverride: MinVer recalculates and overwrites Version itself, so -p:Version was silently ignored and every verification run would have collided on the same package version - the exact bug that comment already warns about. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .github/workflows/build-and-publish.yml | 19 ++++++++++--------- Directory.Build.props | 7 +++++++ .../verify-package.sh | 6 +++++- Nota.CodeAnalysis/Nota.CodeAnalysis.csproj | 8 +++++--- 4 files changed, 27 insertions(+), 13 deletions(-) create mode 100644 Directory.Build.props diff --git a/.github/workflows/build-and-publish.yml b/.github/workflows/build-and-publish.yml index 087bc42..8a8c687 100644 --- a/.github/workflows/build-and-publish.yml +++ b/.github/workflows/build-and-publish.yml @@ -32,6 +32,11 @@ jobs: steps: - uses: actions/checkout@v7 + with: + # MinVer derives the version from git tags and the commit count above them, so it needs the + # actual history rather than actions/checkout's default shallow clone - which contains no + # tags to find. + fetch-depth: 0 - uses: actions/setup-dotnet@v6 with: @@ -41,17 +46,13 @@ jobs: # build with, and testing on what people use beats testing on the oldest thing that works. dotnet-version: '10.x' - # On a tag the tag is the version, so nothing in the repository can disagree with what shipped. - # Off a tag this is unset and expands to nothing, leaving the csproj's own - which is - # then only ever a local default, never the thing that gets published. - - name: Take the version from the tag - if: github.ref_type == 'tag' - run: echo "VERSION_ARG=-p:Version=${GITHUB_REF_NAME#v}" >> "$GITHUB_ENV" - # No NuGet.config and no secure file: every dependency is public on nuget.org. The Azure # pipeline this replaced downloaded a secure NuGet.config it did not need. + # + # No -p:Version here: MinVer sets it from the git tag (and the commit count above one, off a + # tag), so nothing in the repository can disagree with what shipped. - name: Build - run: dotnet build Nota.CodeAnalysis.sln --configuration Release $VERSION_ARG + run: dotnet build Nota.CodeAnalysis.sln --configuration Release - name: Verify the rules report run: ./Nota.CodeAnalysis.Verification/verify.sh @@ -67,7 +68,7 @@ jobs: run: ./Nota.CodeAnalysis.Verification/verify-package.sh - name: Pack - run: dotnet pack Nota.CodeAnalysis.sln --configuration Release --no-build --output artifacts $VERSION_ARG + run: dotnet pack Nota.CodeAnalysis.sln --configuration Release --no-build --output artifacts # Kept even on a pull request, so a packaging mistake is visible without merging. - name: Upload the package diff --git a/Directory.Build.props b/Directory.Build.props new file mode 100644 index 0000000..77a55bd --- /dev/null +++ b/Directory.Build.props @@ -0,0 +1,7 @@ + + + + v + + diff --git a/Nota.CodeAnalysis.Verification/verify-package.sh b/Nota.CodeAnalysis.Verification/verify-package.sh index 791be3a..ebcf4d5 100755 --- a/Nota.CodeAnalysis.Verification/verify-package.sh +++ b/Nota.CodeAnalysis.Verification/verify-package.sh @@ -40,10 +40,14 @@ mkdir -p "$feed" "$app" # whatever 2.2.0 was extracted first - the change under test never reaches the consumer. That is not # hypothetical; this script gave a clean pass against a regression it was written to catch, until the # version was made unique. +# +# MinVerVersionOverride, not -p:Version - MinVer computes Version itself from the git tag and +# overwrites whatever was passed in, so -p:Version here would be silently ignored and every run +# would collide on the same version, reviving the exact bug this comment describes. version="0.0.0-verify.$(date +%Y%m%d%H%M%S)" printf 'Packing %s...\n' "$version" -dotnet pack "$root/Nota.CodeAnalysis.sln" --configuration Release --output "$feed" -p:Version="$version" >"$work/pack.log" 2>&1 || { +dotnet pack "$root/Nota.CodeAnalysis.sln" --configuration Release --output "$feed" -p:MinVerVersionOverride="$version" >"$work/pack.log" 2>&1 || { printf 'pack failed:\n' >&2 cat "$work/pack.log" >&2 exit 1 diff --git a/Nota.CodeAnalysis/Nota.CodeAnalysis.csproj b/Nota.CodeAnalysis/Nota.CodeAnalysis.csproj index 492b3f0..c5c5cc9 100644 --- a/Nota.CodeAnalysis/Nota.CodeAnalysis.csproj +++ b/Nota.CodeAnalysis/Nota.CodeAnalysis.csproj @@ -4,9 +4,6 @@ true https://github.com/Notalib/Nota.CodeAnalysis true - - 2.2.1 content/README.md @@ -25,6 +22,11 @@ + + + From 1028bbf6aef8bcd9f8320e4006a33e5f2273dc03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Otte=20S=C3=B8rensen?= Date: Wed, 12 Aug 2026 20:43:36 +0200 Subject: [PATCH 2/2] docs: Explain MinVer-based versioning in the README. The "Working on this repository" section still described the version living in the tag and a local-default in the csproj - true before this change, wrong after it now that MinVer computes Version from the tag on every build and the property is gone. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 53040a5..7416aa1 100644 --- a/README.md +++ b/README.md @@ -144,8 +144,12 @@ Releases are cut by tagging: git tag -a v2.3.0 -m "Nota.CodeAnalysis 2.3.0" && git push origin v2.3.0 ``` -The tag is the version, so nothing in the repository can disagree with what shipped. `` in -the csproj is only a local default, for anyone packing by hand. +[MinVer](https://github.com/adamralph/minver) derives the package version from that tag on every +build, so nothing in the repository can disagree with what shipped - there is no `` to edit +or forget to bump. Building straight off a tagged commit gets that tag's version exactly; anything +else gets the next patch as a pre-release with the commit count above the tag, e.g. `2.3.1-alpha.0.4`. +CI checks out full history (`fetch-depth: 0`) so MinVer can see the tags at all - a shallow clone has +none, and would fall back to `0.0.0-alpha.0`. Merging to `main` builds and verifies but does not publish, and neither do pull requests - releasing is a separate act from merging.