repomatic.setup_guide module¶
Build and manage the setup guide issue.
Backs the setup-guide command: composes the repository-settings checks from
repomatic.lint_repo and the PAT permission probes from
repomatic.github.token with the setup-guide-* templates into a single
issue body, then drives the issue lifecycle. Each setup step renders as a
collapsible section whose open/closed state and emoji reflect the check
outcome, and the issue closes only once every verifiable step passes.
- repomatic.setup_guide.CANNOT_VERIFY = '\n\n> ℹ️ **Note**: This setting could not be verified: `REPOMATIC_PAT` is missing the **Administration: Read-only** permission. Update the token with the pre-filled link in the first step.'¶
Note appended to a step whose probe could not run.
Both settings it covers are read through Administration-scoped endpoints, so a PAT issued without that permission answers
403and the check lands onNone. Saying so in the step beats dropping it: dropping also hid the token gap itself, since the missing permission had no other symptom.
- class repomatic.setup_guide.GuideContext(config, repo, has_pat, has_notifications_pat, has_virustotal_key, has_cloudflare_api_token, has_cloudflare_r2_keys)[source]¶
Bases:
objectEverything the steps read, resolved once per run.
The expensive lookups (PAT permission probes,
pyproject.toml) are cached properties, so a step that never asks never pays and two steps asking the same question share one answer.- has_cloudflare_r2_keys: bool¶
Whether
CLOUDFLARE_R2_ACCESS_KEY_IDandCLOUDFLARE_R2_SECRET_ACCESS_KEYare both configured.
- property pypi_package_name: str | None[source]¶
The PyPI name to register a Trusted Publisher for, if any.
Gated on
is_python_packagerather than onpackage_namebeing set: a uv virtual project declares[project] namepurely to carry dependencies, so the name alone says nothing about whether anything is ever published. Asking those projects to register a publisher points them at a PyPI name they do not own, for a workflow file they do not have.
- property pat_results: PatPermissionResults | None[source]¶
The PAT permission probe results, or
Nonewhen unrunnable.
- property missing_permissions_section: str[source]¶
Warning table naming the permissions the configured PAT lacks.
- property pat_scope: CheckResult | None[source]¶
The PAT repository-scope probe result, or
Nonewhen unrunnable.
- property scope_warning: str¶
Warning naming another repository the configured PAT covers.
Empty unless the probe failed. A probe that could not conclude answers
None, and the reader has nothing to act on then: the token step stays closed, as it does for a pass.
- property token_ok: bool¶
Whether a PAT is configured, permitted and limited to this repository.
The token step asks for this repository and nothing else, so a token that the scope probe finds on another repository has not done that step.
- property cloudflare_secrets_ok: bool¶
Whether the Cloudflare Pages deploy can authenticate.
The token alone settles it: the account it belongs to is derived from it at run time, even when it is scoped to nothing but
Cloudflare Pages: Edit, so there is no second identifier to configure and nothing else to ask for here.
- property cloudflare_token_name: str¶
Suggested name for the deploy token, carrying the month it was made.
Cloudflare’s token list shows what a token can do and never how old it is, while the rotation procedure turns entirely on telling the incumbent from its replacement. Stamping the month into the name is what makes a token approaching its one-year expiry obvious at a glance, and what lets the two coexist unambiguously during a handover.
Recomputed per run, so the name the guide suggests stays current while the step is still open. It stops moving once the issue closes, which is the point at which the body is no longer rewritten.
- property cloudflare_r2_token_name: str¶
Suggested name for the R2 upload token, dated for the same reason as
cloudflare_token_name: it carries the same one-year expiry.
- deploys_to(target)[source]¶
Whether this repository publishes its site to target.
One host’s setup step is the other’s noise, and the guide asks about exactly the one
site.deploynames: a Cloudflare-hosted project has no GitHub Pages source to set, and the probe for it answers404forever. Routes throughrepomatic.config.deploys_to(), the same predicate thelint-repoaudit reads.- Return type:
- property dependabot_ok: bool¶
Whether vulnerability alerts are confirmed enabled.
Piggybacks the Dependabot alerts permission probe, which only answers
200when the alerts themselves are on.
- class repomatic.setup_guide.SetupStep(placeholder, title, template, probe=<function SetupStep.<lambda>>, applies=<function SetupStep.<lambda>>, args=<function SetupStep.<lambda>>, gates_closure=True, tolerates_unknown=False, explains_unverifiable=False)[source]¶
Bases:
objectOne step of the setup guide, declared once and read by every phase.
The guide used to spell each step out four times: a probe, a render, a template keyword and a clause of the close gate. Keeping the four in sync was manual, and the applicability guards were duplicated between the probe and the render. One entry per step now drives all four.
- probe()¶
Read the step’s completion state.
Tri-state, per
CheckResult.
- applies()¶
Whether this repository needs the step at all.
A step that does not apply renders nothing and satisfies its gate, so a non-Sphinx project is never asked about Pages.
- args()¶
Template variables, defaulting to the pair almost every step wants.
- gates_closure: bool = True¶
Whether this step’s outcome can hold the issue open.
Falsefor the two steps with nothing to probe (immutable releases, the final verification), which would otherwise wedge the issue open forever.
- tolerates_unknown: bool = False¶
Whether an indeterminate probe (
None) satisfies the gate.Truefor the settings read through Administration-scoped endpoints: a PAT without that permission answers403, and a reader has no way to satisfy a check that cannot run, so it must not block the issue closing. Everywhere elseNoneis treated as incomplete, keeping the step prompting.
- explains_unverifiable: bool = False¶
Append
CANNOT_VERIFYto the body when the probe answeredNone.The reader is looking at a setting they were told to configure, so the difference between “verified” and “nobody could look” belongs on screen.
- outcome(ctx)[source]¶
The step’s state as the section renders it.
Nonesurvives only wheretolerates_unknownsays an unreadable probe is not the reader’s fault; elsewhere it collapses to incomplete so the section stays open.
- repomatic.setup_guide.SETUP_STEPS: tuple[SetupStep, ...] = (SetupStep(placeholder='step_token', title='Create and configure the token', template='setup-guide-token', probe=<function <lambda>>, applies=<function SetupStep.<lambda>>, args=<function <lambda>>, gates_closure=True, tolerates_unknown=False, explains_unverifiable=False), SetupStep(placeholder='step_dependabot', title='Configure Dependabot settings', template='setup-guide-dependabot', probe=<function <lambda>>, applies=<function SetupStep.<lambda>>, args=<function SetupStep.<lambda>>, gates_closure=True, tolerates_unknown=False, explains_unverifiable=False), SetupStep(placeholder='immutable_releases_step', title='Enable immutable releases', template='immutable-releases', probe=<function <lambda>>, applies=<function <lambda>>, args=<function <lambda>>, gates_closure=False, tolerates_unknown=True, explains_unverifiable=False), SetupStep(placeholder='step_branch_ruleset', title='Protect the main branch', template='setup-guide-branch-ruleset', probe=<function <lambda>>, applies=<function SetupStep.<lambda>>, args=<function <lambda>>, gates_closure=True, tolerates_unknown=False, explains_unverifiable=False), SetupStep(placeholder='step_fork_pr_approval', title='Require approval for fork PR workflows', template='setup-guide-fork-pr-approval', probe=<function <lambda>>, applies=<function SetupStep.<lambda>>, args=<function SetupStep.<lambda>>, gates_closure=True, tolerates_unknown=True, explains_unverifiable=True), SetupStep(placeholder='step_sha_pinning_required', title='Require SHA pinning for GitHub Actions', template='setup-guide-sha-pinning-required', probe=<function <lambda>>, applies=<function SetupStep.<lambda>>, args=<function SetupStep.<lambda>>, gates_closure=True, tolerates_unknown=True, explains_unverifiable=True), SetupStep(placeholder='step_pypi_trusted_publisher', title='Register the PyPI Trusted Publisher entry', template='setup-guide-pypi-trusted-publisher', probe=<function <lambda>>, applies=<function <lambda>>, args=<function <lambda>>, gates_closure=True, tolerates_unknown=False, explains_unverifiable=False), SetupStep(placeholder='step_pages_source', title='Set GitHub Pages deployment source to GitHub Actions', template='setup-guide-pages-source', probe=<function <lambda>>, applies=<function <lambda>>, args=<function SetupStep.<lambda>>, gates_closure=True, tolerates_unknown=False, explains_unverifiable=False), SetupStep(placeholder='step_cloudflare_pages', title='Configure the Cloudflare Pages credentials', template='setup-guide-cloudflare-pages', probe=<function <lambda>>, applies=<function <lambda>>, args=<function <lambda>>, gates_closure=True, tolerates_unknown=False, explains_unverifiable=False), SetupStep(placeholder='step_cloudflare_r2', title='Configure the R2 upload keys', template='setup-guide-cloudflare-r2', probe=<function <lambda>>, applies=<function <lambda>>, args=<function <lambda>>, gates_closure=True, tolerates_unknown=False, explains_unverifiable=False), SetupStep(placeholder='step_virustotal', title='Configure VirusTotal scanning (optional)', template='setup-guide-virustotal', probe=<function <lambda>>, applies=<function <lambda>>, args=<function SetupStep.<lambda>>, gates_closure=True, tolerates_unknown=False, explains_unverifiable=False), SetupStep(placeholder='step_notifications_pat', title='Create and configure the notifications token', template='setup-guide-notifications-pat', probe=<function <lambda>>, applies=<function <lambda>>, args=<function SetupStep.<lambda>>, gates_closure=True, tolerates_unknown=False, explains_unverifiable=False), SetupStep(placeholder='step_verify', title='Verify the setup', template='setup-guide-verify', probe=<function SetupStep.<lambda>>, applies=<function SetupStep.<lambda>>, args=<function SetupStep.<lambda>>, gates_closure=False, tolerates_unknown=False, explains_unverifiable=False))¶
Every step of the setup guide, in the order the issue body lists them.
Each step’s template takes the shape of the
REPOMATIC_PATstep: one lead sentence saying what to set and why, then numbered actions in the order they run. An action gives the command, then at most one alternative, writtenOr by hand:when it goes through the web UI. A form’s values go in a field table. A note only warns against a wrong action or names the cost of skipping one. Reasons and other routes live indocs/, or in a comment beside the step.
- repomatic.setup_guide.manage_setup_guide(config, *, has_pat, has_notifications_pat, has_virustotal_key, has_cloudflare_api_token=False, has_cloudflare_r2_keys=False, repo)[source]¶
Render the setup guide issue body and drive the issue lifecycle.
Walks
SETUP_STEPS: each step probes its own state, renders its collapsible section, and reports whether it lets the issue close. The issue closes only when every applicable gating step passes.- Parameters:
config (
Config) – The resolved[tool.repomatic]configuration.has_pat (
bool) – WhetherREPOMATIC_PATis configured.has_notifications_pat (
bool) – WhetherREPOMATIC_NOTIFICATIONS_PATis configured.has_virustotal_key (
bool) – WhetherVIRUSTOTAL_API_KEYis configured.has_cloudflare_api_token (
bool) – WhetherCLOUDFLARE_API_TOKENis configured.has_cloudflare_r2_keys (
bool) – Whether both R2 upload secrets are configured.repo (
str|None) – Repository inowner/repoformat; permission and settings checks are skipped whenNone.
- Return type: