Skip to content

Commit 377169f

Browse files
committed
release note 자동화 추가
1 parent 4929338 commit 377169f

File tree

3 files changed

+168
-1
lines changed

3 files changed

+168
-1
lines changed

.github/workflows/release.yml

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
name: Release
2+
3+
on:
4+
push:
5+
tags:
6+
- 'v*'
7+
8+
jobs:
9+
release:
10+
runs-on: ubuntu-latest
11+
12+
permissions:
13+
contents: write
14+
packages: write
15+
16+
steps:
17+
- name: Checkout
18+
uses: actions/checkout@v4
19+
with:
20+
fetch-depth: 0
21+
22+
- name: Setup Node.js
23+
uses: actions/setup-node@v4
24+
with:
25+
node-version: '18'
26+
registry-url: 'https://registry.npmjs.org'
27+
28+
- name: Install dependencies
29+
run: npm ci
30+
31+
- name: Run tests
32+
run: npm test
33+
34+
- name: Build
35+
run: npm run build
36+
37+
- name: Extract version from tag
38+
id: version
39+
run: echo "version=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT
40+
41+
- name: Generate changelog
42+
id: changelog
43+
run: |
44+
# Extract changelog for current version
45+
if [ -f "CHANGELOG.md" ]; then
46+
# Get content between current version and previous version
47+
awk '/^## \[${{ steps.version.outputs.version }}\]/{flag=1; next} /^## \[/{flag=0} flag' CHANGELOG.md > current_changelog.md
48+
echo "changelog<<EOF" >> $GITHUB_OUTPUT
49+
cat current_changelog.md >> $GITHUB_OUTPUT
50+
echo "EOF" >> $GITHUB_OUTPUT
51+
else
52+
echo "changelog=Release ${{ steps.version.outputs.version }}" >> $GITHUB_OUTPUT
53+
fi
54+
55+
- name: Create GitHub Release
56+
uses: softprops/action-gh-release@v1
57+
with:
58+
tag_name: ${{ github.ref_name }}
59+
name: "🚀 Release ${{ steps.version.outputs.version }}"
60+
body: ${{ steps.changelog.outputs.changelog }}
61+
draft: false
62+
prerelease: false
63+
env:
64+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
65+
66+
- name: Publish to NPM
67+
run: npm publish
68+
env:
69+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

package.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,11 @@
4141
"scripts": {
4242
"build": "tsup src/core.ts src/cli.ts src/init.ts --dts --format cjs,esm --out-dir dist",
4343
"test": "node --test test/*.test.js",
44-
"prepublishOnly": "npm run build"
44+
"prepublishOnly": "npm run build",
45+
"release": "node scripts/release.js",
46+
"release:patch": "npm version patch && npm run release",
47+
"release:minor": "npm version minor && npm run release",
48+
"release:major": "npm version major && npm run release"
4549
},
4650
"devDependencies": {
4751
"@types/node": "^24.3.1",

scripts/release.js

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
#!/usr/bin/env node
2+
3+
import { execSync } from 'child_process';
4+
import fs from 'fs';
5+
import path from 'path';
6+
7+
const packageJson = JSON.parse(fs.readFileSync('package.json', 'utf8'));
8+
const currentVersion = packageJson.version;
9+
10+
console.log(`🚀 Starting release process for v${currentVersion}`);
11+
12+
function run(command) {
13+
console.log(`> ${command}`);
14+
try {
15+
return execSync(command, { stdio: 'inherit', encoding: 'utf8' });
16+
} catch (error) {
17+
console.error(`❌ Command failed: ${command}`);
18+
process.exit(1);
19+
}
20+
}
21+
22+
function extractChangelogForVersion(version) {
23+
if (!fs.existsSync('CHANGELOG.md')) {
24+
return `Release v${version}`;
25+
}
26+
27+
const changelog = fs.readFileSync('CHANGELOG.md', 'utf8');
28+
const lines = changelog.split('\n');
29+
const startIndex = lines.findIndex(line =>
30+
line.includes(`[${version}]`) && line.startsWith('## ')
31+
);
32+
33+
if (startIndex === -1) {
34+
return `Release v${version}`;
35+
}
36+
37+
const endIndex = lines.findIndex((line, index) =>
38+
index > startIndex && line.startsWith('## [')
39+
);
40+
41+
const versionLines = lines.slice(
42+
startIndex + 1,
43+
endIndex === -1 ? undefined : endIndex
44+
);
45+
46+
return versionLines.join('\n').trim();
47+
}
48+
49+
async function createRelease() {
50+
// 1. Build and test
51+
console.log('\n📦 Building and testing...');
52+
run('npm run build');
53+
run('npm test');
54+
55+
// 2. Create git tag
56+
console.log('\n🏷️ Creating git tag...');
57+
run(`git tag -a v${currentVersion} -m "Release v${currentVersion}"`);
58+
59+
// 3. Push to GitHub
60+
console.log('\n⬆️ Pushing to GitHub...');
61+
run('git push origin main');
62+
run(`git push origin v${currentVersion}`);
63+
64+
// 4. Publish to NPM
65+
console.log('\n📤 Publishing to NPM...');
66+
run('npm publish');
67+
68+
// 5. Create GitHub release (if gh CLI is available)
69+
console.log('\n🎉 Creating GitHub release...');
70+
try {
71+
const changelog = extractChangelogForVersion(currentVersion);
72+
const releaseTitle = `🚀 Release v${currentVersion}`;
73+
74+
// Escape special characters in changelog
75+
const escapedChangelog = changelog.replace(/`/g, '\\`').replace(/\$/g, '\\$');
76+
77+
run(`gh release create v${currentVersion} --title "${releaseTitle}" --notes "${escapedChangelog}"`);
78+
console.log('✅ GitHub release created successfully!');
79+
} catch (error) {
80+
console.log('⚠️ GitHub CLI not available or not authenticated.');
81+
console.log('Please create the release manually on GitHub.');
82+
console.log('Release notes saved to RELEASE_NOTES_v' + currentVersion + '.md');
83+
}
84+
85+
console.log(`\n🎉 Release v${currentVersion} completed successfully!`);
86+
console.log(`📦 Package: https://www.npmjs.com/package/${packageJson.name}`);
87+
console.log(`🏷️ Tag: https://github.com/${packageJson.repository.url.split('/').slice(-2).join('/').replace('.git', '')}/releases/tag/v${currentVersion}`);
88+
}
89+
90+
// Run the release process
91+
createRelease().catch(error => {
92+
console.error('❌ Release failed:', error);
93+
process.exit(1);
94+
});

0 commit comments

Comments
 (0)