name: CI

on:
  pull_request:
  push:
    branches:
      - main

permissions:
  contents: read

concurrency:
  group: ci-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
  cancel-in-progress: true

jobs:
  workflow-lint:
    name: Workflow lint
    runs-on: ubuntu-latest
    timeout-minutes: 10
    steps:
      - name: Check out the repository
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

      - name: Install actionlint
        run: |
          mkdir -p "$HOME/.local/bin"
          curl -fsSLo actionlint.tar.gz https://github.com/rhysd/actionlint/releases/download/v1.7.8/actionlint_1.7.8_linux_amd64.tar.gz
          echo 'be92c2652ab7b6d08425428797ceabeb16e31a781c07bc388456b4e592f3e36a  actionlint.tar.gz' | sha256sum --check
          tar -xzf actionlint.tar.gz actionlint
          install -m 0755 actionlint "$HOME/.local/bin/actionlint"
          printf '%s\n' "$HOME/.local/bin" >> "$GITHUB_PATH"

      - name: Lint workflows
        run: actionlint -color

  release-metadata:
    name: Release metadata
    runs-on: ubuntu-latest
    timeout-minutes: 10
    steps:
      - name: Check out the repository
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

      - name: Validate release metadata
        run: ./scripts/validate-release-metadata.sh ci

  install-surface-linux:
    name: Install surface (Linux)
    runs-on: ubuntu-latest
    timeout-minutes: 30
    steps:
      - name: Check out the repository
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

      - name: Install Rust toolchain
        run: |
          rustup set profile minimal
          rustup toolchain install stable
          rustup default stable

      - name: Validate Linux cargo install surface
        run: |
          ./scripts/validate-install-surfaces.sh cargo-install \
            --bin-name runewarp \
            --probe-arg --help \
            --expected-text "Usage: runewarp"

  install-surface-macos:
    name: Install surface (macOS)
    runs-on: macos-latest
    timeout-minutes: 30
    steps:
      - name: Check out the repository
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

      - name: Install Rust toolchain
        run: |
          rustup set profile minimal
          rustup toolchain install stable
          rustup default stable

      - name: Validate macOS cargo install surface
        run: |
          ./scripts/validate-install-surfaces.sh cargo-install \
            --bin-name runewarp \
            --probe-arg --help \
            --expected-text "Usage: runewarp"

  package-readiness:
    name: Package readiness
    runs-on: ubuntu-latest
    timeout-minutes: 20
    steps:
      - name: Check out the repository
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

      - name: Install Rust toolchain
        run: |
          rustup set profile minimal
          rustup toolchain install stable
          rustup default stable

      - name: Validate package readiness
        run: ./scripts/validate-install-surfaces.sh package-readiness

  rust-contract:
    name: Rust contract
    runs-on: ubuntu-latest
    timeout-minutes: 30
    env:
      CACHE_SCOPE: ${{ github.event_name == 'pull_request' && format('pr-{0}', github.event.pull_request.number) || format('trusted-{0}', github.ref_name) }}
    steps:
      - name: Check out the repository
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

      - name: Restore Rust build cache
        uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
        with:
          path: |
            ~/.cargo/registry/index/
            ~/.cargo/registry/cache/
            ~/.cargo/git/db/
            target/
          key: ${{ runner.os }}-rust-contract-${{ env.CACHE_SCOPE }}-${{ hashFiles('Cargo.lock') }}
          restore-keys: |
            ${{ runner.os }}-rust-contract-${{ env.CACHE_SCOPE }}-

      - name: Install Rust toolchain
        run: |
          rustup set profile minimal
          rustup toolchain install stable --component clippy,rustfmt
          rustup default stable

      - name: Check Rust formatting
        run: cargo fmt --check

      - name: Run Clippy
        run: cargo clippy --all-targets -- -D warnings

      - name: Run Rust tests
        run: cargo test --quiet

      - name: Build documentation
        run: cargo doc --no-deps

  docker-contract:
    name: Docker contract
    runs-on: ubuntu-latest
    timeout-minutes: 30
    steps:
      - name: Check out the repository
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

      - name: Validate Docker image surface
        run: |
          ./scripts/validate-install-surfaces.sh docker-image \
            --probe-arg --help \
            --expected-text "Usage: runewarp" \
            --image-tag runewarp:ci

      - name: Run Docker smoke test
        run: ./examples/docker/smoke.sh

  ci:
    name: CI
    if: always()
    runs-on: ubuntu-latest
    timeout-minutes: 5
    needs:
      - workflow-lint
      - release-metadata
      - install-surface-linux
      - install-surface-macos
      - package-readiness
      - rust-contract
      - docker-contract
    steps:
      - name: Enforce aggregate success
        env:
          WORKFLOW_LINT_RESULT: ${{ needs.workflow-lint.result }}
          RELEASE_METADATA_RESULT: ${{ needs.release-metadata.result }}
          INSTALL_SURFACE_LINUX_RESULT: ${{ needs.install-surface-linux.result }}
          INSTALL_SURFACE_MACOS_RESULT: ${{ needs.install-surface-macos.result }}
          PACKAGE_READINESS_RESULT: ${{ needs.package-readiness.result }}
          RUST_CONTRACT_RESULT: ${{ needs.rust-contract.result }}
          DOCKER_CONTRACT_RESULT: ${{ needs.docker-contract.result }}
        run: |
          for check in \
            "workflow-lint:$WORKFLOW_LINT_RESULT" \
            "release-metadata:$RELEASE_METADATA_RESULT" \
            "install-surface-linux:$INSTALL_SURFACE_LINUX_RESULT" \
            "install-surface-macos:$INSTALL_SURFACE_MACOS_RESULT" \
            "package-readiness:$PACKAGE_READINESS_RESULT" \
            "rust-contract:$RUST_CONTRACT_RESULT" \
            "docker-contract:$DOCKER_CONTRACT_RESULT"; do
            name="${check%%:*}"
            result="${check#*:}"
            if [[ "$result" != "success" ]]; then
              printf 'error: required job %s finished with %s\n' "$name" "$result" >&2
              exit 1
            fi
          done
