arga-cli 0.1.2__tar.gz → 0.1.3__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.
- {arga_cli-0.1.2 → arga_cli-0.1.3}/PKG-INFO +2 -1
- {arga_cli-0.1.2 → arga_cli-0.1.3}/README.md +1 -0
- {arga_cli-0.1.2 → arga_cli-0.1.3}/arga_cli/main.py +41 -0
- {arga_cli-0.1.2 → arga_cli-0.1.3}/arga_cli.egg-info/PKG-INFO +2 -1
- {arga_cli-0.1.2 → arga_cli-0.1.3}/pyproject.toml +1 -1
- {arga_cli-0.1.2 → arga_cli-0.1.3}/tests/test_cli_runs.py +111 -0
- {arga_cli-0.1.2 → arga_cli-0.1.3}/arga_cli/__init__.py +0 -0
- {arga_cli-0.1.2 → arga_cli-0.1.3}/arga_cli/mcp.py +0 -0
- {arga_cli-0.1.2 → arga_cli-0.1.3}/arga_cli.egg-info/SOURCES.txt +0 -0
- {arga_cli-0.1.2 → arga_cli-0.1.3}/arga_cli.egg-info/dependency_links.txt +0 -0
- {arga_cli-0.1.2 → arga_cli-0.1.3}/arga_cli.egg-info/entry_points.txt +0 -0
- {arga_cli-0.1.2 → arga_cli-0.1.3}/arga_cli.egg-info/requires.txt +0 -0
- {arga_cli-0.1.2 → arga_cli-0.1.3}/arga_cli.egg-info/top_level.txt +0 -0
- {arga_cli-0.1.2 → arga_cli-0.1.3}/setup.cfg +0 -0
- {arga_cli-0.1.2 → arga_cli-0.1.3}/tests/test_cli_git.py +0 -0
- {arga_cli-0.1.2 → arga_cli-0.1.3}/tests/test_cli_mcp.py +0 -0
- {arga_cli-0.1.2 → arga_cli-0.1.3}/tests/test_cli_scan.py +0 -0
- {arga_cli-0.1.2 → arga_cli-0.1.3}/tests/test_cli_test_url.py +0 -0
- {arga_cli-0.1.2 → arga_cli-0.1.3}/tests/test_cli_validate_config.py +0 -0
- {arga_cli-0.1.2 → arga_cli-0.1.3}/tests/test_cli_validate_pr.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: arga-cli
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.3
|
|
4
4
|
Summary: Command-line interface for Arga authentication, MCP installation, and browser validation
|
|
5
5
|
Author: Arga Labs
|
|
6
6
|
Project-URL: Homepage, https://github.com/ArgaLabs/arga-cli
|
|
@@ -198,6 +198,7 @@ arga runs cancel <run_id>
|
|
|
198
198
|
- `arga runs logs <run_id>` prints worker logs plus recent runtime logs for a run you own.
|
|
199
199
|
- When you omit `<run_id>`, `arga runs logs` falls back to `./.arga-session.json` when present, which makes wizard-created twin sessions easy to inspect from the same directory.
|
|
200
200
|
- Add `--json` to `arga runs logs` for a machine-readable response.
|
|
201
|
+
- Add `--errors-only` to keep only failed worker logs plus warning/error runtime entries.
|
|
201
202
|
- `arga runs cancel <run_id>` cancels the run through the validation API.
|
|
202
203
|
|
|
203
204
|
### Git Wrappers
|
|
@@ -178,6 +178,7 @@ arga runs cancel <run_id>
|
|
|
178
178
|
- `arga runs logs <run_id>` prints worker logs plus recent runtime logs for a run you own.
|
|
179
179
|
- When you omit `<run_id>`, `arga runs logs` falls back to `./.arga-session.json` when present, which makes wizard-created twin sessions easy to inspect from the same directory.
|
|
180
180
|
- Add `--json` to `arga runs logs` for a machine-readable response.
|
|
181
|
+
- Add `--errors-only` to keep only failed worker logs plus warning/error runtime entries.
|
|
181
182
|
- `arga runs cancel <run_id>` cancels the run through the validation API.
|
|
182
183
|
|
|
183
184
|
### Git Wrappers
|
|
@@ -905,6 +905,40 @@ def _print_runtime_logs(runtime_logs: list[dict[str, Any]]) -> None:
|
|
|
905
905
|
print()
|
|
906
906
|
|
|
907
907
|
|
|
908
|
+
def _is_error_runtime_log(runtime_log: dict[str, Any]) -> bool:
|
|
909
|
+
severity = str(runtime_log.get("severity") or "").strip().upper()
|
|
910
|
+
return severity in {"WARNING", "ERROR", "CRITICAL", "ALERT", "EMERGENCY"}
|
|
911
|
+
|
|
912
|
+
|
|
913
|
+
def _is_error_worker_log(worker_log: dict[str, Any]) -> bool:
|
|
914
|
+
status = str(worker_log.get("status") or "").strip().lower()
|
|
915
|
+
error = str(worker_log.get("error") or "").strip()
|
|
916
|
+
return status in {"failed", "error", "cancelled"} or bool(error)
|
|
917
|
+
|
|
918
|
+
|
|
919
|
+
def _filter_run_logs_payload(payload: dict[str, Any], *, errors_only: bool) -> dict[str, Any]:
|
|
920
|
+
if not errors_only:
|
|
921
|
+
return payload
|
|
922
|
+
|
|
923
|
+
filtered_payload = dict(payload)
|
|
924
|
+
worker_logs = payload.get("worker_logs")
|
|
925
|
+
runtime_logs = payload.get("runtime_logs")
|
|
926
|
+
warnings = payload.get("warnings")
|
|
927
|
+
|
|
928
|
+
filtered_payload["worker_logs"] = (
|
|
929
|
+
[item for item in worker_logs if isinstance(item, dict) and _is_error_worker_log(item)]
|
|
930
|
+
if isinstance(worker_logs, list)
|
|
931
|
+
else []
|
|
932
|
+
)
|
|
933
|
+
filtered_payload["runtime_logs"] = (
|
|
934
|
+
[item for item in runtime_logs if isinstance(item, dict) and _is_error_runtime_log(item)]
|
|
935
|
+
if isinstance(runtime_logs, list)
|
|
936
|
+
else []
|
|
937
|
+
)
|
|
938
|
+
filtered_payload["warnings"] = warnings if isinstance(warnings, list) else []
|
|
939
|
+
return filtered_payload
|
|
940
|
+
|
|
941
|
+
|
|
908
942
|
def _print_run_logs(payload: dict[str, Any], fallback_run_id: str) -> None:
|
|
909
943
|
run = payload.get("run")
|
|
910
944
|
run_data = run if isinstance(run, dict) else {}
|
|
@@ -996,6 +1030,8 @@ def run_runs_logs(args: argparse.Namespace) -> int:
|
|
|
996
1030
|
finally:
|
|
997
1031
|
client.close()
|
|
998
1032
|
|
|
1033
|
+
payload = _filter_run_logs_payload(payload, errors_only=args.errors_only)
|
|
1034
|
+
|
|
999
1035
|
if args.json:
|
|
1000
1036
|
print(json.dumps(payload, indent=2))
|
|
1001
1037
|
return 0
|
|
@@ -1291,6 +1327,11 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
1291
1327
|
help=f"Validation run ID. Defaults to {WIZARD_SESSION_FILE} in the current directory when available.",
|
|
1292
1328
|
)
|
|
1293
1329
|
runs_logs_parser.add_argument("--json", action="store_true", help="Print the raw JSON response")
|
|
1330
|
+
runs_logs_parser.add_argument(
|
|
1331
|
+
"--errors-only",
|
|
1332
|
+
action="store_true",
|
|
1333
|
+
help="Show only failed worker logs and warning/error runtime logs",
|
|
1334
|
+
)
|
|
1294
1335
|
runs_logs_parser.set_defaults(func=run_runs_logs)
|
|
1295
1336
|
|
|
1296
1337
|
runs_cancel_parser = runs_subparsers.add_parser("cancel", help="Cancel a validation run")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: arga-cli
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.3
|
|
4
4
|
Summary: Command-line interface for Arga authentication, MCP installation, and browser validation
|
|
5
5
|
Author: Arga Labs
|
|
6
6
|
Project-URL: Homepage, https://github.com/ArgaLabs/arga-cli
|
|
@@ -198,6 +198,7 @@ arga runs cancel <run_id>
|
|
|
198
198
|
- `arga runs logs <run_id>` prints worker logs plus recent runtime logs for a run you own.
|
|
199
199
|
- When you omit `<run_id>`, `arga runs logs` falls back to `./.arga-session.json` when present, which makes wizard-created twin sessions easy to inspect from the same directory.
|
|
200
200
|
- Add `--json` to `arga runs logs` for a machine-readable response.
|
|
201
|
+
- Add `--errors-only` to keep only failed worker logs plus warning/error runtime entries.
|
|
201
202
|
- `arga runs cancel <run_id>` cancels the run through the validation API.
|
|
202
203
|
|
|
203
204
|
### Git Wrappers
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "arga-cli"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.3"
|
|
8
8
|
description = "Command-line interface for Arga authentication, MCP installation, and browser validation"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.12"
|
|
@@ -293,6 +293,117 @@ def test_runs_logs_prints_json(monkeypatch, capsys) -> None:
|
|
|
293
293
|
assert json.loads(output) == payload
|
|
294
294
|
|
|
295
295
|
|
|
296
|
+
def test_runs_logs_errors_only_filters_plain_output(monkeypatch, capsys) -> None:
|
|
297
|
+
monkeypatch.setattr(main, "load_api_key", lambda: "arga_api_key")
|
|
298
|
+
monkeypatch.setattr(main.ApiClient, "close", lambda self: None)
|
|
299
|
+
|
|
300
|
+
def fake_get_logs(self, run_id: str):
|
|
301
|
+
assert run_id == "run_123"
|
|
302
|
+
return {
|
|
303
|
+
"run": {
|
|
304
|
+
"id": run_id,
|
|
305
|
+
"status": "ready",
|
|
306
|
+
"run_type": "twin_quickstart",
|
|
307
|
+
"mode": "staging",
|
|
308
|
+
"repo_full_name": None,
|
|
309
|
+
"commit_sha": None,
|
|
310
|
+
"created_at": "2026-03-25T12:30:00Z",
|
|
311
|
+
"environment_url": "https://preview.example.com",
|
|
312
|
+
"event_log_json": [],
|
|
313
|
+
},
|
|
314
|
+
"worker_logs": [
|
|
315
|
+
{
|
|
316
|
+
"job_id": "job_ok",
|
|
317
|
+
"job_type": "build",
|
|
318
|
+
"target_role": "builder",
|
|
319
|
+
"status": "succeeded",
|
|
320
|
+
"content": "all good",
|
|
321
|
+
"truncated": False,
|
|
322
|
+
"error": None,
|
|
323
|
+
},
|
|
324
|
+
{
|
|
325
|
+
"job_id": "job_bad",
|
|
326
|
+
"job_type": "deploy",
|
|
327
|
+
"target_role": "warm-vm",
|
|
328
|
+
"status": "failed",
|
|
329
|
+
"content": "deploy failed output",
|
|
330
|
+
"truncated": False,
|
|
331
|
+
"error": None,
|
|
332
|
+
},
|
|
333
|
+
],
|
|
334
|
+
"runtime_logs": [
|
|
335
|
+
{
|
|
336
|
+
"timestamp": "2026-03-25T12:31:00Z",
|
|
337
|
+
"service_name": "arga-api",
|
|
338
|
+
"severity": "INFO",
|
|
339
|
+
"event": "environment_ready",
|
|
340
|
+
"code": None,
|
|
341
|
+
"request_id": "req_ok",
|
|
342
|
+
"job_id": None,
|
|
343
|
+
"surface_name": None,
|
|
344
|
+
"message": "Environment ready.",
|
|
345
|
+
},
|
|
346
|
+
{
|
|
347
|
+
"timestamp": "2026-03-25T12:32:00Z",
|
|
348
|
+
"service_name": "preview-proxy",
|
|
349
|
+
"severity": "WARNING",
|
|
350
|
+
"event": "preview.request.finish",
|
|
351
|
+
"code": None,
|
|
352
|
+
"request_id": "req_warn",
|
|
353
|
+
"job_id": None,
|
|
354
|
+
"surface_name": "slack",
|
|
355
|
+
"message": "Preview request completed.",
|
|
356
|
+
},
|
|
357
|
+
],
|
|
358
|
+
"warnings": ["Cloud Logging query was partially truncated."],
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
monkeypatch.setattr(main.ApiClient, "get_run_logs", fake_get_logs)
|
|
362
|
+
|
|
363
|
+
args = main.build_parser().parse_args(["runs", "logs", "run_123", "--errors-only"])
|
|
364
|
+
exit_code = args.func(args)
|
|
365
|
+
output = capsys.readouterr().out
|
|
366
|
+
|
|
367
|
+
assert exit_code == 0
|
|
368
|
+
assert "job_bad" in output
|
|
369
|
+
assert "deploy failed output" in output
|
|
370
|
+
assert "job_ok" not in output
|
|
371
|
+
assert "all good" not in output
|
|
372
|
+
assert "Preview request completed." in output
|
|
373
|
+
assert "Environment ready." not in output
|
|
374
|
+
assert "Warnings:" in output
|
|
375
|
+
|
|
376
|
+
|
|
377
|
+
def test_runs_logs_errors_only_filters_json(monkeypatch, capsys) -> None:
|
|
378
|
+
monkeypatch.setattr(main, "load_api_key", lambda: "arga_api_key")
|
|
379
|
+
monkeypatch.setattr(main.ApiClient, "close", lambda self: None)
|
|
380
|
+
|
|
381
|
+
payload = {
|
|
382
|
+
"run": {"id": "run_123", "status": "ready"},
|
|
383
|
+
"worker_logs": [
|
|
384
|
+
{"job_id": "job_ok", "status": "succeeded", "error": None},
|
|
385
|
+
{"job_id": "job_bad", "status": "failed", "error": None},
|
|
386
|
+
],
|
|
387
|
+
"runtime_logs": [
|
|
388
|
+
{"severity": "INFO", "message": "Environment ready."},
|
|
389
|
+
{"severity": "WARNING", "message": "Preview request completed."},
|
|
390
|
+
],
|
|
391
|
+
"warnings": ["Cloud Logging query was partially truncated."],
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
monkeypatch.setattr(main.ApiClient, "get_run_logs", lambda self, run_id: payload)
|
|
395
|
+
|
|
396
|
+
args = main.build_parser().parse_args(["runs", "logs", "run_123", "--json", "--errors-only"])
|
|
397
|
+
exit_code = args.func(args)
|
|
398
|
+
output = capsys.readouterr().out
|
|
399
|
+
|
|
400
|
+
assert exit_code == 0
|
|
401
|
+
parsed = json.loads(output)
|
|
402
|
+
assert parsed["worker_logs"] == [{"job_id": "job_bad", "status": "failed", "error": None}]
|
|
403
|
+
assert parsed["runtime_logs"] == [{"severity": "WARNING", "message": "Preview request completed."}]
|
|
404
|
+
assert parsed["warnings"] == ["Cloud Logging query was partially truncated."]
|
|
405
|
+
|
|
406
|
+
|
|
296
407
|
def test_runs_logs_uses_wizard_session_file_when_run_id_missing(monkeypatch, capsys, tmp_path) -> None:
|
|
297
408
|
monkeypatch.chdir(tmp_path)
|
|
298
409
|
(tmp_path / main.WIZARD_SESSION_FILE).write_text(json.dumps({"run_id": "run_from_session"}) + "\n")
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|