Visitar URL original
Add release workflow with npm trusted publishing · unlayer/cli@1f7b969 · GitHub
Skip to content

Commit 1f7b969

Browse files
committed
Add release workflow with npm trusted publishing
Mirrors the elements publish flow: PR merged to main triggers build & test, then a reviewer approves the publish via the npm-publish environment gate. Version is read from npm and bumped from there (patch by default, override with release:minor or release:major PR labels). Auth uses OIDC trusted publishing — no NPM_TOKEN. Also bumps ci.yml + package.json engines to Node 24 (LTS) and pnpm 10 to match the publish workflow.
1 parent 58be736 commit 1f7b969

3 files changed

Lines changed: 190 additions & 3 deletions

File tree

‎.github/workflows/ci.yml‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,12 @@ jobs:
1717
- name: Setup pnpm
1818
uses: pnpm/action-setup@v4
1919
with:
20-
version: 9
20+
version: 10
2121

2222
- name: Setup Node.js
2323
uses: actions/setup-node@v4
2424
with:
25-
node-version: 20
25+
node-version: 24
2626
cache: pnpm
2727

2828
- name: Install dependencies

‎.github/workflows/publish.yml‎

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
# Release & Publish
2+
#
3+
# Gated publish flow:
4+
# 1. PR merged to main → triggers build & test
5+
# 2. A reviewer approves the publish in the Actions UI (environment gate)
6+
# 3. Package is published to npm via trusted publishing (OIDC)
7+
#
8+
# Version: reads the latest published version from npm and bumps from that.
9+
# Defaults to patch. Add a `release:minor` or `release:major` PR label to
10+
# override. Manual dispatch also supports bump selection.
11+
#
12+
# Auth: Uses npm trusted publishing (OIDC) — no NPM_TOKEN needed.
13+
# The `npm-publish` environment must be configured in repo Settings →
14+
# Environments with at least one required reviewer.
15+
#
16+
# npm trusted publishing must also be configured on npmjs.com:
17+
# Package Settings → Publishing access → Add trusted publisher →
18+
# Repository: unlayer/cli
19+
# Workflow: publish.yml
20+
21+
name: Release
22+
23+
on:
24+
push:
25+
branches: [main]
26+
workflow_dispatch:
27+
inputs:
28+
bump:
29+
description: 'Version bump type'
30+
required: true
31+
type: choice
32+
options:
33+
- patch
34+
- minor
35+
- major
36+
default: patch
37+
38+
jobs:
39+
build-and-test:
40+
name: Build & Test
41+
runs-on: ubuntu-latest
42+
43+
steps:
44+
- name: Checkout code
45+
uses: actions/checkout@v4
46+
47+
- name: Setup pnpm
48+
uses: pnpm/action-setup@v4
49+
with:
50+
version: 10
51+
52+
- name: Setup Node.js 24
53+
uses: actions/setup-node@v4
54+
with:
55+
node-version: 24
56+
cache: pnpm
57+
58+
- name: Install dependencies
59+
run: pnpm install --frozen-lockfile
60+
61+
- name: Type check
62+
run: pnpm typecheck
63+
64+
- name: Build
65+
run: pnpm build
66+
67+
- name: Run tests
68+
run: pnpm test
69+
70+
publish:
71+
name: Publish to npm
72+
needs: build-and-test
73+
runs-on: ubuntu-latest
74+
concurrency:
75+
group: publish
76+
cancel-in-progress: false
77+
environment: npm-publish
78+
permissions:
79+
contents: write
80+
id-token: write
81+
pull-requests: read
82+
83+
steps:
84+
- name: Checkout code
85+
uses: actions/checkout@v4
86+
with:
87+
ref: main
88+
89+
- name: Setup pnpm
90+
uses: pnpm/action-setup@v4
91+
with:
92+
version: 10
93+
94+
# setup-node with registry-url enables OIDC token exchange for npm publish.
95+
- name: Setup Node.js 24 (with npm registry for OIDC)
96+
uses: actions/setup-node@v4
97+
with:
98+
node-version: 24
99+
registry-url: https://registry.npmjs.org
100+
cache: pnpm
101+
102+
- name: Update npm for trusted publishing
103+
run: npm install -g npm@latest
104+
105+
- name: Install dependencies
106+
run: pnpm install --frozen-lockfile
107+
108+
- name: Build
109+
run: pnpm build
110+
111+
- name: Determine version bump
112+
id: bump
113+
run: |
114+
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
115+
echo "type=${{ inputs.bump }}" >> $GITHUB_OUTPUT
116+
else
117+
# Check labels on the PR associated with this commit
118+
LABELS=$(gh api "repos/${GITHUB_REPOSITORY}/commits/${GITHUB_SHA}/pulls" --jq '.[0].labels[].name' 2>/dev/null || echo "")
119+
if echo "$LABELS" | grep -Fxq "release:major"; then
120+
echo "type=major" >> $GITHUB_OUTPUT
121+
elif echo "$LABELS" | grep -Fxq "release:minor"; then
122+
echo "type=minor" >> $GITHUB_OUTPUT
123+
else
124+
echo "type=patch" >> $GITHUB_OUTPUT
125+
fi
126+
fi
127+
env:
128+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
129+
130+
- name: Determine version
131+
id: version
132+
run: |
133+
# Read latest published version from npm (falls back to package.json for first publish)
134+
CURRENT=$(npm view @unlayer/cli version 2>/dev/null || node -p "require('./package.json').version")
135+
echo "current=$CURRENT" >> $GITHUB_OUTPUT
136+
137+
# Write current version to package.json so npm version can bump from it
138+
npm version "$CURRENT" --no-git-tag-version --allow-same-version
139+
140+
# Bump
141+
VERSION=$(npm version ${{ steps.bump.outputs.type }} --no-git-tag-version)
142+
VERSION="${VERSION#v}"
143+
echo "version=$VERSION" >> $GITHUB_OUTPUT
144+
145+
- name: Pre-publish summary
146+
run: |
147+
BUNDLE_SIZE=$(wc -c < dist/index.js | tr -d ' ')
148+
FILE_COUNT=$(find dist -type f | wc -l | tr -d ' ')
149+
150+
echo "## Publish Summary" >> $GITHUB_STEP_SUMMARY
151+
echo "" >> $GITHUB_STEP_SUMMARY
152+
echo "| | |" >> $GITHUB_STEP_SUMMARY
153+
echo "|---|---|" >> $GITHUB_STEP_SUMMARY
154+
echo "| **Package** | \`@unlayer/cli\` |" >> $GITHUB_STEP_SUMMARY
155+
echo "| **Version** | ${{ steps.version.outputs.current }} → ${{ steps.version.outputs.version }} (${{ steps.bump.outputs.type }}) |" >> $GITHUB_STEP_SUMMARY
156+
echo "| **Trigger** | ${{ github.event_name }} |" >> $GITHUB_STEP_SUMMARY
157+
echo "| **Auth** | Trusted publishing (OIDC) |" >> $GITHUB_STEP_SUMMARY
158+
echo "| **Bundle** | ${BUNDLE_SIZE} bytes |" >> $GITHUB_STEP_SUMMARY
159+
echo "| **Files in dist** | ${FILE_COUNT} |" >> $GITHUB_STEP_SUMMARY
160+
161+
- name: Publish to npm (trusted publishing)
162+
run: npm publish --access public
163+
164+
- name: Tag release
165+
run: |
166+
TAG="v${{ steps.version.outputs.version }}"
167+
git config user.name "github-actions[bot]"
168+
git config user.email "github-actions[bot]@users.noreply.github.com"
169+
if git ls-remote --tags origin | awk '{print $2}' | grep -Fxq "refs/tags/$TAG"; then
170+
echo "Tag $TAG already exists — skipping"
171+
else
172+
git tag "$TAG"
173+
git push origin "$TAG"
174+
fi
175+
176+
- name: Create GitHub Release
177+
run: |
178+
TAG="v${{ steps.version.outputs.version }}"
179+
if gh release view "$TAG" >/dev/null 2>&1; then
180+
echo "Release $TAG already exists — skipping"
181+
else
182+
gh release create "$TAG" \
183+
--title "$TAG" \
184+
--generate-notes
185+
fi
186+
env:
187+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

‎package.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
"LICENSE"
1414
],
1515
"engines": {
16-
"node": ">=20"
16+
"node": ">=24"
1717
},
1818
"repository": {
1919
"type": "git",

0 commit comments

Comments
 (0)