diff --git a/scripts/pr.sh b/scripts/pr.sh index 7dccd82..d764d44 100755 --- a/scripts/pr.sh +++ b/scripts/pr.sh @@ -71,6 +71,16 @@ release_title() { [[ "$(printf '%s' "$1" | tr '[:upper:]' '[:lower:]')" == "release "* ]] } +# Auto-merge waits for the required checks only where a ruleset demands them; +# without any, GitHub merges at once, untested. So both commands refuse. +require_checks() { + local n + n=$(gh api 'repos/{owner}/{repo}/rules/branches/main' \ + --jq '[.[] | select(.type == "required_status_checks")] | length') + [ "${n:-0}" -gt 0 ] || + die "main has no required checks: auto-merge would merge untested. Protect main first (a ruleset requiring ci-ok and security / report)." +} + open_pr() { # open_pr : number of the branch's open pull request, if any gh pr list --head "$1" --state open --json number --jq '.[0].number // empty' } @@ -109,6 +119,7 @@ cmd_merge() { die "merge: run on a feature branch" fi require_clean + require_checks git fetch --quiet origin main git merge-base --is-ancestor origin/main HEAD || die "merge: $branch does not contain origin/main (git rebase origin/main)" @@ -138,6 +149,7 @@ cmd_release() { shift 4 local base next tag title branch pr sha run require_clean + require_checks git fetch --quiet origin main branch=$(git rev-parse --abbrev-ref HEAD) if [ "$branch" = main ]; then diff --git a/scripts/test_pr.sh b/scripts/test_pr.sh index db30d86..0020750 100755 --- a/scripts/test_pr.sh +++ b/scripts/test_pr.sh @@ -29,6 +29,7 @@ case "$1 $2" in *) echo MERGED ;; esac ;; "run list") echo 42 ;; + "api repos/{owner}/{repo}/rules/branches/main") cat "$STUB/checks" 2>/dev/null || echo 2 ;; "run watch") exit "$(cat "$STUB/watch" 2>/dev/null || echo 0)" ;; esac EOF @@ -131,6 +132,13 @@ git -C "$repo" commit -q -m "a repository without a version" check "merge: '-' for a repository without a version file" 0 merge - <<<"9.9.9" expect "merge: '-' still opens the pull request" logged "gh pr create --base main --head feat" +setup VERSION 1.2.3 +echo 0 >"$STUB/checks" +check "merge: refused when main has no required checks" 1 merge VERSION +check "release: refused when main has no required checks" 1 release patch x VERSION release.yml VERSION +expect "no required checks: nothing pushed, no pull request" not_logged "gh pr create" +expect "no required checks: the branch stays local" test -z "$(git -C "$origin" branch --list feat)" + setup VERSION 1.2.3 git -C "$repo" switch -q main check "merge: refused on main" 1 merge VERSION