Skip to content

Commit d25e111

Browse files
committed
chore: automatically create release after bumping version
1 parent 8ceb0c3 commit d25e111

File tree

2 files changed

+219
-14
lines changed

2 files changed

+219
-14
lines changed
Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
name: Version Tag and Release Notes
2+
3+
on:
4+
pull_request:
5+
types: [closed]
6+
branches:
7+
- main
8+
9+
workflow_dispatch:
10+
inputs:
11+
version:
12+
description: 'Version number (e.g., 0.17.0)'
13+
required: true
14+
type: string
15+
16+
jobs:
17+
create-tag-and-release:
18+
runs-on: ubuntu-latest
19+
if: (github.event.pull_request.merged == true && contains(github.event.pull_request.title, 'bump version')) || github.event_name == 'workflow_dispatch'
20+
steps:
21+
- name: Checkout code
22+
uses: actions/checkout@v4
23+
with:
24+
fetch-depth: 0 # Fetch full history for release notes
25+
26+
- name: Extract version from versions.json
27+
id: extract_version
28+
run: |
29+
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
30+
VERSION="${{ github.event.inputs.version }}"
31+
else
32+
# Extract version from versions.json
33+
VERSION=$(jq -r '.[0]' versions.json)
34+
echo "Extracted version from versions.json: $VERSION"
35+
fi
36+
37+
if [[ -z "$VERSION" ]]; then
38+
echo "Could not extract version"
39+
exit 1
40+
fi
41+
42+
# Ensure version has patch number (add .0 if missing)
43+
if [[ ! "$VERSION" =~ \.[0-9]+$ ]]; then
44+
VERSION="${VERSION}.0"
45+
fi
46+
47+
echo "Final version: $VERSION"
48+
echo "version=$VERSION" >> $GITHUB_OUTPUT
49+
echo "tag_name=v$VERSION" >> $GITHUB_OUTPUT
50+
51+
- name: Check if tag exists
52+
id: check_tag
53+
run: |
54+
TAG_NAME="v${{ steps.extract_version.outputs.version }}"
55+
if git rev-parse "$TAG_NAME" >/dev/null 2>&1; then
56+
echo "Tag $TAG_NAME already exists"
57+
echo "tag_exists=true" >> $GITHUB_OUTPUT
58+
else
59+
echo "Tag $TAG_NAME does not exist"
60+
echo "tag_exists=false" >> $GITHUB_OUTPUT
61+
fi
62+
63+
- name: Get previous tag for release notes
64+
id: previous_tag
65+
if: steps.check_tag.outputs.tag_exists == 'false'
66+
run: |
67+
# Get the previous tag
68+
PREVIOUS_TAG=$(git tag --sort=-version:refname | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | head -1)
69+
if [[ -z "$PREVIOUS_TAG" ]]; then
70+
# If no previous tag, use the first commit
71+
PREVIOUS_TAG=$(git rev-list --max-parents=0 HEAD)
72+
fi
73+
echo "previous_tag=$PREVIOUS_TAG" >> $GITHUB_OUTPUT
74+
echo "Previous tag: $PREVIOUS_TAG"
75+
76+
- name: Create tag
77+
if: steps.check_tag.outputs.tag_exists == 'false'
78+
run: |
79+
TAG_NAME="${{ steps.extract_version.outputs.tag_name }}"
80+
git config user.name "github-actions[bot]"
81+
git config user.email "github-actions[bot]@users.noreply.github.com"
82+
git tag -a "$TAG_NAME" -m "Release $TAG_NAME"
83+
git push origin "$TAG_NAME"
84+
85+
- name: Generate release notes
86+
if: steps.check_tag.outputs.tag_exists == 'false'
87+
uses: actions/github-script@v7
88+
with:
89+
script: |
90+
const { data: release } = await github.rest.repos.createRelease({
91+
owner: context.repo.owner,
92+
repo: context.repo.repo,
93+
tag_name: '${{ steps.extract_version.outputs.tag_name }}',
94+
name: 'Release ${{ steps.extract_version.outputs.tag_name }}',
95+
body: '', // Will be auto-generated
96+
draft: false,
97+
prerelease: false,
98+
generate_release_notes: true
99+
});
100+
101+
console.log(`Created release: ${release.html_url}`);
102+
103+
// Output release info
104+
core.setOutput('release_url', release.html_url);
105+
core.setOutput('release_id', release.id);
106+
107+
- name: Update release with additional info
108+
if: steps.check_tag.outputs.tag_exists == 'false'
109+
uses: actions/github-script@v7
110+
with:
111+
script: |
112+
// Get the release that was just created
113+
const { data: releases } = await github.rest.repos.listReleases({
114+
owner: context.repo.owner,
115+
repo: context.repo.repo,
116+
per_page: 1
117+
});
118+
119+
if (releases.length === 0) {
120+
console.log('No releases found');
121+
return;
122+
}
123+
124+
const release = releases[0];
125+
126+
// Get commits between previous tag and current tag
127+
const previousTag = '${{ steps.previous_tag.outputs.previous_tag }}';
128+
const currentTag = '${{ steps.extract_version.outputs.tag_name }}';
129+
130+
let commits = [];
131+
try {
132+
const { data: compareData } = await github.rest.repos.compareCommits({
133+
owner: context.repo.owner,
134+
repo: context.repo.repo,
135+
base: previousTag,
136+
head: currentTag
137+
});
138+
commits = compareData.commits;
139+
} catch (error) {
140+
console.log(`Error comparing commits: ${error.message}`);
141+
// Fallback: get recent commits
142+
const { data: recentCommits } = await github.rest.repos.listCommits({
143+
owner: context.repo.owner,
144+
repo: context.repo.repo,
145+
per_page: 50
146+
});
147+
commits = recentCommits;
148+
}
149+
150+
// Get unique contributors
151+
const contributors = [...new Set(commits.map(commit => commit.author?.login).filter(Boolean))];
152+
153+
// Prepare additional release notes content
154+
let additionalContent = '\n\n## Contributors\n\n';
155+
contributors.forEach(contributor => {
156+
additionalContent += `* @${contributor}\n`;
157+
});
158+
159+
additionalContent += `\n**Full Changelog**: https://github.com/${context.repo.owner}/${context.repo.repo}/compare/${previousTag}...${currentTag}`;
160+
161+
// Update the release with additional content
162+
await github.rest.repos.updateRelease({
163+
owner: context.repo.owner,
164+
repo: context.repo.repo,
165+
release_id: release.id,
166+
body: release.body + additionalContent
167+
});
168+
169+
console.log(`Updated release with contributors and changelog link`);
170+
171+
- name: Notify completion
172+
if: steps.check_tag.outputs.tag_exists == 'false'
173+
run: |
174+
echo "✅ Successfully created tag ${{ steps.extract_version.outputs.tag_name }} and generated release notes!"
175+
echo "🔗 Release URL will be available in the GitHub repository releases page"
176+
177+
- name: Skip notification
178+
if: steps.check_tag.outputs.tag_exists == 'true'
179+
run: |
180+
echo "ℹ️ Tag ${{ steps.extract_version.outputs.tag_name }} already exists, skipping release creation"

package-lock.json

Lines changed: 39 additions & 14 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)