From d0cba643b0afed41f0cafb75e7b7e2226b293645 Mon Sep 17 00:00:00 2001 From: Lalatendu Mohanty Date: Thu, 3 Sep 2026 18:19:23 -0400 Subject: [PATCH 1/3] fix(ci): use PR instead of direct push for feature branch sync The sync workflow failed because `new-resolver-config` is a protected branch that requires changes through pull requests. Instead of pushing directly, create a PR from an intermediary `sync/` branch. If an open sync PR already exists, update it in place. Co-Authored-By: Claude Signed-off-by: Lalatendu Mohanty --- .github/workflows/sync-feature-branch.yaml | 24 ++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/.github/workflows/sync-feature-branch.yaml b/.github/workflows/sync-feature-branch.yaml index 51a8f286e..7588f8e38 100644 --- a/.github/workflows/sync-feature-branch.yaml +++ b/.github/workflows/sync-feature-branch.yaml @@ -23,6 +23,7 @@ jobs: permissions: contents: write issues: write + pull-requests: write env: TARGET_BRANCH: ${{ inputs.target_branch || 'new-resolver-config' }} GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -61,9 +62,28 @@ jobs: echo "DELIM" >> "$GITHUB_OUTPUT" fi - - name: Push merged changes + - name: Push merged changes via PR if: steps.merge.outputs.result == 'merged' - run: git push origin "HEAD:${TARGET_BRANCH}" + run: | + SYNC_BRANCH="sync/${TARGET_BRANCH}-from-main" + git push origin "HEAD:${SYNC_BRANCH}" --force + EXISTING_PR=$(gh pr list \ + --head "$SYNC_BRANCH" \ + --base "$TARGET_BRANCH" \ + --state open \ + --json number \ + --jq '.[0].number // empty') + if [ -n "$EXISTING_PR" ]; then + echo "Updated existing sync PR #${EXISTING_PR}" + else + gh pr create \ + --head "$SYNC_BRANCH" \ + --base "$TARGET_BRANCH" \ + --title "Sync ${TARGET_BRANCH} with main" \ + --body "Automated merge of \`main\` into \`${TARGET_BRANCH}\`. + + **Workflow run:** ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" + fi - name: Close resolved sync-conflict issues if: steps.merge.outputs.result == 'merged' || steps.merge.outputs.result == 'up-to-date' From b9af6c17dd91de65015f431fd10dd9d883365dd3 Mon Sep 17 00:00:00 2001 From: Lalatendu Mohanty Date: Tue, 13 Oct 2026 15:05:38 -0400 Subject: [PATCH 2/3] fix(ci): backport main changes with Mergify Create resolver branch backports after each main PR merge using the installed Mergify app. Keep generated backports for maintainer review and manual merging, and document recovery from conflicts or missed events. Remove the superseded sync workflow and limit backports to changes after the baseline sync in #1367. Co-Authored-By: Codex Signed-off-by: Lalatendu Mohanty --- .github/workflows/sync-feature-branch.yaml | 146 --------------------- .mergify.yml | 19 +++ CONTRIBUTING.md | 31 +++++ 3 files changed, 50 insertions(+), 146 deletions(-) delete mode 100644 .github/workflows/sync-feature-branch.yaml diff --git a/.github/workflows/sync-feature-branch.yaml b/.github/workflows/sync-feature-branch.yaml deleted file mode 100644 index 7588f8e38..000000000 --- a/.github/workflows/sync-feature-branch.yaml +++ /dev/null @@ -1,146 +0,0 @@ -name: Sync feature branch with main - -on: - push: - branches: [main] - workflow_dispatch: - inputs: - target_branch: - description: "Feature branch to sync with main" - required: true - default: "new-resolver-config" - -permissions: - contents: read - -jobs: - sync-branch: - runs-on: ubuntu-latest - if: ${{ github.repository_owner == 'python-wheel-build' }} - concurrency: - group: sync-${{ inputs.target_branch || 'new-resolver-config' }} - cancel-in-progress: false - permissions: - contents: write - issues: write - pull-requests: write - env: - TARGET_BRANCH: ${{ inputs.target_branch || 'new-resolver-config' }} - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - steps: - - name: Checkout target branch - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - ref: ${{ env.TARGET_BRANCH }} - fetch-depth: 0 - persist-credentials: false - - - name: Configure git - run: | - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - gh auth setup-git - - - name: Merge main into feature branch - id: merge - run: | - git fetch origin main - BEFORE=$(git rev-parse HEAD) - if git merge origin/main --no-edit; then - AFTER=$(git rev-parse HEAD) - if [ "$BEFORE" = "$AFTER" ]; then - echo "result=up-to-date" >> "$GITHUB_OUTPUT" - else - echo "result=merged" >> "$GITHUB_OUTPUT" - fi - else - CONFLICTS=$(git diff --name-only --diff-filter=U) - git merge --abort - echo "result=conflict" >> "$GITHUB_OUTPUT" - echo "conflicts<> "$GITHUB_OUTPUT" - echo "$CONFLICTS" >> "$GITHUB_OUTPUT" - echo "DELIM" >> "$GITHUB_OUTPUT" - fi - - - name: Push merged changes via PR - if: steps.merge.outputs.result == 'merged' - run: | - SYNC_BRANCH="sync/${TARGET_BRANCH}-from-main" - git push origin "HEAD:${SYNC_BRANCH}" --force - EXISTING_PR=$(gh pr list \ - --head "$SYNC_BRANCH" \ - --base "$TARGET_BRANCH" \ - --state open \ - --json number \ - --jq '.[0].number // empty') - if [ -n "$EXISTING_PR" ]; then - echo "Updated existing sync PR #${EXISTING_PR}" - else - gh pr create \ - --head "$SYNC_BRANCH" \ - --base "$TARGET_BRANCH" \ - --title "Sync ${TARGET_BRANCH} with main" \ - --body "Automated merge of \`main\` into \`${TARGET_BRANCH}\`. - - **Workflow run:** ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" - fi - - - name: Close resolved sync-conflict issues - if: steps.merge.outputs.result == 'merged' || steps.merge.outputs.result == 'up-to-date' - run: | - EXPECTED_TITLE="Sync conflict: ${TARGET_BRANCH} cannot merge main" - gh issue list --label "sync-conflict" --state open --json number,title \ - | jq -r --arg t "$EXPECTED_TITLE" '.[] | select(.title == $t) | .number' \ - | xargs -rI{} gh issue close {} --comment "Resolved by automated sync." - - - name: Report up-to-date - if: steps.merge.outputs.result == 'up-to-date' - run: echo "Branch ${TARGET_BRANCH} is already up to date with main." - - - name: Open issue on conflict - if: steps.merge.outputs.result == 'conflict' - run: | - EXPECTED_TITLE="Sync conflict: ${TARGET_BRANCH} cannot merge main" - - EXISTING=$(gh issue list \ - --label "sync-conflict" \ - --state open \ - --json title \ - | jq --arg expected "$EXPECTED_TITLE" \ - '[.[] | select(.title == $expected)] | length') - - if [ "$EXISTING" -gt 0 ]; then - echo "An open sync-conflict issue for ${TARGET_BRANCH} already exists, skipping." - exit 0 - fi - - gh label create "sync-conflict" \ - --description "Automated sync with main hit merge conflicts" \ - --color "D93F0B" \ - --force - - gh issue create \ - --title "$EXPECTED_TITLE" \ - --label "sync-conflict" \ - --body "$(cat <2026-10-13T18:55:47Z + - head!=new-resolver-config + actions: + backport: + branches: + - new-resolver-config + ignore_conflicts: true + label_conflicts: conflicts + - name: Add CI label conditions: - or: @@ -27,6 +42,10 @@ pull_request_rules: conditions: - and: - "-draft" + # Maintainers merge resolver backports after reviewing CI and conflicts. + - or: + - base!=new-resolver-config + - -head~=^mergify/bp/new-resolver-config/ # Unit tests - check-success=unit (3.12, 1.75, ubuntu-latest) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3f9cc0050..5de313955 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -9,6 +9,7 @@ Fromager thrives on practical, well-tested contributions. This guide summarizes - [Quick Start](#quick-start) - [Coding Standards](#coding-standards) - [Testing](#testing) +- [Resolver Branch Backports](#resolver-branch-backports) - [Commit Guidelines](#commit-guidelines) - [Before Submitting](#before-submitting) - [Design Patterns Used in Fromager](#design-patterns-used-in-fromager) @@ -225,6 +226,36 @@ hatch run test:coverage-report # Coverage summary --- +## Resolver Branch Backports + +Mergify creates a backport PR into `new-resolver-config` for each PR merged into +`main` after the baseline sync in [#1367](https://github.com/python-wheel-build/fromager/pull/1367) +on 2026-10-13 at 18:55:47 UTC. The rule excludes PRs whose head branch is +`new-resolver-config`. It uses the installed Mergify GitHub App and needs no +personal token or additional workflow. + +Backport PRs link to their source and use branches named +`mergify/bp/new-resolver-config/pr-`. An authorized maintainer must review +and manually merge each backport after its applicable CI checks pass. Merge +dependent backports in the order their source PRs landed in `main`. + +Conflicting backports receive the `conflicts` label. Resolve conflicts on the +backport branch, remove the label after resolution, and wait for CI before +merging. If Mergify cannot create a backport, inspect its check on the source PR; +some PRs containing merge commits require a manually prepared backport. + +For a missing backport, first check for an existing PR, then comment +`@mergifyio backport new-resolver-config` on the merged source PR. This also covers +PRs merged between the baseline sync and activation of the rule. Direct pushes to +`main` require manual handling. + +Backports cherry-pick changes into new commits, so Git may report the feature +branch as behind `main` even after its backports have merged. Remove the rule when +the feature branch is retired. Removing it stops new backports; maintainers must +handle any PRs already open. + +--- + ## Commit Guidelines Fromager follows [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/). From 8f9057bdf5a188cd4353b2dbfd8a5940ec19303d Mon Sep 17 00:00:00 2001 From: Lalatendu Mohanty Date: Tue, 13 Oct 2026 15:11:28 -0400 Subject: [PATCH 3/3] docs: shorten resolver backport guidance Keep the baseline, maintainer review and recovery steps, and cherry-pick history caveat in three short paragraphs. Co-Authored-By: Codex Signed-off-by: Lalatendu Mohanty --- CONTRIBUTING.md | 38 +++++++++++++------------------------- 1 file changed, 13 insertions(+), 25 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5de313955..3181dd6c9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -228,31 +228,19 @@ hatch run test:coverage-report # Coverage summary ## Resolver Branch Backports -Mergify creates a backport PR into `new-resolver-config` for each PR merged into -`main` after the baseline sync in [#1367](https://github.com/python-wheel-build/fromager/pull/1367) -on 2026-10-13 at 18:55:47 UTC. The rule excludes PRs whose head branch is -`new-resolver-config`. It uses the installed Mergify GitHub App and needs no -personal token or additional workflow. - -Backport PRs link to their source and use branches named -`mergify/bp/new-resolver-config/pr-`. An authorized maintainer must review -and manually merge each backport after its applicable CI checks pass. Merge -dependent backports in the order their source PRs landed in `main`. - -Conflicting backports receive the `conflicts` label. Resolve conflicts on the -backport branch, remove the label after resolution, and wait for CI before -merging. If Mergify cannot create a backport, inspect its check on the source PR; -some PRs containing merge commits require a manually prepared backport. - -For a missing backport, first check for an existing PR, then comment -`@mergifyio backport new-resolver-config` on the merged source PR. This also covers -PRs merged between the baseline sync and activation of the rule. Direct pushes to -`main` require manual handling. - -Backports cherry-pick changes into new commits, so Git may report the feature -branch as behind `main` even after its backports have merged. Remove the rule when -the feature branch is retired. Removing it stops new backports; maintainers must -handle any PRs already open. +Mergify cherry-picks PRs merged into `main` after the +[baseline sync #1367](https://github.com/python-wheel-build/fromager/pull/1367) +into backport PRs for `new-resolver-config`, using its GitHub App without a personal +token. Maintainers review and manually merge them after applicable CI passes, +merging dependent backports in source order. + +Resolve conflicts and remove the `conflicts` label before merging. To request a +missing backport, check for an existing PR, then comment +`@mergifyio backport new-resolver-config` on the merged source PR. + +Direct pushes and unsupported merge histories need manual backports. Cherry-picks +create new commits, so Git may still report the branch as behind `main`. Remove +the backport rule when the feature branch is retired. ---