tests.test_templating module

Tests for repomatic.templating and the bundled templates.

tests.test_templating.PROGRAMMATIC_TEMPLATES = frozenset({'available-admonition', 'broken-links-issue', 'development-warning', 'generated-footer', 'github-releases', 'immutable-releases', 'pr-metadata', 'refresh-tip', 'release-notes', 'release-sync-report', 'setup-guide', 'setup-guide-branch-ruleset', 'setup-guide-cloudflare-pages', 'setup-guide-cloudflare-r2', 'setup-guide-dependabot', 'setup-guide-fork-pr-approval', 'setup-guide-notifications-pat', 'setup-guide-pages-source', 'setup-guide-pypi-trusted-publisher', 'setup-guide-sha-pinning-required', 'setup-guide-token', 'setup-guide-verify', 'setup-guide-virustotal', 'unavailable-admonition', 'unsubscribe-report', 'upgrade-invite', 'yanked-admonition'})

Templates rendered from Python code, not via the --template CLI flag.

tests.test_templating.CLI_TEMPLATES = ('bump-version', 'fix-changelog', 'fix-typos', 'fix-vulnerable-deps', 'format-images', 'format-json', 'format-markdown', 'format-pyproject', 'format-python', 'format-shell', 'prepare-release', 'sample-metrics', 'scan-virustotal', 'squashed-release', 'sync-action-pins', 'sync-bumpversion', 'sync-dep-sources', 'sync-gitignore', 'sync-mailmap', 'sync-repomatic', 'sync-repomatic-upgrade', 'sync-runner-images', 'sync-tool-versions', 'sync-uv-lock', 'sync-workflow-pins', 'update-dep-graph', 'update-docs')

Templates that front a pull request or an issue pr-sync and pr-body open.

tests.test_templating.REFERENCE_WORKFLOWS = ('.github/workflows/autofix.yaml', '.github/workflows/changelog.yaml', '.github/workflows/_release-build.yaml', '.github/workflows/_release-engine.yaml', '.github/workflows/metrics.yaml', '.github/workflows/self-maintenance.yaml')

Workflow files that reference PR body templates via --template.

tests.test_templating.COMMAND_TEMPLATES: dict[str, str] = {'bump-version': 'bump-version', 'squashed-release': 'squashed-release'}

Templates a command renders on its own, keyed by the command a workflow runs.

Each command opens its pull request or issue itself, so no --template argument names the template in the workflow.

tests.test_templating.WORKFLOWS_DOCS_URL = 'https://repomatic.net/workflows'

Hosted workflows reference that template docs: fields deep-link into.

tests.test_templating.test_unescape_dollars(text, expected)[source]

\$ sequences are converted back to $.

tests.test_templating.test_parse_template_unescapes_body()[source]

Body \$ placeholders are unescaped at parse time.

tests.test_templating.test_parse_template_unescapes_no_frontmatter()[source]

Templates without frontmatter also get \$ unescaped.

footer: false opts out whether written as a YAML boolean or a string.

The frontmatter is real YAML, so a bare false arrives as a boolean, but a downstream template may have quoted it. Both spell the same intent.

tests.test_templating.test_get_template_names()[source]

Every template file is discovered once, under its stem.

tests.test_templating.test_load_reads_the_frontmatter_once()[source]

A bundled template loads once per process, as one shared instance.

tests.test_templating.test_load_template_frontmatter()[source]

Frontmatter is parsed correctly from a parameterized template.

tests.test_templating.test_load_template_title_only_frontmatter()[source]

Static templates have frontmatter with title but no args.

tests.test_templating.test_load_template_external_file(tmp_path)[source]

A Path argument loads the template from disk.

tests.test_templating.test_load_template_external_file_missing(tmp_path)[source]

Pointing at a non-existent file raises FileNotFoundError.

tests.test_templating.test_load_unknown_bundled_template()[source]

A name no bundled template carries raises FileNotFoundError.

tests.test_templating.test_render_template_external_file(tmp_path)[source]

External templates render with substitution like packaged ones.

tests.test_templating.test_render_title_no_title_returns_empty(tmp_path)[source]

A template without a title field renders to an empty string.

tests.test_templating.test_labels_accept_a_list_or_a_string(tmp_path, labels, expected)[source]

The labels: key is a YAML list or a single string.

tests.test_templating.test_draft_accepts_both_spellings(tmp_path, declaration, expected)[source]

draft: true holds the pull request in draft, quoted or not.

tests.test_templating.test_template_args_parameterized()[source]

Parameterized templates report their required arguments.

tests.test_templating.test_template_args_static()[source]

Static templates report no required arguments.

tests.test_templating.test_render_title_static()[source]

Static templates have a literal title.

tests.test_templating.test_render_title_parameterized()[source]

Parameterized templates substitute variables in the title.

tests.test_templating.test_render_commit_message_falls_back_to_title()[source]

Templates without explicit commit_message fall back to title.

tests.test_templating.test_render_commit_message_explicit()[source]

Templates without explicit commit_message fall back to title with backticks.

tests.test_templating.test_render_commit_message_parameterized()[source]

Parameterized templates substitute variables in commit_message.

The bump-version message must start with a MANUAL_VERSION_BUMP_COMMIT_PREFIXES member: that is the emission half of the invariant the workflow gates match against (see test_changelog_prefix_is_the_machinery_invariant).

The footer renders alone: it never appends a second copy of itself.

Several templates wanting the footer still share a single copy.

A pull request template never carries the footer itself.

The metadata block that closes every pull request body carries the attribution footer already, so a template rendering one too shows it twice.

tests.test_templating.test_render_bump_version()[source]

Bump version template includes part, version, and merge instructions.

tests.test_templating.test_render_prepare_release()[source]

Prepare release template includes version, links, and caution admonition.

tests.test_templating.test_render_prepare_release_without_review_steps()[source]

Empty review fragments degrade the checklist to the merge instructions.

tests.test_templating.test_render_surfaces_the_config_surface(template, needles)[source]

Each job’s PR body points the reader at the knobs that job obeys.

tests.test_templating.test_render_upgrade_title()[source]

The upgrade pull request is titled after the release it adopts.

tests.test_templating.test_render_upgrade_invite()[source]

The invitation names both releases and hands over the launcher verbatim.

tests.test_templating.test_dependabot_step_names_the_downstream_updaters()[source]

The setup step names the updaters a downstream repository runs.

sync-tool-versions rewrites repomatic’s own tool registry, so it runs upstream alone and replaces nothing Dependabot does downstream.

tests.test_templating.TABLE_ROW_PLACEHOLDER = re.compile('^\\|.*\\$\\{?\\w+', re.MULTILINE)

A placeholder inside a table row of a template body.

tests.test_templating.test_no_placeholder_splices_into_a_table_row(name)[source]

A multi-line value spliced into one row’s pipes breaks the table.

Its first line takes the row’s leading cell, and its last line gains the row’s trailing ones. A table whose row count varies is rendered whole in Python, or its rows are spliced below the delimiter row, never inside one.

tests.test_templating.test_release_sync_report_renders_a_well_formed_table()[source]

Every row of the summary table has the cells its header declares.

tests.test_templating.VALID_CONFIG_KEYS = frozenset({'abandoned-versions', 'action-pins.sync', 'awesome-template.sync', 'binaries.sync', 'bumpversion.sync', 'cache.dir', 'cache.github-releases-ttl', 'cache.max-age', 'cache.npm-ttl', 'cache.pypi-ttl', 'changelog.archive-location', 'changelog.bullet-word-threshold', 'changelog.location', 'debug.sync', 'dep-sources.sync', 'dependency-graph.all-extras', 'dependency-graph.all-groups', 'dependency-graph.level', 'dependency-graph.no-extras', 'dependency-graph.no-groups', 'dependency-graph.output', 'dependency-graph.update', 'dev-release.sync', 'docs.apidoc-exclude', 'docs.apidoc-extra-args', 'docs.update-script', 'exclude', 'github-releases.sync', 'gitignore.extra-categories', 'gitignore.extra-content', 'gitignore.location', 'gitignore.sync', 'include', 'labels.content-rules', 'labels.extra', 'labels.extra-files', 'labels.file-rules', 'labels.sync', 'lint-deps.allow', 'lint-deps.comment-word-threshold', 'lint-repo.declined', 'mailmap.sync', 'manpages.asset-name', 'manpages.script', 'metrics.charts', 'metrics.colors', 'metrics.forges', 'metrics.predecessors', 'metrics.store', 'metrics.subjects', 'metrics.sync', 'minimum-release-age', 'notification.max-unsubscribes', 'notification.months', 'notification.unsubscribe', 'nuitka.dev-targets', 'nuitka.enabled', 'nuitka.entry-points', 'nuitka.extras', 'nuitka.nofollow-imports', 'nuitka.unstable-targets', 'pypi-package-history', 'release-assets', 'settings.location', 'setup-guide', 'site.cloudflare-compatibility-date', 'site.cloudflare-placement', 'site.cloudflare-project', 'site.cloudflare-r2-bucket', 'site.cloudflare-r2-domain', 'site.deploy', 'skills.location', 'sphinx.builder', 'subagents.location', 'sync-runner-images.ignore', 'sync-runner-images.sync', 'test-matrix.exclude', 'test-matrix.full-include', 'test-matrix.include', 'test-matrix.remove', 'test-matrix.replace', 'test-matrix.unstable', 'test-matrix.variations', 'tool-versions.sync', 'upstream-pin.sync', 'uv-lock.sync', 'vulnerable-deps.sources', 'vulnerable-deps.sync', 'workflow-pins.sync', 'workflow.extra-paths', 'workflow.ignore-paths', 'workflow.paths', 'workflow.source-paths', 'workflow.sync'})

Every [tool.repomatic] key, dotted and nested-expanded, from the schema.

tests.test_templating.test_template_config_options_are_real_keys(name)[source]

Every option a template lists is a real key, anchored and sorted.

Each - `key <…/configuration#anchor>`_ bullet must name a live [tool.repomatic] key, link to its matching anchor, and appear in alphabetical order, so a renamed or mistyped option cannot survive in a PR body template.

Return type:

None

tests.test_templating.SWITCH_KEY_RE = re.compile('exit_if_disabled\\(ctx, "(?P<key>[\\w.-]+)"\\)')

The [tool.repomatic] key a command hands to exit_if_disabled.

tests.test_templating.test_templates_list_the_switch_of_their_command()[source]

A pull request body that lists options names the one that stops it.

A command gated by exit_if_disabled opens no pull request once its switch is off, so the option list of that pull request is where a maintainer looks for the switch. Only a template named after its command is read: audit and sync-binaries fill a template of another name. A template with no option list is left alone, like the setup-guide issue body.

Return type:

None

tests.test_templating.test_template_file_policy(filename, name)[source]

Each PR template file must be a valid .md file with correct frontmatter.

tests.test_templating.test_placeholders_match_declared_args(name)[source]

A template’s $placeholders and its args: frontmatter name one set.

string.Template.get_identifiers() lists the placeholders substitute() fills, bare or braced, so a placeholder the text uses but never declares fails here rather than as a KeyError in the job rendering it, and a declared arg no text references fails the same way. is_valid() rejects the stray $ that substitute() would raise on.

tests.test_templating.FRONTMATTER_KEY_ORDER = ['args', 'title', 'commit_message', 'docs', 'footer']

Canonical ordering of keys within template frontmatter.

tests.test_templating.test_frontmatter_key_ordering(filename, name)[source]

Frontmatter keys must follow the canonical order in FRONTMATTER_KEY_ORDER.

yaml.safe_load preserves document order in the mapping it builds, so the parsed keys read back in the order the template spells them.

A bundled template spells the footer opt-out one way: footer: false.

tests.test_templating.test_templates_match_workflow_references()[source]

Every CLI template must be referenced by --template in a workflow file.

tests.test_templating.test_template_commit_message_carries_no_ci_skip_token(name)[source]

No generated commit message may silently skip CI.

Every sync-*, format-* and fix-* job commits a message rendered from a template, in this repository and in every downstream one. A skip token anywhere in that message stops the run, and because the required check is then never reported, the pull request blocks on a “Pending” status instead of failing visibly.

Return type:

None

tests.test_templating.test_template_commit_subject_claims_no_bracket_prefix(name)[source]

A [bracketed] prefix is reserved for machine-parsed mechanisms.

The one family templates may emit is repomatic.release.protocol.CHANGELOG_COMMIT_PREFIX, which repomatic.release.protocol.VERSION_BUMP_COMMIT_PREFIXES matches back (bump-version is the template that earns it). Any other bracket would either collide with that matcher or invent a label nothing reads. See docs/commit-messages.md.

Return type:

None

tests.test_templating.test_only_the_changelog_prefix_is_bracketed()[source]

The parsed-prefix set stays a single bracket family.

docs/commit-messages.md tells readers that [changelog] is the only bracket prefix any machine reads, carried by every version-machinery commit. This pins that claim to the code, so a second bracket namespace fails here and forces the documentation to follow.

Return type:

None