repomatic 7.1.0__tar.gz → 7.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {repomatic-7.1.0 → repomatic-7.2.0}/PKG-INFO +2 -2
- {repomatic-7.1.0 → repomatic-7.2.0}/pyproject.toml +21 -10
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/__init__.py +2 -2
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/broken_links.py +1 -1
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/cache.py +96 -90
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/changelog.py +47 -17
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/cli.py +292 -614
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/config.py +67 -41
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/data/_release-engine.yaml +26 -19
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/data/action-publish-pypi.yaml +1 -1
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/data/agent-sphinx-docs.md +1 -1
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/data/autofix.yaml +98 -56
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/data/bumpversion.toml +6 -2
- repomatic-7.2.0/repomatic/data/cancel-runs.yaml +50 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/data/changelog.yaml +18 -18
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/data/debug.yaml +4 -4
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/data/docs.yaml +6 -6
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/data/labels.yaml +11 -11
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/data/lint.yaml +17 -17
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/data/skill-babysit-ci.md +6 -3
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/data/skill-repomatic-ship.md +12 -10
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/data/tests.yaml +5 -5
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/data/unsubscribe.yaml +4 -2
- repomatic-7.2.0/repomatic/dep_sources.py +377 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/deps_graph.py +287 -344
- repomatic-7.2.0/repomatic/docs.py +172 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/git_ops.py +14 -35
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/github/__init__.py +3 -6
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/github/actions.py +47 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/github/dev_release.py +1 -2
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/github/gh.py +100 -12
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/github/issue.py +2 -17
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/github/matrix.py +3 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/github/pr_body.py +132 -47
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/github/release_sync.py +5 -50
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/github/releases.py +100 -100
- {repomatic-7.1.0/repomatic → repomatic-7.2.0/repomatic/github}/sponsor.py +11 -49
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/github/token.py +85 -174
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/github/unsubscribe.py +25 -36
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/github/workflow_sync.py +137 -124
- repomatic-7.2.0/repomatic/gitignore.py +88 -0
- repomatic-7.2.0/repomatic/http.py +80 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/images.py +2 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/init_project.py +10 -11
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/lint_repo.py +1 -6
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/metadata.py +51 -47
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/npm.py +4 -7
- repomatic-7.1.0/repomatic/release_prep.py → repomatic-7.2.0/repomatic/prepare_release.py +18 -5
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/pypi.py +22 -16
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/pyproject.py +22 -28
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/registry.py +46 -20
- repomatic-7.2.0/repomatic/setup_guide.py +383 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/sync_ops.py +362 -163
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/templates/bump-version.md +2 -3
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/templates/detect-squash-merge.md +4 -3
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/templates/fix-changelog.md +2 -5
- repomatic-7.2.0/repomatic/templates/fix-typos.md +8 -0
- repomatic-7.2.0/repomatic/templates/fix-vulnerable-deps.md +15 -0
- repomatic-7.2.0/repomatic/templates/format-images.md +5 -0
- repomatic-7.2.0/repomatic/templates/format-json.md +8 -0
- repomatic-7.2.0/repomatic/templates/format-markdown.md +8 -0
- repomatic-7.2.0/repomatic/templates/format-pyproject.md +8 -0
- repomatic-7.2.0/repomatic/templates/format-python.md +8 -0
- repomatic-7.2.0/repomatic/templates/format-shell.md +8 -0
- repomatic-7.2.0/repomatic/templates/pr-metadata.md.noformat +15 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/templates/prepare-release.md +2 -3
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/templates/setup-guide-virustotal.md +3 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/templates/sync-action-pins.md +2 -5
- repomatic-7.2.0/repomatic/templates/sync-bumpversion.md +11 -0
- repomatic-7.2.0/repomatic/templates/sync-dep-sources.md +17 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/templates/sync-gitignore.md +2 -5
- repomatic-7.2.0/repomatic/templates/sync-mailmap.md +11 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/templates/sync-repomatic.md +2 -5
- repomatic-7.2.0/repomatic/templates/sync-tool-versions.md +15 -0
- repomatic-7.2.0/repomatic/templates/sync-uv-lock.md +14 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/templates/sync-workflow-pins.md +2 -5
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/templates/update-deps-graph.md +2 -5
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/templates/update-docs.md +2 -5
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/test_matrix.py +3 -1
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/tool_runner.py +57 -35
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/uv.py +223 -583
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/version_sync.py +50 -39
- repomatic-7.2.0/repomatic/vulnerable_deps.py +592 -0
- repomatic-7.1.0/repomatic/data/cancel-runs.yaml +0 -55
- repomatic-7.1.0/repomatic/github/advisories.py +0 -131
- repomatic-7.1.0/repomatic/templates/fix-typos.md +0 -11
- repomatic-7.1.0/repomatic/templates/fix-vulnerable-deps.md +0 -18
- repomatic-7.1.0/repomatic/templates/format-images.md +0 -8
- repomatic-7.1.0/repomatic/templates/format-json.md +0 -11
- repomatic-7.1.0/repomatic/templates/format-markdown.md +0 -11
- repomatic-7.1.0/repomatic/templates/format-pyproject.md +0 -11
- repomatic-7.1.0/repomatic/templates/format-python.md +0 -11
- repomatic-7.1.0/repomatic/templates/format-shell.md +0 -11
- repomatic-7.1.0/repomatic/templates/pr-metadata.md.noformat +0 -17
- repomatic-7.1.0/repomatic/templates/sync-bumpversion.md +0 -14
- repomatic-7.1.0/repomatic/templates/sync-mailmap.md +0 -14
- repomatic-7.1.0/repomatic/templates/sync-tool-versions.md +0 -18
- repomatic-7.1.0/repomatic/templates/sync-uv-lock.md +0 -17
- {repomatic-7.1.0 → repomatic-7.2.0}/license +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/readme.md +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/__main__.py +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/binaries_page.py +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/binary.py +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/checksums.py +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/data/__init__.py +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/data/agent-grunt-qa.md +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/data/agent-qa-engineer.md +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/data/autolock.yaml +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/data/awesome_template/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/data/awesome_template/.github/ISSUE_TEMPLATE/new-link.yaml +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/data/awesome_template/.github/code-of-conduct.md +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/data/awesome_template/.github/contributing.md +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/data/awesome_template/.github/contributing.zh.md +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/data/awesome_template/.github/funding.yml +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/data/awesome_template/.github/pull_request_template.md +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/data/awesome_template/__init__.py +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/data/awesome_template/license +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/data/codecov.yaml +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/data/labeller-content-based.yaml +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/data/labeller-file-based.yaml +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/data/labels.toml +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/data/lychee.toml +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/data/mdformat.toml +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/data/mypy.toml +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/data/pytest.toml +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/data/release.yaml +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/data/ruff.toml +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/data/skill-av-false-positive.md +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/data/skill-awesome-triage.md +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/data/skill-benchmark-update.md +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/data/skill-brand-assets.md +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/data/skill-file-bug-report.md +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/data/skill-repomatic-audit.md +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/data/skill-repomatic-changelog.md +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/data/skill-repomatic-deps.md +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/data/skill-repomatic-init.md +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/data/skill-repomatic-topics.md +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/data/skill-sphinx-docs-sync.md +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/data/skill-translation-sync.md +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/data/skill-upstream-audit.md +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/data/typos.toml +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/data/uv.toml +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/data/yamllint.yaml +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/data/zizmor.yaml +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/github/pr.py +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/github/status.py +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/mailmap.py +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/myst_converter.py +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/myst_docstrings.py +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/py.typed +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/rst_to_myst.py +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/templates/__init__.py +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/templates/available-admonition.md +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/templates/broken-links-issue.md +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/templates/development-warning.md +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/templates/generated-footer.md +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/templates/github-releases.md +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/templates/immutable-releases.md +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/templates/refresh-tip.md +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/templates/release-notes.md +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/templates/release-sync-report.md +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/templates/setup-guide-branch-ruleset.md +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/templates/setup-guide-dependabot.md +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/templates/setup-guide-fork-pr-approval.md +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/templates/setup-guide-notifications-pat.md +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/templates/setup-guide-pages-source.md +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/templates/setup-guide-pypi-trusted-publisher.md +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/templates/setup-guide-token.md +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/templates/setup-guide-verify.md +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/templates/setup-guide.md +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/templates/unavailable-admonition.md +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/templates/unsubscribe-phase1.md +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/templates/unsubscribe-phase2.md +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/templates/yanked-admonition.md +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/tool_runner_page.py +0 -0
- {repomatic-7.1.0 → repomatic-7.2.0}/repomatic/virustotal.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: repomatic
|
|
3
|
-
Version: 7.
|
|
3
|
+
Version: 7.2.0
|
|
4
4
|
Summary: 🏭 Automate repository maintenance, releases, and CI/CD workflows
|
|
5
5
|
Keywords: changelog-formatter,dependabot-alternative,github-actions,github-labels,github-workflow,gitignore,mailmap,mypy,nuitka,python-automation,release-automation,repository-automation,repository-management,reusable-workflows,software-factory,sphinx-doc,typo,uv,workflow-reusable
|
|
6
6
|
Author: Kevin Deldycke
|
|
@@ -58,7 +58,7 @@ Requires-Dist: wcmatch>=10
|
|
|
58
58
|
Requires-Python: >=3.10
|
|
59
59
|
Project-URL: Changelog, https://github.com/kdeldycke/repomatic/blob/main/changelog.md
|
|
60
60
|
Project-URL: Documentation, https://kdeldycke.github.io/repomatic
|
|
61
|
-
Project-URL: Download, https://github.com/kdeldycke/repomatic/releases/tag/v7.
|
|
61
|
+
Project-URL: Download, https://github.com/kdeldycke/repomatic/releases/tag/v7.2.0
|
|
62
62
|
Project-URL: Funding, https://github.com/sponsors/kdeldycke
|
|
63
63
|
Project-URL: Homepage, https://github.com/kdeldycke/repomatic
|
|
64
64
|
Project-URL: Issues, https://github.com/kdeldycke/repomatic/issues
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
[build-system]
|
|
2
2
|
build-backend = "uv_build"
|
|
3
|
-
requires = [ "uv-build>=0.9" ]
|
|
3
|
+
requires = [ "uv-build>=0.9,<0.12" ]
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
# Docs: https://packaging.python.org/en/latest/guides/writing-pyproject-toml/
|
|
7
7
|
name = "repomatic"
|
|
8
|
-
version = "7.
|
|
8
|
+
version = "7.2.0"
|
|
9
9
|
description = "🏭 Automate repository maintenance, releases, and CI/CD workflows"
|
|
10
10
|
readme = "readme.md"
|
|
11
11
|
keywords = [
|
|
@@ -122,7 +122,7 @@ dependencies = [
|
|
|
122
122
|
]
|
|
123
123
|
urls.Changelog = "https://github.com/kdeldycke/repomatic/blob/main/changelog.md"
|
|
124
124
|
urls.Documentation = "https://kdeldycke.github.io/repomatic"
|
|
125
|
-
urls.Download = "https://github.com/kdeldycke/repomatic/releases/tag/v7.
|
|
125
|
+
urls.Download = "https://github.com/kdeldycke/repomatic/releases/tag/v7.2.0"
|
|
126
126
|
urls.Funding = "https://github.com/sponsors/kdeldycke"
|
|
127
127
|
urls.Homepage = "https://github.com/kdeldycke/repomatic"
|
|
128
128
|
urls.Issues = "https://github.com/kdeldycke/repomatic/issues"
|
|
@@ -206,7 +206,7 @@ exclude-newer = "1 week"
|
|
|
206
206
|
# `exclude-newer`, returning the package to the normal cooldown. repomatic is
|
|
207
207
|
# pinned to git main (no PyPI release to freeze), so it keeps a permanent
|
|
208
208
|
# "0 day" span.
|
|
209
|
-
exclude-newer-package = {
|
|
209
|
+
exclude-newer-package = { repomatic = "0 day" }
|
|
210
210
|
# Package is at root level, not in "./src/".
|
|
211
211
|
build-backend.module-root = ""
|
|
212
212
|
|
|
@@ -219,7 +219,7 @@ copyright = "Kevin Deldycke <kevin@deldycke.com> and contributors. Distributed u
|
|
|
219
219
|
file-description = "🏭 Automate repository maintenance, releases, and CI/CD workflows"
|
|
220
220
|
# Numeric only: Nuitka rejects PEP 440 .devN suffixes. Kept in sync with the
|
|
221
221
|
# package version by the dedicated [tool.bumpversion] rule that strips the suffix.
|
|
222
|
-
file-version = "7.
|
|
222
|
+
file-version = "7.2.0"
|
|
223
223
|
include-data-dir = [
|
|
224
224
|
"repomatic/data/awesome_template=repomatic/data/awesome_template",
|
|
225
225
|
]
|
|
@@ -237,7 +237,7 @@ include-package-data = [ "click_extra" ]
|
|
|
237
237
|
linux-icon = "docs/assets/icon.png"
|
|
238
238
|
macos-app-icon = "docs/assets/icon.icns"
|
|
239
239
|
product-name = "Repomatic"
|
|
240
|
-
product-version = "7.
|
|
240
|
+
product-version = "7.2.0"
|
|
241
241
|
windows-icon-from-ico = "docs/assets/icon.ico"
|
|
242
242
|
|
|
243
243
|
[tool.ruff]
|
|
@@ -276,7 +276,14 @@ default.extend-identifiers = { Github = "GitHub", IOS = "iOS", Javascript = "Jav
|
|
|
276
276
|
# False positives.
|
|
277
277
|
default.extend-words = { astroid = "astroid", oject = "oject", PNGs = "PNGs" }
|
|
278
278
|
# Skip content between <!-- typos:off --> and <!-- typos:on --> markers.
|
|
279
|
-
default.extend-ignore-re = [
|
|
279
|
+
default.extend-ignore-re = [
|
|
280
|
+
"(?s)<!-- typos:off -->.*?<!-- typos:on -->",
|
|
281
|
+
# `{qeury}` is the intentional-typo example in the typos tool's own docs_notes
|
|
282
|
+
# guidance (tool_runner.py), which recommends downstream projects guard such
|
|
283
|
+
# examples and encoded hashes from the unattended fix-typos pull request.
|
|
284
|
+
"\\{qeury\\}",
|
|
285
|
+
'base32 "[0-9a-z]{52}"',
|
|
286
|
+
]
|
|
280
287
|
default.extend-ignore-identifiers-re = [
|
|
281
288
|
# error: `certifi` should be `certify`, `certifies`, `certified`
|
|
282
289
|
# ╭▸ ./docs/assets/dependencies.mmd:184:11
|
|
@@ -344,7 +351,7 @@ run.source = [ "repomatic" ]
|
|
|
344
351
|
report.precision = 2
|
|
345
352
|
|
|
346
353
|
[tool.bumpversion]
|
|
347
|
-
current_version = "7.
|
|
354
|
+
current_version = "7.2.0"
|
|
348
355
|
# Parse versions with an optional .devN suffix (PEP 440).
|
|
349
356
|
parse = "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)(\\.dev(?P<dev>\\d+))?"
|
|
350
357
|
serialize = [
|
|
@@ -399,9 +406,13 @@ search = "## [`{current_version}` (unreleased)]("
|
|
|
399
406
|
replace = "## [`{new_version}` (unreleased)]("
|
|
400
407
|
|
|
401
408
|
[[tool.bumpversion.files]]
|
|
402
|
-
# Update the version in the citation file.
|
|
409
|
+
# Update the version in the citation file. Anchored to a line start (regex) so
|
|
410
|
+
# it does not also match the `cff-version:` schema field, which would otherwise
|
|
411
|
+
# be overwritten with the package version on every bump as soon as the two
|
|
412
|
+
# values coincide once.
|
|
403
413
|
filename = "./citation.cff"
|
|
404
|
-
|
|
414
|
+
regex = true
|
|
415
|
+
search = "(?m)^version: {current_version}"
|
|
405
416
|
replace = "version: {new_version}"
|
|
406
417
|
|
|
407
418
|
[[tool.bumpversion.files]]
|
|
@@ -21,7 +21,7 @@ GitHub issue. Sphinx linkcheck parsing detects broken auto-generated links
|
|
|
21
21
|
(intersphinx, autodoc, type annotations) that Lychee cannot see because they
|
|
22
22
|
only exist in the rendered HTML output.
|
|
23
23
|
|
|
24
|
-
Issue lifecycle management is delegated to {mod}`~repomatic.issue`.
|
|
24
|
+
Issue lifecycle management is delegated to {mod}`~repomatic.github.issue`.
|
|
25
25
|
"""
|
|
26
26
|
|
|
27
27
|
from __future__ import annotations
|
|
@@ -55,6 +55,31 @@ from extra_platforms import is_macos, is_windows
|
|
|
55
55
|
|
|
56
56
|
from .config import load_repomatic_config
|
|
57
57
|
|
|
58
|
+
TYPE_CHECKING = False
|
|
59
|
+
if TYPE_CHECKING:
|
|
60
|
+
from collections.abc import Callable
|
|
61
|
+
from typing import Any
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def _atomic_write(dest: Path, prefix: str, write: Callable[[Path], object]) -> None:
|
|
65
|
+
"""Write *dest* atomically: temp file in the target directory, then rename.
|
|
66
|
+
|
|
67
|
+
The rename is atomic on POSIX (same-filesystem rename) and safe on Windows
|
|
68
|
+
(`Path.replace` overwrites atomically). *write* receives the temp path and
|
|
69
|
+
fills it (its return value is ignored, so `write_text`/`write_bytes` pass
|
|
70
|
+
straight through); partial writes are cleaned up on any failure.
|
|
71
|
+
"""
|
|
72
|
+
dest.parent.mkdir(parents=True, exist_ok=True)
|
|
73
|
+
fd, tmp = tempfile.mkstemp(dir=dest.parent, prefix=prefix, suffix=".tmp")
|
|
74
|
+
try:
|
|
75
|
+
os.close(fd)
|
|
76
|
+
write(Path(tmp))
|
|
77
|
+
Path(tmp).replace(dest)
|
|
78
|
+
except BaseException:
|
|
79
|
+
# Clean up partial writes on any failure.
|
|
80
|
+
Path(tmp).unlink(missing_ok=True)
|
|
81
|
+
raise
|
|
82
|
+
|
|
58
83
|
|
|
59
84
|
@dataclass(frozen=True)
|
|
60
85
|
class CacheEntry:
|
|
@@ -235,17 +260,8 @@ def store_binary(
|
|
|
235
260
|
:return: Path to the cached binary.
|
|
236
261
|
"""
|
|
237
262
|
dest = cached_binary_path(name, version, platform_key, source.name)
|
|
238
|
-
dest.parent.mkdir(parents=True, exist_ok=True)
|
|
239
263
|
|
|
240
|
-
|
|
241
|
-
fd, tmp = tempfile.mkstemp(
|
|
242
|
-
dir=dest.parent,
|
|
243
|
-
prefix=f".{source.name}.",
|
|
244
|
-
suffix=".tmp",
|
|
245
|
-
)
|
|
246
|
-
try:
|
|
247
|
-
os.close(fd)
|
|
248
|
-
tmp_path = Path(tmp)
|
|
264
|
+
def fill(tmp_path: Path) -> None:
|
|
249
265
|
shutil.copy2(source, tmp_path)
|
|
250
266
|
tmp_path.chmod(0o755)
|
|
251
267
|
# copy2 preserves the source mtime, which for a binary extracted from
|
|
@@ -254,12 +270,8 @@ def store_binary(
|
|
|
254
270
|
# auto_purge() call below, before this store even returns. Stamp the
|
|
255
271
|
# store time instead.
|
|
256
272
|
os.utime(tmp_path)
|
|
257
|
-
tmp_path.replace(dest)
|
|
258
|
-
except BaseException:
|
|
259
|
-
# Clean up partial writes on any failure.
|
|
260
|
-
Path(tmp).unlink(missing_ok=True)
|
|
261
|
-
raise
|
|
262
273
|
|
|
274
|
+
_atomic_write(dest, f".{source.name}.", fill)
|
|
263
275
|
logging.debug("Cached %s %s for %s at %s.", name, version, platform_key, dest)
|
|
264
276
|
auto_purge()
|
|
265
277
|
return dest
|
|
@@ -322,30 +334,14 @@ def clear_cache(
|
|
|
322
334
|
if not bin_root.is_dir():
|
|
323
335
|
return 0, 0
|
|
324
336
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
continue
|
|
334
|
-
logging.debug("Purging cached binary: %s", entry.path)
|
|
335
|
-
try:
|
|
336
|
-
bytes_freed += entry.size
|
|
337
|
-
entry.path.unlink()
|
|
338
|
-
# Remove the .sha256 sidecar if present.
|
|
339
|
-
sidecar = entry.path.with_suffix(entry.path.suffix + ".sha256")
|
|
340
|
-
if sidecar.is_file():
|
|
341
|
-
sidecar.unlink()
|
|
342
|
-
files_deleted += 1
|
|
343
|
-
except OSError:
|
|
344
|
-
logging.debug("Failed to remove %s.", entry.path)
|
|
345
|
-
|
|
346
|
-
# Prune empty parent directories up to bin_root.
|
|
347
|
-
_prune_empty_dirs(bin_root)
|
|
348
|
-
return files_deleted, bytes_freed
|
|
337
|
+
return _purge(
|
|
338
|
+
cache_info(),
|
|
339
|
+
bin_root,
|
|
340
|
+
keep=lambda entry: (
|
|
341
|
+
(tool is not None and entry.tool != tool) or _is_fresh(entry, max_age_days)
|
|
342
|
+
),
|
|
343
|
+
sidecars=True,
|
|
344
|
+
)
|
|
349
345
|
|
|
350
346
|
|
|
351
347
|
# ---------------------------------------------------------------------------
|
|
@@ -405,20 +401,7 @@ def store_response(
|
|
|
405
401
|
"""
|
|
406
402
|
dest = _http_dir() / namespace / f"{key}.json"
|
|
407
403
|
try:
|
|
408
|
-
dest.
|
|
409
|
-
fd, tmp = tempfile.mkstemp(
|
|
410
|
-
dir=dest.parent,
|
|
411
|
-
prefix=".response.",
|
|
412
|
-
suffix=".tmp",
|
|
413
|
-
)
|
|
414
|
-
try:
|
|
415
|
-
os.close(fd)
|
|
416
|
-
tmp_path = Path(tmp)
|
|
417
|
-
tmp_path.write_bytes(data)
|
|
418
|
-
tmp_path.replace(dest)
|
|
419
|
-
except BaseException:
|
|
420
|
-
Path(tmp).unlink(missing_ok=True)
|
|
421
|
-
raise
|
|
404
|
+
_atomic_write(dest, ".response.", lambda tmp_path: tmp_path.write_bytes(data))
|
|
422
405
|
except OSError:
|
|
423
406
|
logging.debug("Failed to cache HTTP response: %s/%s.", namespace, key)
|
|
424
407
|
return None
|
|
@@ -478,25 +461,14 @@ def clear_http_cache(
|
|
|
478
461
|
if not http_root.is_dir():
|
|
479
462
|
return 0, 0
|
|
480
463
|
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
continue
|
|
490
|
-
logging.debug("Purging cached response: %s", entry.path)
|
|
491
|
-
try:
|
|
492
|
-
bytes_freed += entry.size
|
|
493
|
-
entry.path.unlink()
|
|
494
|
-
files_deleted += 1
|
|
495
|
-
except OSError:
|
|
496
|
-
logging.debug("Failed to remove %s.", entry.path)
|
|
497
|
-
|
|
498
|
-
_prune_empty_dirs(http_root)
|
|
499
|
-
return files_deleted, bytes_freed
|
|
464
|
+
return _purge(
|
|
465
|
+
http_cache_info(),
|
|
466
|
+
http_root,
|
|
467
|
+
keep=lambda entry: (
|
|
468
|
+
(namespace is not None and entry.namespace != namespace)
|
|
469
|
+
or _is_fresh(entry, max_age_days)
|
|
470
|
+
),
|
|
471
|
+
)
|
|
500
472
|
|
|
501
473
|
|
|
502
474
|
# ---------------------------------------------------------------------------
|
|
@@ -528,20 +500,11 @@ def store_config(
|
|
|
528
500
|
"""
|
|
529
501
|
dest = _config_dir() / tool_name / filename
|
|
530
502
|
try:
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
suffix=".tmp",
|
|
503
|
+
_atomic_write(
|
|
504
|
+
dest,
|
|
505
|
+
f".{filename}.",
|
|
506
|
+
lambda tmp_path: tmp_path.write_text(content, encoding="UTF-8"),
|
|
536
507
|
)
|
|
537
|
-
try:
|
|
538
|
-
os.close(fd)
|
|
539
|
-
tmp_path = Path(tmp)
|
|
540
|
-
tmp_path.write_text(content, encoding="UTF-8")
|
|
541
|
-
tmp_path.replace(dest)
|
|
542
|
-
except BaseException:
|
|
543
|
-
Path(tmp).unlink(missing_ok=True)
|
|
544
|
-
raise
|
|
545
508
|
except OSError:
|
|
546
509
|
logging.debug("Failed to cache config for %s.", tool_name)
|
|
547
510
|
return None
|
|
@@ -592,21 +555,64 @@ def clear_config_cache(
|
|
|
592
555
|
if not config_root.is_dir():
|
|
593
556
|
return 0, 0
|
|
594
557
|
|
|
558
|
+
return _purge(
|
|
559
|
+
config_cache_info(),
|
|
560
|
+
config_root,
|
|
561
|
+
keep=lambda entry: tool is not None and entry.tool != tool,
|
|
562
|
+
)
|
|
563
|
+
|
|
564
|
+
|
|
565
|
+
def _is_fresh(
|
|
566
|
+
entry: CacheEntry | HttpCacheEntry | ConfigCacheEntry,
|
|
567
|
+
max_age_days: int | None,
|
|
568
|
+
) -> bool:
|
|
569
|
+
"""Whether *entry* is younger than the age cutoff.
|
|
570
|
+
|
|
571
|
+
A `None` cutoff keeps nothing: age-unfiltered clears delete every entry
|
|
572
|
+
the caller's other filters matched.
|
|
573
|
+
"""
|
|
574
|
+
if max_age_days is None:
|
|
575
|
+
return False
|
|
576
|
+
return entry.mtime >= time.time() - max_age_days * 86400
|
|
577
|
+
|
|
578
|
+
|
|
579
|
+
def _purge(
|
|
580
|
+
entries: list[CacheEntry] | list[HttpCacheEntry] | list[ConfigCacheEntry],
|
|
581
|
+
root: Path,
|
|
582
|
+
*,
|
|
583
|
+
keep: Callable[[Any], bool],
|
|
584
|
+
sidecars: bool = False,
|
|
585
|
+
) -> tuple[int, int]:
|
|
586
|
+
"""Delete the cache *entries* not spared by the *keep* predicate.
|
|
587
|
+
|
|
588
|
+
Shared delete loop behind {func}`clear_cache`, {func}`clear_http_cache`,
|
|
589
|
+
and {func}`clear_config_cache`. Empty parent directories under *root* are
|
|
590
|
+
pruned afterwards.
|
|
591
|
+
|
|
592
|
+
:param entries: Candidate entries from one of the `*_cache_info()` listers.
|
|
593
|
+
:param root: The cache subtree the entries live in.
|
|
594
|
+
:param keep: Entries for which this returns `True` are left untouched.
|
|
595
|
+
:param sidecars: Also remove each entry's `.sha256` sidecar (binary cache).
|
|
596
|
+
:return: Tuple of (files_deleted, bytes_freed).
|
|
597
|
+
"""
|
|
595
598
|
files_deleted = 0
|
|
596
599
|
bytes_freed = 0
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
if tool is not None and entry.tool != tool:
|
|
600
|
+
for entry in entries:
|
|
601
|
+
if keep(entry):
|
|
600
602
|
continue
|
|
601
|
-
logging.debug("Purging
|
|
603
|
+
logging.debug("Purging cache entry: %s", entry.path)
|
|
602
604
|
try:
|
|
603
605
|
bytes_freed += entry.size
|
|
604
606
|
entry.path.unlink()
|
|
607
|
+
if sidecars:
|
|
608
|
+
sidecar = entry.path.with_suffix(entry.path.suffix + ".sha256")
|
|
609
|
+
if sidecar.is_file():
|
|
610
|
+
sidecar.unlink()
|
|
605
611
|
files_deleted += 1
|
|
606
612
|
except OSError:
|
|
607
613
|
logging.debug("Failed to remove %s.", entry.path)
|
|
608
614
|
|
|
609
|
-
_prune_empty_dirs(
|
|
615
|
+
_prune_empty_dirs(root)
|
|
610
616
|
return files_deleted, bytes_freed
|
|
611
617
|
|
|
612
618
|
|
|
@@ -102,7 +102,7 @@ of this code *and* adding a new dependency — more complexity, not less.
|
|
|
102
102
|
Related modules
|
|
103
103
|
^^^^^^^^^^^^^^^
|
|
104
104
|
|
|
105
|
-
- `
|
|
105
|
+
- `prepare_release.py` orchestrates the full release preparation
|
|
106
106
|
across changelog, citation, and workflow files, delegating
|
|
107
107
|
changelog operations to this module.
|
|
108
108
|
- `metadata.py` handles version bump eligibility checks and
|
|
@@ -124,6 +124,7 @@ from packaging.version import Version
|
|
|
124
124
|
|
|
125
125
|
from .git_ops import get_all_version_tags, get_tag_date
|
|
126
126
|
from .github.actions import AnnotationLevel, emit_annotation
|
|
127
|
+
from .github.pr_body import render_template
|
|
127
128
|
from .github.releases import (
|
|
128
129
|
GitHubRelease,
|
|
129
130
|
GitHubReleasesUnavailable,
|
|
@@ -292,9 +293,6 @@ class Changelog:
|
|
|
292
293
|
if not self.current_version:
|
|
293
294
|
return self.content.rstrip()
|
|
294
295
|
|
|
295
|
-
# Lazy import to avoid circular dependency: pr_body → metadata → changelog.
|
|
296
|
-
from .github.pr_body import render_template
|
|
297
|
-
|
|
298
296
|
elements = self.decompose_version(self.current_version)
|
|
299
297
|
|
|
300
298
|
# Idempotent: skip if an unreleased section already exists.
|
|
@@ -350,9 +348,6 @@ class Changelog:
|
|
|
350
348
|
if not self.current_version:
|
|
351
349
|
return False
|
|
352
350
|
|
|
353
|
-
# Lazy import to avoid circular dependency: pr_body → metadata → changelog.
|
|
354
|
-
from .github.pr_body import render_template
|
|
355
|
-
|
|
356
351
|
elements = self.decompose_version(self.current_version)
|
|
357
352
|
if not elements.version:
|
|
358
353
|
return False
|
|
@@ -488,9 +483,6 @@ class Changelog:
|
|
|
488
483
|
lower_version = v
|
|
489
484
|
break
|
|
490
485
|
|
|
491
|
-
# Lazy import to avoid circular dependency: pr_body → metadata → changelog.
|
|
492
|
-
from .github.pr_body import render_template
|
|
493
|
-
|
|
494
486
|
compare_base = f"v{lower_version}" if lower_version else "v0.0.0"
|
|
495
487
|
elements = VersionElements(
|
|
496
488
|
compare_url=f"{repo_url}/compare/{compare_base}...v{version}",
|
|
@@ -687,8 +679,6 @@ def build_release_admonition(
|
|
|
687
679
|
links.append(f"[{GITHUB_LABEL}]({github_url})")
|
|
688
680
|
if not links:
|
|
689
681
|
return ""
|
|
690
|
-
# Lazy import to avoid circular dependency: pr_body → metadata → changelog.
|
|
691
|
-
from .github.pr_body import render_template
|
|
692
682
|
|
|
693
683
|
platforms = " and ".join(links)
|
|
694
684
|
verb = FIRST_AVAILABLE_VERB if first_on_all else AVAILABLE_VERB
|
|
@@ -718,8 +708,6 @@ def build_unavailable_admonition(
|
|
|
718
708
|
names.append(GITHUB_LABEL)
|
|
719
709
|
if not names:
|
|
720
710
|
return ""
|
|
721
|
-
# Lazy import to avoid circular dependency: pr_body → metadata → changelog.
|
|
722
|
-
from .github.pr_body import render_template
|
|
723
711
|
|
|
724
712
|
platforms = " and ".join(names)
|
|
725
713
|
return render_template(
|
|
@@ -1133,9 +1121,6 @@ def lint_changelog_dates(
|
|
|
1133
1121
|
# decomposing and re-rendering an already-correct section is a
|
|
1134
1122
|
# no-op.
|
|
1135
1123
|
if fix:
|
|
1136
|
-
# Lazy import to avoid circular dependency: pr_body → metadata → changelog.
|
|
1137
|
-
from .github.pr_body import render_template
|
|
1138
|
-
|
|
1139
1124
|
for version, _date in releases:
|
|
1140
1125
|
elements = changelog.decompose_version(version)
|
|
1141
1126
|
|
|
@@ -1235,3 +1220,48 @@ def lint_changelog_dates(
|
|
|
1235
1220
|
if fix and modified:
|
|
1236
1221
|
return 0
|
|
1237
1222
|
return 1 if has_mismatch else 0
|
|
1223
|
+
|
|
1224
|
+
|
|
1225
|
+
def build_expected_body(
|
|
1226
|
+
changelog: Changelog,
|
|
1227
|
+
version: str,
|
|
1228
|
+
*,
|
|
1229
|
+
admonition_override: str | None = None,
|
|
1230
|
+
) -> str:
|
|
1231
|
+
"""Build the expected release body from the changelog.
|
|
1232
|
+
|
|
1233
|
+
Decomposes the changelog section into discrete elements and renders
|
|
1234
|
+
them through the `github-releases` template. This allows the
|
|
1235
|
+
GitHub release body to include a different subset of elements than
|
|
1236
|
+
the `release-notes` template used for `changelog.md` entries.
|
|
1237
|
+
|
|
1238
|
+
:param changelog: Parsed changelog instance.
|
|
1239
|
+
:param version: Version string (e.g. `1.2.3`).
|
|
1240
|
+
:param admonition_override: If provided, replaces the
|
|
1241
|
+
`availability_admonition` from the changelog. Used by
|
|
1242
|
+
`release_notes_with_admonition` to inject a pre-computed
|
|
1243
|
+
admonition at release time.
|
|
1244
|
+
:return: The rendered release body, or empty string if the
|
|
1245
|
+
version has no changelog section.
|
|
1246
|
+
"""
|
|
1247
|
+
elements = changelog.decompose_version(version)
|
|
1248
|
+
if (
|
|
1249
|
+
not elements.changes
|
|
1250
|
+
and not elements.availability_admonition
|
|
1251
|
+
and not elements.development_warning
|
|
1252
|
+
and not elements.editorial_admonition
|
|
1253
|
+
and not elements.yanked_admonition
|
|
1254
|
+
):
|
|
1255
|
+
return ""
|
|
1256
|
+
|
|
1257
|
+
if admonition_override is not None:
|
|
1258
|
+
elements.availability_admonition = admonition_override
|
|
1259
|
+
# Extract tag range from compare URL (e.g. "v1.1.0...v2.0.0").
|
|
1260
|
+
tag_range = (
|
|
1261
|
+
elements.compare_url.rsplit("/compare/", 1)[-1] if elements.compare_url else ""
|
|
1262
|
+
)
|
|
1263
|
+
return render_template(
|
|
1264
|
+
"github-releases",
|
|
1265
|
+
**asdict(elements),
|
|
1266
|
+
tag_range=tag_range,
|
|
1267
|
+
)
|