d3ro-voice/docs/deployment/release-guide.md
Yun Chan 3beba99668 feat(release): switchboard 릴리스 체계 이식 — Mac 배포 + Registry 게시 + 자동 업데이트
- package-macos CI job: arm64 무서명(ad-hoc) dmg+zip, D3RO_MAC_RUNNER 변수 게이트
- sync-version.mjs: 태그 → package.json 버전 동기화
- publish-gitlab-release.mjs: Generic Package Registry(버전별+latest) 업로드 + Release 생성
- electron-builder: publish generic(latest.yml 생성), 공백 없는 artifactName, mac arm64 단일화
- UpdateService: electron-updater 4h 주기 체크 + 재시작 다이얼로그 (update-feed.ts SSOT)
- @rollup/rollup-win32-x64-msvc → optionalDependencies (mac npm ci EBADPLATFORM 해소)
- docs/deployment/release-guide.md: runner 등록·feed 설정·파일명 규칙 가이드

리뷰 워크플로(3관점 적대적 검증)로 확정된 결함 8건 반영:
publish 부재로 latest.yml 미생성, 파일명 공백 vs 레지스트리 404,
mac EBADPLATFORM, needs optional의 실패 미커버, DELETE 권한 의존,
CHANGELOG regex 경계, --arm64 무시, 다이얼로그 parent 부재
2026-07-21 12:43:16 +09:00

4.6 KiB

D3RO Voice 릴리스 가이드

agent-switchboard-client의 릴리스 체계를 이식한 멀티플랫폼 배포 파이프라인.

파이프라인 개요

git tag vX.Y.Z → push
  ├─ package-windows  (runner: windows+shell)   → NSIS exe + latest.yml
  ├─ package-macos    (runner: macos+arm64)     → dmg + zip + latest-mac.yml   [D3RO_MAC_RUNNER="true"일 때만]
  └─ release-create   (runner: windows+shell)
       ├─ Generic Package Registry 업로드
       │    ├─ d3ro-voice/<version>/  (버전별 보관)
       │    └─ d3ro-voice/latest/     (electron-updater feed — 매 릴리스 갱신)
       └─ GitLab Release 생성 + asset 링크
  • 버전은 태그에서 자동 동기화된다 (scripts/ci/sync-version.mjsv0.2.0 → package.json 0.2.0).
  • macOS artifacts가 없으면 Windows 단독으로 릴리스가 생성된다 (경고 로그만).

릴리스 절차

git tag v0.2.0
git push origin v0.2.0

끝. 파이프라인이 패키징 → 레지스트리 업로드 → Release 생성까지 자동 수행한다.

사용자가 1회 설정해야 하는 것

1. macOS runner 등록 (Mac 빌드 활성화)

MacBook에서:

brew install gitlab-runner
gitlab-runner register \
  --url https://gitlab.twentyoz.kr:8443 \
  --executor shell \
  --tag-list "macos,arm64"
# 등록 토큰: GitLab → d3r0/voice → Settings → CI/CD → Runners
brew services start gitlab-runner

Mac 환경 전제조건:

  • Xcode Command Line Tools (xcode-select --install)
  • Node 22+ (시스템 PATH)
  • Python 3.11+ (python3)
  • brew install sox — install-sox.sh가 이 바이너리를 번들함

등록 후 GitLab → Settings → CI/CD → VariablesD3RO_MAC_RUNNER = "true" 추가. (이 변수가 없으면 package-macos 잡이 생성되지 않아 릴리스가 Windows 단독으로 진행)

2. 자동 업데이트 활성화 (Windows)

  1. GitLab → d3r0/voice → 프로젝트 홈에서 Project ID 확인
  2. 두 곳에 같은 feed URL 기입 (어긋나면 안 됨):
    • apps/desktop/src/main/update-feed.tsUPDATE_FEED_URL
    • apps/desktop/electron-builder.ymlpublish.url (projects/0 → 실제 ID)
    https://gitlab.twentyoz.kr:8443/api/v4/projects/<PROJECT_ID>/packages/generic/d3ro-voice/latest
    
    publish 섹션은 latest.yml/latest-mac.yml 생성을 트리거하는 필수 설정이다 (없으면 electron-builder가 update info 파일을 아예 만들지 않음).
  3. GitLab → Settings → General → Visibility에서 "Allow anyone to pull from Package Registry" 활성화 (미설정 시 앱의 무인증 다운로드가 401 — UpdateService는 조용히 건너뜀)
  4. 다음 태그부터 배포된 앱이 4시간 주기로 업데이트를 체크한다

산출물 파일명 규칙

파일명에 공백 금지 — GitLab Generic Package Registry가 공백을 불허해 latest.yml의 url과 레지스트리 파일명이 어긋나면 업데이트 다운로드가 404 난다.

  • Windows: D3RO-Voice-Setup-<version>-x64.exe
  • macOS: D3RO-Voice-<version>-arm64.dmg / .zip

알려진 제약 / 후속 단계

항목 현재 상태 후속
macOS 서명/공증 ad-hoc 서명 (identity=-, switchboard 검증 조합) — Gatekeeper가 차단하면 우클릭→열기 또는 xattr -dr com.apple.quarantine "/Applications/D3RO Voice.app" Apple Developer 계정($99/년) 확보 시 switchboard의 prepare/cleanup-macos-keychain.mjs + 공증 패턴 이식. 주의: D3RO는 asarUnpack native 모듈 + ollama/sox 바이너리 다중 서명 필요
macOS 자동 업데이트 미지원 (Squirrel.Mac이 서명 요구) 서명 도입 후 latest-mac.yml feed 연결
업데이트 무결성 서명 latest.yml SHA-512 (electron-builder 기본) switchboard의 Ed25519 update-policy 매니페스트 체계 이식 검토
CHANGELOG 없음 — Release 노트는 기본 안내문 CHANGELOG.md 작성 시 publish 스크립트가 해당 버전 섹션을 자동 추출
mac x64 (Intel) 빌드 안 함 (사이드카가 arm64 전용) 수요 발생 시 Intel Mac runner 추가

참고 파일

  • .gitlab-ci.yml — 파이프라인 정의
  • scripts/ci/sync-version.mjs — 태그 → package.json 버전 동기화
  • scripts/ci/publish-gitlab-release.mjs — 레지스트리 업로드 + Release 생성
  • apps/desktop/src/main/services/UpdateService.ts — 자동 업데이트 (electron-updater)
  • apps/desktop/src/main/update-feed.ts — feed URL SSOT
  • 원본 패턴: D:\workspace\agent-switchboard-client (.gitlab-ci.yml, scripts/publish-gitlab-release.mjs)