Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 10 additions & 9 deletions .github/workflows/build-and-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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 <Version> - 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
Expand All @@ -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
Expand Down
7 changes: 7 additions & 0 deletions Directory.Build.props
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<Project>
<PropertyGroup>
<!-- Tags are "v2.2.0", not "2.2.0" - MinVer's default prefix is empty, so without this it would
never find a tag and every build would fall back to 0.0.0-alpha.0. -->
<MinVerTagPrefix>v</MinVerTagPrefix>
</PropertyGroup>
</Project>
6 changes: 5 additions & 1 deletion Nota.CodeAnalysis.Verification/verify-package.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 5 additions & 3 deletions Nota.CodeAnalysis/Nota.CodeAnalysis.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<RepositoryUrl>https://github.com/Notalib/Nota.CodeAnalysis</RepositoryUrl>
<NoDefaultExcludes>true</NoDefaultExcludes>
<!-- A local default only. Releases take their version from the git tag, so this is what you get
packing by hand and never what gets published. -->
<Version>2.2.1</Version>
<PackageReadmeFile>content/README.md</PackageReadmeFile>
</PropertyGroup>

Expand All @@ -25,6 +22,11 @@
<PackageReference Include="SerilogAnalyzer" Version="0.15.0" />
<PackageReference Include="StyleCop.Analyzers.Unstable" Version="1.2.0.556" />
<PackageReference Include="UsingLayoutAnalyser" Version="0.3.0" />

<!-- Sets Version from the nearest git tag (Directory.Build.props declares the "v" prefix) plus a
height above it, so the package version can never drift from what was actually tagged. Build-
time only: PrivateAssets stops it flowing to consumers, who have no reason to inherit it. -->
<PackageReference Include="MinVer" Version="7.0.0" PrivateAssets="All" />
</ItemGroup>

<ItemGroup>
Expand Down
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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. `<Version>` 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 `<Version>` 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.