11# https://help.github.com/en/categories/automating-your-workflow-with-github-actions
22# See: https://github.com/JulianCataldo/gh-actions
33
4- # For matrix setup:
5- # https://github.com/withastro/astro/blob/main/.github/workflows/ci.yml
6- # https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/running-variations-of-jobs-in-a-workflow
7-
84name : CI / Release
95
106on :
@@ -23,227 +19,141 @@ on:
2319 - beta
2420 - ' feat/*'
2521 - ' fix/*'
26- # - to-integrate
27- # - to-integrate-next
2822
2923permissions :
30- contents : read # for checkout
24+ contents : read
25+
26+ concurrency :
27+ group : ci-release-${{ github.workflow }}-${{ github.ref }}
28+ cancel-in-progress : true
29+
30+ env :
31+ NODE_VERSION : 24
3132
3233jobs :
3334 release :
3435 name : CI / Release
35-
36- permissions :
37- contents : write # to be able to publish a GitHub release
38- issues : write # to be able to comment on released issues
39- pull-requests : write # to be able to comment on released pull requests
40- id-token : write # to enable use of OIDC for npm provenance
41-
42- timeout-minutes : 30
43-
4436 runs-on : ubuntu-latest
45- # TODO:
46- # runs-on: ${{ matrix.os }}
47- # timeout-minutes: 25
48- # # needs: build
49- # strategy:
50- # matrix:
51- # OS: [ubuntu-latest]
52- # NODE_VERSION: [18, 20]
53- # include:
54- # - os: macos-14
55- # NODE_VERSION: 18
56- # - os: windows-latest
57- # NODE_VERSION: 18
58- # fail-fast: false
59- # env:
60- # NODE_VERSION: ${{ matrix.NODE_VERSION }}
37+ timeout-minutes : 30
38+ permissions :
39+ contents : write
40+ issues : write
41+ pull-requests : write
42+ id-token : write
6143
6244 steps :
63- # MARK: Setup GH Action
64-
65- - name : ' Harden Runner'
66- uses : ' step-security/harden-runner@a90bcbc6539c36a85cdfeb73f7e2f433735f215b' # v2.15.0
45+ - name : Harden runner
46+ uses : step-security/harden-runner@a90bcbc6539c36a85cdfeb73f7e2f433735f215b # v2.15.0
6747 with :
68- egress-policy : ' audit'
48+ egress-policy : audit
6949
7050 - name : Git checkout
7151 uses : actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
72- # run: git fetch --depth=1 origin +refs/tags/*:refs/tags/*
7352 with :
7453 fetch-depth : 0
7554
76- # - run: git fetch --depth=1 origin +refs/tags/*:refs/tags/*
77- # persist-credentials: false
78- # env:
79- # GIT_COMMITTER_NAME: "GitHub Actions Shell"
80- # GIT_AUTHOR_NAME: "GitHub Actions Shell"
81- # EMAIL: "github-actions[bot]@users.noreply.github.com"
82-
83- # MARK: Setup Node env.
84-
8555 - name : Setup PNPM
8656 uses : pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0
8757
88- - name : Use Node.js 24
58+ - name : Use Node.js ${{ env.NODE_VERSION }}
8959 uses : actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
9060 with :
91- registry-url : ' https://registry.npmjs.org'
92- node-version : 24
61+ registry-url : https://registry.npmjs.org
62+ node-version : ${{ env.NODE_VERSION }}
9363 cache : pnpm
9464
9565 - name : Install packages
96- shell : bash
9766 run : pnpm install --frozen-lockfile
9867
99- # TODO: More tests
100- # - name: Syncpack Lint
101- # shell: bash
102- # run: node --run syncpack:lint
103-
104- # NOTE: Audit is for prod only because a lot of root packages (like lerna etc.)
105- # are used old packages with intricate dependency trees, and they are
106- # never shipped to the user. But that's not 100% optimal, as devDeps could
107- # provoke some sec issues, too? A middleground is better than nothing and
108- # regularly blocked releases for obscure root mono-repo tooling deps.
109- - name : ' Verify the integrity of provenance attestations and registry
110- signatures for installed [prod] dependencies'
68+ - name : Verify installed prod dependency attestations
11169 run : node --run audit
11270
113- # MARK: Lint/Checks pre-build
114-
115- # TODO: Setup Husky etc.
116- # - name: Lint last commit — Commitlint
117- # shell: bash
118- # run: node --run lint:commit
119-
120- # - name: Lint CSS — Stylelint
121- # shell: bash
122- # run: node --run lint:css
123-
124- - name : Check all formatting — Prettier
125- shell : bash
126- run : node --run format
127-
128- # MARK: Build packages
129-
13071 - name : Setup Turbo cache
13172 uses : dtinth/setup-github-actions-caching-for-turbo@cc723b4600e40a6b8815b65701d8614b91e2669e # v1.3.0
13273
133- - name : Build all packages
134- shell : bash
135- run : node --run build
74+ - name : Clean build outputs
75+ run : node --run clean
13676
137- # MARK: Lint/Checks post-build
77+ - name : Build packages
78+ run : node --run build
13879
13980 - name : Cache ESLint results
14081 uses : actions/cache@v4
14182 with :
14283 path : .eslintcache
143- key : eslint-${{ hashFiles('pnpm-lock.yaml', 'eslint.config.js') }}
84+ key : eslint-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml', 'eslint.config.js') }}
14485
145- - name : Lint JS/TS — ESLint
146- shell : bash
86+ - name : Lint JS and TS
14787 run : node --run lint:es
14888
149- # MARK:Tests
89+ - name : Lint CSS
90+ run : node --run lint:style
15091
151- - name : Tests — Units
152- shell : bash
153- run : node --run test:unit
92+ - name : Check formatting
93+ run : node --run format
15494
155- # - name: Tests — Integration
156- # shell: bash
157- # run: node --run test:integration
95+ - name : Tests - units
96+ run : node --run test:unit
15897
159- # TODO: Build and launch example-app
160- # - name: Tests — E2E
161- # shell: bash
162- # run: node --run test:e2e
98+ - name : Cache Playwright browsers
99+ uses : actions/cache@v4
100+ with :
101+ path : ~/.cache/ms-playwright
102+ key : playwright-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
163103
164- # MARK: Publish packages
104+ - name : Install Playwright browsers
105+ working-directory : e2e
106+ run : pnpm exec playwright install --with-deps chromium
165107
166- # NOTE: Auth is configured by setup-node's registry-url above.
167- # The NPM_TOKEN secret MUST be a Granular Access Token (or classic Automation
168- # token) to bypass 2FA/OTP requirements in CI.
108+ - name : Tests - E2E
109+ run : node --run test:e2e
169110
170111 - name : Git user configuration
112+ if : github.ref == 'refs/heads/main' || github.ref == 'refs/heads/next'
171113 run : |
172114 git config --global user.name "${{ github.actor }}"
173115 git config --global user.email "${{ github.actor }}@users.noreply.github.com"
174116
175- # MARK: [MAIN]
176- # --force-git-tag: a prior interrupted CI run may have left orphan tags
177- # (e.g. @jsfe/engine@0.5.0) that collide with graduation.
178- - name : ' Lerna publish [main]'
179- # if: github.ref == 'refs/heads/to-integrate'
117+ - name : Publish [main]
180118 if : github.ref == 'refs/heads/main'
181- # https://github.com/lerna/lerna/issues/2532
182119 id : graduateRelease
183120 continue-on-error : true
184121 env :
185- GH_TOKEN : ' ${{ secrets.GITHUB_TOKEN }}'
186- NODE_AUTH_TOKEN : ' ${{ secrets.NPM_TOKEN }}'
122+ GH_TOKEN : ${{ secrets.GITHUB_TOKEN }}
123+ NODE_AUTH_TOKEN : ${{ secrets.NPM_TOKEN }}
187124 NPM_CONFIG_PROVENANCE : ' true'
188125 run : |
189- pnpm lerna publish --message 'chore: publish [main] release [skip ci]' --create-release=github --conventional-graduate --force-git-tag --yes
190-
191- # Fallback for https://github.com/lerna/lerna/issues/2532 (newly introduced
192- # packages that fail --conventional-graduate). Fail explicitly if neither
193- # the graduate nor the fallback actually published anything.
194- - name : ' Lerna publish [main] — fallback (non-graduate)'
195- if : ${{ always() && github.ref == 'refs/heads/main' &&
196- steps.graduateRelease.outcome == 'failure' }}
126+ pnpm exec lerna publish --message 'chore: publish [main] release [skip ci]' --create-release=github --conventional-graduate --force-git-tag --yes
127+
128+ - name : Publish [main] fallback
129+ if : ${{ always() && github.ref == 'refs/heads/main' && steps.graduateRelease.outcome == 'failure' }}
197130 env :
198- GH_TOKEN : ' ${{ secrets.GITHUB_TOKEN }}'
199- NODE_AUTH_TOKEN : ' ${{ secrets.NPM_TOKEN }}'
131+ GH_TOKEN : ${{ secrets.GITHUB_TOKEN }}
132+ NODE_AUTH_TOKEN : ${{ secrets.NPM_TOKEN }}
200133 NPM_CONFIG_PROVENANCE : ' true'
201134 run : |
202- echo "Graduate publish failed — attempting recovery"
135+ echo "Graduate publish failed - attempting recovery"
203136 git stash || true
204137
205- # Recovery 1: from-package (handles Sigstore/Rekor TLOG_CREATE_ENTRY_ERROR 409)
206- # Queries npm directly and publishes any package versions not yet in the registry,
207- # regardless of git tags — safe to run even if some packages are already published.
208138 echo "==> from-package: recovering partial publish"
209- FROM_PKG_OUT=$(pnpm lerna publish from-package --yes 2>&1)
139+ FROM_PKG_OUT=$(pnpm exec lerna publish from-package --yes 2>&1)
210140 FROM_PKG_EXIT=$?
211141 echo "$FROM_PKG_OUT"
212142
213- # Recovery 2: non-graduate lerna publish (handles lerna#2532: newly introduced
214- # packages that have no pre-release version to graduate from).
215143 echo "==> non-graduate: publishing new or changed packages"
216- OUTPUT=$(pnpm lerna publish --message 'chore: publish [main] release [skip ci]' --create-release=github --yes 2>&1) || true
144+ OUTPUT=$(pnpm exec lerna publish --message 'chore: publish [main] release [skip ci]' --create-release=github --yes 2>&1) || true
217145 echo "$OUTPUT"
218146
219- # Fail explicitly only when BOTH approaches published nothing useful.
220147 if [ "$FROM_PKG_EXIT" -ne 0 ] && echo "$OUTPUT" | grep -q 'No changed packages to publish'; then
221148 echo "::error::Neither from-package nor conventional fallback published anything"
222149 exit 1
223150 fi
224151
225- # # TRY: https://www.jessesquires.com/blog/2021/10/17/github-actions-workflows-for-automatic-rebasing-and-merging/
226- # - name: Merge (rebase) back main into next
227- # env:
228- # GH_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
229- # run: |
230- # git checkout next
231- # git rebase main
232- # git push
233-
234- # MARK: [NEXT]
235- - name : ' Lerna publish [next]'
152+ - name : Publish [next]
236153 if : github.ref == 'refs/heads/next'
237- # if: github.ref == 'refs/heads/to-integrate-next'
238154 env :
239- GH_TOKEN : ' ${{ secrets.GITHUB_TOKEN }}'
240- NODE_AUTH_TOKEN : ' ${{ secrets.NPM_TOKEN }}'
155+ GH_TOKEN : ${{ secrets.GITHUB_TOKEN }}
156+ NODE_AUTH_TOKEN : ${{ secrets.NPM_TOKEN }}
241157 NPM_CONFIG_PROVENANCE : ' true'
242-
243- # --canary next
244- # https://github.com/lerna/lerna/issues/1433
245- # pnpm lerna publish --conventional-prerelease --dist-tag=next --preid=next --no-changelog --yes
246- # pnpm lerna publish --conventional-prerelease --pre-dist-tag=next --preid=next --yes
247- # pnpm lerna publish --force-publish='*' --canary --pre-dist-tag=next --preid=next --yes
248158 run : |
249- pnpm lerna publish --message 'chore: publish [next] pre-release' --conventional-prerelease --pre-dist-tag=next --preid=next --yes
159+ pnpm exec lerna publish --message 'chore: publish [next] pre-release' --conventional-prerelease --pre-dist-tag=next --preid=next --yes
0 commit comments