Skip to content
This repository was archived by the owner on Jul 22, 2026. It is now read-only.
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
2 changes: 1 addition & 1 deletion .github/workflows/branch_pr_actions.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ permissions:
contents: read
pull-requests: write
issues: write
actions: read
actions: write
checks: read

concurrency:
Expand Down
25 changes: 21 additions & 4 deletions .github/workflows/queue.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,27 @@ name: GenVM full
# "Force run full tests" checkbox sets the latter);
# - without a marker `validate-end` fails, so the CI check stays red
# until a full run has happened.
#
# The action panel ("Force"/"Rerun full tests") triggers a run directly via
# `workflow_dispatch` rather than relying on a label edit: a label applied by
# the bot's GITHUB_TOKEN does NOT emit a `labeled` event (GitHub suppresses
# recursive runs), but a `workflow_dispatch` from that same token DOES run.
# The dispatch targets the PR head branch, so the run's head_sha equals the
# PR head and the Merge gate (which matches by head_sha) counts it.
on:
pull_request:
branches: ['v*-dev']
types: [opened, synchronize, reopened, ready_for_review, labeled]
workflow_dispatch:
inputs:
pr:
description: PR number this manual run validates (used only for the run name)
type: string
required: false

run-name: >-
GenVM full${{ github.event_name == 'workflow_dispatch' && format(' (manual, PR #{0})', inputs.pr) || '' }}

defaults:
run:
shell: bash -x {0}
Expand All @@ -29,7 +46,7 @@ jobs:
secrets: inherit

module-test-python:
if: ${{ contains(github.event.pull_request.labels.*.name, 'rtm') || contains(github.event.pull_request.labels.*.name, 'run-full-tests') }}
if: ${{ github.event_name == 'workflow_dispatch' || contains(github.event.pull_request.labels.*.name, 'rtm') || contains(github.event.pull_request.labels.*.name, 'run-full-tests') }}
needs: [initial]
runs-on: ubuntu-latest
steps:
Expand All @@ -45,7 +62,7 @@ jobs:
- run: ./support/ci/pipelines/test-python.sh

module-test-rust-fuzz:
if: ${{ contains(github.event.pull_request.labels.*.name, 'rtm') || contains(github.event.pull_request.labels.*.name, 'run-full-tests') }}
if: ${{ github.event_name == 'workflow_dispatch' || contains(github.event.pull_request.labels.*.name, 'rtm') || contains(github.event.pull_request.labels.*.name, 'run-full-tests') }}
needs: [initial]
runs-on: ubuntu-latest
steps:
Expand Down Expand Up @@ -76,7 +93,7 @@ jobs:
GEMINIKEY: ${{ secrets.GEMINIKEY }}

module-test-rust:
if: ${{ contains(github.event.pull_request.labels.*.name, 'rtm') || contains(github.event.pull_request.labels.*.name, 'run-full-tests') }}
if: ${{ github.event_name == 'workflow_dispatch' || contains(github.event.pull_request.labels.*.name, 'rtm') || contains(github.event.pull_request.labels.*.name, 'run-full-tests') }}
needs: [initial]
runs-on: ubuntu-latest
steps:
Expand Down Expand Up @@ -120,7 +137,7 @@ jobs:
- module-test-rust
- module-test-rust-fuzz
env:
HAS_MARKER: ${{ contains(github.event.pull_request.labels.*.name, 'rtm') || contains(github.event.pull_request.labels.*.name, 'run-full-tests') }}
HAS_MARKER: ${{ github.event_name == 'workflow_dispatch' || contains(github.event.pull_request.labels.*.name, 'rtm') || contains(github.event.pull_request.labels.*.name, 'run-full-tests') }}
steps:
- name: check
run: |
Expand Down
13 changes: 7 additions & 6 deletions support/ci/genvm-merge-into-dev.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,15 +86,16 @@ def check_gates(pr):

head_sha = pr['headRefOid']

# 3. full GenVM CI (queue.yaml) green on the head commit. queue.yaml runs
# on the `rtm` label, so the same head may have skipped runs (from
# unrelated labels) alongside the real one — require ANY completed run on
# this exact commit to have succeeded, not just the most recent.
# 3. full GenVM CI (queue.yaml) green on the head commit. The same head may
# carry skipped runs (label events that didn't run full tests) alongside the
# real one, and the run may have been started by either a push
# (event=pull_request) or the action panel (event=workflow_dispatch) — so we
# query all events and require ANY completed run on this exact commit to have
# succeeded, not just the most recent.
runs = json.loads(
gh(
'api',
f'repos/{REPO}/actions/workflows/queue.yaml/runs'
f'?head_sha={head_sha}&event=pull_request',
f'repos/{REPO}/actions/workflows/queue.yaml/runs?head_sha={head_sha}',
)
)['workflow_runs']
if not any(r['status'] == 'completed' and r['conclusion'] == 'success' for r in runs):
Expand Down
51 changes: 37 additions & 14 deletions support/ci/pr-action-panel.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,24 @@
2. do nothing unless the PR carries the `ci-safe` label (the gate that lets
any of these actions run; auto-added for write-access authors);
3. parse which boxes are ticked and act:
- "Force run full tests" is a STICKY toggle: when ticked we just ensure the
`run-full-tests` label is set (so queue.yaml runs on every push). We neither
untick it nor trigger a one-off run — its checked state mirrors the label.
- "Rerun full tests" is a momentary button: re-apply `run-full-tests`
(remove+add) to force a fresh queue.yaml run on the current head, then untick.
- "Force run full tests" is a STICKY toggle: on the edit that newly ticks it
we set the `run-full-tests` label (so queue.yaml runs on every future push)
AND dispatch one run now. We do not untick it — its checked state mirrors the
label, and an already-set label means no re-dispatch on unrelated edits.
- "Rerun full tests" is a momentary button: dispatch a fresh queue.yaml run on
the current head, then untick.
- "Merge" is a momentary button: expose `merge=true` so the caller runs the
reusable merge workflow, then untick.
4. untick the momentary boxes (not the sticky Force one).

Runs are started with `gh workflow run queue.yaml --ref <PR head branch>` (a
`workflow_dispatch`), NOT by toggling a label: a label applied by the bot's
GITHUB_TOKEN does not emit a `labeled` event (GitHub blocks recursive runs),
whereas a `workflow_dispatch` from the same token does run. Dispatching on the
PR head branch makes the run's head_sha equal the PR head, so the Merge gate
counts it. (Fork PRs have no head branch in this repo, so the panel can only
dispatch for same-repo branches — the common GenVM flow.)

Resetting the panel re-fires issue_comment:edited, but that event is sent by
the bot, so it is ignored — no loop.

Expand Down Expand Up @@ -66,10 +75,22 @@ def add_label(name):
)


def remove_label(name):
gh(
'api', '--method', 'DELETE', f'repos/{REPO}/issues/{PR}/labels/{name}', check=False
)
def head_branch():
return gh(
'pr', 'view', PR, '--repo', REPO, '--json', 'headRefName', '--jq', '.headRefName'
).stdout.strip()


def dispatch_full_tests():
# Start queue.yaml on the PR head branch so the run's head_sha matches the
# PR head (the Merge gate keys off head_sha). A workflow_dispatch fired with
# GITHUB_TOKEN does create a run, unlike a bot-applied `labeled` event.
branch = head_branch()
if not branch:
print('could not resolve PR head branch; cannot dispatch full tests')
return
gh('workflow', 'run', 'queue.yaml', '--repo', REPO, '--ref', branch, '-f', f'pr={PR}')
print(f'dispatched queue.yaml on `{branch}`')


def ticked_boxes(body):
Expand Down Expand Up @@ -119,15 +140,17 @@ def main():
print('no ticked boxes; nothing to do')
return

# Force: sticky enable of the run-full-tests marker (no untick, no one-off).
# Force: sticky enable of the run-full-tests marker so every future push
# runs full tests. Only on the edit that newly sets it do we also dispatch
# a run now (an already-set label means this is an unrelated edit -> no
# duplicate run).
if any('force' in b for b in boxes) and RUN_FULL_TESTS_LABEL not in current:
add_label(RUN_FULL_TESTS_LABEL)
dispatch_full_tests()

# Rerun: force a fresh queue run on the current head even if the marker is
# already set (remove+add re-emits the `labeled` event).
# Rerun: momentary -> always dispatch a fresh run on the current head.
if any('rerun' in b for b in boxes):
remove_label(RUN_FULL_TESTS_LABEL)
add_label(RUN_FULL_TESTS_LABEL)
dispatch_full_tests()

if any('merge' in b for b in boxes):
set_output('merge', 'true')
Expand Down
Loading