julee 0.1.4__py3-none-any.whl → 0.1.6__py3-none-any.whl
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.
- julee/__init__.py +1 -1
- julee/api/tests/routers/test_assembly_specifications.py +2 -0
- julee/api/tests/routers/test_documents.py +2 -0
- julee/api/tests/routers/test_knowledge_service_configs.py +2 -0
- julee/api/tests/routers/test_knowledge_service_queries.py +2 -0
- julee/api/tests/routers/test_system.py +2 -0
- julee/api/tests/routers/test_workflows.py +2 -0
- julee/api/tests/test_app.py +2 -0
- julee/api/tests/test_dependencies.py +2 -0
- julee/api/tests/test_requests.py +2 -0
- julee/contrib/polling/__init__.py +22 -19
- julee/contrib/polling/apps/__init__.py +17 -0
- julee/contrib/polling/apps/worker/__init__.py +17 -0
- julee/contrib/polling/apps/worker/pipelines.py +288 -0
- julee/contrib/polling/domain/__init__.py +7 -9
- julee/contrib/polling/domain/models/__init__.py +6 -7
- julee/contrib/polling/domain/models/polling_config.py +18 -1
- julee/contrib/polling/domain/services/__init__.py +6 -5
- julee/contrib/polling/domain/services/poller.py +1 -1
- julee/contrib/polling/infrastructure/__init__.py +9 -8
- julee/contrib/polling/infrastructure/services/__init__.py +6 -5
- julee/contrib/polling/infrastructure/services/polling/__init__.py +6 -5
- julee/contrib/polling/infrastructure/services/polling/http/__init__.py +6 -5
- julee/contrib/polling/infrastructure/services/polling/http/http_poller_service.py +5 -2
- julee/contrib/polling/infrastructure/temporal/__init__.py +12 -12
- julee/contrib/polling/infrastructure/temporal/activities.py +1 -1
- julee/contrib/polling/infrastructure/temporal/manager.py +291 -0
- julee/contrib/polling/infrastructure/temporal/proxies.py +1 -1
- julee/contrib/polling/tests/unit/apps/worker/test_pipelines.py +580 -0
- julee/contrib/polling/tests/unit/infrastructure/services/polling/http/test_http_poller_service.py +40 -2
- julee/contrib/polling/tests/unit/infrastructure/temporal/__init__.py +7 -0
- julee/contrib/polling/tests/unit/infrastructure/temporal/test_manager.py +475 -0
- julee/docs/sphinx_hcd/__init__.py +146 -13
- julee/docs/sphinx_hcd/domain/__init__.py +5 -0
- julee/docs/sphinx_hcd/domain/models/__init__.py +32 -0
- julee/docs/sphinx_hcd/domain/models/accelerator.py +152 -0
- julee/docs/sphinx_hcd/domain/models/app.py +151 -0
- julee/docs/sphinx_hcd/domain/models/code_info.py +121 -0
- julee/docs/sphinx_hcd/domain/models/epic.py +79 -0
- julee/docs/sphinx_hcd/domain/models/integration.py +230 -0
- julee/docs/sphinx_hcd/domain/models/journey.py +222 -0
- julee/docs/sphinx_hcd/domain/models/persona.py +106 -0
- julee/docs/sphinx_hcd/domain/models/story.py +128 -0
- julee/docs/sphinx_hcd/domain/repositories/__init__.py +25 -0
- julee/docs/sphinx_hcd/domain/repositories/accelerator.py +98 -0
- julee/docs/sphinx_hcd/domain/repositories/app.py +57 -0
- julee/docs/sphinx_hcd/domain/repositories/base.py +89 -0
- julee/docs/sphinx_hcd/domain/repositories/code_info.py +69 -0
- julee/docs/sphinx_hcd/domain/repositories/epic.py +62 -0
- julee/docs/sphinx_hcd/domain/repositories/integration.py +79 -0
- julee/docs/sphinx_hcd/domain/repositories/journey.py +106 -0
- julee/docs/sphinx_hcd/domain/repositories/story.py +68 -0
- julee/docs/sphinx_hcd/domain/use_cases/__init__.py +64 -0
- julee/docs/sphinx_hcd/domain/use_cases/derive_personas.py +166 -0
- julee/docs/sphinx_hcd/domain/use_cases/resolve_accelerator_references.py +236 -0
- julee/docs/sphinx_hcd/domain/use_cases/resolve_app_references.py +144 -0
- julee/docs/sphinx_hcd/domain/use_cases/resolve_story_references.py +121 -0
- julee/docs/sphinx_hcd/parsers/__init__.py +48 -0
- julee/docs/sphinx_hcd/parsers/ast.py +150 -0
- julee/docs/sphinx_hcd/parsers/gherkin.py +155 -0
- julee/docs/sphinx_hcd/parsers/yaml.py +184 -0
- julee/docs/sphinx_hcd/repositories/__init__.py +4 -0
- julee/docs/sphinx_hcd/repositories/memory/__init__.py +25 -0
- julee/docs/sphinx_hcd/repositories/memory/accelerator.py +86 -0
- julee/docs/sphinx_hcd/repositories/memory/app.py +45 -0
- julee/docs/sphinx_hcd/repositories/memory/base.py +106 -0
- julee/docs/sphinx_hcd/repositories/memory/code_info.py +59 -0
- julee/docs/sphinx_hcd/repositories/memory/epic.py +54 -0
- julee/docs/sphinx_hcd/repositories/memory/integration.py +70 -0
- julee/docs/sphinx_hcd/repositories/memory/journey.py +96 -0
- julee/docs/sphinx_hcd/repositories/memory/story.py +63 -0
- julee/docs/sphinx_hcd/sphinx/__init__.py +28 -0
- julee/docs/sphinx_hcd/sphinx/adapters.py +116 -0
- julee/docs/sphinx_hcd/sphinx/context.py +163 -0
- julee/docs/sphinx_hcd/sphinx/directives/__init__.py +160 -0
- julee/docs/sphinx_hcd/sphinx/directives/accelerator.py +576 -0
- julee/docs/sphinx_hcd/sphinx/directives/app.py +349 -0
- julee/docs/sphinx_hcd/sphinx/directives/base.py +211 -0
- julee/docs/sphinx_hcd/sphinx/directives/epic.py +434 -0
- julee/docs/sphinx_hcd/sphinx/directives/integration.py +220 -0
- julee/docs/sphinx_hcd/sphinx/directives/journey.py +642 -0
- julee/docs/sphinx_hcd/sphinx/directives/persona.py +345 -0
- julee/docs/sphinx_hcd/sphinx/directives/story.py +575 -0
- julee/docs/sphinx_hcd/sphinx/event_handlers/__init__.py +16 -0
- julee/docs/sphinx_hcd/sphinx/event_handlers/builder_inited.py +31 -0
- julee/docs/sphinx_hcd/sphinx/event_handlers/doctree_read.py +27 -0
- julee/docs/sphinx_hcd/sphinx/event_handlers/doctree_resolved.py +43 -0
- julee/docs/sphinx_hcd/sphinx/event_handlers/env_purge_doc.py +42 -0
- julee/docs/sphinx_hcd/sphinx/initialization.py +139 -0
- julee/docs/sphinx_hcd/tests/__init__.py +9 -0
- julee/docs/sphinx_hcd/tests/conftest.py +6 -0
- julee/docs/sphinx_hcd/tests/domain/__init__.py +1 -0
- julee/docs/sphinx_hcd/tests/domain/models/__init__.py +1 -0
- julee/docs/sphinx_hcd/tests/domain/models/test_accelerator.py +266 -0
- julee/docs/sphinx_hcd/tests/domain/models/test_app.py +258 -0
- julee/docs/sphinx_hcd/tests/domain/models/test_code_info.py +231 -0
- julee/docs/sphinx_hcd/tests/domain/models/test_epic.py +163 -0
- julee/docs/sphinx_hcd/tests/domain/models/test_integration.py +327 -0
- julee/docs/sphinx_hcd/tests/domain/models/test_journey.py +249 -0
- julee/docs/sphinx_hcd/tests/domain/models/test_persona.py +172 -0
- julee/docs/sphinx_hcd/tests/domain/models/test_story.py +216 -0
- julee/docs/sphinx_hcd/tests/domain/use_cases/__init__.py +1 -0
- julee/docs/sphinx_hcd/tests/domain/use_cases/test_derive_personas.py +314 -0
- julee/docs/sphinx_hcd/tests/domain/use_cases/test_resolve_accelerator_references.py +476 -0
- julee/docs/sphinx_hcd/tests/domain/use_cases/test_resolve_app_references.py +265 -0
- julee/docs/sphinx_hcd/tests/domain/use_cases/test_resolve_story_references.py +229 -0
- julee/docs/sphinx_hcd/tests/integration/__init__.py +1 -0
- julee/docs/sphinx_hcd/tests/parsers/__init__.py +1 -0
- julee/docs/sphinx_hcd/tests/parsers/test_ast.py +298 -0
- julee/docs/sphinx_hcd/tests/parsers/test_gherkin.py +282 -0
- julee/docs/sphinx_hcd/tests/parsers/test_yaml.py +496 -0
- julee/docs/sphinx_hcd/tests/repositories/__init__.py +1 -0
- julee/docs/sphinx_hcd/tests/repositories/test_accelerator.py +298 -0
- julee/docs/sphinx_hcd/tests/repositories/test_app.py +218 -0
- julee/docs/sphinx_hcd/tests/repositories/test_base.py +151 -0
- julee/docs/sphinx_hcd/tests/repositories/test_code_info.py +253 -0
- julee/docs/sphinx_hcd/tests/repositories/test_epic.py +237 -0
- julee/docs/sphinx_hcd/tests/repositories/test_integration.py +268 -0
- julee/docs/sphinx_hcd/tests/repositories/test_journey.py +294 -0
- julee/docs/sphinx_hcd/tests/repositories/test_story.py +236 -0
- julee/docs/sphinx_hcd/tests/sphinx/__init__.py +1 -0
- julee/docs/sphinx_hcd/tests/sphinx/directives/__init__.py +1 -0
- julee/docs/sphinx_hcd/tests/sphinx/directives/test_base.py +160 -0
- julee/docs/sphinx_hcd/tests/sphinx/test_adapters.py +176 -0
- julee/docs/sphinx_hcd/tests/sphinx/test_context.py +257 -0
- julee/domain/models/assembly/tests/test_assembly.py +2 -0
- julee/domain/models/assembly_specification/tests/test_assembly_specification.py +2 -0
- julee/domain/models/assembly_specification/tests/test_knowledge_service_query.py +2 -0
- julee/domain/models/custom_fields/tests/test_custom_fields.py +2 -0
- julee/domain/models/document/tests/test_document.py +2 -0
- julee/domain/models/policy/tests/test_document_policy_validation.py +2 -0
- julee/domain/models/policy/tests/test_policy.py +2 -0
- julee/domain/use_cases/tests/test_extract_assemble_data.py +2 -0
- julee/domain/use_cases/tests/test_initialize_system_data.py +2 -0
- julee/domain/use_cases/tests/test_validate_document.py +2 -0
- julee/maintenance/release.py +10 -5
- julee/repositories/memory/tests/test_document.py +2 -0
- julee/repositories/memory/tests/test_document_policy_validation.py +2 -0
- julee/repositories/memory/tests/test_policy.py +2 -0
- julee/repositories/minio/tests/test_assembly.py +2 -0
- julee/repositories/minio/tests/test_assembly_specification.py +2 -0
- julee/repositories/minio/tests/test_client_protocol.py +3 -0
- julee/repositories/minio/tests/test_document.py +2 -0
- julee/repositories/minio/tests/test_document_policy_validation.py +2 -0
- julee/repositories/minio/tests/test_knowledge_service_config.py +2 -0
- julee/repositories/minio/tests/test_knowledge_service_query.py +2 -0
- julee/repositories/minio/tests/test_policy.py +2 -0
- julee/services/knowledge_service/anthropic/tests/test_knowledge_service.py +2 -0
- julee/services/knowledge_service/memory/test_knowledge_service.py +2 -0
- julee/services/knowledge_service/test_factory.py +2 -0
- julee/util/tests/test_decorators.py +2 -0
- julee-0.1.6.dist-info/METADATA +104 -0
- julee-0.1.6.dist-info/RECORD +288 -0
- julee/docs/sphinx_hcd/accelerators.py +0 -1175
- julee/docs/sphinx_hcd/apps.py +0 -518
- julee/docs/sphinx_hcd/epics.py +0 -453
- julee/docs/sphinx_hcd/integrations.py +0 -310
- julee/docs/sphinx_hcd/journeys.py +0 -797
- julee/docs/sphinx_hcd/personas.py +0 -457
- julee/docs/sphinx_hcd/stories.py +0 -960
- julee-0.1.4.dist-info/METADATA +0 -197
- julee-0.1.4.dist-info/RECORD +0 -196
- {julee-0.1.4.dist-info → julee-0.1.6.dist-info}/WHEEL +0 -0
- {julee-0.1.4.dist-info → julee-0.1.6.dist-info}/licenses/LICENSE +0 -0
- {julee-0.1.4.dist-info → julee-0.1.6.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,576 @@
|
|
|
1
|
+
"""Accelerator directives for sphinx_hcd.
|
|
2
|
+
|
|
3
|
+
Provides directives for accelerators with code introspection:
|
|
4
|
+
- define-accelerator: Define accelerator with metadata + introspected code
|
|
5
|
+
- accelerator-index: Generate index table grouped by status
|
|
6
|
+
- accelerators-for-app: List accelerators an app exposes
|
|
7
|
+
- dependent-accelerators: List accelerators that depend on an integration
|
|
8
|
+
- accelerator-dependency-diagram: Generate PlantUML component diagram
|
|
9
|
+
- accelerator-status: Show status, milestone, and acceptance info
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import os
|
|
13
|
+
|
|
14
|
+
from docutils import nodes
|
|
15
|
+
from docutils.parsers.rst import directives
|
|
16
|
+
|
|
17
|
+
from ...domain.models.accelerator import Accelerator, IntegrationReference
|
|
18
|
+
from ...domain.use_cases import (
|
|
19
|
+
get_apps_for_accelerator,
|
|
20
|
+
get_code_info_for_accelerator,
|
|
21
|
+
get_fed_by_accelerators,
|
|
22
|
+
get_publish_integrations,
|
|
23
|
+
get_source_integrations,
|
|
24
|
+
)
|
|
25
|
+
from ...utils import (
|
|
26
|
+
parse_integration_options,
|
|
27
|
+
parse_list_option,
|
|
28
|
+
path_to_root,
|
|
29
|
+
)
|
|
30
|
+
from .base import HCDDirective
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class DefineAcceleratorPlaceholder(nodes.General, nodes.Element):
|
|
34
|
+
"""Placeholder for define-accelerator, replaced at doctree-resolved."""
|
|
35
|
+
|
|
36
|
+
pass
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class AcceleratorIndexPlaceholder(nodes.General, nodes.Element):
|
|
40
|
+
"""Placeholder for accelerator-index, replaced at doctree-resolved."""
|
|
41
|
+
|
|
42
|
+
pass
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class AcceleratorsForAppPlaceholder(nodes.General, nodes.Element):
|
|
46
|
+
"""Placeholder for accelerators-for-app, replaced at doctree-resolved."""
|
|
47
|
+
|
|
48
|
+
pass
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class DependentAcceleratorsPlaceholder(nodes.General, nodes.Element):
|
|
52
|
+
"""Placeholder for dependent-accelerators, replaced at doctree-resolved."""
|
|
53
|
+
|
|
54
|
+
pass
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class AcceleratorDependencyDiagramPlaceholder(nodes.General, nodes.Element):
|
|
58
|
+
"""Placeholder for accelerator-dependency-diagram, replaced at doctree-resolved."""
|
|
59
|
+
|
|
60
|
+
pass
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class DefineAcceleratorDirective(HCDDirective):
|
|
64
|
+
"""Define an accelerator with metadata and introspected code.
|
|
65
|
+
|
|
66
|
+
Usage::
|
|
67
|
+
|
|
68
|
+
.. define-accelerator:: vocabulary-catalog
|
|
69
|
+
:status: active
|
|
70
|
+
:milestone: MVP
|
|
71
|
+
:acceptance: All vocab terms published to CDC
|
|
72
|
+
:sources-from: kafka
|
|
73
|
+
:publishes-to: elasticsearch
|
|
74
|
+
:depends-on: document-processor
|
|
75
|
+
:feeds-into: compliance-mapper
|
|
76
|
+
"""
|
|
77
|
+
|
|
78
|
+
required_arguments = 1
|
|
79
|
+
has_content = True
|
|
80
|
+
option_spec = {
|
|
81
|
+
"status": directives.unchanged,
|
|
82
|
+
"milestone": directives.unchanged,
|
|
83
|
+
"acceptance": directives.unchanged,
|
|
84
|
+
"sources-from": directives.unchanged,
|
|
85
|
+
"publishes-to": directives.unchanged,
|
|
86
|
+
"depends-on": directives.unchanged,
|
|
87
|
+
"feeds-into": directives.unchanged,
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
def run(self):
|
|
91
|
+
slug = self.arguments[0]
|
|
92
|
+
docname = self.env.docname
|
|
93
|
+
|
|
94
|
+
# Parse options
|
|
95
|
+
status = self.options.get("status", "").strip()
|
|
96
|
+
milestone = self.options.get("milestone", "").strip() or None
|
|
97
|
+
acceptance = self.options.get("acceptance", "").strip() or None
|
|
98
|
+
sources_from = parse_integration_options(self.options.get("sources-from", ""))
|
|
99
|
+
publishes_to = parse_integration_options(self.options.get("publishes-to", ""))
|
|
100
|
+
depends_on = parse_list_option(self.options.get("depends-on", ""))
|
|
101
|
+
feeds_into = parse_list_option(self.options.get("feeds-into", ""))
|
|
102
|
+
objective = "\n".join(self.content).strip()
|
|
103
|
+
|
|
104
|
+
# Create accelerator entity
|
|
105
|
+
accelerator = Accelerator(
|
|
106
|
+
slug=slug,
|
|
107
|
+
status=status,
|
|
108
|
+
milestone=milestone,
|
|
109
|
+
acceptance=acceptance,
|
|
110
|
+
objective=objective,
|
|
111
|
+
sources_from=[
|
|
112
|
+
IntegrationReference(
|
|
113
|
+
slug=s["slug"], description=s.get("description", "")
|
|
114
|
+
)
|
|
115
|
+
for s in sources_from
|
|
116
|
+
],
|
|
117
|
+
publishes_to=[
|
|
118
|
+
IntegrationReference(
|
|
119
|
+
slug=p["slug"], description=p.get("description", "")
|
|
120
|
+
)
|
|
121
|
+
for p in publishes_to
|
|
122
|
+
],
|
|
123
|
+
depends_on=depends_on,
|
|
124
|
+
feeds_into=feeds_into,
|
|
125
|
+
docname=docname,
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
# Add to repository
|
|
129
|
+
self.hcd_context.accelerator_repo.save(accelerator)
|
|
130
|
+
|
|
131
|
+
# Track documented accelerators
|
|
132
|
+
if not hasattr(self.env, "documented_accelerators"):
|
|
133
|
+
self.env.documented_accelerators = set()
|
|
134
|
+
self.env.documented_accelerators.add(slug)
|
|
135
|
+
|
|
136
|
+
# Return placeholder - rendering in doctree-resolved
|
|
137
|
+
node = DefineAcceleratorPlaceholder()
|
|
138
|
+
node["accelerator_slug"] = slug
|
|
139
|
+
return [node]
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
class AcceleratorIndexDirective(HCDDirective):
|
|
143
|
+
"""Generate index table grouped by status.
|
|
144
|
+
|
|
145
|
+
Usage::
|
|
146
|
+
|
|
147
|
+
.. accelerator-index::
|
|
148
|
+
"""
|
|
149
|
+
|
|
150
|
+
def run(self):
|
|
151
|
+
return [AcceleratorIndexPlaceholder()]
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
class AcceleratorsForAppDirective(HCDDirective):
|
|
155
|
+
"""List accelerators an app exposes.
|
|
156
|
+
|
|
157
|
+
Usage::
|
|
158
|
+
|
|
159
|
+
.. accelerators-for-app:: vocabulary-tool
|
|
160
|
+
"""
|
|
161
|
+
|
|
162
|
+
required_arguments = 1
|
|
163
|
+
|
|
164
|
+
def run(self):
|
|
165
|
+
node = AcceleratorsForAppPlaceholder()
|
|
166
|
+
node["app_slug"] = self.arguments[0]
|
|
167
|
+
return [node]
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
class DependentAcceleratorsDirective(HCDDirective):
|
|
171
|
+
"""List accelerators that depend on or publish to an integration.
|
|
172
|
+
|
|
173
|
+
Usage::
|
|
174
|
+
|
|
175
|
+
.. dependent-accelerators:: kafka
|
|
176
|
+
"""
|
|
177
|
+
|
|
178
|
+
required_arguments = 1
|
|
179
|
+
|
|
180
|
+
def run(self):
|
|
181
|
+
node = DependentAcceleratorsPlaceholder()
|
|
182
|
+
node["integration_slug"] = self.arguments[0]
|
|
183
|
+
return [node]
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
class AcceleratorDependencyDiagramDirective(HCDDirective):
|
|
187
|
+
"""Generate PlantUML component diagram of accelerator dependencies.
|
|
188
|
+
|
|
189
|
+
Usage::
|
|
190
|
+
|
|
191
|
+
.. accelerator-dependency-diagram::
|
|
192
|
+
"""
|
|
193
|
+
|
|
194
|
+
def run(self):
|
|
195
|
+
return [AcceleratorDependencyDiagramPlaceholder()]
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
class AcceleratorStatusDirective(HCDDirective):
|
|
199
|
+
"""Show status, milestone, and acceptance info for an accelerator.
|
|
200
|
+
|
|
201
|
+
Usage::
|
|
202
|
+
|
|
203
|
+
.. accelerator-status:: vocabulary-catalog
|
|
204
|
+
"""
|
|
205
|
+
|
|
206
|
+
required_arguments = 1
|
|
207
|
+
|
|
208
|
+
def run(self):
|
|
209
|
+
slug = self.arguments[0]
|
|
210
|
+
accelerator = self.hcd_context.accelerator_repo.get(slug)
|
|
211
|
+
|
|
212
|
+
if not accelerator:
|
|
213
|
+
return self.empty_result(f"Accelerator '{slug}' not found")
|
|
214
|
+
|
|
215
|
+
result_nodes = []
|
|
216
|
+
|
|
217
|
+
# Status badge
|
|
218
|
+
if accelerator.status:
|
|
219
|
+
status_para = nodes.paragraph()
|
|
220
|
+
status_para += nodes.strong(text="Status: ")
|
|
221
|
+
status_para += nodes.Text(accelerator.status)
|
|
222
|
+
result_nodes.append(status_para)
|
|
223
|
+
|
|
224
|
+
# Milestone
|
|
225
|
+
if accelerator.milestone:
|
|
226
|
+
milestone_para = nodes.paragraph()
|
|
227
|
+
milestone_para += nodes.strong(text="Milestone: ")
|
|
228
|
+
milestone_para += nodes.Text(accelerator.milestone)
|
|
229
|
+
result_nodes.append(milestone_para)
|
|
230
|
+
|
|
231
|
+
# Acceptance criteria
|
|
232
|
+
if accelerator.acceptance:
|
|
233
|
+
acceptance_para = nodes.paragraph()
|
|
234
|
+
acceptance_para += nodes.strong(text="Acceptance: ")
|
|
235
|
+
acceptance_para += nodes.Text(accelerator.acceptance)
|
|
236
|
+
result_nodes.append(acceptance_para)
|
|
237
|
+
|
|
238
|
+
return result_nodes
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
def build_accelerator_content(slug: str, docname: str, hcd_context):
|
|
242
|
+
"""Build content nodes for an accelerator page."""
|
|
243
|
+
from sphinx.addnodes import seealso
|
|
244
|
+
|
|
245
|
+
from ...config import get_config
|
|
246
|
+
|
|
247
|
+
config = get_config()
|
|
248
|
+
prefix = path_to_root(docname)
|
|
249
|
+
|
|
250
|
+
accelerator = hcd_context.accelerator_repo.get(slug)
|
|
251
|
+
if not accelerator:
|
|
252
|
+
para = nodes.paragraph()
|
|
253
|
+
para += nodes.problematic(text=f"Accelerator '{slug}' not found")
|
|
254
|
+
return [para]
|
|
255
|
+
|
|
256
|
+
# Get all entities for cross-references
|
|
257
|
+
all_accelerators = hcd_context.accelerator_repo.list_all()
|
|
258
|
+
all_apps = hcd_context.app_repo.list_all()
|
|
259
|
+
all_integrations = hcd_context.integration_repo.list_all()
|
|
260
|
+
all_code_infos = hcd_context.code_info_repo.list_all()
|
|
261
|
+
|
|
262
|
+
result_nodes = []
|
|
263
|
+
|
|
264
|
+
# Objective/description
|
|
265
|
+
if accelerator.objective:
|
|
266
|
+
obj_para = nodes.paragraph()
|
|
267
|
+
obj_para += nodes.Text(accelerator.objective)
|
|
268
|
+
result_nodes.append(obj_para)
|
|
269
|
+
|
|
270
|
+
# Code info from introspection
|
|
271
|
+
code_info = get_code_info_for_accelerator(accelerator, all_code_infos)
|
|
272
|
+
if code_info:
|
|
273
|
+
if code_info.entities:
|
|
274
|
+
entities_para = nodes.paragraph()
|
|
275
|
+
entities_para += nodes.strong(text="Entities: ")
|
|
276
|
+
entities_para += nodes.Text(", ".join(e.name for e in code_info.entities))
|
|
277
|
+
result_nodes.append(entities_para)
|
|
278
|
+
|
|
279
|
+
if code_info.use_cases:
|
|
280
|
+
uc_para = nodes.paragraph()
|
|
281
|
+
uc_para += nodes.strong(text="Use Cases: ")
|
|
282
|
+
uc_para += nodes.Text(", ".join(uc.name for uc in code_info.use_cases))
|
|
283
|
+
result_nodes.append(uc_para)
|
|
284
|
+
|
|
285
|
+
# Seealso with metadata
|
|
286
|
+
seealso_node = seealso()
|
|
287
|
+
|
|
288
|
+
# Status
|
|
289
|
+
if accelerator.status:
|
|
290
|
+
status_para = nodes.paragraph()
|
|
291
|
+
status_para += nodes.strong(text="Status: ")
|
|
292
|
+
status_para += nodes.Text(accelerator.status)
|
|
293
|
+
seealso_node += status_para
|
|
294
|
+
|
|
295
|
+
# Milestone
|
|
296
|
+
if accelerator.milestone:
|
|
297
|
+
milestone_para = nodes.paragraph()
|
|
298
|
+
milestone_para += nodes.strong(text="Milestone: ")
|
|
299
|
+
milestone_para += nodes.Text(accelerator.milestone)
|
|
300
|
+
seealso_node += milestone_para
|
|
301
|
+
|
|
302
|
+
# Apps
|
|
303
|
+
apps = get_apps_for_accelerator(accelerator, all_apps)
|
|
304
|
+
if apps:
|
|
305
|
+
apps_para = nodes.paragraph()
|
|
306
|
+
apps_para += nodes.strong(text="Apps: ")
|
|
307
|
+
for i, app in enumerate(apps):
|
|
308
|
+
app_path = f"{prefix}{config.get_doc_path('applications')}/{app.slug}.html"
|
|
309
|
+
ref = nodes.reference("", "", refuri=app_path)
|
|
310
|
+
ref += nodes.Text(app.name)
|
|
311
|
+
apps_para += ref
|
|
312
|
+
if i < len(apps) - 1:
|
|
313
|
+
apps_para += nodes.Text(", ")
|
|
314
|
+
seealso_node += apps_para
|
|
315
|
+
|
|
316
|
+
# Sources from (integrations)
|
|
317
|
+
source_integrations = get_source_integrations(accelerator, all_integrations)
|
|
318
|
+
if source_integrations:
|
|
319
|
+
sources_para = nodes.paragraph()
|
|
320
|
+
sources_para += nodes.strong(text="Sources From: ")
|
|
321
|
+
for i, integration in enumerate(source_integrations):
|
|
322
|
+
int_path = (
|
|
323
|
+
f"{prefix}{config.get_doc_path('integrations')}/{integration.slug}.html"
|
|
324
|
+
)
|
|
325
|
+
ref = nodes.reference("", "", refuri=int_path)
|
|
326
|
+
ref += nodes.Text(integration.name)
|
|
327
|
+
sources_para += ref
|
|
328
|
+
if i < len(source_integrations) - 1:
|
|
329
|
+
sources_para += nodes.Text(", ")
|
|
330
|
+
seealso_node += sources_para
|
|
331
|
+
|
|
332
|
+
# Publishes to (integrations)
|
|
333
|
+
publish_integrations = get_publish_integrations(accelerator, all_integrations)
|
|
334
|
+
if publish_integrations:
|
|
335
|
+
publish_para = nodes.paragraph()
|
|
336
|
+
publish_para += nodes.strong(text="Publishes To: ")
|
|
337
|
+
for i, integration in enumerate(publish_integrations):
|
|
338
|
+
int_path = (
|
|
339
|
+
f"{prefix}{config.get_doc_path('integrations')}/{integration.slug}.html"
|
|
340
|
+
)
|
|
341
|
+
ref = nodes.reference("", "", refuri=int_path)
|
|
342
|
+
ref += nodes.Text(integration.name)
|
|
343
|
+
publish_para += ref
|
|
344
|
+
if i < len(publish_integrations) - 1:
|
|
345
|
+
publish_para += nodes.Text(", ")
|
|
346
|
+
seealso_node += publish_para
|
|
347
|
+
|
|
348
|
+
# Depends on (other accelerators)
|
|
349
|
+
if accelerator.depends_on:
|
|
350
|
+
depends_para = nodes.paragraph()
|
|
351
|
+
depends_para += nodes.strong(text="Depends On: ")
|
|
352
|
+
for i, dep_slug in enumerate(accelerator.depends_on):
|
|
353
|
+
accel_path = (
|
|
354
|
+
f"{prefix}{config.get_doc_path('accelerators')}/{dep_slug}.html"
|
|
355
|
+
)
|
|
356
|
+
ref = nodes.reference("", "", refuri=accel_path)
|
|
357
|
+
ref += nodes.Text(dep_slug.replace("-", " ").title())
|
|
358
|
+
depends_para += ref
|
|
359
|
+
if i < len(accelerator.depends_on) - 1:
|
|
360
|
+
depends_para += nodes.Text(", ")
|
|
361
|
+
seealso_node += depends_para
|
|
362
|
+
|
|
363
|
+
# Fed by (accelerators that feed into this one)
|
|
364
|
+
fed_by = get_fed_by_accelerators(accelerator, all_accelerators)
|
|
365
|
+
if fed_by:
|
|
366
|
+
fed_para = nodes.paragraph()
|
|
367
|
+
fed_para += nodes.strong(text="Fed By: ")
|
|
368
|
+
for i, feeder in enumerate(fed_by):
|
|
369
|
+
accel_path = (
|
|
370
|
+
f"{prefix}{config.get_doc_path('accelerators')}/{feeder.slug}.html"
|
|
371
|
+
)
|
|
372
|
+
ref = nodes.reference("", "", refuri=accel_path)
|
|
373
|
+
ref += nodes.Text(feeder.slug.replace("-", " ").title())
|
|
374
|
+
fed_para += ref
|
|
375
|
+
if i < len(fed_by) - 1:
|
|
376
|
+
fed_para += nodes.Text(", ")
|
|
377
|
+
seealso_node += fed_para
|
|
378
|
+
|
|
379
|
+
result_nodes.append(seealso_node)
|
|
380
|
+
return result_nodes
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
def build_accelerator_index(docname: str, hcd_context):
|
|
384
|
+
"""Build accelerator index grouped by status."""
|
|
385
|
+
all_accelerators = hcd_context.accelerator_repo.list_all()
|
|
386
|
+
|
|
387
|
+
if not all_accelerators:
|
|
388
|
+
para = nodes.paragraph()
|
|
389
|
+
para += nodes.emphasis(text="No accelerators defined")
|
|
390
|
+
return [para]
|
|
391
|
+
|
|
392
|
+
# Group by status
|
|
393
|
+
by_status: dict[str, list[Accelerator]] = {}
|
|
394
|
+
for accel in all_accelerators:
|
|
395
|
+
status = accel.status or "unknown"
|
|
396
|
+
by_status.setdefault(status, []).append(accel)
|
|
397
|
+
|
|
398
|
+
result_nodes = []
|
|
399
|
+
|
|
400
|
+
for status in sorted(by_status.keys()):
|
|
401
|
+
accelerators = by_status[status]
|
|
402
|
+
|
|
403
|
+
# Status heading
|
|
404
|
+
heading = nodes.paragraph()
|
|
405
|
+
heading += nodes.strong(text=status.title())
|
|
406
|
+
result_nodes.append(heading)
|
|
407
|
+
|
|
408
|
+
# Accelerator list
|
|
409
|
+
accel_list = nodes.bullet_list()
|
|
410
|
+
|
|
411
|
+
for accel in sorted(accelerators, key=lambda a: a.slug):
|
|
412
|
+
item = nodes.list_item()
|
|
413
|
+
para = nodes.paragraph()
|
|
414
|
+
|
|
415
|
+
# Link to accelerator
|
|
416
|
+
accel_path = f"{accel.slug}.html"
|
|
417
|
+
ref = nodes.reference("", "", refuri=accel_path)
|
|
418
|
+
ref += nodes.Text(accel.slug.replace("-", " ").title())
|
|
419
|
+
para += ref
|
|
420
|
+
|
|
421
|
+
if accel.milestone:
|
|
422
|
+
para += nodes.Text(f" ({accel.milestone})")
|
|
423
|
+
|
|
424
|
+
item += para
|
|
425
|
+
accel_list += item
|
|
426
|
+
|
|
427
|
+
result_nodes.append(accel_list)
|
|
428
|
+
|
|
429
|
+
return result_nodes
|
|
430
|
+
|
|
431
|
+
|
|
432
|
+
def build_accelerators_for_app(app_slug: str, docname: str, hcd_context):
|
|
433
|
+
"""Build list of accelerators for an app."""
|
|
434
|
+
from ...config import get_config
|
|
435
|
+
|
|
436
|
+
config = get_config()
|
|
437
|
+
prefix = path_to_root(docname)
|
|
438
|
+
|
|
439
|
+
app = hcd_context.app_repo.get(app_slug)
|
|
440
|
+
if not app:
|
|
441
|
+
para = nodes.paragraph()
|
|
442
|
+
para += nodes.emphasis(text=f"App '{app_slug}' not found")
|
|
443
|
+
return [para]
|
|
444
|
+
|
|
445
|
+
all_accelerators = hcd_context.accelerator_repo.list_all()
|
|
446
|
+
|
|
447
|
+
# Filter to accelerators this app exposes
|
|
448
|
+
matching = [a for a in all_accelerators if a.slug in (app.accelerators or [])]
|
|
449
|
+
|
|
450
|
+
if not matching:
|
|
451
|
+
para = nodes.paragraph()
|
|
452
|
+
para += nodes.emphasis(text=f"No accelerators for app '{app_slug}'")
|
|
453
|
+
return [para]
|
|
454
|
+
|
|
455
|
+
bullet_list = nodes.bullet_list()
|
|
456
|
+
|
|
457
|
+
for accel in sorted(matching, key=lambda a: a.slug):
|
|
458
|
+
item = nodes.list_item()
|
|
459
|
+
para = nodes.paragraph()
|
|
460
|
+
|
|
461
|
+
accel_path = f"{prefix}{config.get_doc_path('accelerators')}/{accel.slug}.html"
|
|
462
|
+
ref = nodes.reference("", "", refuri=accel_path)
|
|
463
|
+
ref += nodes.Text(accel.slug.replace("-", " ").title())
|
|
464
|
+
para += ref
|
|
465
|
+
|
|
466
|
+
item += para
|
|
467
|
+
bullet_list += item
|
|
468
|
+
|
|
469
|
+
return [bullet_list]
|
|
470
|
+
|
|
471
|
+
|
|
472
|
+
def build_dependency_diagram(docname: str, hcd_context):
|
|
473
|
+
"""Build PlantUML diagram of accelerator dependencies."""
|
|
474
|
+
try:
|
|
475
|
+
from sphinxcontrib.plantuml import plantuml
|
|
476
|
+
except ImportError:
|
|
477
|
+
para = nodes.paragraph()
|
|
478
|
+
para += nodes.emphasis(text="PlantUML extension not available")
|
|
479
|
+
return [para]
|
|
480
|
+
|
|
481
|
+
all_accelerators = hcd_context.accelerator_repo.list_all()
|
|
482
|
+
|
|
483
|
+
if not all_accelerators:
|
|
484
|
+
para = nodes.paragraph()
|
|
485
|
+
para += nodes.emphasis(text="No accelerators defined")
|
|
486
|
+
return [para]
|
|
487
|
+
|
|
488
|
+
lines = [
|
|
489
|
+
"@startuml",
|
|
490
|
+
"skinparam componentStyle rectangle",
|
|
491
|
+
"skinparam defaultTextAlignment center",
|
|
492
|
+
"",
|
|
493
|
+
]
|
|
494
|
+
|
|
495
|
+
accel_slugs = {a.slug for a in all_accelerators}
|
|
496
|
+
|
|
497
|
+
# Declare components
|
|
498
|
+
for accel in sorted(all_accelerators, key=lambda a: a.slug):
|
|
499
|
+
accel_id = accel.slug.replace("-", "_")
|
|
500
|
+
lines.append(
|
|
501
|
+
f'component "{accel.slug.replace("-", " ").title()}" as {accel_id}'
|
|
502
|
+
)
|
|
503
|
+
|
|
504
|
+
lines.append("")
|
|
505
|
+
|
|
506
|
+
# Add dependency arrows
|
|
507
|
+
for accel in sorted(all_accelerators, key=lambda a: a.slug):
|
|
508
|
+
accel_id = accel.slug.replace("-", "_")
|
|
509
|
+
|
|
510
|
+
for dep_slug in accel.depends_on:
|
|
511
|
+
if dep_slug in accel_slugs:
|
|
512
|
+
dep_id = dep_slug.replace("-", "_")
|
|
513
|
+
lines.append(f"{accel_id} --> {dep_id}")
|
|
514
|
+
|
|
515
|
+
for feed_slug in accel.feeds_into:
|
|
516
|
+
if feed_slug in accel_slugs:
|
|
517
|
+
feed_id = feed_slug.replace("-", "_")
|
|
518
|
+
lines.append(f"{accel_id} --> {feed_id} : feeds")
|
|
519
|
+
|
|
520
|
+
lines.append("")
|
|
521
|
+
lines.append("@enduml")
|
|
522
|
+
|
|
523
|
+
puml_source = "\n".join(lines)
|
|
524
|
+
node = plantuml(puml_source)
|
|
525
|
+
node["uml"] = puml_source
|
|
526
|
+
node["incdir"] = os.path.dirname(docname)
|
|
527
|
+
node["filename"] = os.path.basename(docname)
|
|
528
|
+
|
|
529
|
+
return [node]
|
|
530
|
+
|
|
531
|
+
|
|
532
|
+
def clear_accelerator_state(app, env, docname):
|
|
533
|
+
"""Clear accelerator state when a document is re-read."""
|
|
534
|
+
from ..context import get_hcd_context
|
|
535
|
+
|
|
536
|
+
# Clear documented accelerators tracker
|
|
537
|
+
if (
|
|
538
|
+
hasattr(env, "documented_accelerators")
|
|
539
|
+
and docname in env.documented_accelerators
|
|
540
|
+
):
|
|
541
|
+
env.documented_accelerators.discard(docname)
|
|
542
|
+
|
|
543
|
+
# Clear accelerators from this document via repository
|
|
544
|
+
hcd_context = get_hcd_context(app)
|
|
545
|
+
hcd_context.accelerator_repo.run_async(
|
|
546
|
+
hcd_context.accelerator_repo.async_repo.clear_by_docname(docname)
|
|
547
|
+
)
|
|
548
|
+
|
|
549
|
+
|
|
550
|
+
def process_accelerator_placeholders(app, doctree, docname):
|
|
551
|
+
"""Replace accelerator placeholders with rendered content."""
|
|
552
|
+
from ..context import get_hcd_context
|
|
553
|
+
|
|
554
|
+
hcd_context = get_hcd_context(app)
|
|
555
|
+
|
|
556
|
+
# Process define-accelerator placeholders
|
|
557
|
+
for node in doctree.traverse(DefineAcceleratorPlaceholder):
|
|
558
|
+
slug = node["accelerator_slug"]
|
|
559
|
+
content = build_accelerator_content(slug, docname, hcd_context)
|
|
560
|
+
node.replace_self(content)
|
|
561
|
+
|
|
562
|
+
# Process accelerator-index placeholders
|
|
563
|
+
for node in doctree.traverse(AcceleratorIndexPlaceholder):
|
|
564
|
+
content = build_accelerator_index(docname, hcd_context)
|
|
565
|
+
node.replace_self(content)
|
|
566
|
+
|
|
567
|
+
# Process accelerators-for-app placeholders
|
|
568
|
+
for node in doctree.traverse(AcceleratorsForAppPlaceholder):
|
|
569
|
+
app_slug = node["app_slug"]
|
|
570
|
+
content = build_accelerators_for_app(app_slug, docname, hcd_context)
|
|
571
|
+
node.replace_self(content)
|
|
572
|
+
|
|
573
|
+
# Process accelerator-dependency-diagram placeholders
|
|
574
|
+
for node in doctree.traverse(AcceleratorDependencyDiagramPlaceholder):
|
|
575
|
+
content = build_dependency_diagram(docname, hcd_context)
|
|
576
|
+
node.replace_self(content)
|