repomatic.init_project module¶
Bundled data files, configuration templates, and repository initialization.
Provides a unified interface for accessing bundled data files from
repomatic/data/ and orchestrates repository bootstrapping via
repomatic init.
Every component repomatic init accepts is declared in
COMPONENTS, which carries each one’s description,
default scope and target paths; repomatic init --help lists them. That tuple
is the only roster: a list repeated here would silently fall behind it.
Selectors use the same component[/file] syntax as the exclude
config option in [tool.repomatic]. Qualified entries like
skills/repomatic-topics select a single file within a component.
- repomatic.init_project.RUNTIME_FRAGMENTS: tuple[str, ...] = ('release.yaml', 'vt-trend-chart.js')¶
Bundled files loaded by
repomaticat runtime, not deployed verbatim.These files live in
repomatic/data/so they ship in the wheel and are discoverable viaget_data_content(), butrepomatic initnever copies them as-is.release.yamlis the canonical callerrepomatic.github.workflow_syncreads to assemble each downstreamrelease.yaml, copying its jobs and rewriting the localuses:refs (see_generate_release_caller); the deployedrelease.yamlis generated, not this bundled copy.vt-trend-chart.jsis the detections-chart scriptrepomatic.release.binaries_page.render_chart_sectionsplices intodocs/binaries.mdwith its payload placeholders filled. New entries must be added explicitly so the data-file registry tests stay authoritative.
- repomatic.init_project.EXPORTABLE_FILES: dict[str, str | None] = {'_release-engine.yaml': '.github/workflows/release.yaml', 'action-publish-pypi.yaml': '.github/actions/publish-pypi/action.yaml', 'actionlint.yaml': None, 'agent-grunt-qa.md': '.claude/agents/grunt-qa.md', 'agent-qa-engineer.md': '.claude/agents/qa-engineer.md', 'agent-sphinx-docs.md': '.claude/agents/sphinx-docs.md', 'autofix.yaml': '.github/workflows/autofix.yaml', 'autolock.yaml': '.github/workflows/autolock.yaml', 'bumpversion.toml': None, 'cancel-runs.yaml': '.github/workflows/cancel-runs.yaml', 'changelog.yaml': '.github/workflows/changelog.yaml', 'coverage.toml': None, 'debug.yaml': '.github/workflows/debug.yaml', 'docs.yaml': '.github/workflows/docs.yaml', 'labels.toml': 'labels.toml', 'labels.yaml': '.github/workflows/labels.yaml', 'lint.yaml': '.github/workflows/lint.yaml', 'lychee.toml': None, 'mdformat.toml': None, 'metrics.yaml': '.github/workflows/metrics.yaml', 'mypy.toml': None, 'pytest.toml': None, 'release.yaml': None, 'ruff.toml': None, 'tests.yaml': '.github/workflows/tests.yaml', 'typos.toml': None, 'unsubscribe.yaml': '.github/workflows/unsubscribe.yaml', 'uv.toml': None, 'vt-trend-chart.js': None, 'yamllint.yaml': None, 'zizmor.yaml': None}¶
Registry of all exportable files: maps filename to default output path.
Nonemeans the file is bundled but not directly written to a target path byrepomatic init(used forpyproject.tomltemplates that need merging, tool-runner default configs, and runtime fragments).
- repomatic.init_project.export_content(filename)[source]¶
Get the content of any exportable bundled file.
- Parameters:
filename (
str) – The filename (like “ruff.toml” or “release.yaml”).- Return type:
- Returns:
Content of the file as a string.
- Raises:
ValueError – If the file is not in the registry.
FileNotFoundError – If the file doesn’t exist.
- repomatic.init_project.init_config(config_type, pyproject_path=None)[source]¶
Initialize a configuration by merging it into pyproject.toml.
Reads the pyproject.toml file, checks if the tool section already exists, and if not, inserts the bundled template at the appropriate location.
The template is stored in native format (without
[tool.X]prefix) and is parsed by tomlrt and added under the[tool]table.- Parameters:
- Return type:
- Returns:
The modified pyproject.toml content, or
Noneif no changes needed.- Raises:
ValueError – If the config type is not supported.
- repomatic.init_project.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_project.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 exactly one way: a human moves the pin, by hand or by running a newerinit. Two things follow.A pin equal to the running version is not a decision to gate. The CI
sync-repomaticjob runsinitat the pinned version itself, sobaseequals floor on every sync; re-judging it there downgrades the repository once a week after each hand-bump, and fights the only upgrade path there is.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:run_init()reads it back and, when the repository already carries workflows, skips 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), sorun_initcan surface it in the finalinitsummary rather than only mid-run.floor (
UpstreamRefPin|None) – The highest upstream pin already committed downstream, from_highest_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_project.InitResult(created=<factory>, updated=<factory>, skipped=<factory>, excluded=<factory>, excluded_existing=<factory>, unmodified_configs=<factory>, removed_prunable=<factory>, removed_review=<factory>, warnings=<factory>)[source]¶
Bases:
objectResult of a repository initialization run.
- removed_prunable: list[tuple[str, str]]¶
(relative_path, successor)for on-disk orphans of dropped assets whose content matches the last-shipped version (safe to auto-delete).
- repomatic.init_project.prune_paths(paths, output_dir, *, prune_parents=True)[source]¶
Delete every path of an
InitResultreport section.The deleting half of
init’s delete flags (--delete-excluded,--delete-unmodified, the removed-asset pruning), kept besiderun_init(), which produced the paths: the CLI decides which sections get deleted, this module owns the filesystem mutation.- Parameters:
paths (
Sequence[str] |Sequence[tuple[str,str]]) – Bare relative paths, or(path, successor)pairs for the removed-asset sections.output_dir (
Path) – Repository root the paths are relative to.prune_parents (
bool) – Also remove parent directories left empty. On for the removed-asset and excluded sections, whose targets sit in directories repomatic itself created (.claude/skills/<name>/). Off for unmodified tool configs, which share.github/and the repository root with files repomatic does not own.
- Return type:
- repomatic.init_project.adopted_ongoing_configs(output_dir)[source]¶
Return the ongoing tool configs whose section
pyproject.tomlalready carries.EXPLICITgoverns adoption, not upkeep: it keeps a bareinitfrom pushing[tool.typos]onto a repository that never asked for one. Once the section is there the repository has asked, so anONGOINGcomponent rejoins the bare-init set and resumes tracking the bundled template.Without this the two flags cancel out. The only sync that ever runs unattended is the bare
initthesync-repomaticjob calls, so an ONGOING section is otherwise re-derived only when a human types its component name, and a[tool.typos]written by hand sits indefinitely beside a bundled template it never adopts a single rule from.BOOTSTRAPcomponents stay out: their template is a starting point the repository owns outright after the first write, and re-selecting one would revert deliberate local edits.
- repomatic.init_project.run_init(output_dir, components=(), version=None, cooldown=True, repo='kdeldycke/repomatic', repo_slug=None, config=None)[source]¶
Bootstrap a repository for use with
kdeldycke/repomatic.Creates thin-caller workflow files, exports configuration files, and generates a minimal
changelog.mdif missing. Managed files (workflows, configs, skills) are always overwritten. User-owned files (changelog.md,zizmor.yaml) are created once and never overwritten.For
awesome-*repositories, theawesome-templatecomponent is auto-included when no explicit component selection is made.Note
Scope exclusions (
RepoScope.AWESOME_ONLY,PYTHON_ONLY) and user-config exclusions ([tool.repomatic] exclude) only apply during barerepomatic init. When components are explicitly named on the CLI, scope is bypassed: the caller knows what they asked for. This allows workflows to materialize out-of-scope configs at runtime (likerepomatic init publish-pypi-actionin a non-Python repo).- Parameters:
output_dir (
Path) – Root directory of the target repository.components (
Sequence[str]) – Components to initialize. Empty means all defaults. When non-empty, scope and user-config exclusions are bypassed.version (
str|None) – Version pin for upstream workflows (likev5.10.0). WhenNone, derived from the running package version, gated by cooldown.cooldown (
bool) – WhenTrue(and version is unset), hold the derived pin back to the newest release past the [tool.repomatic] minimum-release-age window instead of pinning a fresh running version (seeresolve_default_pin()). Ignored when version is explicit.repo (
str) – Upstream repository containing reusable workflows.repo_slug (
str|None) – Repositoryowner/nameslug for awesome-template URL rewriting. Auto-detected viaMetadataif not provided.config (
Config|None) – The resolved[tool.repomatic]configuration. Loaded from the current directory when omitted, so a caller working against another tree must pass the config it read from there.
- Return type:
- Returns:
Summary of created, updated, skipped, and warned items.
- repomatic.init_project.is_source_repo(output_dir)[source]¶
Detect whether
output_diris the repomatic source repository root.Returns
Truewhenoutput_dircontains therepomaticPython package source tree (repomatic/__init__.pyandrepomatic/data/). Only the upstream source repo has these. This prevents auto-exclusion from deleting files that are the source of truth (skills, opt-in workflows, bundled configs).Note
Detection is based on
output_dircontents, not on__file__, becauseuvx --from .installs the package into a temp venv where__file__no longer points to the source checkout.- Return type:
- repomatic.init_project.AWESOME_TEMPLATE_SLUG = 'kdeldycke/awesome-template'¶
Source slug embedded in bundled awesome-template files, rewritten at sync time.
- repomatic.init_project.init_awesome_template(output_dir, repo_slug, result)[source]¶
Copy bundled awesome-template files and rewrite URLs.
Copies all files from the
repomatic/data/awesome_template/bundle into output_dir and rewriteskdeldycke/awesome-templateURLs in.github/markdown and YAML files to match repo_slug.Every copied file is recorded on result by its own relative path, the way the skills and agents trees already are. The roll-up stays a log line: those lists are consumed as paths (
--delete-excludedjoins them against output_dir), so a"awesome-template (12 files)"summary sitting among them would be a path that resolves nowhere.- Parameters:
output_dir (
Path) – Root directory of the target repository.repo_slug (
str) – Targetowner/nameslug for URL rewriting.result (
InitResult) –InitResultaccumulator for created/updated files.
- Return type: