Skip to content

Commit f0bce52

Browse files
authored
CI: OICD release (#27)
1 parent 12fefac commit f0bce52

File tree

2 files changed

+210
-0
lines changed

2 files changed

+210
-0
lines changed
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
name: Create Release PR
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
version:
7+
description: 'Version type'
8+
required: true
9+
type: choice
10+
options:
11+
- patch
12+
- minor
13+
- major
14+
15+
jobs:
16+
create-release-pr:
17+
runs-on: ubuntu-latest
18+
permissions:
19+
contents: write
20+
pull-requests: write
21+
steps:
22+
- name: Checkout
23+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
24+
with:
25+
fetch-depth: 0
26+
27+
- name: Setup Node.js
28+
uses: actions/setup-node@3235b876344d2a9aa001b8d1453c930bba69e610 # v3.9.1
29+
with:
30+
node-version: 22
31+
32+
- name: Configure Git
33+
run: |
34+
git config user.name "github-actions[bot]"
35+
git config user.email "github-actions[bot]@users.noreply.github.com"
36+
37+
- name: Version bump
38+
run: |
39+
npm version ${{ github.event.inputs.version }} --no-git-tag-version
40+
VERSION=$(node -p "require('./package.json').version")
41+
echo "VERSION=$VERSION" >> $GITHUB_ENV
42+
43+
- name: Get release notes
44+
id: release-notes
45+
run: |
46+
# Get the last tag
47+
LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
48+
if [ -z "$LAST_TAG" ]; then
49+
LAST_TAG=$(git rev-list --max-parents=0 HEAD)
50+
fi
51+
52+
# Generate release notes
53+
NOTES=$(gh api \
54+
--method POST \
55+
-H "Accept: application/vnd.github+json" \
56+
/repos/${{ github.repository }}/releases/generate-notes \
57+
-f tag_name="v${{ env.VERSION }}" \
58+
-f target_commitish="master" \
59+
-f previous_tag_name="${LAST_TAG}" | jq -r '.body')
60+
61+
# Save to file to handle multiline content
62+
echo "$NOTES" > release-notes.md
63+
env:
64+
GH_TOKEN: ${{ github.token }}
65+
66+
- name: Create Pull Request
67+
uses: peter-evans/create-pull-request@153407881ec5c347639a548ade7d8ad1d6740e38 # v5.0.2
68+
with:
69+
branch: release/v${{ env.VERSION }}
70+
delete-branch: true
71+
title: "Release v${{ env.VERSION }}"
72+
body-path: release-notes.md
73+
commit-message: "chore: release v${{ env.VERSION }}"
74+
labels: |
75+
Type: Release
76+
assignees: ${{ github.actor }}

.github/workflows/release.yml

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
name: Release
2+
3+
on:
4+
pull_request:
5+
branches:
6+
- master
7+
- main
8+
types:
9+
- closed
10+
workflow_dispatch:
11+
inputs:
12+
version:
13+
description: 'Version to publish (e.g., 1.2.3)'
14+
required: false
15+
type: string
16+
17+
jobs:
18+
release:
19+
if: |
20+
(github.event_name == 'pull_request' &&
21+
github.event.pull_request.merged == true &&
22+
contains(github.event.pull_request.labels.*.name, 'Type: Release')) ||
23+
github.event_name == 'workflow_dispatch'
24+
runs-on: ubuntu-latest
25+
permissions:
26+
contents: write
27+
id-token: write # OIDC
28+
pull-requests: write # PR comment
29+
steps:
30+
- name: Checkout
31+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
32+
with:
33+
fetch-depth: 0
34+
35+
- name: Get package info
36+
id: package
37+
run: |
38+
if [ "${{ github.event_name }}" = "workflow_dispatch" ] && [ -n "${{ github.event.inputs.version }}" ]; then
39+
VERSION="${{ github.event.inputs.version }}"
40+
else
41+
VERSION=$(node -p "require('./package.json').version")
42+
fi
43+
PACKAGE_NAME=$(node -p "require('./package.json').name")
44+
echo "version=$VERSION" >> $GITHUB_OUTPUT
45+
echo "name=$PACKAGE_NAME" >> $GITHUB_OUTPUT
46+
47+
- name: Check if tag exists
48+
id: tag-check
49+
run: |
50+
if git rev-parse "v${{ steps.package.outputs.version }}" >/dev/null 2>&1; then
51+
echo "exists=true" >> $GITHUB_OUTPUT
52+
else
53+
echo "exists=false" >> $GITHUB_OUTPUT
54+
fi
55+
56+
- name: Setup Node.js
57+
if: steps.tag-check.outputs.exists == 'false'
58+
uses: actions/setup-node@3235b876344d2a9aa001b8d1453c930bba69e610 # v3.9.1
59+
with:
60+
node-version: 22
61+
registry-url: 'https://registry.npmjs.org'
62+
63+
- name: Ensure npm 11.5.1 or later is installed
64+
if: steps.tag-check.outputs.exists == 'false'
65+
run: |
66+
NPM_VERSION=$(npm -v)
67+
echo "Current npm version: $NPM_VERSION"
68+
if ! npx semver -r ">=11.5.1" "$NPM_VERSION"; then
69+
echo "npm version $NPM_VERSION is too old. Installing latest npm..."
70+
npm install -g npm@latest
71+
echo "Updated npm version: $(npm -v)"
72+
fi
73+
74+
- name: Install dependencies
75+
if: steps.tag-check.outputs.exists == 'false'
76+
run: npm ci
77+
78+
- name: Build package
79+
if: steps.tag-check.outputs.exists == 'false'
80+
run: npm run build
81+
82+
- name: Publish to npm with provenance
83+
if: steps.tag-check.outputs.exists == 'false'
84+
run: npm publish --provenance --access public
85+
86+
- name: Create GitHub Release with tag
87+
id: create-release
88+
if: steps.tag-check.outputs.exists == 'false'
89+
run: |
90+
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
91+
RELEASE_URL=$(gh release create "v${{ steps.package.outputs.version }}" \
92+
--title "v${{ steps.package.outputs.version }}" \
93+
--target "${{ github.sha }}" \
94+
--generate-notes)
95+
else
96+
RELEASE_URL=$(gh release create "v${{ steps.package.outputs.version }}" \
97+
--title "v${{ steps.package.outputs.version }}" \
98+
--target "${{ github.sha }}" \
99+
--notes "${{ github.event.pull_request.body }}")
100+
fi
101+
echo "url=$RELEASE_URL" >> $GITHUB_OUTPUT
102+
env:
103+
GH_TOKEN: ${{ github.token }}
104+
105+
- name: Comment on PR - Success
106+
if: |
107+
always() &&
108+
github.event_name == 'pull_request' &&
109+
steps.tag-check.outputs.exists == 'false' &&
110+
success()
111+
run: |
112+
gh pr comment ${{ github.event.pull_request.number }} \
113+
--body "✅ **Release v${{ steps.package.outputs.version }} completed successfully!**
114+
115+
- 📦 npm package: https://www.npmjs.com/package/${{ steps.package.outputs.name }}/v/${{ steps.package.outputs.version }}
116+
- 🏷️ GitHub Release: ${{ steps.create-release.outputs.url }}
117+
- 🔗 Workflow run: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
118+
env:
119+
GH_TOKEN: ${{ github.token }}
120+
121+
- name: Comment on PR - Failure
122+
if: |
123+
always() &&
124+
github.event_name == 'pull_request' &&
125+
steps.tag-check.outputs.exists == 'false' &&
126+
failure()
127+
run: |
128+
gh pr comment ${{ github.event.pull_request.number }} \
129+
--body "❌ **Release v${{ steps.package.outputs.version }} failed**
130+
131+
Please check the workflow logs for details.
132+
🔗 Workflow run: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
133+
env:
134+
GH_TOKEN: ${{ github.token }}

0 commit comments

Comments
 (0)