-
Notifications
You must be signed in to change notification settings - Fork 0
293 lines (269 loc) · 12.9 KB
/
Copy pathrelease.yaml
File metadata and controls
293 lines (269 loc) · 12.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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
name: Release
# Per-package release pipeline. Each publishable package (opted in via
# `"greasyforkPublish": true` in its own package.json) owns its version in its
# own package.json and its own CHANGELOG.md; packages that are not opted in
# (e.g. the `template`/`_template` scaffolding packages) are simply never
# touched here.
#
# On a pull request: PREVIEW ONLY. Computes the patch bump each changed package
# would receive on merge and posts it as a sticky comment. Nothing is committed
# to the PR branch - bumping inside PR branches produces constant cross-PR
# conflicts on the same version lines.
#
# On push to main: the SOLE place bumps are committed. One job runs
# release-it per changed package, makes the bump commit, and does ONE atomic
# push of that commit plus the release tags. Doing the bump, the lint and the
# tag move in a single push is what stops a bump from triggering a follow-up
# lint/format commit that would trigger another bump.
#
# A second commit, stacked on top of the bump commit but never merged into
# main, adds the built .user.js files to git at their normal
# packages/<pkg>/dist/ path (no flat root-level mirror needed - see below).
# Tagging that commit as the release tag, and moving the floating `latest`
# tag onto it, gives GreasyFork a git ref it can read the real nested path
# from, without ever putting build artifacts in main's history.
#
# Each package's @downloadURL/@updateURL points at
# https://raw.githubusercontent.com/<org>/<repo>/latest/packages/<pkg>/dist/script.user.js.
# On GreasyFork's "release published" webhook, it strips the domain+org+repo
# prefix from that URL, then discards exactly one more path segment as the
# ref (see lib/github.rb#file_from_root_for_url in GreasyFork's source) -
# here that's the `latest` segment - leaving `packages/<pkg>/dist/script.user.js`
# as the real git path, which it then reads with `git show <release-tag>:<path>`
# (a server-side git operation, not an HTTP fetch of the stored URL - the
# `latest` segment is never itself dereferenced by that fetch, only by other
# tools like Tampermonkey polling @updateURL directly). Since the dist commit
# already places the file at that exact nested path, no flat mirror or
# release-asset upload is needed.
on:
push:
branches: [main]
pull_request:
workflow_dispatch:
inputs:
from_sha:
description: "commit sha from...HEAD to bump against (overrides the release/last-run tag)"
required: false
default: ""
type: string
concurrency:
group: ${{ github.ref == 'refs/heads/main' && 'release-main' || format('release-{0}', github.ref) }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
jobs:
version-preview:
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ github.head_ref }}
fetch-depth: 0
- name: Fetch base branch
env:
BASE_REF: ${{ github.base_ref }}
run: git fetch origin "$BASE_REF":refs/remotes/origin/"$BASE_REF"
- uses: jdx/mise-action@3c2e0cf82a5b2e5249f0d3635a4d83d0ae861518 # v4.2.5
with:
install: true
cache: true
- name: Install dependencies
run: yarn install --immutable
- name: Compute version bump preview
id: bump
env:
BASE_REF: ${{ github.base_ref }}
run: |
# Diff against the PR base branch so only THIS PR's changes count.
# Using release/last-run here would be wrong: if main has advanced
# past that tag, the diff would sweep in other merged PRs' changes.
OUTPUT=$(./scripts/auto-bump-packages.sh \
"--change-base=origin/$BASE_REF" "--version-base=$BASE_REF" --preview)
{
echo "report-md<<REPORT_MD_EOF"
echo "$OUTPUT" | jq -r '.report_md'
echo "REPORT_MD_EOF"
} >> "$GITHUB_OUTPUT"
- name: Post version preview comment
uses: marocchino/sticky-pull-request-comment@5770ad5eb8f42dd2c4f34da00c94c5381e49af88 # v3.0.5
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
header: package-versions
message: |
### Userscript Version Preview
_Preview only — versions and CHANGELOGs are bumped automatically on merge to `main`, **not** in this PR. Manual bumps to a higher version are preserved._
${{ steps.bump.outputs.report-md }}
release:
if: (github.event_name == 'push' && github.ref == 'refs/heads/main') || github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout as automation bot
id: auth
# This action doesn't publish version tags, so we pin it to a
# specific commit instead of the main branch - same as every other
# action in this workflow. It matters most here, since this step
# creates a GitHub App token with write access to this repo.
uses: nsheaps/github-actions/.github/actions/checkout-as-app@c1794f6f4fbb3cbc5e5a71e820581a74239f706a
with:
app-id: ${{ secrets.AUTOMATION_GITHUB_APP_ID }}
private-key: ${{ secrets.AUTOMATION_GITHUB_APP_PRIVATE_KEY }}
fetch-depth: 0
- name: Resolve base ref
id: resolve-base
env:
FROM_SHA: ${{ inputs.from_sha }}
run: |
# release/last-run is a moving marker pointing at the commit released
# by the previous successful run. Package change detection diffs
# against it, which is what makes "did this package change since we
# last released it" answerable when several packages are versioned
# independently and no single repo-wide version exists.
TAG_NAME="release/last-run"
if [ -n "$FROM_SHA" ]; then
echo "base-ref=$FROM_SHA" >> "$GITHUB_OUTPUT"
elif git rev-parse "$TAG_NAME" >/dev/null 2>&1; then
echo "base-ref=$TAG_NAME" >> "$GITHUB_OUTPUT"
else
echo "base-ref=HEAD~1" >> "$GITHUB_OUTPUT"
echo "'$TAG_NAME' not found (first run), falling back to HEAD~1"
fi
- uses: jdx/mise-action@3c2e0cf82a5b2e5249f0d3635a4d83d0ae861518 # v4.2.5
with:
install: true
cache: true
- name: Install dependencies
run: yarn install --immutable
- name: Bump changed packages
id: bump
env:
BASE_REF: ${{ steps.resolve-base.outputs.base-ref }}
run: |
OUTPUT=$(./scripts/auto-bump-packages.sh \
"--change-base=$BASE_REF" "--version-base=$BASE_REF")
echo "has-bumps=$(echo "$OUTPUT" | jq -r '.has_bumps')" >> "$GITHUB_OUTPUT"
echo "bumps=$(echo "$OUTPUT" | jq -c '.bumps')" >> "$GITHUB_OUTPUT"
{
echo "report-md<<REPORT_MD_EOF"
echo "$OUTPUT" | jq -r '.report_md'
echo "REPORT_MD_EOF"
} >> "$GITHUB_OUTPUT"
- name: Lint after bump
if: steps.bump.outputs.has-bumps == 'true'
run: yarn run lint
- name: Commit bumps
id: commit
if: steps.bump.outputs.has-bumps == 'true'
env:
GIT_AUTHOR_NAME: ${{ steps.auth.outputs.user-name }}
GIT_AUTHOR_EMAIL: ${{ steps.auth.outputs.user-email }}
GIT_COMMITTER_NAME: ${{ steps.auth.outputs.user-name }}
GIT_COMMITTER_EMAIL: ${{ steps.auth.outputs.user-email }}
run: |
set -euo pipefail
git add packages/*/package.json packages/*/CHANGELOG.md
# A run consisting only of already-bumped packages has nothing to
# stage - the human's bump is already committed - but still needs a
# release cut below, so an empty diff here is not an error.
if git diff --cached --quiet; then
echo "No version/changelog changes to commit (all packages were already bumped)"
else
# [skip ci] keeps this bump commit from re-triggering this workflow.
git commit -m "chore(release): bump userscript versions [skip ci]"
fi
echo "bump-sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"
- name: Build bumped packages
if: steps.bump.outputs.has-bumps == 'true'
run: yarn run build
- name: Commit built userscripts for GreasyFork sync
id: dist-commit
if: steps.bump.outputs.has-bumps == 'true'
env:
GIT_AUTHOR_NAME: ${{ steps.auth.outputs.user-name }}
GIT_AUTHOR_EMAIL: ${{ steps.auth.outputs.user-email }}
GIT_COMMITTER_NAME: ${{ steps.auth.outputs.user-name }}
GIT_COMMITTER_EMAIL: ${{ steps.auth.outputs.user-email }}
run: |
set -euo pipefail
# dist/ is gitignored for normal development. Force-add just the
# built files GreasyFork needs to read via `git show`.
for pkg_dir in packages/*/; do
pkg_name="$(basename "$pkg_dir")"
pjson="${pkg_dir}package.json"
[ -f "$pjson" ] || continue
opted_in="$(node -pe "require('./$pjson').greasyforkPublish === true" 2>/dev/null || echo false)"
[ "$opted_in" = "true" ] || continue
src="packages/${pkg_name}/dist/script.user.js"
if [ ! -f "$src" ]; then
echo "::error::greasyforkPublish is set for $pkg_name but $src is missing after build"
exit 1
fi
git add -f "$src"
done
git commit -m "chore(release): include built userscripts for GreasyFork sync [skip ci]"
echo "dist-sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"
- name: Tag release
id: tag
if: steps.bump.outputs.has-bumps == 'true'
env:
GIT_AUTHOR_NAME: ${{ steps.auth.outputs.user-name }}
GIT_AUTHOR_EMAIL: ${{ steps.auth.outputs.user-email }}
GIT_COMMITTER_NAME: ${{ steps.auth.outputs.user-name }}
GIT_COMMITTER_EMAIL: ${{ steps.auth.outputs.user-email }}
run: |
set -euo pipefail
# One immutable tag per release run, carrying the GitHub Release the
# userscripts' @downloadURL/@updateURL resolve through. It points at
# the dist commit (not main), so it carries the built files.
#
# JUDGEMENT CALL: one shared release per run, not one per package.
# Every published script's @downloadURL points at the stable
# .../latest/packages/<pkg>/dist/script.user.js path. Per-package
# tags would make "latest" ambiguous - whichever package released
# most recently would win, and the other scripts' download URLs
# would resolve to a release commit that predates their own most
# recent build. Moving "latest" onto every dist commit (not just
# ones with bumps for that package - the dist commit above rebuilds
# every greasyforkPublish package) keeps every script's download URL
# resolvable. Per-package provenance is not lost: each package
# keeps its own version in its package.json and its own
# CHANGELOG.md.
RELEASE_TAG="release/$(date -u +%Y%m%d-%H%M%S)"
git tag -a "$RELEASE_TAG" -m "Release $RELEASE_TAG"
# Floating tag every package's @downloadURL/@updateURL resolves
# through (raw.githubusercontent.com/<org>/<repo>/latest/...) so
# each script's URL never has to change again.
git tag -f "latest" HEAD
# release/last-run stays on the bump commit (not the dist commit) -
# it's the base the NEXT run diffs source changes against.
git tag -f "release/last-run" "${{ steps.commit.outputs.bump-sha }}"
echo "release-tag=$RELEASE_TAG" >> "$GITHUB_OUTPUT"
- name: Push commit and tags
if: steps.bump.outputs.has-bumps == 'true'
run: |
set -euo pipefail
# main only fast-forwards to the bump commit - the dist commit
# stacked on top of it is pushed solely as tags, never as a branch
# update, so main's history never gains build artifacts.
git push --atomic origin \
"${{ steps.commit.outputs.bump-sha }}:refs/heads/main" \
"refs/tags/${{ steps.tag.outputs.release-tag }}" \
"+refs/tags/latest" \
"+refs/tags/release/last-run"
- name: Create the GitHub Release
if: steps.bump.outputs.has-bumps == 'true'
env:
GH_TOKEN: ${{ steps.auth.outputs.token }}
RELEASE_TAG: ${{ steps.tag.outputs.release-tag }}
REPORT_MD: ${{ steps.bump.outputs.report-md }}
run: |
set -euo pipefail
printf '%s\n' "$REPORT_MD" > /tmp/release-notes.md
gh release create "$RELEASE_TAG" \
--repo "${{ github.repository }}" \
--title "$RELEASE_TAG" \
--notes-file /tmp/release-notes.md \
--latest