Homebrew Tap 미러링
멀티-캐스크 tap 에 있는 cask 파일을 별도 single-cask tap 으로 자동 복제하는 패턴.
연관 문서: macos-brew-deploy.md (이 미러를 활용하는 macOS 배포 흐름)
언제 필요한가
새 멀티-캐스크 tap (<org>/homebrew-tap) 으로 옮긴 후에도, 이전 single-cask tap (<org>/homebrew-<slug>) 로 이미 받아간 사용자 가 정상적으로 brew upgrade 받을 수 있게 하기 위해.
새 tap (소스): <org>/homebrew-tap ← release-mac 이 cask 갱신
│
│ push paths: Casks/<slug>.rb
▼
mirror-<slug>.yml (GitHub Actions)
│
│ verbatim copy
▼
legacy tap (목적지): <org>/homebrew-<slug> ← 옛 사용자들이 tap 한 위치
옛 사용자는 그대로 <org>/homebrew-<slug> 를 tap 한 상태로 두면서도 새 URL / 새 sha256 의 zip 을 자동으로 받게 된다.
워크플로 (<org>/homebrew-tap/.github/workflows/mirror-<slug>.yml)
name: Mirror <slug> cask to legacy tap
on:
push:
branches: [main]
paths: ['Casks/<slug>.rb']
workflow_dispatch:
permissions:
contents: read
jobs:
mirror:
runs-on: ubuntu-latest
steps:
- name: Checkout source tap
uses: actions/checkout@v4
with:
path: source
- name: Checkout legacy tap
uses: actions/checkout@v4
with:
repository: <org>/homebrew-<slug>
path: legacy
token: $
- name: Sync cask file
working-directory: legacy
run: |
mkdir -p Casks
cp ../source/Casks/<slug>.rb Casks/<slug>.rb
if git diff --quiet Casks/<slug>.rb; then
echo "Cask already in sync — nothing to do."
exit 0
fi
VERSION=$(sed -nE 's/.*version "([^"]+)".*/\1/p' Casks/<slug>.rb | head -1)
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add Casks/<slug>.rb
git commit -m "Mirror <slug> v${VERSION:-unknown} from homebrew-tap"
git push
필요한 시크릿
<org>/homebrew-tap 레포 시크릿에 등록:
LEGACY_TAP_PUSH_TOKEN—<org>/homebrew-<slug>에contents: write권한이 있는 fine-grained PAT
PAT 발급:
- GitHub Settings → Developer settings → Personal access tokens → Fine-grained tokens
- Repository access:
<org>/homebrew-<slug>만 - Permissions: Repository permissions → Contents: Read and write
- 토큰을
<org>/homebrew-tapSecrets 에LEGACY_TAP_PUSH_TOKEN으로 저장
미러는 slug-agnostic
워크플로가 cask 파일을 verbatim 복사한다. 따라서:
- 본 레포
release-mac에서 슬러그 / 태그 / URL 만 바꿔도 legacy tap 까지 자동 전파됨 - 워크플로 자체는 손댈 필요 없음 (앱 추가 시에는 새 yml 파일 하나만 추가)
미러가 보장하는 것
옛 사용자가 <org>/homebrew-<slug> 를 tap 한 상태 그대로 brew upgrade 만 돌려도 새 cask (새 URL / 새 sha256) 가 적용된다. brew untap / 재-tap 같은 사용자 측 마이그레이션이 필요 없음.
새 앱에 미러 추가 절차
- legacy single-app tap 레포 생성 (
<org>/homebrew-<new-slug>) — 빈 main 브랜치면 충분 - fine-grained PAT 발급 후
<org>/homebrew-tapSecrets 에 추가 (시크릿 이름은 공유 가능: 모든 앱이 같은LEGACY_TAP_PUSH_TOKEN을 써도 됨. PAT scope 에 각 legacy 레포가 다 포함되어 있다면) <org>/homebrew-tap에.github/workflows/mirror-<new-slug>.yml추가 (위 템플릿)Casks/<new-slug>.rb가 push 되면 워크플로가 fire 되어 legacy tap 초기화
함정과 교훈
- 순서: 본 레포 push → mirror workflow → legacy push 순으로 fire. mirror 가 cask 만 복사하므로 cask 안의 URL 에 가리키는 release / zip 은 이미 GitHub Releases 에 올라가 있어야 한다 (그래서
release-mac은 release 부터 만들고 cask 를 마지막에 push). - PAT 만료: fine-grained PAT 은 max 1년. 만료 시 mirror 가 silent 하게 실패하지 않도록 Actions 알림 / cron 모니터 설정 권장.
- legacy tap 의 손수 편집 금지: mirror 가 force 가 아닌 일반 push 라 conflict 나면 멈춤. legacy 레포는 mirror 가 단독 소유.
- 변경 없을 때 commit 안 함.
git diff --quiet가드가 핵심. cask 미변경 무 commit 으로 history 깨끗.