Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions actions/common/auto_merge.sh
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,11 @@ fi
# The branch (and its PR) may be reused across runs, so only enable auto-merge
# when it is not already enabled, since re-enabling it errors. A failed lookup
# must fail the step rather than silently skipping the merge.
AUTO_MERGE_REQUEST=$(gh pr view "$BRANCH" --json autoMergeRequest --jq '.autoMergeRequest') || exit $?
if [ "$AUTO_MERGE_REQUEST" = "null" ]; then
#
# Compare against a boolean rather than `null`: gh's built-in --jq prints an
# empty string for a JSON null (unlike jq, which prints "null"), so testing for
# "null" never matches and auto-merge would be silently skipped.
AUTO_MERGE_ENABLED=$(gh pr view "$BRANCH" --json autoMergeRequest --jq '.autoMergeRequest != null') || exit $?
if [ "$AUTO_MERGE_ENABLED" != "true" ]; then
gh pr merge "$BRANCH" --auto --squash --delete-branch
fi
36 changes: 25 additions & 11 deletions actions/common/test_auto_merge.sh
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,12 @@ check_not_contains() {
}

# Fake `gh` that logs the effective GH_TOKEN and arguments for every call. For
# `pr view` it prints a canned autoMergeRequest value, or fails when the
# pr_view_fail sentinel exists. This is not a general gh emulator — it only
# handles the exact call shapes auto_merge.sh makes.
# `pr view` it evaluates the caller's real --jq expression against a canned PR
# JSON document, or fails when the pr_view_fail sentinel exists. Like gh's
# built-in jq (and unlike jq -r), a null result prints as an empty line, so a
# script that tests for the string "null" fails here as it does in production.
# This is not a general gh emulator — it only handles the exact call shapes
# auto_merge.sh makes.
FAKE_GH="$TMPDIR/gh"
cat > "$FAKE_GH" <<FAKE_GH_EOF
#!/usr/bin/env bash
Expand All @@ -46,13 +49,21 @@ if [ "\$1" = "pr" ] && [ "\$2" = "view" ]; then
if [ -f "$TMPDIR/pr_view_fail" ]; then
exit 1
fi
cat "$TMPDIR/pr_view_response"
EXPR="."
while [ \$# -gt 0 ]; do
if [ "\$1" = "--jq" ]; then
EXPR="\$2"
shift
fi
shift
done
jq -r "\$EXPR | if . == null then \"\" else . end" "$TMPDIR/pr_view_response"
fi
FAKE_GH_EOF
chmod +x "$FAKE_GH"
export PATH="$TMPDIR:$PATH"

# run <auto_merge> <dry_run> <app_token> <pr_view_response>
# run <auto_merge> <dry_run> <app_token> <pr_view_json>
run() {
echo "$4" > "$TMPDIR/pr_view_response"
: > "$TMPDIR/gh_calls.log"
Expand All @@ -61,8 +72,11 @@ run() {
bash "$SCRIPT" "poetry-lock-update" > "$TMPDIR/output.log" 2>&1
}

NOT_ENABLED='{"autoMergeRequest":null}'
ENABLED='{"autoMergeRequest":{"enabledBy":{"login":"x"}}}'

# Case 1: disabled -> no gh calls at all
run "false" "false" "app-token" "null"
run "false" "false" "app-token" "$NOT_ENABLED"
CALLS=$(cat "$TMPDIR/gh_calls.log")
if [ -z "$CALLS" ]; then
echo "OK: disabled: no gh calls"
Expand All @@ -72,7 +86,7 @@ else
fi

# Case 2: dry-run -> no gh calls at all
run "true" "true" "app-token" "null"
run "true" "true" "app-token" "$NOT_ENABLED"
CALLS=$(cat "$TMPDIR/gh_calls.log")
if [ -z "$CALLS" ]; then
echo "OK: dry-run: no gh calls"
Expand All @@ -82,25 +96,25 @@ else
fi

# Case 3: opt-in, not yet enabled -> approve with the workflow token, then merge
run "true" "false" "app-token" "null"
run "true" "false" "app-token" "$NOT_ENABLED"
CALLS=$(cat "$TMPDIR/gh_calls.log")
check_contains "opt-in: approves with the workflow token" "GH_TOKEN=workflow-token :: pr review poetry-lock-update --approve" "$CALLS"
check_contains "opt-in: enables squash auto-merge" "pr merge poetry-lock-update --auto --squash --delete-branch" "$CALLS"

# Case 4: already enabled -> approve, but do not re-enable
run "true" "false" "app-token" '{"enabledBy":{"login":"x"}}'
run "true" "false" "app-token" "$ENABLED"
CALLS=$(cat "$TMPDIR/gh_calls.log")
check_contains "already enabled: still approves" "pr review poetry-lock-update --approve" "$CALLS"
check_not_contains "already enabled: does NOT re-enable auto-merge" "pr merge" "$CALLS"

# Case 5: no app token -> skip approval, still enable auto-merge
run "true" "false" "" "null"
run "true" "false" "" "$NOT_ENABLED"
CALLS=$(cat "$TMPDIR/gh_calls.log")
check_not_contains "no app token: does NOT approve" "pr review" "$CALLS"
check_contains "no app token: still enables auto-merge" "pr merge poetry-lock-update --auto --squash --delete-branch" "$CALLS"

# Case 6: gh pr view fails -> step fails, no merge attempted
echo "null" > "$TMPDIR/pr_view_response"
echo "$NOT_ENABLED" > "$TMPDIR/pr_view_response"
: > "$TMPDIR/gh_calls.log"
touch "$TMPDIR/pr_view_fail"
set +e
Expand Down
Loading