name: quality-gates on: pull_request: schedule: - cron: "17 3 * * *" release: types: [published] workflow_dispatch: inputs: tier: description: Quality tier to execute required: true default: nightly type: choice options: - nightly - release permissions: contents: read concurrency: group: quality-gates-${{ github.event_name }}-${{ github.ref }} cancel-in-progress: ${{ github.event_name == 'pull_request' }} jobs: quality: runs-on: ubuntu-latest timeout-minutes: 120 steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 with: fetch-depth: 0 persist-credentials: false - name: Select quality tier id: tier env: EVENT_NAME: ${{ github.event_name }} REQUESTED_TIER: ${{ inputs.tier }} run: | case "$EVENT_NAME" in pull_request) tier="pr" ;; schedule) tier="nightly" ;; release) tier="release" ;; workflow_dispatch) tier="$REQUESTED_TIER" ;; *) echo "unsupported event: $EVENT_NAME" >&2; exit 2 ;; esac echo "tier=$tier" >> "$GITHUB_OUTPUT" echo "Selected quality tier: $tier" - name: Install system dependencies run: | sudo apt-get update sudo apt-get install -y \ clang-19 llvm-19-dev libclang-19-dev libclang-cpp19-dev \ libz3-dev libsqlite3-dev \ meson ninja-build pkg-config \ nlohmann-json3-dev libcli11-dev libspdlog-dev libfmt-dev { echo "CC=clang-19" echo "CXX=clang++-19" echo "LLVM_CONFIG=llvm-config-19" } >> "$GITHUB_ENV" - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5 with: python-version: "3.12" - name: Install build toolchains run: | python -m pip install --upgrade pip python -m pip install 'conan>=2,<3' conan profile detect --force rustup toolchain install nightly-2026-05-28 \ --component rustc-dev --component rustfmt --component llvm-tools-preview rustup toolchain install nightly-2026-07-28 rustup run nightly-2026-05-28 rustc -Vv rustup run nightly-2026-07-28 rustc -Vv - name: Configure and compile run: ./setup.sh release - name: Run tiered quality gate env: TIER: ${{ steps.tier.outputs.tier }} BASE_REF: origin/${{ github.base_ref }} HEAD_REF: ${{ github.sha }} run: | case "$TIER" in pr) ./build/release/src/cli/fold quality \ --skip-format \ --compile-db build/release \ --base-ref "$BASE_REF" \ --head-ref "$HEAD_REF" \ --test-repetitions 1 \ --out-dir quality-report ;; nightly) ./build/release/src/cli/fold quality \ --skip-diff-scan --full-tests \ --test-repetitions 3 \ --out-dir quality-report ;; release) ./build/release/src/cli/fold quality \ --skip-diff-scan --full-tests \ --test-repetitions 1 \ --out-dir quality-report ;; *) echo "unsupported tier: $TIER" >&2; exit 2 ;; esac - name: Install uv for release coverage if: steps.tier.outputs.tier == 'release' run: python -m pip install uv - name: Enforce reviewed release coverage floor if: steps.tier.outputs.tier == 'release' env: COVERAGE_MIN_LINE: "70" run: ./scripts/coverage.sh - name: Smoke release binary if: steps.tier.outputs.tier == 'release' run: | ./build/release/src/cli/fold --version set +e ./build/release/src/cli/fold scan \ tests/fixtures/clones \ --std c++20 --detectors clone --processes 1 \ --format sarif --output quality-report/release-smoke.sarif.json scan_status=$? set -e if (( scan_status > 1 )); then exit "$scan_status" fi test -s quality-report/release-smoke.sarif.json - name: Upload quality evidence if: always() uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: quality-${{ steps.tier.outputs.tier }}-${{ github.sha }} path: | quality-report/ build/coverage/coverage.json build/coverage/coverage.txt if-no-files-found: error