main 에 머지된 앱 변경을 Firebase App Distribution 으로 테스터에게 자동 전달하는 흐름. docs/**·루트 Markdown·LICENSE만 바뀐 push는 제외한다. Firebase 프로젝트 slow-clock-scheduler, 테스터 그룹 slowclock.
이 배포는 Google Play 출시가 아니다. Play 내부 테스트 트랙 배포는 Play release runbook 을 따른다.
| 채널 | 트리거 | 워크플로 | 산출물 | 자격 |
|---|---|---|---|---|
| Firebase App Distribution | main push |
release-distribution.yml |
release APK | release-distribution environment |
| WIF canary | 수동 실행 + environment 승인 | firebase-wif-canary.yml |
업로드만 하는 canary APK, 테스터 배포 없음 | release-distribution environment |
feat/<N> → main 단일 흐름이라 main 에 머지된 PR 하나가 곧 릴리스 후보다. 별도 릴리스 브랜치·릴리스 PR 은 없다.
워크플로는 main push 에 연결된 머지 PR 의 본문에서 두 섹션을 읽는다 (.github/PULL_REQUEST_TEMPLATE.md).
## 📌 Issues
- closed #34
## 📎 Work Description
- Google 로그인 스코프에서 캘린더를 뺐다
- 알람이 잠금 화면에서도 뜬다📌 Issues에서#N형식의 번호를,📎 Work Description에서 글머리표 줄을 모은다.- 둘 중 하나라도 비어 있으면
render-distribution-release-notes.sh가 Firebase 업로드 전에 실패한다. 테스터가 무엇을 확인할지 모르는 배포는 내보내지 않는다. 💬 To Reviewers는 릴리스 노트에 들어가지 않는다.
PR 검증(lint·unit-test·screenshot)은 시크릿 없이 setup-ci-config 가 만드는 stub 설정으로 돈다. 실서비스 값은 보호된 environment 의 secret 으로만 존재한다.
| 이름 | 위치 | 값 |
|---|---|---|
GOOGLE_SERVICES_JSON_B64 |
release-distribution → Environment secrets |
Firebase 콘솔의 google-services.json(com.ilhyok.slowclock) base64 |
RELEASE_STORE_FILE_B64 |
release-distribution → Environment secrets |
upload keystore(~/slowclock-release.jks) base64 |
RELEASE_STORE_PASSWORD · RELEASE_KEY_ALIAS · RELEASE_KEY_PASSWORD |
release-distribution → Environment secrets |
keystore 비밀번호 · alias(slowclock-upload) · key 비밀번호 |
GCP_WORKLOAD_IDENTITY_PROVIDER |
release-distribution → Environment secrets |
projects/887622067286/locations/global/workloadIdentityPools/github-actions/providers/github |
GCP_FIREBASE_SERVICE_ACCOUNT |
release-distribution → Environment secrets |
github-firebase-distribution@slow-clock-scheduler.iam.gserviceaccount.com |
- Deployment branches 는
main만 허용한다. - 장기 서비스 계정 JSON 키는 어디에도 두지 않는다. 업로드 직전에 Workload Identity Federation 으로 단기 자격을 받는다 (WIF runbook).
- base64 인코딩:
base64 -i ~/slowclock-release.jks | tr -d '\n' | pbcopy(macOS) - 시크릿 등록 절차 전체는 CI 설정 runbook.
배포 워크플로는 signing이 끝난 APK를 SDK apksigner verify --verbose --print-certs로 검증한다. 이 검증을 통과한 APK 하나를 subject로 GitHub artifact attestation 을 발급하고, 업로드 전에 스스로 검증한다. 서명·저장소·signer workflow·source commit·GitHub-hosted 러너 중 하나라도 어긋나거나 attestation subject digest 가 빌드 직후 digest 와 다르면 Firebase 업로드까지 가지 않는다.
성공한 run 의 summary 에 남는 값은 넷이다: source commit SHA, sha256: artifact digest, attestation URL, run URL. APK·AAB 자체는 public Actions artifact 로 게시하지 않는다.
받은 APK 가 정말 그 배포 경로에서 나왔는지는 손에 든 파일로 직접 확인할 수 있다.
gh attestation verify ~/Downloads/app-release.apk --repo 1hyok/SlowClock --signer-workflow 1hyok/SlowClock/.github/workflows/release-distribution.yml --source-ref refs/heads/main --deny-self-hosted-runners아래 로컬 fallback 으로 올린 빌드에는 attestation 이 없다. 그 경로로 배포한 APK 는 위 명령이 실패하는 게 정상이며, 그래서 CI 장애 때만 쓴다.
local.properties에RELEASE_STORE_FILE·RELEASE_STORE_PASSWORD·RELEASE_KEY_ALIAS·RELEASE_KEY_PASSWORD4키가 있어야 한다. 새 keystore 를 임의로 만들지 않는다. 다른 키로 서명하면 기존 설치 위에 업데이트되지 않는다.app/google-services.json은 Firebase 콘솔 → 프로젝트 설정 → Android 앱com.ilhyok.slowclock에서 받은 파일이어야 한다.firebase login이 돼 있어야 한다.
git fetch origin main
git switch --detach origin/main
test "$(git rev-parse HEAD)" = "$(git rev-parse origin/main)"
test -z "$(git status --porcelain)"
EVENT_NAME=workflow_dispatch \
ISSUE_NUMBERS="#34" \
RELEASE_NOTES="캘린더 스코프 제거 확인;잠금 화면 알람 확인" \
SOURCE_REF=main \
SOURCE_SHA="$(git rev-parse origin/main)" \
bash .github/scripts/render-distribution-release-notes.sh /tmp/slowclock-release-notes.txt
JAVA_HOME=~/Library/Java/JavaVirtualMachines/temurin-21.0.11/Contents/Home \
./gradlew assembleRelease appDistributionUploadRelease \
--releaseNotesFile=/tmp/slowclock-release-notes.txt \
--no-daemon자동 Firebase 배포는
SLOWCLOCK_VERSION_CODE=github.run_number,SLOWCLOCK_VERSION_NAME=1.0-dist.<run>.<sha7>을 주입한다. 위 로컬 fallback과 WIF canary는 별도 버전 주입이 없으면 기본값versionCode=1,versionName=1.0을 쓴다. Play용 번호는 별도release-play-internal.yml이 생성한다.
| Firebase App Distribution | Play 내부 테스트 트랙 | |
|---|---|---|
| 목적 | 출시 전 내부 확인 | Play 설치 경로 검증 → production 승격 |
| 산출물 | release APK | release AAB |
| 트리거 | main push 자동 |
main 에서 수동 실행 + environment 승인 |
| versionCode | 자동 배포 workflow의 github.run_number |
run 마다 단조 증가 |
| 자격 | release-distribution environment |
play-internal environment (별도 서비스 계정) |
| 롤백 | 이전 빌드를 다시 배포 | 릴리스 중단 후 더 큰 versionCode 로 재배포 |
두 채널의 설치 인증서가 다르면(Play App Signing 이 앱 서명 키를 새로 만들 때) 앱이 서로 위에 업데이트되지 않는다. 테스터가 채널을 옮길 때는 삭제 후 재설치가 필요하다.
- 추가/제거: Firebase Console → App Distribution → 테스터 및 그룹 →
slowclock그룹 편집. CLI:firebase appdistribution:testers:add <email> --group-alias slowclock --project slow-clock-scheduler - 신규 테스터는 첫 초대 이메일에서 App Tester 앱 설치 안내를 받는다 → 이후 빌드는 자동 알림