ssot-cli 0.1.11.dev1__tar.gz → 0.1.12__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.11.dev1 → ssot_cli-0.1.12}/PKG-INFO +17 -9
- {ssot_cli-0.1.11.dev1 → ssot_cli-0.1.12}/README.md +10 -4
- {ssot_cli-0.1.11.dev1 → ssot_cli-0.1.12}/pyproject.toml +7 -5
- {ssot_cli-0.1.11.dev1 → ssot_cli-0.1.12}/src/ssot_cli/claim_cmd.py +20 -5
- {ssot_cli-0.1.11.dev1 → ssot_cli-0.1.12}/src/ssot_cli/common.py +11 -1
- ssot_cli-0.1.12/src/ssot_cli/config_cmd.py +53 -0
- {ssot_cli-0.1.11.dev1 → ssot_cli-0.1.12}/src/ssot_cli/conformance_cmd.py +34 -0
- {ssot_cli-0.1.11.dev1 → ssot_cli-0.1.12}/src/ssot_cli/evidence_cmd.py +8 -2
- {ssot_cli-0.1.11.dev1 → ssot_cli-0.1.12}/src/ssot_cli/feature_cmd.py +8 -2
- {ssot_cli-0.1.11.dev1 → ssot_cli-0.1.12}/src/ssot_cli/main.py +49 -2
- ssot_cli-0.1.12/src/ssot_cli/pack_cmd.py +92 -0
- {ssot_cli-0.1.11.dev1 → ssot_cli-0.1.12}/src/ssot_cli/registry_cmd.py +17 -1
- {ssot_cli-0.1.11.dev1 → ssot_cli-0.1.12}/src/ssot_cli/release_cmd.py +23 -0
- {ssot_cli-0.1.11.dev1 → ssot_cli-0.1.12}/src/ssot_cli/test_cmd.py +8 -2
- {ssot_cli-0.1.11.dev1 → ssot_cli-0.1.12}/src/ssot_cli.egg-info/PKG-INFO +17 -9
- {ssot_cli-0.1.11.dev1 → ssot_cli-0.1.12}/src/ssot_cli.egg-info/SOURCES.txt +2 -0
- ssot_cli-0.1.12/src/ssot_cli.egg-info/requires.txt +7 -0
- ssot_cli-0.1.11.dev1/src/ssot_cli.egg-info/requires.txt +0 -6
- {ssot_cli-0.1.11.dev1 → ssot_cli-0.1.12}/setup.cfg +0 -0
- {ssot_cli-0.1.11.dev1 → ssot_cli-0.1.12}/src/ssot_cli/__init__.py +0 -0
- {ssot_cli-0.1.11.dev1 → ssot_cli-0.1.12}/src/ssot_cli/adr_cmd.py +0 -0
- {ssot_cli-0.1.11.dev1 → ssot_cli-0.1.12}/src/ssot_cli/boundary_cmd.py +0 -0
- {ssot_cli-0.1.11.dev1 → ssot_cli-0.1.12}/src/ssot_cli/graph_cmd.py +0 -0
- {ssot_cli-0.1.11.dev1 → ssot_cli-0.1.12}/src/ssot_cli/init_cmd.py +0 -0
- {ssot_cli-0.1.11.dev1 → ssot_cli-0.1.12}/src/ssot_cli/issue_cmd.py +0 -0
- {ssot_cli-0.1.11.dev1 → ssot_cli-0.1.12}/src/ssot_cli/profile_cmd.py +0 -0
- {ssot_cli-0.1.11.dev1 → ssot_cli-0.1.12}/src/ssot_cli/risk_cmd.py +0 -0
- {ssot_cli-0.1.11.dev1 → ssot_cli-0.1.12}/src/ssot_cli/spec_cmd.py +0 -0
- {ssot_cli-0.1.11.dev1 → ssot_cli-0.1.12}/src/ssot_cli/upgrade_cmd.py +0 -0
- {ssot_cli-0.1.11.dev1 → ssot_cli-0.1.12}/src/ssot_cli/validate_cmd.py +0 -0
- {ssot_cli-0.1.11.dev1 → ssot_cli-0.1.12}/src/ssot_cli.egg-info/dependency_links.txt +0 -0
- {ssot_cli-0.1.11.dev1 → ssot_cli-0.1.12}/src/ssot_cli.egg-info/entry_points.txt +0 -0
- {ssot_cli-0.1.11.dev1 → ssot_cli-0.1.12}/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.12
|
|
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
|
|
@@ -19,14 +19,16 @@ Classifier: Programming Language :: Python :: 3.10
|
|
|
19
19
|
Classifier: Programming Language :: Python :: 3.11
|
|
20
20
|
Classifier: Programming Language :: Python :: 3.12
|
|
21
21
|
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
22
23
|
Classifier: Topic :: Software Development :: Documentation
|
|
23
24
|
Classifier: Topic :: Software Development :: Quality Assurance
|
|
24
25
|
Classifier: Topic :: Utilities
|
|
25
|
-
Requires-Python: <3.
|
|
26
|
+
Requires-Python: <3.15,>=3.10
|
|
26
27
|
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.
|
|
28
|
+
Requires-Dist: ssot-contracts<0.3.0,>=0.2.18
|
|
29
|
+
Requires-Dist: ssot-core<0.3.0,>=0.2.18
|
|
30
|
+
Requires-Dist: ssot-conformance<0.3.0,>=0.2.18
|
|
31
|
+
Requires-Dist: ssot-pack-contracts<0.3.0,>=0.2.19
|
|
30
32
|
Requires-Dist: tomli>=2.0.1; python_version < "3.11"
|
|
31
33
|
|
|
32
34
|
<div align="center">
|
|
@@ -39,11 +41,15 @@ Requires-Dist: tomli>=2.0.1; python_version < "3.11"
|
|
|
39
41
|
<a href="https://pypi.org/project/ssot-cli/"><img src="https://img.shields.io/pypi/pyversions/ssot-cli?label=Python" alt="Supported Python versions" /></a>
|
|
40
42
|
<a href="https://pepy.tech/project/ssot-cli"><img src="https://static.pepy.tech/badge/ssot-cli" alt="Downloads" /></a>
|
|
41
43
|
<a href="https://hits.sh/github.com/groupsum/ssot-registry/"><img src="https://hits.sh/github.com/groupsum/ssot-registry.svg?style=flat-square" alt="Repository hits" /></a>
|
|
44
|
+
<!-- ssot-schema-badges:start -->
|
|
45
|
+
<img src="https://img.shields.io/badge/schema_version-0.5.0-blue" alt="schema_version 0.5.0" />
|
|
46
|
+
<img src="https://img.shields.io/badge/migration%20coverage-12%2F12-brightgreen" alt="Migration coverage 12/12" />
|
|
47
|
+
<!-- ssot-schema-badges:end -->
|
|
42
48
|
</div>
|
|
43
49
|
|
|
44
50
|
`ssot-cli` is the primary command-line distribution for SSOT.
|
|
45
51
|
|
|
46
|
-
It installs `ssot`, `ssot-cli`, and `ssot-registry` as equivalent executables over the same parser and runtime. The command surface is implemented here, while domain logic lives in [ssot-core](https://pypi.org/project/ssot-core/), reusable conformance checks come from [ssot-conformance](https://pypi.org/project/ssot-conformance/),
|
|
52
|
+
It installs `ssot`, `ssot-cli`, and `ssot-registry` as equivalent executables over the same parser and runtime. The command surface is implemented here, while domain logic lives in [ssot-core](https://pypi.org/project/ssot-core/), reusable conformance checks come from [ssot-conformance](https://pypi.org/project/ssot-conformance/), shared contract metadata comes from [ssot-contracts](https://pypi.org/project/ssot-contracts/), and governance pack interoperability contracts come from [ssot-pack-contracts](https://pypi.org/project/ssot-pack-contracts/).
|
|
47
53
|
|
|
48
54
|
- GitHub: https://github.com/groupsum/ssot-registry
|
|
49
55
|
|
|
@@ -65,7 +71,9 @@ For local development:
|
|
|
65
71
|
python -m pip install -e pkgs/ssot-cli
|
|
66
72
|
```
|
|
67
73
|
|
|
68
|
-
This package depends on [ssot-core](https://pypi.org/project/ssot-core/), [ssot-conformance](https://pypi.org/project/ssot-conformance/), and [ssot-contracts](https://pypi.org/project/ssot-contracts/), so installing it gives you the full CLI runtime stack.
|
|
74
|
+
This package depends on [ssot-core](https://pypi.org/project/ssot-core/), [ssot-conformance](https://pypi.org/project/ssot-conformance/), [ssot-contracts](https://pypi.org/project/ssot-contracts/), and [ssot-pack-contracts](https://pypi.org/project/ssot-pack-contracts/), so installing it gives you the full CLI runtime stack for registry operations and governance pack contract checks.
|
|
75
|
+
|
|
76
|
+
The CLI tracks the current core release train through compatible `<0.3.0` ranges and uses the current `ssot-pack-contracts` floor. That keeps pack-aware CLI behavior compatible with the latest contract package without forcing unrelated surface packages into core lockstep.
|
|
69
77
|
|
|
70
78
|
## Executable names
|
|
71
79
|
|
|
@@ -121,7 +129,7 @@ ssot registry --help
|
|
|
121
129
|
|
|
122
130
|
## Screenshots
|
|
123
131
|
|
|
124
|
-
Regenerate
|
|
132
|
+
The screenshots below are generated from the current parser help. Regenerate them with `python scripts/generate_cli_screenshots.py`, or regenerate the CLI and TUI assets together with `python scripts/generate_terminal_screenshots.py`.
|
|
125
133
|
|
|
126
134
|

|
|
127
135
|
|
|
@@ -864,7 +872,7 @@ ssot release certify . --release-id rel:0.1.0 --write-report
|
|
|
864
872
|
## Package relationships
|
|
865
873
|
|
|
866
874
|
- Package type: CLI distribution
|
|
867
|
-
- Depends on: [ssot-core](https://pypi.org/project/ssot-core/), [ssot-conformance](https://pypi.org/project/ssot-conformance/), [ssot-contracts](https://pypi.org/project/ssot-contracts/)
|
|
875
|
+
- Depends on: [ssot-core](https://pypi.org/project/ssot-core/), [ssot-conformance](https://pypi.org/project/ssot-conformance/), [ssot-contracts](https://pypi.org/project/ssot-contracts/), [ssot-pack-contracts](https://pypi.org/project/ssot-pack-contracts/)
|
|
868
876
|
- Related packages: [ssot-registry](https://pypi.org/project/ssot-registry/), [ssot-tui](https://pypi.org/project/ssot-tui/), [ssot-views](https://pypi.org/project/ssot-views/), [ssot-codegen](https://pypi.org/project/ssot-codegen/)
|
|
869
877
|
|
|
870
878
|
If you need the command-line interface, this is the package to install.
|
|
@@ -8,11 +8,15 @@
|
|
|
8
8
|
<a href="https://pypi.org/project/ssot-cli/"><img src="https://img.shields.io/pypi/pyversions/ssot-cli?label=Python" alt="Supported Python versions" /></a>
|
|
9
9
|
<a href="https://pepy.tech/project/ssot-cli"><img src="https://static.pepy.tech/badge/ssot-cli" alt="Downloads" /></a>
|
|
10
10
|
<a href="https://hits.sh/github.com/groupsum/ssot-registry/"><img src="https://hits.sh/github.com/groupsum/ssot-registry.svg?style=flat-square" alt="Repository hits" /></a>
|
|
11
|
+
<!-- ssot-schema-badges:start -->
|
|
12
|
+
<img src="https://img.shields.io/badge/schema_version-0.5.0-blue" alt="schema_version 0.5.0" />
|
|
13
|
+
<img src="https://img.shields.io/badge/migration%20coverage-12%2F12-brightgreen" alt="Migration coverage 12/12" />
|
|
14
|
+
<!-- ssot-schema-badges:end -->
|
|
11
15
|
</div>
|
|
12
16
|
|
|
13
17
|
`ssot-cli` is the primary command-line distribution for SSOT.
|
|
14
18
|
|
|
15
|
-
It installs `ssot`, `ssot-cli`, and `ssot-registry` as equivalent executables over the same parser and runtime. The command surface is implemented here, while domain logic lives in [ssot-core](https://pypi.org/project/ssot-core/), reusable conformance checks come from [ssot-conformance](https://pypi.org/project/ssot-conformance/),
|
|
19
|
+
It installs `ssot`, `ssot-cli`, and `ssot-registry` as equivalent executables over the same parser and runtime. The command surface is implemented here, while domain logic lives in [ssot-core](https://pypi.org/project/ssot-core/), reusable conformance checks come from [ssot-conformance](https://pypi.org/project/ssot-conformance/), shared contract metadata comes from [ssot-contracts](https://pypi.org/project/ssot-contracts/), and governance pack interoperability contracts come from [ssot-pack-contracts](https://pypi.org/project/ssot-pack-contracts/).
|
|
16
20
|
|
|
17
21
|
- GitHub: https://github.com/groupsum/ssot-registry
|
|
18
22
|
|
|
@@ -34,7 +38,9 @@ For local development:
|
|
|
34
38
|
python -m pip install -e pkgs/ssot-cli
|
|
35
39
|
```
|
|
36
40
|
|
|
37
|
-
This package depends on [ssot-core](https://pypi.org/project/ssot-core/), [ssot-conformance](https://pypi.org/project/ssot-conformance/), and [ssot-contracts](https://pypi.org/project/ssot-contracts/), so installing it gives you the full CLI runtime stack.
|
|
41
|
+
This package depends on [ssot-core](https://pypi.org/project/ssot-core/), [ssot-conformance](https://pypi.org/project/ssot-conformance/), [ssot-contracts](https://pypi.org/project/ssot-contracts/), and [ssot-pack-contracts](https://pypi.org/project/ssot-pack-contracts/), so installing it gives you the full CLI runtime stack for registry operations and governance pack contract checks.
|
|
42
|
+
|
|
43
|
+
The CLI tracks the current core release train through compatible `<0.3.0` ranges and uses the current `ssot-pack-contracts` floor. That keeps pack-aware CLI behavior compatible with the latest contract package without forcing unrelated surface packages into core lockstep.
|
|
38
44
|
|
|
39
45
|
## Executable names
|
|
40
46
|
|
|
@@ -90,7 +96,7 @@ ssot registry --help
|
|
|
90
96
|
|
|
91
97
|
## Screenshots
|
|
92
98
|
|
|
93
|
-
Regenerate
|
|
99
|
+
The screenshots below are generated from the current parser help. Regenerate them with `python scripts/generate_cli_screenshots.py`, or regenerate the CLI and TUI assets together with `python scripts/generate_terminal_screenshots.py`.
|
|
94
100
|
|
|
95
101
|

|
|
96
102
|
|
|
@@ -833,7 +839,7 @@ ssot release certify . --release-id rel:0.1.0 --write-report
|
|
|
833
839
|
## Package relationships
|
|
834
840
|
|
|
835
841
|
- Package type: CLI distribution
|
|
836
|
-
- Depends on: [ssot-core](https://pypi.org/project/ssot-core/), [ssot-conformance](https://pypi.org/project/ssot-conformance/), [ssot-contracts](https://pypi.org/project/ssot-contracts/)
|
|
842
|
+
- Depends on: [ssot-core](https://pypi.org/project/ssot-core/), [ssot-conformance](https://pypi.org/project/ssot-conformance/), [ssot-contracts](https://pypi.org/project/ssot-contracts/), [ssot-pack-contracts](https://pypi.org/project/ssot-pack-contracts/)
|
|
837
843
|
- Related packages: [ssot-registry](https://pypi.org/project/ssot-registry/), [ssot-tui](https://pypi.org/project/ssot-tui/), [ssot-views](https://pypi.org/project/ssot-views/), [ssot-codegen](https://pypi.org/project/ssot-codegen/)
|
|
838
844
|
|
|
839
845
|
If you need the command-line interface, this is the package to install.
|
|
@@ -4,16 +4,17 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "ssot-cli"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.12"
|
|
8
8
|
description = "Primary CLI distribution for ssot-registry."
|
|
9
9
|
readme = "README.md"
|
|
10
|
-
requires-python = ">=3.10,<3.
|
|
10
|
+
requires-python = ">=3.10,<3.15"
|
|
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.18,<0.3.0",
|
|
15
|
+
"ssot-core>=0.2.18,<0.3.0",
|
|
16
|
+
"ssot-conformance>=0.2.18,<0.3.0",
|
|
17
|
+
"ssot-pack-contracts>=0.2.19,<0.3.0",
|
|
17
18
|
"tomli>=2.0.1; python_version < '3.11'",
|
|
18
19
|
]
|
|
19
20
|
keywords = ["ssot", "cli", "registry", "governance", "release-management", "validation", "developer-tools"]
|
|
@@ -29,6 +30,7 @@ classifiers = [
|
|
|
29
30
|
"Programming Language :: Python :: 3.11",
|
|
30
31
|
"Programming Language :: Python :: 3.12",
|
|
31
32
|
"Programming Language :: Python :: 3.13",
|
|
33
|
+
"Programming Language :: Python :: 3.14",
|
|
32
34
|
"Topic :: Software Development :: Documentation",
|
|
33
35
|
"Topic :: Software Development :: Quality Assurance",
|
|
34
36
|
"Topic :: Utilities",
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import argparse
|
|
4
4
|
|
|
5
|
+
from ssot_contracts.generated.python.enums import ASSURANCE_ORIGINS
|
|
5
6
|
from ssot_registry.api import (
|
|
6
7
|
create_entity,
|
|
7
8
|
delete_entity,
|
|
@@ -14,13 +15,14 @@ from ssot_registry.api import (
|
|
|
14
15
|
unlink_entities,
|
|
15
16
|
update_entity,
|
|
16
17
|
)
|
|
17
|
-
from ssot_cli.common import add_ids_argument, add_path_argument, collect_list_fields, compact_dict, load_text_argument
|
|
18
|
+
from ssot_cli.common import add_ids_argument, add_origin_argument, add_path_argument, collect_list_fields, compact_dict, load_text_argument
|
|
18
19
|
|
|
19
20
|
|
|
20
21
|
_LINK_MAPPING = {
|
|
21
22
|
"feature_ids": "feature_ids",
|
|
22
23
|
"test_ids": "test_ids",
|
|
23
24
|
"evidence_ids": "evidence_ids",
|
|
25
|
+
"depends_on_claim_ids": "depends_on_claim_ids",
|
|
24
26
|
}
|
|
25
27
|
|
|
26
28
|
|
|
@@ -42,9 +44,11 @@ def register_claim(subparsers: argparse._SubParsersAction) -> None:
|
|
|
42
44
|
create.add_argument("--description", default="", help="What the claim asserts and why it matters.")
|
|
43
45
|
create.add_argument("--body", default=None, help="Optional longer-form narrative for the claim.")
|
|
44
46
|
create.add_argument("--body-file", default=None, help="Path to a UTF-8 text file containing the claim body.")
|
|
47
|
+
add_origin_argument(create, choices=sorted(ASSURANCE_ORIGINS), default="repo-local")
|
|
45
48
|
create.add_argument("--feature-ids", nargs="*", default=[], help="Feature ids the claim is about.")
|
|
46
49
|
create.add_argument("--test-ids", nargs="*", default=[], help="Test ids that support the claim.")
|
|
47
50
|
create.add_argument("--evidence-ids", nargs="*", default=[], help="Evidence ids that substantiate the claim.")
|
|
51
|
+
create.add_argument("--depends-on-claim-ids", nargs="*", default=[], help="Lower-tier claim ids this claim builds on.")
|
|
48
52
|
create.set_defaults(func=run_create)
|
|
49
53
|
|
|
50
54
|
get = claim_sub.add_parser("get", help="Show one claim.", description="Fetch a single claim record by id.")
|
|
@@ -55,6 +59,7 @@ def register_claim(subparsers: argparse._SubParsersAction) -> None:
|
|
|
55
59
|
list_cmd = claim_sub.add_parser("list", help="List claims.", description="List claim records currently known to the registry.")
|
|
56
60
|
add_path_argument(list_cmd)
|
|
57
61
|
add_ids_argument(list_cmd, help_text="Claim ids to include in the list output.")
|
|
62
|
+
add_origin_argument(list_cmd, choices=sorted(ASSURANCE_ORIGINS), default=None)
|
|
58
63
|
list_cmd.set_defaults(func=run_list)
|
|
59
64
|
|
|
60
65
|
update = claim_sub.add_parser("update", help="Edit claim metadata.", description="Update mutable claim fields without changing its linked support graph.")
|
|
@@ -65,6 +70,7 @@ def register_claim(subparsers: argparse._SubParsersAction) -> None:
|
|
|
65
70
|
update.add_argument("--description", default=None, help="Replacement claim description.")
|
|
66
71
|
update.add_argument("--body", default=None, help="Replacement longer-form claim narrative.")
|
|
67
72
|
update.add_argument("--body-file", default=None, help="Path to a UTF-8 text file containing the replacement claim body.")
|
|
73
|
+
add_origin_argument(update, choices=sorted(ASSURANCE_ORIGINS), default=None)
|
|
68
74
|
update.set_defaults(func=run_update)
|
|
69
75
|
|
|
70
76
|
delete = claim_sub.add_parser("delete", help="Delete a claim.", description="Remove a claim record from the registry.")
|
|
@@ -78,6 +84,7 @@ def register_claim(subparsers: argparse._SubParsersAction) -> None:
|
|
|
78
84
|
link.add_argument("--feature-ids", nargs="*", help="Feature ids to attach.")
|
|
79
85
|
link.add_argument("--test-ids", nargs="*", help="Test ids to attach.")
|
|
80
86
|
link.add_argument("--evidence-ids", nargs="*", help="Evidence ids to attach.")
|
|
87
|
+
link.add_argument("--depends-on-claim-ids", nargs="*", help="Lower-tier claim ids this claim builds on.")
|
|
81
88
|
link.set_defaults(func=run_link)
|
|
82
89
|
|
|
83
90
|
unlink = claim_sub.add_parser("unlink", help="Remove related records from a claim.", description="Remove links from a claim to features, tests, or evidence.")
|
|
@@ -86,11 +93,13 @@ def register_claim(subparsers: argparse._SubParsersAction) -> None:
|
|
|
86
93
|
unlink.add_argument("--feature-ids", nargs="*", help="Feature ids to detach.")
|
|
87
94
|
unlink.add_argument("--test-ids", nargs="*", help="Test ids to detach.")
|
|
88
95
|
unlink.add_argument("--evidence-ids", nargs="*", help="Evidence ids to detach.")
|
|
96
|
+
unlink.add_argument("--depends-on-claim-ids", nargs="*", help="Lower-tier claim ids to detach.")
|
|
89
97
|
unlink.set_defaults(func=run_unlink)
|
|
90
98
|
|
|
91
99
|
evaluate = claim_sub.add_parser("evaluate", help="Evaluate claim support.", description="Recompute claim support and readiness for one claim or the entire registry.")
|
|
92
100
|
add_path_argument(evaluate)
|
|
93
101
|
evaluate.add_argument("--claim-id", default=None, help="Claim id to evaluate. Omit to evaluate every claim in the registry.")
|
|
102
|
+
evaluate.add_argument("--include-tier-gate", action="store_true", help="Include machine-actionable claim tier gate evaluation.")
|
|
94
103
|
evaluate.set_defaults(func=run_evaluate)
|
|
95
104
|
|
|
96
105
|
set_status = claim_sub.add_parser("set-status", help="Advance or revise claim status.", description="Change the lifecycle status of a claim without editing other fields.")
|
|
@@ -99,7 +108,11 @@ def register_claim(subparsers: argparse._SubParsersAction) -> None:
|
|
|
99
108
|
set_status.add_argument("--status", required=True, choices=["proposed", "declared", "implemented", "asserted", "evidenced", "certified", "promoted", "published", "blocked", "retired"], help="Target lifecycle or publication state.")
|
|
100
109
|
set_status.set_defaults(func=run_set_status)
|
|
101
110
|
|
|
102
|
-
set_tier = claim_sub.add_parser(
|
|
111
|
+
set_tier = claim_sub.add_parser(
|
|
112
|
+
"set-tier",
|
|
113
|
+
help="Check claim tier immutability.",
|
|
114
|
+
description="Reject in-place claim tier changes; create a new claim row and use depends_on_claim_ids for append-only tier promotion.",
|
|
115
|
+
)
|
|
103
116
|
add_path_argument(set_tier)
|
|
104
117
|
set_tier.add_argument("--id", required=True, help="Claim id whose tier should change.")
|
|
105
118
|
set_tier.add_argument("--tier", required=True, choices=["T0", "T1", "T2", "T3", "T4"], help="Target assurance tier to assign.")
|
|
@@ -123,9 +136,11 @@ def run_create(args: argparse.Namespace) -> dict[str, object]:
|
|
|
123
136
|
"kind": args.kind,
|
|
124
137
|
"description": args.description,
|
|
125
138
|
"body": body,
|
|
139
|
+
"origin": args.origin,
|
|
126
140
|
"feature_ids": args.feature_ids,
|
|
127
141
|
"test_ids": args.test_ids,
|
|
128
142
|
"evidence_ids": args.evidence_ids,
|
|
143
|
+
"depends_on_claim_ids": args.depends_on_claim_ids,
|
|
129
144
|
}
|
|
130
145
|
return create_entity(args.path, "claims", row)
|
|
131
146
|
|
|
@@ -135,12 +150,12 @@ def run_get(args: argparse.Namespace) -> dict[str, object]:
|
|
|
135
150
|
|
|
136
151
|
|
|
137
152
|
def run_list(args: argparse.Namespace) -> dict[str, object]:
|
|
138
|
-
return list_entities(args.path, "claims", ids=args.ids)
|
|
153
|
+
return list_entities(args.path, "claims", ids=args.ids, origin=args.origin)
|
|
139
154
|
|
|
140
155
|
|
|
141
156
|
def run_update(args: argparse.Namespace) -> dict[str, object]:
|
|
142
157
|
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})
|
|
158
|
+
changes = compact_dict({"title": args.title, "kind": args.kind, "description": args.description, "body": body, "origin": args.origin})
|
|
144
159
|
if not changes:
|
|
145
160
|
raise ValueError("At least one update field is required")
|
|
146
161
|
return update_entity(args.path, "claims", args.id, changes)
|
|
@@ -159,7 +174,7 @@ def run_unlink(args: argparse.Namespace) -> dict[str, object]:
|
|
|
159
174
|
|
|
160
175
|
|
|
161
176
|
def run_evaluate(args: argparse.Namespace) -> dict[str, object]:
|
|
162
|
-
return evaluate_claims(path=args.path, claim_id=args.claim_id)
|
|
177
|
+
return evaluate_claims(path=args.path, claim_id=args.claim_id, include_tier_gate=args.include_tier_gate)
|
|
163
178
|
|
|
164
179
|
|
|
165
180
|
def run_set_status(args: argparse.Namespace) -> dict[str, object]:
|
|
@@ -23,6 +23,16 @@ def add_ids_argument(parser: argparse.ArgumentParser, flag: str = "--ids", *, de
|
|
|
23
23
|
parser.add_argument(flag, dest=dest, nargs="+", default=None, help=help_text)
|
|
24
24
|
|
|
25
25
|
|
|
26
|
+
def add_origin_argument(parser: argparse.ArgumentParser, *, choices: list[str], required: bool = False, default: str | None = None) -> None:
|
|
27
|
+
parser.add_argument(
|
|
28
|
+
"--origin",
|
|
29
|
+
choices=choices,
|
|
30
|
+
required=required,
|
|
31
|
+
default=default,
|
|
32
|
+
help="Assurance row origin owner.",
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
|
|
26
36
|
def add_optional_bool_argument(
|
|
27
37
|
parser: argparse.ArgumentParser,
|
|
28
38
|
name: str,
|
|
@@ -81,5 +91,5 @@ def load_text_argument(
|
|
|
81
91
|
if inline_value is not None and file_value is not None:
|
|
82
92
|
raise ValueError(f"{label} accepts only one of body or body_file")
|
|
83
93
|
if file_value is not None:
|
|
84
|
-
return Path(file_value).read_text(encoding="utf-8")
|
|
94
|
+
return Path(file_value).read_text(encoding="utf-8-sig")
|
|
85
95
|
return inline_value
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
|
|
5
|
+
from ssot_registry.api import ensure_repo_config, load_repo_config, validate_repo_config
|
|
6
|
+
|
|
7
|
+
from .common import add_path_argument
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def register_config(subparsers: argparse._SubParsersAction) -> None:
|
|
11
|
+
config = subparsers.add_parser(
|
|
12
|
+
"config",
|
|
13
|
+
help="Manage repo-local SSOT policy configuration.",
|
|
14
|
+
description="Create, inspect, and validate the repo-local `.ssot/ssot.toml` policy file.",
|
|
15
|
+
)
|
|
16
|
+
config_sub = config.add_subparsers(dest="config_command", required=True)
|
|
17
|
+
|
|
18
|
+
init = config_sub.add_parser(
|
|
19
|
+
"init",
|
|
20
|
+
help="Create or refresh the repo-local config file.",
|
|
21
|
+
description="Ensure that `.ssot/ssot.toml` exists and contains a valid default template.",
|
|
22
|
+
)
|
|
23
|
+
add_path_argument(init)
|
|
24
|
+
init.add_argument("--force", action="store_true", help="Overwrite an existing repo-local config file.")
|
|
25
|
+
init.set_defaults(func=run_init)
|
|
26
|
+
|
|
27
|
+
show = config_sub.add_parser(
|
|
28
|
+
"show",
|
|
29
|
+
help="Show the effective repo-local config.",
|
|
30
|
+
description="Load and display the validated repo-local SSOT config.",
|
|
31
|
+
)
|
|
32
|
+
add_path_argument(show)
|
|
33
|
+
show.set_defaults(func=run_show)
|
|
34
|
+
|
|
35
|
+
validate = config_sub.add_parser(
|
|
36
|
+
"validate",
|
|
37
|
+
help="Validate the repo-local config.",
|
|
38
|
+
description="Parse and validate the repo-local SSOT config file without mutating the repository.",
|
|
39
|
+
)
|
|
40
|
+
add_path_argument(validate)
|
|
41
|
+
validate.set_defaults(func=run_validate)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def run_init(args: argparse.Namespace) -> dict[str, object]:
|
|
45
|
+
return ensure_repo_config(args.path, overwrite=args.force)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def run_show(args: argparse.Namespace) -> dict[str, object]:
|
|
49
|
+
return load_repo_config(args.path)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def run_validate(args: argparse.Namespace) -> dict[str, object]:
|
|
53
|
+
return validate_repo_config(args.path)
|
|
@@ -44,6 +44,20 @@ def register_conformance(subparsers: argparse._SubParsersAction) -> None:
|
|
|
44
44
|
run.add_argument("--evidence-output", default=None, help="Optional JSON output path for machine-readable evidence.")
|
|
45
45
|
run.set_defaults(func=run_run)
|
|
46
46
|
|
|
47
|
+
origin = conformance_sub.add_parser(
|
|
48
|
+
"origin",
|
|
49
|
+
help="Generate downstream ssot-origin compliance tests.",
|
|
50
|
+
description="Plan or apply generated downstream conformance tests and SSOT rows for synchronized ssot-origin ADR and SPEC obligations.",
|
|
51
|
+
)
|
|
52
|
+
add_path_argument(origin)
|
|
53
|
+
origin.add_argument("--kinds", nargs="*", choices=["adr", "spec"], default=None, help="Limit generation to ADR or SPEC origin obligations.")
|
|
54
|
+
origin.add_argument("--apply", action="store_true", help="Write generated tests and registry rows instead of only reporting the plan.")
|
|
55
|
+
origin.add_argument("--include-claims", action="store_true", help="Generate claim rows and links.")
|
|
56
|
+
origin.add_argument("--include-evidence", action="store_true", help="Generate evidence rows and a machine-readable report.")
|
|
57
|
+
origin.add_argument("--overwrite", action="store_true", help="Allow replacing previously generated files.")
|
|
58
|
+
origin.add_argument("--report-output", default=None, help="Optional output path for the generated origin conformance report.")
|
|
59
|
+
origin.set_defaults(func=run_origin)
|
|
60
|
+
|
|
47
61
|
|
|
48
62
|
def run_profile_list(args: argparse.Namespace) -> dict[str, object]:
|
|
49
63
|
from ssot_conformance import list_profiles
|
|
@@ -86,3 +100,23 @@ def run_run(args: argparse.Namespace) -> dict[str, object]:
|
|
|
86
100
|
evidence_output=args.evidence_output,
|
|
87
101
|
dry_run=args.dry_run,
|
|
88
102
|
)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def run_origin(args: argparse.Namespace) -> dict[str, object]:
|
|
106
|
+
from ssot_conformance import apply_origin_conformance, plan_origin_conformance
|
|
107
|
+
|
|
108
|
+
if args.apply:
|
|
109
|
+
return apply_origin_conformance(
|
|
110
|
+
args.path,
|
|
111
|
+
kinds=args.kinds,
|
|
112
|
+
include_claims=args.include_claims,
|
|
113
|
+
include_evidence=args.include_evidence,
|
|
114
|
+
overwrite=args.overwrite,
|
|
115
|
+
report_output=args.report_output,
|
|
116
|
+
)
|
|
117
|
+
return plan_origin_conformance(
|
|
118
|
+
args.path,
|
|
119
|
+
kinds=args.kinds,
|
|
120
|
+
include_claims=args.include_claims,
|
|
121
|
+
include_evidence=args.include_evidence,
|
|
122
|
+
)
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import argparse
|
|
4
4
|
|
|
5
|
+
from ssot_contracts.generated.python.enums import ASSURANCE_ORIGINS
|
|
5
6
|
from ssot_registry.api import (
|
|
6
7
|
create_entity,
|
|
7
8
|
delete_entity,
|
|
@@ -12,7 +13,7 @@ from ssot_registry.api import (
|
|
|
12
13
|
update_entity,
|
|
13
14
|
verify_evidence_rows,
|
|
14
15
|
)
|
|
15
|
-
from ssot_cli.common import add_ids_argument, add_path_argument, collect_list_fields, compact_dict, load_text_argument
|
|
16
|
+
from ssot_cli.common import add_ids_argument, add_origin_argument, add_path_argument, collect_list_fields, compact_dict, load_text_argument
|
|
16
17
|
|
|
17
18
|
|
|
18
19
|
_LINK_MAPPING = {
|
|
@@ -38,6 +39,7 @@ def register_evidence(subparsers: argparse._SubParsersAction) -> None:
|
|
|
38
39
|
create.add_argument("--tier", choices=["T0", "T1", "T2", "T3", "T4"], default="T0", help="Assurance tier the evidence contributes toward.")
|
|
39
40
|
create.add_argument("--body", default=None, help="Optional longer-form narrative for the evidence row.")
|
|
40
41
|
create.add_argument("--body-file", default=None, help="Path to a UTF-8 text file containing the evidence body.")
|
|
42
|
+
add_origin_argument(create, choices=sorted(ASSURANCE_ORIGINS), default="repo-local")
|
|
41
43
|
create.add_argument("--evidence-path", dest="evidence_path", required=True, help="Repository-relative location of the evidence artifact.")
|
|
42
44
|
create.add_argument("--claim-ids", nargs="*", default=[], help="Claim ids supported by the evidence.")
|
|
43
45
|
create.add_argument("--test-ids", nargs="*", default=[], help="Test ids associated with the evidence.")
|
|
@@ -51,6 +53,7 @@ def register_evidence(subparsers: argparse._SubParsersAction) -> None:
|
|
|
51
53
|
list_cmd = evidence_sub.add_parser("list", help="List evidence rows.", description="List evidence artifacts currently known to the registry.")
|
|
52
54
|
add_path_argument(list_cmd)
|
|
53
55
|
add_ids_argument(list_cmd, help_text="Evidence ids to include in the list output.")
|
|
56
|
+
add_origin_argument(list_cmd, choices=sorted(ASSURANCE_ORIGINS), default=None)
|
|
54
57
|
list_cmd.set_defaults(func=run_list)
|
|
55
58
|
|
|
56
59
|
update = evidence_sub.add_parser("update", help="Edit evidence metadata.", description="Update mutable evidence fields without changing its link graph.")
|
|
@@ -62,6 +65,7 @@ def register_evidence(subparsers: argparse._SubParsersAction) -> None:
|
|
|
62
65
|
update.add_argument("--tier", choices=["T0", "T1", "T2", "T3", "T4"], default=None, help="Updated assurance tier contribution.")
|
|
63
66
|
update.add_argument("--body", default=None, help="Replacement longer-form evidence narrative.")
|
|
64
67
|
update.add_argument("--body-file", default=None, help="Path to a UTF-8 text file containing the replacement evidence body.")
|
|
68
|
+
add_origin_argument(update, choices=sorted(ASSURANCE_ORIGINS), default=None)
|
|
65
69
|
update.add_argument("--evidence-path", dest="evidence_path", default=None, help="Updated repository-relative path to the artifact.")
|
|
66
70
|
update.set_defaults(func=run_update)
|
|
67
71
|
|
|
@@ -106,6 +110,7 @@ def run_create(args: argparse.Namespace) -> dict[str, object]:
|
|
|
106
110
|
"kind": args.kind,
|
|
107
111
|
"tier": args.tier,
|
|
108
112
|
"body": body,
|
|
113
|
+
"origin": args.origin,
|
|
109
114
|
"path": args.evidence_path,
|
|
110
115
|
"claim_ids": args.claim_ids,
|
|
111
116
|
"test_ids": args.test_ids,
|
|
@@ -118,7 +123,7 @@ def run_get(args: argparse.Namespace) -> dict[str, object]:
|
|
|
118
123
|
|
|
119
124
|
|
|
120
125
|
def run_list(args: argparse.Namespace) -> dict[str, object]:
|
|
121
|
-
return list_entities(args.path, "evidence", ids=args.ids)
|
|
126
|
+
return list_entities(args.path, "evidence", ids=args.ids, origin=args.origin)
|
|
122
127
|
|
|
123
128
|
|
|
124
129
|
def run_update(args: argparse.Namespace) -> dict[str, object]:
|
|
@@ -130,6 +135,7 @@ def run_update(args: argparse.Namespace) -> dict[str, object]:
|
|
|
130
135
|
"kind": args.kind,
|
|
131
136
|
"tier": args.tier,
|
|
132
137
|
"body": body,
|
|
138
|
+
"origin": args.origin,
|
|
133
139
|
"path": args.evidence_path,
|
|
134
140
|
}
|
|
135
141
|
)
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import argparse
|
|
4
4
|
|
|
5
5
|
from ssot_contracts.generated.python.enums import (
|
|
6
|
+
ASSURANCE_ORIGINS,
|
|
6
7
|
CLAIM_TIERS,
|
|
7
8
|
FEATURE_IMPLEMENTATION_STATUSES,
|
|
8
9
|
FEATURE_LIFECYCLE_STAGES,
|
|
@@ -20,7 +21,7 @@ from ssot_registry.api import (
|
|
|
20
21
|
unlink_entities,
|
|
21
22
|
update_entity,
|
|
22
23
|
)
|
|
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
|
+
from ssot_cli.common import add_ids_argument, add_optional_bool_argument, add_origin_argument, add_path_argument, collect_list_fields, compact_dict, load_text_argument
|
|
24
25
|
|
|
25
26
|
|
|
26
27
|
_LINK_MAPPING = {
|
|
@@ -50,6 +51,7 @@ def register_feature(subparsers: argparse._SubParsersAction) -> None:
|
|
|
50
51
|
create.add_argument("--description", default="", help="Operator-facing summary of the feature's purpose.")
|
|
51
52
|
create.add_argument("--body", default=None, help="Optional longer-form narrative for the feature.")
|
|
52
53
|
create.add_argument("--body-file", default=None, help="Path to a UTF-8 text file containing the feature body.")
|
|
54
|
+
add_origin_argument(create, choices=sorted(ASSURANCE_ORIGINS), default="repo-local")
|
|
53
55
|
create.add_argument("--implementation-status", choices=sorted(FEATURE_IMPLEMENTATION_STATUSES), default="absent", help="Current implementation state in the codebase.")
|
|
54
56
|
create.add_argument("--lifecycle-stage", choices=sorted(FEATURE_LIFECYCLE_STAGES), default="active", help="Actual lifecycle state of the feature today.")
|
|
55
57
|
create.add_argument("--replacement-feature-id", nargs="*", default=[], help="Replacement feature ids if this feature is being deprecated or removed.")
|
|
@@ -73,6 +75,7 @@ def register_feature(subparsers: argparse._SubParsersAction) -> None:
|
|
|
73
75
|
list_cmd = feature_sub.add_parser("list", help="List features.", description="List feature records currently known to the registry.")
|
|
74
76
|
add_path_argument(list_cmd)
|
|
75
77
|
add_ids_argument(list_cmd, help_text="Feature ids to include in the list output.")
|
|
78
|
+
add_origin_argument(list_cmd, choices=sorted(ASSURANCE_ORIGINS), default=None)
|
|
76
79
|
list_cmd.set_defaults(func=run_list)
|
|
77
80
|
|
|
78
81
|
update = feature_sub.add_parser("update", help="Edit feature metadata.", description="Update mutable feature fields without changing links or planning state.")
|
|
@@ -82,6 +85,7 @@ def register_feature(subparsers: argparse._SubParsersAction) -> None:
|
|
|
82
85
|
update.add_argument("--description", default=None, help="Replacement feature description.")
|
|
83
86
|
update.add_argument("--body", default=None, help="Replacement longer-form feature narrative.")
|
|
84
87
|
update.add_argument("--body-file", default=None, help="Path to a UTF-8 text file containing the replacement feature body.")
|
|
88
|
+
add_origin_argument(update, choices=sorted(ASSURANCE_ORIGINS), default=None)
|
|
85
89
|
update.add_argument("--implementation-status", choices=sorted(FEATURE_IMPLEMENTATION_STATUSES), default=None, help="Updated implementation state in the codebase.")
|
|
86
90
|
update.set_defaults(func=run_update)
|
|
87
91
|
|
|
@@ -168,6 +172,7 @@ def run_create(args: argparse.Namespace) -> dict[str, object]:
|
|
|
168
172
|
"title": args.title,
|
|
169
173
|
"description": args.description,
|
|
170
174
|
"body": body,
|
|
175
|
+
"origin": args.origin,
|
|
171
176
|
"implementation_status": args.implementation_status,
|
|
172
177
|
"lifecycle": {
|
|
173
178
|
"stage": args.lifecycle_stage,
|
|
@@ -188,7 +193,7 @@ def run_get(args: argparse.Namespace) -> dict[str, object]:
|
|
|
188
193
|
|
|
189
194
|
|
|
190
195
|
def run_list(args: argparse.Namespace) -> dict[str, object]:
|
|
191
|
-
return list_entities(args.path, "features", ids=args.ids)
|
|
196
|
+
return list_entities(args.path, "features", ids=args.ids, origin=args.origin)
|
|
192
197
|
|
|
193
198
|
|
|
194
199
|
def run_update(args: argparse.Namespace) -> dict[str, object]:
|
|
@@ -198,6 +203,7 @@ def run_update(args: argparse.Namespace) -> dict[str, object]:
|
|
|
198
203
|
"title": args.title,
|
|
199
204
|
"description": args.description,
|
|
200
205
|
"body": body,
|
|
206
|
+
"origin": args.origin,
|
|
201
207
|
"implementation_status": args.implementation_status,
|
|
202
208
|
}
|
|
203
209
|
)
|
|
@@ -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
|
|
|
@@ -13,11 +15,13 @@ from .adr_cmd import register_adr
|
|
|
13
15
|
from .boundary_cmd import register_boundary
|
|
14
16
|
from .claim_cmd import register_claim
|
|
15
17
|
from .conformance_cmd import register_conformance
|
|
18
|
+
from .config_cmd import register_config
|
|
16
19
|
from .evidence_cmd import register_evidence
|
|
17
20
|
from .feature_cmd import register_feature
|
|
18
21
|
from .graph_cmd import register_graph
|
|
19
22
|
from .init_cmd import register_init
|
|
20
23
|
from .issue_cmd import register_issue
|
|
24
|
+
from .pack_cmd import register_pack
|
|
21
25
|
from .profile_cmd import register_profile
|
|
22
26
|
from .registry_cmd import register_registry
|
|
23
27
|
from .release_cmd import register_release
|
|
@@ -27,16 +31,51 @@ from .test_cmd import register_test
|
|
|
27
31
|
from .upgrade_cmd import register_upgrade
|
|
28
32
|
from .validate_cmd import register_validate
|
|
29
33
|
|
|
34
|
+
_PACKAGE_NAME = "ssot-cli"
|
|
35
|
+
_PYPROJECT_PATH = Path(__file__).resolve().parents[2] / "pyproject.toml"
|
|
36
|
+
_VERSION_PATTERN = re.compile(r'^version\s*=\s*"(?P<version>[^"]+)"\s*$')
|
|
37
|
+
|
|
30
38
|
|
|
31
39
|
def _default_prog() -> str:
|
|
32
40
|
executable = Path(sys.argv[0]).name
|
|
33
|
-
|
|
34
|
-
|
|
41
|
+
for suffix in (".exe", ".py"):
|
|
42
|
+
if executable.endswith(suffix):
|
|
43
|
+
executable = executable[: -len(suffix)]
|
|
44
|
+
break
|
|
35
45
|
if executable in {"", "__main__", "-m"}:
|
|
36
46
|
return "ssot-registry"
|
|
37
47
|
return executable
|
|
38
48
|
|
|
39
49
|
|
|
50
|
+
def _read_version_from_pyproject(pyproject_path: Path = _PYPROJECT_PATH) -> str:
|
|
51
|
+
in_project_section = False
|
|
52
|
+
|
|
53
|
+
for line in pyproject_path.read_text(encoding="utf-8").splitlines():
|
|
54
|
+
stripped = line.strip()
|
|
55
|
+
|
|
56
|
+
if stripped.startswith("[") and stripped.endswith("]"):
|
|
57
|
+
in_project_section = stripped == "[project]"
|
|
58
|
+
continue
|
|
59
|
+
|
|
60
|
+
if not in_project_section:
|
|
61
|
+
continue
|
|
62
|
+
|
|
63
|
+
match = _VERSION_PATTERN.match(stripped)
|
|
64
|
+
if match is not None:
|
|
65
|
+
return match.group("version")
|
|
66
|
+
|
|
67
|
+
raise RuntimeError(f"Unable to locate [project].version in {pyproject_path}")
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def _cli_version() -> str:
|
|
71
|
+
if _PYPROJECT_PATH.exists():
|
|
72
|
+
return _read_version_from_pyproject()
|
|
73
|
+
try:
|
|
74
|
+
return package_version(_PACKAGE_NAME)
|
|
75
|
+
except PackageNotFoundError:
|
|
76
|
+
return _read_version_from_pyproject()
|
|
77
|
+
|
|
78
|
+
|
|
40
79
|
def build_parser(*, prog: str | None = None) -> argparse.ArgumentParser:
|
|
41
80
|
parser = argparse.ArgumentParser(
|
|
42
81
|
prog=prog or _default_prog(),
|
|
@@ -46,6 +85,12 @@ def build_parser(*, prog: str | None = None) -> argparse.ArgumentParser:
|
|
|
46
85
|
"implementation features, verification artifacts, and publication-ready releases."
|
|
47
86
|
),
|
|
48
87
|
)
|
|
88
|
+
parser.add_argument(
|
|
89
|
+
"--version",
|
|
90
|
+
action="version",
|
|
91
|
+
version=f"%(prog)s {_cli_version()}",
|
|
92
|
+
help="Print the installed CLI package version and exit.",
|
|
93
|
+
)
|
|
49
94
|
parser.add_argument(
|
|
50
95
|
"--output-format",
|
|
51
96
|
default="json",
|
|
@@ -62,12 +107,14 @@ def build_parser(*, prog: str | None = None) -> argparse.ArgumentParser:
|
|
|
62
107
|
register_init(subparsers)
|
|
63
108
|
register_validate(subparsers)
|
|
64
109
|
register_upgrade(subparsers)
|
|
110
|
+
register_config(subparsers)
|
|
65
111
|
register_adr(subparsers)
|
|
66
112
|
register_spec(subparsers)
|
|
67
113
|
register_feature(subparsers)
|
|
68
114
|
register_profile(subparsers)
|
|
69
115
|
register_test(subparsers)
|
|
70
116
|
register_issue(subparsers)
|
|
117
|
+
register_pack(subparsers)
|
|
71
118
|
register_claim(subparsers)
|
|
72
119
|
register_conformance(subparsers)
|
|
73
120
|
register_evidence(subparsers)
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
|
|
5
|
+
from ssot_registry.api import inspect_pack, preflight_pack, sync_pack
|
|
6
|
+
|
|
7
|
+
from .common import add_path_argument
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def register_pack(subparsers: argparse._SubParsersAction) -> None:
|
|
11
|
+
pack = subparsers.add_parser(
|
|
12
|
+
"pack",
|
|
13
|
+
help="Inspect, preflight, and sync governance packs.",
|
|
14
|
+
description="Operate on self-describing SSOT governance packs that expose the shared pack contract.",
|
|
15
|
+
)
|
|
16
|
+
pack_sub = pack.add_subparsers(dest="pack_command", required=True)
|
|
17
|
+
|
|
18
|
+
inspect = pack_sub.add_parser("inspect", help="Inspect packaged governance-pack metadata and manifests.")
|
|
19
|
+
inspect.add_argument("package", help="Import package name for the governance pack.")
|
|
20
|
+
inspect.add_argument("--manifest", action="store_true", help="Include the full packaged manifest in the response.")
|
|
21
|
+
inspect.set_defaults(func=run_inspect)
|
|
22
|
+
|
|
23
|
+
preflight = pack_sub.add_parser("preflight", help="Validate a governance pack before repository mutation.")
|
|
24
|
+
add_path_argument(preflight)
|
|
25
|
+
preflight.add_argument("package", help="Import package name for the governance pack.")
|
|
26
|
+
preflight.add_argument("--kind", choices=["adr", "adrs", "spec", "specs"], default=None)
|
|
27
|
+
preflight.add_argument("--all", action="store_true", help="Check all document kinds declared by the pack.")
|
|
28
|
+
preflight.add_argument("--manifest", action="store_true", help="Include the full packaged manifest in the response.")
|
|
29
|
+
preflight.add_argument("--pin", default=None, help="Require the pack version to match this exact value.")
|
|
30
|
+
preflight.add_argument("--resolved", action="store_true", help="Include resolved manifest document entries in the response.")
|
|
31
|
+
preflight.add_argument("--trusted-only", action="store_true", help="Require the pack to be trusted by default.")
|
|
32
|
+
preflight.set_defaults(func=run_preflight)
|
|
33
|
+
|
|
34
|
+
sync = pack_sub.add_parser("sync", help="Sync declared governance-pack documents into a repository.")
|
|
35
|
+
add_path_argument(sync)
|
|
36
|
+
sync.add_argument("package", help="Import package name for the governance pack.")
|
|
37
|
+
sync.add_argument("--kind", choices=["adr", "adrs", "spec", "specs"], default=None)
|
|
38
|
+
sync.add_argument("--all", action="store_true", help="Sync all document kinds declared by the pack.")
|
|
39
|
+
sync.add_argument("--trusted-only", action="store_true", help="Require the pack to be trusted by default.")
|
|
40
|
+
sync.add_argument("--trust", action="store_true", help="Record explicit operator approval for syncing the selected pack.")
|
|
41
|
+
sync.add_argument("--dry-run", action="store_true", help="Report sync changes without writing files or registry rows.")
|
|
42
|
+
sync.add_argument("--manifest", action="store_true", help="Include the full packaged manifest in the response.")
|
|
43
|
+
sync.add_argument("--no-sync", action="store_true", help="Run preflight and return without writing files or registry rows.")
|
|
44
|
+
sync.add_argument("--pin", default=None, help="Require the pack version to match this exact value.")
|
|
45
|
+
sync.add_argument("--preflight-only", action="store_true", help="Run only preflight checks through the sync command surface.")
|
|
46
|
+
sync.add_argument("--prune-stale", action="store_true", help="Remove stale extension-pack rows for this pack after successful sync.")
|
|
47
|
+
sync.add_argument("--reservations", action="store_true", help="Include reservation changes in the response.")
|
|
48
|
+
sync.add_argument("--resolved", action="store_true", help="Include resolved manifest document entries in the response.")
|
|
49
|
+
sync.add_argument("--yes", action="store_true", help="Acknowledge noninteractive operator approval for the requested sync.")
|
|
50
|
+
sync.set_defaults(func=run_sync)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def run_inspect(args: argparse.Namespace) -> dict[str, object]:
|
|
54
|
+
payload = inspect_pack(args.package)
|
|
55
|
+
if not args.manifest:
|
|
56
|
+
payload.pop("documents", None)
|
|
57
|
+
return payload
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def run_preflight(args: argparse.Namespace) -> dict[str, object]:
|
|
61
|
+
if args.all and args.kind is not None:
|
|
62
|
+
raise ValueError("--all cannot be combined with --kind")
|
|
63
|
+
return preflight_pack(
|
|
64
|
+
args.path,
|
|
65
|
+
args.package,
|
|
66
|
+
kind=None if args.all else args.kind,
|
|
67
|
+
trusted_only=args.trusted_only,
|
|
68
|
+
pin=args.pin,
|
|
69
|
+
include_manifest=args.manifest,
|
|
70
|
+
include_resolved=args.resolved,
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def run_sync(args: argparse.Namespace) -> dict[str, object]:
|
|
75
|
+
if args.all and args.kind is not None:
|
|
76
|
+
raise ValueError("--all cannot be combined with --kind")
|
|
77
|
+
return sync_pack(
|
|
78
|
+
args.path,
|
|
79
|
+
args.package,
|
|
80
|
+
kind=None if args.all else args.kind,
|
|
81
|
+
trusted_only=args.trusted_only,
|
|
82
|
+
dry_run=args.dry_run,
|
|
83
|
+
pin=args.pin,
|
|
84
|
+
preflight_only=args.preflight_only,
|
|
85
|
+
no_sync=args.no_sync,
|
|
86
|
+
prune_stale=args.prune_stale,
|
|
87
|
+
include_manifest=args.manifest,
|
|
88
|
+
include_resolved=args.resolved,
|
|
89
|
+
include_reservations=args.reservations,
|
|
90
|
+
trust=args.trust,
|
|
91
|
+
yes=args.yes,
|
|
92
|
+
)
|
|
@@ -2,7 +2,7 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import argparse
|
|
4
4
|
|
|
5
|
-
from ssot_registry.api import export_registry, sync_automated_statuses
|
|
5
|
+
from ssot_registry.api import export_registry, repair_document_hashes, sync_automated_statuses
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
def register_registry(subparsers: argparse._SubParsersAction) -> None:
|
|
@@ -32,6 +32,18 @@ def register_registry(subparsers: argparse._SubParsersAction) -> None:
|
|
|
32
32
|
sync_statuses.add_argument("--dry-run", action="store_true", help="Report proposed status changes without saving them.")
|
|
33
33
|
sync_statuses.set_defaults(func=run_sync_statuses)
|
|
34
34
|
|
|
35
|
+
repair_doc_hashes = registry_sub.add_parser(
|
|
36
|
+
"repair-doc-hashes",
|
|
37
|
+
help="Refresh mutable repo-local ADR/SPEC content hashes.",
|
|
38
|
+
description=(
|
|
39
|
+
"Repair explicitly selected repo-local ADR and SPEC content_sha256 values after validating each "
|
|
40
|
+
"document at its registered path, then run full registry validation before saving."
|
|
41
|
+
),
|
|
42
|
+
)
|
|
43
|
+
repair_doc_hashes.add_argument("path", nargs="?", default=".", help="Repository root or registry file to repair.")
|
|
44
|
+
repair_doc_hashes.add_argument("--ids", nargs="+", required=True, help="ADR and SPEC ids whose document hashes should be repaired.")
|
|
45
|
+
repair_doc_hashes.set_defaults(func=run_repair_doc_hashes)
|
|
46
|
+
|
|
35
47
|
|
|
36
48
|
def run_export(args: argparse.Namespace) -> dict[str, object]:
|
|
37
49
|
return export_registry(path=args.path, output_format=args.format, output=args.output)
|
|
@@ -39,3 +51,7 @@ def run_export(args: argparse.Namespace) -> dict[str, object]:
|
|
|
39
51
|
|
|
40
52
|
def run_sync_statuses(args: argparse.Namespace) -> dict[str, object]:
|
|
41
53
|
return sync_automated_statuses(path=args.path, dry_run=args.dry_run)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def run_repair_doc_hashes(args: argparse.Namespace) -> dict[str, object]:
|
|
57
|
+
return repair_document_hashes(path=args.path, ids=args.ids)
|
|
@@ -18,6 +18,7 @@ from ssot_registry.api import (
|
|
|
18
18
|
remove_release_evidence,
|
|
19
19
|
revoke_release,
|
|
20
20
|
update_entity,
|
|
21
|
+
verify_local_release,
|
|
21
22
|
)
|
|
22
23
|
from ssot_cli.common import add_ids_argument, add_path_argument, compact_dict, load_text_argument
|
|
23
24
|
|
|
@@ -121,6 +122,18 @@ def register_release(subparsers: argparse._SubParsersAction) -> None:
|
|
|
121
122
|
publish.add_argument("--release-id", default=None, help="Release id to publish. Omit to use the active release.")
|
|
122
123
|
publish.set_defaults(func=run_publish)
|
|
123
124
|
|
|
125
|
+
verify_local = release_sub.add_parser(
|
|
126
|
+
"verify-local",
|
|
127
|
+
help="Run local release assurance verification.",
|
|
128
|
+
description="Generate governed source snapshots, artifact manifests, evidence bundles, and a local verification report for a release.",
|
|
129
|
+
)
|
|
130
|
+
add_path_argument(verify_local)
|
|
131
|
+
verify_local.add_argument("--release-id", default=None, help="Release id to verify. Omit to use the active release.")
|
|
132
|
+
verify_local.add_argument("--path-policy", choices=["ssot-only", "declared", "full-repo"], default="ssot-only", help="Source snapshot path policy.")
|
|
133
|
+
verify_local.add_argument("--no-write-artifacts", action="store_true", help="Return the report without writing the verification report artifact.")
|
|
134
|
+
verify_local.add_argument("--blocking", action="store_true", help="Mark the report as intended for blocking release gates.")
|
|
135
|
+
verify_local.set_defaults(func=run_verify_local)
|
|
136
|
+
|
|
124
137
|
revoke = release_sub.add_parser("revoke", help="Revoke a release.", description="Mark a release revoked and record the reason for operators and auditors.")
|
|
125
138
|
add_path_argument(revoke)
|
|
126
139
|
revoke.add_argument("--release-id", required=True, help="Release id to revoke.")
|
|
@@ -214,6 +227,16 @@ def run_publish(args: argparse.Namespace) -> dict[str, object]:
|
|
|
214
227
|
return publish_release(path=args.path, release_id=args.release_id)
|
|
215
228
|
|
|
216
229
|
|
|
230
|
+
def run_verify_local(args: argparse.Namespace) -> dict[str, object]:
|
|
231
|
+
return verify_local_release(
|
|
232
|
+
path=args.path,
|
|
233
|
+
release_id=args.release_id,
|
|
234
|
+
path_policy=args.path_policy,
|
|
235
|
+
write_artifacts=not args.no_write_artifacts,
|
|
236
|
+
blocking=args.blocking,
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
|
|
217
240
|
def run_revoke(args: argparse.Namespace) -> dict[str, object]:
|
|
218
241
|
return revoke_release(path=args.path, release_id=args.release_id, reason=args.reason)
|
|
219
242
|
|
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
import argparse
|
|
4
4
|
|
|
5
|
+
from ssot_contracts.generated.python.enums import ASSURANCE_ORIGINS
|
|
5
6
|
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, load_text_argument
|
|
7
|
+
from ssot_cli.common import add_ids_argument, add_origin_argument, add_path_argument, collect_list_fields, compact_dict, load_json_object_argument, load_text_argument
|
|
7
8
|
|
|
8
9
|
|
|
9
10
|
_LINK_MAPPING = {
|
|
@@ -27,6 +28,7 @@ def register_test(subparsers: argparse._SubParsersAction) -> None:
|
|
|
27
28
|
create.add_argument("--title", required=True, help="Human-readable test title.")
|
|
28
29
|
create.add_argument("--body", default=None, help="Optional longer-form narrative for the test.")
|
|
29
30
|
create.add_argument("--body-file", default=None, help="Path to a UTF-8 text file containing the test body.")
|
|
31
|
+
add_origin_argument(create, choices=sorted(ASSURANCE_ORIGINS), default="repo-local")
|
|
30
32
|
create.add_argument("--status", choices=["planned", "passing", "failing", "blocked", "skipped"], default="planned", help="Current execution or readiness state of the test.")
|
|
31
33
|
create.add_argument("--kind", required=True, help="Operator-defined test category such as unit, integration, or manual.")
|
|
32
34
|
create.add_argument("--test-path", dest="test_path", required=True, help="Repository-relative location of the executable test or test specification.")
|
|
@@ -45,6 +47,7 @@ def register_test(subparsers: argparse._SubParsersAction) -> None:
|
|
|
45
47
|
list_cmd = test_sub.add_parser("list", help="List tests.", description="List test records currently known to the registry.")
|
|
46
48
|
add_path_argument(list_cmd)
|
|
47
49
|
add_ids_argument(list_cmd, help_text="Test ids to include in the list output.")
|
|
50
|
+
add_origin_argument(list_cmd, choices=sorted(ASSURANCE_ORIGINS), default=None)
|
|
48
51
|
list_cmd.set_defaults(func=run_list)
|
|
49
52
|
|
|
50
53
|
update = test_sub.add_parser("update", help="Edit test metadata.", description="Update mutable test fields without changing link relationships.")
|
|
@@ -53,6 +56,7 @@ def register_test(subparsers: argparse._SubParsersAction) -> None:
|
|
|
53
56
|
update.add_argument("--title", default=None, help="Replacement test title.")
|
|
54
57
|
update.add_argument("--body", default=None, help="Replacement longer-form test narrative.")
|
|
55
58
|
update.add_argument("--body-file", default=None, help="Path to a UTF-8 text file containing the replacement test body.")
|
|
59
|
+
add_origin_argument(update, choices=sorted(ASSURANCE_ORIGINS), default=None)
|
|
56
60
|
update.add_argument("--status", choices=["planned", "passing", "failing", "blocked", "skipped"], default=None, help="Updated execution or readiness state.")
|
|
57
61
|
update.add_argument("--kind", default=None, help="Updated test category.")
|
|
58
62
|
update.add_argument("--test-path", dest="test_path", default=None, help="Updated repository-relative path to the test or procedure.")
|
|
@@ -113,6 +117,7 @@ def run_create(args: argparse.Namespace) -> dict[str, object]:
|
|
|
113
117
|
"id": args.id,
|
|
114
118
|
"title": args.title,
|
|
115
119
|
"body": body,
|
|
120
|
+
"origin": args.origin,
|
|
116
121
|
"status": args.status,
|
|
117
122
|
"kind": args.kind,
|
|
118
123
|
"path": args.test_path,
|
|
@@ -129,7 +134,7 @@ def run_get(args: argparse.Namespace) -> dict[str, object]:
|
|
|
129
134
|
|
|
130
135
|
|
|
131
136
|
def run_list(args: argparse.Namespace) -> dict[str, object]:
|
|
132
|
-
return list_entities(args.path, "tests", ids=args.ids)
|
|
137
|
+
return list_entities(args.path, "tests", ids=args.ids, origin=args.origin)
|
|
133
138
|
|
|
134
139
|
|
|
135
140
|
def run_update(args: argparse.Namespace) -> dict[str, object]:
|
|
@@ -143,6 +148,7 @@ def run_update(args: argparse.Namespace) -> dict[str, object]:
|
|
|
143
148
|
{
|
|
144
149
|
"title": args.title,
|
|
145
150
|
"body": body,
|
|
151
|
+
"origin": args.origin,
|
|
146
152
|
"status": args.status,
|
|
147
153
|
"kind": args.kind,
|
|
148
154
|
"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.12
|
|
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
|
|
@@ -19,14 +19,16 @@ Classifier: Programming Language :: Python :: 3.10
|
|
|
19
19
|
Classifier: Programming Language :: Python :: 3.11
|
|
20
20
|
Classifier: Programming Language :: Python :: 3.12
|
|
21
21
|
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
22
23
|
Classifier: Topic :: Software Development :: Documentation
|
|
23
24
|
Classifier: Topic :: Software Development :: Quality Assurance
|
|
24
25
|
Classifier: Topic :: Utilities
|
|
25
|
-
Requires-Python: <3.
|
|
26
|
+
Requires-Python: <3.15,>=3.10
|
|
26
27
|
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.
|
|
28
|
+
Requires-Dist: ssot-contracts<0.3.0,>=0.2.18
|
|
29
|
+
Requires-Dist: ssot-core<0.3.0,>=0.2.18
|
|
30
|
+
Requires-Dist: ssot-conformance<0.3.0,>=0.2.18
|
|
31
|
+
Requires-Dist: ssot-pack-contracts<0.3.0,>=0.2.19
|
|
30
32
|
Requires-Dist: tomli>=2.0.1; python_version < "3.11"
|
|
31
33
|
|
|
32
34
|
<div align="center">
|
|
@@ -39,11 +41,15 @@ Requires-Dist: tomli>=2.0.1; python_version < "3.11"
|
|
|
39
41
|
<a href="https://pypi.org/project/ssot-cli/"><img src="https://img.shields.io/pypi/pyversions/ssot-cli?label=Python" alt="Supported Python versions" /></a>
|
|
40
42
|
<a href="https://pepy.tech/project/ssot-cli"><img src="https://static.pepy.tech/badge/ssot-cli" alt="Downloads" /></a>
|
|
41
43
|
<a href="https://hits.sh/github.com/groupsum/ssot-registry/"><img src="https://hits.sh/github.com/groupsum/ssot-registry.svg?style=flat-square" alt="Repository hits" /></a>
|
|
44
|
+
<!-- ssot-schema-badges:start -->
|
|
45
|
+
<img src="https://img.shields.io/badge/schema_version-0.5.0-blue" alt="schema_version 0.5.0" />
|
|
46
|
+
<img src="https://img.shields.io/badge/migration%20coverage-12%2F12-brightgreen" alt="Migration coverage 12/12" />
|
|
47
|
+
<!-- ssot-schema-badges:end -->
|
|
42
48
|
</div>
|
|
43
49
|
|
|
44
50
|
`ssot-cli` is the primary command-line distribution for SSOT.
|
|
45
51
|
|
|
46
|
-
It installs `ssot`, `ssot-cli`, and `ssot-registry` as equivalent executables over the same parser and runtime. The command surface is implemented here, while domain logic lives in [ssot-core](https://pypi.org/project/ssot-core/), reusable conformance checks come from [ssot-conformance](https://pypi.org/project/ssot-conformance/),
|
|
52
|
+
It installs `ssot`, `ssot-cli`, and `ssot-registry` as equivalent executables over the same parser and runtime. The command surface is implemented here, while domain logic lives in [ssot-core](https://pypi.org/project/ssot-core/), reusable conformance checks come from [ssot-conformance](https://pypi.org/project/ssot-conformance/), shared contract metadata comes from [ssot-contracts](https://pypi.org/project/ssot-contracts/), and governance pack interoperability contracts come from [ssot-pack-contracts](https://pypi.org/project/ssot-pack-contracts/).
|
|
47
53
|
|
|
48
54
|
- GitHub: https://github.com/groupsum/ssot-registry
|
|
49
55
|
|
|
@@ -65,7 +71,9 @@ For local development:
|
|
|
65
71
|
python -m pip install -e pkgs/ssot-cli
|
|
66
72
|
```
|
|
67
73
|
|
|
68
|
-
This package depends on [ssot-core](https://pypi.org/project/ssot-core/), [ssot-conformance](https://pypi.org/project/ssot-conformance/), and [ssot-contracts](https://pypi.org/project/ssot-contracts/), so installing it gives you the full CLI runtime stack.
|
|
74
|
+
This package depends on [ssot-core](https://pypi.org/project/ssot-core/), [ssot-conformance](https://pypi.org/project/ssot-conformance/), [ssot-contracts](https://pypi.org/project/ssot-contracts/), and [ssot-pack-contracts](https://pypi.org/project/ssot-pack-contracts/), so installing it gives you the full CLI runtime stack for registry operations and governance pack contract checks.
|
|
75
|
+
|
|
76
|
+
The CLI tracks the current core release train through compatible `<0.3.0` ranges and uses the current `ssot-pack-contracts` floor. That keeps pack-aware CLI behavior compatible with the latest contract package without forcing unrelated surface packages into core lockstep.
|
|
69
77
|
|
|
70
78
|
## Executable names
|
|
71
79
|
|
|
@@ -121,7 +129,7 @@ ssot registry --help
|
|
|
121
129
|
|
|
122
130
|
## Screenshots
|
|
123
131
|
|
|
124
|
-
Regenerate
|
|
132
|
+
The screenshots below are generated from the current parser help. Regenerate them with `python scripts/generate_cli_screenshots.py`, or regenerate the CLI and TUI assets together with `python scripts/generate_terminal_screenshots.py`.
|
|
125
133
|
|
|
126
134
|

|
|
127
135
|
|
|
@@ -864,7 +872,7 @@ ssot release certify . --release-id rel:0.1.0 --write-report
|
|
|
864
872
|
## Package relationships
|
|
865
873
|
|
|
866
874
|
- Package type: CLI distribution
|
|
867
|
-
- Depends on: [ssot-core](https://pypi.org/project/ssot-core/), [ssot-conformance](https://pypi.org/project/ssot-conformance/), [ssot-contracts](https://pypi.org/project/ssot-contracts/)
|
|
875
|
+
- Depends on: [ssot-core](https://pypi.org/project/ssot-core/), [ssot-conformance](https://pypi.org/project/ssot-conformance/), [ssot-contracts](https://pypi.org/project/ssot-contracts/), [ssot-pack-contracts](https://pypi.org/project/ssot-pack-contracts/)
|
|
868
876
|
- Related packages: [ssot-registry](https://pypi.org/project/ssot-registry/), [ssot-tui](https://pypi.org/project/ssot-tui/), [ssot-views](https://pypi.org/project/ssot-views/), [ssot-codegen](https://pypi.org/project/ssot-codegen/)
|
|
869
877
|
|
|
870
878
|
If you need the command-line interface, this is the package to install.
|
|
@@ -5,6 +5,7 @@ src/ssot_cli/adr_cmd.py
|
|
|
5
5
|
src/ssot_cli/boundary_cmd.py
|
|
6
6
|
src/ssot_cli/claim_cmd.py
|
|
7
7
|
src/ssot_cli/common.py
|
|
8
|
+
src/ssot_cli/config_cmd.py
|
|
8
9
|
src/ssot_cli/conformance_cmd.py
|
|
9
10
|
src/ssot_cli/evidence_cmd.py
|
|
10
11
|
src/ssot_cli/feature_cmd.py
|
|
@@ -12,6 +13,7 @@ src/ssot_cli/graph_cmd.py
|
|
|
12
13
|
src/ssot_cli/init_cmd.py
|
|
13
14
|
src/ssot_cli/issue_cmd.py
|
|
14
15
|
src/ssot_cli/main.py
|
|
16
|
+
src/ssot_cli/pack_cmd.py
|
|
15
17
|
src/ssot_cli/profile_cmd.py
|
|
16
18
|
src/ssot_cli/registry_cmd.py
|
|
17
19
|
src/ssot_cli/release_cmd.py
|
|
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
|