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 부재
This commit is contained in:
Yun Chan 2026-07-21 12:43:16 +09:00
parent 8f7d300b89
commit 3beba99668
11 changed files with 776 additions and 2291 deletions

View file

@ -0,0 +1,34 @@
// scripts/ci/sync-version.mjs
// CI_COMMIT_TAG(v0.1.0-alpha 등)에서 버전을 추출해 apps/desktop/package.json에 기록한다.
// electron-builder가 package.json version으로 설치파일명/latest.yml을 만들기 때문에
// 태그와 산출물 버전이 어긋나지 않게 패키징 전에 실행한다.
import { readFileSync, writeFileSync } from 'node:fs'
import { fileURLToPath } from 'node:url'
import { dirname, join } from 'node:path'
const tag = process.env.CI_COMMIT_TAG ?? process.argv[2]
if (!tag) {
console.log('[sync-version] CI_COMMIT_TAG 없음 — 버전 동기화 건너뜀')
process.exit(0)
}
const version = tag.replace(/^v/, '')
if (!/^\d+\.\d+\.\d+(-[0-9A-Za-z.-]+)?$/.test(version)) {
console.error(`[sync-version] 유효하지 않은 semver: ${version} (tag: ${tag})`)
process.exit(1)
}
const root = join(dirname(fileURLToPath(import.meta.url)), '..', '..')
const pkgPath = join(root, 'apps', 'desktop', 'package.json')
const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'))
if (pkg.version === version) {
console.log(`[sync-version] 이미 동기화됨: ${version}`)
process.exit(0)
}
const prev = pkg.version
pkg.version = version
writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n', 'utf8')
console.log(`[sync-version] apps/desktop version: ${prev}${version}`)