Skip to content

Commit a15a617

Browse files
authored
Merge pull request #16 from link-foundation/issue-15-b28422959bc5
Add complete CI/CD workflows and release automation
2 parents fef0a28 + cd7ef85 commit a15a617

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+7998
-111
lines changed

.github/workflows/js.yml

Lines changed: 311 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,311 @@
1+
name: JavaScript CI/CD
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
paths:
8+
- 'js/**'
9+
- '.github/workflows/js.yml'
10+
pull_request:
11+
types: [opened, synchronize, reopened]
12+
paths:
13+
- 'js/**'
14+
- '.github/workflows/js.yml'
15+
workflow_dispatch:
16+
inputs:
17+
release_mode:
18+
description: 'Manual release mode'
19+
required: true
20+
type: choice
21+
default: 'instant'
22+
options:
23+
- instant
24+
- changeset-pr
25+
bump_type:
26+
description: 'Manual release type'
27+
required: true
28+
type: choice
29+
options:
30+
- patch
31+
- minor
32+
- major
33+
description:
34+
description: 'Manual release description (optional)'
35+
required: false
36+
type: string
37+
38+
concurrency: ${{ github.workflow }}-${{ github.ref }}
39+
40+
jobs:
41+
# Changeset check - only runs on PRs
42+
changeset-check:
43+
name: Check for Changesets
44+
runs-on: ubuntu-latest
45+
if: github.event_name == 'pull_request'
46+
steps:
47+
- uses: actions/checkout@v4
48+
with:
49+
fetch-depth: 0
50+
51+
- name: Setup Node.js
52+
uses: actions/setup-node@v4
53+
with:
54+
node-version: '22'
55+
56+
- name: Install dependencies
57+
working-directory: ./js
58+
run: npm install
59+
60+
- name: Check for changesets
61+
working-directory: ./js
62+
run: |
63+
# Skip changeset check for automated version PRs
64+
if [[ "${{ github.head_ref }}" == "changeset-release/"* ]]; then
65+
echo "Skipping changeset check for automated release PR"
66+
exit 0
67+
fi
68+
69+
# Run changeset validation script
70+
node scripts/validate-changeset.mjs
71+
72+
# Linting and formatting - runs after changeset check on PRs, immediately on main
73+
lint:
74+
name: Lint and Format Check
75+
runs-on: ubuntu-latest
76+
needs: [changeset-check]
77+
if: always() && (github.event_name == 'push' || needs.changeset-check.result == 'success')
78+
steps:
79+
- uses: actions/checkout@v4
80+
81+
- name: Setup Node.js
82+
uses: actions/setup-node@v4
83+
with:
84+
node-version: '22'
85+
86+
- name: Install dependencies
87+
working-directory: ./js
88+
run: npm install
89+
90+
- name: Run ESLint
91+
working-directory: ./js
92+
run: npm run lint
93+
94+
- name: Check formatting
95+
working-directory: ./js
96+
run: npm run format:check
97+
98+
- name: Check code duplication
99+
working-directory: ./js
100+
run: npm run check:duplication
101+
102+
# Test matrix: Node.js on multiple OS
103+
test:
104+
name: Test (Node.js on ${{ matrix.os }})
105+
runs-on: ${{ matrix.os }}
106+
needs: [changeset-check]
107+
if: always() && (github.event_name == 'push' || needs.changeset-check.result == 'success')
108+
strategy:
109+
fail-fast: false
110+
matrix:
111+
os: [ubuntu-latest, macos-latest, windows-latest]
112+
steps:
113+
- uses: actions/checkout@v4
114+
115+
- name: Setup Node.js
116+
uses: actions/setup-node@v4
117+
with:
118+
node-version: '22'
119+
120+
- name: Install dependencies
121+
working-directory: ./js
122+
run: npm install
123+
124+
- name: Run tests
125+
working-directory: ./js
126+
run: npm test
127+
128+
- name: Run example
129+
working-directory: ./js
130+
run: npm run example
131+
132+
# Release - only runs on main after tests pass (for push events)
133+
release:
134+
name: Release
135+
needs: [lint, test]
136+
# Use always() to ensure this job runs even if changeset-check was skipped
137+
# This is needed because lint/test jobs have a transitive dependency on changeset-check
138+
if: always() && github.ref == 'refs/heads/main' && github.event_name == 'push' && needs.lint.result == 'success' && needs.test.result == 'success'
139+
runs-on: ubuntu-latest
140+
# Permissions required for npm OIDC trusted publishing
141+
permissions:
142+
contents: write
143+
pull-requests: write
144+
id-token: write
145+
steps:
146+
- uses: actions/checkout@v4
147+
with:
148+
fetch-depth: 0
149+
150+
- name: Setup Node.js
151+
uses: actions/setup-node@v4
152+
with:
153+
node-version: '22'
154+
registry-url: 'https://registry.npmjs.org'
155+
156+
- name: Install dependencies
157+
working-directory: ./js
158+
run: npm install
159+
160+
- name: Update npm for OIDC trusted publishing
161+
working-directory: ./js
162+
run: node scripts/setup-npm.mjs
163+
164+
- name: Check for changesets
165+
id: check_changesets
166+
working-directory: ./js
167+
run: |
168+
# Count changeset files (excluding README.md and config.json)
169+
CHANGESET_COUNT=$(find .changeset -name "*.md" ! -name "README.md" | wc -l)
170+
echo "Found $CHANGESET_COUNT changeset file(s)"
171+
echo "has_changesets=$([[ $CHANGESET_COUNT -gt 0 ]] && echo 'true' || echo 'false')" >> $GITHUB_OUTPUT
172+
173+
- name: Version packages and commit to main
174+
if: steps.check_changesets.outputs.has_changesets == 'true'
175+
id: version
176+
working-directory: ./js
177+
run: node scripts/version-and-commit.mjs --mode changeset
178+
179+
- name: Publish to npm
180+
# Run if version was committed OR if a previous attempt already committed (for re-runs)
181+
if: steps.version.outputs.version_committed == 'true' || steps.version.outputs.already_released == 'true'
182+
id: publish
183+
working-directory: ./js
184+
run: node scripts/publish-to-npm.mjs --should-pull
185+
186+
- name: Create GitHub Release
187+
if: steps.publish.outputs.published == 'true'
188+
env:
189+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
190+
working-directory: ./js
191+
run: node scripts/create-github-release.mjs --release-version "${{ steps.publish.outputs.published_version }}" --repository "${{ github.repository }}"
192+
193+
- name: Format GitHub release notes
194+
if: steps.publish.outputs.published == 'true'
195+
env:
196+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
197+
working-directory: ./js
198+
run: node scripts/format-github-release.mjs --release-version "${{ steps.publish.outputs.published_version }}" --repository "${{ github.repository }}" --commit-sha "${{ github.sha }}"
199+
200+
# Manual Instant Release - triggered via workflow_dispatch with instant mode
201+
instant-release:
202+
name: Instant Release
203+
if: github.event_name == 'workflow_dispatch' && github.event.inputs.release_mode == 'instant'
204+
runs-on: ubuntu-latest
205+
# Permissions required for npm OIDC trusted publishing
206+
permissions:
207+
contents: write
208+
pull-requests: write
209+
id-token: write
210+
steps:
211+
- uses: actions/checkout@v4
212+
with:
213+
fetch-depth: 0
214+
215+
- name: Setup Node.js
216+
uses: actions/setup-node@v4
217+
with:
218+
node-version: '22'
219+
registry-url: 'https://registry.npmjs.org'
220+
221+
- name: Install dependencies
222+
working-directory: ./js
223+
run: npm install
224+
225+
- name: Update npm for OIDC trusted publishing
226+
working-directory: ./js
227+
run: node scripts/setup-npm.mjs
228+
229+
- name: Version packages and commit to main
230+
id: version
231+
working-directory: ./js
232+
run: node scripts/version-and-commit.mjs --mode instant --bump-type "${{ github.event.inputs.bump_type }}" --description "${{ github.event.inputs.description }}"
233+
234+
- name: Publish to npm
235+
# Run if version was committed OR if a previous attempt already committed (for re-runs)
236+
if: steps.version.outputs.version_committed == 'true' || steps.version.outputs.already_released == 'true'
237+
id: publish
238+
working-directory: ./js
239+
run: node scripts/publish-to-npm.mjs
240+
241+
- name: Create GitHub Release
242+
if: steps.publish.outputs.published == 'true'
243+
env:
244+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
245+
working-directory: ./js
246+
run: node scripts/create-github-release.mjs --release-version "${{ steps.publish.outputs.published_version }}" --repository "${{ github.repository }}"
247+
248+
- name: Format GitHub release notes
249+
if: steps.publish.outputs.published == 'true'
250+
env:
251+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
252+
working-directory: ./js
253+
run: node scripts/format-github-release.mjs --release-version "${{ steps.publish.outputs.published_version }}" --repository "${{ github.repository }}" --commit-sha "${{ github.sha }}"
254+
255+
# Manual Changeset PR - creates a pull request with the changeset for review
256+
changeset-pr:
257+
name: Create Changeset PR
258+
if: github.event_name == 'workflow_dispatch' && github.event.inputs.release_mode == 'changeset-pr'
259+
runs-on: ubuntu-latest
260+
permissions:
261+
contents: write
262+
pull-requests: write
263+
steps:
264+
- uses: actions/checkout@v4
265+
with:
266+
fetch-depth: 0
267+
268+
- name: Setup Node.js
269+
uses: actions/setup-node@v4
270+
with:
271+
node-version: '22'
272+
273+
- name: Install dependencies
274+
working-directory: ./js
275+
run: npm install
276+
277+
- name: Create changeset file
278+
working-directory: ./js
279+
run: node scripts/create-manual-changeset.mjs --bump-type "${{ github.event.inputs.bump_type }}" --description "${{ github.event.inputs.description }}"
280+
281+
- name: Format changeset with Prettier
282+
working-directory: ./js
283+
run: |
284+
# Run Prettier on the changeset file to ensure it matches project style
285+
npx prettier --write ".changeset/*.md" || true
286+
287+
echo "Formatted changeset files"
288+
289+
- name: Create Pull Request
290+
uses: peter-evans/create-pull-request@v7
291+
with:
292+
token: ${{ secrets.GITHUB_TOKEN }}
293+
commit-message: 'chore: add changeset for manual ${{ github.event.inputs.bump_type }} release'
294+
branch: changeset-manual-release-${{ github.run_id }}
295+
delete-branch: true
296+
title: 'chore: manual ${{ github.event.inputs.bump_type }} release (JS)'
297+
body: |
298+
## Manual Release Request (JavaScript)
299+
300+
This PR was created by a manual workflow trigger to prepare a **${{ github.event.inputs.bump_type }}** release for the JavaScript package.
301+
302+
### Release Details
303+
- **Type:** ${{ github.event.inputs.bump_type }}
304+
- **Description:** ${{ github.event.inputs.description || 'Manual release' }}
305+
- **Triggered by:** @${{ github.actor }}
306+
307+
### Next Steps
308+
1. Review the changeset in this PR
309+
2. Merge this PR to main
310+
3. The automated release workflow will create a version PR
311+
4. Merge the version PR to publish to npm and create a GitHub release

0 commit comments

Comments
 (0)