name: CI on: push: branches: [main] paths-ignore: ['**.md', 'docs/**', 'LICENSE'] pull_request: branches: [main] paths-ignore: ['**.md', 'docs/**', 'LICENSE'] workflow_call: concurrency: group: ci-${{ github.ref }} cancel-in-progress: true # ── Reusable workflow orchestration ───────────────────────────────── # Each concern lives in its own workflow file for maintainability: # ci-quality.yml — typecheck (tsc --noEmit) # ci-tests.yml — unit + integration tests with coverage + cross-platform # ci-e2e.yml — E2E tests (only when gitnexus-web/ changes) # # Shared setup is DRY via .github/actions/setup-gitnexus composite action. jobs: quality: uses: ./.github/workflows/ci-quality.yml permissions: contents: read tests: uses: ./.github/workflows/ci-tests.yml permissions: contents: read e2e: uses: ./.github/workflows/ci-e2e.yml permissions: contents: read # ── Save PR metadata for the reporting workflow ───────────────── # The ci-report.yml workflow (triggered by workflow_run) needs the # PR number and job results to post a comment. We save them as an # artifact because workflow_run context doesn't reliably carry PR # info for fork PRs. save-pr-meta: name: Save PR Metadata if: always() && github.event_name == 'pull_request' needs: [quality, tests, e2e] runs-on: ubuntu-latest timeout-minutes: 5 steps: - name: Write metadata shell: bash env: PR_NUMBER: ${{ github.event.number }} QUALITY: ${{ needs.quality.result }} TESTS: ${{ needs.tests.result }} E2E: ${{ needs.e2e.result }} run: | mkdir -p pr-meta echo "$PR_NUMBER" > pr-meta/pr_number echo "$QUALITY" > pr-meta/quality_result echo "$TESTS" > pr-meta/tests_result echo "$E2E" > pr-meta/e2e_result # TODO(post-merge): remove backward-compat copies once ci-report.yml # on main reads underscore names. # Backward-compat: ci-report.yml on main still reads hyphenated # names. workflow_run always executes from the default branch, so # the main-branch reader won't find the underscore variants until # this PR is merged. Write both until then. cp pr-meta/pr_number pr-meta/pr-number cp pr-meta/quality_result pr-meta/quality-result cp pr-meta/tests_result pr-meta/tests-result cp pr-meta/e2e_result pr-meta/e2e-result - name: Upload PR metadata uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: pr-meta path: pr-meta/ retention-days: 1 # ── Unified CI gate ────────────────────────────────────────────── # Single required check for branch protection. ci-status: name: CI Gate needs: [quality, tests, e2e] if: always() runs-on: ubuntu-latest timeout-minutes: 5 steps: - name: Check all jobs passed shell: bash env: QUALITY: ${{ needs.quality.result }} TESTS: ${{ needs.tests.result }} E2E: ${{ needs.e2e.result }} run: | echo "Quality: $QUALITY" echo "Tests: $TESTS" echo "E2E: $E2E" if [[ "$QUALITY" != "success" ]] || [[ "$TESTS" != "success" ]]; then echo "::error::Quality or test jobs failed" exit 1 fi if [[ "$E2E" != "success" && "$E2E" != "skipped" ]]; then echo "::error::E2E job failed" exit 1 fi