-
-
Notifications
You must be signed in to change notification settings - Fork 0
113 lines (108 loc) · 4.9 KB
/
Copy pathbump.yml
File metadata and controls
113 lines (108 loc) · 4.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# Auto-release. Two ways in:
# 1. Merge to master (push) -> "auto" bump from conventional commits since the last tag.
# A chore/docs-only merge is a graceful skip (bump.mjs exits 3), so nothing publishes
# unless a feat/fix/perf/breaking change actually landed.
# 2. Actions -> "Bump version" -> Run workflow -> pick auto/patch/minor/major by hand.
#
# Either way scripts/bump.mjs bumps every version field (package.json, package-lock.json,
# both plugin manifests, CITATION.cff, landing page) + rotates CHANGELOG, then this workflow
# commits "chore(release): vX.Y.Z", tags vX.Y.Z, and pushes commit + tag.
#
# Pushing the v* tag is what normally triggers release.yml — but pushes made with the default
# GITHUB_TOKEN deliberately do NOT trigger other workflows (GitHub's recursion guard). So this
# workflow also dispatches release.yml on the new tag explicitly, which needs `actions: write`.
# That same recursion guard is why the release commit this workflow pushes does NOT re-trigger
# the push path below (no infinite loop); the actor/subject guard is belt-and-suspenders.
name: Bump version
on:
push:
branches: [master]
workflow_dispatch:
inputs:
bump:
description: "Bump type (auto = conventional commits since last tag: BREAKING -> major, feat -> minor, else patch)"
type: choice
default: auto
options:
- auto
- patch
- minor
- major
permissions:
contents: write # push the release commit + tag
actions: write # dispatch release.yml on the new tag
concurrency:
group: bump
cancel-in-progress: false
jobs:
# Never tag a tree that fails the FULL quality gate (not just tests) — P0-11.
gate:
if: >-
github.actor != 'github-actions[bot]' &&
!startsWith(github.event.head_commit.message, 'chore(release):')
uses: ./.github/workflows/reusable-quality-gate.yml
bump:
needs: gate
runs-on: ubuntu-latest
# Never react to our own release commit (belt-and-suspenders behind GitHub's recursion guard).
if: >-
github.actor != 'github-actions[bot]' &&
!startsWith(github.event.head_commit.message, 'chore(release):')
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0 # full history + tags so "auto" can read commits since the last tag
- uses: actions/[email protected]
with:
node-version: 22
cache: npm
- run: npm ci
- name: Bump version fields + rotate CHANGELOG
id: bump
# On push, always "auto"; on manual dispatch, honor the chosen input.
env:
BUMP: ${{ github.event_name == 'workflow_dispatch' && inputs.bump || 'auto' }}
run: |
set +e
VERSION="$(node scripts/bump.mjs "$BUMP")"
code=$?
set -e
if [ "$code" -eq 0 ]; then
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
echo "release=true" >> "$GITHUB_OUTPUT"
echo "::notice::Releasing v$VERSION"
elif [ "$code" -eq 3 ]; then
echo "release=false" >> "$GITHUB_OUTPUT"
echo "::notice::Nothing to release (no feat/fix/perf/breaking commits) — skipping."
else
echo "::error::bump.mjs failed (exit $code)"
exit "$code"
fi
- name: Commit, tag, push
if: steps.bump.outputs.release == 'true'
env:
VERSION: ${{ steps.bump.outputs.version }}
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
# Orphan-tag guard: a partial prior run (bump committed + tagged, then the push or a
# later step died) can leave vX.Y.Z already present locally or on origin. `git tag`
# would then die with a bare "fatal: tag 'vX.Y.Z' already exists", wedging EVERY
# future auto-release with a cryptic error. Detect it first and fail with an operator
# runbook instead. We do NOT auto-delete the tag — clobbering a release tag in CI is
# too dangerous; a human must remove the orphan deliberately.
if git rev-parse -q --verify "refs/tags/v$VERSION" >/dev/null 2>&1 \
|| git ls-remote --exit-code --tags origin "refs/tags/v$VERSION" >/dev/null 2>&1; then
echo "::error::Release wedged: tag v$VERSION already exists (orphaned partial run). An operator must delete it: git push origin :refs/tags/v$VERSION, then re-run."
exit 1
fi
git add -A
git commit -m "chore(release): v$VERSION"
git tag -a "v$VERSION" -m "v$VERSION"
git push origin "HEAD:${{ github.ref_name }}" "v$VERSION"
- name: Trigger the release workflow on the new tag
if: steps.bump.outputs.release == 'true'
env:
GH_TOKEN: ${{ github.token }}
VERSION: ${{ steps.bump.outputs.version }}
run: gh workflow run release.yml --ref "v$VERSION"