name: Linux deb Release # 릴리스는 태그에서만. develop/main push 로는 트리거되지 않는다. # - v* 태그 push → 릴리스 생성 + 자산 첨부 # - workflow_dispatch(tag 입력) → 해당 태그로 릴리스 # - workflow_dispatch(tag 미입력) → 빌드/검증 리허설만 (아티팩트만, GitHub Release 생성 안 함) # # 배포판 매트릭스: 같은 소스를 배포판별 컨테이너에서 다시 빌드한다. # glibc 는 하위호환만 보장하고 Qt IM 플러그인은 GuiPrivate ABI 에 묶여 있어 # 한 빌드로 여러 배포판을 덮을 수 없다 (docs/dev/linux/os-compatibility.md). # 빌드·게이트 로직은 scripts/ci/ 에 있다 — 로컬 매트릭스 # (scripts/build-linux-matrix.sh)와 같은 스크립트를 쓰므로 여기 YAML 은 # 얇은 호출자다. 로직 수정은 스크립트에서 할 것. on: push: tags: ['v*'] workflow_dispatch: inputs: tag: description: '릴리스할 태그 (예: v0.4.0). 비우면 현재 ref 를 빌드+검증만 하고 릴리스는 만들지 않습니다.' required: false type: string # 같은 ref 의 중복 실행은 취소하지 않는다 (릴리스 파이프라인은 끝까지 완주). concurrency: group: linux-deb-${{ github.ref }} cancel-in-progress: false env: CARGO_TERM_COLOR: always # RUSTFLAGS: -Dwarnings 는 의도적으로 넣지 않는다. # 릴리스 워크플로는 이미 태그된 코드를 '그대로' 빌드해야 한다. Linux GUI # 크레이트(GTK/Qt/Slint)는 windows-msi CI 의 -Dwarnings 게이트를 거치지 # 않으므로, 경고 하나로 릴리스가 막히는 사고를 방지하기 위해 여기서는 # 경고를 오류로 승격하지 않는다. jobs: build-deb: name: Build .deb (${{ matrix.tag }}) runs-on: ubuntu-24.04 # 24.04 레그도 러너 네이티브가 아니라 컨테이너다 — rpm 워크플로·로컬 # 매트릭스와 1:1 로 같은 환경이 되고, sudo 유무 분기가 사라진다. container: ${{ matrix.image }} timeout-minutes: 60 strategy: # 한 배포판의 실패가 다른 배포판 빌드를 중단시키지 않는다. # 단 publish-deb 는 전 레그 성공을 요구한다 — 부분 릴리스 금지. fail-fast: false matrix: include: - { image: 'ubuntu:24.04', tag: ubuntu24.04 } - { image: 'ubuntu:26.04', tag: ubuntu26.04 } - { image: 'debian:13', tag: debian13 } steps: # checkout 액션이 git 를 쓰므로 최소 부트스트랩이 먼저다. # 나머지 의존성은 저장소의 scripts/ci/bootstrap-deb.sh 가 맡는다 # (체크아웃 전에는 그 스크립트가 없다 — 닭과 달걀). - name: Minimal bootstrap (git for checkout) shell: bash run: | set -euo pipefail export DEBIAN_FRONTEND=noninteractive apt-get update -qq apt-get install -y -qq --no-install-recommends git ca-certificates >/dev/null - name: Checkout uses: actions/checkout@v4 with: ref: ${{ github.event.inputs.tag || github.ref }} # 릴리스 본문의 compare 링크가 '바로 앞 태그'를 알아야 해서 전체 이력을 받는다. fetch-depth: 0 - name: Verify version sync (Cargo.toml / debian/changelog / tag) id: guard shell: bash # dispatch 입력값은 셸 보간 대신 env 간접 전달 (GitHub 보안 하드닝 가이드). env: INPUT_TAG: ${{ github.event.inputs.tag }} run: | set -euo pipefail # 컨테이너 uid 불일치로 git 이 워크스페이스를 거부하지 않도록. git config --global --add safe.directory "$GITHUB_WORKSPACE" CARGO_VER=$(grep -E '^version *= *"' Cargo.toml | head -1 | sed -E 's/.*"([0-9.]+)".*/\1/') DEB_FULL=$(head -1 debian/changelog | sed -E 's/^unim \(([^)]+)\).*/\1/') DEB_VER=${DEB_FULL%-*} if [[ "$CARGO_VER" != "$DEB_VER" ]]; then echo "::error::Cargo.toml($CARGO_VER) 와 debian/changelog($DEB_VER) 버전 불일치. 두 파일을 함께 범프하세요." exit 1 fi # 릴리스 태그 결정: push=태그, dispatch=입력값, 그 외=없음(리허설). if [[ "${{ github.event_name }}" == "push" ]]; then TAG="${{ github.ref_name }}" else TAG="$INPUT_TAG" fi if [[ -n "$TAG" ]]; then if [[ ! "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then echo "::error::태그 형식이 올바르지 않습니다: '$TAG' (예: v0.4.0)" exit 1 fi if [[ "${TAG#v}" != "$CARGO_VER" ]]; then echo "::error::태그($TAG) 와 Cargo.toml 버전($CARGO_VER) 불일치. 같은 버전 재릴리스는 debian/changelog 리비전만 올리지 말고 버전을 범프하세요." exit 1 fi fi echo "version=$CARGO_VER" >> "$GITHUB_OUTPUT" echo "release_tag=$TAG" >> "$GITHUB_OUTPUT" - name: Bootstrap build dependencies (scripts/ci/bootstrap-deb.sh) shell: bash run: | set -euo pipefail scripts/ci/bootstrap-deb.sh # rustup 이 설치됐다면 이후 스텝(rust-cache 의 키 계산)에서 보이게 한다. echo "$HOME/.cargo/bin" >> "$GITHUB_PATH" - name: Cargo cache uses: Swatinem/rust-cache@v2 with: # skia 프리빌트 아카이브 등이 배포판별 glibc/clang 에 묶이므로 레그별 분리. shared-key: linux-deb-${{ matrix.tag }} cache-targets: true cache-on-failure: true - name: Build + verify + smoke (scripts/ci/build-deb.sh) shell: bash env: RELEASE_TAG: ${{ steps.guard.outputs.release_tag }} run: scripts/ci/build-deb.sh ${{ matrix.tag }} --smoke - name: Upload functional-test logs (실패 진단용, always) if: always() uses: actions/upload-artifact@v4 with: name: functional-test-${{ matrix.tag }} path: functional-logs/functional-${{ matrix.tag }}/ if-no-files-found: ignore retention-days: 14 - name: Upload build artifacts # 릴리스 여부와 무관하게 항상 업로드 (dispatch 리허설 검증용). uses: actions/upload-artifact@v4 with: name: unim-deb-${{ steps.guard.outputs.version }}-${{ matrix.tag }} path: | debs/*.deb debs/SHA256SUMS-${{ matrix.tag }} if-no-files-found: error retention-days: 30 # 릴리스 생성은 이 잡 하나만 한다. 매트릭스 레그가 각자 릴리스를 upsert 하면 # softprops 동시 쓰기 경합으로 본문·자산이 유실될 수 있어, 레그는 아티팩트만 # 올리고 여기서 팬인한다. 전 레그 성공(needs)이 조건 — 부분 릴리스 금지. publish-deb: name: Publish release (fan-in) runs-on: ubuntu-24.04 needs: build-deb if: startsWith(github.ref, 'refs/tags/v') || github.event.inputs.tag != '' timeout-minutes: 15 permissions: contents: write # softprops/action-gh-release 가 릴리스 생성에 필요 steps: - name: Checkout uses: actions/checkout@v4 with: ref: ${{ github.event.inputs.tag || github.ref }} fetch-depth: 0 # release-body.sh 의 compare 링크용 전체 이력 - name: Read version id: ver shell: bash run: | set -euo pipefail CARGO_VER=$(grep -E '^version *= *"' Cargo.toml | head -1 | sed -E 's/.*"([0-9.]+)".*/\1/') echo "version=$CARGO_VER" >> "$GITHUB_OUTPUT" - name: Download all distro artifacts uses: actions/download-artifact@v4 with: pattern: unim-deb-${{ steps.ver.outputs.version }}-* path: debs merge-multiple: true # 파일명이 ~ 접미사로 갈려 충돌 없음 - name: Verify fan-in completeness + legacy manifest alias shell: bash run: | set -euo pipefail ls -la debs/ # 레그당 11개 × 3 레그 = 33. 매트릭스 구성 변경 시 이 수와 # scripts/build-linux-matrix.sh 의 표를 함께 갱신할 것. count=$(ls debs/*.deb | wc -l) if [[ "$count" -ne 33 ]]; then echo "::error::팬인된 .deb 가 33개가 아닙니다 (실제 $count) — 누락 레그 의심" exit 1 fi for t in ubuntu24.04 ubuntu26.04 debian13; do [[ -f "debs/SHA256SUMS-$t" ]] || { echo "::error::SHA256SUMS-$t 누락"; exit 1; } done # 구버전 install.sh(UNIM_VERSION 핀)와 외부 스크립트 보호용 별칭. # 새 install.sh 가 충분히 보급된 뒤(2~3 릴리스) 제거를 검토한다. cp debs/SHA256SUMS-ubuntu24.04 debs/SHA256SUMS - name: Build release body from CHANGELOG shell: bash env: RELEASE_TAG: ${{ github.event.inputs.tag || github.ref_name }} run: scripts/release-body.sh "$RELEASE_TAG" > /tmp/release-body.md - name: Create GitHub Release uses: softprops/action-gh-release@v2 with: tag_name: ${{ github.event.inputs.tag || github.ref_name }} name: UNIM ${{ steps.ver.outputs.version }} # 33개 .deb + 배포판별 매니페스트 3종 + 레거시 별칭 1종. # ddeb/buildinfo/changes 는 첨부하지 않음. files: | debs/*.deb debs/SHA256SUMS-ubuntu24.04 debs/SHA256SUMS-ubuntu26.04 debs/SHA256SUMS-debian13 debs/SHA256SUMS body_path: /tmp/release-body.md draft: false make_latest: true - name: Verify release asset names match manifests # 릴리스 생성 직후 대조 — 빌드·업로드가 그린이어도 "올라간 이름"이 # 매니페스트와 다르면 install.sh 가 404 를 맞는다 (v0.4.2 실측). shell: bash env: GH_TOKEN: ${{ github.token }} RELEASE_TAG: ${{ github.event.inputs.tag || github.ref_name }} run: | scripts/ci/verify-release-assets.sh "$RELEASE_TAG" \ debs/SHA256SUMS-ubuntu24.04 \ debs/SHA256SUMS-ubuntu26.04 \ debs/SHA256SUMS-debian13 \ debs/SHA256SUMS