docassert 0.5.0__tar.gz → 0.6.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {docassert-0.5.0/docassert.egg-info → docassert-0.6.0}/PKG-INFO +6 -3
- {docassert-0.5.0 → docassert-0.6.0}/README.md +3 -2
- {docassert-0.5.0 → docassert-0.6.0}/docassert/__init__.py +1 -1
- {docassert-0.5.0 → docassert-0.6.0}/docassert/cli.py +9 -1
- {docassert-0.5.0 → docassert-0.6.0}/docassert/consistency.py +4 -2
- {docassert-0.5.0 → docassert-0.6.0}/docassert/profiles.py +1 -1
- {docassert-0.5.0 → docassert-0.6.0}/docassert/semantic.py +1 -1
- {docassert-0.5.0 → docassert-0.6.0}/docassert/status.py +10 -2
- {docassert-0.5.0 → docassert-0.6.0/docassert.egg-info}/PKG-INFO +6 -3
- {docassert-0.5.0 → docassert-0.6.0}/docassert.egg-info/SOURCES.txt +1 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert.egg-info/requires.txt +2 -0
- {docassert-0.5.0 → docassert-0.6.0}/pyproject.toml +18 -1
- docassert-0.6.0/tests/test_badge.py +26 -0
- {docassert-0.5.0 → docassert-0.6.0}/LICENSE +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/NOTICE +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/__main__.py +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/consistency.yaml +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/criteria/adr.criteria.yaml +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/criteria/benefits-realization.criteria.yaml +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/criteria/brd.criteria.yaml +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/criteria/business-case.criteria.yaml +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/criteria/charter.criteria.yaml +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/criteria/data-migration-plan.criteria.yaml +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/criteria/frnfr.criteria.yaml +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/criteria/hypercare-plan.criteria.yaml +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/criteria/post-implementation-review.criteria.yaml +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/criteria/prd.criteria.yaml +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/criteria/project.criteria.yaml +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/criteria/qa-test-plan.criteria.yaml +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/criteria/raci-stakeholder.criteria.yaml +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/criteria/release-cutover-plan.criteria.yaml +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/criteria/risk-register.criteria.yaml +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/criteria/rollback-plan.criteria.yaml +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/criteria/runbook.criteria.yaml +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/criteria/status-report.criteria.yaml +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/criteria/test-cases.criteria.yaml +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/criteria/user-story.criteria.yaml +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/profiles/agile-delivery.yaml +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/profiles/lean-startup.yaml +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/profiles/regulated-industry.yaml +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/schema/adr.schema.json +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/schema/benefits-realization.schema.json +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/schema/brd.schema.json +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/schema/business-case.schema.json +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/schema/charter.schema.json +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/schema/data-migration-plan.schema.json +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/schema/frnfr.schema.json +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/schema/hypercare-plan.schema.json +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/schema/post-implementation-review.schema.json +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/schema/prd.schema.json +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/schema/project.schema.json +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/schema/qa-test-plan.schema.json +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/schema/raci-stakeholder.schema.json +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/schema/release-cutover-plan.schema.json +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/schema/risk-register.schema.json +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/schema/rollback-plan.schema.json +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/schema/runbook.schema.json +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/schema/status-report.schema.json +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/schema/test-cases.schema.json +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/schema/user-story.schema.json +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/skills/doc-to-pmo/SKILL.md +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/templates/adr.template.md +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/templates/benefits-realization.template.md +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/templates/brd.template.md +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/templates/business-case.template.md +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/templates/charter.template.md +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/templates/data-migration-plan.template.md +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/templates/frnfr.template.md +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/templates/hypercare-plan.template.md +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/templates/post-implementation-review.template.md +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/templates/prd.template.md +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/templates/project.template.md +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/templates/qa-test-plan.template.md +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/templates/raci-stakeholder.template.md +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/templates/release-cutover-plan.template.md +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/templates/risk-register.template.md +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/templates/rollback-plan.template.md +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/templates/runbook.template.md +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/templates/status-report.template.md +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/templates/test-cases.template.md +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/templates/user-story.template.md +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/config.py +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/extract.py +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/graph.py +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/loader.py +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/models.py +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/projects.py +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/report.py +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/rtm.py +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/scaffold.py +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert/structural.py +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert.egg-info/dependency_links.txt +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert.egg-info/entry_points.txt +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/docassert.egg-info/top_level.txt +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/setup.cfg +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/tests/test_config.py +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/tests/test_consistency.py +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/tests/test_defects.py +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/tests/test_extract.py +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/tests/test_graph.py +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/tests/test_json_report.py +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/tests/test_kinds_delivery.py +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/tests/test_kinds_governance.py +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/tests/test_kinds_operate.py +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/tests/test_kinds_reporting.py +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/tests/test_profiles.py +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/tests/test_projects.py +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/tests/test_scaffold.py +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/tests/test_status.py +0 -0
- {docassert-0.5.0 → docassert-0.6.0}/tests/test_structural.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: docassert
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.0
|
|
4
4
|
Summary: Unit testing for business documents — validate structured Markdown docs against a configurable audit standard.
|
|
5
5
|
Author: C4G Enterprises Inc.
|
|
6
6
|
License: Apache-2.0
|
|
@@ -33,7 +33,9 @@ Requires-Dist: python-docx>=1.1; extra == "convert"
|
|
|
33
33
|
Requires-Dist: pypdf>=4.0; extra == "convert"
|
|
34
34
|
Provides-Extra: dev
|
|
35
35
|
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
36
|
+
Requires-Dist: pytest-cov>=5.0; extra == "dev"
|
|
36
37
|
Requires-Dist: ruff>=0.6; extra == "dev"
|
|
38
|
+
Requires-Dist: mypy>=1.10; extra == "dev"
|
|
37
39
|
Dynamic: license-file
|
|
38
40
|
|
|
39
41
|
# docassert
|
|
@@ -49,7 +51,8 @@ semantic checks that advise. Requirements trace end to end, and project status i
|
|
|
49
51
|
derived from the documents rather than self-reported.
|
|
50
52
|
|
|
51
53
|
docassert is the reference implementation of **[PMO as Code](https://c4g-john.github.io/pmo-as-code/)** —
|
|
52
|
-
a vendor-neutral standard for running a PMO from version-controlled, declarative
|
|
54
|
+
a vendor-neutral standard for running a PMO from version-controlled, declarative
|
|
55
|
+
files. It implements the [PMO as Code specification](https://github.com/c4g-john/pmo-as-code-spec) **v0.1**.
|
|
53
56
|
|
|
54
57
|
## Install
|
|
55
58
|
|
|
@@ -89,7 +92,7 @@ flagged as TODOs, never invented). The skill's source is
|
|
|
89
92
|
| `docassert consistency` | Cross-document checks: referential integrity, coverage, required links, profile completeness. Reports: `--junit` / `--markdown` / `--json`. |
|
|
90
93
|
| `docassert rtm [--project ID]` | Requirements traceability matrix (Markdown or CSV). |
|
|
91
94
|
| `docassert status [--project ID] [--index]` | Derived project status (md / json / html). |
|
|
92
|
-
| `docassert pages --out DIR` | Build the portfolio site (index + a page per project). |
|
|
95
|
+
| `docassert pages --out DIR` | Build the portfolio site (index + a page per project + shields.io badge endpoints `badge.json` / `badges/<ID>.json`). |
|
|
93
96
|
| `docassert projects [--out] [--check]` | Generate / verify the project registry. |
|
|
94
97
|
| `docassert new <kind> --project ID` | Scaffold a document from its template with identity filled in (`new project --code XYZ` auto-numbers the id); suggests the next free item ids. |
|
|
95
98
|
| `docassert init [DIR]` | Scaffold the default config into a repo. |
|
|
@@ -11,7 +11,8 @@ semantic checks that advise. Requirements trace end to end, and project status i
|
|
|
11
11
|
derived from the documents rather than self-reported.
|
|
12
12
|
|
|
13
13
|
docassert is the reference implementation of **[PMO as Code](https://c4g-john.github.io/pmo-as-code/)** —
|
|
14
|
-
a vendor-neutral standard for running a PMO from version-controlled, declarative
|
|
14
|
+
a vendor-neutral standard for running a PMO from version-controlled, declarative
|
|
15
|
+
files. It implements the [PMO as Code specification](https://github.com/c4g-john/pmo-as-code-spec) **v0.1**.
|
|
15
16
|
|
|
16
17
|
## Install
|
|
17
18
|
|
|
@@ -51,7 +52,7 @@ flagged as TODOs, never invented). The skill's source is
|
|
|
51
52
|
| `docassert consistency` | Cross-document checks: referential integrity, coverage, required links, profile completeness. Reports: `--junit` / `--markdown` / `--json`. |
|
|
52
53
|
| `docassert rtm [--project ID]` | Requirements traceability matrix (Markdown or CSV). |
|
|
53
54
|
| `docassert status [--project ID] [--index]` | Derived project status (md / json / html). |
|
|
54
|
-
| `docassert pages --out DIR` | Build the portfolio site (index + a page per project). |
|
|
55
|
+
| `docassert pages --out DIR` | Build the portfolio site (index + a page per project + shields.io badge endpoints `badge.json` / `badges/<ID>.json`). |
|
|
55
56
|
| `docassert projects [--out] [--check]` | Generate / verify the project registry. |
|
|
56
57
|
| `docassert new <kind> --project ID` | Scaffold a document from its template with identity filled in (`new project --code XYZ` auto-numbers the id); suggests the next free item ids. |
|
|
57
58
|
| `docassert init [DIR]` | Scaffold the default config into a repo. |
|
|
@@ -226,13 +226,21 @@ def cmd_pages(args: argparse.Namespace) -> int:
|
|
|
226
226
|
index = status_mod.build_index(docs_dir)
|
|
227
227
|
(out / "index.html").write_text(status_mod.render_index_html(index))
|
|
228
228
|
|
|
229
|
+
# shields.io endpoint badges: one for the portfolio, one per project
|
|
230
|
+
# (https://img.shields.io/endpoint?url=<site>/badge.json)
|
|
231
|
+
(out / "badge.json").write_text(
|
|
232
|
+
status_mod.render_badge_json(index["overall"]["rag"]))
|
|
233
|
+
(out / "badges").mkdir(exist_ok=True)
|
|
234
|
+
|
|
229
235
|
plist = projects_mod.load_projects(docs_dir)
|
|
230
236
|
for p in plist:
|
|
231
237
|
model = status_mod.build_status(docs_dir, project=p["id"])
|
|
232
238
|
(out / f"{p['id']}.html").write_text(status_mod.render_html(model))
|
|
239
|
+
(out / "badges" / f"{p['id']}.json").write_text(
|
|
240
|
+
status_mod.render_badge_json(model["rag"], label=p["code"].lower()))
|
|
233
241
|
|
|
234
242
|
(out / "RTM.md").write_text(rtm.render_markdown(build_graph(docs_dir)))
|
|
235
|
-
print(f"docassert: wrote {out}/ — index + {len(plist)} project page(s) + RTM.md "
|
|
243
|
+
print(f"docassert: wrote {out}/ — index + {len(plist)} project page(s) + badges + RTM.md "
|
|
236
244
|
f"(portfolio: {index['overall']['rag']})")
|
|
237
245
|
return 0
|
|
238
246
|
|
|
@@ -63,7 +63,8 @@ def check_referential_integrity(graph) -> CheckResult:
|
|
|
63
63
|
|
|
64
64
|
def check_required_links(graph, config) -> CheckResult:
|
|
65
65
|
required = config.get("required_links", {})
|
|
66
|
-
approved_orphans
|
|
66
|
+
approved_orphans: list[str] = []
|
|
67
|
+
draft_orphans: list[str] = []
|
|
67
68
|
for item in graph.all_items():
|
|
68
69
|
relation = required.get(item.type)
|
|
69
70
|
if relation and not item.targets(relation):
|
|
@@ -79,7 +80,8 @@ def check_required_links(graph, config) -> CheckResult:
|
|
|
79
80
|
|
|
80
81
|
|
|
81
82
|
def check_coverage(graph, config) -> CheckResult:
|
|
82
|
-
approved_gaps
|
|
83
|
+
approved_gaps: list[str] = []
|
|
84
|
+
draft_gaps: list[str] = []
|
|
83
85
|
for rule in config.get("coverage", []):
|
|
84
86
|
parent_prefix, relation = rule["parent"], rule["relation"]
|
|
85
87
|
by_prefix = rule.get("by_prefix")
|
|
@@ -73,7 +73,7 @@ def completeness(profile: dict, documents: list[dict], project_status: str) -> d
|
|
|
73
73
|
"""
|
|
74
74
|
by_kind: dict[str, list[dict]] = {}
|
|
75
75
|
for d in documents:
|
|
76
|
-
by_kind.setdefault(d.get("kind"), []).append(d)
|
|
76
|
+
by_kind.setdefault(str(d.get("kind") or ""), []).append(d)
|
|
77
77
|
|
|
78
78
|
required = [{"kind": k, "state": _kind_state(k, by_kind)} for k in profile["required"]]
|
|
79
79
|
recommended = [{"kind": k, "state": _kind_state(k, by_kind)} for k in profile["recommended"]]
|
|
@@ -69,7 +69,7 @@ def _grade(prompt: str, content: str, model: str) -> dict:
|
|
|
69
69
|
"content": f"AUDIT CRITERION:\n{prompt}\n\nDOCUMENT:\n{content}",
|
|
70
70
|
}],
|
|
71
71
|
)
|
|
72
|
-
text = "".join(block
|
|
72
|
+
text = "".join(getattr(block, "text", "") for block in message.content
|
|
73
73
|
if getattr(block, "type", None) == "text").strip()
|
|
74
74
|
# tolerate models that wrap JSON in prose or fences
|
|
75
75
|
start, end = text.find("{"), text.rfind("}")
|
|
@@ -128,9 +128,9 @@ def build_status(documents_dir=DOCUMENTS_DIR, project: str | None = None) -> dic
|
|
|
128
128
|
else:
|
|
129
129
|
docs = all_docs
|
|
130
130
|
|
|
131
|
-
id_index = {}
|
|
131
|
+
id_index: dict[str, list[str]] = {}
|
|
132
132
|
for d in all_docs: # uniqueness is always global
|
|
133
|
-
id_index.setdefault(d.id, []).append(d.path)
|
|
133
|
+
id_index.setdefault(d.id or "", []).append(d.path)
|
|
134
134
|
|
|
135
135
|
documents = [{
|
|
136
136
|
"kind": d.kind,
|
|
@@ -460,6 +460,14 @@ def render_html(model) -> str:
|
|
|
460
460
|
|
|
461
461
|
|
|
462
462
|
_RAG_COLOR = {"green": "var(--ok)", "amber": "var(--amber)", "red": "var(--bad)"}
|
|
463
|
+
_BADGE_COLOR = {"green": "brightgreen", "amber": "orange", "red": "red"}
|
|
464
|
+
|
|
465
|
+
|
|
466
|
+
def render_badge_json(rag: str, label: str = "pmo docs") -> str:
|
|
467
|
+
"""A shields.io endpoint payload (https://shields.io/badges/endpoint-badge),
|
|
468
|
+
so a README can carry a live derived-status badge."""
|
|
469
|
+
return json.dumps({"schemaVersion": 1, "label": label,
|
|
470
|
+
"message": rag, "color": _BADGE_COLOR[rag]}) + "\n"
|
|
463
471
|
|
|
464
472
|
|
|
465
473
|
def _index_card(p, esc) -> str:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: docassert
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.0
|
|
4
4
|
Summary: Unit testing for business documents — validate structured Markdown docs against a configurable audit standard.
|
|
5
5
|
Author: C4G Enterprises Inc.
|
|
6
6
|
License: Apache-2.0
|
|
@@ -33,7 +33,9 @@ Requires-Dist: python-docx>=1.1; extra == "convert"
|
|
|
33
33
|
Requires-Dist: pypdf>=4.0; extra == "convert"
|
|
34
34
|
Provides-Extra: dev
|
|
35
35
|
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
36
|
+
Requires-Dist: pytest-cov>=5.0; extra == "dev"
|
|
36
37
|
Requires-Dist: ruff>=0.6; extra == "dev"
|
|
38
|
+
Requires-Dist: mypy>=1.10; extra == "dev"
|
|
37
39
|
Dynamic: license-file
|
|
38
40
|
|
|
39
41
|
# docassert
|
|
@@ -49,7 +51,8 @@ semantic checks that advise. Requirements trace end to end, and project status i
|
|
|
49
51
|
derived from the documents rather than self-reported.
|
|
50
52
|
|
|
51
53
|
docassert is the reference implementation of **[PMO as Code](https://c4g-john.github.io/pmo-as-code/)** —
|
|
52
|
-
a vendor-neutral standard for running a PMO from version-controlled, declarative
|
|
54
|
+
a vendor-neutral standard for running a PMO from version-controlled, declarative
|
|
55
|
+
files. It implements the [PMO as Code specification](https://github.com/c4g-john/pmo-as-code-spec) **v0.1**.
|
|
53
56
|
|
|
54
57
|
## Install
|
|
55
58
|
|
|
@@ -89,7 +92,7 @@ flagged as TODOs, never invented). The skill's source is
|
|
|
89
92
|
| `docassert consistency` | Cross-document checks: referential integrity, coverage, required links, profile completeness. Reports: `--junit` / `--markdown` / `--json`. |
|
|
90
93
|
| `docassert rtm [--project ID]` | Requirements traceability matrix (Markdown or CSV). |
|
|
91
94
|
| `docassert status [--project ID] [--index]` | Derived project status (md / json / html). |
|
|
92
|
-
| `docassert pages --out DIR` | Build the portfolio site (index + a page per project). |
|
|
95
|
+
| `docassert pages --out DIR` | Build the portfolio site (index + a page per project + shields.io badge endpoints `badge.json` / `badges/<ID>.json`). |
|
|
93
96
|
| `docassert projects [--out] [--check]` | Generate / verify the project registry. |
|
|
94
97
|
| `docassert new <kind> --project ID` | Scaffold a document from its template with identity filled in (`new project --code XYZ` auto-numbers the id); suggests the next free item ids. |
|
|
95
98
|
| `docassert init [DIR]` | Scaffold the default config into a repo. |
|
|
@@ -90,6 +90,7 @@ docassert/_data/templates/runbook.template.md
|
|
|
90
90
|
docassert/_data/templates/status-report.template.md
|
|
91
91
|
docassert/_data/templates/test-cases.template.md
|
|
92
92
|
docassert/_data/templates/user-story.template.md
|
|
93
|
+
tests/test_badge.py
|
|
93
94
|
tests/test_config.py
|
|
94
95
|
tests/test_consistency.py
|
|
95
96
|
tests/test_defects.py
|
|
@@ -29,7 +29,7 @@ dependencies = [
|
|
|
29
29
|
[project.optional-dependencies]
|
|
30
30
|
ai = ["anthropic>=0.40"]
|
|
31
31
|
convert = ["python-docx>=1.1", "pypdf>=4.0"] # source extraction for doc-to-pmo
|
|
32
|
-
dev = ["pytest>=8.0", "ruff>=0.6"]
|
|
32
|
+
dev = ["pytest>=8.0", "pytest-cov>=5.0", "ruff>=0.6", "mypy>=1.10"]
|
|
33
33
|
|
|
34
34
|
[project.urls]
|
|
35
35
|
Homepage = "https://docassert.com"
|
|
@@ -69,3 +69,20 @@ target-version = "py310"
|
|
|
69
69
|
select = ["E", "F", "I", "W", "B", "UP"]
|
|
70
70
|
# Long lines are common in the descriptive check messages and sample content.
|
|
71
71
|
ignore = ["E501"]
|
|
72
|
+
|
|
73
|
+
[tool.mypy]
|
|
74
|
+
files = ["docassert"]
|
|
75
|
+
python_version = "3.10"
|
|
76
|
+
warn_unused_ignores = true
|
|
77
|
+
warn_redundant_casts = true
|
|
78
|
+
|
|
79
|
+
[[tool.mypy.overrides]]
|
|
80
|
+
module = ["frontmatter", "docx", "pypdf", "yaml", "jsonschema", "anthropic"]
|
|
81
|
+
ignore_missing_imports = true
|
|
82
|
+
|
|
83
|
+
[tool.coverage.run]
|
|
84
|
+
source = ["docassert"]
|
|
85
|
+
|
|
86
|
+
[tool.coverage.report]
|
|
87
|
+
# Keep the gate honest: fail CI if coverage drops below the floor.
|
|
88
|
+
fail_under = 80
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"""Tests for the shields.io status-badge endpoint output."""
|
|
2
|
+
import json
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
from docassert import status as S
|
|
6
|
+
from docassert.cli import main
|
|
7
|
+
|
|
8
|
+
ROOT = Path(__file__).resolve().parent.parent
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def test_badge_payload_shape_and_colors():
|
|
12
|
+
for rag, color in (("green", "brightgreen"), ("amber", "orange"), ("red", "red")):
|
|
13
|
+
data = json.loads(S.render_badge_json(rag))
|
|
14
|
+
assert data == {"schemaVersion": 1, "label": "pmo docs",
|
|
15
|
+
"message": rag, "color": color}
|
|
16
|
+
assert json.loads(S.render_badge_json("green", label="aur"))["label"] == "aur"
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def test_pages_emits_badges(tmp_path, monkeypatch):
|
|
20
|
+
monkeypatch.chdir(ROOT)
|
|
21
|
+
out = tmp_path / "site"
|
|
22
|
+
assert main(["pages", "--out", str(out)]) == 0
|
|
23
|
+
overall = json.loads((out / "badge.json").read_text())
|
|
24
|
+
assert overall["schemaVersion"] == 1 and overall["message"] in {"green", "amber", "red"}
|
|
25
|
+
aur = json.loads((out / "badges" / "PRJ-001-AUR.json").read_text())
|
|
26
|
+
assert aur["label"] == "aur" and aur["message"] in {"green", "amber", "red"}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{docassert-0.5.0 → docassert-0.6.0}/docassert/_data/criteria/benefits-realization.criteria.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{docassert-0.5.0 → docassert-0.6.0}/docassert/_data/criteria/data-migration-plan.criteria.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{docassert-0.5.0 → docassert-0.6.0}/docassert/_data/criteria/release-cutover-plan.criteria.yaml
RENAMED
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{docassert-0.5.0 → docassert-0.6.0}/docassert/_data/schema/post-implementation-review.schema.json
RENAMED
|
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
|
{docassert-0.5.0 → docassert-0.6.0}/docassert/_data/templates/benefits-realization.template.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{docassert-0.5.0 → docassert-0.6.0}/docassert/_data/templates/data-migration-plan.template.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{docassert-0.5.0 → docassert-0.6.0}/docassert/_data/templates/post-implementation-review.template.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{docassert-0.5.0 → docassert-0.6.0}/docassert/_data/templates/release-cutover-plan.template.md
RENAMED
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|