repomatic.init.upgrade module¶
Pick the upstream pin repomatic init writes, and move it with --upgrade.
A downstream repository runs the reusable workflows of the release its thin
callers pin. init decides that pin: the running release, held back by the
[tool.repomatic] minimum-release-age cooldown when the release is too fresh,
and never moved below the pin the repository already carries. init --upgrade
picks the newest release past the cooldown instead, runs init as that
release, and describes the move for the pull request that carries it.
This module is the only reader of the running version and of the commit SHA of its tag, so a test stages a release in one place.
- repomatic.init.upgrade.BREAKING_BULLET_RE = re.compile('^[ \\t]*[-*][ \\t]+(?P<bullet>\\*\\*(?:Breaking|Deprecated):\\*\\*.*)$', re.MULTILINE)¶
A release-notes bullet announcing a breaking change or a deprecation.
The changelog convention opens these bullets with a bold
**Breaking:**or**Deprecated:**label, and each GitHub release body repeats its changelog section verbatim. The upgrade report lifts them above the full notes, because they are the entries a repository may have to act on.
- repomatic.init.upgrade.INIT_WARNING_RE = re.compile('^[ \\t]*warning:.*$', re.IGNORECASE|re.MULTILINE)¶
A warning line in the output of
repomatic init.Matches the
warning:lines the configuration loader logs, like an unknown[tool.repomatic]key, and theWarning:lines of the closing summary.
- repomatic.init.upgrade.default_version_pin()[source]¶
Derive the default version pin from
__version__.Strips any
.dev0suffix and prefixes withv. For example,"5.10.0.dev0"becomes"v5.10.0".- Return type:
- repomatic.init.upgrade.pins_running_release(version)[source]¶
Whether the pin version names the release the running build heads for.
Compared on the release tuple, so a development build matches the release it is heading for: the pin drops the
.devNsuffix the running version carries, and string equality would never match on a dev checkout.
- repomatic.init.upgrade.github_yaml_texts(root)[source]¶
Read every workflow and composite-action file under root, once.
- Parameters:
root (
Path) – Root of the repository to scan.- Return type:
- Returns:
The text of each file
github_yaml_paths()lists, keyed by path. A file that cannot be read is skipped.
- repomatic.init.upgrade.highest_upstream_pin(texts, repo)[source]¶
The highest upstream
uses:pin the given workflow texts carry.Read off the files
github_yaml_texts()returns, the same filessync-workflow-pinsbumps. Stragglers left behind at an older pin therefore converge upward onto the repository-wide maximum, matching howsync-action-pinstreats a slug pinned at more than one version.Only repo is matched, not every slug in
UPSTREAM_REPO_SLUGS: a caller still naming a pre-rename slug is a tombstoneinitrewrites, not a pin to preserve.- Parameters:
- Return type:
- Returns:
The highest pin found, or
Nonefor a repository carrying none.
- repomatic.init.upgrade.resolve_default_pin(config, *, repo='kdeldycke/repomatic', today=None, warnings=None, floor=None)[source]¶
Resolve the upstream pin, holding a fresh release back by cooldown.
Returns the
(version, commit_sha)initstamps into thin-calleruses:refs. In the common case, and on any datasource failure, this is the running repomatic version paired with its build-time SHA. Only when adopting a release still inside the[tool.repomatic] minimum-release-agewindow does the pin step back to the newest cooldown-cleared release (see_select_cooldown_pin), resolving that tag’s SHA afresh.Important
The cooldown may hold back an adoption. It may never rewrite a pin the repository already carries, which is what floor records.
initis the only writer of these refs:sync-action-pinsskips every slug inUPSTREAM_REPO_SLUGS, andACTION_PIN_REdoes not even match a subpath-carrying reusable-workflow ref. So a downstream repository adopts a new repomatic release one way: a newerinitruns. A maintainer runs one by hand, and the CIsync-repomaticjob runs one throughinit --upgrade, which picks the release itself (seeresolve_upgrade_target()) and bypasses this function. Two things follow.A pin equal to the running version is not a decision to gate. Without a newer release to adopt, the CI
sync-repomaticjob runsinitat the pinned version itself, sobaseequals floor; re-judging it there downgrades the repository once a week after each hand-bump.A pin below the running version is a skew.
initrenders caller content from the running version, so a ref naming an older release ships that content against an older reusable-workflow surface, which GitHub rejects as soon as the two disagree (seetest_thin_caller_workflow_call_inputs_stay_minimal). Returning such a pin is therefore only half a decision:resolve_workflow_pin()reads it back and, when the repository already carries workflows, tellsinitto skip regenerating them so the tree stays coherent at the pin it keeps. A first-time adoption has no tree to keep, so there the skew stands as the only alternative to writing no workflows at all.- Parameters:
config (
Config) – Repomatic config supplying theminimum-release-agewindow.repo (
str) – Upstreamowner/repowhose releases gate the pin.today (
date|None) – Reference date for the cooldown; defaults to the current UTC date.warnings (
list[str] |None) – When provided, a cooldown note is appended here (in addition to being logged), soinitcan surface it in its final summary rather than only mid-run.floor (
UpstreamRefPin|None) – The highest upstream pin already committed downstream, fromhighest_upstream_pin().Nonefor a repository carrying none, the one case the cooldown may step back freely.
- Return type:
- Returns:
(version_pin, commit_sha).commit_shaisNonewhen no SHA can be resolved, leaving a bare tag pin.
- class repomatic.init.upgrade.WorkflowPin(version, commit_sha, adopts_content=True)[source]¶
Bases:
objectThe upstream pin
initwrites into the thin callers it generates.
- repomatic.init.upgrade.resolve_workflow_pin(config, *, version, cooldown, repo, floor, warnings)[source]¶
Resolve the pin
initwrites, and whether the workflows move with it.An explicit version keeps the build-time SHA and bypasses the cooldown. Without one, the pin derives from the running release, held back by
resolve_default_pin()when cooldown is set.A pin the cooldown held below the running version cannot carry this version’s caller content.
initrenders bodies from the running wheel and substitutes only the ref, so writing them beside an olderuses:pin ships half an adoption: the trigger blocks,concurrencygroups andenv:of the new release, against the reusable-workflow surface of the old one. Declining the pin has to decline the content with it, or the cooldown buys nothing while the caller half lands anyway, silently.Only a repository that already carries workflows (a floor) has somewhere to stand: leaving them untouched keeps a coherent tree at floor. A first-time adoption has no such fallback, since skipping would write no workflows at all, and is the one case
resolve_default_pin()documents the skew as unavoidable.- Parameters:
config (
Config) – Repomatic config supplying theminimum-release-agewindow.version (
str|None) – An explicit pin, in itsvX.Y.Ztag spelling, orNone.cooldown (
bool) – Hold a fresh running release back by the cooldown.repo (
str) – Upstreamowner/repowhose releases gate the pin.floor (
UpstreamRefPin|None) – The highest upstream pin already committed downstream.warnings (
list[str]) – Cooldown notes are appended here, for theinitsummary.
- Return type:
- class repomatic.init.upgrade.UpgradeTarget(version, released, previous=None, held_back=None)[source]¶
Bases:
objectThe release
init --upgraderuns as, chosen before any file is written.- released: str¶
PyPI upload date of
version, asYYYY-MM-DD. Empty when the datasource does not list the release pinned on disk.
- previous: str | None = None¶
Bare version of the highest upstream pin on disk before the run, or
Nonefor a repository carrying none.
- repomatic.init.upgrade.resolve_upgrade_target(config, output_dir, *, repo='kdeldycke/repomatic', today=None)[source]¶
Pick the release
init --upgraderuns as.That is the newest final, non-yanked release on PyPI older than the
[tool.repomatic] minimum-release-agewindow, and never one below the upstream pin the repository already carries: a release pinned by hand inside the window stays. PyPI is the datasource becauseuvxinstalls from it, so a version whose publication failed, with a tag but no wheel, is never picked.- Parameters:
config (
Config) – Repomatic config supplying the window and both opt-outs.output_dir (
Path) – Root of the target repository, read for its current pin.repo (
str) – Upstreamowner/repo; its name is the PyPI package.today (
date|None) – Reference date for the cooldown; defaults to the current UTC date.
- Return type:
- Returns:
The target, or
Nonewhen the upgrade does not apply: turned off byupstream-pin.syncorworkflow.sync, run from a build that is not a release, or no release has cleared the window.
- repomatic.init.upgrade.upgrade_command(version, init_args, *, config, repo='kdeldycke/repomatic', today=None)[source]¶
Build the command running
initas anotherrepomaticrelease.--no-cooldownhands the child the decisionresolve_upgrade_target()already took. Left to judge the window again, the child reads GitHub release dates where the parent read PyPI ones, and a split verdict near the limit writes the new configs but leaves the callers at the old release.The window reaches the resolution as
--exclude-newer, which gates the child’s dependency tree like any other install. The package itself carries the self-pin exemption, because it already cleared this repository’s window: with that window disabled, no cutoff is passed, and the workflow’s ownUV_EXCLUDE_NEWERwould refuse the release.- Parameters:
version (
str) – Bare version to run.init_args (
Sequence[str]) – Arguments for the childinit, after--no-cooldown.config (
Config) – Repomatic config supplying theminimum-release-agewindow.repo (
str) – Upstreamowner/repo; its name is the package and the command.today (
date|None) – Reference date for the cutoff; defaults to the current UTC date.
- Return type:
- Returns:
The command line.
- repomatic.init.upgrade.run_upgrade(command, output_dir)[source]¶
Run the
inithand-off built byupgrade_command().Runs from output_dir, where the child finds
[tool.repomatic]as the parent did. Both output streams are merged in the order they were written, then captured, becauseupgrade_report()quotes the warnings the child printed: a config key the new release no longer knows shows up nowhere else.- Parameters:
command (
Sequence[str]) – The command line fromupgrade_command().output_dir (
Path) – Root of the target repository.
- Return type:
- Returns:
The finished process, its merged output in
stdout.
- repomatic.init.upgrade.hand_off_upgrade(target, config, *, repo, output_dir, flags=())[source]¶
Run
initas the release target names, in a child process.The child gets the upstream repository and the output directory of this run, then flags: the deletion flags this run was given, so the child prunes what this run would have.
- Parameters:
target (
UpgradeTarget) – The targetresolve_upgrade_target()picked.config (
Config) – Repomatic config supplying theminimum-release-agewindow.repo (
str) – Upstreamowner/repo; its name is the package and the command.output_dir (
Path) – Root of the target repository.flags (
Sequence[str]) – Extrainitoptions for the child, likerepomatic.init.run.DeletionPolicy.flags()returns.
- Return type:
- Returns:
The finished process, its merged output in
stdout.
- repomatic.init.upgrade.upgrade_invite(previous, adopted)[source]¶
Render the invitation to review a move of the upstream pin.
Shared by every pull request that moves the pin, the
init --upgradereport and async-workflow-pinslockstep bump, so both hand over the same launcher.
- repomatic.init.upgrade.upgrade_report(target, output_dir, config, *, init_output='', repo='kdeldycke/repomatic', today=None)[source]¶
Describe the upgrade a run just applied, for its pull request body.
Reads the pin back from disk rather than trusting target, since what the run wrote is what the pull request carries. The sections, in reading order:
The version move, with its compare link and release date.
Every
**Breaking:**and**Deprecated:**bullet of the releases in between.The warnings the run printed, then its whole output, collapsed.
The release notes, one collapsed block per release.
The invitation to run the
repomatic-upgradereview.The newer release the window still holds back, if any.
- Parameters:
target (
UpgradeTarget) – The targetresolve_upgrade_target()picked.output_dir (
Path) – Root of the target repository, read for the new pin.config (
Config) – Repomatic config supplying theminimum-release-agewindow.init_output (
str) – The output of a hand-off run, empty for an in-process one.repo (
str) – Upstreamowner/repowhose releases are described.today (
date|None) – Reference date for relative dates; defaults to the current UTC date.
- Return type:
- Returns:
(adopted, markdown), orNonewhen the run moved no pin forward.