Skip to content

Commit 660a10b

Browse files
authored
ci: unreleased changes check + tag safety in release workflow (#66)
## Summary Two CI improvements to prevent the v1.6.0 → v1.6.1 gap from happening again. ### 1. Unreleased changes check (`unreleased-check.yml`) Runs on every push to main. Compares HEAD against the latest version tag and emits a `::warning` annotation when source commits exist without a version bump. Skips gracefully when the tag doesn't exist yet (i.e., the push IS the release). ### 2. Tag safety in release workflow (`publish-release.yml`) - Explicit `git tag` + `git push origin <tag>` step before `gh release create` - `--verify-tag` flag on `gh release create` for belt-and-suspenders safety - Outputs version for reuse across steps ### Also going forward Release commits must use `chore: release vX.Y.Z` format to pass commitlint. Always create a branch first, never commit directly to main.
2 parents 3b613d6 + 9d98972 commit 660a10b

2 files changed

Lines changed: 50 additions & 2 deletions

File tree

.github/workflows/publish-release.yml

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ jobs:
88
runs-on: ubuntu-latest
99
steps:
1010
- uses: actions/checkout@v4
11+
with: { fetch-depth: 0 }
1112
- uses: pnpm/action-setup@v4
1213
- uses: actions/setup-node@v4
1314
with:
@@ -21,6 +22,7 @@ jobs:
2122
run: |
2223
PKG_NAME=$(node -p "require('./package.json').name")
2324
PKG_VERSION=$(node -p "require('./package.json').version")
25+
echo "version=${PKG_VERSION}" >> "$GITHUB_OUTPUT"
2426
if npm view "${PKG_NAME}@${PKG_VERSION}" version 2>/dev/null; then
2527
echo "published=true" >> "$GITHUB_OUTPUT"
2628
else
@@ -34,10 +36,20 @@ jobs:
3436
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
3537
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
3638

39+
- name: Ensure git tag exists
40+
if: steps.check.outputs.published == 'false'
41+
run: |
42+
TAG="v${{ steps.check.outputs.version }}"
43+
if ! git rev-parse "${TAG}" >/dev/null 2>&1; then
44+
git tag "${TAG}"
45+
git push origin "${TAG}"
46+
fi
47+
3748
- name: Create GitHub Release
3849
if: steps.check.outputs.published == 'false'
3950
run: |
40-
PKG_VERSION=$(node -p "require('./package.json').version")
41-
gh release create "v${PKG_VERSION}" --generate-notes --title "v${PKG_VERSION}"
51+
TAG="v${{ steps.check.outputs.version }}"
52+
# --verify-tag ensures the tag exists before creating the release
53+
gh release create "${TAG}" --generate-notes --title "${TAG}" --verify-tag
4254
env:
4355
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
name: Unreleased Changes Check
2+
on:
3+
push:
4+
branches: [main]
5+
6+
jobs:
7+
check:
8+
runs-on: ubuntu-latest
9+
steps:
10+
- uses: actions/checkout@v4
11+
with: { fetch-depth: 0 }
12+
13+
- name: Check for unreleased source changes
14+
run: |
15+
PKG_VERSION=$(node -p "require('./package.json').version")
16+
TAG="v${PKG_VERSION}"
17+
18+
# If the tag doesn't exist yet, this is the release commit itself — skip
19+
if ! git rev-parse "${TAG}" >/dev/null 2>&1; then
20+
echo "Tag ${TAG} not found — this push likely IS the release. Skipping."
21+
exit 0
22+
fi
23+
24+
# Count source-file commits since the last release tag
25+
UNRELEASED=$(git log "${TAG}..HEAD" --oneline -- 'src/' | wc -l | tr -d ' ')
26+
27+
if [ "$UNRELEASED" -gt 0 ]; then
28+
echo "::warning::${UNRELEASED} source commits on main since ${TAG} — version has not been bumped."
29+
echo ""
30+
echo "Unreleased commits:"
31+
git log "${TAG}..HEAD" --oneline -- 'src/'
32+
echo ""
33+
echo "Run: bump package.json version, update CHANGELOG.md, push to trigger publish."
34+
else
35+
echo "No unreleased source changes since ${TAG}."
36+
fi

0 commit comments

Comments
 (0)