mirror of
https://github.com/snapotter-hq/SnapOtter.git
synced 2026-08-03 07:46:42 +02:00
ci: move path filtering to job level so required checks stay mergeable (#415)
Workflow-level paths-ignore never creates the check runs on docs-only PRs, which would deadlock required status checks (contexts stay "expected" forever). A new always-on changes job diffs against the base commit and every downstream job skips when only README, CONTRIBUTING, branding, apps/docs, apps/landing, or docs changed. Skipped jobs report a conclusion, which satisfies branch protection, so main can now require the full CI matrix without blocking docs-only changes. Fails open: unknown base (force push, dispatch, new branch) runs the full pipeline. Prerequisite for enabling required status checks on main. Claude-Session: https://claude.ai/code/session_01XGB4pGvTvb7sUX4JN745U7
This commit is contained in:
+75
-15
@@ -1,25 +1,16 @@
|
||||
name: CI
|
||||
|
||||
# Path filtering happens at the JOB level (see the `changes` job), not here.
|
||||
# Workflow-level paths-ignore never creates the check runs at all, which
|
||||
# deadlocks required status checks on docs-only PRs (contexts stay "expected"
|
||||
# forever). Job-level skips complete with conclusion "skipped", which
|
||||
# satisfies branch protection.
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches: [main]
|
||||
paths-ignore:
|
||||
- "README.md"
|
||||
- "CONTRIBUTING.md"
|
||||
- "branding/**"
|
||||
- "apps/docs/**"
|
||||
- "apps/landing/**"
|
||||
- "docs/**"
|
||||
pull_request:
|
||||
branches: [main]
|
||||
paths-ignore:
|
||||
- "README.md"
|
||||
- "CONTRIBUTING.md"
|
||||
- "branding/**"
|
||||
- "apps/docs/**"
|
||||
- "apps/landing/**"
|
||||
- "docs/**"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
@@ -36,9 +27,56 @@ env:
|
||||
TESTCONTAINERS_RYUK_DISABLED: "true"
|
||||
|
||||
jobs:
|
||||
# Detects whether anything outside the docs/landing/branding surfaces
|
||||
# changed. Downstream jobs skip when code is untouched; a skipped job still
|
||||
# reports a conclusion, so required status checks stay mergeable.
|
||||
# Fails open: any uncertainty (unknown base, force push, dispatch) runs
|
||||
# the full pipeline.
|
||||
changes:
|
||||
name: Changes
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
code: ${{ steps.filter.outputs.code }}
|
||||
steps:
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
- id: filter
|
||||
name: Diff against the base commit
|
||||
env:
|
||||
EVENT_NAME: ${{ github.event_name }}
|
||||
PR_BASE_SHA: ${{ github.event.pull_request.base.sha }}
|
||||
PUSH_BEFORE_SHA: ${{ github.event.before }}
|
||||
run: |
|
||||
if [ "$EVENT_NAME" = "pull_request" ]; then
|
||||
base="$PR_BASE_SHA"
|
||||
else
|
||||
base="$PUSH_BEFORE_SHA"
|
||||
fi
|
||||
code=true
|
||||
if [ -n "$base" ] && [ "$base" != "0000000000000000000000000000000000000000" ]; then
|
||||
if git fetch --no-tags --depth=1 origin "$base" && git cat-file -e "$base" 2>/dev/null; then
|
||||
changed=$(git diff --name-only "$base" HEAD)
|
||||
echo "Changed files:"
|
||||
printf '%s\n' "$changed"
|
||||
code=false
|
||||
for f in $changed; do
|
||||
case "$f" in
|
||||
README.md|CONTRIBUTING.md|branding/*|apps/docs/*|apps/landing/*|docs/*) ;;
|
||||
*) code=true; break ;;
|
||||
esac
|
||||
done
|
||||
else
|
||||
echo "Base commit unavailable; running the full pipeline"
|
||||
fi
|
||||
else
|
||||
echo "No usable base (dispatch, force push, or new branch); running the full pipeline"
|
||||
fi
|
||||
echo "code=$code" >> "$GITHUB_OUTPUT"
|
||||
|
||||
lint:
|
||||
name: Lint
|
||||
runs-on: ubuntu-latest
|
||||
needs: changes
|
||||
if: needs.changes.outputs.code == 'true'
|
||||
steps:
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
- uses: ./.github/actions/setup
|
||||
@@ -49,6 +87,8 @@ jobs:
|
||||
typecheck:
|
||||
name: Typecheck
|
||||
runs-on: ubuntu-latest
|
||||
needs: changes
|
||||
if: needs.changes.outputs.code == 'true'
|
||||
steps:
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
- uses: ./.github/actions/setup
|
||||
@@ -58,6 +98,8 @@ jobs:
|
||||
name: Unit Tests
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 8
|
||||
needs: changes
|
||||
if: needs.changes.outputs.code == 'true'
|
||||
steps:
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
|
||||
@@ -82,6 +124,8 @@ jobs:
|
||||
name: Integration (${{ matrix.shard }}/4)
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
needs: changes
|
||||
if: needs.changes.outputs.code == 'true'
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
@@ -131,6 +175,8 @@ jobs:
|
||||
name: E2E Smoke (Chromium)
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 15
|
||||
needs: changes
|
||||
if: needs.changes.outputs.code == 'true'
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:17-alpine
|
||||
@@ -187,6 +233,8 @@ jobs:
|
||||
name: E2E Mobile Smoke (Chromium)
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 15
|
||||
needs: changes
|
||||
if: needs.changes.outputs.code == 'true'
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:17-alpine
|
||||
@@ -238,6 +286,8 @@ jobs:
|
||||
pip-audit:
|
||||
name: Python Dependency Audit
|
||||
runs-on: ubuntu-latest
|
||||
needs: changes
|
||||
if: needs.changes.outputs.code == 'true'
|
||||
steps:
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
|
||||
@@ -276,7 +326,17 @@ jobs:
|
||||
build:
|
||||
name: Build
|
||||
runs-on: ubuntu-latest
|
||||
needs: [lint, typecheck, test-unit, test-integration, test-e2e-smoke, test-e2e-mobile-smoke]
|
||||
needs:
|
||||
[
|
||||
changes,
|
||||
lint,
|
||||
typecheck,
|
||||
test-unit,
|
||||
test-integration,
|
||||
test-e2e-smoke,
|
||||
test-e2e-mobile-smoke,
|
||||
]
|
||||
if: needs.changes.outputs.code == 'true'
|
||||
steps:
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
- uses: ./.github/actions/setup
|
||||
|
||||
Reference in New Issue
Block a user