name: "🔀 Pull Request" run-name: >- ${{ github.event_name }} / PR #${{ github.event.pull_request.number }} / ${{ github.event.action }} / ${{ github.event.pull_request.head.label }} on: pull_request: types: - opened - synchronize - reopened - ready_for_review - labeled pull_request_target: types: - opened - synchronize - reopened - ready_for_review - labeled concurrency: group: pr-ci-${{ github.repository }}-${{ github.event_name }}-pr-${{ github.event.pull_request.number }} cancel-in-progress: true permissions: contents: read jobs: detect-pr-scope: name: 🔎 Detect PR scope if: ${{ github.event.pull_request.draft == false && (github.event_name == 'pull_request' || github.event.pull_request.head.repo.full_name != github.repository) }} runs-on: ubuntu-26.04 outputs: scope: ${{ steps.resolve.outputs.scope }} run_ci_orchestrator: ${{ steps.resolve.outputs.run_ci_orchestrator }} steps: - name: ⬇️ Checkout uses: actions/checkout@v7.0.0 - name: 🔍 Resolve PR scope id: resolve env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} REPOSITORY: ${{ github.repository }} PR_NUMBER: ${{ github.event.pull_request.number }} run: ./scripts/meta/resolve/pr/scope.sh validation: name: 🧭 PR scope needs: detect-pr-scope if: ${{ github.event_name == 'pull_request' || github.event.pull_request.head.repo.full_name != github.repository }} uses: ./.github/workflows/call-validation.yml with: pr_scope: ${{ needs.detect-pr-scope.outputs.scope }} pr-scope-gate: name: 🚦 Gate PR scope needs: - detect-pr-scope - validation if: ${{ needs.detect-pr-scope.outputs.run_ci_orchestrator == 'false' }} runs-on: ubuntu-26.04 steps: - name: ✅ Confirm lightweight PR scope shell: bash run: | set -euo pipefail echo "Lightweight PR scope '${{ needs.detect-pr-scope.outputs.scope }}' passed." detect-affected-roles: name: 🧭 Detect affected roles needs: - detect-pr-scope - validation if: ${{ needs.detect-pr-scope.outputs.run_ci_orchestrator == 'true' }} runs-on: ubuntu-26.04 outputs: whitelist: ${{ steps.resolve.outputs.whitelist }} steps: - name: ⬇️ Checkout uses: actions/checkout@v7.0.0 with: fetch-depth: 0 - name: 🔧 Set up Python uses: actions/setup-python@v6 with: python-version: "3.12" cache: pip cache-dependency-path: pyproject.toml - name: 📦 Install project (host venv) shell: bash run: make install - name: 🔍 Resolve affected roles id: resolve shell: bash env: SUBSET_LABELED: ${{ contains(github.event.pull_request.labels.*.name, '🧩 Subset') }} PR_BODY: ${{ github.event.pull_request.body }} run: bash scripts/github/resolve/pr_affected_roles.sh ci-orchestrator: needs: - detect-pr-scope - validation - detect-affected-roles if: ${{ github.event_name == 'pull_request' && needs.detect-pr-scope.outputs.run_ci_orchestrator == 'true' }} permissions: actions: read contents: read packages: write security-events: write issues: write uses: ./.github/workflows/call-orchestrator.yml with: distros: "arch debian ubuntu fedora centos" whitelist: ${{ needs.detect-affected-roles.outputs.whitelist }} trusted_pr: ${{ contains(github.event.pull_request.labels.*.name, '🛡️ Trusted') }} prepare-fork-merge-ref: needs: - detect-pr-scope - validation if: ${{ github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.full_name != github.repository && needs.detect-pr-scope.outputs.run_ci_orchestrator == 'true' }} runs-on: ubuntu-26.04 outputs: checkout_ref: ${{ steps.out.outputs.checkout_ref }} image_tag: ${{ steps.out.outputs.image_tag }} trusted: ${{ contains(github.event.pull_request.labels.*.name, '🛡️ Trusted') }} steps: - name: ⬇️ Checkout uses: actions/checkout@v7.0.0 - name: 🔍 Resolve merge ref and image tag id: out env: PR_NUMBER: ${{ github.event.pull_request.number }} PR_MERGE_SHA: ${{ github.event.pull_request.merge_commit_sha || '' }} run: ./scripts/meta/resolve/pr/merge_ref.sh build-ci-images-fork: needs: prepare-fork-merge-ref permissions: contents: read packages: write uses: ./.github/workflows/call-images-build-ci.yml with: distros: "arch debian ubuntu fedora centos" checkout_ref: ${{ needs.prepare-fork-merge-ref.outputs.trusted == 'true' && github.event.pull_request.head.sha || needs.prepare-fork-merge-ref.outputs.checkout_ref }} source_repository: ${{ needs.prepare-fork-merge-ref.outputs.trusted == 'true' && github.event.pull_request.head.repo.full_name || github.repository }} image_tag: ${{ needs.prepare-fork-merge-ref.outputs.image_tag }} concurrency_channel: pr-target-build-producer allow_unsafe_checkout: true images-mirror-missing-fork: needs: prepare-fork-merge-ref permissions: contents: read packages: write uses: ./.github/workflows/call-images-mirror-missing.yml with: repo_root: _pr_source source_repository: ${{ github.repository }} source_ref: ${{ needs.prepare-fork-merge-ref.outputs.checkout_ref }} source_path: _pr_source concurrency_channel: pr-target-mirror-producer concurrency_key: pr-${{ github.event.pull_request.number }} allow_unsafe_checkout: true secrets: inherit