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.
Files changed (110) hide show
  1. {docassert-0.5.0/docassert.egg-info → docassert-0.6.0}/PKG-INFO +6 -3
  2. {docassert-0.5.0 → docassert-0.6.0}/README.md +3 -2
  3. {docassert-0.5.0 → docassert-0.6.0}/docassert/__init__.py +1 -1
  4. {docassert-0.5.0 → docassert-0.6.0}/docassert/cli.py +9 -1
  5. {docassert-0.5.0 → docassert-0.6.0}/docassert/consistency.py +4 -2
  6. {docassert-0.5.0 → docassert-0.6.0}/docassert/profiles.py +1 -1
  7. {docassert-0.5.0 → docassert-0.6.0}/docassert/semantic.py +1 -1
  8. {docassert-0.5.0 → docassert-0.6.0}/docassert/status.py +10 -2
  9. {docassert-0.5.0 → docassert-0.6.0/docassert.egg-info}/PKG-INFO +6 -3
  10. {docassert-0.5.0 → docassert-0.6.0}/docassert.egg-info/SOURCES.txt +1 -0
  11. {docassert-0.5.0 → docassert-0.6.0}/docassert.egg-info/requires.txt +2 -0
  12. {docassert-0.5.0 → docassert-0.6.0}/pyproject.toml +18 -1
  13. docassert-0.6.0/tests/test_badge.py +26 -0
  14. {docassert-0.5.0 → docassert-0.6.0}/LICENSE +0 -0
  15. {docassert-0.5.0 → docassert-0.6.0}/NOTICE +0 -0
  16. {docassert-0.5.0 → docassert-0.6.0}/docassert/__main__.py +0 -0
  17. {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/consistency.yaml +0 -0
  18. {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/criteria/adr.criteria.yaml +0 -0
  19. {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/criteria/benefits-realization.criteria.yaml +0 -0
  20. {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/criteria/brd.criteria.yaml +0 -0
  21. {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/criteria/business-case.criteria.yaml +0 -0
  22. {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/criteria/charter.criteria.yaml +0 -0
  23. {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/criteria/data-migration-plan.criteria.yaml +0 -0
  24. {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/criteria/frnfr.criteria.yaml +0 -0
  25. {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/criteria/hypercare-plan.criteria.yaml +0 -0
  26. {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/criteria/post-implementation-review.criteria.yaml +0 -0
  27. {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/criteria/prd.criteria.yaml +0 -0
  28. {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/criteria/project.criteria.yaml +0 -0
  29. {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/criteria/qa-test-plan.criteria.yaml +0 -0
  30. {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/criteria/raci-stakeholder.criteria.yaml +0 -0
  31. {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/criteria/release-cutover-plan.criteria.yaml +0 -0
  32. {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/criteria/risk-register.criteria.yaml +0 -0
  33. {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/criteria/rollback-plan.criteria.yaml +0 -0
  34. {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/criteria/runbook.criteria.yaml +0 -0
  35. {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/criteria/status-report.criteria.yaml +0 -0
  36. {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/criteria/test-cases.criteria.yaml +0 -0
  37. {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/criteria/user-story.criteria.yaml +0 -0
  38. {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/profiles/agile-delivery.yaml +0 -0
  39. {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/profiles/lean-startup.yaml +0 -0
  40. {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/profiles/regulated-industry.yaml +0 -0
  41. {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/schema/adr.schema.json +0 -0
  42. {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/schema/benefits-realization.schema.json +0 -0
  43. {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/schema/brd.schema.json +0 -0
  44. {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/schema/business-case.schema.json +0 -0
  45. {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/schema/charter.schema.json +0 -0
  46. {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/schema/data-migration-plan.schema.json +0 -0
  47. {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/schema/frnfr.schema.json +0 -0
  48. {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/schema/hypercare-plan.schema.json +0 -0
  49. {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/schema/post-implementation-review.schema.json +0 -0
  50. {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/schema/prd.schema.json +0 -0
  51. {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/schema/project.schema.json +0 -0
  52. {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/schema/qa-test-plan.schema.json +0 -0
  53. {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/schema/raci-stakeholder.schema.json +0 -0
  54. {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/schema/release-cutover-plan.schema.json +0 -0
  55. {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/schema/risk-register.schema.json +0 -0
  56. {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/schema/rollback-plan.schema.json +0 -0
  57. {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/schema/runbook.schema.json +0 -0
  58. {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/schema/status-report.schema.json +0 -0
  59. {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/schema/test-cases.schema.json +0 -0
  60. {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/schema/user-story.schema.json +0 -0
  61. {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/skills/doc-to-pmo/SKILL.md +0 -0
  62. {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/templates/adr.template.md +0 -0
  63. {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/templates/benefits-realization.template.md +0 -0
  64. {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/templates/brd.template.md +0 -0
  65. {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/templates/business-case.template.md +0 -0
  66. {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/templates/charter.template.md +0 -0
  67. {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/templates/data-migration-plan.template.md +0 -0
  68. {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/templates/frnfr.template.md +0 -0
  69. {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/templates/hypercare-plan.template.md +0 -0
  70. {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/templates/post-implementation-review.template.md +0 -0
  71. {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/templates/prd.template.md +0 -0
  72. {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/templates/project.template.md +0 -0
  73. {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/templates/qa-test-plan.template.md +0 -0
  74. {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/templates/raci-stakeholder.template.md +0 -0
  75. {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/templates/release-cutover-plan.template.md +0 -0
  76. {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/templates/risk-register.template.md +0 -0
  77. {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/templates/rollback-plan.template.md +0 -0
  78. {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/templates/runbook.template.md +0 -0
  79. {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/templates/status-report.template.md +0 -0
  80. {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/templates/test-cases.template.md +0 -0
  81. {docassert-0.5.0 → docassert-0.6.0}/docassert/_data/templates/user-story.template.md +0 -0
  82. {docassert-0.5.0 → docassert-0.6.0}/docassert/config.py +0 -0
  83. {docassert-0.5.0 → docassert-0.6.0}/docassert/extract.py +0 -0
  84. {docassert-0.5.0 → docassert-0.6.0}/docassert/graph.py +0 -0
  85. {docassert-0.5.0 → docassert-0.6.0}/docassert/loader.py +0 -0
  86. {docassert-0.5.0 → docassert-0.6.0}/docassert/models.py +0 -0
  87. {docassert-0.5.0 → docassert-0.6.0}/docassert/projects.py +0 -0
  88. {docassert-0.5.0 → docassert-0.6.0}/docassert/report.py +0 -0
  89. {docassert-0.5.0 → docassert-0.6.0}/docassert/rtm.py +0 -0
  90. {docassert-0.5.0 → docassert-0.6.0}/docassert/scaffold.py +0 -0
  91. {docassert-0.5.0 → docassert-0.6.0}/docassert/structural.py +0 -0
  92. {docassert-0.5.0 → docassert-0.6.0}/docassert.egg-info/dependency_links.txt +0 -0
  93. {docassert-0.5.0 → docassert-0.6.0}/docassert.egg-info/entry_points.txt +0 -0
  94. {docassert-0.5.0 → docassert-0.6.0}/docassert.egg-info/top_level.txt +0 -0
  95. {docassert-0.5.0 → docassert-0.6.0}/setup.cfg +0 -0
  96. {docassert-0.5.0 → docassert-0.6.0}/tests/test_config.py +0 -0
  97. {docassert-0.5.0 → docassert-0.6.0}/tests/test_consistency.py +0 -0
  98. {docassert-0.5.0 → docassert-0.6.0}/tests/test_defects.py +0 -0
  99. {docassert-0.5.0 → docassert-0.6.0}/tests/test_extract.py +0 -0
  100. {docassert-0.5.0 → docassert-0.6.0}/tests/test_graph.py +0 -0
  101. {docassert-0.5.0 → docassert-0.6.0}/tests/test_json_report.py +0 -0
  102. {docassert-0.5.0 → docassert-0.6.0}/tests/test_kinds_delivery.py +0 -0
  103. {docassert-0.5.0 → docassert-0.6.0}/tests/test_kinds_governance.py +0 -0
  104. {docassert-0.5.0 → docassert-0.6.0}/tests/test_kinds_operate.py +0 -0
  105. {docassert-0.5.0 → docassert-0.6.0}/tests/test_kinds_reporting.py +0 -0
  106. {docassert-0.5.0 → docassert-0.6.0}/tests/test_profiles.py +0 -0
  107. {docassert-0.5.0 → docassert-0.6.0}/tests/test_projects.py +0 -0
  108. {docassert-0.5.0 → docassert-0.6.0}/tests/test_scaffold.py +0 -0
  109. {docassert-0.5.0 → docassert-0.6.0}/tests/test_status.py +0 -0
  110. {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.5.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 files.
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 files.
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. |
@@ -5,4 +5,4 @@ standard: deterministic structural checks that gate a merge, plus optional
5
5
  AI-graded semantic checks that advise.
6
6
  """
7
7
 
8
- __version__ = "0.5.0"
8
+ __version__ = "0.6.0"
@@ -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, draft_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, draft_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.text for block in message.content
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.5.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 files.
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
@@ -11,4 +11,6 @@ pypdf>=4.0
11
11
 
12
12
  [dev]
13
13
  pytest>=8.0
14
+ pytest-cov>=5.0
14
15
  ruff>=0.6
16
+ mypy>=1.10
@@ -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
File without changes
File without changes
File without changes
File without changes
File without changes