Skip to content

Commit 010569d

Browse files
committed
feat(ci): auto forward-port v5 merge-train PRs to next
## Problem `next` was cut from a reshaped snapshot of `v5-next`, so the daily whole-branch merge (`port-v5-next-to-next.yml`) fights ~300 byte-level false conflicts against `next`'s reshaped history and never converges. Genuinely-new v5 work is a small, recent set, but it drowns in that noise. ## Change Replace the whole-branch merge with per-PR forward-porting, reusing the existing `port-to-next` → `backport.yml` → `port-to-next-staging` pipeline: - **`auto-port-v5-merge-trains.yml`** (new): on open, label every PR into a `merge-train/*-v5` branch with `port-to-next`, so `backport.yml` cherry-picks it individually when it merges. Opt out by removing the label before merge. - **`backport_to_staging.sh`**: skip empty cherry-picks (change already in `next` — e.g. a next→release backport bounced back) instead of reporting a false conflict; and when the target is `next`, skip release-line artifacts (release bumps, per-release upgrade/deploy scripts, regenerated fixtures, v5-merge plumbing). - **`port-v5-next-to-next.yml`**: disable the superseded daily schedule; keep `workflow_dispatch` as a manual drift-check. Individual-PR granularity keeps each conflict small (one PR against `next`, resolved by the existing ClaudeBox path) instead of one unreviewable 300-file blob. New release lines need their train pattern added to the labeler (e.g. `merge-train/*-v6`).
1 parent eade347 commit 010569d

4 files changed

Lines changed: 89 additions & 14 deletions

File tree

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
name: Auto-label v5 merge-train PRs for forward-port
2+
3+
# Forward-port every PR that lands in a v5 merge-train to public `next` by
4+
# default. We add the `port-to-next` label when the PR opens; backport.yml acts
5+
# on it when the PR merges, cherry-picking that single PR onto port-to-next-
6+
# staging (individual granularity keeps conflicts small). Labelling on open makes
7+
# the intent visible for the PR's whole life and leaves an opt-out window: remove
8+
# `port-to-next` before merge for v5-only work such as release-line artifacts.
9+
#
10+
# New release lines need their train pattern added below (e.g. merge-train/*-v6).
11+
on:
12+
pull_request_target:
13+
types: [opened]
14+
branches:
15+
- 'merge-train/*-v5'
16+
17+
jobs:
18+
label:
19+
name: Add port-to-next label
20+
runs-on: ubuntu-latest
21+
steps:
22+
- name: Add port-to-next label
23+
env:
24+
GH_TOKEN: ${{ secrets.AZTEC_BOT_GITHUB_TOKEN }}
25+
run: gh pr edit ${{ github.event.pull_request.number }} --repo ${{ github.repository }} --add-label port-to-next

.github/workflows/backport.yml

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,25 @@ jobs:
99
name: Check labels
1010
runs-on: ubuntu-latest
1111
outputs:
12-
state: ${{ steps.check.outputs.label_check }}
12+
state: ${{ steps.check.outputs.state }}
1313
steps:
14+
# The agilepathway label-checker action only supports a single prefix in
15+
# prefix_mode, so `any_of: backport-to-,port-to-next` errored out and the
16+
# gate never opened (silently breaking both backports and forward-ports).
17+
# Check the prefixes directly instead.
1418
- id: check
15-
uses: agilepathway/label-checker@825944377ab3bce1269b38c99b718767e2ca6bbc
16-
with:
17-
prefix_mode: true
18-
any_of: backport-to-,port-to-next
19-
repo_token: ${{ secrets.AZTEC_BOT_GITHUB_TOKEN }}
20-
allow_failure: true
21-
- name: Print status
2219
shell: bash
23-
run: 'echo "Label detection status: ${{ steps.check.outputs.label_check }}"'
20+
env:
21+
LABELS_JSON: ${{ toJson(github.event.pull_request.labels.*.name) }}
22+
run: |
23+
echo "Labels: $LABELS_JSON"
24+
if echo "$LABELS_JSON" | jq -e 'any(.[]; startswith("backport-to-") or startswith("port-to-next"))' >/dev/null; then
25+
echo "Label detection status: success"
26+
echo "state=success" >> "$GITHUB_OUTPUT"
27+
else
28+
echo "Label detection status: failure"
29+
echo "state=failure" >> "$GITHUB_OUTPUT"
30+
fi
2431
2532
backport:
2633
needs: [label_checker]

.github/workflows/port-v5-next-to-next.yml

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
name: Port v5-next to next
22

3-
# Daily forward-port: accumulate everything new from `v5-next` onto the
3+
# Whole-branch forward-port: accumulate everything new from `v5-next` onto the
44
# long-lived `port-v5-next-to-next` branch (merging `next` and `v5-next` into
55
# it) and open/update one large PR against `next`. See scripts/port_to_next.sh.
6-
6+
#
7+
# SUPERSEDED by per-PR forward-porting (auto-port-v5-merge-trains.yml applies the
8+
# `port-to-next` label to each v5 merge-train PR; backport.yml ports it). Because
9+
# `next` was cut from a reshaped snapshot of `v5-next`, a whole-branch merge fights
10+
# ~300 byte-level false conflicts and never converges. The daily schedule is
11+
# therefore disabled; kept for manual `workflow_dispatch` as an occasional
12+
# drift-check (its conflicted PR shows what the per-PR path may have missed).
713
on:
8-
schedule:
9-
# Daily at 06:30 UTC.
10-
- cron: "30 6 * * *"
1114
workflow_dispatch:
1215
inputs:
1316
source_branch:

scripts/backport_to_staging.sh

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,37 @@ if [[ $CONTINUE_MODE -eq 0 ]]; then
149149
echo "Merge commit: $MERGE_COMMIT"
150150
git fetch origin "$MERGE_COMMIT"
151151

152+
# When forward-porting into next, skip release-line artifacts that are
153+
# meaningless on the mainline: release-version bumps, per-release upgrade/deploy
154+
# scripts, regenerated-fixture refreshes, and the plumbing commits a release
155+
# line creates when it merges its own public snapshot. A PR is skipped only when
156+
# its subject marks it as such, or every file it touches is an artifact path.
157+
if [[ "$TARGET_BRANCH" == "next" ]]; then
158+
EXCLUDE_SUBJECTS='^chore\(release\)|regenerate pinned|re-pin standard contracts|regenerate standard-contract|resolve v[0-9]+ -> v[0-9]+-next|public-v[0-9]+-next merge|refresh pinned'
159+
EXCLUDE_GLOBS=('l1-contracts/src/periphery/V*UpgradePayload*' 'l1-contracts/script/deploy/DeployRollupForUpgrade*' 'l1-contracts/*/V*_UPGRADE_RUNBOOK.md' '.github/workflows/*-v*-next.yml')
160+
MERGE_SUBJECT=$(git show -s --format=%s "$MERGE_COMMIT")
161+
SKIP_ARTIFACT=0
162+
if [[ "$MERGE_SUBJECT" =~ $EXCLUDE_SUBJECTS ]]; then
163+
SKIP_ARTIFACT=1
164+
else
165+
ALL_EXCLUDED=1
166+
while IFS= read -r f; do
167+
[[ -z "$f" ]] && continue
168+
matched=0
169+
for g in "${EXCLUDE_GLOBS[@]}"; do
170+
# shellcheck disable=SC2254
171+
case "$f" in $g) matched=1; break ;; esac
172+
done
173+
[[ $matched -eq 0 ]] && { ALL_EXCLUDED=0; break; }
174+
done < <(git diff --no-renames --name-only "${MERGE_COMMIT}^1" "$MERGE_COMMIT")
175+
[[ $ALL_EXCLUDED -eq 1 ]] && SKIP_ARTIFACT=1
176+
fi
177+
if [[ $SKIP_ARTIFACT -eq 1 ]]; then
178+
echo "Skipping PR #$PR_NUMBER: release-line artifact, not forward-ported to $TARGET_BRANCH."
179+
exit 0
180+
fi
181+
fi
182+
152183
# Detect if merge commit has multiple parents (merge commit vs squash commit)
153184
PARENT_COUNT=$(git rev-list --parents -n 1 "$MERGE_COMMIT" | wc -w)
154185
# First word is the commit itself, remaining are parents
@@ -161,6 +192,15 @@ if [[ $CONTINUE_MODE -eq 0 ]]; then
161192

162193
echo "Cherry-picking $MERGE_COMMIT..."
163194
if ! git cherry-pick $CHERRY_PICK_ARGS "$MERGE_COMMIT" --no-edit; then
195+
# No unmerged paths means the patch applied to nothing: the change is already
196+
# present in the target (e.g. a fix that also reached next independently, or
197+
# a next->release backport bounced back). Skip it quietly instead of treating
198+
# it as a conflict, so auto-forward-porting does not raise false alarms.
199+
if [[ -z "$(git diff --name-only --diff-filter=U)" ]]; then
200+
git cherry-pick --skip >/dev/null 2>&1 || git reset --hard >/dev/null
201+
echo "PR #$PR_NUMBER is already present in $TARGET_BRANCH; nothing to port."
202+
exit 0
203+
fi
164204
git cherry-pick --abort 2>/dev/null || true
165205
echo "Error: Failed to cherry-pick. Fix conflicts manually, then run: ./scripts/backport_to_staging.sh --continue $PR_NUMBER $TARGET_BRANCH" >&2
166206
exit 1

0 commit comments

Comments
 (0)