Skip to content

Publish a GitHub release from the changelog section - #144

Merged
Platonenkov merged 2 commits into
devfrom
claude/github-release-step-8fd79c
Aug 26, 2026
Merged

Publish a GitHub release from the changelog section#144
Platonenkov merged 2 commits into
devfrom
claude/github-release-step-8fd79c

Conversation

@Platonenkov

Copy link
Copy Markdown
Collaborator

Closes the gap noticed after 11.0.0.0 went out: packages appeared on nuget.org, nothing appeared under Releases.

It was never automated

Worth saying plainly, because the assumption going in was that this had existed and was lost in a migration. It had not:

  • no workflow in the repository creates a release — gh release create, actions/create-release and softprops/action-gh-release return nothing across the whole history of .github/
  • the previous NugetPublish.yml did not either — same steps, ending at the nuget.org push
  • v10.8.0 and v10.9.0 were both created by hand (author Platonenkov on both)

CLAUDE.md lists it as step 7 of the release process, manual. It has been skipped for 10.10.0.0, 10.11.0.0, 10.11.1.0 and 10.12.0.0 — four releases in a row, which is what makes it worth automating rather than remembering.

What it does

Notes come from the CHANGES.md section matching <PackageVersion> in Xrpl.csproj, taken from the ## <version> <date> heading to the next heading.

The check runs before the build, not next to the release step. A changelog still titled ## Unreleased fails the run while nothing has been published — rather than after the push to nuget.org, which cannot be undone and whose version number cannot be reused. That is not hypothetical: 11.0.0.0 reached a promotion PR with the heading unstamped, and it was caught by eye.

Tags follow NuGet's normalisation, so 11.0.0.0v11.0.0 — matching both the published package and the hand-made v10.9.0/v10.8.0. A non-zero fourth component is kept.

The release step runs last so a release only appears for packages that actually shipped, and skips an existing tag rather than failing, since the pushes above are already idempotent via --skip-duplicate.

Long notes are truncated, not fatal. GitHub caps bodies at 125000 characters; 11.0.0.0 came to 98638, so the headroom is thinner than it looks. Over the limit it truncates with a pointer to CHANGES.md.

Permissions go from contents: read to contents: write. Nothing else in the file changed — the diff removes exactly one line.

Checked

  • actionlint — clean
  • YAML parses; step order and steps.notes / steps.nuget-login references verified
  • the shell logic run against this repository:
case result
11.0.0.0, 10.11.1.0, 10.9.0.0 v11.0.0, v10.11.1, v10.9.0
12.1.3.7 (non-zero fourth) v12.1.3.7, kept whole
11.0.10.0 v11.0.10 — the 0 in 10 survives
notes for 11.0.0.0 315 lines, 98638 chars, no stray ## heading
changelog left at ## Unreleased empty → step fails
version absent from changelog empty → step fails
querying 11.0.0 against ## 11.0.0.0 no match — the ( |$) boundary holds

Not in scope

The already-shipped 11.0.0.0 still has no release: this workflow only fires on a push to release, and that push has happened. It can be created as a one-off from the same changelog section — say the word and I will, or it can wait for the next release to prove the automation on real input.

Release titles are just the tag. v10.9.0 — Unified hex helpers had a subtitle a human wrote, and nothing here can invent one; the title is editable after the fact.

Pushing to release published packages and stopped there - no tag, no GitHub
release. CLAUDE.md lists creating one as step 7 of the process, by hand, and it
has not happened since v10.9.0: 10.10.0.0, 10.11.0.0, 10.11.1.0 and 10.12.0.0
all shipped to nuget.org without either. A manual step that is skipped four
times running is a step that wants automating.

The notes are the CHANGES.md section for the version in Xrpl.csproj, read from
the "## <version> <date>" heading to the next heading.

Two details worth stating, because both are deliberate:

Resolving the version and extracting the notes happens BEFORE the build, not
next to the release step where it would read more naturally. A changelog still
titled "Unreleased" then fails the run while nothing has been published, rather
than after the push to nuget.org - which cannot be taken back, and whose
version number cannot be reused. That case nearly happened on 11.0.0.0.

Tags follow NuGet's own normalisation, so 11.0.0.0 becomes v11.0.0, matching
both the published package and the v10.9.0 / v10.8.0 tags made by hand. A
fourth component that is not zero is kept, because then it carries meaning.

The release step runs last, so a release only appears for packages that
actually shipped, and skips an existing tag instead of failing - the pushes
above are already idempotent through --skip-duplicate, and a re-run should be
able to finish.

Release bodies are capped at 125000 characters by GitHub and this changelog
runs long - 11.0.0.0 came to 98638. Over the limit it is truncated with a
pointer to CHANGES.md rather than failing the release.

Needs contents: write, which the workflow did not have.
…aped traps

Self-review of the step added in the previous commit.

The version came from `sed ... | head -1` under `set -o pipefail`. That works
only while Xrpl.csproj holds a single <PackageVersion> - there is exactly one
today, so sed finishes before head closes the pipe. Add a second one and sed
takes a SIGPIPE, the pipeline reports 141, and the release stops for a reason
that reads like anything but the truth. awk takes the first match and exits.

Truncation used head -c. These notes carry non-ASCII characters, so a byte cut
can land inside one and hand the API a body that is not valid UTF-8 - a failure
in the path taken least often and understood slowest. Now trimmed by whole
lines, with LC_ALL=C so awk's length() counts bytes, which is the unit the cap
is expressed in. Checked: a 50000-byte budget yields 49082 bytes over 185
lines, and the result decodes as UTF-8.
@Platonenkov
Platonenkov added this pull request to the merge queue Aug 26, 2026
Merged via the queue into dev with commit 57ac7f8 Aug 26, 2026
4 checks passed
@Platonenkov
Platonenkov deleted the claude/github-release-step-8fd79c branch August 26, 2026 14:46
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