gitpro 0.3.4__tar.gz → 0.4.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.
- {gitpro-0.3.4 → gitpro-0.4.0}/PKG-INFO +30 -24
- {gitpro-0.3.4 → gitpro-0.4.0}/README.md +29 -23
- {gitpro-0.3.4 → gitpro-0.4.0}/src/gitpro/__init__.py +1 -1
- {gitpro-0.3.4 → gitpro-0.4.0}/src/gitpro/agents.py +24 -2
- {gitpro-0.3.4 → gitpro-0.4.0}/src/gitpro/args.py +10 -0
- {gitpro-0.3.4 → gitpro-0.4.0}/src/gitpro/audit.py +17 -6
- {gitpro-0.3.4 → gitpro-0.4.0}/src/gitpro/cli.py +243 -26
- gitpro-0.4.0/src/gitpro/commitcheck.py +113 -0
- {gitpro-0.3.4 → gitpro-0.4.0}/src/gitpro/completion.py +2 -2
- {gitpro-0.3.4 → gitpro-0.4.0}/src/gitpro/config.py +3 -3
- gitpro-0.4.0/src/gitpro/deprecation.py +36 -0
- {gitpro-0.3.4 → gitpro-0.4.0}/src/gitpro/discover.py +40 -9
- {gitpro-0.3.4 → gitpro-0.4.0}/src/gitpro/guard.py +8 -1
- {gitpro-0.3.4 → gitpro-0.4.0}/src/gitpro/hot.py +2 -1
- {gitpro-0.3.4 → gitpro-0.4.0}/src/gitpro/jsonfile.py +13 -4
- {gitpro-0.3.4 → gitpro-0.4.0}/src/gitpro/jsonout.py +3 -0
- {gitpro-0.3.4 → gitpro-0.4.0}/src/gitpro/keys.py +3 -2
- gitpro-0.4.0/src/gitpro/learn.py +116 -0
- {gitpro-0.3.4 → gitpro-0.4.0}/src/gitpro/mcp.py +89 -120
- gitpro-0.4.0/src/gitpro/pin.py +166 -0
- {gitpro-0.3.4 → gitpro-0.4.0}/src/gitpro/plan.py +11 -6
- {gitpro-0.3.4 → gitpro-0.4.0}/src/gitpro/resolve.py +149 -19
- {gitpro-0.3.4 → gitpro-0.4.0}/src/gitpro/scan.py +117 -9
- gitpro-0.4.0/src/gitpro/setup.py +668 -0
- {gitpro-0.3.4 → gitpro-0.4.0}/src/gitpro/view.py +22 -3
- gitpro-0.3.4/src/gitpro/pin.py +0 -89
- gitpro-0.3.4/src/gitpro/setup.py +0 -260
- {gitpro-0.3.4 → gitpro-0.4.0}/.gitignore +0 -0
- {gitpro-0.3.4 → gitpro-0.4.0}/LICENSE +0 -0
- {gitpro-0.3.4 → gitpro-0.4.0}/pyproject.toml +0 -0
- {gitpro-0.3.4 → gitpro-0.4.0}/src/gitpro/__main__.py +0 -0
- {gitpro-0.3.4 → gitpro-0.4.0}/src/gitpro/approval_policy.py +0 -0
- {gitpro-0.3.4 → gitpro-0.4.0}/src/gitpro/change_contract.py +0 -0
- {gitpro-0.3.4 → gitpro-0.4.0}/src/gitpro/changes.py +0 -0
- {gitpro-0.3.4 → gitpro-0.4.0}/src/gitpro/clone.py +0 -0
- {gitpro-0.3.4 → gitpro-0.4.0}/src/gitpro/devcontainer.py +0 -0
- {gitpro-0.3.4 → gitpro-0.4.0}/src/gitpro/doctor.py +0 -0
- {gitpro-0.3.4 → gitpro-0.4.0}/src/gitpro/envcmd.py +0 -0
- {gitpro-0.3.4 → gitpro-0.4.0}/src/gitpro/example.toml +0 -0
- {gitpro-0.3.4 → gitpro-0.4.0}/src/gitpro/files.py +0 -0
- {gitpro-0.3.4 → gitpro-0.4.0}/src/gitpro/forge.py +0 -0
- {gitpro-0.3.4 → gitpro-0.4.0}/src/gitpro/health.py +0 -0
- {gitpro-0.3.4 → gitpro-0.4.0}/src/gitpro/incident.py +0 -0
- {gitpro-0.3.4 → gitpro-0.4.0}/src/gitpro/lint.py +0 -0
- {gitpro-0.3.4 → gitpro-0.4.0}/src/gitpro/lost.py +0 -0
- {gitpro-0.3.4 → gitpro-0.4.0}/src/gitpro/operation_contract.py +0 -0
- {gitpro-0.3.4 → gitpro-0.4.0}/src/gitpro/operation_io.py +0 -0
- {gitpro-0.3.4 → gitpro-0.4.0}/src/gitpro/operation_reconcile.py +0 -0
- {gitpro-0.3.4 → gitpro-0.4.0}/src/gitpro/operations.py +0 -0
- {gitpro-0.3.4 → gitpro-0.4.0}/src/gitpro/policy.py +0 -0
- {gitpro-0.3.4 → gitpro-0.4.0}/src/gitpro/prompt.py +0 -0
- {gitpro-0.3.4 → gitpro-0.4.0}/src/gitpro/render.py +0 -0
- {gitpro-0.3.4 → gitpro-0.4.0}/src/gitpro/report.py +0 -0
- {gitpro-0.3.4 → gitpro-0.4.0}/src/gitpro/scanroots.py +0 -0
- {gitpro-0.3.4 → gitpro-0.4.0}/src/gitpro/trailers.py +0 -0
- {gitpro-0.3.4 → gitpro-0.4.0}/src/gitpro/tui.py +0 -0
- {gitpro-0.3.4 → gitpro-0.4.0}/src/gitpro/undo.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: gitpro
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Per-remote git identities (name, email, SSH key, commit signing) from one TOML file
|
|
5
5
|
Project-URL: Homepage, https://gitpro.dev
|
|
6
6
|
Project-URL: Source, https://github.com/Yantrakar/gitpro
|
|
@@ -48,26 +48,38 @@ Install from [PyPI](https://pypi.org/project/gitpro/) with pipx.
|
|
|
48
48
|
|
|
49
49
|
```sh
|
|
50
50
|
pipx install gitpro
|
|
51
|
-
gitpro setup
|
|
51
|
+
gitpro setup
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
54
|
+
Setup offers to look through your repos and proposes your identities. Accept,
|
|
55
|
+
edit or answer the questions yourself; **no TOML editing is needed.** One
|
|
56
|
+
preview shows everything, including the commit guard and, with Claude Code, its
|
|
57
|
+
hook and MCP server. One yes applies it all. Setup never changes your repos.
|
|
58
|
+
|
|
59
|
+
```mermaid
|
|
60
|
+
flowchart LR
|
|
61
|
+
S["gitpro setup"] --> HC{"Config <br/>exists?"}
|
|
62
|
+
HC -->|no| L["Read your repos, <br/>SSH config and <br/>editor recents, <br/>if you agree"]
|
|
63
|
+
L --> Q["Propose <br/>identities; you <br/>accept or edit"]
|
|
64
|
+
Q --> I
|
|
65
|
+
HC -->|yes| I["Inspect config, <br/>Git and SSH files, <br/>keys, guard, <br/>agent hook, MCP"]
|
|
66
|
+
I -->|all current| OK["Nothing <br/>to do"]
|
|
67
|
+
I -->|something to do| PV["One preview, <br/>each part with <br/>its undo"]
|
|
68
|
+
PV --> ASK{"Apply <br/>all?"}
|
|
69
|
+
ASK -->|no| NONE["Nothing <br/>written"]
|
|
70
|
+
ASK -->|yes| AP["Write it, print <br/>the public keys <br/>to register"]
|
|
71
|
+
AP --> NX["Next: <br/>gitpro scan"]
|
|
61
72
|
```
|
|
62
73
|
|
|
63
|
-
Then
|
|
74
|
+
Then:
|
|
64
75
|
|
|
65
76
|
```sh
|
|
66
|
-
gitpro why #
|
|
77
|
+
gitpro why # inside a repository: the expected identity and anything overriding it
|
|
78
|
+
gitpro scan # repos that need a fix, with the command for each
|
|
67
79
|
```
|
|
68
80
|
|
|
69
|
-
Already have a config?
|
|
70
|
-
|
|
81
|
+
Already have a config? `gitpro setup` brings this machine up to date with it.
|
|
82
|
+
`gitpro setup -n` only shows what is left to do. Prefer editing files? The
|
|
71
83
|
[user guide](docs/guide.md#configuration) covers the full TOML format.
|
|
72
84
|
|
|
73
85
|
## What you get
|
|
@@ -79,20 +91,17 @@ your existing settings or comments. Prefer editing files? The
|
|
|
79
91
|
|
|
80
92
|
Gitpro generates ordinary Git and SSH configuration; it needs no background
|
|
81
93
|
service. Changes can be previewed, existing hand-written files are backed up,
|
|
82
|
-
and key
|
|
94
|
+
and key uploads are never part of setup.
|
|
83
95
|
|
|
84
96
|
## Using VS Code?
|
|
85
97
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
repository-level overrides. [Install the extension](vscode/README.md).
|
|
98
|
+
The extension shows the current identity and helps find repository-level
|
|
99
|
+
overrides. It runs the same commands as the terminal. [Install the extension](vscode/README.md).
|
|
89
100
|
|
|
90
101
|
## Go further when you need to
|
|
91
102
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
and GitHub PRs. Persistent changes use exact proposals, human approval by default,
|
|
95
|
-
optional operator-scoped preauthorization, and recoverable apply. MCP execution is opt-in.
|
|
103
|
+
AI agents get the same answers through the MCP server and the Claude Code hook:
|
|
104
|
+
see [agent workflows](docs/agent-workflows.md).
|
|
96
105
|
|
|
97
106
|
| I want to… | Start here |
|
|
98
107
|
|---|---|
|
|
@@ -103,9 +112,6 @@ optional operator-scoped preauthorization, and recoverable apply. MCP execution
|
|
|
103
112
|
| Look up a command or undo changes | [Command reference](docs/guide.md#commands) · [Undo](docs/guide.md#undo-everything) |
|
|
104
113
|
| Troubleshoot or contribute | [Troubleshooting](docs/guide.md#troubleshooting) · [Development](docs/guide.md#development) |
|
|
105
114
|
|
|
106
|
-
The detailed TOML, YAML and command examples live in the guide, not on the
|
|
107
|
-
getting-started path.
|
|
108
|
-
|
|
109
115
|
## Problems and questions
|
|
110
116
|
|
|
111
117
|
Run `gitpro report` to draft an issue with the versions and a redacted
|
|
@@ -22,26 +22,38 @@ Install from [PyPI](https://pypi.org/project/gitpro/) with pipx.
|
|
|
22
22
|
|
|
23
23
|
```sh
|
|
24
24
|
pipx install gitpro
|
|
25
|
-
gitpro setup
|
|
25
|
+
gitpro setup
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
28
|
+
Setup offers to look through your repos and proposes your identities. Accept,
|
|
29
|
+
edit or answer the questions yourself; **no TOML editing is needed.** One
|
|
30
|
+
preview shows everything, including the commit guard and, with Claude Code, its
|
|
31
|
+
hook and MCP server. One yes applies it all. Setup never changes your repos.
|
|
32
|
+
|
|
33
|
+
```mermaid
|
|
34
|
+
flowchart LR
|
|
35
|
+
S["gitpro setup"] --> HC{"Config <br/>exists?"}
|
|
36
|
+
HC -->|no| L["Read your repos, <br/>SSH config and <br/>editor recents, <br/>if you agree"]
|
|
37
|
+
L --> Q["Propose <br/>identities; you <br/>accept or edit"]
|
|
38
|
+
Q --> I
|
|
39
|
+
HC -->|yes| I["Inspect config, <br/>Git and SSH files, <br/>keys, guard, <br/>agent hook, MCP"]
|
|
40
|
+
I -->|all current| OK["Nothing <br/>to do"]
|
|
41
|
+
I -->|something to do| PV["One preview, <br/>each part with <br/>its undo"]
|
|
42
|
+
PV --> ASK{"Apply <br/>all?"}
|
|
43
|
+
ASK -->|no| NONE["Nothing <br/>written"]
|
|
44
|
+
ASK -->|yes| AP["Write it, print <br/>the public keys <br/>to register"]
|
|
45
|
+
AP --> NX["Next: <br/>gitpro scan"]
|
|
35
46
|
```
|
|
36
47
|
|
|
37
|
-
Then
|
|
48
|
+
Then:
|
|
38
49
|
|
|
39
50
|
```sh
|
|
40
|
-
gitpro why #
|
|
51
|
+
gitpro why # inside a repository: the expected identity and anything overriding it
|
|
52
|
+
gitpro scan # repos that need a fix, with the command for each
|
|
41
53
|
```
|
|
42
54
|
|
|
43
|
-
Already have a config?
|
|
44
|
-
|
|
55
|
+
Already have a config? `gitpro setup` brings this machine up to date with it.
|
|
56
|
+
`gitpro setup -n` only shows what is left to do. Prefer editing files? The
|
|
45
57
|
[user guide](docs/guide.md#configuration) covers the full TOML format.
|
|
46
58
|
|
|
47
59
|
## What you get
|
|
@@ -53,20 +65,17 @@ your existing settings or comments. Prefer editing files? The
|
|
|
53
65
|
|
|
54
66
|
Gitpro generates ordinary Git and SSH configuration; it needs no background
|
|
55
67
|
service. Changes can be previewed, existing hand-written files are backed up,
|
|
56
|
-
and key
|
|
68
|
+
and key uploads are never part of setup.
|
|
57
69
|
|
|
58
70
|
## Using VS Code?
|
|
59
71
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
repository-level overrides. [Install the extension](vscode/README.md).
|
|
72
|
+
The extension shows the current identity and helps find repository-level
|
|
73
|
+
overrides. It runs the same commands as the terminal. [Install the extension](vscode/README.md).
|
|
63
74
|
|
|
64
75
|
## Go further when you need to
|
|
65
76
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
and GitHub PRs. Persistent changes use exact proposals, human approval by default,
|
|
69
|
-
optional operator-scoped preauthorization, and recoverable apply. MCP execution is opt-in.
|
|
77
|
+
AI agents get the same answers through the MCP server and the Claude Code hook:
|
|
78
|
+
see [agent workflows](docs/agent-workflows.md).
|
|
70
79
|
|
|
71
80
|
| I want to… | Start here |
|
|
72
81
|
|---|---|
|
|
@@ -77,9 +86,6 @@ optional operator-scoped preauthorization, and recoverable apply. MCP execution
|
|
|
77
86
|
| Look up a command or undo changes | [Command reference](docs/guide.md#commands) · [Undo](docs/guide.md#undo-everything) |
|
|
78
87
|
| Troubleshoot or contribute | [Troubleshooting](docs/guide.md#troubleshooting) · [Development](docs/guide.md#development) |
|
|
79
88
|
|
|
80
|
-
The detailed TOML, YAML and command examples live in the guide, not on the
|
|
81
|
-
getting-started path.
|
|
82
|
-
|
|
83
89
|
## Problems and questions
|
|
84
90
|
|
|
85
91
|
Run `gitpro report` to draft an issue with the versions and a redacted
|
|
@@ -34,7 +34,7 @@ MAX_SCAN = 1024 * 1024 # the regex scan reads at most this much
|
|
|
34
34
|
MAX_FOR = 20 # `for x in w1 .. wN` with more words: the body is judged once, x unknown
|
|
35
35
|
MAX_VALUE = 4096 # a longer expanded $VAR value counts as unknown
|
|
36
36
|
ALIAS_TIMEOUT = 3 # seconds for the `git config --get alias.X` lookup on the hook path
|
|
37
|
-
TRIGGERS = ("override", "pin_stale", "no_identity", "env_override")
|
|
37
|
+
TRIGGERS = ("ambiguous", "override", "pin_stale", "no_identity", "env_override")
|
|
38
38
|
SKIP_ENV = "GITPRO_SKIP"
|
|
39
39
|
BYPASS_HELP = (f"{SKIP_ENV}=1 in the environment the agent starts with turns the check off for that session; "
|
|
40
40
|
"[agents] hook = \"warn\" or \"off\" in the config changes it for good. The deny message never "
|
|
@@ -1322,6 +1322,8 @@ def _judge_one(c: Call, rep, cfg, own: set, pushed_to: Optional[str] = None) ->
|
|
|
1322
1322
|
from .resolve import redact_url
|
|
1323
1323
|
url = redact_url(next(iter(rep.effective.remotes.values()), None)) or top
|
|
1324
1324
|
headline = f"no identity matches this repo ({url}) and [default] has no email"
|
|
1325
|
+
elif any(p.code == "ambiguous" for p in triggers):
|
|
1326
|
+
headline = f"this {what} runs in a repo whose remotes belong to different identities"
|
|
1325
1327
|
elif c_bad or a_bad:
|
|
1326
1328
|
email, verb = (committer, "committed") if c_bad else (author, "authored")
|
|
1327
1329
|
email = email or "(no email)"
|
|
@@ -1812,11 +1814,31 @@ def _edit(args: argparse.Namespace, removing: bool) -> int:
|
|
|
1812
1814
|
view.step("added .claude/settings.local.json to .git/info/exclude so it is not committed")
|
|
1813
1815
|
view.ok(f"removed the gitpro hook from {shown}" if removing else
|
|
1814
1816
|
f"installed; {title} picks it up on its next session")
|
|
1815
|
-
restores = f"restores from {undo.tilde(res.backup)}" if res.backup else f"removes {shown}"
|
|
1817
|
+
restores = f"restores from {undo.tilde(res.backup)}" if res.backup else f"removes {shown} unless it changed since"
|
|
1816
1818
|
print(f"↩ undo: sh {undo.tilde(res.undo)} ({restores})")
|
|
1817
1819
|
return 0
|
|
1818
1820
|
|
|
1819
1821
|
|
|
1822
|
+
HOOK_AGENTS = ("claude", "cursor", "gemini")
|
|
1823
|
+
|
|
1824
|
+
|
|
1825
|
+
def plugin_enabled(home: Path) -> Optional[str]:
|
|
1826
|
+
"""The enabled gitpro plugin in ~/.claude/settings.json (it ships the hook and the MCP server), or None."""
|
|
1827
|
+
t = target("claude", "user", home, None)
|
|
1828
|
+
return _plugin(_read_lenient(t.path)) if t.path.is_file() else None
|
|
1829
|
+
|
|
1830
|
+
|
|
1831
|
+
def hook_change(agent: str, home: Path) -> Optional[str]:
|
|
1832
|
+
"""For gitpro setup: what `agent install --agent AGENT` would do at user scope ("create PATH" or
|
|
1833
|
+
"update PATH"), or None when the hook is in place. ConfigError for a file gitpro must not edit."""
|
|
1834
|
+
from . import undo
|
|
1835
|
+
t = target(agent, "user", home, gitpro_path())
|
|
1836
|
+
obj = _precheck(t.path, t, _snippet(t))
|
|
1837
|
+
if obj is not None and add_hook(copy.deepcopy(obj), t) == obj:
|
|
1838
|
+
return None
|
|
1839
|
+
return f"{'update' if obj is not None else 'create'} {undo.tilde(t.path)}"
|
|
1840
|
+
|
|
1841
|
+
|
|
1820
1842
|
def install(args: argparse.Namespace) -> int:
|
|
1821
1843
|
"""`gitpro agent install`."""
|
|
1822
1844
|
return _edit(args, removing=False)
|
|
@@ -43,7 +43,17 @@ def confirm() -> argparse.ArgumentParser:
|
|
|
43
43
|
return p
|
|
44
44
|
|
|
45
45
|
|
|
46
|
+
def dry_run(p: argparse.ArgumentParser) -> None:
|
|
47
|
+
"""-n/--dry-run for a command that already previews without -y (pin, scan, audit; spec 22 R4)."""
|
|
48
|
+
p.add_argument("-n", "--dry-run", action="store_true", help="show only, change nothing (as without -y)")
|
|
49
|
+
|
|
50
|
+
|
|
46
51
|
def preview_only(args: object) -> bool:
|
|
52
|
+
if getattr(args, "dry_run", False):
|
|
53
|
+
if getattr(args, "yes", False):
|
|
54
|
+
from .config import ConfigError
|
|
55
|
+
raise ConfigError("choose one: -n shows the change, -y makes it")
|
|
56
|
+
return True
|
|
47
57
|
return not (getattr(args, "yes", False) or getattr(args, "write", False))
|
|
48
58
|
|
|
49
59
|
|
|
@@ -7,6 +7,7 @@ keeping every date; it never runs `rebase`, never touches pushed commits, the in
|
|
|
7
7
|
"""
|
|
8
8
|
from __future__ import annotations
|
|
9
9
|
|
|
10
|
+
import argparse
|
|
10
11
|
import os
|
|
11
12
|
import re
|
|
12
13
|
import shlex
|
|
@@ -18,7 +19,7 @@ from pathlib import Path
|
|
|
18
19
|
from typing import Dict, List, Optional, Sequence, Set, Tuple
|
|
19
20
|
|
|
20
21
|
from . import config, jsonout, resolve, trailers, undo
|
|
21
|
-
from .args import capability
|
|
22
|
+
from .args import capability, dry_run, preview_only
|
|
22
23
|
from .config import Config, ConfigError
|
|
23
24
|
|
|
24
25
|
PROG = "gitpro"
|
|
@@ -31,7 +32,7 @@ FORMAT = "%H%x00%an%x00%ae%x00%cn%x00%ce%x00%cI%x00%P%x00%s%x00%(trailers:only,u
|
|
|
31
32
|
# Options --range may contain besides revisions; anything else (--output=..., say) is refused.
|
|
32
33
|
RANGE_OPTIONS = ("--not", "--all", "--remotes", "--branches", "--tags", "--first-parent", "--no-merges",
|
|
33
34
|
"--merges", "--since", "--until", "--after", "--before", "--max-count")
|
|
34
|
-
_CAUSES = ("url_form", "override", "pin_stale", "global_override", "not_applied", "env_override")
|
|
35
|
+
_CAUSES = ("ambiguous", "url_form", "override", "pin_stale", "global_override", "not_applied", "env_override")
|
|
35
36
|
|
|
36
37
|
|
|
37
38
|
@dataclass
|
|
@@ -715,9 +716,11 @@ def _preview(data: dict, exp) -> List[str]:
|
|
|
715
716
|
|
|
716
717
|
def cmd_audit(args) -> int:
|
|
717
718
|
as_json = jsonout.wants_json(args)
|
|
719
|
+
args.rewrite = args.rewrite or getattr(args, "rewrite_flag", False)
|
|
718
720
|
if args.rewrite and getattr(args, "agents", False):
|
|
719
721
|
raise ConfigError("--rewrite needs the author audit; drop --agents")
|
|
720
|
-
|
|
722
|
+
show_only = bool(args.rewrite and args.dry_run and preview_only(args))
|
|
723
|
+
if args.rewrite and as_json and not args.yes and not show_only:
|
|
721
724
|
raise ConfigError("--json needs -y with --rewrite (there is no terminal to confirm on)")
|
|
722
725
|
home = Path(args.home).expanduser().resolve()
|
|
723
726
|
path, how = config.find(args.config, home)
|
|
@@ -746,6 +749,12 @@ def cmd_audit(args) -> int:
|
|
|
746
749
|
print()
|
|
747
750
|
print("\n".join(_preview(data, exp)))
|
|
748
751
|
n = data["rewrite"]["commits"]
|
|
752
|
+
if show_only:
|
|
753
|
+
if as_json:
|
|
754
|
+
jsonout.emit("audit", dict(_public(data), dry_run=True))
|
|
755
|
+
else:
|
|
756
|
+
print(f"Dry run: nothing written. Rewrite the {n} unpushed commit{'s' * (n != 1)} with -y.")
|
|
757
|
+
return 0 if data["ok"] else 1
|
|
749
758
|
if not _confirm(f"rewrite {n} unpushed commit{'s' * (n != 1)}?", args.yes):
|
|
750
759
|
print("✗ aborted, nothing written")
|
|
751
760
|
return 1
|
|
@@ -773,7 +782,7 @@ def cmd_audit(args) -> int:
|
|
|
773
782
|
def register(sub, common, confirm) -> None:
|
|
774
783
|
sp = sub.add_parser(
|
|
775
784
|
"audit", parents=[common, confirm],
|
|
776
|
-
help="find commits made as the wrong identity or with an AI agent; fix unpushed ones with --
|
|
785
|
+
help="find commits made as the wrong identity or with an AI agent; fix unpushed ones with --fix",
|
|
777
786
|
description="Audit the history of a repo: commits whose committer (or your own other email as author) is "
|
|
778
787
|
"not the repo's identity, commits made with an AI agent (Co-Authored-By trailers, bot "
|
|
779
788
|
"emails) and the [*.trailers] policy. Default: the unpushed commits (as of the last fetch) "
|
|
@@ -792,9 +801,11 @@ def register(sub, common, confirm) -> None:
|
|
|
792
801
|
w = sp.add_mutually_exclusive_group()
|
|
793
802
|
w.add_argument("--agents", action="store_true", help="only the agent / trailer audit")
|
|
794
803
|
w.add_argument("--authors", action="store_true", help="only the wrong-author audit")
|
|
795
|
-
sp.add_argument("--rewrite", action="store_true",
|
|
804
|
+
sp.add_argument("--fix", dest="rewrite", action="store_true",
|
|
796
805
|
help="fix the unpushed wrong-author commits (asks first; writes an undo script)")
|
|
806
|
+
sp.add_argument("--rewrite", dest="rewrite_flag", action="store_true", help=argparse.SUPPRESS) # 0.4: --fix
|
|
807
|
+
dry_run(sp)
|
|
797
808
|
sp.add_argument("--json", action="store_true", help="machine-readable output")
|
|
798
809
|
sp.add_argument("-v", "--verbose", action="store_true", help="list every commit, not the first ten")
|
|
799
810
|
sp.set_defaults(func=cmd_audit)
|
|
800
|
-
capability("audit", "audit.rewrite", "trailers")
|
|
811
|
+
capability("audit", "audit.rewrite", "audit.fix", "trailers")
|