diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index 7c99c7476c..0aba05322b 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -1,35 +1,21 @@ name: Lint -on: [pull_request] +on: + pull_request: + # Do not start this workflow for docs/markdown/Actions-only PRs. + # Required check name `lint` for those PRs is reported by + # non-code-ci-status.yml so branch protection does not hang. + paths-ignore: + - 'docs/**' + - '**/*.md' + - '**/*.mdx' + - '.github/**' permissions: contents: read jobs: - changes: - name: Detect changes - runs-on: ubuntu-latest - outputs: - code: ${{ steps.filter.outputs.code }} - steps: - - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 - - uses: dorny/paths-filter@d1c1ffe0248fe513906c8e24db8ea791d46f8590 # v3 - id: filter - with: - # Exclusion-only patterns match every non-excluded file under the - # default "some" quantifier. Require all patterns (including "**") - # so docs/markdown/Actions-only PRs correctly set code=false. - predicate-quantifier: every - filters: | - code: - - '**' - - '!docs/**' - - '!**/*.md' - - '!.github/**' - lint-run: - needs: changes - if: needs.changes.outputs.code == 'true' runs-on: ubuntu-latest steps: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 @@ -76,15 +62,11 @@ jobs: lint: name: lint runs-on: ubuntu-latest - needs: [changes, lint-run] + needs: [lint-run] if: always() steps: - name: Check results run: | - if [ "${{ needs.changes.outputs.code }}" != "true" ]; then - echo "Non-code change, skipping lint" - exit 0 - fi if [ "${{ needs.lint-run.result }}" == "success" ]; then echo "Lint passed" else diff --git a/.github/workflows/non-code-ci-status.yml b/.github/workflows/non-code-ci-status.yml new file mode 100644 index 0000000000..5939eb28b8 --- /dev/null +++ b/.github/workflows/non-code-ci-status.yml @@ -0,0 +1,86 @@ +# Reports required branch-protection check names when the Python CI workflows +# are skipped via paths-ignore (docs / markdown / Actions-only PRs). +# +# Creates check runs via the Checks API (instead of same-named jobs) so code +# PRs do not get conflicting skipped `tests` / `lint` checks alongside the +# real workflows. +# +# Required contexts (ruleset "main"): lint, type-checker, tests, +# tests (3.10)–tests (3.13). +name: Non-code CI status + +on: + pull_request: + # Only start when a non-code path changed. Mixed PRs (docs + code) still + # enter here, but `report` no-ops when dorny detects code changes so we + # do not create duplicate check runs alongside Run Tests / Lint / etc. + paths: + - 'docs/**' + - '**/*.md' + - '**/*.mdx' + - '.github/**' + +permissions: + contents: read + checks: write + +jobs: + changes: + name: Detect changes + runs-on: ubuntu-latest + outputs: + code: ${{ steps.filter.outputs.code }} + steps: + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + - uses: dorny/paths-filter@d1c1ffe0248fe513906c8e24db8ea791d46f8590 # v3 + id: filter + with: + # Exclusion-only patterns match every non-excluded file under the + # default "some" quantifier. Require all patterns (including "**") + # so docs/markdown/Actions-only PRs correctly set code=false. + predicate-quantifier: every + filters: | + code: + - '**' + - '!docs/**' + - '!**/*.md' + - '!**/*.mdx' + - '!.github/**' + + report: + name: Report required checks + needs: changes + if: needs.changes.outputs.code != 'true' + runs-on: ubuntu-latest + steps: + - name: Create successful check runs for required contexts + uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7 + with: + script: | + const headSha = context.payload.pull_request.head.sha; + const names = [ + 'lint', + 'type-checker', + 'tests', + 'tests (3.10)', + 'tests (3.11)', + 'tests (3.12)', + 'tests (3.13)', + ]; + const summary = + 'Non-code change (docs / markdown / Actions-only). ' + + 'Python CI workflows were skipped via paths-ignore.'; + for (const name of names) { + await github.rest.checks.create({ + owner: context.repo.owner, + repo: context.repo.repo, + name, + head_sha: headSha, + status: 'completed', + conclusion: 'success', + output: { + title: 'Skipped (non-code change)', + summary, + }, + }); + } diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index e3a34e94c5..3cd2cac786 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -1,36 +1,22 @@ name: Run Tests -on: [pull_request] +on: + pull_request: + # Do not start this workflow for docs/markdown/Actions-only PRs. + # Required check names for those PRs are reported by non-code-ci-status.yml + # so branch protection does not hang. + paths-ignore: + - 'docs/**' + - '**/*.md' + - '**/*.mdx' + - '.github/**' permissions: contents: read jobs: - changes: - name: Detect changes - runs-on: ubuntu-latest - outputs: - code: ${{ steps.filter.outputs.code }} - steps: - - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 - - uses: dorny/paths-filter@d1c1ffe0248fe513906c8e24db8ea791d46f8590 # v3 - id: filter - with: - # Exclusion-only patterns match every non-excluded file under the - # default "some" quantifier. Require all patterns (including "**") - # so docs/markdown/Actions-only PRs correctly set code=false. - predicate-quantifier: every - filters: | - code: - - '**' - - '!docs/**' - - '!**/*.md' - - '!.github/**' - tests-matrix: name: tests (${{ matrix.python-version }}) - needs: changes - if: needs.changes.outputs.code == 'true' runs-on: ubuntu-latest timeout-minutes: 15 strategy: @@ -122,33 +108,15 @@ jobs: .venv key: uv-main-py${{ matrix.python-version }}-${{ hashFiles('uv.lock') }} - # Report the required check names (tests 3.10–3.13) when the matrix is skipped. - # Branch protection expects these names; a skipped matrix never reports them. - tests-skip: - name: tests (${{ matrix.python-version }}) - needs: changes - if: needs.changes.outputs.code != 'true' - runs-on: ubuntu-latest - strategy: - matrix: - python-version: ['3.10', '3.11', '3.12', '3.13'] - steps: - - name: Skip non-code change - run: echo "Non-code change, skipping tests" - # Summary job to provide single status for branch protection tests: name: tests runs-on: ubuntu-latest - needs: [changes, tests-matrix, tests-skip] + needs: [tests-matrix] if: always() steps: - name: Check results run: | - if [ "${{ needs.changes.outputs.code }}" != "true" ]; then - echo "Non-code change, skipping tests" - exit 0 - fi if [ "${{ needs.tests-matrix.result }}" == "success" ]; then echo "All tests passed" else diff --git a/.github/workflows/type-checker.yml b/.github/workflows/type-checker.yml index 9cb6889247..4d0aa21f44 100644 --- a/.github/workflows/type-checker.yml +++ b/.github/workflows/type-checker.yml @@ -1,36 +1,22 @@ name: Run Type Checks -on: [pull_request] +on: + pull_request: + # Do not start this workflow for docs/markdown/Actions-only PRs. + # Required check name `type-checker` for those PRs is reported by + # non-code-ci-status.yml so branch protection does not hang. + paths-ignore: + - 'docs/**' + - '**/*.md' + - '**/*.mdx' + - '.github/**' permissions: contents: read jobs: - changes: - name: Detect changes - runs-on: ubuntu-latest - outputs: - code: ${{ steps.filter.outputs.code }} - steps: - - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 - - uses: dorny/paths-filter@d1c1ffe0248fe513906c8e24db8ea791d46f8590 # v3 - id: filter - with: - # Exclusion-only patterns match every non-excluded file under the - # default "some" quantifier. Require all patterns (including "**") - # so docs/markdown/Actions-only PRs correctly set code=false. - predicate-quantifier: every - filters: | - code: - - '**' - - '!docs/**' - - '!**/*.md' - - '!.github/**' - type-checker-matrix: name: type-checker (${{ matrix.python-version }}) - needs: changes - if: needs.changes.outputs.code == 'true' runs-on: ubuntu-latest strategy: fail-fast: false @@ -76,33 +62,15 @@ jobs: .venv key: uv-main-py${{ matrix.python-version }}-${{ hashFiles('uv.lock') }} - # Report the required check names when the matrix is skipped. - # Branch protection expects these names; a skipped matrix never reports them. - type-checker-skip: - name: type-checker (${{ matrix.python-version }}) - needs: changes - if: needs.changes.outputs.code != 'true' - runs-on: ubuntu-latest - strategy: - matrix: - python-version: ["3.10", "3.11", "3.12", "3.13"] - steps: - - name: Skip non-code change - run: echo "Non-code change, skipping type checks" - # Summary job to provide single status for branch protection type-checker: name: type-checker runs-on: ubuntu-latest - needs: [changes, type-checker-matrix, type-checker-skip] + needs: [type-checker-matrix] if: always() steps: - name: Check results run: | - if [ "${{ needs.changes.outputs.code }}" != "true" ]; then - echo "Non-code change, skipping type checks" - exit 0 - fi if [ "${{ needs.type-checker-matrix.result }}" == "success" ]; then echo "All type checks passed" else diff --git a/.github/workflows/vulnerability-scan.yml b/.github/workflows/vulnerability-scan.yml index c82c3199fc..f4fb1abfb6 100644 --- a/.github/workflows/vulnerability-scan.yml +++ b/.github/workflows/vulnerability-scan.yml @@ -33,6 +33,7 @@ jobs: - '**' - '!docs/**' - '!**/*.md' + - '!**/*.mdx' - '!.github/**' - name: Set code output id: set