Wails 실전 강좌 #6 CI/CD 자동 릴리스 — GitHub Actions로 세 플랫폼 배포

5 분 소요

1부의 마지막 글입니다. #5에서 서명·공증을 익혔으니, 이제 이 전 과정을 자동화합니다. 목표는 명확합니다. Git 태그 하나를 밀면 macOS·Windows·Linux 세 플랫폼의 서명된 릴리스가 자동으로 만들어지는 것입니다. 손으로 세 번 빌드하고 서명하던 일을 GitHub Actions에 넘깁니다.

총 10편, 2부 구성이며 이 글은 1부의 마지막입니다.

왜 매트릭스인가: macOS는 크로스컴파일이 안 된다 #

입문 #6에서 언급했듯, 데스크톱 앱은 한 OS에서 세 OS용 바이너리를 뽑기 어렵습니다. 특히 macOS 앱은 macOS에서만 빌드할 수 있습니다. 서명·공증 도구(codesign, notarytool)가 macOS 전용이기 때문입니다. 그래서 한 러너에서 크로스컴파일하는 대신, 플랫폼마다 그 OS의 러너에서 빌드하는 매트릭스를 씁니다. GitHub Actions는 macos, windows, ubuntu 러너를 모두 제공하므로 이 구조가 자연스럽습니다.

여기서 #2의 선택이 보상을 줍니다. SQLite를 순수 Go 드라이버 modernc.org/sqlite로 골랐기 때문에 각 러너에서 CGO 없이 그냥 빌드됩니다. CGO판을 골랐다면 러너마다 C 툴체인을 맞추느라 워크플로가 훨씬 복잡해졌을 것입니다.

워크플로: 태그에 반응하는 매트릭스 #

v로 시작하는 태그가 푸시되면 세 러너가 병렬로 빌드합니다.

.github/workflows/release.yml — 매트릭스 골격
on:
  push:
    tags: ["v*"]

jobs:
  build:
    strategy:
      matrix:
        include:
          - os: macos-latest
            platform: darwin/universal
          - os: windows-latest
            platform: windows/amd64
          - os: ubuntu-latest
            platform: linux/amd64
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-go@v5
        with: { go-version: "1.23" }
      - name: Wails 빌드
        uses: dAppServer/wails-build-action@main
        with:
          build-platform: ${{ matrix.platform }}

dAppServer/wails-build-action은 Wails CLI 설치, 프론트엔드 의존성 설치, 빌드를 묶어 처리하는 커뮤니티 액션입니다. 직접 wails build를 부르는 단계로 대체해도 되지만, 이 액션이 서명·설치 파일 생성까지 옵션으로 지원해 초기 구성을 줄여 줍니다.

서명을 CI로: Secrets에서 복원 #

#5에서 비밀을 로컬에 두지 않기로 한 것이 여기서 이어집니다. 인증서는 base64로 인코딩해 GitHub Secrets에 넣고, 워크플로에서 복원해 서명에 씁니다.

macOS 러너에서 인증서 복원과 서명·공증
      - name: 인증서 가져오기 (macOS)
        if: matrix.os == 'macos-latest'
        env:
          CERT_P12: ${{ secrets.MACOS_CERT_P12 }}       # base64 인코딩된 .p12
          CERT_PW: ${{ secrets.MACOS_CERT_PASSWORD }}
        run: |
          echo "$CERT_P12" | base64 --decode > cert.p12
          security create-keychain -p "" build.keychain
          security import cert.p12 -k build.keychain -P "$CERT_PW" -T /usr/bin/codesign
          # 이후 codesign → notarytool submit --wait → stapler staple (#5 참조)

Windows 러너도 같은 방식으로 코드 서명 인증서를 복원해 signtool로 서명합니다. 민감한 값은 모두 secrets.*에서만 오고, 로그에 찍히지 않도록 주의합니다.

릴리스로 묶기 #

각 러너가 만든 산출물을 하나의 GitHub Release에 모읍니다. 빌드 산출물을 아티팩트로 올린 뒤, 마지막 잡에서 릴리스를 만들어 붙이거나, 각 잡이 같은 태그의 릴리스에 자산을 추가하는 방식을 씁니다.

빌드 결과를 릴리스에 첨부
      - name: 릴리스에 자산 업로드
        uses: softprops/action-gh-release@v2
        with:
          files: build/bin/*

이제 사이클은 이렇습니다. 코드를 커밋하고 git tag v1.0.0 && git push --tags를 하면, 세 러너가 각자 빌드·서명하고, 완성된 설치 파일이 v1.0.0 릴리스 페이지에 올라갑니다. 사용자는 자기 OS에 맞는 파일을 내려받아 경고 없이 설치합니다.

자동 업데이트: 무엇을 쓸 수 있나 #

앱을 배포한 뒤의 다음 질문은 자동 업데이트입니다. Wails에는 공식 내장 업데이터가 없으므로 전략을 골라야 합니다.

  • 가벼운 방식: 앱이 시작할 때 GitHub Releases의 최신 태그를 조회해, 현재 버전보다 높으면 릴리스 페이지를 열어 사용자가 직접 받게 안내합니다. 구현이 단순하고 서명 흐름과 충돌하지 않습니다.
  • 완전 자동: 새 바이너리를 내려받아 스스로 교체하는 방식입니다. 서명 검증, 권한, 롤백까지 직접 다뤄야 해서 복잡하고, 잘못하면 서명된 앱의 신뢰를 깨뜨릴 수 있습니다.

개인·소규모 배포라면 가벼운 방식(업데이트 있음을 알리고 릴리스로 보내기)이 안전한 기본값입니다. 완전 자동 교체는 사용자 규모가 커져 수동 업데이트 안내가 부담이 될 때 검토합니다.

노트
Wails v3 는 멀티 윈도우·내장 트레이와 함께 도구 체계도 다듬어지고 있습니다. 이 글의 매트릭스 빌드, Secrets 기반 서명, 릴리스 자동화의 개념은 v3 에서도 그대로 유효하며, 달라지는 것은 CLI 명령과 액션의 세부입니다. 정식 릴리스 시 마이그레이션 가이드를 확인하면 됩니다.

1부를 마치며 — 그리고 2부 #

여기까지 1부에서 메모리 기반 뼈대를 실제 배포 가능한 노트 앱으로 키웠습니다. 층을 나누고(#1), 순수 Go SQLite를 붙이고(#2), 검색과 데이터 흐름을 잡고(#3), 백그라운드에 상주시키고(#4), 서명·공증하고(#5), CI로 자동화(#6)해, 아이디어를 세 플랫폼의 서명된 설치 파일로 배포하는 전체 사이클을 손에 넣었습니다.

그런데 배포 가능한 앱과 사용자가 매일 다시 여는 앱은 다릅니다. 지금까지 백엔드에 치우쳐 뒤로 미룬 앞단(에디터·UX), 약속만 한 테스트, 전략만 이야기한 자동 업데이트, 그리고 설정·다크모드·데이터 안전 같은 마감이 남아 있습니다. 2부(#7#10)에서 이 앱을 리피터가 생기는 완성도까지 끌어올립니다.

정리 #

  • macOS 앱은 macOS에서만 빌드·서명되므로, 한 러너 크로스컴파일 대신 플랫폼별 러너 매트릭스를 씁니다. 순수 Go SQLite 덕에 각 러너 빌드가 단순합니다.
  • 워크플로는 v* 태그에 반응해 세 러너에서 병렬 빌드하고, wails-build-action이 빌드·설치 파일 생성을 묶어 줍니다.
  • 서명 비밀은 base64로 GitHub Secrets에 넣고 러너에서 복원해 씁니다. 로컬에 두지 않는 #5의 원칙이 CI에서 완성됩니다.
  • Wails에는 공식 업데이터가 없습니다. 개인·소규모는 “업데이트 있음을 알리고 릴리스로 보내기"가 안전한 기본값이고, 완전 자동 교체는 규모가 커질 때 검토합니다.
  • 태그 하나로 세 플랫폼 서명 릴리스가 자동 생성되는 지점이, 이 시리즈가 목표한 배포 자동화의 완성입니다.
X