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
11 changes: 11 additions & 0 deletions scripts/gh-merge-green
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,13 @@ if [ -n "$override_reason" ]; then
'explain the concrete red check and why this exact head is safe to merge'
fi
fi
skip_vercel=0
if [ -n "$override_reason" ] && [[ "$override_reason" =~ [Vv]ercel ]]; then
# Vercel is an optional preview deployment status in this repository. An
# explicit, auditable override may waive that one external status when it is
# pending or red; all other pending statuses remain merge blockers.
skip_vercel=1
fi
if [ "$fix" -eq 1 ] && [ -n "$override_reason" ]; then
refuse \
'not green: --override cannot be combined with --main-fix' \
Expand Down Expand Up @@ -477,6 +484,10 @@ if [ "$has_ci" -eq 0 ]; then
while IFS=$'\t' read -r name st co; do
[ -n "$name" ] || continue
reported=$((reported + 1))
if [ "$skip_vercel" -eq 1 ] && [ "$name" = Vercel ]; then
echo "note: --override waived Vercel $st/$co status" >&2
continue
fi

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Waived Vercel counts as reported

Medium Severity

The Vercel skip continues after reported is incremented, so a waived pending Vercel status still satisfies the later “no checks have reported” guard. A head whose only GitHub verdict is that pending status can merge under --override, including in the window before Actions has created any check runs.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 3485d2f. Configure here.

if [ "$st" != completed ]; then
refuse \
"not green: '$name' is $st/$co on $sha (no ci-status workflow on base $base)" \
Expand Down
18 changes: 16 additions & 2 deletions tests/test_gh_merge_green.py
Original file line number Diff line number Diff line change
Expand Up @@ -686,7 +686,7 @@ class WorkflowPresenceRegression(unittest.TestCase):
"""Repositories without the aggregate workflow use all exact-head verdicts."""

def run_case(self, *, workflow=False, probe_status=404, checks=None, statuses=None, app_workflow=False, files=None, workflow_body=None,
raw_content=None, app_workflow_body=None):
raw_content=None, app_workflow_body=None, extra_args=()):
with tempfile.TemporaryDirectory() as directory:
directory = Path(directory)
marker = directory / "merged"
Expand All @@ -706,6 +706,8 @@ def run_case(self, *, workflow=False, probe_status=404, checks=None, statuses=No
with open(os.environ['QUERIES'], 'a') as f: f.write(' '.join(a) + '\n')
if a[:2] == ['pr', 'view']:
print(json.dumps({'headRefOid': x['head'], 'baseRefName': 'main', 'state': 'OPEN'}))
elif a[:2] == ['pr', 'comment']:
pass
elif a[:2] == ['pr', 'merge']:
Path(os.environ['MERGE_MARKER']).touch()
elif a[0] == 'api' and any('/contents/' in arg for arg in a):
Expand All @@ -731,7 +733,7 @@ def run_case(self, *, workflow=False, probe_status=404, checks=None, statuses=No
sys.exit(2)
"""))
gh.chmod(0o755)
result = subprocess.run([str(ROOT / 'scripts/gh-merge-green'), 'manaflow-ai/cmuxterm-hq#1254', '--squash'],
result = subprocess.run([str(ROOT / 'scripts/gh-merge-green'), 'manaflow-ai/cmuxterm-hq#1254', *extra_args, '--squash'],
env={**os.environ, 'PATH': str(directory) + os.pathsep + os.environ['PATH'], 'FIXTURE': str(fixture), 'MERGE_MARKER': str(marker), 'QUERIES': str(queries), 'GH_MERGE_GREEN_NO_AUTO_UPDATE': '1'}, capture_output=True, text=True)
return result, marker.exists(), queries.read_text()

Expand Down Expand Up @@ -763,6 +765,18 @@ def test_no_ci_workflow_refuses_pending_status_context(self):
self.assertNotEqual(result.returncode, 0)
self.assertFalse(merged)

def test_vercel_override_waives_only_the_named_external_status(self):
result, merged, _ = self.run_case(
statuses=[{'id': 2, 'context': 'Vercel', 'state': 'pending'}],
extra_args=("--override", "Vercel preview is unrelated to this CLI change"))
self.assertEqual(result.returncode, 0, result.stderr)
self.assertTrue(merged)
result, merged, _ = self.run_case(
statuses=[{'id': 2, 'context': 'review', 'state': 'pending'}],
extra_args=("--override", "Vercel preview is unrelated to this CLI change"))
self.assertNotEqual(result.returncode, 0)
self.assertFalse(merged)

def test_workflow_probe_failure_is_not_absence(self):
for code in (403, 500):
result, merged, _ = self.run_case(probe_status=code)
Expand Down
Loading