polygit 0.3.4__tar.gz → 0.5.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.
- {polygit-0.3.4 → polygit-0.5.0}/PKG-INFO +25 -2
- {polygit-0.3.4 → polygit-0.5.0}/README.md +23 -0
- {polygit-0.3.4 → polygit-0.5.0}/pyproject.toml +1 -1
- {polygit-0.3.4 → polygit-0.5.0}/src/polygit/cli.py +11 -5
- {polygit-0.3.4 → polygit-0.5.0}/src/polygit/repo.py +38 -5
- polygit-0.5.0/tests/test_polygit.py +251 -0
- {polygit-0.3.4 → polygit-0.5.0}/uv.lock +107 -62
- polygit-0.3.4/tests/test_polygit.py +0 -117
- {polygit-0.3.4 → polygit-0.5.0}/.github/workflows/ci.yml +0 -0
- {polygit-0.3.4 → polygit-0.5.0}/.gitignore +0 -0
- {polygit-0.3.4 → polygit-0.5.0}/AGENTS.md +0 -0
- {polygit-0.3.4 → polygit-0.5.0}/CLAUDE.md +0 -0
- {polygit-0.3.4 → polygit-0.5.0}/LICENSE.txt +0 -0
- {polygit-0.3.4 → polygit-0.5.0}/src/polygit/__init__.py +0 -0
- {polygit-0.3.4 → polygit-0.5.0}/src/polygit/config.py +0 -0
- {polygit-0.3.4 → polygit-0.5.0}/src/polygit/repos.py +0 -0
- {polygit-0.3.4 → polygit-0.5.0}/tests/__init__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: polygit
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: Manage multiple git repos from a single .pgit config file.
|
|
5
5
|
Project-URL: Repository, https://github.com/gschaetz/polygit
|
|
6
6
|
Author-email: Gary Schaetz <gary@schaetzkc.com>
|
|
@@ -87,6 +87,29 @@ pgit push --all # one message for all dirty repos
|
|
|
87
87
|
pgit push --wip # auto-commit with "WIP <timestamp>"
|
|
88
88
|
```
|
|
89
89
|
|
|
90
|
+
## dry run
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
pgit pull --dry-run # show ahead/behind per repo; changes nothing
|
|
94
|
+
pgit push --dry-run # list dirty repos that would be committed and pushed
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
`pull --dry-run` compares against the last fetched state of each upstream, so run `pgit sync` first for current numbers.
|
|
98
|
+
|
|
99
|
+
## status --json
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
pgit status --json # machine-readable list of dirty repos
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Prints a single JSON array on stdout and nothing else:
|
|
106
|
+
|
|
107
|
+
```json
|
|
108
|
+
[{"platform": "github", "path": "gschaetz/mousehat", "changed_files": 2}]
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
`changed_files` is the number of entries in `git status --short`. Clean repos are omitted, so the array is empty when there is nothing to commit.
|
|
112
|
+
|
|
90
113
|
## repos — drift detection
|
|
91
114
|
|
|
92
115
|
`pgit repos` compares what's actually on disk against your `.pgit` config and reports:
|
|
@@ -54,6 +54,29 @@ pgit push --all # one message for all dirty repos
|
|
|
54
54
|
pgit push --wip # auto-commit with "WIP <timestamp>"
|
|
55
55
|
```
|
|
56
56
|
|
|
57
|
+
## dry run
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
pgit pull --dry-run # show ahead/behind per repo; changes nothing
|
|
61
|
+
pgit push --dry-run # list dirty repos that would be committed and pushed
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
`pull --dry-run` compares against the last fetched state of each upstream, so run `pgit sync` first for current numbers.
|
|
65
|
+
|
|
66
|
+
## status --json
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
pgit status --json # machine-readable list of dirty repos
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Prints a single JSON array on stdout and nothing else:
|
|
73
|
+
|
|
74
|
+
```json
|
|
75
|
+
[{"platform": "github", "path": "gschaetz/mousehat", "changed_files": 2}]
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
`changed_files` is the number of entries in `git status --short`. Clean repos are omitted, so the array is empty when there is nothing to commit.
|
|
79
|
+
|
|
57
80
|
## repos — drift detection
|
|
58
81
|
|
|
59
82
|
`pgit repos` compares what's actually on disk against your `.pgit` config and reports:
|
|
@@ -13,8 +13,12 @@ def main():
|
|
|
13
13
|
sub = parser.add_subparsers(dest="command", metavar="command")
|
|
14
14
|
|
|
15
15
|
sub.add_parser("sync", help="Clone missing repos and fetch all")
|
|
16
|
-
sub.add_parser("status", help="Show repos with uncommitted changes")
|
|
17
|
-
|
|
16
|
+
status_p = sub.add_parser("status", help="Show repos with uncommitted changes")
|
|
17
|
+
status_p.add_argument("--json", action="store_true",
|
|
18
|
+
help="Print dirty repos as a JSON list")
|
|
19
|
+
pull_p = sub.add_parser("pull", help="Pull all repos, auto-stashing local changes")
|
|
20
|
+
pull_p.add_argument("--dry-run", action="store_true",
|
|
21
|
+
help="Show ahead/behind vs. last-fetched upstream; changes nothing")
|
|
18
22
|
|
|
19
23
|
push_p = sub.add_parser("push", help="Commit and push dirty repos")
|
|
20
24
|
mode_g = push_p.add_mutually_exclusive_group()
|
|
@@ -25,6 +29,8 @@ def main():
|
|
|
25
29
|
mode_g.add_argument("--wip", dest="push_mode", action="store_const",
|
|
26
30
|
const="wip", help='Auto-commit with "WIP <timestamp>"')
|
|
27
31
|
push_p.set_defaults(push_mode="interactive")
|
|
32
|
+
push_p.add_argument("--dry-run", action="store_true",
|
|
33
|
+
help="Show the commit/push plan without committing or pushing")
|
|
28
34
|
|
|
29
35
|
sub.add_parser("repos", help="Discover drift between .pgit and the filesystem")
|
|
30
36
|
|
|
@@ -45,9 +51,9 @@ def main():
|
|
|
45
51
|
|
|
46
52
|
commands = {
|
|
47
53
|
"sync": lambda: cmd_sync(config, base),
|
|
48
|
-
"status": lambda: cmd_status(config, base),
|
|
49
|
-
"pull": lambda: cmd_pull(config, base),
|
|
50
|
-
"push": lambda: cmd_push(config, base, mode=args.push_mode),
|
|
54
|
+
"status": lambda: cmd_status(config, base, json_output=args.json),
|
|
55
|
+
"pull": lambda: cmd_pull(config, base, dry_run=args.dry_run),
|
|
56
|
+
"push": lambda: cmd_push(config, base, mode=args.push_mode, dry_run=args.dry_run),
|
|
51
57
|
"repos": lambda: cmd_repos(config, base, config_path),
|
|
52
58
|
}
|
|
53
59
|
commands[args.command]()
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import json
|
|
1
2
|
import shutil
|
|
2
3
|
import subprocess
|
|
3
4
|
import sys
|
|
@@ -137,8 +138,25 @@ def _sync_one(platform, local_path, remote_path, d):
|
|
|
137
138
|
_emit(lines)
|
|
138
139
|
|
|
139
140
|
|
|
140
|
-
def
|
|
141
|
+
def _pull_dry_run(label, d):
|
|
142
|
+
"""Report ahead/behind vs. upstream without touching the repo."""
|
|
143
|
+
counts = subprocess.run(
|
|
144
|
+
["git", "-C", str(d), "rev-list", "--left-right", "--count", "HEAD...@{u}"],
|
|
145
|
+
capture_output=True, text=True,
|
|
146
|
+
)
|
|
147
|
+
if counts.returncode != 0:
|
|
148
|
+
return [f"{WARN} {label}: no upstream branch set"]
|
|
149
|
+
ahead, behind = counts.stdout.split()
|
|
150
|
+
if ahead == "0" and behind == "0":
|
|
151
|
+
return [f"{OK} {_DIM}{label}{_RST}"]
|
|
152
|
+
return [f"{UPD} {label}: {ahead} ahead, {behind} behind"]
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def _pull_one(platform, local_path, d, dry_run=False):
|
|
141
156
|
label = f"{platform}/{local_path}"
|
|
157
|
+
if dry_run:
|
|
158
|
+
_emit(_pull_dry_run(label, d))
|
|
159
|
+
return
|
|
142
160
|
lines = []
|
|
143
161
|
stashed = False
|
|
144
162
|
if is_dirty(d):
|
|
@@ -177,7 +195,7 @@ def cmd_sync(config, base):
|
|
|
177
195
|
f.result()
|
|
178
196
|
|
|
179
197
|
|
|
180
|
-
def cmd_status(config, base):
|
|
198
|
+
def cmd_status(config, base, json_output=False):
|
|
181
199
|
results = []
|
|
182
200
|
|
|
183
201
|
def _check(platform, local_path, d):
|
|
@@ -193,6 +211,15 @@ def cmd_status(config, base):
|
|
|
193
211
|
for f in as_completed(futures):
|
|
194
212
|
results.append(f.result())
|
|
195
213
|
|
|
214
|
+
if json_output:
|
|
215
|
+
entries = [
|
|
216
|
+
{"platform": platform, "path": local_path, "changed_files": len(output.splitlines())}
|
|
217
|
+
for platform, local_path, output in sorted(results)
|
|
218
|
+
if output
|
|
219
|
+
]
|
|
220
|
+
print(json.dumps(entries))
|
|
221
|
+
return
|
|
222
|
+
|
|
196
223
|
found_dirty = False
|
|
197
224
|
for platform, local_path, output in sorted(results):
|
|
198
225
|
if output:
|
|
@@ -204,15 +231,15 @@ def cmd_status(config, base):
|
|
|
204
231
|
print(f"{OK} All repos are clean.")
|
|
205
232
|
|
|
206
233
|
|
|
207
|
-
def cmd_pull(config, base):
|
|
234
|
+
def cmd_pull(config, base, dry_run=False):
|
|
208
235
|
repos = list(each_existing_repo(config, base))
|
|
209
236
|
with ThreadPoolExecutor(max_workers=MAX_WORKERS) as pool:
|
|
210
|
-
futures = [pool.submit(_pull_one, p, lp, d) for p, lp, _, d in repos]
|
|
237
|
+
futures = [pool.submit(_pull_one, p, lp, d, dry_run) for p, lp, _, d in repos]
|
|
211
238
|
for f in as_completed(futures):
|
|
212
239
|
f.result()
|
|
213
240
|
|
|
214
241
|
|
|
215
|
-
def cmd_push(config, base, mode="interactive"):
|
|
242
|
+
def cmd_push(config, base, mode="interactive", dry_run=False):
|
|
216
243
|
dirty = [
|
|
217
244
|
(platform, local_path, d)
|
|
218
245
|
for platform, local_path, _, d in each_existing_repo(config, base)
|
|
@@ -223,6 +250,12 @@ def cmd_push(config, base, mode="interactive"):
|
|
|
223
250
|
print("No dirty repos to commit.")
|
|
224
251
|
return
|
|
225
252
|
|
|
253
|
+
if dry_run:
|
|
254
|
+
print("Would commit and push the following dirty repos:")
|
|
255
|
+
for platform, local_path, _ in dirty:
|
|
256
|
+
print(f" {platform}/{local_path}")
|
|
257
|
+
return
|
|
258
|
+
|
|
226
259
|
if mode == "wip":
|
|
227
260
|
msg = f"WIP {datetime.now().strftime('%Y-%m-%d %H:%M')}"
|
|
228
261
|
with ThreadPoolExecutor(max_workers=MAX_WORKERS) as pool:
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import subprocess
|
|
3
|
+
import tempfile
|
|
4
|
+
import pytest
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from polygit.config import find_config, load_config, write_config
|
|
7
|
+
from polygit.repos import parse_remote_url, del_nested, _add_to_config
|
|
8
|
+
from polygit.repo import walk, _pull_one, cmd_push, cmd_status
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
# ── parse_remote_url ──────────────────────────────────────────────────────────
|
|
12
|
+
|
|
13
|
+
def test_parse_github_ssh():
|
|
14
|
+
platform, path = parse_remote_url("git@github.com:gschaetz/mousehat.git")
|
|
15
|
+
assert platform == "github"
|
|
16
|
+
assert path == "gschaetz/mousehat"
|
|
17
|
+
|
|
18
|
+
def test_parse_gitlab_ssh_nested():
|
|
19
|
+
platform, path = parse_remote_url("git@gitlab.com:gary.schaetz/private/dev-setup.git")
|
|
20
|
+
assert platform == "gitlab"
|
|
21
|
+
assert path == "gary.schaetz/private/dev-setup"
|
|
22
|
+
|
|
23
|
+
def test_parse_https():
|
|
24
|
+
platform, path = parse_remote_url("https://github.com/openclaw/openclaw")
|
|
25
|
+
assert platform == "github"
|
|
26
|
+
assert path == "openclaw/openclaw"
|
|
27
|
+
|
|
28
|
+
def test_parse_none():
|
|
29
|
+
platform, path = parse_remote_url(None)
|
|
30
|
+
assert platform is None
|
|
31
|
+
assert path is None
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
# ── walk ──────────────────────────────────────────────────────────────────────
|
|
35
|
+
|
|
36
|
+
def test_walk_null():
|
|
37
|
+
results = list(walk(None, "ns/repo"))
|
|
38
|
+
assert results == [("ns/repo", "ns/repo")]
|
|
39
|
+
|
|
40
|
+
def test_walk_remote_override():
|
|
41
|
+
results = list(walk({"remote": "other/repo"}, "ns/local"))
|
|
42
|
+
assert results == [("ns/local", "other/repo")]
|
|
43
|
+
|
|
44
|
+
def test_walk_nested():
|
|
45
|
+
node = {"a": None, "b": {"c": None}}
|
|
46
|
+
results = list(walk(node, "ns"))
|
|
47
|
+
assert ("ns/a", "ns/a") in results
|
|
48
|
+
assert ("ns/b/c", "ns/b/c") in results
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
# ── del_nested ────────────────────────────────────────────────────────────────
|
|
52
|
+
|
|
53
|
+
def test_del_nested_simple():
|
|
54
|
+
d = {"a": {"b": None}}
|
|
55
|
+
del_nested(d, ["a", "b"])
|
|
56
|
+
assert d == {}
|
|
57
|
+
|
|
58
|
+
def test_del_nested_preserves_siblings():
|
|
59
|
+
d = {"a": {"b": None, "c": None}}
|
|
60
|
+
del_nested(d, ["a", "b"])
|
|
61
|
+
assert d == {"a": {"c": None}}
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
# ── _add_to_config ──────────────────────────────────────────────────────────
|
|
65
|
+
|
|
66
|
+
def test_add_to_config_plain():
|
|
67
|
+
config = {}
|
|
68
|
+
_add_to_config(config, "github", "gschaetz/mousehat", "git@github.com:gschaetz/mousehat.git")
|
|
69
|
+
assert config == {"github": {"gschaetz": {"mousehat": None}}}
|
|
70
|
+
|
|
71
|
+
def test_add_to_config_cross_namespace_override():
|
|
72
|
+
# Local dir lives under a namespace unrelated to the remote org — must
|
|
73
|
+
# nest under the local namespace, not silently fall back to the remote's.
|
|
74
|
+
config = {}
|
|
75
|
+
_add_to_config(config, "github", "community/modelrelay", "git@github.com:ellipticmarketing/modelrelay.git")
|
|
76
|
+
assert config == {"github": {"community": {"modelrelay": {"remote": "ellipticmarketing/modelrelay"}}}}
|
|
77
|
+
|
|
78
|
+
def test_add_to_config_no_remote():
|
|
79
|
+
config = {}
|
|
80
|
+
_add_to_config(config, "github", "gschaetz/scratch", None)
|
|
81
|
+
assert config == {"github": {"gschaetz": {"scratch": None}}}
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
# ── find_config / write_config / load_config ──────────────────────────────────
|
|
85
|
+
|
|
86
|
+
def test_find_config_in_cwd():
|
|
87
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
88
|
+
config_path = Path(tmp) / ".pgit"
|
|
89
|
+
config_path.write_text("github:\n org:\n repo:\n")
|
|
90
|
+
found = find_config(start=tmp)
|
|
91
|
+
assert found == config_path
|
|
92
|
+
|
|
93
|
+
def test_find_config_walks_up():
|
|
94
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
95
|
+
config_path = Path(tmp) / ".pgit"
|
|
96
|
+
config_path.write_text("github:\n org:\n repo:\n")
|
|
97
|
+
subdir = Path(tmp) / "sub" / "dir"
|
|
98
|
+
subdir.mkdir(parents=True)
|
|
99
|
+
found = find_config(start=subdir)
|
|
100
|
+
assert found == config_path
|
|
101
|
+
|
|
102
|
+
def test_find_config_not_found():
|
|
103
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
104
|
+
found = find_config(start=tmp)
|
|
105
|
+
assert found is None
|
|
106
|
+
|
|
107
|
+
def test_write_and_load_roundtrip():
|
|
108
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
109
|
+
path = Path(tmp) / ".pgit"
|
|
110
|
+
data = {
|
|
111
|
+
"github": {
|
|
112
|
+
"gschaetz": {"mousehat": None, "dotfiles": None},
|
|
113
|
+
"community": {"openclaw": {"remote": "openclaw/openclaw"}},
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
write_config(data, path)
|
|
117
|
+
loaded = load_config(path)
|
|
118
|
+
assert loaded["github"]["gschaetz"]["mousehat"] is None
|
|
119
|
+
assert loaded["github"]["community"]["openclaw"] == {"remote": "openclaw/openclaw"}
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
# ── dry-run pull / push ──────────────────────────────────────────────────────
|
|
123
|
+
|
|
124
|
+
def _git(d, *args):
|
|
125
|
+
subprocess.run(["git", "-C", str(d), *args], check=True, capture_output=True)
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def _commit(d, name):
|
|
129
|
+
(d / name).write_text(name)
|
|
130
|
+
_git(d, "add", ".")
|
|
131
|
+
_git(d, "-c", "user.email=t@t.com", "-c", "user.name=T", "commit", "-qm", name)
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def _make_clone(tmp, ahead=0, behind=0):
|
|
135
|
+
"""Clone of a bare origin, `ahead` commits ahead and `behind` behind it."""
|
|
136
|
+
origin = tmp / "origin.git"
|
|
137
|
+
subprocess.run(["git", "init", "-q", "--bare", "-b", "main", str(origin)], check=True)
|
|
138
|
+
seed = tmp / "seed"
|
|
139
|
+
subprocess.run(["git", "clone", "-q", str(origin), str(seed)], check=True, capture_output=True)
|
|
140
|
+
_commit(seed, "init")
|
|
141
|
+
_git(seed, "push", "-q", "origin", "HEAD:main")
|
|
142
|
+
d = tmp / "github" / "r"
|
|
143
|
+
d.parent.mkdir()
|
|
144
|
+
subprocess.run(["git", "clone", "-q", str(origin), str(d)], check=True, capture_output=True)
|
|
145
|
+
for i in range(behind):
|
|
146
|
+
_commit(seed, f"b{i}")
|
|
147
|
+
if behind:
|
|
148
|
+
_git(seed, "push", "-q", "origin", "HEAD:main")
|
|
149
|
+
_git(d, "fetch", "-q")
|
|
150
|
+
for i in range(ahead):
|
|
151
|
+
_commit(d, f"a{i}")
|
|
152
|
+
return d
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def test_pull_dry_run_shows_ahead_behind(capsys, tmp_path):
|
|
156
|
+
d = _make_clone(tmp_path, ahead=2, behind=1)
|
|
157
|
+
_pull_one("github", "r", d, dry_run=True)
|
|
158
|
+
assert "2 ahead, 1 behind" in capsys.readouterr().out
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def test_pull_dry_run_up_to_date(capsys, tmp_path):
|
|
162
|
+
d = _make_clone(tmp_path)
|
|
163
|
+
_pull_one("github", "r", d, dry_run=True)
|
|
164
|
+
out = capsys.readouterr().out
|
|
165
|
+
assert "github/r" in out
|
|
166
|
+
assert "ahead" not in out and "behind" not in out
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def test_pull_dry_run_no_upstream(capsys, tmp_path):
|
|
170
|
+
d = tmp_path / "r"
|
|
171
|
+
subprocess.run(["git", "init", "-q", str(d)], check=True)
|
|
172
|
+
_pull_one("github", "r", d, dry_run=True)
|
|
173
|
+
assert "no upstream" in capsys.readouterr().out
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def test_pull_dry_run_leaves_dirty_tree_alone(tmp_path):
|
|
177
|
+
d = _make_clone(tmp_path)
|
|
178
|
+
(d / "init").write_text("edited")
|
|
179
|
+
(d / "new.txt").write_text("x")
|
|
180
|
+
_pull_one("github", "r", d, dry_run=True)
|
|
181
|
+
assert (d / "init").read_text() == "edited"
|
|
182
|
+
assert (d / "new.txt").exists()
|
|
183
|
+
stash = subprocess.run(["git", "-C", str(d), "stash", "list"],
|
|
184
|
+
capture_output=True, text=True).stdout
|
|
185
|
+
assert stash == ""
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def test_push_dry_run_lists_dirty_without_committing(capsys, tmp_path):
|
|
189
|
+
d = _make_clone(tmp_path)
|
|
190
|
+
(d / "dirty.txt").write_text("x")
|
|
191
|
+
cmd_push({"github": {"r": None}}, tmp_path, dry_run=True)
|
|
192
|
+
out = capsys.readouterr().out
|
|
193
|
+
assert "Would commit and push" in out
|
|
194
|
+
assert "github/r" in out
|
|
195
|
+
assert (d / "dirty.txt").exists()
|
|
196
|
+
log = subprocess.run(["git", "-C", str(d), "log", "--oneline"],
|
|
197
|
+
capture_output=True, text=True).stdout
|
|
198
|
+
assert len(log.splitlines()) == 1
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
# ── status --json ────────────────────────────────────────────────────────────
|
|
202
|
+
|
|
203
|
+
def test_status_json_lists_dirty_repos(capsys, tmp_path):
|
|
204
|
+
d = _make_clone(tmp_path)
|
|
205
|
+
(d / "init").write_text("edited")
|
|
206
|
+
(d / "a.txt").write_text("a")
|
|
207
|
+
(d / "b.txt").write_text("b")
|
|
208
|
+
|
|
209
|
+
cmd_status({"github": {"r": None}}, tmp_path, json_output=True)
|
|
210
|
+
|
|
211
|
+
payload = json.loads(capsys.readouterr().out)
|
|
212
|
+
assert payload == [{"platform": "github", "path": "r", "changed_files": 3}]
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def test_status_json_empty_when_clean(capsys, tmp_path):
|
|
216
|
+
_make_clone(tmp_path)
|
|
217
|
+
cmd_status({"github": {"r": None}}, tmp_path, json_output=True)
|
|
218
|
+
assert json.loads(capsys.readouterr().out) == []
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
def test_status_json_omits_clean_repos(capsys, tmp_path):
|
|
222
|
+
_make_clone(tmp_path)
|
|
223
|
+
dirty = tmp_path / "github" / "other"
|
|
224
|
+
subprocess.run(["git", "clone", "-q", str(tmp_path / "origin.git"), str(dirty)],
|
|
225
|
+
check=True, capture_output=True)
|
|
226
|
+
(dirty / "x.txt").write_text("x")
|
|
227
|
+
|
|
228
|
+
cmd_status({"github": {"r": None, "other": None}}, tmp_path, json_output=True)
|
|
229
|
+
|
|
230
|
+
payload = json.loads(capsys.readouterr().out)
|
|
231
|
+
assert payload == [{"platform": "github", "path": "other", "changed_files": 1}]
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
def test_status_default_output_unchanged(capsys, tmp_path):
|
|
235
|
+
d = _make_clone(tmp_path)
|
|
236
|
+
(d / "dirty.txt").write_text("x")
|
|
237
|
+
|
|
238
|
+
cmd_status({"github": {"r": None}}, tmp_path)
|
|
239
|
+
out = capsys.readouterr().out
|
|
240
|
+
|
|
241
|
+
assert "github/r" in out
|
|
242
|
+
assert "dirty.txt" in out
|
|
243
|
+
assert out.strip()[0] != "["
|
|
244
|
+
with pytest.raises(ValueError):
|
|
245
|
+
json.loads(out)
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
def test_status_default_clean_message(capsys, tmp_path):
|
|
249
|
+
_make_clone(tmp_path)
|
|
250
|
+
cmd_status({"github": {"r": None}}, tmp_path)
|
|
251
|
+
assert "All repos are clean." in capsys.readouterr().out
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
version = 1
|
|
2
|
-
revision =
|
|
2
|
+
revision = 5
|
|
3
3
|
requires-python = ">=3.8"
|
|
4
4
|
resolution-markers = [
|
|
5
5
|
"python_full_version >= '3.10'",
|
|
@@ -44,25 +44,41 @@ wheels = [
|
|
|
44
44
|
|
|
45
45
|
[[package]]
|
|
46
46
|
name = "iniconfig"
|
|
47
|
-
version = "2.3.
|
|
47
|
+
version = "2.3.1"
|
|
48
48
|
source = { registry = "https://pypi.org/simple" }
|
|
49
49
|
resolution-markers = [
|
|
50
50
|
"python_full_version >= '3.10'",
|
|
51
51
|
]
|
|
52
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
|
52
|
+
sdist = { url = "https://files.pythonhosted.org/packages/01/e1/2069291243c926a2ff1cd706c7f3eeb9b62144bf60f77c9fb9ff2fb26bd3/iniconfig-2.3.1.tar.gz", hash = "sha256:67f4b9c50da0dedf52af349e7749a80a9057a5031199791b906c3bb3ae878960", size = 21209, upload-time = "2026-10-06T22:48:38.076Z" }
|
|
53
53
|
wheels = [
|
|
54
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
54
|
+
{ url = "https://files.pythonhosted.org/packages/56/43/4ca9e49d27a1fcf6bece6f6aec0ea46bb9112489b93d4b688fb415457bdb/iniconfig-2.3.1-py3-none-any.whl", hash = "sha256:9121e2c1fdb355232495be3194c8dfe87ccc2d5dee45947b78e68f499790d7a7", size = 7552, upload-time = "2026-10-06T22:48:36.959Z" },
|
|
55
55
|
]
|
|
56
56
|
|
|
57
57
|
[[package]]
|
|
58
58
|
name = "packaging"
|
|
59
59
|
version = "26.2"
|
|
60
60
|
source = { registry = "https://pypi.org/simple" }
|
|
61
|
+
resolution-markers = [
|
|
62
|
+
"python_full_version < '3.9'",
|
|
63
|
+
]
|
|
61
64
|
sdist = { url = "https://files.pythonhosted.org/packages/d7/f1/e7a6dd94a8d4a5626c03e4e99c87f241ba9e350cd9e6d75123f992427270/packaging-26.2.tar.gz", hash = "sha256:ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661", size = 228134, upload-time = "2026-04-24T20:15:23.917Z" }
|
|
62
65
|
wheels = [
|
|
63
66
|
{ url = "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl", hash = "sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e", size = 100195, upload-time = "2026-04-24T20:15:22.081Z" },
|
|
64
67
|
]
|
|
65
68
|
|
|
69
|
+
[[package]]
|
|
70
|
+
name = "packaging"
|
|
71
|
+
version = "26.3"
|
|
72
|
+
source = { registry = "https://pypi.org/simple" }
|
|
73
|
+
resolution-markers = [
|
|
74
|
+
"python_full_version >= '3.10'",
|
|
75
|
+
"python_full_version == '3.9.*'",
|
|
76
|
+
]
|
|
77
|
+
sdist = { url = "https://files.pythonhosted.org/packages/7d/fa/3944b40b07da9ce895c0e6303a5ab7d53da063554f534556b134a54d6093/packaging-26.3.tar.gz", hash = "sha256:94edc256424af38762eb31306eed28beb9f0efc50a8837492c9d6fd6004aed79", size = 313412, upload-time = "2026-08-04T18:15:28.737Z" }
|
|
78
|
+
wheels = [
|
|
79
|
+
{ url = "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl", hash = "sha256:d7193f7c8e4e93f444fde0262bf90af30e16fa0ad0ad44cb553c87339b23cd1c", size = 129956, upload-time = "2026-08-04T18:15:27.159Z" },
|
|
80
|
+
]
|
|
81
|
+
|
|
66
82
|
[[package]]
|
|
67
83
|
name = "pluggy"
|
|
68
84
|
version = "1.5.0"
|
|
@@ -80,7 +96,6 @@ name = "pluggy"
|
|
|
80
96
|
version = "1.6.0"
|
|
81
97
|
source = { registry = "https://pypi.org/simple" }
|
|
82
98
|
resolution-markers = [
|
|
83
|
-
"python_full_version >= '3.10'",
|
|
84
99
|
"python_full_version == '3.9.*'",
|
|
85
100
|
]
|
|
86
101
|
sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" }
|
|
@@ -88,9 +103,21 @@ wheels = [
|
|
|
88
103
|
{ url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" },
|
|
89
104
|
]
|
|
90
105
|
|
|
106
|
+
[[package]]
|
|
107
|
+
name = "pluggy"
|
|
108
|
+
version = "1.7.0"
|
|
109
|
+
source = { registry = "https://pypi.org/simple" }
|
|
110
|
+
resolution-markers = [
|
|
111
|
+
"python_full_version >= '3.10'",
|
|
112
|
+
]
|
|
113
|
+
sdist = { url = "https://files.pythonhosted.org/packages/bf/db/7fc19e6f2dc92a966727031389fc2e08b558f0f25eb7403c1119ad4713cd/pluggy-1.7.0.tar.gz", hash = "sha256:d1eaa46ebb595891b860ab086b4d09c8588af65ebd4361b8e8f4bb8920b90ba8", size = 123304, upload-time = "2026-10-15T09:50:58.343Z" }
|
|
114
|
+
wheels = [
|
|
115
|
+
{ url = "https://files.pythonhosted.org/packages/40/9e/2b38731e0fc536806f16490e1a12d7f0dc2a1235aa8cc07bcc75416a7daa/pluggy-1.7.0-py3-none-any.whl", hash = "sha256:7dd7b0d8832ba3cb632c306926ded123429211b83641b35dc5c41ad2d34f9bec", size = 27082, upload-time = "2026-10-15T09:50:56.808Z" },
|
|
116
|
+
]
|
|
117
|
+
|
|
91
118
|
[[package]]
|
|
92
119
|
name = "polygit"
|
|
93
|
-
version = "0.
|
|
120
|
+
version = "0.5.0"
|
|
94
121
|
source = { editable = "." }
|
|
95
122
|
dependencies = [
|
|
96
123
|
{ name = "pyyaml" },
|
|
@@ -111,11 +138,11 @@ dev = [{ name = "pytest", specifier = ">=8.0" }]
|
|
|
111
138
|
|
|
112
139
|
[[package]]
|
|
113
140
|
name = "pygments"
|
|
114
|
-
version = "2.
|
|
141
|
+
version = "2.21.0"
|
|
115
142
|
source = { registry = "https://pypi.org/simple" }
|
|
116
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
|
143
|
+
sdist = { url = "https://files.pythonhosted.org/packages/49/2e/ced460408999b33da6b31b0021b0f37d329e202d4169aeb164493778f25b/pygments-2.21.0.tar.gz", hash = "sha256:610ca751c9bc2492b38eb9a38a7fbc93edbbb2d7182edaf34e66ae493dee5c8c", size = 5005329, upload-time = "2026-08-17T08:02:48.824Z" }
|
|
117
144
|
wheels = [
|
|
118
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
145
|
+
{ url = "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl", hash = "sha256:2363c69b61c4a97c838da3b130dcd6468f4848992b21a82f2a63ec34377137d9", size = 1250147, upload-time = "2026-08-17T08:02:44.912Z" },
|
|
119
146
|
]
|
|
120
147
|
|
|
121
148
|
[[package]]
|
|
@@ -129,7 +156,7 @@ dependencies = [
|
|
|
129
156
|
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
|
130
157
|
{ name = "exceptiongroup" },
|
|
131
158
|
{ name = "iniconfig", version = "2.1.0", source = { registry = "https://pypi.org/simple" } },
|
|
132
|
-
{ name = "packaging" },
|
|
159
|
+
{ name = "packaging", version = "26.2", source = { registry = "https://pypi.org/simple" } },
|
|
133
160
|
{ name = "pluggy", version = "1.5.0", source = { registry = "https://pypi.org/simple" } },
|
|
134
161
|
{ name = "tomli" },
|
|
135
162
|
]
|
|
@@ -149,7 +176,7 @@ dependencies = [
|
|
|
149
176
|
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
|
150
177
|
{ name = "exceptiongroup" },
|
|
151
178
|
{ name = "iniconfig", version = "2.1.0", source = { registry = "https://pypi.org/simple" } },
|
|
152
|
-
{ name = "packaging" },
|
|
179
|
+
{ name = "packaging", version = "26.3", source = { registry = "https://pypi.org/simple" } },
|
|
153
180
|
{ name = "pluggy", version = "1.6.0", source = { registry = "https://pypi.org/simple" } },
|
|
154
181
|
{ name = "pygments" },
|
|
155
182
|
{ name = "tomli" },
|
|
@@ -169,9 +196,9 @@ resolution-markers = [
|
|
|
169
196
|
dependencies = [
|
|
170
197
|
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
|
171
198
|
{ name = "exceptiongroup", marker = "python_full_version < '3.11'" },
|
|
172
|
-
{ name = "iniconfig", version = "2.3.
|
|
173
|
-
{ name = "packaging" },
|
|
174
|
-
{ name = "pluggy", version = "1.
|
|
199
|
+
{ name = "iniconfig", version = "2.3.1", source = { registry = "https://pypi.org/simple" } },
|
|
200
|
+
{ name = "packaging", version = "26.3", source = { registry = "https://pypi.org/simple" } },
|
|
201
|
+
{ name = "pluggy", version = "1.7.0", source = { registry = "https://pypi.org/simple" } },
|
|
175
202
|
{ name = "pygments" },
|
|
176
203
|
{ name = "tomli", marker = "python_full_version < '3.11'" },
|
|
177
204
|
]
|
|
@@ -262,56 +289,74 @@ wheels = [
|
|
|
262
289
|
|
|
263
290
|
[[package]]
|
|
264
291
|
name = "tomli"
|
|
265
|
-
version = "2.
|
|
292
|
+
version = "2.5.0"
|
|
266
293
|
source = { registry = "https://pypi.org/simple" }
|
|
267
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
|
294
|
+
sdist = { url = "https://files.pythonhosted.org/packages/b0/78/9ad63712633ed3ab5cc1a648d863d7e7da371e9425e209555a0fe711b695/tomli-2.5.0.tar.gz", hash = "sha256:264507556cd8b8c8e7c6ee037cdf443a463f03f4c958e57195e3d369711b8ff6", size = 17662, upload-time = "2026-10-07T12:23:37.892Z" }
|
|
268
295
|
wheels = [
|
|
269
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
270
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
271
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
272
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
273
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
274
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
275
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
276
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
277
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
278
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
279
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
280
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
281
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
282
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
283
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
284
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
285
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
286
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
287
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
288
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
289
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
290
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
291
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
292
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
293
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
294
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
295
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
296
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
297
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
298
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
299
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
300
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
301
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
302
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
303
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
304
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
305
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
306
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
307
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
308
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
309
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
310
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
311
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
312
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
313
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
314
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
296
|
+
{ url = "https://files.pythonhosted.org/packages/22/a6/ab99b60ee52acd949684febabc3005d0045d0f66bebd9cdebd67372d26dd/tomli-2.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c4dc1c1781f2f716de763d1e9a7b34c6a894e167e291c7c5d16c72f7a9538545", size = 163901, upload-time = "2026-10-07T12:22:15.601Z" },
|
|
297
|
+
{ url = "https://files.pythonhosted.org/packages/bc/00/ee01b7ed4579180fff07142d290257f25ba786f23f3ec6005f620933c2f5/tomli-2.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:eff8babca5a7999bc137acbc7482a8b7e17ffca5075ab41f5d770ab408c7bfef", size = 163756, upload-time = "2026-10-07T12:22:16.957Z" },
|
|
298
|
+
{ url = "https://files.pythonhosted.org/packages/72/c2/4efebf65372f6583185f79799312109dddb61102d47e5c33dcfd1a297aca/tomli-2.5.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:86665cee9c4835b7a7f1e8ec2c719b5258d4dc782887aded5a8ae7352a96843b", size = 268038, upload-time = "2026-10-07T12:22:18.135Z" },
|
|
299
|
+
{ url = "https://files.pythonhosted.org/packages/53/07/5850468e925d898abb36038666f9c333a94d2a223e802a8ba5b6d319d23f/tomli-2.5.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d7e369fd63331746182360977b1892bfc215476a30d61612d732425311639f56", size = 276422, upload-time = "2026-10-07T12:22:19.567Z" },
|
|
300
|
+
{ url = "https://files.pythonhosted.org/packages/b4/87/f293984cdcf83c054196d4fd3dad44fc68ae55b4b8c44bc76cef360c3150/tomli-2.5.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7ad1ea345759240d6463efa0ed1c704402752e49aa21476620738d74d72d8aa1", size = 272616, upload-time = "2026-10-07T12:22:20.794Z" },
|
|
301
|
+
{ url = "https://files.pythonhosted.org/packages/ce/ce/db582886b3c1219d3fec93ebd669332482e5aee7a91e0f7838d84f2d1759/tomli-2.5.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:96243987194634bd411066ce40c952e108f86af04db533ecd8ac3ff2a85b1885", size = 276593, upload-time = "2026-10-07T12:22:22.12Z" },
|
|
302
|
+
{ url = "https://files.pythonhosted.org/packages/bf/72/7619b87dea4261fc27dd7b54c4461c129c1f7d9bb7ba3aec89c797a431b8/tomli-2.5.0-cp311-cp311-win32.whl", hash = "sha256:610b27d99f28ec5f191c7064a48f3ddb179a1fe6ca73d571483ae859f57b605e", size = 101830, upload-time = "2026-10-07T12:22:23.651Z" },
|
|
303
|
+
{ url = "https://files.pythonhosted.org/packages/1e/74/220106da34502304b6751a2a9b8a9fbca6c3fd47e737a2e2e3da7c61c9db/tomli-2.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:c804ae44fe7b4bab5da295e4f980a1ff04670bca9d23fe0a4e887e08ebd741a8", size = 112742, upload-time = "2026-10-07T12:22:24.972Z" },
|
|
304
|
+
{ url = "https://files.pythonhosted.org/packages/27/99/7d9c8b41837a7773613e169504147375c157a290167aa59ad74a085f521f/tomli-2.5.0-cp311-cp311-win_arm64.whl", hash = "sha256:cfac177ebd6236003846ea339981f71457cb6eb748f23381eb257e45092e3980", size = 109332, upload-time = "2026-10-07T12:22:26.117Z" },
|
|
305
|
+
{ url = "https://files.pythonhosted.org/packages/52/ed/7baa86f87493646a594de388c7c1c40a39dd0461f7e9c0359cbeefc91fe8/tomli-2.5.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:1f4a40d03fb9f63424f0979855bdeaf44dd7696b8d59501822c10ed30ba532df", size = 164854, upload-time = "2026-10-07T12:22:27.444Z" },
|
|
306
|
+
{ url = "https://files.pythonhosted.org/packages/a5/b1/44c0341f2224397855723c7a8a39f718ea6fcbcc3dacc66e5aeca0f334e3/tomli-2.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9ebf8d19b17bd0daeb7b7dec81a946a439b753942fd0210d6e96c532249eea6b", size = 164074, upload-time = "2026-10-07T12:22:28.679Z" },
|
|
307
|
+
{ url = "https://files.pythonhosted.org/packages/23/04/e2d5b7d3fba47adedb23de616c16d428ea076c79a3d8e1d95d649ffe197e/tomli-2.5.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bf0b5e8e0f68ebb494356e577c06c139161efd8d3b9050f93b39b7c26cc54ff0", size = 274274, upload-time = "2026-10-07T12:22:29.804Z" },
|
|
308
|
+
{ url = "https://files.pythonhosted.org/packages/43/90/6090e706ff27a6f89f4a40578e3324b95c3cd8c4150868aabf33a8f414c3/tomli-2.5.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6cf74416bdc94ae458b14e37286c1073081850ac8459a00d0c5efef5d44294c6", size = 286435, upload-time = "2026-10-07T12:22:31.297Z" },
|
|
309
|
+
{ url = "https://files.pythonhosted.org/packages/0a/9e/a2c40768df16c408f22430afb0a73e9d7e5f79c950884954649d1146b74d/tomli-2.5.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:61ea1ebe1e55a34ea8199cc8dbff398d35027b82271c8ac4802fd3a1fd5b1bcc", size = 278119, upload-time = "2026-10-07T12:22:32.601Z" },
|
|
310
|
+
{ url = "https://files.pythonhosted.org/packages/12/25/3c0cb485b98e9cfac495629b1c93c87ccf0b72fbe9d2689fd8fe62c6d5a3/tomli-2.5.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ed53f7e89bb04f6d9e8e7799112360b0c4d5cbff067de0814c98c37c39b920f7", size = 286177, upload-time = "2026-10-07T12:22:33.745Z" },
|
|
311
|
+
{ url = "https://files.pythonhosted.org/packages/77/8b/0144c65f0e37e51c18d04ae15c21b19431c165002d0131fe9aa8b0b8b1e8/tomli-2.5.0-cp312-cp312-win32.whl", hash = "sha256:e7ad033e27a516a233bea839cdb77b80146facb3b4f40bf02cd0cac165cdd5c2", size = 102760, upload-time = "2026-10-07T12:22:34.887Z" },
|
|
312
|
+
{ url = "https://files.pythonhosted.org/packages/de/32/5d6d8f42fc9a05fce69354e00ff256484192f5f2fc9a2165718fa0de61ec/tomli-2.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:bd05de8c1698f8413dd7d869492693a0bf2211543b787ac78cd5e7536af1a6d7", size = 112722, upload-time = "2026-10-07T12:22:36.162Z" },
|
|
313
|
+
{ url = "https://files.pythonhosted.org/packages/30/65/df18032218db0fb9b769fb23c8039a051f15c811993995ea04c350273a32/tomli-2.5.0-cp312-cp312-win_arm64.whl", hash = "sha256:069435bd5480429b98c5e5afb02ab21c219b6f0064680671c6dc0d46817346ea", size = 109534, upload-time = "2026-10-07T12:22:37.296Z" },
|
|
314
|
+
{ url = "https://files.pythonhosted.org/packages/42/e5/51736d70da209350969e15aca5c5ab6e2ce1ea87a0a892a6c13aec172a86/tomli-2.5.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:943276cf269e0071948d9ff697159c1735e623c1151d88abb09b74659ef0cbea", size = 163328, upload-time = "2026-10-07T12:22:38.373Z" },
|
|
315
|
+
{ url = "https://files.pythonhosted.org/packages/ec/55/086f80dab4ab497602644274e6dea7ec5dd0b4e262e443a8ad3bb7edee2d/tomli-2.5.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:463b16086865b97facd8d0b3fb4cb7c544e3f58d2a69dc3113d6db9653fdb043", size = 162246, upload-time = "2026-10-07T12:22:39.673Z" },
|
|
316
|
+
{ url = "https://files.pythonhosted.org/packages/aa/eb/3ecc94459f3635c92321f4e7bde571323fdb2267c50e19e3188a281eae3b/tomli-2.5.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1245a6638fc4bb0a60af38a7d45413db34a13842027c77597c712c998c62fdf0", size = 272655, upload-time = "2026-10-07T12:22:41.08Z" },
|
|
317
|
+
{ url = "https://files.pythonhosted.org/packages/c0/d7/494fd1f0c37a621f1ad9975c2efadb523e8101f144ed6edb2e7fe64738f2/tomli-2.5.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5d8bac3d603c97e6854424e5b2b5b741bdbde387e09f162fb0446812b4a8362b", size = 283595, upload-time = "2026-10-07T12:22:42.222Z" },
|
|
318
|
+
{ url = "https://files.pythonhosted.org/packages/70/51/bb8d62b1317e6640866f6949b2d5855e5300f2c99d46de1cd245570bba65/tomli-2.5.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:21e4cae4114aba25aa0d4f85cdf486d290fb35c0954d7bba536248da64d43066", size = 276253, upload-time = "2026-10-07T12:22:43.625Z" },
|
|
319
|
+
{ url = "https://files.pythonhosted.org/packages/66/f4/f46bd7f0763cd47de2db697dca9257c6a4adfd1a93b018cc75c8190ed5a8/tomli-2.5.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:bbaefc84548d754be821bba7c4141c4787dda182f9e77f2f87b71213529efa7b", size = 283582, upload-time = "2026-10-07T12:22:44.983Z" },
|
|
320
|
+
{ url = "https://files.pythonhosted.org/packages/ac/03/70f2bcb2923a6db37818d917e124270a7f4cfd38ea576f5aa753a91c0ef5/tomli-2.5.0-cp313-cp313-win32.whl", hash = "sha256:abdbf6313b8d9efe157edeb7ab6eae4de064b1300ad31abf73755154b30abe68", size = 102628, upload-time = "2026-10-07T12:22:46.508Z" },
|
|
321
|
+
{ url = "https://files.pythonhosted.org/packages/dc/98/d52024bb5b0ff68b4f0d276d867f634c84a67319a7e9f6b7708a37742333/tomli-2.5.0-cp313-cp313-win_amd64.whl", hash = "sha256:fd4dc129784e0c5335bd4e61dfcc4487499a013419e655cf2da1d091b7e0efdc", size = 113301, upload-time = "2026-10-07T12:22:47.647Z" },
|
|
322
|
+
{ url = "https://files.pythonhosted.org/packages/6f/f2/540db3a70572a8c23a28aba3e9c358ce0ffffbafc990905c1343aa265b31/tomli-2.5.0-cp313-cp313-win_arm64.whl", hash = "sha256:69491c143d2fe063046e0301e62a810bed338fa4d1ce0fd870c27dc1e09b0d84", size = 109744, upload-time = "2026-10-07T12:22:48.925Z" },
|
|
323
|
+
{ url = "https://files.pythonhosted.org/packages/e4/49/caf6b307766eb9567664a8707e9d6be5fcc0e8903f18781c6677a60d80c7/tomli-2.5.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:d3182ee2d887e507bd67319a0a61105d1dd33facc111329559a233b772c1a105", size = 162899, upload-time = "2026-10-07T12:22:50.088Z" },
|
|
324
|
+
{ url = "https://files.pythonhosted.org/packages/d3/c8/68cfce773a2733a49c74f99d627fb461bd990756860099eac25617889585/tomli-2.5.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:521345fd1f19d45b8df87657aaa38b6f2ca3800059fadf428e7ebf479a383646", size = 162080, upload-time = "2026-10-07T12:22:51.558Z" },
|
|
325
|
+
{ url = "https://files.pythonhosted.org/packages/7e/b2/e5bb8651fdad593f670501a7d718b1a7f73f064d44dea15e04c04dfef45d/tomli-2.5.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6e95c7614e705bfe2b04b27aa124adec59752d15813df37e2156747cab3a006b", size = 273380, upload-time = "2026-10-07T12:22:52.918Z" },
|
|
326
|
+
{ url = "https://files.pythonhosted.org/packages/8d/d2/9e2d7f8b1dfe0e2b34c245986ebd55c4c553ea4ce6c47c443b332673253f/tomli-2.5.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7ac2027d37c3afbdf4bdd377f2676f6f1d2122a5be1f1137b49dced590b37e75", size = 283228, upload-time = "2026-10-07T12:22:54.173Z" },
|
|
327
|
+
{ url = "https://files.pythonhosted.org/packages/ba/df/ec7b876b7b1a2718bd74a3743c076fff565b04029ba33e8f61fac262739f/tomli-2.5.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c414be4ed9d3cac80c42e348fa5a956117d1a48227f48026e31f59cb4a7671eb", size = 277189, upload-time = "2026-10-07T12:22:55.342Z" },
|
|
328
|
+
{ url = "https://files.pythonhosted.org/packages/7d/7b/e192d9eed0b9cb80da799f4d77052297fb9a2c3cc9b19f571f56ea88add6/tomli-2.5.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:9b03d7dc168353b4132965bde20feceabaa470e570c6f59660dfae59b1f9eeb3", size = 283632, upload-time = "2026-10-07T12:22:56.735Z" },
|
|
329
|
+
{ url = "https://files.pythonhosted.org/packages/84/50/ff94454e75461d75623e47401ed323d65c10aab8fe9033242c20cd2fdf32/tomli-2.5.0-cp314-cp314-win32.whl", hash = "sha256:6f041843c4d3a37245c0c056fd955b186bf8b1fb85690cbe40b81230891dc34b", size = 103535, upload-time = "2026-10-07T12:22:58.084Z" },
|
|
330
|
+
{ url = "https://files.pythonhosted.org/packages/54/0b/bdacf05f963bd6026ebf6eeb0beda847d1d60e03e440725c64a4e08a0afd/tomli-2.5.0-cp314-cp314-win_amd64.whl", hash = "sha256:f4b653094e18f9031102d3a1da5c729c8f222d85225b18037dac621695e46e1a", size = 114621, upload-time = "2026-10-07T12:22:59.2Z" },
|
|
331
|
+
{ url = "https://files.pythonhosted.org/packages/61/99/53f438fa6ae4f9d4ed0ddde3e7242b3bdc34b48c8f9948b72b9e9b127676/tomli-2.5.0-cp314-cp314-win_arm64.whl", hash = "sha256:3f89d10c1ff6a38d992c27fc8a4816af71a909e08a40ec66934240b1e74347c3", size = 111572, upload-time = "2026-10-07T12:23:00.479Z" },
|
|
332
|
+
{ url = "https://files.pythonhosted.org/packages/b9/20/1f88f19427d380a40e90a770e087489eaafe4aeee070ae88ed2bbec00acd/tomli-2.5.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:e9e15b4a6c7dd6b85b5fbab29488a73f1f70de516942308daa266bf0e0aeb0d4", size = 171814, upload-time = "2026-10-07T12:23:01.914Z" },
|
|
333
|
+
{ url = "https://files.pythonhosted.org/packages/d0/56/cbe5079c9f9a54b9b3e27fc82f08f3cb36edee75561679f53d2380c801d6/tomli-2.5.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:e12bbcd32897272fb05929110362ae9ff4c1b9bb26bd9e971e71dcd3275b4c3d", size = 171324, upload-time = "2026-10-07T12:23:03.18Z" },
|
|
334
|
+
{ url = "https://files.pythonhosted.org/packages/2b/30/1d53fd3b0f1cb3ba542e345ec32c26aefdddc4e829e4f3429af8a4f27782/tomli-2.5.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:20aa36de8f2cf87237143bc1fa1aae8d6612c09118f4da21c6a684db5dd1f6f9", size = 297441, upload-time = "2026-10-07T12:23:04.345Z" },
|
|
335
|
+
{ url = "https://files.pythonhosted.org/packages/66/d9/0800acb6a111686f764c1b91ef15cc42a20a66a46013bb42220f1d2c61c1/tomli-2.5.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:22185fad8a1e622f064e78008018a0dd3323550dcb479cb7a1d296888d74024f", size = 307476, upload-time = "2026-10-07T12:23:05.671Z" },
|
|
336
|
+
{ url = "https://files.pythonhosted.org/packages/e8/63/30a8f3cd51b5bec37f04744bad0b0dc6160df84aad4f27b0e9283d66f221/tomli-2.5.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:984012f71908165449a951de2050d52f276bfe3aa5d5f570f63ddad814370374", size = 296113, upload-time = "2026-10-07T12:23:07.202Z" },
|
|
337
|
+
{ url = "https://files.pythonhosted.org/packages/ab/18/0b9ffc597e69c5a1e20a7823cb60d54b39a9f54e91edcb8574f022186758/tomli-2.5.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f79203b3965b4000e91808aaa7c040206093f2b8bf86f455982f2274c9ccf442", size = 307725, upload-time = "2026-10-07T12:23:08.508Z" },
|
|
338
|
+
{ url = "https://files.pythonhosted.org/packages/ab/c7/18f8baae0b5607a60e8e19b4a7fedee43a8ff6458e3896dcbbadeeac9c22/tomli-2.5.0-cp314-cp314t-win32.whl", hash = "sha256:91294a9fb94a75542f6e46e4a2ae709bd8d9b51134098cae5cf3bea5478b6d03", size = 108546, upload-time = "2026-10-07T12:23:09.956Z" },
|
|
339
|
+
{ url = "https://files.pythonhosted.org/packages/72/34/4cca9739254130627bde87500b3f2b512154fe2f278efa7e2a5e10ad4bcb/tomli-2.5.0-cp314-cp314t-win_amd64.whl", hash = "sha256:f15e3e0b835a6d68b10c86bf80a3149780498d6911c93c3ffd1861d19f9200f1", size = 117814, upload-time = "2026-10-07T12:23:11.486Z" },
|
|
340
|
+
{ url = "https://files.pythonhosted.org/packages/7d/fb/afa530d47dd80a78fce43beac6bc6e00f84558eafcffbc6f37b21e80d056/tomli-2.5.0-cp314-cp314t-win_arm64.whl", hash = "sha256:6664b7ae7af7294256c53960a6103077f4914cec8ff98479c352f622c6f6b2f0", size = 115188, upload-time = "2026-10-07T12:23:12.728Z" },
|
|
341
|
+
{ url = "https://files.pythonhosted.org/packages/66/98/316fdc00f8c0939e6fe50461dd343c162d3ad51d1286eb25b7db54361d50/tomli-2.5.0-cp315-cp315-macosx_10_15_x86_64.whl", hash = "sha256:a525685c2f97da40762b8695eb7aa0af4c8344ca1905c73e4e29cb04d34607dc", size = 162775, upload-time = "2026-10-07T12:23:13.941Z" },
|
|
342
|
+
{ url = "https://files.pythonhosted.org/packages/c5/22/7b10fa5bb01c9539f53f69b619361b19350acc73657772ea7ac70ba309a8/tomli-2.5.0-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:9dbb18c1cfb2f6517942fc9314437f66aa06d94436ffb1f06102ef3572f35276", size = 161406, upload-time = "2026-10-07T12:23:15.215Z" },
|
|
343
|
+
{ url = "https://files.pythonhosted.org/packages/9c/e7/1a069d86dfd20f1f84f71c63faed9f83c1d890bc06c27d82dc7d888fb573/tomli-2.5.0-cp315-cp315-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:752e8b1aa6a4367ef8bf6a1a1e005540f7ed055ba36d7193796812ca5404eb52", size = 273855, upload-time = "2026-10-07T12:23:16.471Z" },
|
|
344
|
+
{ url = "https://files.pythonhosted.org/packages/ae/83/d1ef43d1687d092ab9c235455c76e6e709483b346b056f086095c7c263a5/tomli-2.5.0-cp315-cp315-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c47300f9bf791808f77d82747691c4bb09cb14bdf3060cca99b42cdc4361d5a7", size = 284910, upload-time = "2026-10-07T12:23:18.166Z" },
|
|
345
|
+
{ url = "https://files.pythonhosted.org/packages/cc/05/f4d9cf7de61822ece0c3873f30d291e324911c71a378b8bfe5ced13fd9f5/tomli-2.5.0-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:19b0dd8749f4ea2f112c5fcfb3c5248390c899d7e2e173f1d91abee1fa0ff391", size = 277723, upload-time = "2026-10-07T12:23:19.355Z" },
|
|
346
|
+
{ url = "https://files.pythonhosted.org/packages/42/28/78262493141fa543151cf005760c3cb01d09fc28a11f993c05109902cb8c/tomli-2.5.0-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:57b1c3b01fab802e2899bc3d168dca320e14165e2fd9fd584760fb4ca5826859", size = 285115, upload-time = "2026-10-07T12:23:20.698Z" },
|
|
347
|
+
{ url = "https://files.pythonhosted.org/packages/1a/b9/e1dab9a30bcb677b5cc5cee810609cfd64f24306a3055767dd3fda00b1e0/tomli-2.5.0-cp315-cp315-win32.whl", hash = "sha256:667e521b37a6c5ccaa044202c235b530f90177ffe2cd4a64ecc213c7dd535feb", size = 103475, upload-time = "2026-10-07T12:23:21.941Z" },
|
|
348
|
+
{ url = "https://files.pythonhosted.org/packages/4c/bd/31a3790c11d6ea95fcf5e6022ac0f8d0543c9b61120b730fc481bd43d3b4/tomli-2.5.0-cp315-cp315-win_amd64.whl", hash = "sha256:d747252933c8a65ef6bd8da0fbb7ce28a90eb6119d8cd00772cd528aa07b68d5", size = 114589, upload-time = "2026-10-07T12:23:23.098Z" },
|
|
349
|
+
{ url = "https://files.pythonhosted.org/packages/47/a2/4f6310fa699364f0e3af7ee3af88dddd9af066d33e716a0265bbe2b3ea84/tomli-2.5.0-cp315-cp315-win_arm64.whl", hash = "sha256:75dbcde8751b0a960aa3de173aa5e894d590755c6d7758b7e774c06f1dc3cbdd", size = 111493, upload-time = "2026-10-07T12:23:24.233Z" },
|
|
350
|
+
{ url = "https://files.pythonhosted.org/packages/68/14/00853f0b396d8971107ae1921bb5b322fdee1650d2f16bf06c20adb532e5/tomli-2.5.0-cp315-cp315t-macosx_10_15_x86_64.whl", hash = "sha256:2419c2a189551987b59d80e63ec355671283336f41c6b9b89462df679c7d0c57", size = 171380, upload-time = "2026-10-07T12:23:25.512Z" },
|
|
351
|
+
{ url = "https://files.pythonhosted.org/packages/89/ad/fa6949321dadee46b27363974fb197b94c911c3b0f7a5fd26d7dc18fc2a0/tomli-2.5.0-cp315-cp315t-macosx_11_0_arm64.whl", hash = "sha256:0dc598040da8d42cf20f0be588ed7004f46db12a0ac6c32e03a59dccedaaadcd", size = 170553, upload-time = "2026-10-07T12:23:26.855Z" },
|
|
352
|
+
{ url = "https://files.pythonhosted.org/packages/53/aa/3056c919eb3e084df3752b2cf5f865dcc04af0b27dba2f66d7b28af4633a/tomli-2.5.0-cp315-cp315t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:49096930c8d886c9bbdab62d2d0d17ce823ddeea522309a190b36245d5b49e01", size = 294428, upload-time = "2026-10-07T12:23:28.132Z" },
|
|
353
|
+
{ url = "https://files.pythonhosted.org/packages/96/b2/faeeb5d8769ea3832021d73e892c8391eae7b4b4f8b55a789127bd8b18a9/tomli-2.5.0-cp315-cp315t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8ade5023067f99fe72b88accd30d0ea05a158e9e32a11f124e731ea9695313f", size = 304909, upload-time = "2026-10-07T12:23:29.381Z" },
|
|
354
|
+
{ url = "https://files.pythonhosted.org/packages/f6/52/f094c09e73fb654b621716d019acb5d29bdfd1be01df80c281d552bda48d/tomli-2.5.0-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:b69564772b5c8f22ea5f498dff08cfa825045b4d4c4400529000bdf818aa3b2a", size = 293220, upload-time = "2026-10-07T12:23:30.608Z" },
|
|
355
|
+
{ url = "https://files.pythonhosted.org/packages/86/f5/0c30541078ca4b505ce3bd76ed931facbfec524dd018535d691d1af0a6d2/tomli-2.5.0-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:8ff3a2ca028c7eee0c777f9a092038d0a594a9fa04e215f929a22c329e2cb142", size = 305705, upload-time = "2026-10-07T12:23:32.181Z" },
|
|
356
|
+
{ url = "https://files.pythonhosted.org/packages/05/74/590e7d19d6a118fc5cc5704ff358e21d95b8573f6b9443b1519f29ca8825/tomli-2.5.0-cp315-cp315t-win32.whl", hash = "sha256:62fc1bc8eb03e3a9cadfca713d65614ed8e09d974a283295ffe3a831976b4dc5", size = 108432, upload-time = "2026-10-07T12:23:33.496Z" },
|
|
357
|
+
{ url = "https://files.pythonhosted.org/packages/1c/b8/63a75cfb27a17c38550e44025d3a6e7be64516fd8608a3b75703bf37d81b/tomli-2.5.0-cp315-cp315t-win_amd64.whl", hash = "sha256:f3fcbc57b1791fa6cbe5d8434179d51de12be1a4811469529f47f6e7487a2571", size = 117281, upload-time = "2026-10-07T12:23:34.648Z" },
|
|
358
|
+
{ url = "https://files.pythonhosted.org/packages/72/01/e8c1debb2173973372934c68fc8e46170ab60ef23ed4592dff4dec6e8993/tomli-2.5.0-cp315-cp315t-win_arm64.whl", hash = "sha256:d2ba24db8a9376921b5e87b4762b9adb0f3f1deaea68f2b8b0bb2c11efb9c3e7", size = 115069, upload-time = "2026-10-07T12:23:35.77Z" },
|
|
359
|
+
{ url = "https://files.pythonhosted.org/packages/60/3f/3e3f8fd0919249b0200c80fbc4f9a1e70be19f9883da71dfb7f8b9ab8aca/tomli-2.5.0-py3-none-any.whl", hash = "sha256:32a7b79ac57a2e83670ce329ccf675798bc5a2094783a63676866b70503f2e2b", size = 14765, upload-time = "2026-10-07T12:23:36.875Z" },
|
|
315
360
|
]
|
|
316
361
|
|
|
317
362
|
[[package]]
|
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
import tempfile
|
|
2
|
-
import pytest
|
|
3
|
-
from pathlib import Path
|
|
4
|
-
from polygit.config import find_config, load_config, write_config
|
|
5
|
-
from polygit.repos import parse_remote_url, del_nested, _add_to_config
|
|
6
|
-
from polygit.repo import walk
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
# ── parse_remote_url ──────────────────────────────────────────────────────────
|
|
10
|
-
|
|
11
|
-
def test_parse_github_ssh():
|
|
12
|
-
platform, path = parse_remote_url("git@github.com:gschaetz/mousehat.git")
|
|
13
|
-
assert platform == "github"
|
|
14
|
-
assert path == "gschaetz/mousehat"
|
|
15
|
-
|
|
16
|
-
def test_parse_gitlab_ssh_nested():
|
|
17
|
-
platform, path = parse_remote_url("git@gitlab.com:gary.schaetz/private/dev-setup.git")
|
|
18
|
-
assert platform == "gitlab"
|
|
19
|
-
assert path == "gary.schaetz/private/dev-setup"
|
|
20
|
-
|
|
21
|
-
def test_parse_https():
|
|
22
|
-
platform, path = parse_remote_url("https://github.com/openclaw/openclaw")
|
|
23
|
-
assert platform == "github"
|
|
24
|
-
assert path == "openclaw/openclaw"
|
|
25
|
-
|
|
26
|
-
def test_parse_none():
|
|
27
|
-
platform, path = parse_remote_url(None)
|
|
28
|
-
assert platform is None
|
|
29
|
-
assert path is None
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
# ── walk ──────────────────────────────────────────────────────────────────────
|
|
33
|
-
|
|
34
|
-
def test_walk_null():
|
|
35
|
-
results = list(walk(None, "ns/repo"))
|
|
36
|
-
assert results == [("ns/repo", "ns/repo")]
|
|
37
|
-
|
|
38
|
-
def test_walk_remote_override():
|
|
39
|
-
results = list(walk({"remote": "other/repo"}, "ns/local"))
|
|
40
|
-
assert results == [("ns/local", "other/repo")]
|
|
41
|
-
|
|
42
|
-
def test_walk_nested():
|
|
43
|
-
node = {"a": None, "b": {"c": None}}
|
|
44
|
-
results = list(walk(node, "ns"))
|
|
45
|
-
assert ("ns/a", "ns/a") in results
|
|
46
|
-
assert ("ns/b/c", "ns/b/c") in results
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
# ── del_nested ────────────────────────────────────────────────────────────────
|
|
50
|
-
|
|
51
|
-
def test_del_nested_simple():
|
|
52
|
-
d = {"a": {"b": None}}
|
|
53
|
-
del_nested(d, ["a", "b"])
|
|
54
|
-
assert d == {}
|
|
55
|
-
|
|
56
|
-
def test_del_nested_preserves_siblings():
|
|
57
|
-
d = {"a": {"b": None, "c": None}}
|
|
58
|
-
del_nested(d, ["a", "b"])
|
|
59
|
-
assert d == {"a": {"c": None}}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
# ── _add_to_config ──────────────────────────────────────────────────────────
|
|
63
|
-
|
|
64
|
-
def test_add_to_config_plain():
|
|
65
|
-
config = {}
|
|
66
|
-
_add_to_config(config, "github", "gschaetz/mousehat", "git@github.com:gschaetz/mousehat.git")
|
|
67
|
-
assert config == {"github": {"gschaetz": {"mousehat": None}}}
|
|
68
|
-
|
|
69
|
-
def test_add_to_config_cross_namespace_override():
|
|
70
|
-
# Local dir lives under a namespace unrelated to the remote org — must
|
|
71
|
-
# nest under the local namespace, not silently fall back to the remote's.
|
|
72
|
-
config = {}
|
|
73
|
-
_add_to_config(config, "github", "community/modelrelay", "git@github.com:ellipticmarketing/modelrelay.git")
|
|
74
|
-
assert config == {"github": {"community": {"modelrelay": {"remote": "ellipticmarketing/modelrelay"}}}}
|
|
75
|
-
|
|
76
|
-
def test_add_to_config_no_remote():
|
|
77
|
-
config = {}
|
|
78
|
-
_add_to_config(config, "github", "gschaetz/scratch", None)
|
|
79
|
-
assert config == {"github": {"gschaetz": {"scratch": None}}}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
# ── find_config / write_config / load_config ──────────────────────────────────
|
|
83
|
-
|
|
84
|
-
def test_find_config_in_cwd():
|
|
85
|
-
with tempfile.TemporaryDirectory() as tmp:
|
|
86
|
-
config_path = Path(tmp) / ".pgit"
|
|
87
|
-
config_path.write_text("github:\n org:\n repo:\n")
|
|
88
|
-
found = find_config(start=tmp)
|
|
89
|
-
assert found == config_path
|
|
90
|
-
|
|
91
|
-
def test_find_config_walks_up():
|
|
92
|
-
with tempfile.TemporaryDirectory() as tmp:
|
|
93
|
-
config_path = Path(tmp) / ".pgit"
|
|
94
|
-
config_path.write_text("github:\n org:\n repo:\n")
|
|
95
|
-
subdir = Path(tmp) / "sub" / "dir"
|
|
96
|
-
subdir.mkdir(parents=True)
|
|
97
|
-
found = find_config(start=subdir)
|
|
98
|
-
assert found == config_path
|
|
99
|
-
|
|
100
|
-
def test_find_config_not_found():
|
|
101
|
-
with tempfile.TemporaryDirectory() as tmp:
|
|
102
|
-
found = find_config(start=tmp)
|
|
103
|
-
assert found is None
|
|
104
|
-
|
|
105
|
-
def test_write_and_load_roundtrip():
|
|
106
|
-
with tempfile.TemporaryDirectory() as tmp:
|
|
107
|
-
path = Path(tmp) / ".pgit"
|
|
108
|
-
data = {
|
|
109
|
-
"github": {
|
|
110
|
-
"gschaetz": {"mousehat": None, "dotfiles": None},
|
|
111
|
-
"community": {"openclaw": {"remote": "openclaw/openclaw"}},
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
write_config(data, path)
|
|
115
|
-
loaded = load_config(path)
|
|
116
|
-
assert loaded["github"]["gschaetz"]["mousehat"] is None
|
|
117
|
-
assert loaded["github"]["community"]["openclaw"] == {"remote": "openclaw/openclaw"}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|