C++ 프로젝트용 GitHub Actions: 3개 OS 매트릭스, vcpkg 캐시, Sanitizer, 릴리스 배포

들어가며: “로컬에서는 되는데 CI에서만 빌드 실패해요”

실제 겪는 문제 시나리오

C++ 프로젝트에 CI/CD를 붙입니다 보면 이런 상황을 자주 마주합니다:

"로컬에서는 되는데 CI에서만 빌드가 실패해요."
"vcpkg로 fmt, spdlog 설치하는데 20분 넘게 걸려요."
"푸시할 때마다 전체 빌드가 돌아서 30분씩 기다려요."
"Linux는 되는데 Windows·macOS 빌드는 어떻게 해요?"
"빌드 결과물을 릴리스에 자동으로 올리고 싶습니다."
"캐시가 적용됐는데 왜 매번 vcpkg를 다시 빌드해요?"
"find_package(fmt) failed — CI에서만 못 찾아요."
"매트릭스 빌드에서 Windows job만 실패해요."
"아티팩트 업로드 용량 초과 에러가 나요."
"시크릿·환경 변수 설정이 복잡해요."

GitHub Actions로 해결:

문제GitHub Actions 해결
로컬과 CI 환경 차이동일한 runner 이미지·CMake preset으로 재현
vcpkg 설치 지연Binary Caching(files+actions/cache 또는 NuGet)으로 캐싱
전체 빌드 반복build/·vcpkg installed/ 캐시 키 설계
멀티 플랫폼strategy.matrix로 ubuntu·macos·windows 병렬
릴리스 배포actions/upload-release-asset·create-release
find_package 실패CMAKE_TOOLCHAIN_FILE·vcpkg.json Manifest 모드
Windows 빌드 실패MSVC preset·Ninja Multi-Config
아티팩트 용량압축·필요한 파일만 업로드·split job

요구 환경: GitHub 저장소, CMake 3.19+, vcpkg Manifest 모드 또는 Conan

GitHub Actions 워크플로 구조에서 출발해 Linux·macOS·Windows 매트릭스 빌드, vcpkg와 빌드 캐시로 CI 시간을 줄이는 방법, 아티팩트 업로드와 릴리스 자동 배포까지 다룹니다.


CI에서만 터지는 여덟 가지 상황

로컬과 CI 환경 불일치

상황: 로컬 Ubuntu 22.04, GCC 12, Ninja로 빌드 성공
CI: ubuntu-latest(22.04), 기본 GCC, Makefile → "undefined reference"
원인: Generator·컴파일러·빌드 타입이 다름
해결: CMake Presets의 ci-release preset + 동일 runner 이미지

vcpkg 의존성 설치 지연

상황: vcpkg.json에 fmt, spdlog, boost-asio 등 10개 패키지
문제: 매 CI 실행마다 vcpkg install → 15~25분 소요
해결: vcpkg Binary Caching(files 공급자+actions/cache, 또는 GitHub Packages NuGet)

푸시할 때마다 전체 빌드

상황: 소스 일부만 수정했는데 매번 configure·build·test 전체 실행
문제: 5분이면 될 빌드가 30분 걸림
해결: hashFiles로 CMakeLists.txt·vcpkg.json·소스 변경 시에만 캐시 무효화

멀티 플랫폼 검증 필요

상황: Windows·macOS 사용자도 있어 세 플랫폼 모두 빌드 검증 필요
문제: 로컬에서 Windows 빌드 환경 구축이 어려움
해결: strategy.matrix로 ubuntu-22.04, macos-14, windows-2022 병렬 실행

릴리스 배포 수동 작업

상황: 태그 푸시 시 수동으로 바이너리 빌드·업로드
문제: 실수·누락·시간 소모
해결: release workflow에서 빌드 → 아티팩트 → GitHub Release에 업로드

find_package CI에서만 실패

상황: 로컬 Classic 모드로 vcpkg install한 패키지가 CI에 없음
문제: CI에는 빈 runner라 패키지가 없음
해결: Manifest 모드(vcpkg.json) + CMAKE_TOOLCHAIN_FILE로 CI에서 자동 설치

Windows에서 MSVC 빌드 실패

상황: Linux용 CMake 설정을 Windows에 그대로 적용
문제: Ninja 단일 설정 vs MSVC 멀티 설정 차이
해결: Windows용 preset에서 Ninja Multi-Config, --config Release

캐시 키 설계 실패

상황: actions/cache를 넣었는데 매번 "Cache not found"
문제: key가 너무 구체적이거나 hashFiles 대상이 잘못됨
해결: restore-keys로 fallback, vcpkg.json·CMakeLists.txt 포함
flowchart TB
  subgraph Problems[문제]
    P1[로컬 vs CI 불일치]
    P2[vcpkg 설치 지연]
    P3[전체 빌드 반복]
    P4[멀티 플랫폼]
    P5[수동 배포]
  end
  subgraph Solutions[GitHub Actions 해결]
    S1[CMake Presets + 동일 이미지]
    S2[Binary Caching / actions/cache]
    S3[캐시 키 설계]
    S4[strategy.matrix]
    S5[release workflow]
  end
  P1 --> S1
  P2 --> S2
  P3 --> S3
  P4 --> S4
  P5 --> S5

워크플로 파일 위치와 최소 구성

파일 위치

.github/
  workflows/
    ci.yml          # PR·push 시 빌드·테스트
    release.yml     # 태그 푸시 시 릴리스 배포

최소 워크플로 예제

name: CI
on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main, develop]
jobs:
  build:
    runs-on: ubuntu-22.04
    steps:
      - name: Checkout
        uses: actions/checkout@v4
      - name: Install CMake
        uses: jwlawson/actions-setup-cmake@v2
        with:
          cmake-version: '3.28'
      - name: Configure
        run: cmake --preset ci-release
      - name: Build
        run: cmake --build --preset ci-release
      - name: Test
        run: ctest --preset ci-test

핵심:

  • on: 트리거 조건 (push, pull_request, workflow_dispatch 등)
  • jobs.build: 단일 job, runs-on으로 runner 지정
  • steps: 순차 실행. uses로 액션, run으로 셸 명령

CMake Presets와 연동

CMakePresets.json에 ci-release preset이 있어야 합니다. CMake Presets 가이드 참고.

{
  "name": "ci-release",
  "inherits": "base",
  "cacheVariables": {
    "CMAKE_BUILD_TYPE": "Release"
  }
}

vcpkg 사용 시 toolchainFile로 vcpkg.cmake 지정. CI에서는 vcpkg.json Manifest 모드로 자동 설치됩니다.


완성형 CI 워크플로 세 가지 변형

vcpkg Manifest 모드 + CMake Presets

name: CI
on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main, develop]
env:
  VCPKG_BINARY_SOURCES: 'clear;files,${{ github.workspace }}/.vcpkg-cache,readwrite'
jobs:
  build:
    runs-on: ubuntu-22.04
    steps:
      - name: Checkout
        uses: actions/checkout@v4
      - name: Restore vcpkg binary cache
        uses: actions/cache@v4
        with:
          path: .vcpkg-cache
          key: vcpkg-${{ runner.os }}-${{ hashFiles('vcpkg.json', 'vcpkg-configuration.json') }}
          restore-keys: vcpkg-${{ runner.os }}-
      - name: Setup vcpkg
        uses: lukka/run-vcpkg@v11
        with:
          vcpkgDirectory: '${{ github.workspace }}/vcpkg'
          runVcpkgInstall: false
      - name: Configure
        run: cmake --preset ci-release
      - name: Build
        run: cmake --build --preset ci-release
      - name: Test
        run: ctest --preset ci-test --output-on-failure

설명:

  • VCPKG_BINARY_SOURCES: 'clear;files,...,readwrite': vcpkg가 빌드한 패키지를 .vcpkg-cache에 저장하고, actions/cache가 그 디렉터리를 실행 사이에 보존합니다. 예전에 쓰던 x-gha 공급자는 GitHub 캐시 API 변경으로 2025년에 vcpkg에서 제거되었으므로 쓰지 않습니다.
  • runVcpkgInstall: false: vcpkg install을 이 단계에서 하지 않음. CMake configure 시 vcpkg.cmake toolchain이 vcpkg.json을 읽고 자동 설치.
  • vcpkg를 submodule로 두면 vcpkgDirectory에 맞게 지정.

vcpkg 서브모듈 없이 사용

- name: Setup vcpkg
  uses: lukka/run-vcpkg@v11
  with:
    vcpkgGitCommitId: '2024.01.15'
    runVcpkgInstall: false

vcpkgGitCommitId로 고정 커밋을 사용하면 재현 가능한 빌드가 됩니다.

수동 캐시 (run-vcpkg 미사용 시)

- name: Cache vcpkg
  uses: actions/cache@v4
  with:
    path: |
      ${{ github.workspace }}/vcpkg/installed
      ${{ github.workspace }}/vcpkg/buildtrees
    key: ${{ runner.os }}-vcpkg-${{ hashFiles('vcpkg.json', 'vcpkg.lock') }}
    restore-keys: |
      ${{ runner.os }}-vcpkg-
- name: Install vcpkg dependencies
  run: |
    ./vcpkg/bootstrap-vcpkg.sh
    ./vcpkg install --triplet ${{ env.VCPKG_DEFAULT_TRIPLET }}

주의: installed/ 디렉터리를 통째로 캐시하는 것보다 vcpkg 바이너리 캐시(위의 files 공급자 방식)를 쓰는 편이 안정적입니다. installed/는 vcpkg 버전·트리플렛이 바뀌면 조용히 어긋날 수 있습니다.


OS·컴파일러 매트릭스 빌드

Linux·macOS·Windows

jobs:
  build:
    strategy:
      fail-fast: false
      matrix:
        include:
          - os: ubuntu-22.04
            preset: linux-release
          - os: macos-14
            preset: macos-release
          - os: windows-2022
            preset: msvc-release
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/checkout@v4
      - name: Setup vcpkg
        uses: lukka/run-vcpkg@v11
        with:
          vcpkgDirectory: '${{ github.workspace }}/vcpkg'
          runVcpkgInstall: false
      - name: Configure
        run: cmake --preset ${{ matrix.preset }}
      - name: Build
        run: cmake --build --preset ${{ matrix.preset }}
      - name: Test
        run: ctest --preset ci-test --output-on-failure

설명:

  • fail-fast: false: 한 job 실패 시 다른 job은 계속 실행.
  • matrix.include: os·preset 조합을 명시.
  • CMakePresets.json에 linux-release, macos-release, msvc-release preset 필요.

컴파일러 매트릭스 (Linux)

strategy:
  matrix:
    compiler: [gcc, clang]
    build_type: [Debug, Release]
runs-on: ubuntu-22.04
steps:
  - uses: actions/checkout@v4
  - name: Install ${{ matrix.compiler }}
    run: |
      if [ "${{ matrix.compiler }}" = "gcc" ]; then
        sudo apt-get update && sudo apt-get install -y g++-12
        echo "CXX=g++-12" >> $GITHUB_ENV
      else
        sudo apt-get update && sudo apt-get install -y clang-15
        echo "CXX=clang++-15" >> $GITHUB_ENV
      fi
  - name: Configure
    run: |
      cmake --preset ci-release \
        -DCMAKE_CXX_COMPILER=${{ matrix.compiler == 'gcc' && 'g++-12' || 'clang++-15' }}
  - name: Build
    run: cmake --build --preset ci-release

exclude로 조합 제외

strategy:
  matrix:
    os: [ubuntu-22.04, macos-14, windows-2022]
    config: [Debug, Release]
    exclude:
      - os: windows-2022
        config: Debug

Windows Debug는 제외하고 싶을 때 사용.

Windows에서 MSVC 설정

- name: Configure (Windows)
  if: runner.os == 'Windows'
  run: cmake --preset msvc-release
- name: Build (Windows)
  if: runner.os == 'Windows'
  run: cmake --build --preset msvc-release --config Release

MSVC preset은 Ninja Multi-Config 또는 Visual Studio 17 2022 generator 사용. 빌드 시 --config Release 필요.


vcpkg·빌드 디렉터리·Conan 캐싱

vcpkg Binary Caching

한때 표준처럼 쓰이던 VCPKG_BINARY_SOURCES: 'clear;x-gha,readwrite'(GitHub Actions 캐시 직접 사용)는 GitHub가 캐시 서비스의 내부 API를 바꾸면서 동작하지 않게 되었고, vcpkg는 2025년에 이 공급자를 제거했습니다. 인터넷 예제와 오래된 워크플로에 아직 많이 남아 있어서, 어느 날부터 CI가 모든 의존성을 매번 다시 빌드하며 수십 분씩 늘어났다면 이게 원인일 가능성이 큽니다.

대안은 두 가지입니다.

# 1) files 공급자 + actions/cache (가장 간단)
env:
  VCPKG_BINARY_SOURCES: 'clear;files,${{ github.workspace }}/.vcpkg-cache,readwrite'
# steps에서 actions/cache로 .vcpkg-cache 경로를 보존 (3.1절 예제 참고)

# 2) GitHub Packages NuGet 피드 (vcpkg 팀 권장, 여러 저장소가 캐시 공유)
env:
  VCPKG_BINARY_SOURCES: 'clear;nuget,https://nuget.pkg.github.com/<OWNER>/index.json,readwrite'
# packages: write 권한의 GITHUB_TOKEN으로 NuGet 소스 등록 단계가 필요, Linux/macOS는 mono 필요

1번은 설정이 쉽지만 GitHub Actions 캐시의 저장소당 용량 한도에 걸리기 쉽고, 매트릭스 조합이 많으면 캐시가 자주 밀려납니다. 2번은 초기 설정이 번거롭지만 용량 한도와 저장소 간 공유 면에서 유리합니다.

actions/cache로 빌드 디렉터리

- name: Cache build
  uses: actions/cache@v4
  with:
    path: |
      build
      out
    key: ${{ runner.os }}-cmake-${{ hashFiles('CMakeLists.txt', 'CMakePresets.json', '**/CMakeLists.txt', 'vcpkg.json') }}
    restore-keys: |
      ${{ runner.os }}-cmake-

주의: configure 결과가 캐시되면 CMake 변수 변경이 반영되지 않을 수 있습니다. 소스·설정 변경 시 캐시가 무효화되도록 hashFiles에 필요한 파일을 넣습니다.

vcpkg installed 캐시 (수동)

- name: Cache vcpkg
  uses: actions/cache@v4
  with:
    path: ${{ github.workspace }}/vcpkg/installed
    key: ${{ runner.os }}-vcpkg-${{ hashFiles('vcpkg.json', 'vcpkg.lock') }}
    restore-keys: |
      ${{ runner.os }}-vcpkg-

Conan 캐시

- name: Cache Conan
  uses: actions/cache@v4
  with:
    path: ~/.conan2
    key: ${{ runner.os }}-conan-${{ hashFiles('conanfile.txt', 'conanfile.py') }}
    restore-keys: |
      ${{ runner.os }}-conan-

캐시 키 설계 원칙

대상key에 포함할 것restore-keys
vcpkgvcpkg.json, vcpkg.lockos-vcpkg- (fallback)
CMake buildCMakeLists.txt, preset, 소스os-cmake-
Conanconanfile.txt, conanfile.pyos-conan-

restore-keys에 prefix만 두면 부분 일치로 이전 캐시를 사용합니다. 완전 일치가 없을 때 유용합니다.


아티팩트 업로드·다운로드

빌드 결과물 업로드

- name: Upload artifacts
  uses: actions/upload-artifact@v4
  with:
    name: build-${{ matrix.os }}-${{ matrix.preset }}
    path: |
      build/*/myapp
      build/*/myapp.exe
    if-no-files-found: warn

path에 와일드카드 사용 가능. preset별로 build/ci-release/ 등 경로가 다를 수 있으니 build/*/로 유연하게 지정.

여러 아티팩트를 하나로 합치기

jobs:
  build:
    # ... 빌드 단계 ...
    - uses: actions/upload-artifact@v4
      with:
        name: build-${{ matrix.os }}
        path: build/
  merge:
    needs: build
    runs-on: ubuntu-22.04
    steps:
      - name: Download all
        uses: actions/download-artifact@v4
        with:
          pattern: build-*
          path: artifacts
          merge-multiple: true
      - name: List
        run: ls -la artifacts/

아티팩트 압축으로 용량 절감

- name: Create archive
  run: |
    cd build
    tar czvf ../release-linux.tar.gz myapp
    cd ..
- name: Upload
  uses: actions/upload-artifact@v4
  with:
    name: release-linux
    path: release-linux.tar.gz

아티팩트 보존 기간

- uses: actions/upload-artifact@v4
  with:
    name: build
    path: build/
    retention-days: 7

기본 90일. 저장소 용량 관리 시 조정.

용량 제한

  • 저장소당 아티팩트 총 용량 제한 있음 (GitHub 플랜별 상이).
  • 개별 아티팩트는 압축 후 업로드.
  • 필요한 바이너리만 업로드 (path를 좁게 지정).

태그 푸시로 Release·Docker 이미지 배포

GitHub Release에 자동 업로드

name: Release
on:
  push:
    tags:
      - 'v*'
jobs:
  build:
    strategy:
      matrix:
        include:
          - os: ubuntu-22.04
            preset: linux-release
            artifact: myapp
          - os: macos-14
            preset: macos-release
            artifact: myapp
          - os: windows-2022
            preset: msvc-release
            artifact: myapp.exe
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/checkout@v4
      - name: Setup vcpkg
        uses: lukka/run-vcpkg@v11
        with:
          vcpkgDirectory: '${{ github.workspace }}/vcpkg'
          runVcpkgInstall: false
      - name: Configure
        run: cmake --preset ${{ matrix.preset }}
      - name: Build
        run: cmake --build --preset ${{ matrix.preset }}
      - name: Upload artifact
        uses: actions/upload-artifact@v4
        with:
          name: ${{ matrix.os }}-${{ matrix.artifact }}
  release:
    needs: build
    runs-on: ubuntu-22.04
    permissions:
      contents: write
    steps:
      - name: Download all artifacts
        uses: actions/download-artifact@v4
        with:
          path: artifacts
      - name: Create Release
        uses: softprops/action-gh-release@v2
        with:
          files: |
            artifacts/ubuntu-22.04-myapp
            artifacts/macos-14-myapp
            artifacts/windows-2022-myapp.exe
          generate_release_notes: true
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

설명:

  • on.push.tags: 'v*': v1.0.0 같은 태그 푸시 시 실행.
  • permissions.contents: write: 릴리스 생성·업로드에 필요.
  • GITHUB_TOKEN: 자동 제공, 별도 시크릿 불필요.

Docker 이미지 빌드·푸시

- name: Set up Docker Buildx
  uses: docker/setup-buildx-action@v3
- name: Login to Container Registry
  uses: docker/login-action@v3
  with:
    registry: ghcr.io
    username: ${{ github.actor }}
    password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
  uses: docker/build-push-action@v6
  with:
    context: .
    file: ./Dockerfile
    push: true
    tags: ghcr.io/${{ github.repository }}:latest

Dockerfile 예시 (멀티 스테이지)

FROM ubuntu:22.04 AS builder
RUN apt-get update && apt-get install -y cmake ninja-build g++
COPY . /src
WORKDIR /src
RUN cmake --preset ci-release && cmake --build --preset ci-release
FROM ubuntu:22.04
COPY --from=builder /src/build/ci-release/myapp /usr/local/bin/
CMD [myapp]

조건부 배포 (main 브랜치만)

release:
  if: github.ref == 'refs/heads/main' && github.event_name == 'push'
  needs: build
  # ...

Presets·vcpkg·권한·러너 환경에서 나는 에러

”Could not find preset “ci-release""

원인: CMakePresets.json에 ci-release가 없거나, condition으로 현재 환경에서 비활성화됩니다. 해결법:

# 로컬에서 preset 목록 확인
cmake --list-presets

CMakePresets.json에 ci-release를 추가하며, condition이 CI 환경($env{CI} 등)에서 true인지 확인하세요.

”find_package(fmt) failed”

원인: CI에 vcpkg 패키지가 설치되지 않음. Classic 모드만 로컬에서 사용했거나, CMAKE_TOOLCHAIN_FILE 미지정. 해결법:

# vcpkg Manifest 모드 + toolchain 지정
# CMakePresets.json의 ci-release에:
# "toolchainFile": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake"

그리고 run-vcpkg 또는 vcpkg install 단계가 configure 전에 실행되는지 확인하세요.

”Cache not found” — 캐시가 매번 miss

원인: key가 너무 구체적이거나, hashFiles 대상 파일이 없음. 해결법:

# hashFiles에 존재하는 파일만
key: ${{ runner.os }}-vcpkg-${{ hashFiles('vcpkg.json') }}
# vcpkg.lock이 없으면 hashFiles가 실패할 수 있음
key: ${{ runner.os }}-vcpkg-${{ hashFiles('vcpkg.json', 'vcpkg.lock') }}

vcpkg.lock이 없으면 vcpkg.json만 넣거나, hashFiles('**/vcpkg.json')로 경로를 유연하게.

”Resource not accessible by integration”

원인: GITHUB_TOKEN 권한 부족. Release 생성·푸시에 contents: write 필요. 해결법:

permissions:
  contents: write

워크플로 또는 job 레벨에 추가.

Windows에서 “cmake: command not found”

원인: Windows runner에 CMake가 기본 설치되어 있지만, 경로가 다를 수 있음. 또는 actions-setup-cmake 미사용. 해결법:

- name: Install CMake
  uses: jwlawson/actions-setup-cmake@v2
  with:
    cmake-version: '3.28'

“VCPKG_ROOT not set”

원인: vcpkg 경로를 모르는 상태에서 toolchain 또는 vcpkg install 실행. 해결법:

- name: Setup vcpkg
  uses: lukka/run-vcpkg@v11
  # run-vcpkg가 VCPKG_ROOT 설정
- name: Configure
  run: cmake --preset ci-release
  env:
    VCPKG_ROOT: ${{ github.workspace }}/vcpkg

run-vcpkg 사용 시 보통 자동 설정됩니다.

”Artifact upload failed: Resource not found”

원인: path에 지정한 파일·디렉터리가 없음. 해결법:

- uses: actions/upload-artifact@v4
  with:
    name: build
    path: build/
    if-no-files-found: warn

if-no-files-found: warn으로 실패 대신 경고만. 또는 path를 실제 빌드 출력 경로에 맞게 수정 (preset별로 build/ci-release/ 등).

”The process ‘/usr/bin/bash’ failed with exit code 1”

원인: run 단계에서 명령이 실패. CMake configure/build 에러, 테스트 실패 등. 해결법: 해당 step의 로그를 확인. --output-on-failure로 ctest 출력을 늘리기:

- name: Test
  run: ctest --preset ci-test --output-on-failure

macOS에서 “xcode-select” 관련 에러

원인: Xcode 명령줄 도구 미설정. 해결법:

- name: Select Xcode
  run: sudo xcode-select -s /Applications/Xcode_15.2.app/Contents/Developer
  if: runner.os == 'macOS'

또는 macos-14 등 최신 runner는 기본 설정된 경우가 많습니다.

”No space left on device”

원인: runner 디스크 부족. vcpkg·빌드 산출물이 큼. 해결법:

  • 불필요한 캐시 정리.
  • path를 좁혀서 캐시에 넣는 데이터 축소.
  • Docker 등에서 멀티 스테이지로 최종 이미지 크기 축소.

매트릭스에서 Windows만 실패

원인: Windows는 MSVC·Ninja Multi-Config 등 설정이 다름. --config Release 누락. 해결법:

- name: Build (Windows)
  run: cmake --build --preset msvc-release --config Release

“conan: command not found”

원인: Conan 미설치. 해결법:

- name: Install Conan
  run: pip install conan
  # 또는
- uses: conan-io/setup-conan@v2
  with:
    conan-version: '2.x'

액션 버전 고정·timeout·concurrency 설정

액션 버전 고정

# ❌ 나쁜 예
uses: actions/checkout@main
# ✅ 좋은 예
uses: actions/checkout@v4

@main은 변경될 수 있어 재현성이 떨어집니다. @v4처럼 major 버전을 고정하세요.

fail-fast 설정

strategy:
  fail-fast: false

매트릭스에서 한 job 실패 시 나머지도 중단하지 않으려면 false로 설정.

timeout 설정

jobs:
  build:
    timeout-minutes: 30

무한 대기 방지.

concurrency로 중복 실행 제한

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

같은 브랜치에 연속 푸시 시 이전 실행을 취소.

환경 변수는 env로

env:
  VCPKG_BINARY_SOURCES: 'clear;files,${{ github.workspace }}/.vcpkg-cache,readwrite'
  CXX: g++-12

job 또는 step 레벨에서 env로 지정하면 가독성이 좋습니다.

시크릿 노출 방지

# ❌ 나쁜 예
run: echo "Key is ${{ secrets.API_KEY }}"
# ✅ 좋은 예
run: ./deploy.sh
env:
  API_KEY: ${{ secrets.API_KEY }}

secrets를 로그에 출력하지 않도록 합니다. GitHub는 자동 마스킹을 하지만, 스크립트에서 echo하지 않는 것이 안전합니다.

필요 시에만 checkout

- uses: actions/checkout@v4
  with:
    fetch-depth: 0

fetch-depth: 0은 전체 히스토리. Git describe·캐시 키에 커밋이 필요할 때 사용. 기본 1이면 shallow clone으로 빠름.

빌드 산출물 경로 통일

CMake Presets에서 binaryDir를 ${sourceDir}/build/${presetName}로 통일하면, 아티팩트 path를 build/*/myapp처럼 단순하게 지정할 수 있습니다.


PR/Push 분리와 재사용 워크플로

PR과 Push 분리

on:
  pull_request:
    branches: [main]
  push:
    branches: [main]
jobs:
  build:
    steps: [...]
  # PR에서는 빌드·테스트만
  # push에서는 추가로 아티팩트 업로드 등

빌드·테스트·배포 단계 분리

jobs:
  build:
    outputs:
      build_id: ${{ steps.meta.outputs.id }}
  test:
    needs: build
  deploy:
    needs: [build, test]
    if: github.ref == 'refs/heads/main'

재사용 가능한 워크플로

workflow_call로 입력을 받는 워크플로를 정의하며, 다른 워크플로에서 uses: ./.github/workflows/build.yml로 호출할 수 있습니다.

# .github/workflows/build.yml
name: Build
on:
  workflow_call:
    inputs:
      preset:
        required: true
        type: string
jobs:
  build:
    runs-on: ubuntu-22.04
    steps:
      - uses: actions/checkout@v4
      - run: cmake --preset ${{ inputs.preset }}
      - run: cmake --build --preset ${{ inputs.preset }}

Self-hosted runner

runs-on: [self-hosted, linux, x64]

사내 하드웨어·특수 환경이 필요할 때 사용. GitHub 호스트 runner보다 설정이 필요합니다.

의존성 업데이트 자동화 (Dependabot)

# .github/dependabot.yml
version: 2
updates:
  - package-ecosystem: "github-actions"
    directory: "/"
    schedule:
      interval: "weekly"

액션 버전 업데이트 PR을 자동 생성.

워크플로 상태 배지

README에 ![CI Status](https://github.com/OWNER/REPO/actions/workflows/ci.yml/badge.svg) 추가.

Slack·이메일 알림 (선택)

- name: Notify on failure
  if: failure()
  uses: slackapi/slack-github-action@v1
  with:
    payload: |
      {
        "text": "Build failed: ${{ github.repository }}"
      }
  env:
    SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}

CI 워크플로 점검 목록

기본 설정:

  • .github/workflows/ci.yml 생성

  • on.push, on.pull_request 트리거 설정

  • actions/checkout@v4 사용

  • CMake·Ninja 설치 (jwlawson/actions-setup-cmake, lukka/get-cmake 등)

  • 액션 버전 고정 (@v4, @v11 등) CMake Presets:

  • CMakePresets.json에 ci-release preset 정의

  • vcpkg 사용 시 toolchainFile 지정

  • cmake --preset, cmake --build --preset, ctest --preset 사용 캐싱:

  • vcpkg: VCPKG_BINARY_SOURCES를 files(+actions/cache) 또는 nuget으로 설정 (x-gha는 제거됨)

  • build: actions/cache로 build/ 캐시 (선택)

  • 캐시 키에 hashFiles('vcpkg.json', 'CMakeLists.txt', ...) 포함 매트릭스:

  • strategy.matrix로 os·preset 조합

  • fail-fast: false (선택)

  • Windows 시 --config Release 지정 아티팩트·배포:

  • actions/upload-artifact로 빌드 결과 업로드

  • Release workflow: on.push.tags, softprops/action-gh-release

  • permissions.contents: write (릴리스 시) 에러 대응:

  • ctest --output-on-failure

  • if-no-files-found: warn (아티팩트)

  • timeout-minutes 설정


설정 항목별 요약

항목설명
트리거on.push, on.pull_request, on.push.tags
매트릭스strategy.matrix로 os·compiler·config 조합
vcpkg 캐싱VCPKG_BINARY_SOURCES: files+actions/cache 또는 nuget
빌드 캐시actions/cache + hashFiles
아티팩트upload-artifact, download-artifact
릴리스softprops/action-gh-release, contents: write
CMake Presetsci-release 등 CI 전용 preset

핵심: CMake Presets로 로컬·CI 설정 통일 → vcpkg Binary Caching으로 의존성 설치 가속 → 매트릭스로 멀티 플랫폼 검증 → 아티팩트·릴리스로 배포 자동화


자주 묻는 질문 (FAQ)

  • run-vcpkg vs 수동 vcpkg? run-vcpkg는 vcpkg 설치·경로 설정을 대신해 줘서 편합니다. 바이너리 캐시는 어느 쪽이든 VCPKG_BINARY_SOURCES를 files나 nuget으로 직접 지정하세요(x-gha는 2025년에 제거됨).
  • 캐시가 적용됐는데 왜 느려요? 캐시 키가 매번 바뀌면 miss. hashFiles에 불필요한 파일이 들어가면 소스 수정 시마다 캐시 무효화.
  • Windows에서 Ninja vs MSVC? Ninja Multi-Config + MSVC 조합이 일반적. --config Release 필수.
  • 아티팩트 용량 초과? 압축(tar.gz, zip), 필요한 파일만 업로드, retention-days 줄이기.
  • Self-hosted runner? GitHub 호스트 대신 자체 서버 사용. 설정·보안 관리 필요.

참고 자료


같이 보면 좋은 글