Skip to content

T8782: Restore backport conflict workspace via label_conflicts and assignees#7

Merged
andamasov merged 3 commits into
productionfrom
claude/stoic-saha-f62fe0
May 14, 2026
Merged

T8782: Restore backport conflict workspace via label_conflicts and assignees#7
andamasov merged 3 commits into
productionfrom
claude/stoic-saha-f62fe0

Conversation

@andamasov
Copy link
Copy Markdown
Member

@andamasov andamasov commented May 14, 2026

Summary

Two-part change to the central backport configuration:

  1. Restore the in-PR workspace for backport cherry-pick conflicts (ignore_conflicts: true + label_conflicts: backport-conflict + assignees: ["{{ author }}"]).
  2. Block merge while the backport-conflict label is present via a merge_protections rule, so the conflicted PR cannot proceed to merge until the operator resolves the conflict and removes the label.

Mirrored on VyOS-Networks/mergify#5.

Why

The prior ignore_conflicts: false (set after vyos/vyos-documentation#1994#1998 / #1999 shipped literal conflict markers) stopped silent merges but eliminated the in-PR workspace. With no PR, conflict resolution had no tracking surface. This config restores the workspace AND closes the silent-merge hole by gating merge on label absence.

Backport-action defaults

Setting Effect
ignore_conflicts: true PR is created even when cherry-pick conflicts
label_conflicts: backport-conflict Distinct label (not the base-merge conflicts label) so triage can tell backport-conflict PRs apart
assignees: ["{{ author }}"] Source PR author pinged automatically

Why two distinct labels (backport-conflict vs conflicts)

label_conflicts fires only on backport (cherry-pick) conflicts. The existing Label conflicting pull requests rule (predicate: conflict) fires on base-branch merge conflicts and would NOT catch this case — cherry-pick conflict markers live in committed file content, not as unmerged paths, so the conflict attribute stays false. Two distinct labels keep triage unambiguous.

Why merge_protections and not a dequeue action

Mergify exposes dequeue as a slash command and as a commands_restrictions key, but NOT as a YAML action under pull_request_rules. merge_protections is the declarative equivalent — a PR with the label fails the success_condition label != backport-conflict and is held back from merge.

Resolution flow: assignee pushes a fix commit, removes the backport-conflict label, CI flips green, Mergify queue-merges.

Manual @Mergifyio dequeue remains available to Maintainers as an escape hatch.

Evaluation timing — partial documentation

Mergify documents that merge_protections are "safe to edit live; re-evaluations happen automatically", but does NOT explicitly state whether already-queued PRs are actively ejected when a success_condition starts failing. Two safe assumptions:

  1. A PR with the label cannot enter queue admission.
  2. A PR that gains the label while queued will fail the merge check at the next evaluation.

Whether the queued PR is ejected vs. held is TBD on first real backport conflict — the comment in the file says so explicitly.

Inheritance

Per Mergify docs, merge_protections from extends: merges across parent and child, with same-named rules in the child overriding the parent. Consumer repos can disable this rule by defining a same-named rule locally with weaker conditions.

Caveat — merge button bypass

merge_protections only governs Mergify-driven merges. A determined operator can still click GitHub's merge button if branch protection doesn't require Mergify checks. Defense-in-depth (required CI status that fails on <<<<<<< in tracked files, or branch-protection ruleset on the label) is tracked under T8850 (Cat 1 branch governance rulesets).

Related

  • Pairs with VyOS-Networks/mergify#5.
  • Rollout context: T8782 (Mergify central-config rollout master).
  • Defense-in-depth follow-up: T8850 (Cat 1 branch governance rulesets).

🤖 Generated by robots

…signees

Re-enable PR creation on backport cherry-pick conflicts (ignore_conflicts:
true) and add label_conflicts: backport-conflict + assignees: ["{{ author }}"]
so the conflicted PR is discoverable and accountable instead of silent.

The prior ignore_conflicts: false (set after vyos-documentation#1994 →
#1998/#1999 shipped conflict markers) stopped silent merges but eliminated
the workspace where conflicts could be resolved. With this config the PR
exists, carries a distinct label (backport-conflict, not the base-merge
`conflicts` label), and pings the source PR author.

The label itself does not block merge — fleet-wide enforcement (required
CI catching <<<<<<< markers, or branch-protection ruleset on the label)
is governance work tracked under T8850 Cat 1, not central config.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 14, 2026

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Central YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 5d1df0a6-5eed-4322-805a-b7034f5690ed

📥 Commits

Reviewing files that changed from the base of the PR and between 9b6a166 and 591d5d2.

📒 Files selected for processing (1)
  • .mergify.yml
🚧 Files skipped from review as they are similar to previous changes (1)
  • .mergify.yml
📜 Recent review details
🧰 Additional context used
🔍 Remote MCP

Additional relevant facts for reviewing PR #7 (concise)

  • Mergify's backport action supports these parameters: branches, assignees, ignore_conflicts (defaults to true), label_conflicts, labels, merge_conflict_style, report_mode, title. The PR's use of ignore_conflicts: true, label_conflicts: backport-conflict, and assignees: ["{{ author }}"] matches documented parameters and intent to create conflicted backport PRs and assign them to the original author. [::Context7_resolve-library-id::], [::Context7_query-docs::]

  • ignore_conflicts = true (the documented default) causes Mergify to create backport PRs even when cherry-pick conflicts occur; label_conflicts applies only when ignore_conflicts is enabled and will add the specified label to conflicted backports. This confirms the PR's design will restore an in-PR workspace and label conflicted backports. [::Context7_query-docs::]

  • merge_protections rules define activation conditions (if) and required success_conditions; when an active rule's success_conditions are not met, the Mergify Merge Protections check fails and blocks Mergify-driven merges. The PR's pattern—activate when backport-conflict label is present and require success_condition label != backport-conflict—matches the documented rule model and will prevent Mergify from merging while the label remains. Note: merge_protections only impacts Mergify-driven merges (not manual GitHub UI merges). [::Context7_query-docs::]

  • Configuration schema enforcement: Merge Protections rules require the if clause to scope the rule; missing if causes schema validation rejection. This explains the commit that added if: - label = backport-conflict (schema-compliance change without behavior change). [::Context7_query-docs::]

Sources/tools used: Context7 library lookup and Mergify docs (backport action, configuration schema, and merge_protections documentation). [::Context7_resolve-library-id::], [::Context7_query-docs::]

🔀 Multi-repo context ansible/ansible

[::ansible/ansible::]

  • No repository-level Mergify configuration or references to ".mergify" found in the tree (rg returned no .mergify.yml or "mergify" config matches). Files searched globally; nothing matching mergify-specific keys (label_conflicts, ignore_conflicts, merge_protections) was found.
  • Repository contains backport-related tooling/scripts which may interact with backport workflows:
    • hacking/backport/backport_of_line_adder.py — utilities to add "Backport of ..." lines and to detect backport PRs. [::ansible/ansible::hacking/backport/backport_of_line_adder.py]
    • hacking/backport/README.md — documentation for backport scripts. [::ansible/ansible::hacking/backport/README.md]
  • Several other mentions of "backport" in docs/tests (e.g., AGENTS.md, test/sanity files) but no automated Mergify configuration integration points discovered by text search.

Conclusion: No direct Mergify configuration or label/merge-protection consumers found; only repository-local backport helper scripts exist which are relevant to backport workflows but do not show direct integration with Mergify labels/actions from the searches above.


📝 Walkthrough

Summary by CodeRabbit

  • Chores
    • Backport conflicts are now automatically labeled and assigned to the original author for manual resolution.
    • Automatic merges are blocked while a backport-conflict label is present; merges proceed only after conflicts are resolved and the label removed.

Walkthrough

Mergify backport defaults changed to create backport PRs even on cherry-pick conflicts by committing conflict markers, auto-label conflicted PRs backport-conflict, and assign them to the original author. A new merge protection prevents Mergify-driven merges while that label exists; label removal is required to re-enable auto-merge. (see .mergify.yml edits at lines 21–74 and 169–203)

Changes

Backport Conflict Handling and Merge Protection

Layer / File(s) Summary
Backport conflict defaults
.mergify.yml (lines 21–74)
Changed defaults.actions.backport.ignore_conflicts from false to true so Mergify proceeds when cherry-pick conflicts occur (commits conflict markers). Added automatic labels: - backport-conflict and assignees: - "{{ author }}" on conflicted backport PRs.
Merge protection gate
.mergify.yml (lines 169–203)
Added merge_protections rule that prevents Mergify merges while backport-conflict label is present by requiring success_conditions: label != backport-conflict. This forces manual conflict resolution and label removal before auto-merge.

Possibly related PRs

  • vyos/mergify#1: Prior changes to backport conflict handling and labeling; this PR builds on that flow by adding merge-protection enforcement and assignee behavior.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed Title accurately describes the main change: restoring backport conflict workspace via Mergify configuration updates with label_conflicts and assignees.
Description check ✅ Passed Description is comprehensive and directly related to the changeset, explaining both the configuration updates and the rationale behind them.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch claude/stoic-saha-f62fe0

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@andamasov
Copy link
Copy Markdown
Member Author

@copilot review

Copy link
Copy Markdown

Copilot AI commented May 14, 2026

@copilot review

Here's my review of the changes in this PR:

What changed (defaults.actions.backport in .mergify.yml):

  • ignore_conflicts: falseignore_conflicts: true — backport PRs are now created even when the cherry-pick conflicts
  • Added label_conflicts: backport-conflict — applies a distinct label (separate from conflicts which fires on base-branch merge conflicts)
  • Added assignees: ["{{ author }}"] — auto-assigns the source PR author so the conflict doesn't get lost
  • Expanded the comment block to document the caveat that the label does not block merge by itself and points to T8850 for governance follow-up

Assessment — no issues found:

  1. Logic is sound. label_conflicts fires on cherry-pick (backport) conflicts; the existing Label conflicting pull requests rule fires on conflict (unmerged paths / base-branch merge conflicts). These two predicates are orthogonal, so there is no double-labeling or label collision.

  2. {{ author }} template is correct. Mergify resolves {{ author }} to the source PR author at rule-evaluation time — the right person for resolution accountability.

  3. Inheritance behavior is correct. These are defaults, so per-repo .mergify.yml files can override any of these keys locally without breakage.

  4. Operational caveat is well-documented. The comment explicitly notes the label does not prevent merge and points to T8850 for the enforcement work. This sets accurate expectations for operators relying on this config.

  5. Commit message / label format rules are untouched. No unintended side effects on the Flag T-ID format violation or commands_restrictions blocks.

One minor observation: the ignore_conflicts: true default restores the pre-incident Mergify default, so downstream repos that previously relied on ignore_conflicts: false as a safety net will want to add a required CI check (e.g., fail on <<<<<<< in tracked files) before this rolls out — as called out in the comment and T8850. No code change needed here; this is a rollout communication item.

…_protections

Add a merge_protections rule requiring `label != backport-conflict` for
merge. The backport action above auto-applies the label on cherry-pick
conflicts, so this closes the loop: the conflicted PR exists (workspace
preserved), is labeled and assigned, AND cannot be merged until the
operator pushes a resolution and removes the label manually.

Per Mergify docs, merge_protections from `extends:` merges across parent
and child with same-name override semantics; consumer repos can opt out
by defining a same-named rule locally with weaker conditions.

`dequeue` is not exposed as a YAML action under pull_request_rules — only
as a user-facing slash command and a key under commands_restrictions.
merge_protections is the declarative equivalent. Manual `@Mergifyio
dequeue` remains available to Maintainers via commands_restrictions.

Active ejection of an already-queued PR when the label arrives vs.
holding the PR indefinitely in queue is not explicitly documented by
Mergify; the comment marks this as TBD on first real backport conflict.
@andamasov
Copy link
Copy Markdown
Member Author

@copilot review

Copy link
Copy Markdown

Copilot AI commented May 14, 2026

@copilot review

Review of the current state (both commits, ab25a1a + 9b6a166):

Changes in scope

Commit 1 (ab25a1a): defaults.actions.backportignore_conflicts: true, label_conflicts: backport-conflict, assignees: ["{{ author }}"].
Commit 2 (9b6a166): New merge_protections block — success_conditions: - label != backport-conflict.


Assessment — no issues found, a few notes worth flagging:

  1. label != backport-conflict is correct Mergify syntax. For list attributes, != evaluates to true when the value is absent from the list — exactly the semantics needed here.

  2. merge_protections + ignore_conflicts loop is sound. The backport action creates the PR and applies the label; the protection holds it back from merge; the assignee resolves, removes the label; Mergify proceeds. No gaps in the flow.

  3. dequeue availability is correct. dequeue: *allowed is present under commands_restrictions, so Maintainers can issue @Mergifyio dequeue as an escape hatch for stuck/mislabeled PRs.

  4. Inheritance caveat is accurate. Per Mergify docs, merge_protections from extends: merges with per-repo rules and same-named rules in the child override the parent. Child repos can opt out by defining a same-named rule locally — documented in comments.

  5. One genuine uncertainty — queued-PR ejection behavior. The comment honestly marks it as TBD: Mergify documents that merge_protections re-evaluate automatically, but does not explicitly state whether a PR already in queue is actively ejected or just held when a success_condition starts failing. The @Mergifyio dequeue escape hatch covers this gap in practice.

  6. Merge-button bypass caveat is correct and well-scoped. merge_protections only governs Mergify-driven merges; the GitHub merge button remains an unguarded path until branch-protection rulesets are enforced per T8850. The comment is clear on this.

No blocking issues — the implementation is complete and consistent with the stated design.

@andamasov andamasov marked this pull request as ready for review May 14, 2026 21:35
Mergify schema validation rejected the prior commit with
`Field required @ root → merge_protections → item 0 → if`. The `if:`
clause scopes when the rule applies; without it the entry is invalid.

Now `if: - label = backport-conflict` so the rule applies only when the
label is present, and `success_conditions: - label != backport-conflict`
fails whenever the rule applies → merge blocked while the label is set.

No behavior change vs. intent — purely fixing schema compliance.
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
.mergify.yml (1)

195-201: Operational follow-up: automate backport-conflict removal so resolved PRs don't stay gated by forgotten labels.

The label is added automatically but only removed manually, so a maintainer who pushes a clean resolution commit but forgets the label change leaves the PR permanently blocked. The defense-in-depth piece you reference (T8850 — CI status matching <<<<<<< in tracked files) would naturally pair with a pull_request_rules toggle so the label tracks the actual file state, mirroring how conflicts is toggled by the conflict predicate above.

Not blocking — T8850 is the right home for this. Flagging so the link between the two doesn't get lost.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.mergify.yml around lines 195 - 201, Add automation to remove the
backport-conflict label when a PR no longer has merge conflicts by adding a
pull_request_rules entry that uses the existing conflict predicate (or the
conflicts predicate used elsewhere) and a toggle action targeting the
backport-conflict label; specifically, create a pull_request_rules rule that
matches when conflicts are false/absent and applies toggle: - label:
backport-conflict to remove the label, mirroring how the conflicts predicate
currently toggles other labels so resolved PRs are no longer blocked.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In @.mergify.yml:
- Around line 195-201: Add automation to remove the backport-conflict label when
a PR no longer has merge conflicts by adding a pull_request_rules entry that
uses the existing conflict predicate (or the conflicts predicate used elsewhere)
and a toggle action targeting the backport-conflict label; specifically, create
a pull_request_rules rule that matches when conflicts are false/absent and
applies toggle: - label: backport-conflict to remove the label, mirroring how
the conflicts predicate currently toggles other labels so resolved PRs are no
longer blocked.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Central YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: ad24b881-1680-4b62-ad09-81b16ef7dd5b

📥 Commits

Reviewing files that changed from the base of the PR and between 3bf4a1c and 9b6a166.

📒 Files selected for processing (1)
  • .mergify.yml
📜 Review details
🧰 Additional context used
🔍 Remote MCP

Summary of Additional Context

Based on the Mergify documentation, here are the key facts relevant to reviewing this PR:

Configuration Parameters

ignore_conflicts (backport action)

  • Controls whether backport PRs are created when cherry-pick conflicts occur
  • Default value is true, meaning PRs are created even with conflicts
  • The PR changes the default to explicitly set true to ensure a PR workspace is created for manual conflict resolution

label_conflicts (backport action)

  • Automatically labels backport PRs that have conflicts during cherry-pick
  • Only applies when ignore_conflicts is enabled
  • Used here to mark conflicted backports with the backport-conflict label for visibility and filtering

assignees (backport action)

  • Assigns the created backport PR to specified users
  • The PR uses ["{{ author }}"] to assign backports to the original PR author
  • This ensures the person who authored the original change is responsible for resolving conflicts

merge_protections rule

  • Defines conditions that must be satisfied before a PR can be merged
  • Uses success_conditions to validate rules (in this case: label != backport-conflict)
  • Only affects Mergify-driven merges, not manual merges via GitHub UI
  • The PR adds this to prevent merging conflicted backports until the label is manually removed

Key Workflow Behavior

  • When a backport cherry-pick encounters conflicts with ignore_conflicts: true and label_conflicts: backport-conflict configured, Mergify creates a PR with conflict markers visible, applies the backport-conflict label, and assigns it to the original author
  • The merge_protections rule then blocks Mergify from automatically merging such PRs while the label is present
  • Manual label removal is required before the merge_protections rule allows the PR to merge

[::Context7_resolve-library-id::], [::Context7_query-docs::]

🔀 Multi-repo context ansible/ansible

[::ansible/ansible::]

  • No repository-level Mergify configuration or references to ".mergify" found in the tree (rg returned no .mergify.yml or "mergify" config matches). Files searched globally; nothing matching mergify-specific keys (label_conflicts, ignore_conflicts, merge_protections) was found.
  • Repository contains backport-related tooling/scripts which may interact with backport workflows:
    • hacking/backport/backport_of_line_adder.py — utilities to add "Backport of ..." lines and to detect backport PRs. [::ansible/ansible::hacking/backport/backport_of_line_adder.py]
    • hacking/backport/README.md — documentation for backport scripts. [::ansible/ansible::hacking/backport/README.md]
  • Several other mentions of "backport" in docs/tests (e.g., AGENTS.md, test/sanity files) but no automated Mergify configuration integration points discovered by text search.

Conclusion: No direct Mergify configuration or label/merge-protection consumers found; only repository-local backport helper scripts exist which are relevant to backport workflows but do not show direct integration with Mergify labels/actions from the searches above.

🔇 Additional comments (1)
.mergify.yml (1)

21-74: LGTM!

Also applies to: 170-201

@andamasov andamasov merged commit 51b5b1e into production May 14, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants