Skip to content

Pre-release flow, step 2: CI workflows (obs-release-pr, qa-fanout, obs-release rewrite) - #144

Merged
rjd15372 merged 21 commits into
mainfrom
prerelease-workflows
Oct 14, 2026
Merged

rjd15372 merged 21 commits into
mainfrom
prerelease-workflows

Conversation

@rjd15372

@rjd15372 rjd15372 commented Oct 14, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Wires the two-hop release flow (spec: docs/superpowers/specs/
2026-10-13-prerelease-project-release-flow-design.md) into CI. Follows
#142/#143 (tool side). Nothing in this PR has run against a live OBS yet;
the labs rehearsal runbook is included and is the next step.

  • obs-release-pr.yml (new): a release PR (every root/ change under
    root/*/releases/) populates per-instance pre-release OBS projects
    (<pr_rootprj>:pr-N:<product>:releases:<major>) with sync prerelease
    and runs every QA lane of the release mirrors against them. Own
    no-cancel concurrency group (obs-pr-check cancels superseded runs, and a
    cancelled populate would strand a frozen staging). workflow_dispatch
    with a PR number repopulates. resolve enforces release-only, one
    in-flight release PR per major, a non-empty release list and same-repo
    origin (populate runs with production credentials).
  • qa-fanout.yml (new, reusable): the former detect/merge/qa jobs of
    obs-pr-check, parameterised by pr_number, qa_types, ref. Check
    runs now read PR / OBS QA / … and Release / OBS QA / ….
  • obs-pr-check.yml: release PRs gated out; QA via the reusable workflow
    after build (discovery no longer overlaps the build poll).
  • obs-pr-cleanup.yml: one tag per changed release.yaml, ONE dispatch of
    obs-release.yml with pr_number + tags (only tags created here or
    already at the merge commit); no sync-main lock; the merged release PR's
    project tree is kept (it is the pre-release).
  • obs-release.yml: validate → sync release <project> --from <pre-release> per instance (own group) → GitHub releases, or a loud
    failure that keeps the pre-release → delete the pre-release per instance.
  • sync-main.yml: the release-only push skip is gone.
  • obs-stale-cleanup.yml: skips release-only PRs.
  • Tool: sync prerelease applies mirror meta with branch-root redirection
    and no branch fallbacks (branch_fallbacks=False), the record check
    includes _shared/ link targets, inherited config layers and the
    major's release.yaml, and the synced-commit lookup keys on the sync
    job's conclusion per instance instead of the whole run.
  • post_pr_comment.py: pre-release comment mode (tested renderer).
  • project release bakes EXPECTED_VERSIONS into every mirror qa: entry
    at cut time (same rules as qa show on staging; verified identical on the
    real staging:18 tree incl. containers/extras/tarballs), so release QA on
    the pre-release, which has no package directories, gets the parameter it
    requires. An entry that sets it by hand keeps its value.
  • Docs: tool reference, copilot-instructions Workflows 1-8, READMEs,
    spec §3-§5 corrected; rehearsal runbook at
    docs/superpowers/specs/2026-10-14-prerelease-rehearsal-runbook.md.

Known limits (documented)

  • GitHub keeps one pending run per concurrency group: a populate queued
    behind a sync-main upload, or back-to-back hop-2 dispatches, can be
    displaced; recovery is a re-dispatch (idempotent).
  • A merged release PR that creates no new tag, or a populate that starts
    after the PR closed, leaves a pre-release to delete by hand.

Testing

640 tests, black, pyright 0 errors, actionlint 1.7.7 clean on every
workflow. Live validation = the rehearsal runbook on labs.

Signed-off-by: Ricardo Dias <ricardo.dias@percona.com>
… root

Signed-off-by: Ricardo Dias <ricardo.dias@percona.com>
…nd on the prior release project

Signed-off-by: Ricardo Dias <ricardo.dias@percona.com>
…paths on hop 1

Signed-off-by: Ricardo Dias <ricardo.dias@percona.com>
Signed-off-by: Ricardo Dias <ricardo.dias@percona.com>
Signed-off-by: Ricardo Dias <ricardo.dias@percona.com>
…ty-release guard)

Signed-off-by: Ricardo Dias <ricardo.dias@percona.com>
Signed-off-by: Ricardo Dias <ricardo.dias@percona.com>
Signed-off-by: Ricardo Dias <ricardo.dias@percona.com>
…lock

Signed-off-by: Ricardo Dias <ricardo.dias@percona.com>
Signed-off-by: Ricardo Dias <ricardo.dias@percona.com>
Signed-off-by: Ricardo Dias <ricardo.dias@percona.com>
Signed-off-by: Ricardo Dias <ricardo.dias@percona.com>
Signed-off-by: Ricardo Dias <ricardo.dias@percona.com>
Signed-off-by: Ricardo Dias <ricardo.dias@percona.com>
…book

Signed-off-by: Ricardo Dias <ricardo.dias@percona.com>
last_synced_head_sha no longer filters on status=completed: the build
poll keeps a sync-main run in progress for hours after its upload, so a
populate would pin to the previous run's head. The new instance= keyword
restricts the check to that instance's upload leg.

_scope_local_paths adds <product>/releases/<major>/release.yaml: PPG_RELEASE
is computed from it, so after a release PR merges main's copy differs from
source_commit and a repopulate is refused.

The copy-failure test now also pins that the top-level mirror meta (which
drops the old source_commit marker) is applied before the drain.

Signed-off-by: Ricardo Dias <ricardo.dias@percona.com>
obs-release-pr: refuse fork PRs, resolve the synced commit per instance,
pass values to python -c as argv, check QA out at the PR head
(qa-fanout gains an optional ref input).
obs-pr-cleanup: re-dispatch an existing tag only when it already points
at the merge commit; an empty is_release_pr never deletes a merged
pre-release.
obs-release: own obs-release-<name> concurrency group, inputs through
env instead of script interpolation, top-level permissions: {}.
obs-stale-cleanup: skip release-only PRs (their tree is the pre-release).

Docs/spec/runbook: a deleted pre-release after merge is recovered by
cutting a new release (repopulating the merged PR is refused by the
record check); hop 2 never touches staging, hop 1 freezes it only for
the copy; runbook gains in-progress-poll and tag re-run rehearsal items.

Signed-off-by: Ricardo Dias <ricardo.dias@percona.com>
Signed-off-by: Ricardo Dias <ricardo.dias@percona.com>
Mirrors have no package directories, so qa show cannot compute the
parameter on a pre-release. Compute it from the staging project at cut
time; explicit values are kept.

Signed-off-by: Ricardo Dias <ricardo.dias@percona.com>
@rjd15372

Copy link
Copy Markdown
Collaborator Author

Added b37c1f1: project release now bakes EXPECTED_VERSIONS into every mirror qa: entry at cut time (same rules as qa show on staging; verified identical on the real staging:18 tree incl. containers/extras/tarballs), so release QA on the pre-release gets the parameter it requires. The runbook item is now a check, not a limitation.

Signed-off-by: Ricardo Dias <ricardo.dias@percona.com>
@rjd15372
rjd15372 merged commit ac455d6 into main Oct 14, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant