-
Notifications
You must be signed in to change notification settings - Fork 0
165 lines (154 loc) · 7.16 KB
/
Copy pathpush.yml
File metadata and controls
165 lines (154 loc) · 7.16 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
name: Check and release
# What lands on main gets checked, and if it changed anything that ships, it gets
# a version and a release without anybody remembering to tag.
#
# WHY THIS EXISTS
#
# Releasing was `pnpm version patch && git push --follow-tags`, run by hand. It
# was run twice in the life of this repo, and one of those produced nothing
# because the release workflow was broken. Meanwhile the tap served a tarball
# from a tag nobody had rebuilt since, so an install predated `assets/` being
# published and showed blank cards on the New video page.
#
# Nothing checked a push either: the gate ran only inside the tag workflow, so
# main could go red and stay red until somebody cut a release.
#
# WHAT IT DOES
#
# 1. Runs the gate on every push to main (check:ci — see the step for what
# it leaves out and why).
# 2. If the gate passes AND the push changed something that ships, bumps the
# patch version, commits it, and pushes the tag.
# 3. release.yml sees the tag and does the publishing.
#
# The version bump is a real commit on main. That is deliberate: package.json is
# what `sync-tap` and the Studio's own version line read, so a tag without it
# would leave three places disagreeing about what is installed.
on:
push:
branches: [main]
permissions:
contents: write
packages: read
# A second push while one is mid-release would race on the tag. Queue rather than
# cancel: the first run may already have tagged, and cancelling it half way is how
# you get a tag with no release behind it.
concurrency:
group: release-main
cancel-in-progress: false
jobs:
check:
name: The gate
runs-on: ubuntu-latest
env:
# setup-node writes this placeholder into the npm config. Keep the token
# available for every pnpm step, not only install, so the runner does not
# report a missing registry credential while it runs the gate.
NODE_AUTH_TOKEN: ${{ secrets.ROLEMODEL_PACKAGE_REPO_READ_TOKEN || github.token }}
# Keep the gate against the same OpenScreen version the tag workflow
# verifies. This repository owns the source tokens; the app owns the
# generated CSS that consumes them.
OPENSCREEN_REF: v0.0.2
OPENSCREEN_ROOT: /tmp/openscreen
steps:
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v6
with: { version: 11.20.0 }
- uses: actions/setup-node@v7
with:
node-version: "24"
cache: "pnpm"
scope: "@rolemodel"
registry-url: "https://npm.pkg.github.com"
# The frozen pnpm lock keeps CI on the exact dependency graph contributors use.
# needs the dev ones the checks use.
- run: pnpm install --frozen-lockfile
- run: pnpm exec playwright install --with-deps chromium
- name: Check out OpenScreen for app-side token checks
run: git clone --depth 1 --branch "$OPENSCREEN_REF" https://github.com/RoleModel/openscreen.git "$OPENSCREEN_ROOT"
# This output belongs to the app checkout, not this toolkit. Generate it
# in the pinned temporary checkout before checking the complete gate.
- name: Generate the OpenScreen Optics token layer
run: node lib/optics-tokens.mjs --openscreen "$OPENSCREEN_ROOT"
# `check:ci`, not `check`.
#
# The full gate ends with sync-tap:check and sync-docs:check, and both
# compare this repo against a SIBLING checkout — the Homebrew tap and the
# fork's website. Neither exists on a runner, so both exit 1 and the gate
# would fail on every push for a reason that has nothing to do with the
# push. Those two are about cross-repo publication and are checked where
# publication happens: release.yml for the tap, the fork's own Docs
# workflow for the site.
- run: pnpm run check:ci
release:
name: Version and tag
needs: check
runs-on: ubuntu-latest
# Three ways not to release, all of them deliberate:
#
# - the bot's own version commit, or main would release itself forever
# - a commit that says not to
# - a push that changed nothing anybody installs
#
# The last is checked in the step below rather than with `paths:` on the
# trigger, because the gate should run on every push even when the release
# does not.
if: >-
github.actor != 'github-actions[bot]'
&& !contains(github.event.head_commit.message, '[skip release]')
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
persist-credentials: true
# This job runs no checks, so it installs nothing — but the bump below is
# `pnpm version`, and a bare runner has no pnpm on PATH. Without this the
# job died at `pnpm: command not found` after the gate had already passed,
# which reads as a failed release of a perfectly good commit.
- uses: pnpm/action-setup@v6
with: { version: 11.20.0 }
- uses: actions/setup-node@v7
with:
node-version: "24"
- name: Did anything that ships change?
id: shipped
run: |
# The same directories package.json publishes, plus the manifest
# itself. Docs, CI and the verify suite are not installed by anybody,
# so a change to them is not a release — it would put a version number
# on a tarball identical to the one before it.
BEFORE="${{ github.event.before }}"
if [ -z "$BEFORE" ] || [ "$BEFORE" = "0000000000000000000000000000000000000000" ]; then
BEFORE="$(git rev-parse HEAD~1 2>/dev/null || git rev-parse HEAD)"
fi
CHANGED="$(git diff --name-only "$BEFORE" HEAD -- assets bin lib presets brand components skill package.json || true)"
# lib/verify.mjs is the suite, not the product. A push that only moves
# assertions is not a new version of anything.
CHANGED="$(printf '%s\n' "$CHANGED" | grep -v '^lib/verify\.mjs$' || true)"
if [ -z "$CHANGED" ]; then
echo "nothing that ships changed — no release"
echo "go=no" >> "$GITHUB_OUTPUT"
else
echo "$CHANGED"
echo "go=yes" >> "$GITHUB_OUTPUT"
fi
- name: Bump, commit and tag
if: steps.shipped.outputs.go == 'yes'
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
# If package.json already names a version with no tag, that version is
# the release and nothing needs bumping — which is how a deliberate
# `pnpm version minor` on a branch reaches main and means what it says.
CURRENT="$(node -p "require('./package.json').version")"
if git rev-parse "v$CURRENT" >/dev/null 2>&1; then
pnpm version patch --no-git-tag-version >/dev/null
CURRENT="$(node -p "require('./package.json').version")"
git add package.json pnpm-lock.yaml
git commit -m "v$CURRENT [skip release]"
git push origin HEAD:main
fi
git tag -a "v$CURRENT" -m "v$CURRENT"
# The tag is what release.yml watches; pushing it is the whole handover.
git push origin "v$CURRENT"
echo "tagged v$CURRENT"