template_press 3.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.
- template_press-3.0.0/PKG-INFO +129 -0
- template_press-3.0.0/README.md +106 -0
- template_press-3.0.0/pyproject.toml +225 -0
- template_press-3.0.0/src/template_press/__init__.py +24 -0
- template_press-3.0.0/src/template_press/press_cli.py +50 -0
- template_press-3.0.0/src/template_press/py.typed +0 -0
- template_press-3.0.0/src/template_press/rebrand/__init__.py +0 -0
- template_press-3.0.0/src/template_press/rebrand/cli.py +287 -0
- template_press-3.0.0/src/template_press/rebrand/config.py +67 -0
- template_press-3.0.0/src/template_press/rebrand/discovery.py +109 -0
- template_press-3.0.0/src/template_press/rebrand/doctor.py +97 -0
- template_press-3.0.0/src/template_press/rebrand/engine.py +258 -0
- template_press-3.0.0/src/template_press/rebrand/identity.py +184 -0
- template_press-3.0.0/src/template_press/rebrand/receipt.py +58 -0
- template_press-3.0.0/src/template_press/rebrand/rules.py +87 -0
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: template_press
|
|
3
|
+
Version: 3.0.0
|
|
4
|
+
Summary: Standalone rebrand utility — press a new identity onto an external target repo
|
|
5
|
+
Author: Steve Morin
|
|
6
|
+
Author-email: Steve Morin <steve.morin@gmail.com>
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
Classifier: Development Status :: 4 - Beta
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
14
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
15
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
16
|
+
Requires-Python: >=3.12
|
|
17
|
+
Project-URL: Homepage, https://github.com/smorinlabs/template-press
|
|
18
|
+
Project-URL: Repository, https://github.com/smorinlabs/template-press
|
|
19
|
+
Project-URL: Documentation, https://template-press.readthedocs.io/en/latest/
|
|
20
|
+
Project-URL: Changelog, https://github.com/smorinlabs/template-press/blob/main/CHANGELOG.md
|
|
21
|
+
Project-URL: Issues, https://github.com/smorinlabs/template-press/issues
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
|
|
24
|
+
<!-- ITM-081 — badges. Single horizontal row (decided round 23). -->
|
|
25
|
+
[](https://pypi.org/project/template-press/)
|
|
26
|
+
[](https://pypi.org/project/template-press/)
|
|
27
|
+
[](https://github.com/smorinlabs/template-press/actions/workflows/ci.yml)
|
|
28
|
+
[](https://codecov.io/gh/smorinlabs/template-press)
|
|
29
|
+
[](LICENSE)
|
|
30
|
+
[](https://github.com/astral-sh/ruff)
|
|
31
|
+
[](https://github.com/astral-sh/uv)
|
|
32
|
+
[](https://www.conventionalcommits.org/)
|
|
33
|
+
|
|
34
|
+
# template-press
|
|
35
|
+
|
|
36
|
+
**Press a new identity onto an existing repository.** template-press is a
|
|
37
|
+
standalone command-line utility: you point it at a target repo, it discovers
|
|
38
|
+
and *validates* that repo's current identity, rewrites every occurrence to a
|
|
39
|
+
new identity, and — only after verifying that none of the old identity
|
|
40
|
+
survives — writes a receipt. A wrong or partial run fails loudly instead of
|
|
41
|
+
silently corrupting the target.
|
|
42
|
+
|
|
43
|
+
It is **not** a project template you fork; it is a tool you run against other
|
|
44
|
+
repos, one at a time. The rebrand engine is pure standard library, so the
|
|
45
|
+
installed package has **zero runtime dependencies**.
|
|
46
|
+
|
|
47
|
+
## Install
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
uvx --from template-press press --help # run without installing
|
|
51
|
+
# or
|
|
52
|
+
pip install template-press
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Usage
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
# preview the plan (writes nothing)
|
|
59
|
+
press rebrand --target ../my-repo --config press-answers.toml --dry-run
|
|
60
|
+
|
|
61
|
+
# apply, verify, and write a receipt
|
|
62
|
+
press rebrand --target ../my-repo --config press-answers.toml
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
`press-answers.toml` describes the **destination** identity:
|
|
66
|
+
|
|
67
|
+
```toml
|
|
68
|
+
[answers]
|
|
69
|
+
package_name = "new_pkg"
|
|
70
|
+
repo_name = "new-repo"
|
|
71
|
+
app_name = "newcli"
|
|
72
|
+
author = "Jane Dev"
|
|
73
|
+
email = "jane@example.com"
|
|
74
|
+
owner = "janedev"
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Keep your filled-in `press-answers.toml` out of the target (it is transient
|
|
78
|
+
operator input, not committed state). A repo may commit a
|
|
79
|
+
`press/press-answers.example.toml` placeholder to advertise the field
|
|
80
|
+
shape — copy it, fill it, and pass it via `--config`. It has the same
|
|
81
|
+
`[answers]` fields shown above.
|
|
82
|
+
|
|
83
|
+
The target's **current** identity is read from a committed
|
|
84
|
+
`<target>/press/press-source.toml`. On a first run, `--dry-run` prints a proposed
|
|
85
|
+
source-config from discovery; review it and re-run with `--accept-discovery`
|
|
86
|
+
to write and use it.
|
|
87
|
+
|
|
88
|
+
## How it stays safe
|
|
89
|
+
|
|
90
|
+
- **Config-first identity, discovery as a guard.** The committed source-config
|
|
91
|
+
is authoritative; discovery cross-checks it against the target and *refuses
|
|
92
|
+
to run on a mismatch*, so the press never rewrites the wrong repo.
|
|
93
|
+
- **Verify-then-mark.** After rewriting, a no-leak scan confirms no source
|
|
94
|
+
identity remains. Any leftover ⇒ **exit 1 and no receipt** — a partial
|
|
95
|
+
rebrand is a loud failure, not a false success.
|
|
96
|
+
- **Boundary-safe replacement.** Short tokens (`press`, an owner like `go`)
|
|
97
|
+
match only at word boundaries, so ordinary prose (`compress`, `ongoing`) is
|
|
98
|
+
never touched.
|
|
99
|
+
|
|
100
|
+
## Exit codes
|
|
101
|
+
|
|
102
|
+
The exit code is the contract:
|
|
103
|
+
|
|
104
|
+
| Code | Meaning |
|
|
105
|
+
|------|---------|
|
|
106
|
+
| `0` | Verified — rebrand complete, no source identity remains, receipt written. |
|
|
107
|
+
| `1` | Leaks found after applying. No receipt; restore with `git -C <target> checkout . && git clean -fd`. |
|
|
108
|
+
| `2` | Precondition/config error (missing target, dirty tree, identity mismatch, existing receipt without `--force`). Nothing written. |
|
|
109
|
+
|
|
110
|
+
`--dry-run` exits `0` after printing the plan without touching the target (no receipt).
|
|
111
|
+
|
|
112
|
+
## Documentation
|
|
113
|
+
|
|
114
|
+
- Full docs: <https://template-press.readthedocs.io/>
|
|
115
|
+
- Design contract: [`docs/design/0006-external-target-model.md`](docs/design/0006-external-target-model.md)
|
|
116
|
+
- Agent runbooks: [`press-target`](.claude/skills/press-target/SKILL.md) (drive a
|
|
117
|
+
press) and [`rebrand-matrix`](.claude/skills/rebrand-matrix/SKILL.md) (the
|
|
118
|
+
R1/R2/R3 acceptance matrix)
|
|
119
|
+
|
|
120
|
+
## Contributing
|
|
121
|
+
|
|
122
|
+
See [`AGENTS.md`](AGENTS.md) for the canonical toolchain and verification flow
|
|
123
|
+
(`just setup` → `just check` → commit) and
|
|
124
|
+
[`.github/CONTRIBUTING.md`](.github/CONTRIBUTING.md) for the human contributor
|
|
125
|
+
guide.
|
|
126
|
+
|
|
127
|
+
## License
|
|
128
|
+
|
|
129
|
+
MIT — see [`LICENSE`](LICENSE).
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
<!-- ITM-081 — badges. Single horizontal row (decided round 23). -->
|
|
2
|
+
[](https://pypi.org/project/template-press/)
|
|
3
|
+
[](https://pypi.org/project/template-press/)
|
|
4
|
+
[](https://github.com/smorinlabs/template-press/actions/workflows/ci.yml)
|
|
5
|
+
[](https://codecov.io/gh/smorinlabs/template-press)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
[](https://github.com/astral-sh/ruff)
|
|
8
|
+
[](https://github.com/astral-sh/uv)
|
|
9
|
+
[](https://www.conventionalcommits.org/)
|
|
10
|
+
|
|
11
|
+
# template-press
|
|
12
|
+
|
|
13
|
+
**Press a new identity onto an existing repository.** template-press is a
|
|
14
|
+
standalone command-line utility: you point it at a target repo, it discovers
|
|
15
|
+
and *validates* that repo's current identity, rewrites every occurrence to a
|
|
16
|
+
new identity, and — only after verifying that none of the old identity
|
|
17
|
+
survives — writes a receipt. A wrong or partial run fails loudly instead of
|
|
18
|
+
silently corrupting the target.
|
|
19
|
+
|
|
20
|
+
It is **not** a project template you fork; it is a tool you run against other
|
|
21
|
+
repos, one at a time. The rebrand engine is pure standard library, so the
|
|
22
|
+
installed package has **zero runtime dependencies**.
|
|
23
|
+
|
|
24
|
+
## Install
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
uvx --from template-press press --help # run without installing
|
|
28
|
+
# or
|
|
29
|
+
pip install template-press
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Usage
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
# preview the plan (writes nothing)
|
|
36
|
+
press rebrand --target ../my-repo --config press-answers.toml --dry-run
|
|
37
|
+
|
|
38
|
+
# apply, verify, and write a receipt
|
|
39
|
+
press rebrand --target ../my-repo --config press-answers.toml
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
`press-answers.toml` describes the **destination** identity:
|
|
43
|
+
|
|
44
|
+
```toml
|
|
45
|
+
[answers]
|
|
46
|
+
package_name = "new_pkg"
|
|
47
|
+
repo_name = "new-repo"
|
|
48
|
+
app_name = "newcli"
|
|
49
|
+
author = "Jane Dev"
|
|
50
|
+
email = "jane@example.com"
|
|
51
|
+
owner = "janedev"
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Keep your filled-in `press-answers.toml` out of the target (it is transient
|
|
55
|
+
operator input, not committed state). A repo may commit a
|
|
56
|
+
`press/press-answers.example.toml` placeholder to advertise the field
|
|
57
|
+
shape — copy it, fill it, and pass it via `--config`. It has the same
|
|
58
|
+
`[answers]` fields shown above.
|
|
59
|
+
|
|
60
|
+
The target's **current** identity is read from a committed
|
|
61
|
+
`<target>/press/press-source.toml`. On a first run, `--dry-run` prints a proposed
|
|
62
|
+
source-config from discovery; review it and re-run with `--accept-discovery`
|
|
63
|
+
to write and use it.
|
|
64
|
+
|
|
65
|
+
## How it stays safe
|
|
66
|
+
|
|
67
|
+
- **Config-first identity, discovery as a guard.** The committed source-config
|
|
68
|
+
is authoritative; discovery cross-checks it against the target and *refuses
|
|
69
|
+
to run on a mismatch*, so the press never rewrites the wrong repo.
|
|
70
|
+
- **Verify-then-mark.** After rewriting, a no-leak scan confirms no source
|
|
71
|
+
identity remains. Any leftover ⇒ **exit 1 and no receipt** — a partial
|
|
72
|
+
rebrand is a loud failure, not a false success.
|
|
73
|
+
- **Boundary-safe replacement.** Short tokens (`press`, an owner like `go`)
|
|
74
|
+
match only at word boundaries, so ordinary prose (`compress`, `ongoing`) is
|
|
75
|
+
never touched.
|
|
76
|
+
|
|
77
|
+
## Exit codes
|
|
78
|
+
|
|
79
|
+
The exit code is the contract:
|
|
80
|
+
|
|
81
|
+
| Code | Meaning |
|
|
82
|
+
|------|---------|
|
|
83
|
+
| `0` | Verified — rebrand complete, no source identity remains, receipt written. |
|
|
84
|
+
| `1` | Leaks found after applying. No receipt; restore with `git -C <target> checkout . && git clean -fd`. |
|
|
85
|
+
| `2` | Precondition/config error (missing target, dirty tree, identity mismatch, existing receipt without `--force`). Nothing written. |
|
|
86
|
+
|
|
87
|
+
`--dry-run` exits `0` after printing the plan without touching the target (no receipt).
|
|
88
|
+
|
|
89
|
+
## Documentation
|
|
90
|
+
|
|
91
|
+
- Full docs: <https://template-press.readthedocs.io/>
|
|
92
|
+
- Design contract: [`docs/design/0006-external-target-model.md`](docs/design/0006-external-target-model.md)
|
|
93
|
+
- Agent runbooks: [`press-target`](.claude/skills/press-target/SKILL.md) (drive a
|
|
94
|
+
press) and [`rebrand-matrix`](.claude/skills/rebrand-matrix/SKILL.md) (the
|
|
95
|
+
R1/R2/R3 acceptance matrix)
|
|
96
|
+
|
|
97
|
+
## Contributing
|
|
98
|
+
|
|
99
|
+
See [`AGENTS.md`](AGENTS.md) for the canonical toolchain and verification flow
|
|
100
|
+
(`just setup` → `just check` → commit) and
|
|
101
|
+
[`.github/CONTRIBUTING.md`](.github/CONTRIBUTING.md) for the human contributor
|
|
102
|
+
guide.
|
|
103
|
+
|
|
104
|
+
## License
|
|
105
|
+
|
|
106
|
+
MIT — see [`LICENSE`](LICENSE).
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
# Copyright (c) 2026, Steve Morin
|
|
2
|
+
#
|
|
3
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
4
|
+
# this software and associated documentation files (the "Software"), to deal in
|
|
5
|
+
# the Software without restriction, including without limitation the rights to
|
|
6
|
+
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
7
|
+
# the Software, and to permit persons to whom the Software is furnished to do so,
|
|
8
|
+
# subject to the following conditions:
|
|
9
|
+
#
|
|
10
|
+
# The above copyright notice and this permission notice shall be included in all
|
|
11
|
+
# copies or substantial portions of the Software.
|
|
12
|
+
#
|
|
13
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
15
|
+
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
16
|
+
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
17
|
+
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
18
|
+
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
19
|
+
|
|
20
|
+
[project]
|
|
21
|
+
name = "template_press"
|
|
22
|
+
# ITM-070 — static version (ADR-06 cutover). release-please bumps this.
|
|
23
|
+
version = "3.0.0"
|
|
24
|
+
description = "Standalone rebrand utility — press a new identity onto an external target repo"
|
|
25
|
+
readme = "README.md"
|
|
26
|
+
requires-python = ">=3.12"
|
|
27
|
+
license = "MIT" # PEP 639 license expression (ITM-070, round-19).
|
|
28
|
+
authors = [{ name = "Steve Morin", email = "steve.morin@gmail.com" }]
|
|
29
|
+
classifiers = [
|
|
30
|
+
# ITM-070 — round-19. py3.12+ only (per ITM-033 floor); MIT classifier
|
|
31
|
+
# intentionally omitted (PEP 639 license expression above is the single
|
|
32
|
+
# source of truth — duplication would drift).
|
|
33
|
+
"Development Status :: 4 - Beta",
|
|
34
|
+
"Intended Audience :: Developers",
|
|
35
|
+
"Operating System :: OS Independent",
|
|
36
|
+
"Programming Language :: Python :: 3",
|
|
37
|
+
"Programming Language :: Python :: 3.12",
|
|
38
|
+
"Programming Language :: Python :: 3.13",
|
|
39
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
40
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
41
|
+
]
|
|
42
|
+
# The rebrand engine is pure standard library (tomllib, re, dataclasses,
|
|
43
|
+
# subprocess) — the shipped utility has ZERO runtime dependencies.
|
|
44
|
+
dependencies = []
|
|
45
|
+
|
|
46
|
+
# ITM-063 — PEP 735 dependency-groups (round-13 decision). Replaces
|
|
47
|
+
# [project.optional-dependencies] dev+docs. Install via `uv sync --group <name>`.
|
|
48
|
+
[dependency-groups]
|
|
49
|
+
dev = [
|
|
50
|
+
"pytest>=9.1.1",
|
|
51
|
+
"pytest-cov>=7.1.0",
|
|
52
|
+
"ty>=0.0.56", # per ADR-03 (pre-1.0; bump as needed)
|
|
53
|
+
"ruff>=0.15.20",
|
|
54
|
+
"cogapp",
|
|
55
|
+
# WL-001 — hook/CI tools pinned via uv.lock (run with `uv run`, not floating
|
|
56
|
+
# `uvx`), so local hooks and CI use the same version and upgrades arrive as
|
|
57
|
+
# reviewable dependabot PRs instead of surprise breakage.
|
|
58
|
+
"bandit>=1.9.4",
|
|
59
|
+
"codespell>=2.4.2",
|
|
60
|
+
"editorconfig-checker>=3.6.1",
|
|
61
|
+
"yamllint>=1.38.0",
|
|
62
|
+
"pip-audit>=2.10.1", # WL-014 — `just audit` + scheduled dep-audit workflow
|
|
63
|
+
"twine>=6.2.0", # WL-004 — dist metadata check in the build-smoke CI job
|
|
64
|
+
"syrupy>=5.4.0", # WL-023 — CLI --help snapshot tests
|
|
65
|
+
]
|
|
66
|
+
|
|
67
|
+
docs = [
|
|
68
|
+
"sphinx>=7.0.0",
|
|
69
|
+
"sphinx-rtd-theme",
|
|
70
|
+
"furo",
|
|
71
|
+
"myst-parser",
|
|
72
|
+
"sphinx-autodoc-typehints",
|
|
73
|
+
"cogapp",
|
|
74
|
+
"sphinx-copybutton",
|
|
75
|
+
"sphinx-autobuild",
|
|
76
|
+
"sphinxext-opengraph", # https://github.com/wpilibsuite/sphinxext-opengraph
|
|
77
|
+
]
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
[project.scripts]
|
|
81
|
+
# Noun-verb CLI (design 0006 §2): press <verb>. `rebrand` is live; `provision`
|
|
82
|
+
# and `status` arrive with the M6 Provision phase.
|
|
83
|
+
press = "template_press.press_cli:main"
|
|
84
|
+
# Alias escape hatch (design 0004 §2): a legacy `press` exists on PyPI, so
|
|
85
|
+
# ship `tpress` as a collision-proof alias console script.
|
|
86
|
+
tpress = "template_press.press_cli:main"
|
|
87
|
+
|
|
88
|
+
# ITM-072 — package metadata URLs (round 19).
|
|
89
|
+
[project.urls]
|
|
90
|
+
Homepage = "https://github.com/smorinlabs/template-press"
|
|
91
|
+
Repository = "https://github.com/smorinlabs/template-press"
|
|
92
|
+
Documentation = "https://template-press.readthedocs.io/en/latest/"
|
|
93
|
+
Changelog = "https://github.com/smorinlabs/template-press/blob/main/CHANGELOG.md"
|
|
94
|
+
Issues = "https://github.com/smorinlabs/template-press/issues"
|
|
95
|
+
|
|
96
|
+
# ITM-073 — uv_build (ADR-06 cutover; replaces Hatchling + hatch-vcs).
|
|
97
|
+
[build-system]
|
|
98
|
+
requires = ["uv_build>=0.5,<1.0"]
|
|
99
|
+
build-backend = "uv_build"
|
|
100
|
+
|
|
101
|
+
# ITM-074 — uv_build module configuration.
|
|
102
|
+
# Template uses a flat layout (package at repo root, not src/) — must set
|
|
103
|
+
# module-root = "" so uv_build doesn't expect src/template_press/.
|
|
104
|
+
[tool.uv.build-backend]
|
|
105
|
+
module-name = "template_press"
|
|
106
|
+
# src/ layout (Decision 1) — package now lives at src/template_press/.
|
|
107
|
+
module-root = "src"
|
|
108
|
+
|
|
109
|
+
[tool.ruff]
|
|
110
|
+
# ITM-018 reconciled config (round-2). Merge: template's stricter rule
|
|
111
|
+
# selection + source's ignore rationale. target-version reflects ITM-033
|
|
112
|
+
# Python-floor bump.
|
|
113
|
+
target-version = "py312"
|
|
114
|
+
line-length = 88
|
|
115
|
+
|
|
116
|
+
lint.select = [
|
|
117
|
+
"E", # pycodestyle errors
|
|
118
|
+
"F", # pyflakes
|
|
119
|
+
"I", # isort
|
|
120
|
+
"B", # flake8-bugbear
|
|
121
|
+
"C4", # flake8-comprehensions
|
|
122
|
+
"UP", # pyupgrade
|
|
123
|
+
"N", # pep8-naming
|
|
124
|
+
"RUF", # Ruff-specific rules
|
|
125
|
+
"W", # pycodestyle warnings
|
|
126
|
+
"YTT", # flake8-2020
|
|
127
|
+
"S", # flake8-bandit
|
|
128
|
+
]
|
|
129
|
+
|
|
130
|
+
# Source's ignore rationale (round-2): line-length handled by formatter;
|
|
131
|
+
# template-applicable subset adopted (B904/B007 omitted — source-specific
|
|
132
|
+
# patterns that don't apply here).
|
|
133
|
+
lint.ignore = [
|
|
134
|
+
"E501", # line too long (formatter owns this)
|
|
135
|
+
"W293", # whitespace on blank line (formatter owns trim_trailing)
|
|
136
|
+
]
|
|
137
|
+
|
|
138
|
+
# Allow autofix behavior for specific rules
|
|
139
|
+
fix = true
|
|
140
|
+
lint.unfixable = [] # Rules that should not be fixed automatically
|
|
141
|
+
|
|
142
|
+
# Exclude files/folders
|
|
143
|
+
exclude = [
|
|
144
|
+
".git",
|
|
145
|
+
".venv",
|
|
146
|
+
"__pycache__",
|
|
147
|
+
"build",
|
|
148
|
+
"dist",
|
|
149
|
+
"docs/source/conf.py",
|
|
150
|
+
"src/template_press/_version.py",
|
|
151
|
+
"prototypes", # P0004 template-press engine prototypes (own lint config in template-press)
|
|
152
|
+
]
|
|
153
|
+
# Per-file-ignores
|
|
154
|
+
[tool.ruff.lint.pycodestyle]
|
|
155
|
+
max-line-length = 88
|
|
156
|
+
[tool.ruff.lint.per-file-ignores]
|
|
157
|
+
"__init__.py" = ["F401"] # Ignore unused imports in __init__.py files
|
|
158
|
+
"tests/*" = ["S101", "S105", "S106"] # Ignore assert statements in tests
|
|
159
|
+
# S101: assert statements removed under -O — security risk if assert is the only gate.
|
|
160
|
+
# S105/S106: hardcoded password strings/variables in code.
|
|
161
|
+
|
|
162
|
+
# ITM-018 — explicit format config (round-2; mirrors source). Values match Ruff
|
|
163
|
+
# defaults but being explicit prevents silent drift if defaults change.
|
|
164
|
+
[tool.ruff.format]
|
|
165
|
+
quote-style = "double"
|
|
166
|
+
indent-style = "space"
|
|
167
|
+
line-ending = "auto"
|
|
168
|
+
|
|
169
|
+
# Pyright/Pylance (IDE) strict type checking — formerly pyrightconfig.json.
|
|
170
|
+
# CI typechecking runs ty (ADR-03); this section drives the VS Code Pyright
|
|
171
|
+
# extension and ad-hoc `pyright` runs.
|
|
172
|
+
[tool.pyright]
|
|
173
|
+
include = ["src/template_press", "tests"]
|
|
174
|
+
exclude = ["**/node_modules", "**/__pycache__"]
|
|
175
|
+
defineConstant = { DEBUG = true }
|
|
176
|
+
typeCheckingMode = "strict"
|
|
177
|
+
pythonVersion = "3.12"
|
|
178
|
+
useLibraryCodeForTypes = true
|
|
179
|
+
reportMissingImports = true
|
|
180
|
+
reportMissingTypeStubs = true
|
|
181
|
+
reportUnknownParameterType = true
|
|
182
|
+
reportUnknownArgumentType = true
|
|
183
|
+
reportUnknownLambdaType = true
|
|
184
|
+
reportUnknownVariableType = true
|
|
185
|
+
reportUnknownMemberType = true
|
|
186
|
+
reportMissingTypeArgument = true
|
|
187
|
+
reportInvalidTypeVarUse = true
|
|
188
|
+
reportUnnecessaryIsInstance = true
|
|
189
|
+
reportUnnecessaryCast = true
|
|
190
|
+
reportUnnecessaryComparison = true
|
|
191
|
+
reportDuplicateImport = true
|
|
192
|
+
reportPrivateUsage = "warning"
|
|
193
|
+
reportUnusedImport = true
|
|
194
|
+
reportUnusedVariable = true
|
|
195
|
+
reportUnusedFunction = true
|
|
196
|
+
reportUnusedClass = true
|
|
197
|
+
|
|
198
|
+
# ITM-027 — bandit config (round 3). Tests legitimately use `assert`
|
|
199
|
+
# (pytest convention) — exclude_dirs covers tests/.
|
|
200
|
+
[tool.bandit]
|
|
201
|
+
exclude_dirs = ["tests", ".venv", "build", "dist"]
|
|
202
|
+
skips = [] # No global skips; add with rationale only.
|
|
203
|
+
|
|
204
|
+
[tool.pytest.ini_options]
|
|
205
|
+
testpaths = ["tests"]
|
|
206
|
+
python_files = ["test_*.py"]
|
|
207
|
+
# Marker taxonomy (ITM-046, round-9 decision).
|
|
208
|
+
# `live` = requires external services; `slow` = takes >1s.
|
|
209
|
+
# Default `addopts` excludes both — run full suite with `pytest -m ""`.
|
|
210
|
+
markers = ["live: requires external services", "slow: takes >1s"]
|
|
211
|
+
addopts = "-m 'not live and not slow'"
|
|
212
|
+
strict_markers = true
|
|
213
|
+
|
|
214
|
+
# ITM-015 — codespell. US English baseline (default builtin="clear,rare"); empty
|
|
215
|
+
# ignore list — add terms only when intentional. Decided round 9.
|
|
216
|
+
[tool.codespell]
|
|
217
|
+
skip = ".git,.venv,build,dist,node_modules,uv.lock,bun.lock,*.lock,docs/_build,*.svg,*.cast,.ruff_cache,.pytest_cache,.mypy_cache,.ty_cache,*.log"
|
|
218
|
+
# *.log: raw run output, not prose.
|
|
219
|
+
ignore-words-list = "ans,porjects"
|
|
220
|
+
# ans: variable name used in prompt-handling code; codespell wants to "fix"
|
|
221
|
+
# it to "and". Whitelist to keep the short variable name.
|
|
222
|
+
# porjects: intentional typo — the did-you-mean example in cli/groups.py and
|
|
223
|
+
# its test ("press porjects" must suggest "projects").
|
|
224
|
+
check-filenames = true
|
|
225
|
+
check-hidden = false
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Copyright (c) 2025, Steve Morin
|
|
2
|
+
#
|
|
3
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
4
|
+
# this software and associated documentation files (the "Software"), to deal in
|
|
5
|
+
# the Software without restriction, including without limitation the rights to
|
|
6
|
+
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
7
|
+
# the Software, and to permit persons to whom the Software is furnished to do so,
|
|
8
|
+
# subject to the following conditions:
|
|
9
|
+
#
|
|
10
|
+
# The above copyright notice and this permission notice shall be included in all
|
|
11
|
+
# copies or substantial portions of the Software.
|
|
12
|
+
#
|
|
13
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
15
|
+
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
16
|
+
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
17
|
+
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
18
|
+
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
19
|
+
|
|
20
|
+
"""template-press — a standalone external-target rebrand utility."""
|
|
21
|
+
|
|
22
|
+
from importlib import metadata
|
|
23
|
+
|
|
24
|
+
__version__ = metadata.version("template_press")
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"""press — the template-press command line.
|
|
2
|
+
|
|
3
|
+
Noun-verb dispatcher (design 0006): `press rebrand --target …` presses an
|
|
4
|
+
identity onto an external target repo. `provision` and `status` are reserved
|
|
5
|
+
for the M6 Provision phase and currently exit 2 with a pointer.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import sys
|
|
11
|
+
|
|
12
|
+
from template_press import __version__
|
|
13
|
+
from template_press.rebrand import cli as rebrand_cli
|
|
14
|
+
|
|
15
|
+
_RESERVED = {"provision", "status"}
|
|
16
|
+
|
|
17
|
+
_USAGE = """\
|
|
18
|
+
usage: press <command> [options]
|
|
19
|
+
|
|
20
|
+
commands:
|
|
21
|
+
rebrand press an identity onto a target repo (press rebrand --help)
|
|
22
|
+
provision configure a target's features (coming in M6)
|
|
23
|
+
status report a target's provisioned state (coming in M6)
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def main(argv: list[str] | None = None) -> int:
|
|
28
|
+
args = list(sys.argv[1:] if argv is None else argv)
|
|
29
|
+
if args and args[0] in ("-V", "--version"):
|
|
30
|
+
print(f"press {__version__}")
|
|
31
|
+
return 0
|
|
32
|
+
if not args or args[0] in ("-h", "--help"):
|
|
33
|
+
print(_USAGE)
|
|
34
|
+
return 0
|
|
35
|
+
verb, rest = args[0], args[1:]
|
|
36
|
+
if verb == "rebrand":
|
|
37
|
+
return rebrand_cli.main(rest)
|
|
38
|
+
if verb in _RESERVED:
|
|
39
|
+
print(
|
|
40
|
+
f"error: '{verb}' is part of the Provision phase and is not "
|
|
41
|
+
f"available yet (coming in M6).",
|
|
42
|
+
file=sys.stderr,
|
|
43
|
+
)
|
|
44
|
+
return 2
|
|
45
|
+
print(f"error: unknown command {verb!r}\n\n{_USAGE}", file=sys.stderr)
|
|
46
|
+
return 2
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
if __name__ == "__main__":
|
|
50
|
+
raise SystemExit(main())
|
|
File without changes
|
|
File without changes
|