Skip to content

[FEATURE] Branching strategy Phase 2.B - release trigger and versioning docs - #557

Merged
John McCall (lowlydba) merged 47 commits into
mainfrom
533-devops-branching-strategy---phase-2b---release-versions
Aug 5, 2026
Merged

[FEATURE] Branching strategy Phase 2.B - release trigger and versioning docs#557
John McCall (lowlydba) merged 47 commits into
mainfrom
533-devops-branching-strategy---phase-2b---release-versions

Conversation

@lowlydba

@lowlydba John McCall (lowlydba) commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Summary

Phase 2.B of the branching strategy (#533): release detection on main, the changelog machinery, and the versioning docs. No publish workflows, those are Phase 3 (#509), which this unblocks.

The versioning model settled during review (thanks Victor Schappert (@vcschapp), Seth Fitzsimmons (@sethfitz)): humans own the full <major>.<minor>.<patch> per package, any bump merged to main is a release, and CI only versions the interim internal builds between releases.

What lands

Release trigger

  • release-trigger.yaml + detect_version_bumps.py: on push to main, diffs every packages/*/pyproject.toml version against the previous commit. Any increase (patch included) cuts one published GitHub Release per bumped package: tag <pkg>-v<version>, title `<pkg>` <version>, notes read from that package's CHANGELOG.md. Fails loudly on version decreases and on pre-existing tags. The umbrella overture-schema release is marked Latest.
  • Major-bump cascade guard: a package whose direct workspace dependency takes a major bump must take one itself, since the old dependency floor would admit a breaking version. Enforced at PR time by the version check and again by release-trigger. Direct-dep checking covers longer chains, each unbumped link fails its own check.
  • create-package-release composite action with a dry-run input for testing.

Changelog machinery

  • towncrier fragments per package (packages/<pkg>/changelog.d/), config centralized in the root pyproject.toml.
  • require-changelog-fragment.yaml: any PR touching a package must carry a fragment or a built CHANGELOG.md. Plain git diff + grep, no action dependencies.
  • Release PRs run towncrier build so the notes are reviewed as part of the version-bump diff.

Internal build versioning

  • compute-version reworked: no-bump merges produce <version>.postN+main.<sha> (or +vnext.<sha>). PEP 440 post-releases order after the release, so >=X.Y.Z consumers resolve the freshest internal build while ==X.Y.Z selects the clean release; local labels are rejected by public PyPI, keeping these builds internal by construction. N is a per-version sequence resolved from CodeArtifact: the first internal build of a version is .post0, later builds increment the highest published .postN.
  • Verified against uv with a local two-wheel resolution test; the one spec gotcha (> never matches post-releases) is documented.
  • main and vnext builds must not share a CodeArtifact repository (local labels don't participate in ordering, so >= consumers could resolve vnext breaking builds). vnext publishing is blocked on the dedicated dev repo in ops-team#299.

Workspace dependency floors

  • Intra-repo dependencies now follow uv's dual declaration pattern: explicit >= floors in project.dependencies alongside the [tool.uv.sources] workspace entries. Built wheels carry the floors directly, no build-time metadata rewriting. Floors are hand-maintained; the cascade guard above is the sanity net. This replaced an earlier just-in-time materialization script after review discussion.

Docs

  • docs/versioning.md: scheme, trigger x destination table, bump rules, floor maintenance, release walkthrough, pin guidance.
  • CONTRIBUTING.md: per-path release flows with gitGraphs, versioning quick reference, phase roadmap.

Bonus

  • 🧹 package_versions.py replaces the dual-checkout version diff: reads pyproject.toml blobs straight from git and derives the topological order from declared dependencies instead of a hardcoded map. The reusable check drops a checkout, two uv syncs, and Python setup on the no-change path.
  • 🧹 The change-type label check sheds its github-script JS for jq over the event payload.
  • 🔧 The legacy publish workflow syncs with --locked so it installs exactly the committed uv.lock.

Testing

Detection, cascade enforcement, release-notes extraction, floor-carrying wheel metadata, and the resolver-ordering claims are tested locally against real repo history (simulated bump, downgrade, uncascaded-major, and multi-package cases). The workflows themselves can't run until they're on main; release-trigger supports dry-run for a low-stakes first live pass. zizmor is clean on all touched workflows.

Closes #533

Detects an umbrella overture-schema major/minor bump on main and creates
a draft GitHub Release at v<major>.<minor>.0. Publishing the draft is the
only trigger for the public PyPI publish (Phase 3).

Decisions locked: patch builds stay CodeArtifact-only; release notes are
authored manually at release time; only the umbrella package bump cuts a
release.

Closes #533

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Signed-off-by: John McCall <john@overturemaps.org>
…ases

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Signed-off-by: John McCall <john@overturemaps.org>
…ft release tag

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Signed-off-by: John McCall <john@overturemaps.org>
@lowlydba
John McCall (lowlydba) marked this pull request as ready for review July 14, 2026 14:54
Copilot AI review requested due to automatic review settings July 14, 2026 14:54
@lowlydba
John McCall (lowlydba) requested a review from a team as a code owner July 14, 2026 14:54

This comment was marked as outdated.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Signed-off-by: John McCall <john@overturemaps.org>
@vcschapp

This comment has been minimized.

@vcschapp

This comment has been minimized.

@vcschapp

This comment has been minimized.

@vcschapp

This comment has been minimized.

@vcschapp

This comment has been minimized.

@vcschapp

This comment has been minimized.

@vcschapp

This comment has been minimized.

@lowlydba
John McCall (lowlydba) marked this pull request as draft July 21, 2026 18:54
…changelog

- release-trigger: detect per-package major.minor bumps on main and cut a
  published GitHub Release per package (tag `<package>-v<major>.<minor>.0`,
  notes extracted from that package's CHANGELOG.md; umbrella marked Latest)
- require-changelog-fragment: new PR check enforcing a changelog update on any
  major.minor bump (accepts a towncrier fragment or a built CHANGELOG.md)
- towncrier: centralize [tool.towncrier] in root pyproject.toml; per-package
  changelog.d/ with a DRY README that defers to docs/versioning.md (no .gitkeep)
- docs/versioning.md: Diataxis rewrite (reference/how-to/why) with a TOC
- CONTRIBUTING.md: lean guiding-light rewrite (217 -> 91 lines); richer,
  workflow-accurate gitGraphs
- publish-python-packages: add contents: read for reusable-workflow checkout

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Signed-off-by: John McCall <john@overturemaps.org>
Wrap each release path (main->patch, main->minor, vnext->major) in a
collapsible <details> section with its own workflow-accurate gitGraph.
Drop the branch-protection bullet and reduce the CI notes to authoritative
links to the vnext-compat and pr-advisory workflows, which comment their
own fix steps inline.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Signed-off-by: John McCall <john@overturemaps.org>
… a PR

Add how/when each release path reaches consumers (patch rides the next
release to PyPI via the umbrella; minor and major publish to PyPI on merge).
Reword the Opening a PR CI notes to point at the checks without narrating.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Signed-off-by: John McCall <john@overturemaps.org>
Move the inline detect heredoc and the extract_notes heredoc out of
release-trigger.yaml into .github/workflows/scripts/detect_version_bumps.py
and extract_release_notes.py, matching the existing package-versions.py
convention. The workflow steps now just invoke them, so the Python is
lint-covered, testable, and free of heredoc quoting. Behavior is unchanged.

Also vary the CONTRIBUTING release diagrams across distinct packages
(places/base/transportation themes) and note that a no-bump merge still
publishes a patch to internal CodeArtifact.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Signed-off-by: John McCall <john@overturemaps.org>
Review suggested packaging.version.parse for PEP 440 variants, but the
model only permits plain X.Y.Z in pyproject.toml, so a 1.2.3rc4 should
fail loudly rather than parse. Strict regex + explicit ValueError keeps
the scripts dependency-free and gives a better message than the int()
conversion error.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Signed-off-by: John McCall <john@overturemaps.org>
…dable commits

before/after now pair naturally in the bump loop (the commit arg is
before_commit). package_manifests emits a ::notice:: when a commit's
tree is unreadable and a ::debug:: with the git stderr, instead of
silently returning empty. Both suggested by @vcschapp in review.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Signed-off-by: John McCall <john@overturemaps.org>
detect_version_bumps.py no longer reads git at all: it is a pure filter
from the package_versions.py diff JSON (stdin) to releasable bumps
(stdout), applying the plain-semver and no-decrease policies. The
detect-version-bumps action pipes the two scripts together, so the DRY
lives at the action layer; the cross-script import and its PYTHONPATH
wiring are gone. Cascade enforcement rides the first stage's exit
status through pipefail.

Addresses the duplication flagged by @vcschapp in review.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Signed-off-by: John McCall <john@overturemaps.org>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Signed-off-by: John McCall <john@overturemaps.org>
docs/versioning.md promised that a dependency's major bump requires the
dependent to raise its declared floor, but check_major_cascade only
checked the dependent's own version. It now also fails when the floor's
major stays below the dependency's new major, closing the gap where
published metadata would still admit the old breaking-incompatible
major. Flagged by @vcschapp in review.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Signed-off-by: John McCall <john@overturemaps.org>
Suggested by @vcschapp; the old name described the event, not the
action taken.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Signed-off-by: John McCall <john@overturemaps.org>
towncrier build deletes fragments as it folds them into CHANGELOG.md;
the docs never said so, which invited an on-demand-generation reading
in review.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Signed-off-by: John McCall <john@overturemaps.org>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Signed-off-by: John McCall <john@overturemaps.org>
@sethfitz

Copy link
Copy Markdown
Collaborator

P>=1.2.3 is ignored entirely as long as there's a package in the workspace that matches by name.

John McCall (John McCall (@lowlydba)) and I just met on this topic. The tl;dr is:

  • We acknowledge it's a real issue.
  • The solution is a bit complex.
  • We're recommending to go forward and finish this phase without solving it, and let our experience with the system in the wild tell us how important it is to add guardrails. In other words, defer for now; if needed fix later.

Seth Fitzsimmons (Seth Fitzsimmons (@sethfitz)) What are your thoughts on the above?

Works for me. I don't want to overthink it (yet), but did want to flag the behavioral side-effect to using intra-repo dependency specifiers (which, even if we have to do crazy things to enforce them, seem like a net positive).

Pins the changelog tool the release process depends on instead of
pulling latest via uvx at each invocation; all documented invocations
become uv run towncrier. Suggested by @sethfitz in review.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Signed-off-by: John McCall <john@overturemaps.org>
Umbrella overture-schema releases now also create a bare v<version>
vanity git tag at the release commit, with no second GitHub Release
attached (the secondary release provides nothing of value). The bare
series is the convention consumers of the primary entrypoint already
know. Collisions on the vanity tag warn rather than failing the
already-published release. Consensus from review with @sethfitz and
@vcschapp.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Signed-off-by: John McCall <john@overturemaps.org>

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Found two little tiny documentation things to tweak (two lines).

Everything else looks absolutely stellar.

Comment thread pyproject.toml Outdated
Comment thread docs/versioning.md Outdated
towncrier only discovers a version from its config file (version or
package key), and the shared root config deliberately has neither, so
--version is mandatory in our setup (verified: omitting it errors).
Also drops the towncrier command from the contributor-facing
CONTRIBUTING bullet, folding fragments is a release-time step, not part
of a normal PR. Plus the .0 -> .<patch> nit in the root config comment.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Signed-off-by: John McCall <john@overturemaps.org>
@lowlydba
John McCall (lowlydba) merged commit 02d5538 into main Aug 5, 2026
34 checks passed
@lowlydba
John McCall (lowlydba) deleted the 533-devops-branching-strategy---phase-2b---release-versions branch August 5, 2026 15:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Devops] Branching Strategy - Phase 2.B - Release Versions

5 participants