Skip to content

Add a workflow to build and package the library - #5

Merged
AlyxSharkBite merged 1 commit into
mainfrom
ci/package
Aug 28, 2026
Merged

AlyxSharkBite merged 1 commit into
mainfrom
ci/package

Conversation

@AlyxSharkBite

Copy link
Copy Markdown
Owner

Adds .github/workflows/package.yml, which builds the NuGet package as a CI artifact and attaches it to a draft GitHub release when a v* tag is pushed.

The package is provably the tested build

The solution is built once, tested, then packed with --no-build. The assembly inside the .nupkg is byte for byte the one the 966 tests exercised, not a later rebuild that merely used the same source.

Versioning

Trigger Version
Tag v1.2.3 1.2.3
Push to main, PR, manual 1.0.0-ci.<run>.g<sha>

The tag is authoritative, but the step emits a ::warning:: if it disagrees with the version in PkLibSharp.csproj — that mismatch almost always means the csproj wasn't bumped. Non-tag builds derive from the project version, so every main and PR build produces a uniquely identifiable package rather than overwriting 1.0.0.

Verification, because a package that builds isn't necessarily correct

A dedicated step asserts what's easy to lose silently:

  • both .nupkg and .snupkg exist
  • the nupkg contains LICENSE, README.md, lib/net10.0/PkLibSharp.dll, lib/net10.0/PkLibSharp.xml
  • the nuspec declares the expected version
  • the snupkg contains lib/net10.0/PkLibSharp.pdb

The LICENSE check matters specifically: the MIT terms require Zezula's notice to travel with the package, and that's an easy thing to break without noticing.

Packing also sets ContinuousIntegrationBuild (normalises PDB paths) plus PublishRepositoryUrl and EmbedUntrackedSources, so the symbol package is usable for SourceLink debugging. Confirmed the nuspec ends up with the full repository URL and commit rather than just a bare commit hash.

Consistent with the existing security posture

--locked-mode restore, all four actions pinned to commit SHAs (each verified to exist upstream and carry the tag claimed in the comment), permissions: contents: read with only the release job elevated to contents: write, persist-credentials: false on checkout, concurrency group, timeouts.

Two deliberate stopping points

The release is a draft. Pushing a tag builds and attaches the package, but publishing stays a human step — consistent with the review gates already on this repo. Drop --draft to publish automatically.

NuGet.org publishing is not wired up. That's outward-facing and needs an API key secret this workflow neither has nor asks for. Happy to add it as a follow-up, ideally gated behind a GitHub Environment with a required reviewer.

Verification done before pushing

  • Every pinned SHA resolved against the GitHub API and confirmed to carry its claimed tag
  • YAML parses; both jobs present
  • Both branches of the version logic dry-run locally → 1.0.0-ci.42.g751d52a and 2.5.0 (with the warning firing correctly)
  • The verification step dry-run against a real package, including a negative test confirming it fails when a required entry is absent
  • Full build → test → pack --no-build sequence run locally: 966 tests pass, both packages produced

No source or csproj changes — the packaging properties are passed on the command line, so local dotnet pack behaviour is unchanged.

Produces the NuGet package as a CI artifact, and attaches it to a draft
GitHub release when a v* tag is pushed.

The package is proven to be the artifact that passed the tests: the
solution is built once, tested, then packed with --no-build, so the
assembly inside the .nupkg is byte for byte the one the test run
exercised rather than a later rebuild.

Versioning has two modes. A v* tag is authoritative and yields a release
version; the step warns if the tag disagrees with the version declared
in PkLibSharp.csproj, since that usually means the csproj was not
bumped. Every other build yields a prerelease derived from the project
version, the run number and the commit, so main builds and pull request
builds produce uniquely identifiable packages.

Packing sets ContinuousIntegrationBuild to normalise paths recorded in
the PDB, and PublishRepositoryUrl with EmbedUntrackedSources so the
accompanying .snupkg is usable for SourceLink debugging.

A verification step asserts the things that are easy to lose silently: a
package that builds is not necessarily one that is correct. It checks
that both packages exist, that the nupkg carries LICENSE, README.md, the
assembly and the XML documentation, that the nuspec declares the
expected version, and that the snupkg carries the symbols.

Restore runs in locked mode like the rest of CI, actions are pinned to
commit SHAs, permissions are contents:read with the release job elevated
to contents:write, and checkout runs with persist-credentials disabled.

The release is created as a draft on purpose, so publishing stays a
deliberate step. Pushing to NuGet.org is not wired up: it is an
outward-facing action needing an API key secret this workflow neither
has nor asks for.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@AlyxSharkBite
AlyxSharkBite merged commit 7db07f9 into main Aug 28, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant