Skip to content

Compose release body locally and set via gh release edit#19

Merged
foadshafighi merged 1 commit intomainfrom
fix/release-body-via-gh-edit
Apr 27, 2026
Merged

Compose release body locally and set via gh release edit#19
foadshafighi merged 1 commit intomainfrom
fix/release-body-via-gh-edit

Conversation

@foadshafighi
Copy link
Copy Markdown
Contributor

@foadshafighi foadshafighi commented Apr 27, 2026

Summary

Second iteration of the release-pipeline smoke test fix. The first fix (PR #18) solved goreleaser's "dirty git state" rejection by writing release notes to /tmp. The release published successfully but with only the goreleaser header in the body — the CHANGELOG content from --release-notes /tmp/release-notes.md was silently dropped, likely because of changelog: disable: true in the goreleaser config.

This PR takes ownership of the release body explicitly:

  1. Compose the full body locally in the workflow — header + CHANGELOG section, written to /tmp/release-body.md.
  2. Drop --release-notes from goreleaser args since we override anyway.
  3. Add a final step that runs gh release edit ... --notes-file /tmp/release-body.md after goreleaser publishes, replacing whatever body goreleaser produced with our composed content.

This pattern is robust regardless of goreleaser internals. It also bounds the dependency on goreleaser to "build and upload binaries"; the body presentation is now purely the workflow's responsibility.

What v0.5.1 looks like now

The v0.5.1 release body was patched manually with gh release edit immediately after the smoke test. From v0.5.2 onward, this fix means the workflow does it automatically.

Test plan

  • YAML valid
  • CI passes
  • Validated end-to-end on the next release (v0.5.2 or v0.6.0)

Callouts for reviewers

  1. Header text duplicated. The header text "## ulc CLI {{ .Tag }} / Download a single-file binary..." now appears in both tools/validator/.goreleaser.yaml (the dead-code path goreleaser uses) and the workflow (the actual path). They must stay in sync. If you change one, change the other. Future cleanup: remove release.header from the goreleaser config since it's no longer rendered to users.
  2. The wc -l < ... | -lt 7 sanity check ensures the composed body has more than just the header — catches edge cases where the awk extraction fails silently.
  3. Goreleaser still publishes the release. We just override its body. Binary build, archive, checksum, and asset upload all continue to be goreleaser's job.

Greptile Summary

This PR takes ownership of the GitHub Release body by composing it directly in the workflow (header + awk-extracted CHANGELOG section written to /tmp/release-body.md) and applying it with gh release edit --notes-file after goreleaser publishes, replacing whatever body goreleaser produced. The --release-notes flag is dropped from the goreleaser invocation since it was silently discarded anyway due to changelog: disable: true in the goreleaser config.

The approach is sound and the implementation is clean. One callout worth tracking: release.header in tools/validator/.goreleaser.yaml is now dead code (goreleaser still writes it initially, but gh release edit immediately overwrites it); the PR description flags this for future cleanup.

Confidence Score: 5/5

Safe to merge; no blocking issues — sole finding is a P2 threshold nit on the wc -l guard.

All findings are P2 or lower. The wc -l threshold of 7 could theoretically block a single-bullet CHANGELOG section, but given the project's section format this is extremely unlikely in practice and does not affect correctness of the release body. The overall approach (compose locally, apply via gh release edit) is robust and correct.

No files require special attention, though tools/validator/.goreleaser.yaml carries a now-dead release.header block that can be removed in a follow-up.

Important Files Changed

Filename Overview
.github/workflows/release.yml Composes release body locally and applies it via gh release edit; one minor concern with the wc -l threshold that could silently block a valid very-short CHANGELOG section.
Prompt To Fix All With AI
This is a comment left during a code review.
Path: .github/workflows/release.yml
Line: 92-95

Comment:
**`wc -l` threshold may block valid single-entry releases**

The header contributes exactly 5 lines, so the check requires awk to emit at least 2 lines of CHANGELOG content. A section with a single bullet (e.g. `- Patch typo.`) produces only 6 lines total and would fail this guard even though the extraction worked correctly. Lowering the threshold to `6` (i.e., "header + at least 1 CHANGELOG line") keeps the safety net while allowing minimal-but-valid sections.

```suggestion
          if [ "$(wc -l < /tmp/release-body.md)" -lt 6 ]; then
```

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "Compose release body locally and set via..." | Re-trigger Greptile

Greptile also left 1 inline comment on this PR.

@foadshafighi foadshafighi requested a review from a team as a code owner April 27, 2026 15:14
@foadshafighi foadshafighi merged commit 10bd5d8 into main Apr 27, 2026
4 checks passed
@foadshafighi foadshafighi deleted the fix/release-body-via-gh-edit branch April 27, 2026 15:14
@github-actions
Copy link
Copy Markdown

Codex Automated Code Review

Code Review Summary

PR: Updates release workflow to compose GitHub Release body from CHANGELOG.md and edit the release after GoReleaser publishes assets.

P0 - Critical Issues (Must Fix)

None found.

P1 - High Priority Issues (Should Fix)

  • .github/workflows/release.yml:121 / .github/workflows/release.yml:126 - The release is now published by GoReleaser before the composed changelog body is applied. If gh release edit fails, the public release remains published with only the GoReleaser-configured header/body, not the intended changelog content. Fix by passing the composed file directly to GoReleaser, e.g. args: release --clean --release-notes /tmp/release-body.md, or publish as a draft until the body update succeeds.

P2 - Medium Priority Issues (Consider Fixing)

  • .github/workflows/release.yml:92 - The “suspiciously short” check rejects valid one-line changelog sections. The static header contributes 5 lines, so a real single-line section produces 6 lines and still fails < 7. Fix by validating the extracted changelog content separately before composing the header, similar to the previous -s /tmp/release-notes.md check.

P3 - Low Priority Issues (Optional)

None found.

Positive Observations

  • Action references remain pinned by commit SHA.
  • Shell inputs are routed through environment variables and quoted before use.
  • The workflow keeps release permissions scoped to contents: write, which is appropriate for tagging and publishing releases.

Automated review by OpenAI Codex

Comment on lines +92 to 95
if [ "$(wc -l < /tmp/release-body.md)" -lt 7 ]; then
echo "::error::Composed release body for ${TAG} is suspiciously short — CHANGELOG section may be empty."
exit 1
fi
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 wc -l threshold may block valid single-entry releases

The header contributes exactly 5 lines, so the check requires awk to emit at least 2 lines of CHANGELOG content. A section with a single bullet (e.g. - Patch typo.) produces only 6 lines total and would fail this guard even though the extraction worked correctly. Lowering the threshold to 6 (i.e., "header + at least 1 CHANGELOG line") keeps the safety net while allowing minimal-but-valid sections.

Suggested change
if [ "$(wc -l < /tmp/release-body.md)" -lt 7 ]; then
echo "::error::Composed release body for ${TAG} is suspiciously short — CHANGELOG section may be empty."
exit 1
fi
if [ "$(wc -l < /tmp/release-body.md)" -lt 6 ]; then
Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/release.yml
Line: 92-95

Comment:
**`wc -l` threshold may block valid single-entry releases**

The header contributes exactly 5 lines, so the check requires awk to emit at least 2 lines of CHANGELOG content. A section with a single bullet (e.g. `- Patch typo.`) produces only 6 lines total and would fail this guard even though the extraction worked correctly. Lowering the threshold to `6` (i.e., "header + at least 1 CHANGELOG line") keeps the safety net while allowing minimal-but-valid sections.

```suggestion
          if [ "$(wc -l < /tmp/release-body.md)" -lt 6 ]; then
```

How can I resolve this? If you propose a fix, please make it concise.

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