ci: only read the Depends on lines, and let the label be the gate

This commit is contained in:
Lunny Xiao
2026-09-08 12:03:59 -07:00
parent 83cbd0138f
commit fecad73221
3 changed files with 78 additions and 26 deletions
+58 -19
View File
@@ -5,15 +5,26 @@
# Usage: ./scripts/check-upstream-deps.sh <pull request json>
#
# The json is what the gitea api returns for a pull request; the script reads
# the description and the labels from it. A dependency is declared in the
# description as
# the description and the labels from it. A dependency is declared on a line of
# its own in the description:
#
# Depends on: gitea#35851
# Depends on: https://github.com/go-gitea/gitea/pull/35851
#
# and may appear several times. `GITHUB_COM_TOKEN` is optional and only lifts
# the rate limit of the unauthenticated github api, `UPSTREAM_LABEL` overrides
# the label the check looks for.
# and may be declared several times. Only such lines count, so a pull request
# that merely mentions gitea#35851 in prose is not held back.
#
# The `depends-on-upstream` label is what blocks the merge: it fails the check
# unless every declared dependency is verified as merged. Without the label, a
# dependency that is known to be unmerged still fails, so a forgotten label does
# not let an unreleased feature through.
#
# Exit codes: 0 nothing blocks, 1 blocked, 2 usage.
#
# Environment:
# GITHUB_COM_TOKEN optional, lifts the rate limit of the github api
# UPSTREAM_LABEL label to look for, `depends-on-upstream` by default
# REQUIRE_VERIFIED set to 1 to also fail when the state cannot be determined
set -euo pipefail
@@ -30,8 +41,16 @@ body="$(jq -r '.body // ""' "$PULL_JSON")"
# argument cannot be named after it; `(.labels // [])` keeps it parsable there
labelled="$(jq -r --arg want "$LABEL" '[(.labels // [])[].name] | index($want) != null' "$PULL_JSON")"
# every gitea#<id> and every pull request url, deduplicated
require_verified="${REQUIRE_VERIFIED:-0}"
if [ "$labelled" = 'true' ]; then
# the label says the pull request is not ready, so an unverifiable dependency
# keeps it blocked instead of letting it through
require_verified=1
fi
# the ids of the `Depends on:` lines, deduplicated
refs="$(printf '%s\n' "$body" \
| grep -iE '^[[:space:]]*depends[ _-]?on[[:space:]]*:' \
| grep -oiE 'gitea#[0-9]+|github\.com/go-gitea/gitea/pull/[0-9]+' \
| grep -oE '[0-9]+' \
| sort -un || true)"
@@ -58,7 +77,8 @@ github_api() {
fi
}
status=0
unmerged=0
unknown=0
for ref in $refs; do
response="$(github_api "https://api.github.com/repos/go-gitea/gitea/pulls/$ref")"
code="$(printf '%s' "$response" | tail -n 1)"
@@ -70,34 +90,53 @@ for ref in $refs; do
echo "gitea#$ref is merged"
else
echo "gitea#$ref is not merged yet ($(printf '%s' "$payload" | jq -r '.state'))"
status=1
unmerged=1
fi
;;
404)
echo "gitea#$ref is not a pull request of go-gitea/gitea, reference the pull request that adds the feature"
status=1
unmerged=1
;;
403 | 429)
echo "the github api refused the request for gitea#$ref (rate limit?), cannot tell whether it is merged"
status=1
echo "gitea#$ref: the github api rejected the request (rate limit), cannot tell whether it is merged"
unknown=1
;;
*)
echo "unexpected response $code from the github api for gitea#$ref"
status=1
echo "gitea#$ref: unexpected response $code from the github api, cannot tell whether it is merged"
unknown=1
;;
esac
done
if [ "$status" -ne 0 ]; then
if [ "$unknown" -eq 1 ] && [ -z "${GITHUB_COM_TOKEN:-}" ]; then
echo
echo "The documentation of an unreleased feature can only be merged once the"
echo "feature itself is in gitea main. Keep the \"$LABEL\" label on this pull"
echo "request; the scheduled job removes it and reruns this check as soon as"
echo "every referenced pull request is merged."
echo "The github api allows 60 unauthenticated requests per hour and address,"
echo "which the runners share. Set the GITHUB_COM_TOKEN secret to a token with"
echo "no scopes to raise that limit."
fi
if [ "$unmerged" -eq 1 ] || { [ "$unknown" -eq 1 ] && [ "$require_verified" = '1' ]; }; then
echo
if [ "$labelled" = 'true' ]; then
echo "This pull request is labelled \"$LABEL\", so it stays blocked until every"
echo "dependency above is merged into gitea main. The scheduled job removes the"
echo "label and reruns this check as soon as that is the case."
else
echo "The documentation of an unreleased feature can only be merged once the"
echo "feature itself is in gitea main. Add the \"$LABEL\" label so the pull"
echo "request is picked up by the job that watches for it."
fi
exit 1
fi
if [ "$unknown" -eq 1 ]; then
echo
echo "Could not verify every dependency, letting the check pass: the pull request"
echo "does not carry the \"$LABEL\" label."
exit 0
fi
if [ "$labelled" = 'true' ]; then
echo
echo "every referenced pull request is merged, the \"$LABEL\" label can be removed"
echo "every declared dependency is merged, the \"$LABEL\" label can be removed"
fi
+3 -1
View File
@@ -54,7 +54,9 @@ for index in $indexes; do
# the check script exits 0 when every reference is merged; it needs the label
# to be absent from its input to stay quiet about it, so drop it here
jq 'del(.labels)' "$work/pull.json" > "$work/pull-unlabelled.json"
if ! output="$("$here/check-upstream-deps.sh" "$work/pull-unlabelled.json" 2>&1)"; then
# REQUIRE_VERIFIED keeps a dependency whose state could not be determined from
# counting as merged, which would drop the label too early
if ! output="$(REQUIRE_VERIFIED=1 "$here/check-upstream-deps.sh" "$work/pull-unlabelled.json" 2>&1)"; then
echo "#$index still waits for upstream:"
printf '%s\n' "$output" | sed 's/^/ /'
continue