๐ GitHub Actions๋ก CHANGELOG ์๋ ์์ฑํ๋ ์๋ฒฝ ๊ฐ์ด๋
โข2026๋ 2์ 10์ผ ํ์์ผ
GitHub Actions๋ก CHANGELOG ์๋ ์์ฑํ๋ ์๋ฒฝ ๊ฐ์ด๋
์ปค๋ฐ ๋ด์ญ์ ์ผ์ผ์ด ํ์ธํ๊ณ , ๋ณ๊ฒฝ ์ฌํญ์ ์ ๋ฆฌํ๊ณ , ๋ฒ์ ๋ณ๋ก ๋ถ๋ฅํ๋ ์์ ์ ์๊ฐ์ด ๋ง์ด ๊ฑธ๋ ค์.
์ด ๊ธ์์๋ GitHub Actions๋ฅผ ์ฌ์ฉํด์ CHANGELOG ์์ฑ์ ์์ ํ ์๋ํํ๋ ๋ฐฉ๋ฒ์ ๋ค๋ฃน๋๋ค. Conventional Commits ๊ท์น๊ณผ ์๋ํ ๋๊ตฌ๋ฅผ ํ์ฉํ๋ฉด ๋ฆด๋ฆฌ์ฆ๋ง๋ค ๊น๋ํ CHANGELOG๊ฐ ์๋์ผ๋ก ๋ง๋ค์ด์ ธ์.
์ด ๊ธ์ GitHub Actions๋ฅผ ํ ๋ฒ์ด๋ผ๋ ์ฌ์ฉํด๋ณธ ๊ฐ๋ฐ์๋ฅผ ๋์์ผ๋ก ํฉ๋๋ค.
์ CHANGELOG๋ฅผ ์๋ํํด์ผ ํ ๊น์?
์๋์ผ๋ก CHANGELOG๋ฅผ ์์ฑํ๋ฉด ๋ค์๊ณผ ๊ฐ์ ๋ฌธ์ ๊ฐ ์๊ฒจ์.
์๊ฐ ๋ญ๋น์ ์ค์
๋ฆด๋ฆฌ์ฆ๋ง๋ค ์ปค๋ฐ ํ์คํ ๋ฆฌ๋ฅผ ํ์ธํ๊ณ ๋ณ๊ฒฝ ์ฌํญ์ ์ ๋ฆฌํ๋ ๋ฐ ์๊ฐ์ด ๊ฑธ๋ ค์. ์ค์ํ ์ปค๋ฐ์ ๋์น๊ฑฐ๋ ์๋ชป๋ ์ ๋ณด๋ฅผ ๊ธฐ๋กํ ์๋ ์์ฃ .
์ผ๊ด์ฑ ๋ถ์กฑ
์์ฑ์๋ง๋ค ํ์์ด ๋ฌ๋ผ์ง๊ณ , ์ค์๋ ํ๋จ์ด ๋ฌ๋ผ์ ธ์. ํ์๋ค์ด CHANGELOG๋ฅผ ์ ๋ขฐํ์ง ๋ชปํ๊ฒ ๋ฉ๋๋ค.
์๋ํ์ ์ด์
GitHub Actions๋ก ์๋ํํ๋ฉด ๋ค์๊ณผ ๊ฐ์ ์ด์ ์ด ์์ด์.
- ๋ฆด๋ฆฌ์ฆ๋ง๋ค ์ผ๊ด๋ ํ์์ CHANGELOG ์์ฑ
- ์ปค๋ฐ ๋ฉ์์ง ๊ธฐ๋ฐ์ผ๋ก ์๋ ๋ถ๋ฅ (์ ๊ธฐ๋ฅ, ๋ฒ๊ทธ ์์ , ๋ฌธ์ ๋ฑ)
- ๋ฒ์ ํ๊ทธ์ ํจ๊ป ์๋์ผ๋ก GitHub Release ์์ฑ
- ๊ฐ๋ฐ์๋ ์ฝ๋์๋ง ์ง์คํ๊ณ CHANGELOG๋ ์๋์ผ๋ก ๊ด๋ฆฌ
Conventional Commits ๊ท์น ๋น ๋ฅด๊ฒ ์ดํดํ๊ธฐ
CHANGELOG ์๋ํ์ ํต์ฌ์ Conventional Commits ๊ท์น์ด์์. ์ปค๋ฐ ๋ฉ์์ง๋ฅผ ์ผ์ ํ ํ์์ผ๋ก ์์ฑํ๋ฉด ์๋ํ ๋๊ตฌ๊ฐ ์ด๋ฅผ ํ์ฑํด์ CHANGELOG๋ฅผ ์์ฑํด์.
์ปค๋ฐ ๋ฉ์์ง ํ์
๊ธฐ๋ณธ ํ์์ ๋ค์๊ณผ ๊ฐ์์.
<ํ์
>(<๋ฒ์>): <์ ๋ชฉ>
<๋ณธ๋ฌธ>
<ํธํฐ>ํ์ ์ ๋ณ๊ฒฝ ์ฌํญ์ ์ข ๋ฅ๋ฅผ ๋ํ๋ด์.
feat- ์๋ก์ด ๊ธฐ๋ฅ ์ถ๊ฐfix- ๋ฒ๊ทธ ์์ docs- ๋ฌธ์ ๋ณ๊ฒฝstyle- ์ฝ๋ ํฌ๋งทํ , ์ธ๋ฏธ์ฝ๋ก ๋๋ฝ ๋ฑ (๊ธฐ๋ฅ ๋ณ๊ฒฝ ์์)refactor- ์ฝ๋ ๋ฆฌํฉํ ๋งtest- ํ ์คํธ ์ถ๊ฐ ๋๋ ์์ chore- ๋น๋ ํ๋ก์ธ์ค, ๋๊ตฌ ์ค์ ๋ณ๊ฒฝ
๋ฒ์๋ ์ ํ ์ฌํญ์ด๋ฉฐ, ๋ณ๊ฒฝ๋ ๋ชจ๋์ด๋ ํ์ผ์ ๋ํ๋ด์.
์ ๋ชฉ์ ๋ณ๊ฒฝ ์ฌํญ์ ๊ฐ๋จํ ์ค๋ช ํด์.
์ค์ ์ฌ์ฉ ์์
๋ค์์ ์ค์ ํ๋ก์ ํธ์์ ์ฌ์ฉํ๋ ์ปค๋ฐ ๋ฉ์์ง ์์์์.
feat(auth): ๋ก๊ทธ์ธ ๊ธฐ๋ฅ ์ถ๊ฐ
์ฌ์ฉ์๊ฐ ์ด๋ฉ์ผ๊ณผ ๋น๋ฐ๋ฒํธ๋ก ๋ก๊ทธ์ธํ ์ ์์ต๋๋ค.
Closes #123fix(api): ์ฌ์ฉ์ ์กฐํ API ๋ฒ๊ทธ ์์
null ์ฒดํฌ ๋๋ฝ์ผ๋ก ์ธํ 500 ์๋ฌ๋ฅผ ์์ ํ์ต๋๋ค.docs: README์ ์ค์น ๊ฐ์ด๋ ์ถ๊ฐBreaking Change ํ์ํ๊ธฐ
ํ์ ํธํ์ฑ์ ๊นจ๋ ๋ณ๊ฒฝ ์ฌํญ์ ํธํฐ์ BREAKING CHANGE:๋ฅผ ์ถ๊ฐํ๊ฑฐ๋ ํ์
๋ค์ !๋ฅผ ๋ถ์ฌ์.
feat!: API ์๋ต ํ์ ๋ณ๊ฒฝ
BREAKING CHANGE: API ์๋ต์ด { data } ํ์์ผ๋ก ๋ณ๊ฒฝ๋์์ต๋๋ค.GitHub Actions ์ํฌํ๋ก์ฐ ์์ฑํ๊ธฐ
์ด์ CHANGELOG๋ฅผ ์๋์ผ๋ก ์์ฑํ๋ GitHub Actions ์ํฌํ๋ก์ฐ๋ฅผ ๋ง๋ค์ด๋ณผ๊ฒ์.
์ํฌํ๋ก์ฐ ํ์ผ ์์ฑ
ํ๋ก์ ํธ ๋ฃจํธ์ .github/workflows/ ๋๋ ํ ๋ฆฌ๋ฅผ ๋ง๋ค๊ณ release.yml ํ์ผ์ ์์ฑํ์ธ์.
mkdir -p .github/workflows
touch .github/workflows/release.ymlํธ๋ฆฌ๊ฑฐ ์ค์
์ํฌํ๋ก์ฐ๊ฐ ์คํ๋ ์์ ์ ์ ์ํด์. ์ผ๋ฐ์ ์ผ๋ก main ๋ธ๋์น์ ํธ์๋ ๋ ๋๋ ์๋์ผ๋ก ์คํํ ์ ์๊ฒ ์ค์ ํด์.
# .github/workflows/release.yml
name: Release
on:
push:
branches:
- main
workflow_dispatch: # ์๋ ์คํ ํ์ฉCHANGELOG ์๋ ์์ฑ ๊ตฌํ
CHANGELOG๋ฅผ ์๋์ผ๋ก ์์ฑํ๋ ๋ฐฉ๋ฒ์ ํฌ๊ฒ ๋ ๊ฐ์ง์์. standard-version๊ณผ release-please ์ค ํ๋๋ฅผ ์ ํํ ์ ์์ด์.
๋ฐฉ๋ฒ 1 - standard-version ์ฌ์ฉ
standard-version์ Conventional Commits ๊ธฐ๋ฐ์ผ๋ก ๋ฒ์ ์ ์ฌ๋ฆฌ๊ณ CHANGELOG๋ฅผ ์์ฑํ๋ ๋๊ตฌ์์.
์ฅ์
- ๊ฐ๋จํ ์ค์
- npm ํ๋ก์ ํธ์ ์ต์ ํ
- ์ปค์คํฐ๋ง์ด์ง ๊ฐ๋ฅ
์ ์ฒด ์ํฌํ๋ก์ฐ
# .github/workflows/release.yml
name: Release
on:
workflow_dispatch: # ์๋ ์คํ
jobs:
release:
runs-on: ubuntu-latest
steps:
- name: Checkout ์ฝ๋
uses: actions/checkout@v4
with:
fetch-depth: 0 # ์ ์ฒด ํ์คํ ๋ฆฌ ๊ฐ์ ธ์ค๊ธฐ
token: ${{ secrets.GITHUB_TOKEN }}
- name: Node.js ์ค์
uses: actions/setup-node@v4
with:
node-version: "20"
- name: ์์กด์ฑ ์ค์น
run: npm install
- name: Git ์ค์
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
- name: standard-version ์คํ
run: npx standard-version
- name: ๋ณ๊ฒฝ์ฌํญ ํธ์
run: |
git push --follow-tags origin main
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: GitHub Release ์์ฑ
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: Release ${{ github.ref }}
body_path: CHANGELOG.mdstandard-version์ ์คํํ๋ฉด ๋ค์๊ณผ ๊ฐ์ ์์
์ด ์๋์ผ๋ก ์ํ๋ผ์.
- ์ด์ ๋ฒ์ ์ดํ์ ๋ชจ๋ ์ปค๋ฐ ๋ถ์
- Conventional Commits ๊ท์น์ ๋ฐ๋ผ ๋ฒ์ ๊ฒฐ์ (major, minor, patch)
- CHANGELOG.md ์ ๋ฐ์ดํธ
- package.json ๋ฒ์ ์ ๋ฐ์ดํธ
- Git ํ๊ทธ ์์ฑ
๋ฐฉ๋ฒ 2 - release-please ์ฌ์ฉ
release-please๋ Google์์ ๋ง๋ ์๋ํ ๋๊ตฌ๋ก, Pull Request ๊ธฐ๋ฐ์ผ๋ก ๋ฆด๋ฆฌ์ฆ๋ฅผ ๊ด๋ฆฌํด์.
์ฅ์
- PR๋ก ๋ฆด๋ฆฌ์ฆ ๊ฒํ ๊ฐ๋ฅ
- ์ฌ๋ฌ ์ธ์ด ์ง์ (Node.js, Python, Go ๋ฑ)
- ์๋์ผ๋ก GitHub Release ์์ฑ
์ ์ฒด ์ํฌํ๋ก์ฐ
# .github/workflows/release-please.yml
name: Release Please
on:
push:
branches:
- main
permissions:
contents: write
pull-requests: write
jobs:
release-please:
runs-on: ubuntu-latest
steps:
- uses: google-github-actions/release-please-action@v4
with:
release-type: node # ํ๋ก์ ํธ ํ์
(node, python, go ๋ฑ)
package-name: my-package # ํจํค์ง ์ด๋ฆrelease-please๋ ๋ค์๊ณผ ๊ฐ์ด ๋์ํด์.
main๋ธ๋์น์ ํธ์๋ ๋๋ง๋ค ์คํ- Conventional Commits ๋ถ์
- Release PR ์์ฑ (CHANGELOG ๋ฏธ๋ฆฌ๋ณด๊ธฐ ํฌํจ)
- Release PR์ด ๋จธ์ง๋๋ฉด ์๋์ผ๋ก ํ๊ทธ ์์ฑ ๋ฐ GitHub Release ์์ฑ
์ด๋ค ๋ฐฉ๋ฒ์ ์ ํํ ๊น?
standard-version์ ๊ฐ๋จํ ํ๋ก์ ํธ์ ์ ํฉํ๊ณ , release-please๋ ๋ฆด๋ฆฌ์ฆ ์ ๊ฒํ ๊ฐ ํ์ํ ํ ํ๋ก์ ํธ์ ์ ํฉํด์.
- ๊ฐ์ธ ํ๋ก์ ํธ, ๋น ๋ฅธ ๋ฆด๋ฆฌ์ฆ โ standard-version
- ํ ํ๋ก์ ํธ, ๋ฆด๋ฆฌ์ฆ ๊ฒํ ํ์ โ release-please
๊ณ ๊ธ ์ค์
CHANGELOG ํ ํ๋ฆฟ ์ปค์คํฐ๋ง์ด์ง
standard-version์ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ .versionrc.json ํ์ผ๋ก CHANGELOG ํ
ํ๋ฆฟ์ ์ปค์คํฐ๋ง์ด์งํ ์ ์์ด์.
// .versionrc.json
{
"types": [
{ "type": "feat", "section": "โจ Features" },
{ "type": "fix", "section": "๐ Bug Fixes" },
{ "type": "docs", "section": "๐ Documentation" },
{ "type": "style", "section": "๐ Styles" },
{ "type": "refactor", "section": "โป๏ธ Code Refactoring" },
{ "type": "perf", "section": "โก๏ธ Performance Improvements" },
{ "type": "test", "section": "โ
Tests" },
{ "type": "chore", "section": "๐ง Chores" }
],
"commitUrlFormat": "{{host}}/{{owner}}/{{repository}}/commit/{{hash}}",
"compareUrlFormat": "{{host}}/{{owner}}/{{repository}}/compare/{{previousTag}}...{{currentTag}}"
}์ด ์ค์ ์ ์ฌ์ฉํ๋ฉด CHANGELOG์ ์ด๋ชจ์ง์ ํ๊ธ ์น์ ์ ๋ชฉ์ด ์ถ๊ฐ๋ผ์.
PR์ CHANGELOG ๋ฏธ๋ฆฌ๋ณด๊ธฐ ์ถ๊ฐ
release-please๋ฅผ ์ฌ์ฉํ๋ฉด Release PR์ ์๋์ผ๋ก CHANGELOG ๋ฏธ๋ฆฌ๋ณด๊ธฐ๊ฐ ์ถ๊ฐ๋ผ์. ๋ณ๋ ์ค์ ์ด ํ์ ์์ด์.
standard-version์ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ์๋ ์ถ๊ฐ ์ก์
์ ์ฌ์ฉํด์ PR์ ์ฝ๋ฉํธ๋ก CHANGELOG๋ฅผ ๋ฌ ์ ์์ด์.
# .github/workflows/preview-changelog.yml
name: Preview CHANGELOG
on:
pull_request:
branches:
- main
jobs:
preview:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Generate preview
run: |
npx standard-version --dry-run > changelog-preview.txt
- name: Comment PR
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const preview = fs.readFileSync('changelog-preview.txt', 'utf8');
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: `## CHANGELOG Preview\n\n\`\`\`\n${preview}\n\`\`\``
});ํธ๋ฌ๋ธ์ํ
์ปค๋ฐ ์ปจ๋ฒค์ ๋ฏธ์ค์ ๋ฌธ์
ํ์๋ค์ด Conventional Commits ๊ท์น์ ๋ฐ๋ฅด์ง ์์ผ๋ฉด CHANGELOG๊ฐ ์ ๋๋ก ์์ฑ๋์ง ์์์.
ํด๊ฒฐ ๋ฐฉ๋ฒ
Husky์ commitlint๋ฅผ ์ฌ์ฉํด์ ์ปค๋ฐ ๋ฉ์์ง๋ฅผ ๊ฒ์ฆํ์ธ์.
npm install --save-dev @commitlint/cli @commitlint/config-conventional husky// commitlint.config.js
module.exports = {
extends: ["@commitlint/config-conventional"],
};# Husky ์ค์
npx husky init
echo "npx --no -- commitlint --edit \$1" > .husky/commit-msg์ด์ ๊ท์น์ ๋ง์ง ์๋ ์ปค๋ฐ ๋ฉ์์ง๋ ์๋์ผ๋ก ๊ฑฐ๋ถ๋ผ์.
๊ถํ ์ค๋ฅ (GITHUB_TOKEN)
์ํฌํ๋ก์ฐ์์ Git ํธ์๋ Release ์์ฑ ์ ๊ถํ ์ค๋ฅ๊ฐ ๋ฐ์ํ ์ ์์ด์.
Error: Resource not accessible by integrationํด๊ฒฐ ๋ฐฉ๋ฒ
์ํฌํ๋ก์ฐ ํ์ผ์ permissions๋ฅผ ๋ช
์ํ์ธ์.
permissions:
contents: write
pull-requests: write๋๋ GitHub ์ ์ฅ์ Settings > Actions > General > Workflow permissions์์ "Read and write permissions"๋ฅผ ํ์ฑํํ์ธ์.
์ฃผ์
GITHUB_TOKEN์ ์ํฌํ๋ก์ฐ๊ฐ ์คํ๋ ๋ ์๋์ผ๋ก ์์ฑ๋ผ์. ๋ณ๋๋ก ์ํฌ๋ฆฟ์
์ถ๊ฐํ ํ์๊ฐ ์์ด์.
๋ง๋ฌด๋ฆฌ
GitHub Actions๋ก CHANGELOG๋ฅผ ์๋ํํ๋ฉด ๋ฆด๋ฆฌ์ฆ ํ๋ก์ธ์ค๊ฐ ํจ์ฌ ํจ์จ์ ์ผ๋ก ๋ณํด์. ํต์ฌ ๋ด์ฉ์ ์ ๋ฆฌํ๋ฉด ๋ค์๊ณผ ๊ฐ์์.
- Conventional Commits ๊ท์น ์ค์:
feat,fix,docs๋ฑ์ ํ์ ์ผ๋ก ์ปค๋ฐ ๋ฉ์์ง ์์ฑ - ์๋ํ ๋๊ตฌ ์ ํ: ๊ฐ๋จํ ํ๋ก์ ํธ๋ standard-version, ํ ํ๋ก์ ํธ๋ release-please ์ถ์ฒ
- GitHub Actions ์ํฌํ๋ก์ฐ:
main๋ธ๋์น ํธ์ ๋๋ ์๋ ํธ๋ฆฌ๊ฑฐ๋ก CHANGELOG ์๋ ์์ฑ - ์ปค๋ฐ ๋ฉ์์ง ๊ฒ์ฆ: commitlint๋ก ๊ท์น์ ๊ฐ์ ํ์ฌ ์ผ๊ด์ฑ ์ ์ง
์ค๋ฌด ์ ์ฉ ํ
- ์ฒ์์๋
release-please๋ก ์์ํด์ PR๋ก ๋ฆด๋ฆฌ์ฆ๋ฅผ ๊ฒํ ํ์ธ์ - ํ์๋ค์๊ฒ Conventional Commits ๊ฐ์ด๋๋ฅผ ๊ณต์ ํ์ธ์
.versionrc.json์ผ๋ก CHANGELOG ํ์์ ํ ์คํ์ผ์ ๋ง๊ฒ ์ปค์คํฐ๋ง์ด์งํ์ธ์- ๋ฆด๋ฆฌ์ฆ ๋ ธํธ์ ๋ง์ด๊ทธ๋ ์ด์ ๊ฐ์ด๋๋ ์ฃผ์ ๋ณ๊ฒฝ ์ฌํญ์ ์ถ๊ฐ๋ก ์์ฑํ์ธ์
์ด์ ์๋์ผ๋ก CHANGELOG๋ฅผ ์์ฑํ๋ ์๊ณ ๋ฅผ ๋๊ณ ์ฝ๋ ์์ฑ์ ์ง์คํ์ธ์!
Afaik ยฉ 2025
์ธ๋ถ ๋งํฌ