ssot-cli 0.1.10.dev1__tar.gz → 0.1.11__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.
- {ssot_cli-0.1.10.dev1 → ssot_cli-0.1.11}/PKG-INFO +4 -4
- {ssot_cli-0.1.10.dev1 → ssot_cli-0.1.11}/pyproject.toml +4 -4
- {ssot_cli-0.1.10.dev1 → ssot_cli-0.1.11}/src/ssot_cli/boundary_cmd.py +9 -2
- {ssot_cli-0.1.10.dev1 → ssot_cli-0.1.11}/src/ssot_cli/claim_cmd.py +9 -2
- {ssot_cli-0.1.10.dev1 → ssot_cli-0.1.11}/src/ssot_cli/common.py +15 -0
- {ssot_cli-0.1.10.dev1 → ssot_cli-0.1.11}/src/ssot_cli/evidence_cmd.py +9 -1
- {ssot_cli-0.1.10.dev1 → ssot_cli-0.1.11}/src/ssot_cli/feature_cmd.py +9 -1
- {ssot_cli-0.1.10.dev1 → ssot_cli-0.1.11}/src/ssot_cli/issue_cmd.py +9 -1
- {ssot_cli-0.1.10.dev1 → ssot_cli-0.1.11}/src/ssot_cli/main.py +45 -2
- {ssot_cli-0.1.10.dev1 → ssot_cli-0.1.11}/src/ssot_cli/profile_cmd.py +9 -1
- {ssot_cli-0.1.10.dev1 → ssot_cli-0.1.11}/src/ssot_cli/release_cmd.py +9 -1
- {ssot_cli-0.1.10.dev1 → ssot_cli-0.1.11}/src/ssot_cli/risk_cmd.py +9 -1
- {ssot_cli-0.1.10.dev1 → ssot_cli-0.1.11}/src/ssot_cli/test_cmd.py +9 -1
- {ssot_cli-0.1.10.dev1 → ssot_cli-0.1.11}/src/ssot_cli.egg-info/PKG-INFO +4 -4
- ssot_cli-0.1.11/src/ssot_cli.egg-info/requires.txt +6 -0
- ssot_cli-0.1.10.dev1/src/ssot_cli.egg-info/requires.txt +0 -6
- {ssot_cli-0.1.10.dev1 → ssot_cli-0.1.11}/README.md +0 -0
- {ssot_cli-0.1.10.dev1 → ssot_cli-0.1.11}/setup.cfg +0 -0
- {ssot_cli-0.1.10.dev1 → ssot_cli-0.1.11}/src/ssot_cli/__init__.py +0 -0
- {ssot_cli-0.1.10.dev1 → ssot_cli-0.1.11}/src/ssot_cli/adr_cmd.py +0 -0
- {ssot_cli-0.1.10.dev1 → ssot_cli-0.1.11}/src/ssot_cli/conformance_cmd.py +0 -0
- {ssot_cli-0.1.10.dev1 → ssot_cli-0.1.11}/src/ssot_cli/graph_cmd.py +0 -0
- {ssot_cli-0.1.10.dev1 → ssot_cli-0.1.11}/src/ssot_cli/init_cmd.py +0 -0
- {ssot_cli-0.1.10.dev1 → ssot_cli-0.1.11}/src/ssot_cli/registry_cmd.py +0 -0
- {ssot_cli-0.1.10.dev1 → ssot_cli-0.1.11}/src/ssot_cli/spec_cmd.py +0 -0
- {ssot_cli-0.1.10.dev1 → ssot_cli-0.1.11}/src/ssot_cli/upgrade_cmd.py +0 -0
- {ssot_cli-0.1.10.dev1 → ssot_cli-0.1.11}/src/ssot_cli/validate_cmd.py +0 -0
- {ssot_cli-0.1.10.dev1 → ssot_cli-0.1.11}/src/ssot_cli.egg-info/SOURCES.txt +0 -0
- {ssot_cli-0.1.10.dev1 → ssot_cli-0.1.11}/src/ssot_cli.egg-info/dependency_links.txt +0 -0
- {ssot_cli-0.1.10.dev1 → ssot_cli-0.1.11}/src/ssot_cli.egg-info/entry_points.txt +0 -0
- {ssot_cli-0.1.10.dev1 → ssot_cli-0.1.11}/src/ssot_cli.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ssot-cli
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.11
|
|
4
4
|
Summary: Primary CLI distribution for ssot-registry.
|
|
5
5
|
Author-email: Jacob Stewart <jacob@swarmauri.com>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -24,9 +24,9 @@ Classifier: Topic :: Software Development :: Quality Assurance
|
|
|
24
24
|
Classifier: Topic :: Utilities
|
|
25
25
|
Requires-Python: <3.14,>=3.10
|
|
26
26
|
Description-Content-Type: text/markdown
|
|
27
|
-
Requires-Dist: ssot-contracts<0.3.0,>=0.2.
|
|
28
|
-
Requires-Dist: ssot-core<0.3.0,>=0.2.
|
|
29
|
-
Requires-Dist: ssot-conformance<0.3.0,>=0.2.
|
|
27
|
+
Requires-Dist: ssot-contracts<0.3.0,>=0.2.17
|
|
28
|
+
Requires-Dist: ssot-core<0.3.0,>=0.2.17
|
|
29
|
+
Requires-Dist: ssot-conformance<0.3.0,>=0.2.17
|
|
30
30
|
Requires-Dist: tomli>=2.0.1; python_version < "3.11"
|
|
31
31
|
|
|
32
32
|
<div align="center">
|
|
@@ -4,16 +4,16 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "ssot-cli"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.11"
|
|
8
8
|
description = "Primary CLI distribution for ssot-registry."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10,<3.14"
|
|
11
11
|
license = "Apache-2.0"
|
|
12
12
|
authors = [{ name = "Jacob Stewart", email = "jacob@swarmauri.com" }]
|
|
13
13
|
dependencies = [
|
|
14
|
-
"ssot-contracts>=0.2.
|
|
15
|
-
"ssot-core>=0.2.
|
|
16
|
-
"ssot-conformance>=0.2.
|
|
14
|
+
"ssot-contracts>=0.2.17,<0.3.0",
|
|
15
|
+
"ssot-core>=0.2.17,<0.3.0",
|
|
16
|
+
"ssot-conformance>=0.2.17,<0.3.0",
|
|
17
17
|
"tomli>=2.0.1; python_version < '3.11'",
|
|
18
18
|
]
|
|
19
19
|
keywords = ["ssot", "cli", "registry", "governance", "release-management", "validation", "developer-tools"]
|
|
@@ -15,7 +15,7 @@ from ssot_registry.api import (
|
|
|
15
15
|
run_boundary_tests,
|
|
16
16
|
update_entity,
|
|
17
17
|
)
|
|
18
|
-
from ssot_cli.common import add_ids_argument, add_optional_bool_argument, add_path_argument, compact_dict
|
|
18
|
+
from ssot_cli.common import add_ids_argument, add_optional_bool_argument, add_path_argument, compact_dict, load_text_argument
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
def register_boundary(subparsers: argparse._SubParsersAction) -> None:
|
|
@@ -30,6 +30,8 @@ def register_boundary(subparsers: argparse._SubParsersAction) -> None:
|
|
|
30
30
|
add_path_argument(create)
|
|
31
31
|
create.add_argument("--id", required=True, help="Normalized boundary id to create.")
|
|
32
32
|
create.add_argument("--title", required=True, help="Human-readable boundary title.")
|
|
33
|
+
create.add_argument("--body", default=None, help="Optional longer-form narrative for the boundary.")
|
|
34
|
+
create.add_argument("--body-file", default=None, help="Path to a UTF-8 text file containing the boundary body.")
|
|
33
35
|
create.add_argument("--status", choices=["draft", "active", "frozen", "retired"], default="draft", help="Current lifecycle state of the boundary.")
|
|
34
36
|
add_optional_bool_argument(create, "--frozen", default=False, help_text="Record whether the boundary contents are locked against further scope edits.")
|
|
35
37
|
create.add_argument("--feature-ids", nargs="*", default=[], help="Direct feature ids included in the scoped delivery unit.")
|
|
@@ -50,6 +52,8 @@ def register_boundary(subparsers: argparse._SubParsersAction) -> None:
|
|
|
50
52
|
add_path_argument(update)
|
|
51
53
|
update.add_argument("--id", required=True, help="Boundary id to update.")
|
|
52
54
|
update.add_argument("--title", default=None, help="Replacement boundary title.")
|
|
55
|
+
update.add_argument("--body", default=None, help="Replacement longer-form boundary narrative.")
|
|
56
|
+
update.add_argument("--body-file", default=None, help="Path to a UTF-8 text file containing the replacement boundary body.")
|
|
53
57
|
update.add_argument("--status", choices=["draft", "active", "frozen", "retired"], default=None, help="Updated lifecycle state.")
|
|
54
58
|
add_optional_bool_argument(update, "--frozen", default=None, help_text="Change whether the boundary is locked against scope edits.")
|
|
55
59
|
update.set_defaults(func=run_update)
|
|
@@ -101,9 +105,11 @@ def register_boundary(subparsers: argparse._SubParsersAction) -> None:
|
|
|
101
105
|
|
|
102
106
|
|
|
103
107
|
def run_create(args: argparse.Namespace) -> dict[str, object]:
|
|
108
|
+
body = load_text_argument(inline_value=args.body, file_value=args.body_file, label="boundary")
|
|
104
109
|
row = {
|
|
105
110
|
"id": args.id,
|
|
106
111
|
"title": args.title,
|
|
112
|
+
"body": body,
|
|
107
113
|
"status": args.status,
|
|
108
114
|
"frozen": args.frozen,
|
|
109
115
|
"feature_ids": args.feature_ids,
|
|
@@ -121,7 +127,8 @@ def run_list(args: argparse.Namespace) -> dict[str, object]:
|
|
|
121
127
|
|
|
122
128
|
|
|
123
129
|
def run_update(args: argparse.Namespace) -> dict[str, object]:
|
|
124
|
-
|
|
130
|
+
body = load_text_argument(inline_value=args.body, file_value=args.body_file, label="boundary")
|
|
131
|
+
changes = compact_dict({"title": args.title, "body": body, "status": args.status, "frozen": args.frozen})
|
|
125
132
|
if not changes:
|
|
126
133
|
raise ValueError("At least one update field is required")
|
|
127
134
|
return update_entity(args.path, "boundaries", args.id, changes)
|
|
@@ -14,7 +14,7 @@ from ssot_registry.api import (
|
|
|
14
14
|
unlink_entities,
|
|
15
15
|
update_entity,
|
|
16
16
|
)
|
|
17
|
-
from ssot_cli.common import add_ids_argument, add_path_argument, collect_list_fields, compact_dict
|
|
17
|
+
from ssot_cli.common import add_ids_argument, add_path_argument, collect_list_fields, compact_dict, load_text_argument
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
_LINK_MAPPING = {
|
|
@@ -40,6 +40,8 @@ def register_claim(subparsers: argparse._SubParsersAction) -> None:
|
|
|
40
40
|
create.add_argument("--tier", choices=["T0", "T1", "T2", "T3", "T4"], default="T0", help="Assurance tier required for the claim.")
|
|
41
41
|
create.add_argument("--kind", required=True, help="Operator-defined claim category.")
|
|
42
42
|
create.add_argument("--description", default="", help="What the claim asserts and why it matters.")
|
|
43
|
+
create.add_argument("--body", default=None, help="Optional longer-form narrative for the claim.")
|
|
44
|
+
create.add_argument("--body-file", default=None, help="Path to a UTF-8 text file containing the claim body.")
|
|
43
45
|
create.add_argument("--feature-ids", nargs="*", default=[], help="Feature ids the claim is about.")
|
|
44
46
|
create.add_argument("--test-ids", nargs="*", default=[], help="Test ids that support the claim.")
|
|
45
47
|
create.add_argument("--evidence-ids", nargs="*", default=[], help="Evidence ids that substantiate the claim.")
|
|
@@ -61,6 +63,8 @@ def register_claim(subparsers: argparse._SubParsersAction) -> None:
|
|
|
61
63
|
update.add_argument("--title", default=None, help="Replacement claim title.")
|
|
62
64
|
update.add_argument("--kind", default=None, help="Updated claim category.")
|
|
63
65
|
update.add_argument("--description", default=None, help="Replacement claim description.")
|
|
66
|
+
update.add_argument("--body", default=None, help="Replacement longer-form claim narrative.")
|
|
67
|
+
update.add_argument("--body-file", default=None, help="Path to a UTF-8 text file containing the replacement claim body.")
|
|
64
68
|
update.set_defaults(func=run_update)
|
|
65
69
|
|
|
66
70
|
delete = claim_sub.add_parser("delete", help="Delete a claim.", description="Remove a claim record from the registry.")
|
|
@@ -110,6 +114,7 @@ def _build_links(args: argparse.Namespace) -> dict[str, list[str]]:
|
|
|
110
114
|
|
|
111
115
|
|
|
112
116
|
def run_create(args: argparse.Namespace) -> dict[str, object]:
|
|
117
|
+
body = load_text_argument(inline_value=args.body, file_value=args.body_file, label="claim")
|
|
113
118
|
row = {
|
|
114
119
|
"id": args.id,
|
|
115
120
|
"title": args.title,
|
|
@@ -117,6 +122,7 @@ def run_create(args: argparse.Namespace) -> dict[str, object]:
|
|
|
117
122
|
"tier": args.tier,
|
|
118
123
|
"kind": args.kind,
|
|
119
124
|
"description": args.description,
|
|
125
|
+
"body": body,
|
|
120
126
|
"feature_ids": args.feature_ids,
|
|
121
127
|
"test_ids": args.test_ids,
|
|
122
128
|
"evidence_ids": args.evidence_ids,
|
|
@@ -133,7 +139,8 @@ def run_list(args: argparse.Namespace) -> dict[str, object]:
|
|
|
133
139
|
|
|
134
140
|
|
|
135
141
|
def run_update(args: argparse.Namespace) -> dict[str, object]:
|
|
136
|
-
|
|
142
|
+
body = load_text_argument(inline_value=args.body, file_value=args.body_file, label="claim")
|
|
143
|
+
changes = compact_dict({"title": args.title, "kind": args.kind, "description": args.description, "body": body})
|
|
137
144
|
if not changes:
|
|
138
145
|
raise ValueError("At least one update field is required")
|
|
139
146
|
return update_entity(args.path, "claims", args.id, changes)
|
|
@@ -68,3 +68,18 @@ def load_json_object_argument(
|
|
|
68
68
|
if not isinstance(payload, dict):
|
|
69
69
|
raise ValueError(f"{label} must decode to a JSON object")
|
|
70
70
|
return payload
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def load_text_argument(
|
|
74
|
+
*,
|
|
75
|
+
inline_value: str | None,
|
|
76
|
+
file_value: str | None,
|
|
77
|
+
label: str,
|
|
78
|
+
) -> str | None:
|
|
79
|
+
if inline_value is None and file_value is None:
|
|
80
|
+
return None
|
|
81
|
+
if inline_value is not None and file_value is not None:
|
|
82
|
+
raise ValueError(f"{label} accepts only one of body or body_file")
|
|
83
|
+
if file_value is not None:
|
|
84
|
+
return Path(file_value).read_text(encoding="utf-8-sig")
|
|
85
|
+
return inline_value
|
|
@@ -12,7 +12,7 @@ from ssot_registry.api import (
|
|
|
12
12
|
update_entity,
|
|
13
13
|
verify_evidence_rows,
|
|
14
14
|
)
|
|
15
|
-
from ssot_cli.common import add_ids_argument, add_path_argument, collect_list_fields, compact_dict
|
|
15
|
+
from ssot_cli.common import add_ids_argument, add_path_argument, collect_list_fields, compact_dict, load_text_argument
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
_LINK_MAPPING = {
|
|
@@ -36,6 +36,8 @@ def register_evidence(subparsers: argparse._SubParsersAction) -> None:
|
|
|
36
36
|
create.add_argument("--status", choices=["planned", "collected", "passed", "failed", "stale"], default="planned", help="Current freshness or outcome state of the evidence artifact.")
|
|
37
37
|
create.add_argument("--kind", required=True, help="Operator-defined evidence category such as report, bundle, or log.")
|
|
38
38
|
create.add_argument("--tier", choices=["T0", "T1", "T2", "T3", "T4"], default="T0", help="Assurance tier the evidence contributes toward.")
|
|
39
|
+
create.add_argument("--body", default=None, help="Optional longer-form narrative for the evidence row.")
|
|
40
|
+
create.add_argument("--body-file", default=None, help="Path to a UTF-8 text file containing the evidence body.")
|
|
39
41
|
create.add_argument("--evidence-path", dest="evidence_path", required=True, help="Repository-relative location of the evidence artifact.")
|
|
40
42
|
create.add_argument("--claim-ids", nargs="*", default=[], help="Claim ids supported by the evidence.")
|
|
41
43
|
create.add_argument("--test-ids", nargs="*", default=[], help="Test ids associated with the evidence.")
|
|
@@ -58,6 +60,8 @@ def register_evidence(subparsers: argparse._SubParsersAction) -> None:
|
|
|
58
60
|
update.add_argument("--status", choices=["planned", "collected", "passed", "failed", "stale"], default=None, help="Updated freshness or outcome state.")
|
|
59
61
|
update.add_argument("--kind", default=None, help="Updated evidence category.")
|
|
60
62
|
update.add_argument("--tier", choices=["T0", "T1", "T2", "T3", "T4"], default=None, help="Updated assurance tier contribution.")
|
|
63
|
+
update.add_argument("--body", default=None, help="Replacement longer-form evidence narrative.")
|
|
64
|
+
update.add_argument("--body-file", default=None, help="Path to a UTF-8 text file containing the replacement evidence body.")
|
|
61
65
|
update.add_argument("--evidence-path", dest="evidence_path", default=None, help="Updated repository-relative path to the artifact.")
|
|
62
66
|
update.set_defaults(func=run_update)
|
|
63
67
|
|
|
@@ -94,12 +98,14 @@ def _build_links(args: argparse.Namespace) -> dict[str, list[str]]:
|
|
|
94
98
|
|
|
95
99
|
|
|
96
100
|
def run_create(args: argparse.Namespace) -> dict[str, object]:
|
|
101
|
+
body = load_text_argument(inline_value=args.body, file_value=args.body_file, label="evidence")
|
|
97
102
|
row = {
|
|
98
103
|
"id": args.id,
|
|
99
104
|
"title": args.title,
|
|
100
105
|
"status": args.status,
|
|
101
106
|
"kind": args.kind,
|
|
102
107
|
"tier": args.tier,
|
|
108
|
+
"body": body,
|
|
103
109
|
"path": args.evidence_path,
|
|
104
110
|
"claim_ids": args.claim_ids,
|
|
105
111
|
"test_ids": args.test_ids,
|
|
@@ -116,12 +122,14 @@ def run_list(args: argparse.Namespace) -> dict[str, object]:
|
|
|
116
122
|
|
|
117
123
|
|
|
118
124
|
def run_update(args: argparse.Namespace) -> dict[str, object]:
|
|
125
|
+
body = load_text_argument(inline_value=args.body, file_value=args.body_file, label="evidence")
|
|
119
126
|
changes = compact_dict(
|
|
120
127
|
{
|
|
121
128
|
"title": args.title,
|
|
122
129
|
"status": args.status,
|
|
123
130
|
"kind": args.kind,
|
|
124
131
|
"tier": args.tier,
|
|
132
|
+
"body": body,
|
|
125
133
|
"path": args.evidence_path,
|
|
126
134
|
}
|
|
127
135
|
)
|
|
@@ -20,7 +20,7 @@ from ssot_registry.api import (
|
|
|
20
20
|
unlink_entities,
|
|
21
21
|
update_entity,
|
|
22
22
|
)
|
|
23
|
-
from ssot_cli.common import add_ids_argument, add_optional_bool_argument, add_path_argument, collect_list_fields, compact_dict
|
|
23
|
+
from ssot_cli.common import add_ids_argument, add_optional_bool_argument, add_path_argument, collect_list_fields, compact_dict, load_text_argument
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
_LINK_MAPPING = {
|
|
@@ -48,6 +48,8 @@ def register_feature(subparsers: argparse._SubParsersAction) -> None:
|
|
|
48
48
|
create.add_argument("--id", required=True, help="Normalized feature id to create.")
|
|
49
49
|
create.add_argument("--title", required=True, help="Human-readable feature title.")
|
|
50
50
|
create.add_argument("--description", default="", help="Operator-facing summary of the feature's purpose.")
|
|
51
|
+
create.add_argument("--body", default=None, help="Optional longer-form narrative for the feature.")
|
|
52
|
+
create.add_argument("--body-file", default=None, help="Path to a UTF-8 text file containing the feature body.")
|
|
51
53
|
create.add_argument("--implementation-status", choices=sorted(FEATURE_IMPLEMENTATION_STATUSES), default="absent", help="Current implementation state in the codebase.")
|
|
52
54
|
create.add_argument("--lifecycle-stage", choices=sorted(FEATURE_LIFECYCLE_STAGES), default="active", help="Actual lifecycle state of the feature today.")
|
|
53
55
|
create.add_argument("--replacement-feature-id", nargs="*", default=[], help="Replacement feature ids if this feature is being deprecated or removed.")
|
|
@@ -78,6 +80,8 @@ def register_feature(subparsers: argparse._SubParsersAction) -> None:
|
|
|
78
80
|
update.add_argument("--id", required=True, help="Feature id to update.")
|
|
79
81
|
update.add_argument("--title", default=None, help="Replacement feature title.")
|
|
80
82
|
update.add_argument("--description", default=None, help="Replacement feature description.")
|
|
83
|
+
update.add_argument("--body", default=None, help="Replacement longer-form feature narrative.")
|
|
84
|
+
update.add_argument("--body-file", default=None, help="Path to a UTF-8 text file containing the replacement feature body.")
|
|
81
85
|
update.add_argument("--implementation-status", choices=sorted(FEATURE_IMPLEMENTATION_STATUSES), default=None, help="Updated implementation state in the codebase.")
|
|
82
86
|
update.set_defaults(func=run_update)
|
|
83
87
|
|
|
@@ -149,6 +153,7 @@ def _build_links(args: argparse.Namespace) -> dict[str, list[str]]:
|
|
|
149
153
|
|
|
150
154
|
|
|
151
155
|
def run_create(args: argparse.Namespace) -> dict[str, object]:
|
|
156
|
+
body = load_text_argument(inline_value=args.body, file_value=args.body_file, label="feature")
|
|
152
157
|
plan = {
|
|
153
158
|
"horizon": args.horizon,
|
|
154
159
|
"slot": args.slot,
|
|
@@ -162,6 +167,7 @@ def run_create(args: argparse.Namespace) -> dict[str, object]:
|
|
|
162
167
|
"id": args.id,
|
|
163
168
|
"title": args.title,
|
|
164
169
|
"description": args.description,
|
|
170
|
+
"body": body,
|
|
165
171
|
"implementation_status": args.implementation_status,
|
|
166
172
|
"lifecycle": {
|
|
167
173
|
"stage": args.lifecycle_stage,
|
|
@@ -186,10 +192,12 @@ def run_list(args: argparse.Namespace) -> dict[str, object]:
|
|
|
186
192
|
|
|
187
193
|
|
|
188
194
|
def run_update(args: argparse.Namespace) -> dict[str, object]:
|
|
195
|
+
body = load_text_argument(inline_value=args.body, file_value=args.body_file, label="feature")
|
|
189
196
|
changes = compact_dict(
|
|
190
197
|
{
|
|
191
198
|
"title": args.title,
|
|
192
199
|
"description": args.description,
|
|
200
|
+
"body": body,
|
|
193
201
|
"implementation_status": args.implementation_status,
|
|
194
202
|
}
|
|
195
203
|
)
|
|
@@ -13,7 +13,7 @@ from ssot_registry.api import (
|
|
|
13
13
|
unlink_entities,
|
|
14
14
|
update_entity,
|
|
15
15
|
)
|
|
16
|
-
from ssot_cli.common import add_ids_argument, add_optional_bool_argument, add_path_argument, collect_list_fields, compact_dict
|
|
16
|
+
from ssot_cli.common import add_ids_argument, add_optional_bool_argument, add_path_argument, collect_list_fields, compact_dict, load_text_argument
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
_LINK_MAPPING = {
|
|
@@ -40,6 +40,8 @@ def register_issue(subparsers: argparse._SubParsersAction) -> None:
|
|
|
40
40
|
create.add_argument("--status", choices=["open", "in_progress", "blocked", "resolved", "closed"], default="open", help="Current workflow state of the issue.")
|
|
41
41
|
create.add_argument("--severity", choices=["low", "medium", "high", "critical"], default="medium", help="Operational severity of the issue.")
|
|
42
42
|
create.add_argument("--description", default="", help="Operator-facing problem summary and context.")
|
|
43
|
+
create.add_argument("--body", default=None, help="Optional longer-form narrative for the issue.")
|
|
44
|
+
create.add_argument("--body-file", default=None, help="Path to a UTF-8 text file containing the issue body.")
|
|
43
45
|
create.add_argument("--horizon", choices=["current", "next", "future", "explicit", "backlog", "out_of_bounds"], default="backlog", help="Planning horizon used to schedule the issue.")
|
|
44
46
|
create.add_argument("--slot", default=None, help="Explicit release train, sprint, or slot label when planning explicitly.")
|
|
45
47
|
create.add_argument("--feature-ids", nargs="*", default=[], help="Feature ids affected by the issue.")
|
|
@@ -66,6 +68,8 @@ def register_issue(subparsers: argparse._SubParsersAction) -> None:
|
|
|
66
68
|
update.add_argument("--title", default=None, help="Replacement issue title.")
|
|
67
69
|
update.add_argument("--severity", choices=["low", "medium", "high", "critical"], default=None, help="Updated operational severity.")
|
|
68
70
|
update.add_argument("--description", default=None, help="Replacement issue description.")
|
|
71
|
+
update.add_argument("--body", default=None, help="Replacement longer-form issue narrative.")
|
|
72
|
+
update.add_argument("--body-file", default=None, help="Path to a UTF-8 text file containing the replacement issue body.")
|
|
69
73
|
add_optional_bool_argument(update, "--release-blocking", default=None, help_text="Change whether the issue is treated as a release blocker.")
|
|
70
74
|
update.set_defaults(func=run_update)
|
|
71
75
|
|
|
@@ -125,12 +129,14 @@ def _build_links(args: argparse.Namespace) -> dict[str, list[str]]:
|
|
|
125
129
|
|
|
126
130
|
|
|
127
131
|
def run_create(args: argparse.Namespace) -> dict[str, object]:
|
|
132
|
+
body = load_text_argument(inline_value=args.body, file_value=args.body_file, label="issue")
|
|
128
133
|
row = {
|
|
129
134
|
"id": args.id,
|
|
130
135
|
"title": args.title,
|
|
131
136
|
"status": args.status,
|
|
132
137
|
"severity": args.severity,
|
|
133
138
|
"description": args.description,
|
|
139
|
+
"body": body,
|
|
134
140
|
"plan": {"horizon": args.horizon, "slot": args.slot},
|
|
135
141
|
"feature_ids": args.feature_ids,
|
|
136
142
|
"claim_ids": args.claim_ids,
|
|
@@ -151,11 +157,13 @@ def run_list(args: argparse.Namespace) -> dict[str, object]:
|
|
|
151
157
|
|
|
152
158
|
|
|
153
159
|
def run_update(args: argparse.Namespace) -> dict[str, object]:
|
|
160
|
+
body = load_text_argument(inline_value=args.body, file_value=args.body_file, label="issue")
|
|
154
161
|
changes = compact_dict(
|
|
155
162
|
{
|
|
156
163
|
"title": args.title,
|
|
157
164
|
"severity": args.severity,
|
|
158
165
|
"description": args.description,
|
|
166
|
+
"body": body,
|
|
159
167
|
"release_blocking": args.release_blocking,
|
|
160
168
|
}
|
|
161
169
|
)
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import argparse
|
|
4
|
+
import re
|
|
4
5
|
import sys
|
|
6
|
+
from importlib.metadata import PackageNotFoundError, version as package_version
|
|
5
7
|
from pathlib import Path
|
|
6
8
|
from typing import Any
|
|
7
9
|
|
|
@@ -27,16 +29,51 @@ from .test_cmd import register_test
|
|
|
27
29
|
from .upgrade_cmd import register_upgrade
|
|
28
30
|
from .validate_cmd import register_validate
|
|
29
31
|
|
|
32
|
+
_PACKAGE_NAME = "ssot-cli"
|
|
33
|
+
_PYPROJECT_PATH = Path(__file__).resolve().parents[2] / "pyproject.toml"
|
|
34
|
+
_VERSION_PATTERN = re.compile(r'^version\s*=\s*"(?P<version>[^"]+)"\s*$')
|
|
35
|
+
|
|
30
36
|
|
|
31
37
|
def _default_prog() -> str:
|
|
32
38
|
executable = Path(sys.argv[0]).name
|
|
33
|
-
|
|
34
|
-
|
|
39
|
+
for suffix in (".exe", ".py"):
|
|
40
|
+
if executable.endswith(suffix):
|
|
41
|
+
executable = executable[: -len(suffix)]
|
|
42
|
+
break
|
|
35
43
|
if executable in {"", "__main__", "-m"}:
|
|
36
44
|
return "ssot-registry"
|
|
37
45
|
return executable
|
|
38
46
|
|
|
39
47
|
|
|
48
|
+
def _read_version_from_pyproject(pyproject_path: Path = _PYPROJECT_PATH) -> str:
|
|
49
|
+
in_project_section = False
|
|
50
|
+
|
|
51
|
+
for line in pyproject_path.read_text(encoding="utf-8").splitlines():
|
|
52
|
+
stripped = line.strip()
|
|
53
|
+
|
|
54
|
+
if stripped.startswith("[") and stripped.endswith("]"):
|
|
55
|
+
in_project_section = stripped == "[project]"
|
|
56
|
+
continue
|
|
57
|
+
|
|
58
|
+
if not in_project_section:
|
|
59
|
+
continue
|
|
60
|
+
|
|
61
|
+
match = _VERSION_PATTERN.match(stripped)
|
|
62
|
+
if match is not None:
|
|
63
|
+
return match.group("version")
|
|
64
|
+
|
|
65
|
+
raise RuntimeError(f"Unable to locate [project].version in {pyproject_path}")
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def _cli_version() -> str:
|
|
69
|
+
if _PYPROJECT_PATH.exists():
|
|
70
|
+
return _read_version_from_pyproject()
|
|
71
|
+
try:
|
|
72
|
+
return package_version(_PACKAGE_NAME)
|
|
73
|
+
except PackageNotFoundError:
|
|
74
|
+
return _read_version_from_pyproject()
|
|
75
|
+
|
|
76
|
+
|
|
40
77
|
def build_parser(*, prog: str | None = None) -> argparse.ArgumentParser:
|
|
41
78
|
parser = argparse.ArgumentParser(
|
|
42
79
|
prog=prog or _default_prog(),
|
|
@@ -46,6 +83,12 @@ def build_parser(*, prog: str | None = None) -> argparse.ArgumentParser:
|
|
|
46
83
|
"implementation features, verification artifacts, and publication-ready releases."
|
|
47
84
|
),
|
|
48
85
|
)
|
|
86
|
+
parser.add_argument(
|
|
87
|
+
"--version",
|
|
88
|
+
action="version",
|
|
89
|
+
version=f"%(prog)s {_cli_version()}",
|
|
90
|
+
help="Print the installed CLI package version and exit.",
|
|
91
|
+
)
|
|
49
92
|
parser.add_argument(
|
|
50
93
|
"--output-format",
|
|
51
94
|
default="json",
|
|
@@ -12,7 +12,7 @@ from ssot_registry.api import (
|
|
|
12
12
|
unlink_entities,
|
|
13
13
|
update_entity,
|
|
14
14
|
)
|
|
15
|
-
from ssot_cli.common import add_ids_argument, add_optional_bool_argument, add_path_argument, collect_list_fields, compact_dict
|
|
15
|
+
from ssot_cli.common import add_ids_argument, add_optional_bool_argument, add_path_argument, collect_list_fields, compact_dict, load_text_argument
|
|
16
16
|
|
|
17
17
|
_LINK_MAPPING = {
|
|
18
18
|
"feature_ids": "feature_ids",
|
|
@@ -33,6 +33,8 @@ def register_profile(subparsers: argparse._SubParsersAction) -> None:
|
|
|
33
33
|
create.add_argument("--id", required=True, help="Normalized profile id to create.")
|
|
34
34
|
create.add_argument("--title", required=True, help="Human-readable profile title.")
|
|
35
35
|
create.add_argument("--description", default="", help="Operator-facing summary of the profile's scope.")
|
|
36
|
+
create.add_argument("--body", default=None, help="Optional longer-form narrative for the profile.")
|
|
37
|
+
create.add_argument("--body-file", default=None, help="Path to a UTF-8 text file containing the profile body.")
|
|
36
38
|
create.add_argument("--status", choices=["draft", "active", "retired"], default="draft", help="Current lifecycle state of the profile.")
|
|
37
39
|
create.add_argument("--kind", choices=["capability", "certification", "deployment", "interoperability"], default="capability", help="Why the profile exists operationally.")
|
|
38
40
|
create.add_argument("--feature-ids", nargs="*", default=[], help="Feature ids directly included in the profile.")
|
|
@@ -61,6 +63,8 @@ def register_profile(subparsers: argparse._SubParsersAction) -> None:
|
|
|
61
63
|
update.add_argument("--id", required=True, help="Profile id to update.")
|
|
62
64
|
update.add_argument("--title", default=None, help="Replacement profile title.")
|
|
63
65
|
update.add_argument("--description", default=None, help="Replacement profile description.")
|
|
66
|
+
update.add_argument("--body", default=None, help="Replacement longer-form profile narrative.")
|
|
67
|
+
update.add_argument("--body-file", default=None, help="Path to a UTF-8 text file containing the replacement profile body.")
|
|
64
68
|
update.add_argument("--status", choices=["draft", "active", "retired"], default=None, help="New lifecycle state.")
|
|
65
69
|
update.add_argument("--kind", choices=["capability", "certification", "deployment", "interoperability"], default=None, help="New operational role for the profile.")
|
|
66
70
|
update.add_argument("--claim-tier", choices=["T0", "T1", "T2", "T3", "T4"], default=None, help="Updated default claim tier for evaluation.")
|
|
@@ -104,6 +108,7 @@ def _build_links(args: argparse.Namespace) -> dict[str, list[str]]:
|
|
|
104
108
|
|
|
105
109
|
|
|
106
110
|
def run_create(args: argparse.Namespace) -> dict[str, object]:
|
|
111
|
+
body = load_text_argument(inline_value=args.body, file_value=args.body_file, label="profile")
|
|
107
112
|
return create_entity(
|
|
108
113
|
args.path,
|
|
109
114
|
"profiles",
|
|
@@ -111,6 +116,7 @@ def run_create(args: argparse.Namespace) -> dict[str, object]:
|
|
|
111
116
|
"id": args.id,
|
|
112
117
|
"title": args.title,
|
|
113
118
|
"description": args.description,
|
|
119
|
+
"body": body,
|
|
114
120
|
"status": args.status,
|
|
115
121
|
"kind": args.kind,
|
|
116
122
|
"feature_ids": args.feature_ids,
|
|
@@ -133,10 +139,12 @@ def run_list(args: argparse.Namespace) -> dict[str, object]:
|
|
|
133
139
|
|
|
134
140
|
|
|
135
141
|
def run_update(args: argparse.Namespace) -> dict[str, object]:
|
|
142
|
+
body = load_text_argument(inline_value=args.body, file_value=args.body_file, label="profile")
|
|
136
143
|
changes = compact_dict(
|
|
137
144
|
{
|
|
138
145
|
"title": args.title,
|
|
139
146
|
"description": args.description,
|
|
147
|
+
"body": body,
|
|
140
148
|
"status": args.status,
|
|
141
149
|
"kind": args.kind,
|
|
142
150
|
"claim_tier": args.claim_tier,
|
|
@@ -19,7 +19,7 @@ from ssot_registry.api import (
|
|
|
19
19
|
revoke_release,
|
|
20
20
|
update_entity,
|
|
21
21
|
)
|
|
22
|
-
from ssot_cli.common import add_ids_argument, add_path_argument, compact_dict
|
|
22
|
+
from ssot_cli.common import add_ids_argument, add_path_argument, compact_dict, load_text_argument
|
|
23
23
|
|
|
24
24
|
|
|
25
25
|
def register_release(subparsers: argparse._SubParsersAction) -> None:
|
|
@@ -33,6 +33,8 @@ def register_release(subparsers: argparse._SubParsersAction) -> None:
|
|
|
33
33
|
create = release_sub.add_parser("create", help="Create a release candidate.", description="Create a release record tied to a frozen boundary and optional supporting claims and evidence.")
|
|
34
34
|
add_path_argument(create)
|
|
35
35
|
create.add_argument("--id", required=True, help="Normalized release id to create.")
|
|
36
|
+
create.add_argument("--body", default=None, help="Optional longer-form narrative for the release.")
|
|
37
|
+
create.add_argument("--body-file", default=None, help="Path to a UTF-8 text file containing the release body.")
|
|
36
38
|
create.add_argument("--version", required=True, help="Semantic or operator-defined version string for the release.")
|
|
37
39
|
create.add_argument("--status", choices=["draft", "candidate", "certified", "promoted", "published", "revoked"], default="draft", help="Current publication stage of the release.")
|
|
38
40
|
create.add_argument("--boundary-id", required=True, help="Primary frozen boundary id that defines the release scope.")
|
|
@@ -54,6 +56,8 @@ def register_release(subparsers: argparse._SubParsersAction) -> None:
|
|
|
54
56
|
update = release_sub.add_parser("update", help="Edit release metadata.", description="Update mutable release fields without changing its claim or evidence membership lists.")
|
|
55
57
|
add_path_argument(update)
|
|
56
58
|
update.add_argument("--id", required=True, help="Release id to update.")
|
|
59
|
+
update.add_argument("--body", default=None, help="Replacement longer-form release narrative.")
|
|
60
|
+
update.add_argument("--body-file", default=None, help="Path to a UTF-8 text file containing the replacement release body.")
|
|
57
61
|
update.add_argument("--version", default=None, help="Replacement release version string.")
|
|
58
62
|
update.add_argument("--status", choices=["draft", "candidate", "certified", "promoted", "published", "revoked"], default=None, help="Updated publication stage.")
|
|
59
63
|
update.add_argument("--boundary-id", default=None, help="Replacement primary boundary id that defines the release scope.")
|
|
@@ -125,10 +129,12 @@ def register_release(subparsers: argparse._SubParsersAction) -> None:
|
|
|
125
129
|
|
|
126
130
|
|
|
127
131
|
def run_create(args: argparse.Namespace) -> dict[str, object]:
|
|
132
|
+
body = load_text_argument(inline_value=args.body, file_value=args.body_file, label="release")
|
|
128
133
|
boundary_ids = [args.boundary_id, *(args.boundary_ids or [])]
|
|
129
134
|
boundary_ids = list(dict.fromkeys(boundary_ids))
|
|
130
135
|
row = {
|
|
131
136
|
"id": args.id,
|
|
137
|
+
"body": body,
|
|
132
138
|
"version": args.version,
|
|
133
139
|
"status": args.status,
|
|
134
140
|
"boundary_id": args.boundary_id,
|
|
@@ -148,6 +154,7 @@ def run_list(args: argparse.Namespace) -> dict[str, object]:
|
|
|
148
154
|
|
|
149
155
|
|
|
150
156
|
def run_update(args: argparse.Namespace) -> dict[str, object]:
|
|
157
|
+
body = load_text_argument(inline_value=args.body, file_value=args.body_file, label="release")
|
|
151
158
|
boundary_ids = args.boundary_ids
|
|
152
159
|
if boundary_ids is not None:
|
|
153
160
|
boundary_ids = list(dict.fromkeys(([args.boundary_id] if args.boundary_id else []) + boundary_ids))
|
|
@@ -156,6 +163,7 @@ def run_update(args: argparse.Namespace) -> dict[str, object]:
|
|
|
156
163
|
elif args.boundary_id is not None:
|
|
157
164
|
boundary_ids = [args.boundary_id]
|
|
158
165
|
changes = compact_dict({
|
|
166
|
+
"body": body,
|
|
159
167
|
"version": args.version,
|
|
160
168
|
"status": args.status,
|
|
161
169
|
"boundary_id": args.boundary_id or (boundary_ids[0] if boundary_ids else None),
|
|
@@ -12,7 +12,7 @@ from ssot_registry.api import (
|
|
|
12
12
|
unlink_entities,
|
|
13
13
|
update_entity,
|
|
14
14
|
)
|
|
15
|
-
from ssot_cli.common import add_ids_argument, add_optional_bool_argument, add_path_argument, collect_list_fields, compact_dict
|
|
15
|
+
from ssot_cli.common import add_ids_argument, add_optional_bool_argument, add_path_argument, collect_list_fields, compact_dict, load_text_argument
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
_LINK_MAPPING = {
|
|
@@ -39,6 +39,8 @@ def register_risk(subparsers: argparse._SubParsersAction) -> None:
|
|
|
39
39
|
create.add_argument("--status", choices=["active", "mitigated", "accepted", "retired"], default="active", help="Current treatment state of the risk.")
|
|
40
40
|
create.add_argument("--severity", choices=["low", "medium", "high", "critical"], default="medium", help="Operational severity of the exposure.")
|
|
41
41
|
create.add_argument("--description", default="", help="Operator-facing description of the exposure and context.")
|
|
42
|
+
create.add_argument("--body", default=None, help="Optional longer-form narrative for the risk.")
|
|
43
|
+
create.add_argument("--body-file", default=None, help="Path to a UTF-8 text file containing the risk body.")
|
|
42
44
|
create.add_argument("--feature-ids", nargs="*", default=[], help="Feature ids exposed by the risk.")
|
|
43
45
|
create.add_argument("--claim-ids", nargs="*", default=[], help="Claim ids affected by the risk.")
|
|
44
46
|
create.add_argument("--test-ids", nargs="*", default=[], help="Test ids related to the risk.")
|
|
@@ -63,6 +65,8 @@ def register_risk(subparsers: argparse._SubParsersAction) -> None:
|
|
|
63
65
|
update.add_argument("--title", default=None, help="Replacement risk title.")
|
|
64
66
|
update.add_argument("--severity", choices=["low", "medium", "high", "critical"], default=None, help="Updated operational severity.")
|
|
65
67
|
update.add_argument("--description", default=None, help="Replacement risk description.")
|
|
68
|
+
update.add_argument("--body", default=None, help="Replacement longer-form risk narrative.")
|
|
69
|
+
update.add_argument("--body-file", default=None, help="Path to a UTF-8 text file containing the replacement risk body.")
|
|
66
70
|
add_optional_bool_argument(update, "--release-blocking", default=None, help_text="Change whether the risk is treated as a release blocker.")
|
|
67
71
|
update.set_defaults(func=run_update)
|
|
68
72
|
|
|
@@ -115,12 +119,14 @@ def _build_links(args: argparse.Namespace) -> dict[str, list[str]]:
|
|
|
115
119
|
|
|
116
120
|
|
|
117
121
|
def run_create(args: argparse.Namespace) -> dict[str, object]:
|
|
122
|
+
body = load_text_argument(inline_value=args.body, file_value=args.body_file, label="risk")
|
|
118
123
|
row = {
|
|
119
124
|
"id": args.id,
|
|
120
125
|
"title": args.title,
|
|
121
126
|
"status": args.status,
|
|
122
127
|
"severity": args.severity,
|
|
123
128
|
"description": args.description,
|
|
129
|
+
"body": body,
|
|
124
130
|
"feature_ids": args.feature_ids,
|
|
125
131
|
"claim_ids": args.claim_ids,
|
|
126
132
|
"test_ids": args.test_ids,
|
|
@@ -140,11 +146,13 @@ def run_list(args: argparse.Namespace) -> dict[str, object]:
|
|
|
140
146
|
|
|
141
147
|
|
|
142
148
|
def run_update(args: argparse.Namespace) -> dict[str, object]:
|
|
149
|
+
body = load_text_argument(inline_value=args.body, file_value=args.body_file, label="risk")
|
|
143
150
|
changes = compact_dict(
|
|
144
151
|
{
|
|
145
152
|
"title": args.title,
|
|
146
153
|
"severity": args.severity,
|
|
147
154
|
"description": args.description,
|
|
155
|
+
"body": body,
|
|
148
156
|
"release_blocking": args.release_blocking,
|
|
149
157
|
}
|
|
150
158
|
)
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import argparse
|
|
4
4
|
|
|
5
5
|
from ssot_registry.api import create_entity, delete_entity, get_entity, link_entities, list_entities, run_tests, unlink_entities, update_entity
|
|
6
|
-
from ssot_cli.common import add_ids_argument, add_path_argument, collect_list_fields, compact_dict, load_json_object_argument
|
|
6
|
+
from ssot_cli.common import add_ids_argument, add_path_argument, collect_list_fields, compact_dict, load_json_object_argument, load_text_argument
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
_LINK_MAPPING = {
|
|
@@ -25,6 +25,8 @@ def register_test(subparsers: argparse._SubParsersAction) -> None:
|
|
|
25
25
|
add_path_argument(create)
|
|
26
26
|
create.add_argument("--id", required=True, help="Normalized test id to create.")
|
|
27
27
|
create.add_argument("--title", required=True, help="Human-readable test title.")
|
|
28
|
+
create.add_argument("--body", default=None, help="Optional longer-form narrative for the test.")
|
|
29
|
+
create.add_argument("--body-file", default=None, help="Path to a UTF-8 text file containing the test body.")
|
|
28
30
|
create.add_argument("--status", choices=["planned", "passing", "failing", "blocked", "skipped"], default="planned", help="Current execution or readiness state of the test.")
|
|
29
31
|
create.add_argument("--kind", required=True, help="Operator-defined test category such as unit, integration, or manual.")
|
|
30
32
|
create.add_argument("--test-path", dest="test_path", required=True, help="Repository-relative location of the executable test or test specification.")
|
|
@@ -49,6 +51,8 @@ def register_test(subparsers: argparse._SubParsersAction) -> None:
|
|
|
49
51
|
add_path_argument(update)
|
|
50
52
|
update.add_argument("--id", required=True, help="Test id to update.")
|
|
51
53
|
update.add_argument("--title", default=None, help="Replacement test title.")
|
|
54
|
+
update.add_argument("--body", default=None, help="Replacement longer-form test narrative.")
|
|
55
|
+
update.add_argument("--body-file", default=None, help="Path to a UTF-8 text file containing the replacement test body.")
|
|
52
56
|
update.add_argument("--status", choices=["planned", "passing", "failing", "blocked", "skipped"], default=None, help="Updated execution or readiness state.")
|
|
53
57
|
update.add_argument("--kind", default=None, help="Updated test category.")
|
|
54
58
|
update.add_argument("--test-path", dest="test_path", default=None, help="Updated repository-relative path to the test or procedure.")
|
|
@@ -99,6 +103,7 @@ def _build_links(args: argparse.Namespace) -> dict[str, list[str]]:
|
|
|
99
103
|
|
|
100
104
|
|
|
101
105
|
def run_create(args: argparse.Namespace) -> dict[str, object]:
|
|
106
|
+
body = load_text_argument(inline_value=args.body, file_value=args.body_file, label="test")
|
|
102
107
|
execution = load_json_object_argument(
|
|
103
108
|
inline_value=args.execution_json,
|
|
104
109
|
file_value=args.execution_file,
|
|
@@ -107,6 +112,7 @@ def run_create(args: argparse.Namespace) -> dict[str, object]:
|
|
|
107
112
|
row = {
|
|
108
113
|
"id": args.id,
|
|
109
114
|
"title": args.title,
|
|
115
|
+
"body": body,
|
|
110
116
|
"status": args.status,
|
|
111
117
|
"kind": args.kind,
|
|
112
118
|
"path": args.test_path,
|
|
@@ -127,6 +133,7 @@ def run_list(args: argparse.Namespace) -> dict[str, object]:
|
|
|
127
133
|
|
|
128
134
|
|
|
129
135
|
def run_update(args: argparse.Namespace) -> dict[str, object]:
|
|
136
|
+
body = load_text_argument(inline_value=args.body, file_value=args.body_file, label="test")
|
|
130
137
|
execution = load_json_object_argument(
|
|
131
138
|
inline_value=args.execution_json,
|
|
132
139
|
file_value=args.execution_file,
|
|
@@ -135,6 +142,7 @@ def run_update(args: argparse.Namespace) -> dict[str, object]:
|
|
|
135
142
|
changes = compact_dict(
|
|
136
143
|
{
|
|
137
144
|
"title": args.title,
|
|
145
|
+
"body": body,
|
|
138
146
|
"status": args.status,
|
|
139
147
|
"kind": args.kind,
|
|
140
148
|
"path": args.test_path,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ssot-cli
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.11
|
|
4
4
|
Summary: Primary CLI distribution for ssot-registry.
|
|
5
5
|
Author-email: Jacob Stewart <jacob@swarmauri.com>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -24,9 +24,9 @@ Classifier: Topic :: Software Development :: Quality Assurance
|
|
|
24
24
|
Classifier: Topic :: Utilities
|
|
25
25
|
Requires-Python: <3.14,>=3.10
|
|
26
26
|
Description-Content-Type: text/markdown
|
|
27
|
-
Requires-Dist: ssot-contracts<0.3.0,>=0.2.
|
|
28
|
-
Requires-Dist: ssot-core<0.3.0,>=0.2.
|
|
29
|
-
Requires-Dist: ssot-conformance<0.3.0,>=0.2.
|
|
27
|
+
Requires-Dist: ssot-contracts<0.3.0,>=0.2.17
|
|
28
|
+
Requires-Dist: ssot-core<0.3.0,>=0.2.17
|
|
29
|
+
Requires-Dist: ssot-conformance<0.3.0,>=0.2.17
|
|
30
30
|
Requires-Dist: tomli>=2.0.1; python_version < "3.11"
|
|
31
31
|
|
|
32
32
|
<div align="center">
|
|
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
|
|
File without changes
|