diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 18d61f7..bb6e3a6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -45,6 +45,21 @@ jobs: - name: Test boot script run: node --test tests/boot/boot.test.mjs + # `signsofai --version` reported 0.1.0 for seven releases, because the number was restated in + # Program.cs instead of read from the build. Anyone checking whether they had a fix was told + # they were on the first release ever published. This runs the tool that was just built and + # compares what it says against the version the csproj packs, so the two cannot drift again. + - name: The CLI reports the version it was built as + run: | + want=$(grep -oPm1 '(?<=)[^<]+' src/SignsOfAI.Cli/SignsOfAI.Cli.csproj) + got=$(dotnet run --project src/SignsOfAI.Cli -c Release --no-build -- --version) + echo "csproj packs $want; the tool reports $got" + if [ "$want" != "$got" ]; then + echo "::error::signsofai --version says $got but this build is $want." + echo "Program.cs must read the version from the assembly, never restate it." + exit 1 + fi + # The desktop app is WPF, so it needs a Windows runner and it is not in SignsOfAI.slnx — see the # comment at the top of that file. Its own job keeps the build above on Linux, where it stays fast # for the translation PRs that are the reason this workflow exists. diff --git a/src/SignsOfAI.Cli/BuildInfo.cs b/src/SignsOfAI.Cli/BuildInfo.cs new file mode 100644 index 0000000..6d79de2 --- /dev/null +++ b/src/SignsOfAI.Cli/BuildInfo.cs @@ -0,0 +1,32 @@ +using System.Reflection; + +namespace SignsOfAI.Cli; + +/// +/// The version this build actually is, taken from the assembly the compiler stamped from +/// <Version> in the csproj. Restating it in source is how `--version` came to report 0.1.0 +/// while the published package was 0.6.0 — seven releases of a tool telling people the wrong +/// answer to the one question they ask when a fix does not seem to be there. +/// +public static class BuildInfo +{ + public static string Version { get; } = Read(); + + private static string Read() + { + var assembly = typeof(BuildInfo).Assembly; + + // InformationalVersion carries the full "0.7.0+" when SourceLink is on; the build + // metadata after '+' is not part of the version people are asking about. + string? informational = assembly + .GetCustomAttribute()?.InformationalVersion; + if (!string.IsNullOrWhiteSpace(informational)) + { + int plus = informational.IndexOf('+'); + return plus < 0 ? informational : informational[..plus]; + } + + // A version with a trailing ".0" the csproj never wrote is still the truth about this build. + return assembly.GetName().Version?.ToString(3) ?? "unknown"; + } +} diff --git a/src/SignsOfAI.Cli/Program.cs b/src/SignsOfAI.Cli/Program.cs index 767f0f4..3b1d54e 100644 --- a/src/SignsOfAI.Cli/Program.cs +++ b/src/SignsOfAI.Cli/Program.cs @@ -10,7 +10,9 @@ using SignsOfAI.Core.Rules; // ── signsofai: lint prose for the signs of AI writing ──────────────────────── -const string Version = "0.1.0"; +// Read from the assembly, never restated here: a constant went seven releases saying 0.1.0 while +// the package said 0.6.0, so anyone checking whether they had a fix was told they did not. +string Version = SignsOfAI.Cli.BuildInfo.Version; // Emit UTF-8 so accents, · separators and glyphs render on Windows consoles too. try { Console.OutputEncoding = System.Text.Encoding.UTF8; } catch { /* redirected / unsupported */ }