mirror of
https://github.com/stack-auth/stack.git
synced 2026-07-20 21:29:36 +08:00
163 lines
6.7 KiB
YAML
163 lines
6.7 KiB
YAML
name: "all-good: Did all the other checks pass?"
|
|
|
|
on:
|
|
push:
|
|
branches:
|
|
- main
|
|
- dev
|
|
pull_request:
|
|
|
|
concurrency:
|
|
group: ${{ github.workflow }}-${{ github.ref }}
|
|
cancel-in-progress: ${{ github.ref != 'refs/heads/main' && github.ref != 'refs/heads/dev' }}
|
|
|
|
jobs:
|
|
all-good:
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
checks: read
|
|
contents: read
|
|
env:
|
|
REPO: ${{ github.repository }}
|
|
COMMIT: ${{ github.sha }}
|
|
PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }}
|
|
steps:
|
|
- name: Wait for 60 seconds
|
|
run: sleep 60
|
|
|
|
- name: Poll Checks API until complete
|
|
env:
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
run: |
|
|
set -euo pipefail
|
|
|
|
echo "Checking check runs for commit ${COMMIT} in repo ${REPO}..."
|
|
|
|
function get_check_runs() {
|
|
local endpoint=$1
|
|
local page=1
|
|
local response
|
|
local page_count
|
|
local responses_file
|
|
local expected_count
|
|
local returned_count
|
|
local combined
|
|
responses_file=$(mktemp)
|
|
|
|
while true; do
|
|
if ! response=$(curl -sS --fail-with-body \
|
|
--retry 3 \
|
|
--retry-all-errors \
|
|
--connect-timeout 10 \
|
|
--max-time 30 \
|
|
-H "Authorization: Bearer ${GITHUB_TOKEN}" \
|
|
-H "Accept: application/vnd.github+json" \
|
|
-H "X-GitHub-Api-Version: 2022-11-28" \
|
|
"${endpoint}?filter=latest&per_page=100&page=${page}"); then
|
|
echo "Error fetching page ${page} from ${endpoint}" >&2
|
|
rm -f "$responses_file"
|
|
return 1
|
|
fi
|
|
|
|
printf '%s\n' "$response" >> "$responses_file"
|
|
if ! page_count=$(jq '.check_runs | length' <<< "$response"); then
|
|
echo "Invalid Checks API response from ${endpoint}" >&2
|
|
rm -f "$responses_file"
|
|
return 1
|
|
fi
|
|
|
|
[ "$page_count" -lt 100 ] && break
|
|
page=$((page + 1))
|
|
done
|
|
|
|
# Check runs can be added while pagination is in progress. Deduplicate
|
|
# overlapping pages, then fail closed if the collected pages do not
|
|
# contain every run promised by the largest observed total_count.
|
|
expected_count=$(jq -s '[.[].total_count // 0] | max // 0' "$responses_file")
|
|
combined=$(jq -s '
|
|
[.[].check_runs[]?] | unique_by(.id) as $runs
|
|
| { total_count: ($runs | length), check_runs: $runs }
|
|
' "$responses_file")
|
|
returned_count=$(jq '.total_count' <<< "$combined")
|
|
rm -f "$responses_file"
|
|
|
|
if [ "$returned_count" -lt "$expected_count" ]; then
|
|
echo "Checks API returned ${returned_count} unique runs but reported ${expected_count}; refusing a partial result." >&2
|
|
return 1
|
|
fi
|
|
|
|
printf '%s\n' "$combined"
|
|
}
|
|
|
|
function count_pending_checks() {
|
|
local response=$1
|
|
echo "$response" | jq '([.check_runs[]? | select(.status != "completed" and .name != "all-good" and .name != "claude-review")] | length) // 0'
|
|
}
|
|
|
|
function count_failed_checks() {
|
|
local response=$1
|
|
echo "$response" | jq '([.check_runs[]? | select(.conclusion != "success" and .conclusion != "skipped" and .conclusion != "neutral" and .name != "all-good" and .name != "claude-review")] | length) // 0'
|
|
}
|
|
|
|
while true; do
|
|
# Always check the current commit's checks
|
|
commit_response=$(get_check_runs "https://api.github.com/repos/${REPO}/commits/${COMMIT}/check-runs")
|
|
commit_total=$(echo "$commit_response" | jq -r '.total_count // 0')
|
|
|
|
# If this is a PR, check the PR's head commit checks
|
|
pr_total=0
|
|
pr_response='{"total_count":0,"check_runs":[]}'
|
|
if [ -n "$PR_HEAD_SHA" ] && [ "$PR_HEAD_SHA" != "$COMMIT" ]; then
|
|
pr_response=$(get_check_runs "https://api.github.com/repos/${REPO}/commits/${PR_HEAD_SHA}/check-runs")
|
|
pr_total=$(echo "$pr_response" | jq -r '.total_count // 0')
|
|
echo "Found ${commit_total} current commit checks and ${pr_total} PR head commit checks"
|
|
else
|
|
echo "Found ${commit_total} commit checks"
|
|
fi
|
|
|
|
# If no checks found at all, wait and retry
|
|
if [ "$commit_total" -eq 0 ] && { [ -z "$PR_HEAD_SHA" ] || [ "$pr_total" -eq 0 ]; }; then
|
|
echo "No check runs found. Waiting..."
|
|
sleep 10
|
|
continue
|
|
fi
|
|
|
|
# Check for pending runs in both current and PR head commit checks
|
|
commit_pending=$(count_pending_checks "$commit_response")
|
|
pr_pending=0
|
|
if [ -n "$PR_HEAD_SHA" ] && [ "$PR_HEAD_SHA" != "$COMMIT" ]; then
|
|
pr_pending=$(count_pending_checks "$pr_response")
|
|
fi
|
|
|
|
total_pending=$((commit_pending + pr_pending))
|
|
if [ "$total_pending" -gt 0 ]; then
|
|
echo "$total_pending check run(s) still in progress. Waiting..."
|
|
sleep 10
|
|
continue
|
|
fi
|
|
|
|
# Check for failures in both current and PR head commit checks
|
|
commit_failed=$(count_failed_checks "$commit_response")
|
|
pr_failed=0
|
|
if [ -n "$PR_HEAD_SHA" ] && [ "$PR_HEAD_SHA" != "$COMMIT" ]; then
|
|
pr_failed=$(count_failed_checks "$pr_response")
|
|
fi
|
|
|
|
total_failed=$((commit_failed + pr_failed))
|
|
if [ "$total_failed" -eq 0 ]; then
|
|
echo "All check runs passed!"
|
|
exit 0
|
|
else
|
|
echo "The following check run(s) failed:"
|
|
# Failed checks on the current commit (excluding claude-review)
|
|
echo "$commit_response" | jq -r '.check_runs[] | select(.conclusion != "success" and .conclusion != "skipped" and .conclusion != "neutral" and .name != "claude-review") | .name' | sed 's/^/ - /'
|
|
# Failed checks on the PR head commit (if different, excluding claude-review)
|
|
if [ -n "$PR_HEAD_SHA" ] && [ "$PR_HEAD_SHA" != "$COMMIT" ]; then
|
|
echo "$pr_response" | jq -r '.check_runs[] | select(.conclusion != "success" and .conclusion != "skipped" and .conclusion != "neutral" and .name != "claude-review") | .name' | sed 's/^/ - /'
|
|
fi
|
|
echo "$commit_response"
|
|
echo "$pr_response"
|
|
exit 1
|
|
fi
|
|
done
|