diff --git a/.github/README.md b/.github/README.md new file mode 100644 index 000000000000..215f5dfd0b98 --- /dev/null +++ b/.github/README.md @@ -0,0 +1,47 @@ +# v4-next Branch + +`v4-next` is a forward-looking branch that builds on top of `v4`. It contains everything in `v4` plus additional features and changes that are staged for the next v4 release cycle. + +## How it works + +### Branch relationship + +``` +next (v5 development) + │ + v4 ──────────────► v4-next + (stable v4 releases) (next v4 features) +``` + +- `v4-next` is branched off `v4` and stays up to date with it automatically. +- Changes merged to `v4` flow into `v4-next` on every merge via the `pull-v4-into-v4-next` workflow. +- If a merge conflict occurs, a PR is automatically created for manual resolution. + +### Getting changes into v4-next + +There are three ways to land code in `v4-next`: + +1. **Via v4**: Any PR merged to `v4` is automatically pulled into `v4-next`. +2. **Backport from next**: Add the `backport-to-v4-next` label to a PR targeting `next`. On merge, the backport workflow will cherry-pick the changes into `v4-next` via a staging branch. +3. **Direct PR**: Open a PR directly targeting `v4-next` for changes that are only relevant to the next release. + +### Nightly releases + +Every night at 5:00 AM UTC, `nightly-release-tag-v4-next.yml` creates a tag from `v4-next` in the format `v{version}-nightly.{date}`. This mirrors the nightly release process on `next`. + +### Backports + +The existing backport infrastructure (`backport.yml`) works with `v4-next` out of the box: + +- Label a PR with `backport-to-v4-next` to backport it. +- On merge, the changes are cherry-picked onto a `backport-to-v4-next-staging` branch. +- If cherry-pick fails, ClaudeBox is dispatched to resolve conflicts automatically. +- A staging PR accumulates backported commits targeting `v4-next`. + +### Automation summary + +| Workflow | Trigger | Action | +|---|---|---| +| `pull-v4-into-v4-next.yml` | Push to `v4` | Merges `v4` into `v4-next`; creates conflict PR if needed | +| `nightly-release-tag-v4-next.yml` | Daily at 05:00 UTC | Tags `v4-next` with `v{version}-nightly.{date}` | +| `backport.yml` | `backport-to-v4-next` label + PR merge | Cherry-picks into `v4-next` via staging branch | diff --git a/.github/workflows/nightly-release-tag-v4-next.yml b/.github/workflows/nightly-release-tag-v4-next.yml new file mode 100644 index 000000000000..66fa5f862986 --- /dev/null +++ b/.github/workflows/nightly-release-tag-v4-next.yml @@ -0,0 +1,32 @@ +name: Nightly Release Tag (v4-next) +on: + schedule: + # Run the workflow every night at 5:00 AM UTC. + - cron: "0 5 * * *" + workflow_dispatch: {} + +permissions: + contents: write + +concurrency: + group: ${{ github.workflow }}-v4-next + +jobs: + nightly-release-tag-v4-next: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + ref: v4-next + token: ${{ secrets.AZTEC_BOT_GITHUB_TOKEN }} + + - name: Create v4-next Nightly Tag + run: | + git config --global user.email "tech@aztecprotocol.com" + git config --global user.name "AztecBot" + current_version=$(jq -r '."."' .release-please-manifest.json) + echo "Current version: $current_version" + nightly_tag="v${current_version}-nightly.$(date -u +%Y%m%d)" + echo "v4-next nightly tag: $nightly_tag" + git tag -a "$nightly_tag" -m "$nightly_tag" + git push origin "$nightly_tag" diff --git a/.github/workflows/pull-v4-into-v4-next.yml b/.github/workflows/pull-v4-into-v4-next.yml new file mode 100644 index 000000000000..9d6d284ab05f --- /dev/null +++ b/.github/workflows/pull-v4-into-v4-next.yml @@ -0,0 +1,95 @@ +name: Pull v4 into v4-next + +on: + push: + branches: + - v4 + +permissions: + contents: write + pull-requests: write + +jobs: + pull-v4-into-v4-next: + runs-on: ubuntu-latest + steps: + - name: Checkout v4-next + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + ref: v4-next + fetch-depth: 0 + token: ${{ secrets.AZTEC_BOT_GITHUB_TOKEN }} + + - name: Configure Git + run: | + git config user.name "AztecBot" + git config user.email "tech@aztecprotocol.com" + + - name: Attempt to merge v4 into v4-next + id: merge + run: | + git fetch origin v4 + if git merge origin/v4 --no-edit; then + echo "conflict=false" >> $GITHUB_OUTPUT + echo "Merge succeeded without conflicts." + else + git merge --abort + echo "conflict=true" >> $GITHUB_OUTPUT + echo "Merge has conflicts." + fi + + - name: Push merged v4-next + if: steps.merge.outputs.conflict == 'false' + run: git push origin v4-next + + - name: Create conflict-resolution PR + if: steps.merge.outputs.conflict == 'true' + id: conflict-pr + env: + GH_TOKEN: ${{ secrets.AZTEC_BOT_GITHUB_TOKEN }} + run: | + SYNC_BRANCH="sync/v4-into-v4-next-$(date -u +%Y%m%d-%H%M%S)" + git merge --abort 2>/dev/null || true + git checkout -b "$SYNC_BRANCH" + + # Merge with conflicts left in place + git merge origin/v4 --no-commit --no-ff || true + git add -A + git commit -m "chore: merge v4 into v4-next (conflicts need resolution)" || true + git push origin "$SYNC_BRANCH" + + # Check if there's already an open sync PR by branch naming convention + EXISTING_PR=$(gh pr list --base v4-next --state open --json number,headRefName --jq '[.[] | select(.headRefName | startswith("sync/v4-into-v4-next-"))][0].number // empty') + + if [ -n "$EXISTING_PR" ]; then + gh pr comment "$EXISTING_PR" --body "New v4 changes pushed. A fresh sync branch \`$SYNC_BRANCH\` has been created. Please resolve conflicts there or close this PR and use the new branch." + echo "pr_url=$(gh pr view "$EXISTING_PR" --json url --jq '.url')" >> $GITHUB_OUTPUT + else + PR_URL=$(gh pr create \ + --base v4-next \ + --head "$SYNC_BRANCH" \ + --title "chore: merge v4 into v4-next (resolve conflicts)" \ + --body "$(cat <<'EOF' +## Automatic v4 → v4-next sync + +This PR was created because merging `v4` into `v4-next` resulted in conflicts. + +Please resolve the conflicts and merge this PR to keep `v4-next` up to date. + +This PR was auto-generated by the `pull-v4-into-v4-next` workflow. +EOF + )") + echo "pr_url=$PR_URL" >> $GITHUB_OUTPUT + fi + + - name: Notify Slack + if: steps.merge.outputs.conflict == 'true' + env: + SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }} + run: | + PR_URL="${{ steps.conflict-pr.outputs.pr_url }}" + TEXT=$(printf '⚠️ Auto-merge v4 → v4-next failed due to conflicts. <%s|View PR>. @Claudebox' "$PR_URL") + curl -sS -X POST https://slack.com/api/chat.postMessage \ + -H "Authorization: Bearer $SLACK_BOT_TOKEN" \ + -H "Content-type: application/json" \ + -d "$(jq -n --arg c "#backports" --arg t "$TEXT" '{channel:$c, text:$t}')"