polygit 0.4.0__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: polygit
3
- Version: 0.4.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>
@@ -96,6 +96,20 @@ pgit push --dry-run # list dirty repos that would be committed and pushed
96
96
 
97
97
  `pull --dry-run` compares against the last fetched state of each upstream, so run `pgit sync` first for current numbers.
98
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
+
99
113
  ## repos — drift detection
100
114
 
101
115
  `pgit repos` compares what's actually on disk against your `.pgit` config and reports:
@@ -63,6 +63,20 @@ pgit push --dry-run # list dirty repos that would be committed and pushed
63
63
 
64
64
  `pull --dry-run` compares against the last fetched state of each upstream, so run `pgit sync` first for current numbers.
65
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
+
66
80
  ## repos — drift detection
67
81
 
68
82
  `pgit repos` compares what's actually on disk against your `.pgit` config and reports:
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "polygit"
7
- version = "0.4.0"
7
+ version = "0.5.0"
8
8
  description = "Manage multiple git repos from a single .pgit config file."
9
9
  readme = "README.md"
10
10
  license = { file = "LICENSE.txt" }
@@ -13,7 +13,9 @@ 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")
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")
17
19
  pull_p = sub.add_parser("pull", help="Pull all repos, auto-stashing local changes")
18
20
  pull_p.add_argument("--dry-run", action="store_true",
19
21
  help="Show ahead/behind vs. last-fetched upstream; changes nothing")
@@ -49,7 +51,7 @@ def main():
49
51
 
50
52
  commands = {
51
53
  "sync": lambda: cmd_sync(config, base),
52
- "status": lambda: cmd_status(config, base),
54
+ "status": lambda: cmd_status(config, base, json_output=args.json),
53
55
  "pull": lambda: cmd_pull(config, base, dry_run=args.dry_run),
54
56
  "push": lambda: cmd_push(config, base, mode=args.push_mode, dry_run=args.dry_run),
55
57
  "repos": lambda: cmd_repos(config, base, config_path),
@@ -1,3 +1,4 @@
1
+ import json
1
2
  import shutil
2
3
  import subprocess
3
4
  import sys
@@ -194,7 +195,7 @@ def cmd_sync(config, base):
194
195
  f.result()
195
196
 
196
197
 
197
- def cmd_status(config, base):
198
+ def cmd_status(config, base, json_output=False):
198
199
  results = []
199
200
 
200
201
  def _check(platform, local_path, d):
@@ -210,6 +211,15 @@ def cmd_status(config, base):
210
211
  for f in as_completed(futures):
211
212
  results.append(f.result())
212
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
+
213
223
  found_dirty = False
214
224
  for platform, local_path, output in sorted(results):
215
225
  if output:
@@ -1,10 +1,11 @@
1
+ import json
1
2
  import subprocess
2
3
  import tempfile
3
4
  import pytest
4
5
  from pathlib import Path
5
6
  from polygit.config import find_config, load_config, write_config
6
7
  from polygit.repos import parse_remote_url, del_nested, _add_to_config
7
- from polygit.repo import walk, _pull_one, cmd_push
8
+ from polygit.repo import walk, _pull_one, cmd_push, cmd_status
8
9
 
9
10
 
10
11
  # ── parse_remote_url ──────────────────────────────────────────────────────────
@@ -195,3 +196,56 @@ def test_push_dry_run_lists_dirty_without_committing(capsys, tmp_path):
195
196
  log = subprocess.run(["git", "-C", str(d), "log", "--oneline"],
196
197
  capture_output=True, text=True).stdout
197
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
@@ -117,7 +117,7 @@ wheels = [
117
117
 
118
118
  [[package]]
119
119
  name = "polygit"
120
- version = "0.4.0"
120
+ version = "0.5.0"
121
121
  source = { editable = "." }
122
122
  dependencies = [
123
123
  { name = "pyyaml" },
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes