thermograph/.forgejo/workflows/pr-build.yml

99 lines
3.3 KiB
YAML
Raw Permalink Normal View History

name: PR build (required check)
# Monorepo port of the app repos' pr-build.yml: ONE workflow, ONE stable
# required-check name (`gate`), any number of domains. A `changes` job diffs
# the PR against its base; per-domain jobs run only for domains the PR
# touches; `gate` reduces their results into the single status branch
# protection requires.
#
# Deliberately NOT path-filtered at the workflow level: a path-filtered
# required check that never fires leaves the PR stuck "expected -- waiting for
# status" forever, so auto-merge never proceeds. An always-running gate whose
# domain jobs skip cleanly gives the same compute savings without the
# deadlock.
#
# One-time web UI setup (Settings -> Branches, rules for `dev` and `main`):
# -> enable "Enable Status Check", list this workflow's "gate" job
# -> merge style: squash
# Then on a ready PR: "Auto merge when checks succeed".
on:
pull_request:
branches: [dev, main]
concurrency:
group: pr-build-${{ github.event.pull_request.number }}
cancel-in-progress: true
jobs:
changes:
runs-on: docker
outputs:
backend: ${{ steps.diff.outputs.backend }}
frontend: ${{ steps.diff.outputs.frontend }}
observability: ${{ steps.diff.outputs.observability }}
steps:
- uses: actions/checkout@v4
with:
# The PR base commit isn't reachable from a depth-1 clone; full
# history keeps the diff computable however far the branch diverged.
fetch-depth: 0
- name: Detect changed domains
id: diff
run: |
set -euo pipefail
base="${{ github.event.pull_request.base.sha }}"
changed=$(git diff --name-only "$base" "$GITHUB_SHA")
echo "changed files:"; printf '%s\n' "$changed"
for d in backend frontend observability; do
if printf '%s\n' "$changed" | grep -q "^$d/"; then
echo "$d=true" >> "$GITHUB_OUTPUT"
else
echo "$d=false" >> "$GITHUB_OUTPUT"
fi
done
build-backend:
needs: changes
if: needs.changes.outputs.backend == 'true'
uses: ./.forgejo/workflows/build.yml
with:
domain: backend
build-frontend:
needs: changes
if: needs.changes.outputs.frontend == 'true'
uses: ./.forgejo/workflows/build.yml
with:
domain: frontend
validate-observability:
needs: changes
if: needs.changes.outputs.observability == 'true'
uses: ./.forgejo/workflows/observability-validate.yml
gate:
name: gate
# always(): skipped domain jobs (nothing changed there) must not skip the
# gate itself -- the required check has to report on EVERY PR.
if: always()
needs: [changes, build-backend, build-frontend, validate-observability]
runs-on: docker
steps:
- name: Reduce domain results
run: |
set -euo pipefail
ok=1
for pair in \
"backend=${{ needs.build-backend.result }}" \
"frontend=${{ needs.build-frontend.result }}" \
"observability=${{ needs.validate-observability.result }}"; do
echo "$pair"
case "${pair#*=}" in
success|skipped) ;;
*) ok=0 ;;
esac
done
[ "$ok" = 1 ] || { echo "a changed domain's check failed"; exit 1; }