repomatic 6.30.0__tar.gz → 7.0.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-6.30.0 → repomatic-7.0.0}/PKG-INFO +7 -6
- {repomatic-6.30.0 → repomatic-7.0.0}/pyproject.toml +30 -16
- {repomatic-6.30.0 → repomatic-7.0.0}/readme.md +3 -2
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/__init__.py +2 -2
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/changelog.py +14 -1
- repomatic-7.0.0/repomatic/checksums.py +127 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/cli.py +496 -220
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/config.py +81 -2
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/data/_release-engine.yaml +26 -18
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/data/agent-sphinx-docs.md +1 -1
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/data/autofix.yaml +212 -66
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/data/changelog.yaml +18 -18
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/data/debug.yaml +3 -3
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/data/docs.yaml +7 -7
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/data/labeller-content-based.yaml +0 -1
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/data/labeller-file-based.yaml +0 -1
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/data/labels.yaml +11 -11
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/data/lint.yaml +26 -23
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/data/pytest.toml +0 -4
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/data/release.yaml +4 -16
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/data/ruff.toml +7 -0
- repomatic-7.0.0/repomatic/data/skill-babysit-ci.md +245 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/data/skill-repomatic-audit.md +3 -4
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/data/skill-repomatic-changelog.md +1 -1
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/data/skill-repomatic-deps.md +2 -2
- repomatic-7.0.0/repomatic/data/skill-repomatic-ship.md +150 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/data/tests.yaml +23 -37
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/data/unsubscribe.yaml +2 -2
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/data/zizmor.yaml +1 -1
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/deps_graph.py +180 -77
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/git_ops.py +151 -7
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/github/matrix.py +1 -1
- repomatic-7.0.0/repomatic/github/releases.py +408 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/github/token.py +12 -47
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/github/unsubscribe.py +7 -14
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/github/workflow_sync.py +11 -10
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/init_project.py +13 -103
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/lint_repo.py +67 -7
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/metadata.py +116 -111
- repomatic-7.0.0/repomatic/npm.py +89 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/pypi.py +1 -1
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/registry.py +10 -10
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/release_prep.py +25 -75
- repomatic-7.0.0/repomatic/sync_ops.py +886 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/templates/fix-changelog.md +3 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/templates/fix-vulnerable-deps.md +7 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/templates/setup-guide-dependabot.md +2 -2
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/templates/setup-guide-token.md +4 -5
- repomatic-7.0.0/repomatic/templates/sync-action-pins.md +18 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/templates/sync-repomatic.md +5 -0
- repomatic-7.0.0/repomatic/templates/sync-tool-versions.md +18 -0
- repomatic-7.0.0/repomatic/templates/sync-workflow-pins.md +18 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/templates/update-docs.md +8 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/test_matrix.py +6 -7
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/tool_runner.py +415 -189
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/uv.py +333 -118
- repomatic-7.0.0/repomatic/version_sync.py +482 -0
- repomatic-6.30.0/repomatic/checksums.py +0 -181
- repomatic-6.30.0/repomatic/data/renovate.json5 +0 -202
- repomatic-6.30.0/repomatic/data/renovate.yaml +0 -138
- repomatic-6.30.0/repomatic/data/skill-babysit-ci.md +0 -246
- repomatic-6.30.0/repomatic/data/skill-repomatic-ship.md +0 -144
- repomatic-6.30.0/repomatic/github/releases.py +0 -141
- repomatic-6.30.0/repomatic/renovate.py +0 -358
- repomatic-6.30.0/repomatic/templates/renovate-migration.md +0 -13
- {repomatic-6.30.0 → repomatic-7.0.0}/license +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/__main__.py +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/binary.py +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/broken_links.py +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/cache.py +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/data/__init__.py +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/data/action-publish-pypi.yaml +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/data/agent-grunt-qa.md +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/data/agent-qa-engineer.md +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/data/autolock.yaml +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/data/awesome_template/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/data/awesome_template/.github/ISSUE_TEMPLATE/new-link.yaml +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/data/awesome_template/.github/code-of-conduct.md +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/data/awesome_template/.github/contributing.md +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/data/awesome_template/.github/contributing.zh.md +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/data/awesome_template/.github/funding.yml +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/data/awesome_template/.github/pull_request_template.md +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/data/awesome_template/__init__.py +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/data/awesome_template/license +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/data/bumpversion.toml +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/data/cancel-runs.yaml +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/data/codecov.yaml +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/data/labels.toml +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/data/lychee.toml +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/data/mdformat.toml +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/data/mypy.toml +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/data/skill-av-false-positive.md +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/data/skill-awesome-triage.md +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/data/skill-benchmark-update.md +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/data/skill-brand-assets.md +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/data/skill-file-bug-report.md +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/data/skill-repomatic-init.md +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/data/skill-repomatic-topics.md +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/data/skill-sphinx-docs-sync.md +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/data/skill-translation-sync.md +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/data/skill-upstream-audit.md +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/data/typos.toml +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/data/uv.toml +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/data/yamllint.yaml +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/github/__init__.py +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/github/actions.py +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/github/advisories.py +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/github/dev_release.py +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/github/gh.py +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/github/issue.py +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/github/pr.py +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/github/pr_body.py +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/github/release_sync.py +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/github/status.py +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/images.py +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/mailmap.py +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/myst_converter.py +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/myst_docstrings.py +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/py.typed +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/pyproject.py +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/rst_to_myst.py +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/sponsor.py +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/templates/__init__.py +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/templates/available-admonition.md +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/templates/broken-links-issue.md +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/templates/bump-version.md +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/templates/detect-squash-merge.md +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/templates/development-warning.md +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/templates/fix-typos.md +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/templates/format-images.md +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/templates/format-json.md +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/templates/format-markdown.md +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/templates/format-pyproject.md +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/templates/format-python.md +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/templates/format-shell.md +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/templates/generated-footer.md +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/templates/github-releases.md +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/templates/immutable-releases.md +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/templates/pr-metadata.md.noformat +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/templates/prepare-release.md +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/templates/refresh-tip.md +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/templates/release-notes.md +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/templates/release-sync-report.md +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/templates/setup-guide-branch-ruleset.md +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/templates/setup-guide-fork-pr-approval.md +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/templates/setup-guide-pages-source.md +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/templates/setup-guide-pypi-trusted-publisher.md +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/templates/setup-guide-verify.md +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/templates/setup-guide-virustotal.md +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/templates/setup-guide.md +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/templates/sync-bumpversion.md +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/templates/sync-gitignore.md +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/templates/sync-mailmap.md +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/templates/sync-uv-lock.md +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/templates/unavailable-admonition.md +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/templates/unsubscribe-phase1.md +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/templates/unsubscribe-phase2.md +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/templates/update-deps-graph.md +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/templates/yanked-admonition.md +0 -0
- {repomatic-6.30.0 → repomatic-7.0.0}/repomatic/virustotal.py +0 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: repomatic
|
|
3
|
-
Version:
|
|
3
|
+
Version: 7.0.0
|
|
4
4
|
Summary: 🏭 Automate repository maintenance, releases, and CI/CD workflows
|
|
5
|
-
Keywords: changelog-formatter,dependabot-alternative,github-actions,github-labels,github-workflow,gitignore,mailmap,mypy,nuitka,python-automation,release-automation,
|
|
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
|
|
7
7
|
Author-email: Kevin Deldycke <kevin@deldycke.com>
|
|
8
8
|
License-Expression: GPL-2.0-or-later
|
|
@@ -43,13 +43,13 @@ Classifier: Topic :: Text Processing :: Markup :: HTML
|
|
|
43
43
|
Classifier: Topic :: Text Processing :: Markup :: Markdown
|
|
44
44
|
Classifier: Topic :: Utilities
|
|
45
45
|
Classifier: Typing :: Typed
|
|
46
|
+
Requires-Dist: arrow>=1.3
|
|
46
47
|
Requires-Dist: backports-strenum>=1 ; python_full_version < '3.11'
|
|
47
48
|
Requires-Dist: boltons>=25
|
|
48
49
|
Requires-Dist: click-extra>=8.1
|
|
49
50
|
Requires-Dist: extra-platforms>=12.0.2
|
|
50
51
|
Requires-Dist: packaging>=17
|
|
51
52
|
Requires-Dist: py-walk>=0.3.1
|
|
52
|
-
Requires-Dist: pydriller>=2
|
|
53
53
|
Requires-Dist: pyproject-metadata>=0.9
|
|
54
54
|
Requires-Dist: pyyaml>=6.0.3
|
|
55
55
|
Requires-Dist: tomlrt>=1.7.6
|
|
@@ -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/
|
|
61
|
+
Project-URL: Download, https://github.com/kdeldycke/repomatic/releases/tag/v7.0.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
|
|
@@ -88,7 +88,8 @@ A Python CLI and `pyproject.toml` configuration that let you **release Python pa
|
|
|
88
88
|
- Cross-platform binary compilation (Linux / macOS / Windows, x86_64 / arm64)
|
|
89
89
|
- Formatting autofix for Python, Markdown, JSON, Shell, and typos
|
|
90
90
|
- Linting: Python types with mypy, YAML, GitHub Actions, workflow security, URLs, secrets, and Awesome lists
|
|
91
|
-
- Synchronization of `uv.lock`,
|
|
91
|
+
- Synchronization of `uv.lock`, GitHub Action pins, workflow version literals, and `repomatic run` tool versions with configurable stabilization cooldowns
|
|
92
|
+
- Synchronization of `.gitignore`, `.mailmap`, and Mermaid dependency graph
|
|
92
93
|
- Label management with file-based and content-based rules
|
|
93
94
|
- Inactive issue locking
|
|
94
95
|
- Static image optimization
|
|
@@ -100,7 +101,7 @@ A Python CLI and `pyproject.toml` configuration that let you **release Python pa
|
|
|
100
101
|
- [18 third-party GitHub Actions replaced](https://kdeldycke.github.io/repomatic/security.html#third-party-action-minimization) by internal CLI commands and SHA-256-verified binary downloads, keeping the supply chain attack surface minimal
|
|
101
102
|
- [8 Python linters and formatters](https://kdeldycke.github.io/repomatic/security.html#ruff-consolidation) (pylint, black, isort, pyupgrade, pydocstyle, pycln, docformatter, blacken-docs) consolidated into ruff
|
|
102
103
|
- [5 packaging and install tools](https://kdeldycke.github.io/repomatic/security.html#uv-consolidation) (poetry, build, twine, check-wheel-contents, pip-audit) consolidated into uv
|
|
103
|
-
- All `uses:` references [pinned to full commit SHAs](https://kdeldycke.github.io/repomatic/security.html#supply-chain-security)
|
|
104
|
+
- All `uses:` references [pinned to full commit SHAs](https://kdeldycke.github.io/repomatic/security.html#supply-chain-security) with stabilization windows before adopting new versions, managed entirely by self-hosted sync jobs
|
|
104
105
|
- [SLSA provenance attestations](https://kdeldycke.github.io/repomatic/security.html#supply-chain-security) on every release artifact (wheels and compiled binaries)
|
|
105
106
|
- [VirusTotal scanning](https://kdeldycke.github.io/repomatic/security.html#av-false-positive-submissions) of compiled binaries to seed AV vendor databases and reduce false positives
|
|
106
107
|
- [Trusted Publishing](https://kdeldycke.github.io/repomatic/workflows.html#github-workflows-release-yaml-jobs) for PyPI uploads: no long-lived tokens stored as secrets
|
|
@@ -5,7 +5,7 @@ requires = [ "uv-build>=0.9" ]
|
|
|
5
5
|
[project]
|
|
6
6
|
# Docs: https://packaging.python.org/en/latest/guides/writing-pyproject-toml/
|
|
7
7
|
name = "repomatic"
|
|
8
|
-
version = "
|
|
8
|
+
version = "7.0.0"
|
|
9
9
|
description = "🏭 Automate repository maintenance, releases, and CI/CD workflows"
|
|
10
10
|
readme = "readme.md"
|
|
11
11
|
keywords = [
|
|
@@ -20,7 +20,6 @@ keywords = [
|
|
|
20
20
|
"nuitka",
|
|
21
21
|
"python-automation",
|
|
22
22
|
"release-automation",
|
|
23
|
-
"renovate",
|
|
24
23
|
"repository-automation",
|
|
25
24
|
"repository-management",
|
|
26
25
|
"reusable-workflows",
|
|
@@ -75,14 +74,19 @@ classifiers = [
|
|
|
75
74
|
"Typing :: Typed",
|
|
76
75
|
]
|
|
77
76
|
dependencies = [
|
|
77
|
+
# arrow parses the RFC 3339 timestamps uv emits (nanosecond fractional seconds
|
|
78
|
+
# + a Z suffix, which Python 3.10's stdlib fromisoformat rejects) and renders the
|
|
79
|
+
# relative-time hints in sync-uv-lock tables and the unsubscribe report through
|
|
80
|
+
# its .humanize(). whenever was the prior parser but has no humanizer; switch back
|
|
81
|
+
# to it once one lands: https://github.com/ariebovenberg/whenever/discussions/277
|
|
82
|
+
"arrow>=1.3",
|
|
78
83
|
# Provides enum.StrEnum for Python < 3.11; all versions expose the class.
|
|
79
84
|
"backports-strenum>=1; python_version<'3.11'",
|
|
80
85
|
# boltons 25.0.0 dropped Python 3.9, matching our requires-python >= 3.10.
|
|
81
86
|
"boltons>=25",
|
|
82
87
|
# 8.1.0 is the first release carrying the APIs repomatic uses: the `test-suite`
|
|
83
|
-
# engine (renamed from `test-plan`)
|
|
84
|
-
# `NORMALIZE_KEYS_METADATA_KEY` schema-metadata constants
|
|
85
|
-
# `@sort_by_option` / `ColumnSpec` `columns=` table registry.
|
|
88
|
+
# engine (renamed from `test-plan`) and the `CONFIG_PATH_METADATA_KEY` /
|
|
89
|
+
# `NORMALIZE_KEYS_METADATA_KEY` schema-metadata constants.
|
|
86
90
|
"click-extra>=8.1",
|
|
87
91
|
# extra-platforms 12.0.2 reimplemented is_macos() with sys.platform, avoiding
|
|
88
92
|
# the platform.platform() shell-out to ``cmd /c ver`` on Windows that broke
|
|
@@ -95,8 +99,6 @@ dependencies = [
|
|
|
95
99
|
# XXX Replace py-walk with wcmatch once the latter supports gitignore files:
|
|
96
100
|
# https://github.com/facelessuser/wcmatch/issues/226
|
|
97
101
|
"py-walk>=0.3.1",
|
|
98
|
-
# pydriller 2.0 redesigned the API; Git, Commit, and Repository are core 2.x classes.
|
|
99
|
-
"pydriller>=2",
|
|
100
102
|
# pyproject-metadata 0.9 added PEP 639 (license expressions) and PEP 685 (extras
|
|
101
103
|
# normalization); our StandardMetadata.from_pyproject() call benefits from these.
|
|
102
104
|
"pyproject-metadata>=0.9",
|
|
@@ -120,7 +122,7 @@ dependencies = [
|
|
|
120
122
|
]
|
|
121
123
|
urls.Changelog = "https://github.com/kdeldycke/repomatic/blob/main/changelog.md"
|
|
122
124
|
urls.Documentation = "https://kdeldycke.github.io/repomatic"
|
|
123
|
-
urls.Download = "https://github.com/kdeldycke/repomatic/releases/tag/
|
|
125
|
+
urls.Download = "https://github.com/kdeldycke/repomatic/releases/tag/v7.0.0"
|
|
124
126
|
urls.Funding = "https://github.com/sponsors/kdeldycke"
|
|
125
127
|
urls.Homepage = "https://github.com/kdeldycke/repomatic"
|
|
126
128
|
urls.Issues = "https://github.com/kdeldycke/repomatic/issues"
|
|
@@ -201,7 +203,7 @@ exclude-newer = "1 week"
|
|
|
201
203
|
# "0 day" span. click-extra is held at its 8.1.0 release date so the lock adopts
|
|
202
204
|
# it before the 1-week cooldown elapses; sync-uv-lock prunes this entry once
|
|
203
205
|
# 8.1.0 ages past `exclude-newer`.
|
|
204
|
-
exclude-newer-package = {
|
|
206
|
+
exclude-newer-package = { repomatic = "0 day" }
|
|
205
207
|
# Package is at root level, not in "./src/".
|
|
206
208
|
build-backend.module-root = ""
|
|
207
209
|
|
|
@@ -214,7 +216,7 @@ copyright = "Kevin Deldycke <kevin@deldycke.com> and contributors. Distributed u
|
|
|
214
216
|
file-description = "🏭 Automate repository maintenance, releases, and CI/CD workflows"
|
|
215
217
|
# Numeric only: Nuitka rejects PEP 440 .devN suffixes. Kept in sync with the
|
|
216
218
|
# package version by the dedicated [tool.bumpversion] rule that strips the suffix.
|
|
217
|
-
file-version = "
|
|
219
|
+
file-version = "7.0.0"
|
|
218
220
|
include-data-dir = [
|
|
219
221
|
"repomatic/data/awesome_template=repomatic/data/awesome_template",
|
|
220
222
|
]
|
|
@@ -232,7 +234,7 @@ include-package-data = [ "click_extra" ]
|
|
|
232
234
|
linux-icon = "docs/assets/icon.png"
|
|
233
235
|
macos-app-icon = "docs/assets/icon.icns"
|
|
234
236
|
product-name = "Repomatic"
|
|
235
|
-
product-version = "
|
|
237
|
+
product-version = "7.0.0"
|
|
236
238
|
windows-icon-from-ico = "docs/assets/icon.ico"
|
|
237
239
|
|
|
238
240
|
[tool.ruff]
|
|
@@ -243,6 +245,13 @@ show-fixes = true
|
|
|
243
245
|
# Enable reformatting of code snippets in docstrings.
|
|
244
246
|
# https://docs.astral.sh/ruff/formatter/#docstring-formatting
|
|
245
247
|
format.docstring-code-format = true
|
|
248
|
+
# PLW1514: `open` and friends called without an explicit `encoding` argument.
|
|
249
|
+
# Windows defaults text I/O to cp1252, so a bare `open()`, `read_text()` or
|
|
250
|
+
# `write_text()` breaks on non-ASCII content, and only on Windows runners.
|
|
251
|
+
# Preview rule; its type inference misses unannotated `Path` locals, so
|
|
252
|
+
# PEP 597's `PYTHONWARNDEFAULTENCODING=1` remains the complete runtime net.
|
|
253
|
+
# See: https://docs.astral.sh/ruff/rules/unspecified-encoding/
|
|
254
|
+
lint.extend-select = [ "PLW1514" ]
|
|
246
255
|
# D400: First line should end with a period.
|
|
247
256
|
# Allows docstrings to end up with any punctuation, not just a period.
|
|
248
257
|
# See: https://github.com/astral-sh/ruff/issues/1858#issuecomment-1382640623
|
|
@@ -305,10 +314,7 @@ pretty = true
|
|
|
305
314
|
warn_unused_configs = true
|
|
306
315
|
overrides = [
|
|
307
316
|
{ module = [
|
|
308
|
-
"bumpversion.*",
|
|
309
|
-
"gitdb.*",
|
|
310
317
|
"py_walk.*",
|
|
311
|
-
"pydriller.*",
|
|
312
318
|
"vt",
|
|
313
319
|
], ignore_missing_imports = true },
|
|
314
320
|
]
|
|
@@ -319,7 +325,6 @@ addopts = [
|
|
|
319
325
|
"--cov",
|
|
320
326
|
"--cov-report=term",
|
|
321
327
|
"--numprocesses=auto",
|
|
322
|
-
"--dist=loadgroup",
|
|
323
328
|
]
|
|
324
329
|
# https://docs.pytest.org/en/latest/customize.html#pyproject-toml
|
|
325
330
|
markers = [
|
|
@@ -335,7 +340,7 @@ run.source = [ "repomatic" ]
|
|
|
335
340
|
report.precision = 2
|
|
336
341
|
|
|
337
342
|
[tool.bumpversion]
|
|
338
|
-
current_version = "
|
|
343
|
+
current_version = "7.0.0"
|
|
339
344
|
# Parse versions with an optional .devN suffix (PEP 440).
|
|
340
345
|
parse = "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)(\\.dev(?P<dev>\\d+))?"
|
|
341
346
|
serialize = [
|
|
@@ -419,6 +424,14 @@ exclude = [
|
|
|
419
424
|
"^https://www\\.npmjs\\.com/package/.*$",
|
|
420
425
|
# star-history.com fragments are JS-rendered and invisible to lychee.
|
|
421
426
|
"^https://star-history\\.com/.*$",
|
|
427
|
+
# githubstatus.com returns 405 to HEAD requests from bots.
|
|
428
|
+
"githubstatus\\.com",
|
|
429
|
+
# Local intra-docs heading fragments are Sphinx cross-references, validated
|
|
430
|
+
# at doc build time via `myst_heading_anchors`. Lychee's GitHub-style slugger
|
|
431
|
+
# strips dots (`cache.dir` → `cachedir`) and cannot see MyST `(target)=`
|
|
432
|
+
# anchors, so it would false-positive links that resolve fine in the rendered
|
|
433
|
+
# docs. Anchored to `file://` so external `.../docs/*.md#` URLs stay checked.
|
|
434
|
+
"^file://.*/docs/[\\w.-]+\\.md#",
|
|
422
435
|
]
|
|
423
436
|
exclude_path = [
|
|
424
437
|
# Template files contain $variable placeholders that are not real URLs.
|
|
@@ -435,5 +448,6 @@ abandoned-versions = [
|
|
|
435
448
|
"6.0.0",
|
|
436
449
|
"6.18.0",
|
|
437
450
|
]
|
|
451
|
+
changelog.archive-location = "./docs/changelog-archive.md"
|
|
438
452
|
exclude = [ "workflows" ]
|
|
439
453
|
pypi-package-history = [ "gha-utils", "repokit" ]
|
|
@@ -21,7 +21,8 @@ A Python CLI and `pyproject.toml` configuration that let you **release Python pa
|
|
|
21
21
|
- Cross-platform binary compilation (Linux / macOS / Windows, x86_64 / arm64)
|
|
22
22
|
- Formatting autofix for Python, Markdown, JSON, Shell, and typos
|
|
23
23
|
- Linting: Python types with mypy, YAML, GitHub Actions, workflow security, URLs, secrets, and Awesome lists
|
|
24
|
-
- Synchronization of `uv.lock`,
|
|
24
|
+
- Synchronization of `uv.lock`, GitHub Action pins, workflow version literals, and `repomatic run` tool versions with configurable stabilization cooldowns
|
|
25
|
+
- Synchronization of `.gitignore`, `.mailmap`, and Mermaid dependency graph
|
|
25
26
|
- Label management with file-based and content-based rules
|
|
26
27
|
- Inactive issue locking
|
|
27
28
|
- Static image optimization
|
|
@@ -33,7 +34,7 @@ A Python CLI and `pyproject.toml` configuration that let you **release Python pa
|
|
|
33
34
|
- [18 third-party GitHub Actions replaced](https://kdeldycke.github.io/repomatic/security.html#third-party-action-minimization) by internal CLI commands and SHA-256-verified binary downloads, keeping the supply chain attack surface minimal
|
|
34
35
|
- [8 Python linters and formatters](https://kdeldycke.github.io/repomatic/security.html#ruff-consolidation) (pylint, black, isort, pyupgrade, pydocstyle, pycln, docformatter, blacken-docs) consolidated into ruff
|
|
35
36
|
- [5 packaging and install tools](https://kdeldycke.github.io/repomatic/security.html#uv-consolidation) (poetry, build, twine, check-wheel-contents, pip-audit) consolidated into uv
|
|
36
|
-
- All `uses:` references [pinned to full commit SHAs](https://kdeldycke.github.io/repomatic/security.html#supply-chain-security)
|
|
37
|
+
- All `uses:` references [pinned to full commit SHAs](https://kdeldycke.github.io/repomatic/security.html#supply-chain-security) with stabilization windows before adopting new versions, managed entirely by self-hosted sync jobs
|
|
37
38
|
- [SLSA provenance attestations](https://kdeldycke.github.io/repomatic/security.html#supply-chain-security) on every release artifact (wheels and compiled binaries)
|
|
38
39
|
- [VirusTotal scanning](https://kdeldycke.github.io/repomatic/security.html#av-false-positive-submissions) of compiled binaries to seed AV vendor databases and reduce false positives
|
|
39
40
|
- [Trusted Publishing](https://kdeldycke.github.io/repomatic/workflows.html#github-workflows-release-yaml-jobs) for PyPI uploads: no long-lived tokens stored as secrets
|
|
@@ -812,6 +812,7 @@ def lint_changelog_dates(
|
|
|
812
812
|
changelog_path: Path,
|
|
813
813
|
package: str | None = None,
|
|
814
814
|
*,
|
|
815
|
+
archive_path: Path | None = None,
|
|
815
816
|
fix: bool = False,
|
|
816
817
|
pypi_package_history: Sequence[str] = (),
|
|
817
818
|
abandoned_versions: Sequence[str] = (),
|
|
@@ -853,6 +854,10 @@ def lint_changelog_dates(
|
|
|
853
854
|
linking to adjacent versions.
|
|
854
855
|
|
|
855
856
|
:param changelog_path: Path to the changelog file.
|
|
857
|
+
:param archive_path: Optional path to a frozen changelog archive. Versions
|
|
858
|
+
documented there are treated as present, suppressing false-positive
|
|
859
|
+
orphan detection (and re-insertion under `fix`) for entries split out
|
|
860
|
+
of the live changelog. Archived dates are not re-validated.
|
|
856
861
|
:param package: PyPI package name. If `None`, auto-detected from
|
|
857
862
|
`pyproject.toml`. If detection fails, falls back to git tags.
|
|
858
863
|
:param fix: If True, fix dates and add admonitions to the file.
|
|
@@ -955,8 +960,16 @@ def lint_changelog_dates(
|
|
|
955
960
|
# from the changelog.
|
|
956
961
|
tag_versions = get_all_version_tags()
|
|
957
962
|
changelog_headings = changelog.extract_all_version_headings()
|
|
963
|
+
# Versions documented in the frozen archive count as present, so entries
|
|
964
|
+
# split out of the live changelog are neither flagged nor re-inserted as
|
|
965
|
+
# orphans.
|
|
966
|
+
archive_headings: set[str] = set()
|
|
967
|
+
if archive_path and archive_path.exists():
|
|
968
|
+
archive_headings = Changelog(
|
|
969
|
+
archive_path.read_text(encoding="UTF-8")
|
|
970
|
+
).extract_all_version_headings()
|
|
958
971
|
all_known = set(pypi_data) | set(github_releases) | set(tag_versions)
|
|
959
|
-
orphans = all_known - changelog_headings
|
|
972
|
+
orphans = all_known - changelog_headings - archive_headings
|
|
960
973
|
if orphans:
|
|
961
974
|
for orphan in sorted(orphans, key=Version):
|
|
962
975
|
logging.warning(
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# Copyright Kevin Deldycke <kevin@deldycke.com> and contributors.
|
|
2
|
+
#
|
|
3
|
+
# This program is Free Software; you can redistribute it and/or
|
|
4
|
+
# modify it under the terms of the GNU General Public License
|
|
5
|
+
# as published by the Free Software Foundation; either version 2
|
|
6
|
+
# of the License, or (at your option) any later version.
|
|
7
|
+
#
|
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
11
|
+
# GNU General Public License for more details.
|
|
12
|
+
#
|
|
13
|
+
# You should have received a copy of the GNU General Public License
|
|
14
|
+
# along with this program; if not, write to the Free Software
|
|
15
|
+
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
16
|
+
|
|
17
|
+
"""Recompute SHA-256 checksums for the binary tool registry.
|
|
18
|
+
|
|
19
|
+
Iterates every `TOOL_REGISTRY` entry with a `binary` spec, downloads each
|
|
20
|
+
platform's release artifact, and rewrites stale hashes in-place in
|
|
21
|
+
`tool_runner.py` (alongside the `VERSIONS` stamps). Driven by
|
|
22
|
+
`repomatic update-checksums` and, with a version override, by
|
|
23
|
+
`sync-tool-versions` so a version bump and its matching checksums land in one
|
|
24
|
+
pass.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
from __future__ import annotations
|
|
28
|
+
|
|
29
|
+
import hashlib
|
|
30
|
+
import logging
|
|
31
|
+
import re
|
|
32
|
+
import sys
|
|
33
|
+
from pathlib import Path
|
|
34
|
+
from urllib.request import Request, urlopen
|
|
35
|
+
|
|
36
|
+
from click_extra import progressbar
|
|
37
|
+
|
|
38
|
+
from .tool_runner import TOOL_REGISTRY
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _download_sha256(url: str) -> str:
|
|
42
|
+
"""Download a URL and return its SHA-256 hex digest.
|
|
43
|
+
|
|
44
|
+
:param url: The URL to download.
|
|
45
|
+
:return: Lowercase hex SHA-256 digest of the response body.
|
|
46
|
+
"""
|
|
47
|
+
request = Request(url)
|
|
48
|
+
with urlopen(request) as response:
|
|
49
|
+
digest = hashlib.sha256(response.read()).hexdigest()
|
|
50
|
+
logging.debug(f"SHA-256 of {url}: {digest}")
|
|
51
|
+
return digest
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def update_registry_checksums(
|
|
55
|
+
tool_runner_path: Path,
|
|
56
|
+
version_overrides: dict[str, str] | None = None,
|
|
57
|
+
) -> list[tuple[str, str, str]]:
|
|
58
|
+
"""Recompute binary checksums and version stamps in `tool_runner.py`.
|
|
59
|
+
|
|
60
|
+
Iterates every `TOOL_REGISTRY` entry with a `binary` spec, downloads each
|
|
61
|
+
platform URL, computes its SHA-256, and replaces stale hashes in-place.
|
|
62
|
+
Also reconciles each tool's `VERSIONS` stamp with the version the checksums
|
|
63
|
+
were computed for, the basis of the offline staleness test.
|
|
64
|
+
|
|
65
|
+
:param tool_runner_path: Path to `tool_runner.py`.
|
|
66
|
+
:param version_overrides: Optional mapping of tool name to a version to
|
|
67
|
+
download instead of the in-memory `ToolSpec.version`. `sync-tool-versions`
|
|
68
|
+
passes this so it can bump the version in the source and refresh the
|
|
69
|
+
checksums in a single process: the in-memory registry still holds the
|
|
70
|
+
pre-bump version because the file was edited, not reimported.
|
|
71
|
+
:return: List of `(url, old_hash, new_hash)` for each updated checksum.
|
|
72
|
+
Empty if all checksums are already correct.
|
|
73
|
+
"""
|
|
74
|
+
overrides = version_overrides or {}
|
|
75
|
+
original = tool_runner_path.read_text(encoding="UTF-8")
|
|
76
|
+
content = original
|
|
77
|
+
updated: list[tuple[str, str, str]] = []
|
|
78
|
+
|
|
79
|
+
# Flatten all binary platform entries for progress tracking, resolving each
|
|
80
|
+
# download URL against the override version when one is supplied.
|
|
81
|
+
entries = [
|
|
82
|
+
(
|
|
83
|
+
spec,
|
|
84
|
+
pk,
|
|
85
|
+
tmpl.format(version=overrides.get(spec.name, spec.version)),
|
|
86
|
+
spec.binary.checksums[pk],
|
|
87
|
+
)
|
|
88
|
+
for spec in TOOL_REGISTRY.values()
|
|
89
|
+
if spec.binary is not None
|
|
90
|
+
for pk, tmpl in spec.binary.urls.items()
|
|
91
|
+
]
|
|
92
|
+
|
|
93
|
+
with progressbar(
|
|
94
|
+
entries,
|
|
95
|
+
label="Verifying checksums",
|
|
96
|
+
file=sys.stderr,
|
|
97
|
+
) as items:
|
|
98
|
+
for spec, platform_key, url, old_hash in items:
|
|
99
|
+
logging.info(
|
|
100
|
+
f"Verifying registry checksum for {spec.name} ({platform_key})"
|
|
101
|
+
)
|
|
102
|
+
new_hash = _download_sha256(url)
|
|
103
|
+
|
|
104
|
+
if old_hash != new_hash:
|
|
105
|
+
content = content.replace(old_hash, new_hash)
|
|
106
|
+
updated.append((url, old_hash, new_hash))
|
|
107
|
+
logging.info(f"Updated checksum: {old_hash} -> {new_hash}")
|
|
108
|
+
else:
|
|
109
|
+
logging.info("Checksum unchanged.")
|
|
110
|
+
|
|
111
|
+
# Reconcile each tool's VERSIONS stamp with its target version (idempotent).
|
|
112
|
+
# The key pattern only matches the quoted-string values in `VERSIONS`, never
|
|
113
|
+
# the `ToolSpec(` registry entries or the tuple-keyed `CHECKSUMS` entries.
|
|
114
|
+
for spec in TOOL_REGISTRY.values():
|
|
115
|
+
if spec.binary is None:
|
|
116
|
+
continue
|
|
117
|
+
target = overrides.get(spec.name, spec.version)
|
|
118
|
+
content = re.sub(
|
|
119
|
+
rf'("{re.escape(spec.name)}":\s*)"[^"]*"',
|
|
120
|
+
rf'\g<1>"{target}"',
|
|
121
|
+
content,
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
if content != original:
|
|
125
|
+
tool_runner_path.write_text(content, encoding="UTF-8")
|
|
126
|
+
|
|
127
|
+
return updated
|