* ci: add Product CI merge gate and Autopilot auto-merge path
Aggregate lint, typecheck, builds, unit, Postgres journeys, and Web E2E
into a single Product CI check for branch protection. Soft-fail artifact
uploads and skip headless macOS screenshots so infra noise does not block
merge. Add autopilot/auto-merge workflow and MERGE_GATES.md.
Co-authored-by: cynarAI <cynarAI@users.noreply.github.com>
* fix(ci): keep autopilot auto-merge inert without label
Co-authored-by: cynarAI <cynarAI@users.noreply.github.com>
* fix(ci): run autopilot auto-merge on self-hosted runner
Co-authored-by: cynarAI <cynarAI@users.noreply.github.com>
* fix(ci): free stale E2E ports before Playwright bind on Linux
Self-hosted evoo-ci runners can retain listeners on harness ports
(3110 API, 5180 web, 4321 marketing, 3111 device control) after a
failed run, causing EADDRINUSE before the next job. Add a guarded
free-e2e-ports.sh that uses fuser on Linux only and never touches
live dev ports 3100/5173. Wire it into the Playwright workflow and
the E2E harness with clear logging.
Co-authored-by: cynarAI <cynarAI@users.noreply.github.com>
* fix(web): stabilize message More menu Escape in hover E2E
The desktop hover spec assumed Escape always closed the first page-level
menu within one keypress. On self-hosted Chromium the Copy menu could stay
open while the rail remained visible, failing getByRole('menu') count.
Wait for the Copy item to prove the menu opened, then retry Escape until
that item hides while asserting the More control stays on the hover rail.
Co-authored-by: cynarAI <cynarAI@users.noreply.github.com>
* fix(web): retry sign-up navigation in Playwright helpers
Late-suite specs can miss the sign-up heading when Vite is still
warming on self-hosted runners. Retry goto until the form renders
instead of failing once at the default timeout.
Co-authored-by: cynarAI <cynarAI@users.noreply.github.com>
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: cynarAI <cynarAI@users.noreply.github.com>
120 lines
4.5 KiB
YAML
120 lines
4.5 KiB
YAML
# Enables GitHub auto-merge for Autopilot PRs once the Product CI gate is green.
|
|
# Label a pull request with `autopilot` or `automerge` to opt in.
|
|
# This workflow is informational only — never add it to required status checks.
|
|
name: autopilot auto-merge
|
|
|
|
on:
|
|
pull_request:
|
|
types: [labeled, unlabeled, opened, synchronize, reopened, ready_for_review]
|
|
check_suite:
|
|
types: [completed]
|
|
|
|
permissions:
|
|
contents: read
|
|
pull-requests: write
|
|
checks: read
|
|
|
|
concurrency:
|
|
group: autopilot-auto-merge-${{ github.event.pull_request.number || github.run_id }}
|
|
cancel-in-progress: false
|
|
|
|
jobs:
|
|
auto-merge:
|
|
name: Autopilot auto-merge
|
|
runs-on: [self-hosted, evoo-ci, Linux]
|
|
steps:
|
|
- name: Resolve pull request
|
|
id: pr
|
|
env:
|
|
GH_TOKEN: ${{ github.token }}
|
|
run: |
|
|
set -euo pipefail
|
|
event_name="${{ github.event_name }}"
|
|
number=""
|
|
if [[ "$event_name" == "pull_request" ]]; then
|
|
number="${{ github.event.pull_request.number }}"
|
|
elif [[ "$event_name" == "check_suite" ]]; then
|
|
number="$(jq -r '.check_suite.pull_requests[0].number // empty' "$GITHUB_EVENT_PATH")"
|
|
fi
|
|
if [[ -z "$number" ]]; then
|
|
echo "No pull request in event; skipping."
|
|
echo "enabled=false" >> "$GITHUB_OUTPUT"
|
|
exit 0
|
|
fi
|
|
pr_json="$(gh api "repos/${GITHUB_REPOSITORY}/pulls/${number}")"
|
|
labels="$(jq -r '[.labels[].name] | join(",")' <<<"$pr_json")"
|
|
enabled=false
|
|
if [[ ",${labels}," == *",autopilot,"* || ",${labels}," == *",automerge,"* ]]; then
|
|
enabled=true
|
|
fi
|
|
{
|
|
echo "number=$number"
|
|
echo "head_sha=$(jq -r .head.sha <<<"$pr_json")"
|
|
echo "draft=$(jq -r .draft <<<"$pr_json")"
|
|
echo "labels=$labels"
|
|
echo "enabled=$enabled"
|
|
} >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Skip unless Autopilot label is present
|
|
if: steps.pr.outputs.enabled != 'true'
|
|
run: echo "No autopilot/automerge label; skipping."
|
|
|
|
- name: Skip draft pull requests
|
|
if: steps.pr.outputs.enabled == 'true' && steps.pr.outputs.draft == 'true'
|
|
run: echo "Draft pull request; auto-merge waits for ready_for_review."
|
|
|
|
- name: Verify Product CI on head commit
|
|
id: gate
|
|
if: steps.pr.outputs.enabled == 'true' && steps.pr.outputs.draft != 'true'
|
|
env:
|
|
GH_TOKEN: ${{ github.token }}
|
|
HEAD_SHA: ${{ steps.pr.outputs.head_sha }}
|
|
run: |
|
|
set -euo pipefail
|
|
mapfile -t conclusions < <(
|
|
gh api "repos/${GITHUB_REPOSITORY}/commits/${HEAD_SHA}/check-runs" --paginate \
|
|
--jq '.check_runs[] | select(.name == "Product CI") | .conclusion'
|
|
)
|
|
if [[ "${#conclusions[@]}" -eq 0 ]]; then
|
|
echo "Product CI has not finished yet."
|
|
echo "ready=false" >> "$GITHUB_OUTPUT"
|
|
exit 0
|
|
fi
|
|
for conclusion in "${conclusions[@]}"; do
|
|
case "$conclusion" in
|
|
success)
|
|
echo "Product CI succeeded."
|
|
echo "ready=true" >> "$GITHUB_OUTPUT"
|
|
exit 0
|
|
;;
|
|
failure|cancelled|timed_out|action_required)
|
|
echo "Product CI failed ($conclusion); not enabling auto-merge."
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
echo "Product CI still pending."
|
|
echo "ready=false" >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Enable auto-merge
|
|
if: steps.pr.outputs.enabled == 'true' && steps.pr.outputs.draft != 'true' && steps.gate.outputs.ready == 'true'
|
|
env:
|
|
AUTOPILOT_MERGE_TOKEN: ${{ secrets.AUTOPILOT_MERGE_TOKEN }}
|
|
DRY_RUN: ${{ vars.AUTOPILOT_MERGE_DRY_RUN }}
|
|
PR_NUMBER: ${{ steps.pr.outputs.number }}
|
|
run: |
|
|
set -euo pipefail
|
|
if [[ "$DRY_RUN" == 'true' ]]; then
|
|
echo "AUTOPILOT_MERGE_DRY_RUN=true — would run: gh pr merge $PR_NUMBER --auto --squash"
|
|
exit 0
|
|
fi
|
|
if [[ -n "$AUTOPILOT_MERGE_TOKEN" ]]; then
|
|
export GH_TOKEN="$AUTOPILOT_MERGE_TOKEN"
|
|
echo "Using AUTOPILOT_MERGE_TOKEN."
|
|
else
|
|
export GH_TOKEN="${{ github.token }}"
|
|
echo "Using GITHUB_TOKEN. Add AUTOPILOT_MERGE_TOKEN if branch protection requires a PAT."
|
|
fi
|
|
gh pr merge "$PR_NUMBER" --repo "$GITHUB_REPOSITORY" --auto --squash
|
|
echo "Auto-merge enabled (squash). GitHub merges when branch protection allows."
|