-
Notifications
You must be signed in to change notification settings - Fork 13
236 lines (214 loc) · 10.3 KB
/
alfa-release.yml
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
# Create a release for the Alfa repos.
#
# WARNING! This workflow pushes to main which **does** trigger other workflow (build, scan, …)
# WARNING! Therefore, there is a risk of creating infinite workflow loops if this workflow is
# WARNING! called from another automated workflow.
# WARNING! Therefore, only ever call this workflow from manual ones (only accepting workflow_dispatch
# WARNING! trigger) to avoid problems.
name: Create a new release (generic workflow)
# This workflow creates and publish a new release of an Alfa repo.
#
# This workflow is intended to work on Alfa repos sharing the same structure for code and release.
# Namely:
# * TypeScript (or ECMAScript) mono-repo, with yarn workspaces in `<prefix>/alfa-*`
# * Default branch on `main`
# * Relying on the `yarn install` / `yarn build` / `yarn test` cycle.
# * Using node_modules for dependencies resolution.
# * Using changeset for storing local changes as they happen.
# * Sharing version number between all packages (`fixed` in changeset config).
# * One CHANGELOG.md per workspace (this is part of changeset)
# * One top-level CHANGELOG.md
# * One `yarn alfa-changelog` command to update the top-level changelog.
# * Packages published on the Github registry (may be public or restricted).
#
# This workflow is likely to fail on any repository that does not have the same structure.
# Use at your own judgement call.
# The github.token of workflows calling this needs
# permissions:
# contents: write <- update the repo with new changelog, …
# packages: write <- actually publish the packages.
# id-token: write <- generate provenance statements, only for public packages.
on:
workflow_call:
inputs:
# Authentication of the user who will commit the changes
# This user must be able to bypass branch protections as it will commit directly to main.
user-name:
required: true
type: string
user-email:
required: true
type: string
generate-documentation:
required: false
type: boolean
default: false
public:
required: false
type: boolean
default: true # Most Alfa repos are public.
npm-publish:
required: false
type: boolean
default: false
secrets:
# A PAT for the user who will commit. Need to have the repo:write permission.
token:
required: true
# Token for NPM publication, must be set up if inputs.npm-publish is true.
npm-token:
required: false
defaults:
run:
shell: bash
jobs:
release:
name: Release
runs-on: ubuntu-latest
steps:
- name: Are we called from `main`?
# New releases should only be created from the main branch of the repo.
# If this workflow is somehow called from another branch, crash.
if: github.ref_name != 'main'
run: exit 1
- uses: actions/checkout@v4
with:
# Only this step needs to be done with the upgraded token, all other actions steps can be done
# with the regular token generated by Github
token: ${{ secrets.token }}
- uses: actions/setup-node@v4
with:
node-version: 20
cache: yarn
registry-url: "https://npm.pkg.github.com"
scope: "@siteimprove"
- name: Configure token for Alfa packages
run: >
yarn config set
npmScopes.siteimprove.npmAuthToken
${{ github.token }}
- name: Install dependencies
run: yarn install --immutable
- name: Install Playwright browsers if needed
# https://playwright.dev/docs/ci-intro
# This is very dirty hacks! We should let callers opt-in for extra setup instead.
run: |
[[ ! -d packages/alfa-playwright ]] || yarn workspace @siteimprove/alfa-playwright playwright install
yarn playwright install || true
- name: Build toolchain if needed
run: |
[[ ! -d packages/alfa-toolchain ]] || yarn build packages/alfa-toolchain
- name: Build global changelog
run: yarn alfa-changelog
env:
GITHUB_TOKEN: ${{ github.token }}
- name: Gather changes and update packages
run: yarn changeset version
env:
GITHUB_TOKEN: ${{ github.token }}
- name: Get new version
# This is needed to push the correct git tag
id: new
run: |
echo "version=$(grep \"version\": */alfa-*/package.json | cut -d\" -f 4 | sort -u)" >> $GITHUB_OUTPUT
- name: Run post version scripts
# yarn is deliberately low on lifecycle scripts and does not include a postversion one.
# See https://yarnpkg.com/advanced/lifecycle-scripts
# We therefore do it manually and rely on yarn workspaces ignoring non-existent scripts.
# We also name our script differently to avoid problems in case npm is ever used and
# triggers the hooks.
run: yarn workspaces foreach --all --no-private --topological-dev run alfa-postversion
- name: Hack around toplevel dependencies
# https://github.com/changesets/changesets/issues/1229
# Need to unescape the sed string to interpret ${VERSION} and re-escape it again.
run: sed -i 's/workspace:^[0-9\.]*/workspace:^'${VERSION}'/' package.json
env:
# Passing it as a variable rather than inline hardens against script injection.
# See https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions#using-an-intermediate-environment-variable
VERSION: ${{ steps.new.outputs.version }}
- name: Update lockfile
# Cross-workspaces references need to be updated.
run: yarn install --no-immutable && yarn dedupe
- name: Verify changes
run: yarn build && yarn test
- name: Set up git config
# We need a user able to bypass branch protection (i.e. admin on the repo).
run: |
git config --local core.filemode false
git config --local user.name "${{ inputs.user-name }}"
git config --local user.email "${{ inputs.user-email }}"
- name: Generate documentation
if: inputs.generate-documentation
run: |
yarn extract
yarn document
git add docs/api
- name: Commit and push changes
# If we made it thus far, we can commit the changes
# We need to take care to **not** commit .yarnrc.yml which has been updated with a token.
run: |
# Removed individual changesets, all changelog (global and local), all package.json (new version number), lockfile
git add .changeset/ CHANGELOG.md **/CHANGELOG.md package.json **/package.json yarn.lock
git commit -m ${VERSION}
git tag --annotate ${VERSION} --message=${VERSION}
git push --follow-tags
env:
# Passing it as a variable rather than inline hardens against script injection.
# See https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions#using-an-intermediate-environment-variable
VERSION: v${{ steps.new.outputs.version }}
- name: Pack packages
# We use yarn for preparing the packs, but npm for actually uploading them and publishing them.
# This is because npm poorly handles the "workspace:" protocol which yarn supports.
# On the other hand, npm is more flexible in its options for overwriting config file,
# and can generate provenance statements.
#
# It seems that in some cases npm builds its metadata from the package.json file, and not from the
# tarball, and thus adds wrong dependencies to "workspace:…" versions that do not exist.
# Packing in a separate directory forces npm to use the tarball for metadata.
#
# This was witnessed with npm 10.7.0 in the CI/CD pipeline, but could not be reproduced
# locally with the same npm version. npm may change its behaviour, in which case we
# could switch do simply use npm for pack+publish, i.e. do
# yarn workspaces foreach <options> exec npm publish <options>
# Alternatively, if yarn let us overwrite @siteimprove:registry in the CLI, and generate provenance
# statements, we could use yarn for the whole process:
# yarn workspaces foreach <options> run npm publish <options>
run: |
mkdir ${{ github.workspace }}/artifacts
yarn workspaces foreach --all --no-private --topological-dev pack --out ${{ github.workspace }}/artifacts/%s-%v.tgz
- name: Set token for npm publication (Github package registry)
run: npm config set //npm.pkg.github.com/:_authToken=${{ github.token }}
- name: Make npm release (Github Packages Registry / public)
if: inputs.public
run: >
for package in ${{ github.workspace }}/artifacts/@siteimprove-*.tgz; do
npm publish ${package} --tolerate-republish --provenance --tag latest;
done
- name: Make npm release (Github Packages Registry / private)
if: ${{ ! inputs.public }}
run: >
for package in ${{ github.workspace }}/artifacts/@siteimprove-*.tgz; do
npm publish ${package} --tolerate-republish --tag latest;
done
- name: Set token for npm publication (npm registry)
if: inputs.npm-publish
run: npm config set //registry.npmjs.org/:_authToken=${{ secrets.npm-token }}
- name: Make npm release (npm Packages Registry)
# Overwrite the registry with a CLI option, thus leaving the package.json files untouched.
if: inputs.npm-publish
run: >
for package in ${{ github.workspace }}/artifacts/@siteimprove-*.tgz; do
npm publish ${package} --tolerate-republish --provenance --tag latest --@siteimprove:registry="https://registry.npmjs.org/";
done
- name: Make Github release
run: >
gh release create ${VERSION}
--prerelease
--verify-tag
--title ${VERSION}
--notes "[Changelog for this release](CHANGELOG.md)"
env:
GH_TOKEN: ${{ github.token }}
# Passing it as a variable rather than inline hardens against script injection.
# See https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions#using-an-intermediate-environment-variable
VERSION: v${{ steps.new.outputs.version }}