Skip to content

PR 제목으로 버전을 올리고 머지를 막는 체크를 추가한다 #107

Description

@Wisesaturn

배경

v3 는 PR 이 머지될 때마다 Vercel 이 운영에 배포한다. 버전은 package.json 을 손으로 올리고 있어서, v3.0.0 과 v3.0.1 모두 버전 커밋을 따로 만들었다. 푸터가 package.json 의 버전을 읽으므로, 버전을 빠뜨리면 운영 화면의 버전 표시가 틀린다.

v3 에 머지하는 단위를 곧 릴리즈 단위로 삼는다(trunk-based). 이 이슈는 그 앞 절반이다: PR 이 머지되기 전에 버전이 올라가 있게 만들고, 올라가 있지 않으면 머지를 막는다.

정한 규칙

PR 에 붙인 버전 레이블로 정한다. 셋 중 하나만 붙이고, 없으면 버전을 올리지 않는다.

레이블 bump 흔한 PR Type
major major 개편
minor minor feat
patch patch fix, style, refactor
없음 none docs, chore
  • 처음에는 PR 제목의 타입(fix:, feat:)으로 정하려 했다. 타입은 변경의 성격이지 운영에 주는 영향이 아니라서, 판단을 명시하는 레이블로 바꿨다. 커밋 제목(hotfix/#104:)은 Conventional Commits 파서와 맞지 않아 처음부터 쓰지 않았다
  • /pr-convention 이 PR 을 만들 때 레이블을 고른다
  • bump commit 은 머지 전에 bot 이 PR 브랜치에 올린다. 머지 커밋 하나가 올바른 버전으로 한 번만 배포된다
  • sofac-front 의 .github/actions/version-parser 처럼 버전 계산을 composite action 으로 떼어 둔다

토큰

GITHUB_TOKEN 으로 push 하면 GitHub 이 그 push 로 워크플로를 다시 돌리지 않는다. bump commit 이 새 head 가 되어도 필수 체크가 돌지 않아 머지가 영원히 막힌다. 그래서 bot push 는 PAT 로 한다.

작업 범위

대상 브랜치는 .github/release.env 로 관리하고, 단계마다 composite action 으로 떼어 #108 의 릴리즈 워크플로와 나중에 바뀔 브랜치에서도 그대로 쓴다.

  • .github/release.env
    • RELEASE_BRANCHES="v3": 머지 1건이 릴리즈 1건인 브랜치. 공백으로 여러 개를 적을 수 있다
    • VERSION_FILE="package.json"
  • .github/actions/
    • release-config: env 파일을 읽어 PR 의 base 브랜치가 대상인지(enabled)와 버전 파일 경로를 돌려준다
    • version-label: PR 레이블에서 major·minor·patch 를 찾아 올릴 자리를 돌려준다. 없으면 none, 둘 이상이면 실패
    • semver-bump: 버전과 올릴 자리로 다음 버전을 계산한다 (sofac-front 의 version-parser 자리)
    • commit-version: 버전 파일을 기대 버전으로 덮어쓰고(누적하지 않음) 다르면 github-actions[bot] 이름으로 커밋해 push 한다
  • .github/scripts/getBumpType.ts (+spec): version-label 의 판단 규칙. 규칙은 spec 이 있는 이 파일에만 둔다
    • 테스트가 src/** 만 보므로 vitest.config.ts 의 include 에 더한다
  • .github/workflows/version-bump.yml
    • on.pull_request.branches 는 파일을 읽을 수 없어 모든 PR 의 opened, synchronize, reopened, labeled, unlabeled 에서 돌고, 대상 브랜치가 아니면 설정 단계 뒤에 끝난다
    • concurrency 를 PR 번호로 묶고 이전 실행을 취소한다
    • 기대 버전 = 지금 base 브랜치 끝의 버전 + 레이블의 bump. PR 의 base SHA 는 오래됐을 수 있어 쓰지 않는다
    • bump commit 을 push 한 실행은 실패로 끝내고, push 로 다시 도는 실행이 통과를 낸다. 레이블을 patch → minor → 없음 으로 바꿔도 매번 기대 버전으로 맞춰진다
  • .github/actions/ensure-version: version-label → base 버전 → semver-bump → commit-version 을 잇는다. 두 워크플로가 같은 규칙을 쓴다
  • .github/actions/sync-base: base 를 merge 한다. 버전 파일만 충돌하면 base 쪽 값으로 풀고, 다른 파일이 충돌하면 취소한다
  • .github/workflows/sync-release-prs.yml
    • PR 이 릴리즈 브랜치에 머지되면 같은 base 로 열린 PR 을 matrix 로 갱신한다: sync-base → ensure-version → push
    • 다른 파일이 충돌하면 PR 에 코멘트만 남긴다. fork PR 은 뺀다
    • 이슈마다 PR 이 자동으로 열려 여러 PR 이 동시에 열린다. 룰셋의 up-to-date 요구가 뒤처진 PR 을 막고, 이 워크플로가 풀어 준다
  • 레포 레이블 major, minor, patch 생성
  • /pr-convention
    • PR 을 만들 때 버전 레이블을 고르는 단계와 기준표를 더한다
    • PR 을 올린 뒤 로컬에서 더 커밋하려면 bot 커밋을 먼저 git pull --rebase 로 받는다

사용자가 할 일

  1. Fine-grained PAT 생성: Wisesaturn/blog 한정, Contents 읽기·쓰기, Pull requests 읽기, No expiration
  2. 레포 secret RELEASE_BOT_TOKEN 으로 등록
  3. 룰셋 생성 완료: release-branches (id 24037187), 대상 refs/heads/v3, 우회 없음
    • PR 필수(merge commit 만), 필수 체크 version-bump, Require branches to be up to date, 삭제·force push 금지
    • RELEASE_BRANCHES 를 바꾸면 룰셋 대상도 함께 바꾼다
    • PR 필수, 우회 없음
    • 필수 상태 체크: version-bump
    • Require branches to be up to date before merging 켜기
    • 허용 머지 방식: merge commit 만

이 설정이 막는 것

  • 동시에 열린 PR 두 개가 같은 버전(예: 둘 다 3.0.2)을 잡는 경우. 두 PR 의 version 변경이 같아 git 이 충돌 없이 합치므로, up-to-date 요구가 없으면 같은 버전이 두 번 나간다. 브랜치를 갱신하면 synchronize 로 다시 계산되어 3.0.3 이 된다
  • fork 에서 온 PR 은 secret 이 없어 체크가 실패한다. 개인 레포라 받아들인다
  • 이 이슈의 PR 은 워크플로 추가라 버전 레이블을 붙이지 않는다. 버전이 오르지 않는다

완료 조건

선행 의존

없음

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions