diff --git a/.github/actions/detect-code-changes/action.yml b/.github/actions/detect-code-changes/action.yml new file mode 100644 index 00000000..2bdf1a97 --- /dev/null +++ b/.github/actions/detect-code-changes/action.yml @@ -0,0 +1,56 @@ +name: "Detect Code Changes" +description: "Reports whether the event touched anything a build or test could care about" + +outputs: + code: + description: "'true' unless this is a pull request that only touched documentation" + value: ${{ steps.detect.outputs.code }} + +runs: + using: "composite" + steps: + - name: Detect + id: detect + shell: bash -e {0} + env: + GH_TOKEN: ${{ github.token }} + PR_NUMBER: ${{ github.event.pull_request.number }} + REPO: ${{ github.repository }} + run: | + # Only a pull request has a base to diff against. push, merge_group, + # workflow_dispatch and schedule all guard a branch directly, so they run + # everything. + if [ "$GITHUB_EVENT_NAME" != "pull_request" ]; then + echo "Event is $GITHUB_EVENT_NAME, nothing to diff." >> "$GITHUB_STEP_SUMMARY" + echo "code=true" >> "$GITHUB_OUTPUT" + exit 0 + fi + + # Fails open: downstream jobs are skipped when this one fails, and a + # skipped required check counts as successful, so an API hiccup must + # never look like "documentation only". + files=$(gh api --paginate "repos/$REPO/pulls/$PR_NUMBER/files" \ + --jq '.[].filename') || files="" + + if [ -z "$files" ]; then + echo "No file list available, running everything." >> "$GITHUB_STEP_SUMMARY" + echo "code=true" >> "$GITHUB_OUTPUT" + exit 0 + fi + + code=false + while IFS= read -r file; do + case "$file" in + *.md | docs/* | .claude/* | specs/*) ;; + *) + echo "Code change: $file" >> "$GITHUB_STEP_SUMMARY" + code=true + break + ;; + esac + done <<< "$files" + + if [ "$code" = false ]; then + echo "Documentation only." >> "$GITHUB_STEP_SUMMARY" + fi + echo "code=$code" >> "$GITHUB_OUTPUT" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4bfd1527..98e84859 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,13 +5,7 @@ on: branches: - develop - main - paths-ignore: - - "**.md" - - "docs/**" pull_request: - paths-ignore: - - "**.md" - - "docs/**" merge_group: concurrency: @@ -19,7 +13,21 @@ concurrency: cancel-in-progress: true jobs: + changes: + runs-on: ubuntu-slim + permissions: + contents: read + pull-requests: read + outputs: + code: ${{ steps.detect.outputs.code }} + steps: + - uses: actions/checkout@v4 + - id: detect + uses: ./.github/actions/detect-code-changes + tests: + needs: changes + if: needs.changes.outputs.code == 'true' runs-on: ubuntu-latest strategy: fail-fast: false diff --git a/.github/workflows/typecheck.yml b/.github/workflows/typecheck.yml index f7bd93e7..0ea48f95 100644 --- a/.github/workflows/typecheck.yml +++ b/.github/workflows/typecheck.yml @@ -13,8 +13,22 @@ concurrency: cancel-in-progress: true jobs: + changes: + runs-on: ubuntu-slim + permissions: + contents: read + pull-requests: read + outputs: + code: ${{ steps.detect.outputs.code }} + steps: + - uses: actions/checkout@v4 + - id: detect + uses: ./.github/actions/detect-code-changes + typecheck: name: TypeScript + needs: changes + if: needs.changes.outputs.code == 'true' runs-on: ubuntu-latest steps: diff --git a/.github/workflows/ui-tests.yml b/.github/workflows/ui-tests.yml index 67eae662..5b64f6a0 100644 --- a/.github/workflows/ui-tests.yml +++ b/.github/workflows/ui-tests.yml @@ -5,13 +5,7 @@ on: branches: - develop - main - paths-ignore: - - "**.md" - - "docs/**" pull_request: - paths-ignore: - - "**.md" - - "docs/**" merge_group: workflow_dispatch: @@ -20,7 +14,21 @@ concurrency: cancel-in-progress: true jobs: + changes: + runs-on: ubuntu-slim + permissions: + contents: read + pull-requests: read + outputs: + code: ${{ steps.detect.outputs.code }} + steps: + - uses: actions/checkout@v4 + - id: detect + uses: ./.github/actions/detect-code-changes + ui-tests: + needs: changes + if: needs.changes.outputs.code == 'true' runs-on: ubuntu-latest timeout-minutes: 20 name: Playwright E2E Tests diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 3c41af0e..bdb172d0 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -13,8 +13,22 @@ concurrency: cancel-in-progress: true jobs: + changes: + runs-on: ubuntu-slim + permissions: + contents: read + pull-requests: read + outputs: + code: ${{ steps.detect.outputs.code }} + steps: + - uses: actions/checkout@v4 + - id: detect + uses: ./.github/actions/detect-code-changes + unit-tests: name: Unit Tests + needs: changes + if: needs.changes.outputs.code == 'true' runs-on: ubuntu-latest steps: