Skip to content

Commit 28ca7b7

Browse files
drernieclaude
andauthored
Add make tag target for GitHub release (#334)
## Summary - Add `wf/tag-release.sh` that reads the current `version` from `build.gradle`, extracts the matching `## [x.y.z]` section from `CHANGELOG.md`, creates an annotated git tag, pushes it, and runs `gh release create` with those notes. - Wire it up as `make tag`. Complements `make release` (publishes to the Nextflow Plugin Registry) by handling the separate GitHub-release step. ## Test plan - [x] Verified the awk CHANGELOG extraction returns the 1.0.1 bullets - [ ] Run `make tag` after merge to cut the 1.0.1 GitHub release 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- greptile_comment --> <h3>Greptile Summary</h3> This PR adds `wf/tag-release.sh` (wired as `make tag`) which reads the version from `build.gradle`, extracts the matching `CHANGELOG.md` section, creates an annotated git tag, pushes it, and calls `gh release create`. - **Partial-failure gap (P1):** `git push origin "$VERSION"` runs before `gh release create`. If the GitHub release step fails (auth error, release already exists, network timeout), the tag is already live on the remote but no release is attached. The "tag already exists" guard then prevents any re-run, leaving the repo in a half-released state without rollback. <h3>Confidence Score: 3/5</h3> Needs the partial-failure rollback fixed before running in production; the remaining issues are minor. One P1 (tag pushed without rollback on release-creation failure) plus three P2s (ref scoping, awk dot escaping, whitespace check) pulls the score below the P1 ceiling of 4. wf/tag-release.sh — specifically lines 30-33 around tag push / release create ordering <h3>Important Files Changed</h3> | Filename | Overview | |----------|----------| | wf/tag-release.sh | New script to tag and publish a GitHub release; has a P1 partial-failure risk (tag pushed before release creation, no rollback), plus P2 issues with ref scoping, awk regex dot escaping, and incomplete whitespace trimming. | | Makefile | Adds `tag` to .PHONY and wires it to `wf/tag-release.sh`; straightforward and correct. | </details> <h3>Sequence Diagram</h3> ```mermaid sequenceDiagram participant Dev as Developer participant Script as tag-release.sh participant FS as Filesystem participant Git as Git (local+remote) participant GH as GitHub Releases Dev->>Script: make tag Script->>FS: grep version from build.gradle FS-->>Script: VERSION Script->>Git: git rev-parse refs/tags/VERSION Git-->>Script: not found → proceed Script->>FS: awk extract CHANGELOG section FS-->>Script: NOTES Script->>Git: git tag -a VERSION Script->>Git: git push origin VERSION Git-->>Script: tag pushed ✓ Script->>GH: gh release create VERSION --notes NOTES GH-->>Script: release created ✓ (or ✗ → tag stranded) Script->>Dev: echo "Tagged and released VERSION" ``` <sub>Reviews (1): Last reviewed commit: ["Make release depend on tag"](539ab28) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=30405953)</sub> > Greptile also left **4 inline comments** on this PR. <!-- /greptile_comment --> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 9cf5d68 commit 28ca7b7

3 files changed

Lines changed: 78 additions & 3 deletions

File tree

Makefile

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ S3_BASE = s3://$(WRITE_BUCKET)/$(PROJECT)
1212
REPORT ?= ./build/reports/tests/test/index.html
1313

1414
.PHONY: all assemble clean test test-all check rebuild install package release verify fast \
15-
coverage verifyCoverage bump \
15+
coverage verifyCoverage bump tag \
1616
check-env pkg-test dyn-test s3-overlay s3-test s3-in s3-out \
1717
pkg-fail path-input deps refresh
1818

@@ -65,6 +65,11 @@ LEVEL ?= patch
6565
bump:
6666
./wf/bump-version.sh $(LEVEL)
6767

68+
# Tag the current build.gradle version and create a GitHub release
69+
# using the matching CHANGELOG section as release notes.
70+
tag:
71+
./wf/tag-release.sh
72+
6873
test-all: clean test
6974

7075
install: assemble
@@ -73,7 +78,7 @@ install: assemble
7378
package:
7479
./gradlew packagePlugin
7580

76-
release:
81+
release: tag
7782
./gradlew releasePlugin
7883

7984
#

wf/bump-version.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ case "$LEVEL" in
2626
esac
2727
NEW="${MAJOR}.${MINOR}.${PATCH}"
2828

29-
sed -i.bak "s/^version = '${OLD}'\$/version = '${NEW}'/" "$FILE"
29+
sed -i.bak "s/^version = '${OLD//./\\.}'\$/version = '${NEW}'/" "$FILE"
3030
rm "$FILE.bak"
3131

3232
cd "$ROOT"

wf/tag-release.sh

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
DRY_RUN=0
5+
if [[ "${1:-}" == "--dry-run" ]]; then
6+
DRY_RUN=1
7+
fi
8+
9+
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
10+
cd "$ROOT"
11+
12+
VERSION="$(grep "^version" build.gradle | head -1 | awk -F"'" '{ print $2 }')"
13+
if [[ -z "$VERSION" ]]; then
14+
echo "Could not parse version from build.gradle" >&2
15+
exit 1
16+
fi
17+
18+
# Refuse to tag from anywhere but main at origin/main's HEAD.
19+
git fetch origin main --quiet
20+
BRANCH="$(git rev-parse --abbrev-ref HEAD)"
21+
HEAD_SHA="$(git rev-parse HEAD)"
22+
MAIN_SHA="$(git rev-parse origin/main)"
23+
if [[ "$BRANCH" != "main" || "$HEAD_SHA" != "$MAIN_SHA" ]]; then
24+
echo "Refusing to tag: must be on main at origin/main (currently $BRANCH @ ${HEAD_SHA:0:7}, origin/main @ ${MAIN_SHA:0:7})" >&2
25+
[[ $DRY_RUN -eq 1 ]] || exit 1
26+
echo "(dry-run: continuing anyway)" >&2
27+
fi
28+
29+
if git rev-parse "refs/tags/$VERSION" >/dev/null 2>&1; then
30+
echo "Tag $VERSION already exists" >&2
31+
[[ $DRY_RUN -eq 1 ]] || exit 1
32+
fi
33+
34+
# Escape dots so awk treats the version literally (1.0.1 must not match 1X0Y1).
35+
ESCAPED_VERSION="${VERSION//./\\.}"
36+
NOTES="$(awk -v v="$ESCAPED_VERSION" '
37+
$0 ~ "^## \\[" v "\\]" { found=1; next }
38+
found && /^## \[/ { exit }
39+
found { print }
40+
' CHANGELOG.md)"
41+
42+
if [[ -z "$(printf %s "$NOTES" | tr -d '[:space:]')" ]]; then
43+
echo "No CHANGELOG section found for [$VERSION]" >&2
44+
exit 1
45+
fi
46+
47+
if [[ $DRY_RUN -eq 1 ]]; then
48+
echo "=== DRY RUN ==="
49+
echo "Version: $VERSION"
50+
echo "HEAD: ${HEAD_SHA:0:7} ($BRANCH)"
51+
echo "--- Release notes ---"
52+
echo "$NOTES"
53+
echo "--- Would run ---"
54+
echo "git tag -a $VERSION -m 'Release $VERSION'"
55+
echo "git push origin $VERSION"
56+
echo "gh release create $VERSION --title 'Version $VERSION' --notes <notes above>"
57+
exit 0
58+
fi
59+
60+
git tag -a "$VERSION" -m "Release $VERSION"
61+
git push origin "$VERSION"
62+
63+
# Roll back the tag if release creation fails so we don't leave a half-released state.
64+
if ! gh release create "$VERSION" --title "Version $VERSION" --notes "$NOTES"; then
65+
echo "gh release create failed; rolling back tag $VERSION" >&2
66+
git push origin --delete "$VERSION" || true
67+
git tag -d "$VERSION" || true
68+
exit 1
69+
fi
70+
echo "Tagged and released $VERSION"

0 commit comments

Comments
 (0)