release-plz로 Rust 패키지 릴리스 자동화하기
Rust로 라이브러리를 만들어서 crates.io에 배포하고 있다면 릴리스할 때마다 반복해야 하는 작업이 꽤 많다는 걸 느끼셨을 거예요. Cargo.toml의 버전 올리고 체인지로그 정리하고 cargo publish 실행하고 git 태그 만들고 GitHub Release도 작성하고… 🤔 매번 수작업으로 하다 보면 빼먹는 단계가 생기기 마련이죠.
release-plz는 이 과정을 통째로 자동화해주는 도구인데요. Conventional Commits 기반으로 버전을 알아서 올려주고, 체인지로그도 자동 생성하고, PR 하나 머지하면 crates.io 배포까지 끝나도록 만들어줍니다. 이번 글에서는 release-plz를 처음 도입하는 분들을 위해 설치부터 GitHub Actions 연동까지 차근차근 살펴보겠습니다.
release-plz가 뭔가요?
release-plz는 Rust 프로젝트의 릴리스 파이프라인을 자동화해주는 도구입니다. Google의 release-please에서 영감을 받아 만들어졌는데, Rust 생태계에 최적화되어 있다는 게 큰 차이점이에요.
release-please가 git 태그를 기준으로 다음 버전을 결정하는 반면, release-plz는 cargo 레지스트리에 실제로 배포된 버전과 로컬 패키지를 비교합니다. 덕분에 별다른 설정 없이도 바로 사용할 수 있고, Cargo 워크스페이스도 잘 지원합니다.
핵심 기능을 정리하면 이렇습니다.
우선 커밋 메시지를 분석해서 Semantic Versioning에 맞게 버전을 자동으로 올려줍니다. feat: 커밋이 있으면 마이너 버전을, fix: 커밋이 있으면 패치 버전을, BREAKING CHANGE가 포함되면 메이저 버전을 올리는 식이죠. 여기에 cargo-semver-checks를 활용해서 API 호환성이 깨지는 변경도 자동 감지합니다.
또한 git-cliff를 내장하고 있어서 체인지로그를 Keep a Changelog 형식으로 자동 생성해줍니다. 수작업으로 체인지로그를 관리할 필요가 없어지는 거예요.
마지막으로 Release PR이라는 개념이 있는데, 버전 변경과 체인지로그 업데이트를 담은 PR을 자동으로 만들어줍니다. 이 PR을 머지하면 crates.io에 배포되고, git 태그와 GitHub Release도 알아서 생성됩니다.
CLI 설치하기
release-plz CLI를 로컬에서 사용하려면 cargo로 설치할 수 있습니다.
cargo install release-plz --locked
설치가 완료되면 release-plz --help로 사용 가능한 명령어를 확인해볼 수 있어요.
Usage: release-plz <COMMAND>
Commands:
update Update version and changelog
release-pr Open a release Pull Request
release Release unpublished packages
init Initialize release-plz
set-version Set version of a package
generate-completions Generate shell completions
generate-schema Generate JSON schema
Conventional Commits 알아두기
release-plz가 버전을 자동으로 올려주는 기반이 되는 게 바로 Conventional Commits 규칙입니다. 커밋 메시지를 일정한 형식으로 작성하면 도구가 이를 파싱해서 어떤 종류의 변경인지 판단하는 거예요.
기본 형식은 <type>(<scope>): <description>이고, 자주 쓰는 타입을 살펴보면 이렇습니다.
# 새 기능 추가 → 마이너 버전 올림 (0.1.0 → 0.2.0)
git commit -m "feat: add serialize support for Config struct"
# 버그 수정 → 패치 버전 올림 (0.1.0 → 0.1.1)
git commit -m "fix: handle empty input in parse function"
# 문서 변경 → 패치 버전 올림
git commit -m "docs: update README with usage examples"
# 리팩토링 → 패치 버전 올림
git commit -m "refactor: simplify error handling logic"
# 호환성 깨지는 변경 → 메이저 버전 올림 (0.1.0 → 1.0.0)
git commit -m "feat!: redesign public API"
커밋 본문에 BREAKING CHANGE:를 명시하는 방법도 있습니다.
git commit -m "feat: change return type of process()
BREAKING CHANGE: process() now returns Result<T> instead of Option<T>"
이렇게 규칙을 지켜서 커밋하면 release-plz가 알아서 적절한 버전을 계산해줍니다. 처음에는 좀 번거롭게 느껴질 수 있지만, 습관이 되면 커밋 히스토리도 깔끔해지고 체인지로그도 저절로 만들어지니 꽤 편해요.
로컬에서 사용하기
CI 없이 로컬 환경에서도 release-plz를 활용할 수 있습니다. 주요 명령어 세 가지를 순서대로 살펴볼게요.
release-plz update
release-plz update 명령어는 현재 프로젝트의 패키지를 분석해서 버전과 체인지로그를 업데이트합니다. 아직 아무것도 커밋하거나 배포하지 않고, 로컬 파일만 수정하는 거예요.
release-plz update
이 명령어가 실행되면 내부적으로 여러 단계를 거칩니다. 먼저 cargo 레지스트리에서 현재 배포된 패키지를 다운로드한 뒤, 로컬 코드와 비교해서 새로운 커밋이 있는지 확인합니다. cargo-semver-checks가 설치되어 있다면 API 호환성 검사도 수행하고요. 그다음 Conventional Commits 규칙에 따라 적절한 버전을 결정하고, Cargo.toml의 버전을 올리고 CHANGELOG.md를 업데이트합니다.
실행 후에는 변경된 파일을 직접 확인하고 커밋하면 됩니다.
# 변경 내역 확인
git diff
# 변경사항 커밋
git add Cargo.toml Cargo.lock CHANGELOG.md
git commit -m "chore: prepare release v0.2.0"
release-plz release
release-plz release 명령어는 아직 배포되지 않은 패키지를 실제로 릴리스합니다.
release-plz release
이 명령어는 <패키지명>-v<버전> 형식의 git 태그를 만들고(예: my-crate-v0.2.0) cargo publish를 실행해서 crates.io에 배포하고 GitHub Release까지 생성합니다. 패키지가 하나뿐인 프로젝트에서는 태그에서 패키지명이 생략되어 v0.2.0 같은 형식이 됩니다.
이 명령어는 Cargo.toml을 수정하거나 새 커밋을 만들지 않습니다. 현재 저장소 상태 그대로 릴리스하는 거예요. 그래서 보통 release-plz update로 버전을 올린 뒤 커밋하고, 그다음에 release-plz release를 실행하는 흐름으로 사용합니다.
release-plz release-pr
release-plz release-pr은 release-plz update와 비슷하지만, 변경사항을 로컬에 남기는 대신 GitHub PR로 만들어줍니다.
release-plz release-pr
이 명령어가 생성하는 PR에는 Cargo.toml의 버전 변경과 Cargo.lock 업데이트 그리고 CHANGELOG.md 업데이트가 포함돼요. PR 본문에는 각 패키지의 변경 내역이 체인지로그 형태로 정리되어 나옵니다.
이미 Release PR이 열려있는 상태에서 새 커밋이 추가되면 release-plz가 기존 PR을 업데이트합니다. 다만 누군가 PR에 직접 커밋을 추가한 경우에는 기존 PR을 닫고 새 PR을 만들어서 기여 내역을 보존해요.
GitHub Actions로 완전 자동화
release-plz의 진가는 GitHub Actions와 함께 쓸 때 발휘됩니다. main 브랜치에 푸시될 때마다 자동으로 Release PR을 만들고, PR이 머지되면 자동 배포까지 이루어지는 파이프라인을 구성할 수 있어요.
사전 준비
GitHub Actions 워크플로우를 설정하기 전에 두 가지를 먼저 준비해야 합니다.
우선 저장소의 GitHub Actions 설정에서 “Workflow permissions”를 수정해야 합니다. “Allow GitHub Actions to create and approve pull requests” 옵션을 활성화해야 release-plz가 PR을 만들 수 있습니다.
다음으로 crates.io에 배포하려면 레지스트리 토큰이 필요합니다. crates.io에서 API 토큰을 발급받을 때 publish-new와 publish-update 스코프를 지정하고, 이 토큰을 저장소의 Secrets에 CARGO_REGISTRY_TOKEN이라는 이름으로 저장합니다.
워크플로우 작성
.github/workflows/release-plz.yml 파일을 만들어서 다음과 같이 작성합니다.
name: Release-plz
on:
push:
branches:
- main
jobs:
release-plz-release:
name: Release-plz release
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: read
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
persist-credentials: false
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
- name: Run release-plz
uses: release-plz/action@v0.5
with:
command: release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
release-plz-pr:
name: Release-plz PR
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
concurrency:
group: release-plz-${{ github.ref }}
cancel-in-progress: false
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
persist-credentials: false
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
- name: Run release-plz
uses: release-plz/action@v0.5
with:
command: release-pr
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
이 워크플로우에는 두 개의 job이 있는데요.
release-plz-release job은 release-plz release 명령어를 실행합니다. Release PR이 머지되어 main에 푸시가 일어나면 아직 배포되지 않은 패키지를 crates.io에 배포하고 git 태그와 GitHub Release를 만들어요. 이 job에서는 concurrency 설정을 일부러 넣지 않았는데요. 동시 실행 제한을 걸면 새 커밋이 들어올 때 대기 중인 릴리스가 취소될 수 있기 때문입니다.
release-plz-pr job은 release-plz release-pr 명령어를 실행합니다. 새 커밋이 main에 들어올 때마다 Release PR을 생성하거나 업데이트하고요. 여기에는 concurrency 설정이 들어가 있어서 동시에 여러 PR 업데이트가 일어나는 걸 방지합니다.
checkout 단계에서 fetch-depth: 0을 설정하는 건 전체 git 히스토리가 필요하기 때문이에요. release-plz가 이전 릴리스 이후의 커밋을 분석해야 올바른 버전과 체인지로그를 생성할 수 있거든요.
전체 릴리스 흐름
GitHub Actions를 설정하고 나면 릴리스 과정이 이렇게 진행됩니다.
개발자: feat: add new parser (커밋 & 푸시)
↓
GitHub Actions: release-plz release-pr 실행
↓
Release PR 자동 생성 (버전 0.1.0 → 0.2.0, CHANGELOG 업데이트)
↓
개발자: PR 리뷰 & 머지
↓
GitHub Actions: release-plz release 실행
↓
crates.io 배포 + git 태그 생성 + GitHub Release 생성
개발자가 할 일은 Conventional Commits 규칙에 맞춰 커밋하고, 생성된 Release PR을 확인한 뒤 머지하는 것뿐입니다. 나머지는 전부 자동이에요.
GitHub 토큰 관련 참고사항
기본 GITHUB_TOKEN으로도 대부분 잘 작동하지만 한 가지 제약이 있습니다. GITHUB_TOKEN으로 만든 PR이나 태그는 다른 GitHub Actions 워크플로우를 트리거하지 못해요. 예를 들어 Release PR에 대해 CI 검사를 자동으로 돌리고 싶거나, 릴리스 후 추가 워크플로우를 실행하고 싶다면 Personal Access Token(PAT)을 사용해야 합니다.
Fine-grained PAT을 만들 때는 “Contents”와 “Pull requests”에 read/write 권한을 부여하면 됩니다. 이 토큰을 저장소 Secrets에 RELEASE_PLZ_TOKEN 같은 이름으로 저장하고, 워크플로우에서 GITHUB_TOKEN 대신 사용하면 돼요.
env:
GITHUB_TOKEN: ${{ secrets.RELEASE_PLZ_TOKEN }}
GitHub App을 만들어서 사용하는 방법도 있는데, 이렇게 하면 커밋 작성자가 release-plz[bot] 같은 봇 계정으로 표시되어서 더 깔끔해 보입니다.
설정 파일로 커스터마이징
release-plz는 설정 없이도 잘 동작하지만, 프로젝트 특성에 맞게 조정하고 싶을 때는 release-plz.toml 파일을 프로젝트 루트에 만들면 됩니다.
기본 설정
[workspace]
# Release PR의 브랜치 접두사 (기본값: "release-plz-")
pr_branch_prefix = "release-plz-"
# Release PR에 라벨 추가
pr_labels = ["release"]
# cargo-semver-checks로 API 호환성 검사 (기본값: true)
semver_check = true
# 체인지로그 자동 업데이트 (기본값: true)
changelog_update = true
# git 태그 생성 (기본값: true)
git_tag_enable = true
# GitHub Release 생성 (기본값: true)
git_release_enable = true
# Release PR을 draft로 만들기
pr_draft = false
패키지별 설정
Cargo 워크스페이스에서 패키지마다 다른 설정을 적용할 수도 있습니다.
[workspace]
semver_check = true
# 특정 패키지 설정 오버라이드
[[package]]
name = "my-core-lib"
changelog_path = "crates/core/CHANGELOG.md"
# 내부용 패키지는 배포 제외
[[package]]
name = "my-internal-tool"
publish = false
release = false
# 여러 패키지의 버전을 동기화
[[package]]
name = "my-client"
version_group = "sdk"
[[package]]
name = "my-server"
version_group = "sdk"
version_group을 같은 값으로 설정하면 그 패키지의 버전이 항상 동일하게 유지됩니다. SDK처럼 클라이언트와 서버의 버전을 맞춰야 할 때 유용하죠.
PR 템플릿 커스터마이징
Release PR의 제목과 본문을 Tera 템플릿으로 커스터마이징할 수도 있습니다.
[workspace]
pr_name = "chore: release {{ version }}"
pr_body = """
{% for release in releases %}
## {{ release.package }} {{ release.next_version }}
{% if release.changelog %}
{{ release.changelog }}
{% endif %}
{% endfor %}
"""
release-plz init으로 빠르게 시작하기
처음 release-plz를 도입할 때 release-plz init 명령어를 사용하면 대화형으로 필요한 설정을 해줍니다.
release-plz init
이 명령어는 내부적으로 gh CLI를 사용해서 저장소 Secrets에 토큰을 등록하고, GitHub Actions 워크플로우 파일을 생성합니다. gh CLI가 미리 설치되어 있어야 하니 참고하세요.
단일 패키지 vs 워크스페이스
release-plz는 단일 크레이트 프로젝트와 Cargo 워크스페이스 프로젝트 모두 지원합니다.
단일 패키지 프로젝트에서는 git 태그가 v0.2.0 형식으로 생성되고 Release PR에도 그 패키지의 변경사항만 담깁니다.
워크스페이스 프로젝트에서는 패키지별로 독립적인 버전 관리가 이루어져요. git 태그는 my-crate-v0.2.0 형식으로 패키지명이 포함되고 Release PR 하나에 변경된 모든 패키지의 버전 범프와 체인지로그가 함께 담깁니다.
워크스페이스에서 특정 패키지만 릴리스하고 싶다면 -p 플래그를 사용할 수 있어요.
release-plz release -p my-core-lib
문제가 생겼을 때
release-plz를 사용하면서 자주 마주치는 상황과 해결 방법을 살펴볼게요.
“왜 버전이 안 올라가지?” 싶을 때는 커밋 메시지가 Conventional Commits 형식을 따르고 있는지 확인해보세요. feat:, fix:, docs: 같은 접두사 없이 그냥 “fixed bug”라고 쓰면 release-plz가 이를 분석할 수 없습니다.
Release PR이 생성되지 않는다면 GitHub Actions 설정에서 PR 생성 권한이 활성화되어 있는지 확인해보세요. 저장소의 Settings → Actions → General에서 “Allow GitHub Actions to create and approve pull requests”가 체크되어 있어야 합니다.
cargo publish가 실패한다면 CARGO_REGISTRY_TOKEN이 올바르게 설정되어 있는지 확인해보세요. 토큰에 publish-new와 publish-update 스코프가 포함되어 있어야 합니다.
마치며
release-plz를 도입하면 Rust 프로젝트의 릴리스 과정에서 사람이 직접 해야 하는 일이 크게 줄어듭니다. Conventional Commits 규칙만 잘 지켜서 커밋하면 버전 관리와 체인지로그 그리고 배포가 전부 자동으로 이루어지니까요.
처음 설정할 때 약간의 시간이 들지만 한번 파이프라인을 구축해놓으면 그 뒤로는 Release PR 머지 한 번으로 릴리스가 끝나는 편안함을 느낄 수 있을 거예요. 특히 여러 크레이트를 관리하는 워크스페이스 프로젝트에서 진가를 발휘합니다.
GitHub Actions 워크플로우에 익숙하지 않다면 관련 글을 먼저 읽어보시는 걸 추천드리고요. release-plz의 더 자세한 설정 옵션은 공식 문서에서 확인할 수 있습니다.
This work is licensed under
CC BY 4.0