Skip to content

Commit 8eb34c8

Browse files
committed
improve github workflows
1 parent 000b4aa commit 8eb34c8

File tree

2 files changed

+166
-18
lines changed

2 files changed

+166
-18
lines changed

.github/workflows/release.yml

Lines changed: 135 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,153 @@
11
name: Release
22

33
on:
4-
release:
5-
types: [published]
4+
workflow_dispatch:
5+
inputs:
6+
version:
7+
description: "Version to publish"
8+
required: true
9+
dry_run:
10+
description: "Perform a dry run without publishing"
11+
type: boolean
12+
required: false
13+
default: true
14+
15+
concurrency:
16+
group: npm-publish-${{ github.repository }}
17+
cancel-in-progress: false
618

719
jobs:
820
release:
921
name: Release workflow
10-
1122
runs-on: ubuntu-latest
1223

24+
permissions:
25+
contents: read
26+
id-token: write # Required for OIDC trusted publishing
27+
1328
steps:
14-
- uses: actions/checkout@v4
29+
- name: Validate GitHub release and tag exists
30+
env:
31+
GH_TOKEN: ${{ github.token }}
32+
run: |
33+
TAG="v${{ inputs.version }}"
34+
echo "Looking for release with tag $TAG..."
35+
36+
RELEASE=$(gh release view "$TAG" --repo ${{ github.repository }} --json tagName,name 2>/dev/null)
37+
if [ $? -ne 0 ]; then
38+
echo "❌ No GitHub release found with tag $TAG"
39+
exit 1
40+
fi
41+
42+
RELEASE_NAME=$(echo "$RELEASE" | jq -r '.name')
43+
if [ "$RELEASE_NAME" != "$TAG" ]; then
44+
echo "❌ Release name '$RELEASE_NAME' does not match expected '$TAG'"
45+
exit 1
46+
fi
47+
48+
echo "✅ GitHub release '$RELEASE_NAME' confirmed"
49+
50+
- name: Checkout tag
51+
uses: actions/checkout@v4
52+
with:
53+
ref: "v${{ inputs.version }}"
54+
fetch-depth: 0
55+
56+
- name: Ensure tag commit is on master
57+
run: |
58+
if ! git branch -r --contains "$(git rev-parse HEAD)" | grep -q "origin/master"; then
59+
echo "❌ Tag is not based on master branch"
60+
exit 1
61+
fi
62+
echo "✅ Tag commit is on master"
1563
1664
- name: Setup Node.js
1765
uses: actions/setup-node@v4
1866
with:
19-
node-version: '22.x'
20-
registry-url: 'https://registry.npmjs.org/'
67+
node-version: "22.x"
68+
registry-url: "https://registry.npmjs.org/"
2169

22-
- name: Install
23-
run: yarn --frozen-lockfile --non-interactive
70+
- name: Enable Corepack
71+
run: corepack enable
72+
73+
- name: Detect Yarn version
74+
id: yarn-version
75+
run: |
76+
# Resolve the Yarn major version from the packageManager field in
77+
# package.json if present, otherwise fall back to the installed version.
78+
YARN_VERSION=$(node -p "
79+
try {
80+
const pm = require('./package.json').packageManager ?? '';
81+
const match = pm.match(/^yarn@(\d+)/);
82+
match ? match[1] : '';
83+
} catch { '' }
84+
")
85+
if [ -z "$YARN_VERSION" ]; then
86+
YARN_VERSION=$(yarn --version | cut -d. -f1)
87+
fi
88+
echo "major=$YARN_VERSION" >> "$GITHUB_OUTPUT"
89+
echo "Detected Yarn major version: $YARN_VERSION"
90+
91+
- name: Validate version matches package.json
92+
run: |
93+
PKG_VERSION=$(node -p "require('./package.json').version")
94+
INPUT_VERSION="${{ inputs.version }}"
95+
if [ "$PKG_VERSION" != "$INPUT_VERSION" ]; then
96+
echo "❌ Version mismatch: package.json has $PKG_VERSION but input was $INPUT_VERSION"
97+
exit 1
98+
fi
99+
echo "✅ Version $PKG_VERSION confirmed"
100+
101+
- name: Install dependencies
102+
run: |
103+
if [ "${{ steps.yarn-version.outputs.major }}" = "1" ]; then
104+
yarn install --frozen-lockfile --non-interactive
105+
else
106+
yarn install --immutable
107+
fi
108+
109+
- name: Build package (if build script exists)
110+
run: |
111+
if node -e "process.exit(require('./package.json').scripts?.build ? 0 : 1)" 2>/dev/null; then
112+
yarn build
113+
else
114+
echo "No build script found — skipping build step"
115+
fi
116+
117+
- name: Publish (dry run)
118+
if: ${{ inputs.dry_run }}
119+
env:
120+
# The npm CLI automatically detects the OIDC environment via
121+
# ACTIONS_ID_TOKEN_REQUEST_URL / ACTIONS_ID_TOKEN_REQUEST_TOKEN and
122+
# handles the token exchange itself. NODE_AUTH_TOKEN must still be set
123+
# (even if empty) to satisfy the .npmrc written by actions/setup-node,
124+
# otherwise npm errors before it reaches OIDC auth.
125+
NODE_AUTH_TOKEN: ""
126+
run: npm publish --provenance --access public --dry-run
24127

25128
- name: Publish
26-
run: yarn publish
129+
if: ${{ !inputs.dry_run }}
27130
env:
28-
NODE_AUTH_TOKEN: ${{ secrets.NODE_AUTH_TOKEN }}
131+
NODE_AUTH_TOKEN: ""
132+
run: npm publish --provenance --access public
133+
134+
- name: Verify published version
135+
if: ${{ !inputs.dry_run }}
136+
run: |
137+
PACKAGE_NAME=$(node -p "require('./package.json').name")
138+
EXPECTED_VERSION="${{ inputs.version }}"
139+
140+
echo "Waiting for npm propagation..."
141+
142+
for i in {1..10}; do
143+
PUBLISHED_VERSION=$(npm view "$PACKAGE_NAME" version 2>/dev/null)
144+
if [ "$PUBLISHED_VERSION" = "$EXPECTED_VERSION" ]; then
145+
echo "✅ Version $PUBLISHED_VERSION confirmed on npm"
146+
exit 0
147+
fi
148+
echo "Not visible yet (attempt $i)..."
149+
sleep 15
150+
done
151+
152+
echo "❌ Published version not visible after waiting"
153+
exit 1

.github/workflows/tests.yml

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@ name: Tests
33
on: [push, pull_request]
44

55
jobs:
6-
build:
7-
6+
test:
87
runs-on: ubuntu-latest
98

109
strategy:
10+
fail-fast: false
1111
matrix:
12-
node-version: [18.x, 20.x, 22.x, 24.x]
12+
node-version: ["lts/-0", "lts/-1", "lts/-2", "lts/-3"]
1313

1414
steps:
1515
- uses: actions/checkout@v4
@@ -18,13 +18,36 @@ jobs:
1818
uses: actions/setup-node@v4
1919
with:
2020
node-version: ${{ matrix.node-version }}
21-
cache: 'yarn'
2221

23-
- name: Install dependencies
24-
run: yarn --frozen-lockfile --non-interactive --prefer-offline
22+
- name: Enable Corepack
23+
run: corepack enable
24+
25+
- name: Detect Yarn version
26+
id: yarn-version
27+
run: |
28+
YARN_VERSION=$(node -p "
29+
try {
30+
const pm = require('./package.json').packageManager ?? '';
31+
const match = pm.match(/^yarn@(\d+)/);
32+
match ? match[1] : '';
33+
} catch { '' }
34+
")
35+
if [ -z "$YARN_VERSION" ]; then
36+
YARN_VERSION=$(yarn --version | cut -d. -f1)
37+
fi
38+
echo "major=$YARN_VERSION" >> "$GITHUB_OUTPUT"
39+
echo "Detected Yarn major version: $YARN_VERSION"
2540
26-
- name: Test
27-
run: yarn test
41+
- name: Install dependencies
42+
run: |
43+
if [ "${{ steps.yarn-version.outputs.major }}" = "1" ]; then
44+
yarn install --frozen-lockfile --non-interactive --prefer-offline
45+
else
46+
yarn install --immutable
47+
fi
2848
2949
- name: Lint
3050
run: yarn lint
51+
52+
- name: Test
53+
run: yarn test

0 commit comments

Comments
 (0)