feat(buds): per-BUD branch override for UAT / PROD tabs - #194
Merged
Conversation
Lets a BUD opt out of the repo-wide tracking branch and watch its own
pattern instead. Release-train BUDs whose PRs target ``release/*`` can
be tracked without retraining the global repo setting; one-off ad-hoc
release branches can be pointed at directly.
Backend
- New ``branch_overrides`` JSONB column on ``bud_documents``, keyed by
stage (``uat`` / ``prod``) with fnmatch-style values.
- ``BUDUpdate`` accepts ``branch_overrides`` and ``impacted_repos`` on
PATCH. The validator rejects unknown stage keys, empty / whitespace
patterns, and the wrong case (``"UAT"`` / ``"production"``) — typos
surface as 422 at the API edge instead of silently missing in the
filter.
- PATCH handler MERGES branch_overrides per-key so saving a UAT
override doesn't clobber an existing prod override; ``{"uat": null}``
is the clear-this-stage signal and drops the key from the merged
column. Sending ``branch_overrides: null`` wipes both stages.
- ``bud_prs.py::release_stage`` honors ``bud.branch_overrides[stage]``
before falling back to ``repo.uat_branch`` / ``repo.main_branch``.
Reuses the existing ``branch_matches()`` fnmatch utility so wildcard
semantics stay consistent with release detection.
- Editing ``impacted_repos`` after the planning phase logs
``bud_impacted_repos_edited_post_planning`` so an operator can audit
scope changes that may leave PR rows linked to repos that no longer
appear on the stage tab.
Frontend
- New ``BUDStageBranchOverride.vue`` widget rendered inside the shared
``BUDReleaseStagePanel.vue``. Shows the currently-effective pattern
(override or repo default), an Edit affordance opening an inline
dialog, and — for multi-repo BUDs — a one-line "applies to N repos"
disclosure so the per-stage scope is explicit before saving.
- Save → PATCH ``/v1/buds/{id}`` with ``branch_overrides``; on success
the panel re-fetches its stage data and emits ``refresh-bud`` so
``BUDDetail`` pulls the new override into the props feed.
- Empty input on Save and the dedicated Clear button both send
``{[stage]: null}`` — the merge-aware handler drops just that key.
Schema validator covered by 16 new parametrized tests.
Signed-off-by: Arun Rajkumar <mickyarunr@gmail.com>
6 tasks
The override widget previously described only the fnmatch half of the
filter ("Open PRs are matched against this pattern on each impacted
repo. Supports fnmatch wildcards"). After the over-match fix added the
content guard that requires PRs to also reference the BUD by number,
that copy understated what surfaces a PR on a release-stage tab.
Rewrites the in-card hint and the dialog body so both rules are
visible. The example is now per-BUD: BUD-4 sees
``release/bud-001-bud-004``, BUD-12 sees ``release/bud-001-bud-012``.
Threads ``bud_number`` from BUDDetail → BUDReleaseStagePanel → the
override widget so the copy renders the actual reference, not a
placeholder.
Signed-off-by: Arun Rajkumar <mickyarunr@gmail.com>
The validator hardcoded ``{"uat", "prod"}`` next to a comment that
already pointed at the existing ``Literal["uat", "prod"]`` in
``app.schemas.bud_release``. Drop the duplicate and source the
allowed-keys set from ``get_args(ReleaseStage)`` so adding a new
release-stage tab in one place automatically widens the override
contract — no second edit needed, no drift possible.
Behaviour and tests unchanged (16 cases pass).
Signed-off-by: Arun Rajkumar <mickyarunr@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Lets a BUD opt out of the repo-wide tracking branch and watch its own pattern instead. Useful for release-train BUDs whose PRs target
release/*and one-off ad-hoc release branches that don't belong in the global repo setting.Builds on top of #193 (PR 1). Without #193's broadened resolver + three-way query predicate the over-matching bug returns the moment you set any override — both PRs are needed for the full fix.
What changed
Backend
branch_overridesJSONB column onbud_documentskeyed by stage (uat/prod) with fnmatch-style values. Migration is autogenerated, nullable, no backfill needed.BUDUpdateacceptsbranch_overridesandimpacted_reposon PATCH. The validator rejects unknown stage keys (UAT,production,code_review), empty / whitespace patterns, and non-string values — typos surface as 422 at the API edge instead of fnmatching nothing.branch_overridesper-key so saving a UAT override doesn't clobber an existing prod override.{stage: null}drops just that key;branch_overrides: nullwipes both.bud_prs.py::release_stagehonorsbud.branch_overrides[stage]before falling back torepo.uat_branch/repo.main_branch. Reuses the existingbranch_matches()fnmatch utility — wildcard semantics stay consistent with release detection.impacted_reposafter the planning phase logsbud_impacted_repos_edited_post_planningso post-deploy auditing of scope changes is possible.Frontend
BUDStageBranchOverride.vuewidget rendered inside the sharedBUDReleaseStagePanel.vue. Shows the currently-effective pattern (override or repo default), an Edit affordance opening an inline dialog, and — for multi-repo BUDs — a one-lineapplies to N reposdisclosure so the per-stage scope is explicit before saving./v1/buds/{id}withbranch_overrides; the panel re-fetches its stage data on success and emitsrefresh-budsoBUDDetailpulls the new override into the prop feed.{[stage]: null}— the merge-aware handler drops just that key, leaving the sibling stage untouched.Test plan
cd backend && pytest tests/schemas/test_bud_branch_overrides.py -q— 16 cases pass (accept valid stage keys + clear signal; reject unknown keys, wrong case, empty / whitespace, non-string).vue-tsc --noEmitclean.release/*→ save. Confirm the PRs targetingrelease/2026-08-01start appearing.main_branch." "— confirm the 422must be a non-empty pattern or nullsurfaces inline.Notes
release/*) that matches all of them; the dialog explicitly tells the user this on multi-repo BUDs.(bud.branch_overrides or {}).get(stage)so the absence is the silent fallback path.