modwire 3.2.0__tar.gz → 4.0.2__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 (328) hide show
  1. modwire-4.0.2/.github/modwire-ecosystem.yml +171 -0
  2. modwire-4.0.2/.github/scripts/reconcile_ecosystem.py +405 -0
  3. modwire-4.0.2/.github/workflows/ci.yml +30 -0
  4. modwire-4.0.2/.github/workflows/python-package.yml +84 -0
  5. modwire-4.0.2/.github/workflows/python-release-assets.yml +36 -0
  6. modwire-4.0.2/.github/workflows/python-release-build.yml +86 -0
  7. modwire-4.0.2/.github/workflows/release.yml +47 -0
  8. {modwire-3.2.0 → modwire-4.0.2}/.gitignore +1 -0
  9. modwire-4.0.2/.modwire/boundaries.yaml +44 -0
  10. modwire-4.0.2/.modwire/shape.yaml +5 -0
  11. modwire-4.0.2/CHANGELOG.md +102 -0
  12. {modwire-3.2.0 → modwire-4.0.2}/CONTRIBUTING.md +3 -1
  13. modwire-4.0.2/MANIFEST.in +1 -0
  14. modwire-4.0.2/Makefile +6 -0
  15. modwire-4.0.2/PKG-INFO +119 -0
  16. modwire-4.0.2/README.md +81 -0
  17. modwire-4.0.2/docs/governance/github-ecosystem.md +183 -0
  18. modwire-4.0.2/docs/governance/python-workflows.md +127 -0
  19. modwire-4.0.2/docs/wiki/Development-checks.md +25 -0
  20. modwire-4.0.2/docs/wiki/Home.md +27 -0
  21. {modwire-3.2.0 → modwire-4.0.2}/pyproject.toml +16 -18
  22. modwire-4.0.2/src/modwire/__init__.py +12 -0
  23. {modwire-3.2.0 → modwire-4.0.2}/src/modwire/_version.py +3 -3
  24. modwire-4.0.2/src/modwire/architecture/__init__.py +10 -0
  25. modwire-4.0.2/src/modwire/architecture/app.py +137 -0
  26. modwire-4.0.2/src/modwire/architecture/boundaries/__init__.py +8 -0
  27. modwire-4.0.2/src/modwire/architecture/boundaries/analyzer.py +56 -0
  28. modwire-4.0.2/src/modwire/architecture/boundaries/analyzers/__init__.py +1 -0
  29. modwire-4.0.2/src/modwire/architecture/boundaries/analyzers/analyzer_base.py +41 -0
  30. {modwire-3.2.0 → modwire-4.0.2}/src/modwire/architecture/boundaries/analyzers/backward.py +10 -6
  31. {modwire-3.2.0 → modwire-4.0.2}/src/modwire/architecture/boundaries/analyzers/no_cycles.py +10 -9
  32. {modwire-3.2.0 → modwire-4.0.2}/src/modwire/architecture/boundaries/analyzers/no_reentry.py +10 -9
  33. modwire-4.0.2/src/modwire/architecture/boundaries/base.py +54 -0
  34. modwire-4.0.2/src/modwire/architecture/boundaries/collector.py +32 -0
  35. modwire-4.0.2/src/modwire/architecture/boundaries/tags/__init__.py +9 -0
  36. modwire-4.0.2/src/modwire/architecture/boundaries/tags/matcher.py +135 -0
  37. {modwire-3.2.0 → modwire-4.0.2}/src/modwire/architecture/boundaries/tags/tag_map.py +6 -3
  38. modwire-4.0.2/src/modwire/architecture/insights/__init__.py +8 -0
  39. modwire-4.0.2/src/modwire/architecture/insights/base.py +14 -0
  40. modwire-4.0.2/src/modwire/architecture/insights/collector.py +31 -0
  41. modwire-4.0.2/src/modwire/architecture/insights/reporters/__init__.py +7 -0
  42. modwire-4.0.2/src/modwire/architecture/insights/reporters/base.py +43 -0
  43. modwire-4.0.2/src/modwire/architecture/insights/reporters/callables.py +60 -0
  44. {modwire-3.2.0/src/modwire/architecture/insight/reports → modwire-4.0.2/src/modwire/architecture/insights/reporters}/clusters.py +21 -19
  45. {modwire-3.2.0/src/modwire/architecture/insight/reports → modwire-4.0.2/src/modwire/architecture/insights/reporters}/coherence.py +24 -15
  46. {modwire-3.2.0/src/modwire/architecture/insight/reports → modwire-4.0.2/src/modwire/architecture/insights/reporters}/exports.py +18 -22
  47. {modwire-3.2.0/src/modwire/architecture/insight/reports → modwire-4.0.2/src/modwire/architecture/insights/reporters}/hotspots.py +25 -20
  48. modwire-4.0.2/src/modwire/architecture/map/__init__.py +11 -0
  49. modwire-4.0.2/src/modwire/architecture/map/base.py +20 -0
  50. modwire-4.0.2/src/modwire/architecture/map/collector.py +40 -0
  51. modwire-4.0.2/src/modwire/architecture/map/loader.py +63 -0
  52. modwire-4.0.2/src/modwire/architecture/shape/__init__.py +8 -0
  53. modwire-4.0.2/src/modwire/architecture/shape/base.py +92 -0
  54. modwire-4.0.2/src/modwire/architecture/shape/collector.py +42 -0
  55. {modwire-3.2.0/src/modwire/architecture/shape/rules → modwire-4.0.2/src/modwire/architecture/shape/resolvers}/abstract_class_resolver.py +22 -18
  56. {modwire-3.2.0/src/modwire/architecture/shape/rules → modwire-4.0.2/src/modwire/architecture/shape/resolvers}/callable_resolver.py +31 -31
  57. {modwire-3.2.0/src/modwire/architecture/shape/rules → modwire-4.0.2/src/modwire/architecture/shape/resolvers}/class_resolver.py +25 -22
  58. modwire-4.0.2/src/modwire/architecture/shape/resolvers/file_resolver.py +77 -0
  59. {modwire-3.2.0/src/modwire/architecture/shape/rules → modwire-4.0.2/src/modwire/architecture/shape/resolvers}/import_resolver.py +19 -12
  60. modwire-4.0.2/src/modwire/architecture/shape/resolvers/property_resolver.py +92 -0
  61. {modwire-3.2.0/src/modwire/architecture/shape/rules → modwire-4.0.2/src/modwire/architecture/shape/resolvers}/signature_resolver.py +28 -24
  62. modwire-4.0.2/src/modwire/architecture/shape/resolvers/symbol_resolver.py +33 -0
  63. modwire-4.0.2/src/modwire/code/__init__.py +10 -0
  64. modwire-4.0.2/src/modwire/code/package.py +48 -0
  65. modwire-4.0.2/src/modwire/code/reader.py +9 -0
  66. modwire-4.0.2/src/modwire/code/writer.py +27 -0
  67. modwire-4.0.2/src/modwire/facade.py +30 -0
  68. modwire-4.0.2/src/modwire/layers/__init__.py +11 -0
  69. modwire-4.0.2/src/modwire/layers/app.py +9 -0
  70. modwire-4.0.2/src/modwire/modules/__init__.py +4 -0
  71. modwire-4.0.2/src/modwire/modules/app.py +9 -0
  72. modwire-4.0.2/src/modwire/projects/__init__.py +43 -0
  73. modwire-4.0.2/src/modwire/projects/app.py +9 -0
  74. modwire-4.0.2/src/modwire/projects/ecosystem.py +269 -0
  75. modwire-4.0.2/src/modwire/shared/__init__.py +19 -0
  76. modwire-4.0.2/src/modwire/shared/base.py +76 -0
  77. modwire-4.0.2/src/modwire/shared/config/__init__.py +36 -0
  78. modwire-4.0.2/src/modwire/shared/config/architecture.py +67 -0
  79. modwire-4.0.2/src/modwire/shared/config/layers.py +30 -0
  80. modwire-4.0.2/src/modwire/shared/config/modules.py +18 -0
  81. modwire-4.0.2/src/modwire/shared/config/modwire.py +54 -0
  82. modwire-4.0.2/src/modwire/shared/config/projects.py +27 -0
  83. modwire-3.2.0/src/modwire/architecture/shape/config.py → modwire-4.0.2/src/modwire/shared/config/shape.py +8 -13
  84. modwire-4.0.2/src/modwire/shared/report/__init__.py +18 -0
  85. modwire-4.0.2/src/modwire/shared/report/base.py +105 -0
  86. modwire-4.0.2/src/modwire.egg-info/PKG-INFO +119 -0
  87. modwire-4.0.2/src/modwire.egg-info/SOURCES.txt +104 -0
  88. modwire-4.0.2/src/modwire.egg-info/requires.txt +11 -0
  89. modwire-4.0.2/src/modwire.egg-info/scm_file_list.json +101 -0
  90. modwire-4.0.2/src/modwire.egg-info/scm_version.json +8 -0
  91. modwire-4.0.2/tests/test_architecture.py +19 -0
  92. modwire-4.0.2/tests/test_ecosystem_contract.py +69 -0
  93. modwire-4.0.2/tests/test_models.py +60 -0
  94. {modwire-3.2.0 → modwire-4.0.2}/uv.lock +60 -291
  95. modwire-3.2.0/.github/workflows/ci.yml +0 -45
  96. modwire-3.2.0/.github/workflows/release.yml +0 -210
  97. modwire-3.2.0/CHANGELOG.md +0 -49
  98. modwire-3.2.0/PKG-INFO +0 -247
  99. modwire-3.2.0/README.md +0 -212
  100. modwire-3.2.0/docs/wiki/Development-checks.md +0 -18
  101. modwire-3.2.0/docs/wiki/Home.md +0 -25
  102. modwire-3.2.0/src/modwire/__init__.py +0 -6
  103. modwire-3.2.0/src/modwire/architecture/__init__.py +0 -26
  104. modwire-3.2.0/src/modwire/architecture/boundaries/analyzers/__init__.py +0 -0
  105. modwire-3.2.0/src/modwire/architecture/boundaries/base.py +0 -93
  106. modwire-3.2.0/src/modwire/architecture/boundaries/config.py +0 -43
  107. modwire-3.2.0/src/modwire/architecture/boundaries/map.py +0 -155
  108. modwire-3.2.0/src/modwire/architecture/boundaries/pipeline.py +0 -108
  109. modwire-3.2.0/src/modwire/architecture/boundaries/tags/__init__.py +0 -0
  110. modwire-3.2.0/src/modwire/architecture/boundaries/tags/matcher.py +0 -131
  111. modwire-3.2.0/src/modwire/architecture/config.py +0 -14
  112. modwire-3.2.0/src/modwire/architecture/insight/__init__.py +0 -0
  113. modwire-3.2.0/src/modwire/architecture/insight/base.py +0 -14
  114. modwire-3.2.0/src/modwire/architecture/insight/pipeline.py +0 -92
  115. modwire-3.2.0/src/modwire/architecture/insight/reports/__init__.py +0 -22
  116. modwire-3.2.0/src/modwire/architecture/insight/reports/callables.py +0 -54
  117. modwire-3.2.0/src/modwire/architecture/report.py +0 -102
  118. modwire-3.2.0/src/modwire/architecture/root.py +0 -18
  119. modwire-3.2.0/src/modwire/architecture/shape/__init__.py +0 -0
  120. modwire-3.2.0/src/modwire/architecture/shape/base.py +0 -52
  121. modwire-3.2.0/src/modwire/architecture/shape/pipeline.py +0 -95
  122. modwire-3.2.0/src/modwire/architecture/shape/rules/__init__.py +0 -20
  123. modwire-3.2.0/src/modwire/architecture/shape/rules/file_resolver.py +0 -57
  124. modwire-3.2.0/src/modwire/architecture/shape/rules/property_resolver.py +0 -81
  125. modwire-3.2.0/src/modwire/architecture/shape/rules/symbol_resolver.py +0 -34
  126. modwire-3.2.0/src/modwire/modules/__init__.py +0 -3
  127. modwire-3.2.0/src/modwire/modules/generate.py +0 -74
  128. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/copier.yml +0 -48
  129. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/php/src/Application/Ports/{{ repository_name }}.php.jinja +0 -14
  130. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/php/src/Application/UseCases/{{ use_case_name }}.php.jinja +0 -32
  131. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/php/src/Domain/Entities/{{ entity_name }}.php.jinja +0 -45
  132. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/php/src/Domain/Events/{{ event_name }}.php.jinja +0 -14
  133. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/php/src/Domain/Exceptions/{{ entity_name }}ValidationException.php.jinja +0 -11
  134. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/php/src/Infrastructure/Persistence/InMemory{{ repository_name }}.php.jinja +0 -24
  135. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/php/src/Interface/Http/{{ controller_name }}.php.jinja +0 -23
  136. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/python/{{ module_name }}/__init__.py.jinja +0 -1
  137. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/python/{{ module_name }}/application/__init__.py.jinja +0 -1
  138. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/python/{{ module_name }}/application/ports/__init__.py.jinja +0 -1
  139. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/python/{{ module_name }}/application/ports/{{ repository_name | lower }}.py.jinja +0 -13
  140. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/python/{{ module_name }}/application/use_cases/__init__.py.jinja +0 -1
  141. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/python/{{ module_name }}/application/use_cases/{{ use_case_name | lower }}.py.jinja +0 -22
  142. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/python/{{ module_name }}/domain/__init__.py.jinja +0 -1
  143. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/python/{{ module_name }}/domain/entities/__init__.py.jinja +0 -1
  144. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/python/{{ module_name }}/domain/entities/{{ entity_name | lower }}.py.jinja +0 -35
  145. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/python/{{ module_name }}/domain/events/__init__.py.jinja +0 -1
  146. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/python/{{ module_name }}/domain/events/{{ event_name | lower }}.py.jinja +0 -7
  147. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/python/{{ module_name }}/domain/exceptions/__init__.py.jinja +0 -1
  148. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/python/{{ module_name }}/domain/exceptions/{{ entity_name | lower }}validationerror.py.jinja +0 -2
  149. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/python/{{ module_name }}/infrastructure/__init__.py.jinja +0 -1
  150. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/python/{{ module_name }}/infrastructure/persistence/__init__.py.jinja +0 -1
  151. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/python/{{ module_name }}/infrastructure/persistence/inmemory{{ repository_name | lower }}.py.jinja +0 -14
  152. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/python/{{ module_name }}/interface/__init__.py.jinja +0 -1
  153. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/python/{{ module_name }}/interface/http/__init__.py.jinja +0 -1
  154. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/python/{{ module_name }}/interface/http/{{ controller_name | lower }}.py.jinja +0 -15
  155. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/typescript/{{ module_name }}/application/ports/{{ repository_name }}.ts.jinja +0 -6
  156. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/typescript/{{ module_name }}/application/use_cases/{{ use_case_name }}.ts.jinja +0 -19
  157. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/typescript/{{ module_name }}/domain/entities/{{ entity_name }}.ts.jinja +0 -31
  158. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/typescript/{{ module_name }}/domain/events/{{ event_name }}.ts.jinja +0 -6
  159. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/typescript/{{ module_name }}/domain/exceptions/{{ entity_name }}ValidationError.ts.jinja +0 -1
  160. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/typescript/{{ module_name }}/infrastructure/persistence/InMemory{{ repository_name }}.ts.jinja +0 -14
  161. modwire-3.2.0/src/modwire/modules/scaffoldings/clean/template/typescript/{{ module_name }}/interface/http/{{ controller_name }}.ts.jinja +0 -10
  162. modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/copier.yml +0 -68
  163. modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/php/src/BoundedContexts/{{ context_class_name }}/{{ module_class_name }}/Application/Ports/{{ repository_name }}.php.jinja +0 -14
  164. modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/php/src/BoundedContexts/{{ context_class_name }}/{{ module_class_name }}/Application/UseCases/{{ use_case_name }}.php.jinja +0 -35
  165. modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/php/src/BoundedContexts/{{ context_class_name }}/{{ module_class_name }}/Domain/Aggregates/{{ aggregate_name }}.php.jinja +0 -44
  166. modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/php/src/BoundedContexts/{{ context_class_name }}/{{ module_class_name }}/Domain/Entities/{{ entity_name }}.php.jinja +0 -16
  167. modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/php/src/BoundedContexts/{{ context_class_name }}/{{ module_class_name }}/Domain/Events/{{ event_name }}.php.jinja +0 -14
  168. modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/php/src/BoundedContexts/{{ context_class_name }}/{{ module_class_name }}/Domain/Exceptions/{{ aggregate_name }}ValidationException.php.jinja +0 -11
  169. modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/php/src/BoundedContexts/{{ context_class_name }}/{{ module_class_name }}/Domain/Services/{{ domain_service_name }}.php.jinja +0 -15
  170. modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/php/src/BoundedContexts/{{ context_class_name }}/{{ module_class_name }}/Domain/ValueObjects/{{ value_object_name }}.php.jinja +0 -17
  171. modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/php/src/BoundedContexts/{{ context_class_name }}/{{ module_class_name }}/Infrastructure/Persistence/InMemory{{ repository_name }}.php.jinja +0 -24
  172. modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/php/src/BoundedContexts/{{ context_class_name }}/{{ module_class_name }}/Interface/Http/{{ controller_name }}.php.jinja +0 -23
  173. modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/python/bounded_contexts/__init__.py.jinja +0 -1
  174. modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/python/bounded_contexts/{{ context_name }}/__init__.py.jinja +0 -1
  175. modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/python/bounded_contexts/{{ context_name }}/{{ module_name }}/__init__.py.jinja +0 -1
  176. modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/python/bounded_contexts/{{ context_name }}/{{ module_name }}/application/__init__.py.jinja +0 -1
  177. modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/python/bounded_contexts/{{ context_name }}/{{ module_name }}/application/ports/__init__.py.jinja +0 -1
  178. modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/python/bounded_contexts/{{ context_name }}/{{ module_name }}/application/ports/{{ repository_name | lower }}.py.jinja +0 -13
  179. modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/python/bounded_contexts/{{ context_name }}/{{ module_name }}/application/use_cases/__init__.py.jinja +0 -1
  180. modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/python/bounded_contexts/{{ context_name }}/{{ module_name }}/application/use_cases/{{ use_case_name | lower }}.py.jinja +0 -28
  181. modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/python/bounded_contexts/{{ context_name }}/{{ module_name }}/domain/__init__.py.jinja +0 -1
  182. modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/python/bounded_contexts/{{ context_name }}/{{ module_name }}/domain/aggregates/__init__.py.jinja +0 -1
  183. modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/python/bounded_contexts/{{ context_name }}/{{ module_name }}/domain/aggregates/{{ aggregate_name | lower }}.py.jinja +0 -37
  184. modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/python/bounded_contexts/{{ context_name }}/{{ module_name }}/domain/entities/__init__.py.jinja +0 -1
  185. modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/python/bounded_contexts/{{ context_name }}/{{ module_name }}/domain/entities/{{ entity_name | lower }}.py.jinja +0 -9
  186. modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/python/bounded_contexts/{{ context_name }}/{{ module_name }}/domain/events/__init__.py.jinja +0 -1
  187. modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/python/bounded_contexts/{{ context_name }}/{{ module_name }}/domain/events/{{ event_name | lower }}.py.jinja +0 -7
  188. modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/python/bounded_contexts/{{ context_name }}/{{ module_name }}/domain/exceptions/__init__.py.jinja +0 -1
  189. modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/python/bounded_contexts/{{ context_name }}/{{ module_name }}/domain/exceptions/{{ aggregate_name | lower }}validationerror.py.jinja +0 -2
  190. modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/python/bounded_contexts/{{ context_name }}/{{ module_name }}/domain/services/__init__.py.jinja +0 -1
  191. modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/python/bounded_contexts/{{ context_name }}/{{ module_name }}/domain/services/{{ domain_service_name | lower }}.py.jinja +0 -8
  192. modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/python/bounded_contexts/{{ context_name }}/{{ module_name }}/domain/value_objects/__init__.py.jinja +0 -1
  193. modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/python/bounded_contexts/{{ context_name }}/{{ module_name }}/domain/value_objects/{{ value_object_name | lower }}.py.jinja +0 -14
  194. modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/python/bounded_contexts/{{ context_name }}/{{ module_name }}/infrastructure/__init__.py.jinja +0 -1
  195. modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/python/bounded_contexts/{{ context_name }}/{{ module_name }}/infrastructure/persistence/__init__.py.jinja +0 -1
  196. modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/python/bounded_contexts/{{ context_name }}/{{ module_name }}/infrastructure/persistence/inmemory{{ repository_name | lower }}.py.jinja +0 -14
  197. modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/python/bounded_contexts/{{ context_name }}/{{ module_name }}/interface/__init__.py.jinja +0 -1
  198. modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/python/bounded_contexts/{{ context_name }}/{{ module_name }}/interface/http/__init__.py.jinja +0 -1
  199. modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/python/bounded_contexts/{{ context_name }}/{{ module_name }}/interface/http/{{ controller_name | lower }}.py.jinja +0 -17
  200. modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/typescript/bounded_contexts/{{ context_name }}/{{ module_name }}/application/ports/{{ repository_name }}.ts.jinja +0 -6
  201. modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/typescript/bounded_contexts/{{ context_name }}/{{ module_name }}/application/use_cases/{{ use_case_name }}.ts.jinja +0 -23
  202. modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/typescript/bounded_contexts/{{ context_name }}/{{ module_name }}/domain/aggregates/{{ aggregate_name }}.ts.jinja +0 -29
  203. modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/typescript/bounded_contexts/{{ context_name }}/{{ module_name }}/domain/entities/{{ entity_name }}.ts.jinja +0 -8
  204. modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/typescript/bounded_contexts/{{ context_name }}/{{ module_name }}/domain/events/{{ event_name }}.ts.jinja +0 -6
  205. modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/typescript/bounded_contexts/{{ context_name }}/{{ module_name }}/domain/exceptions/{{ aggregate_name }}ValidationError.ts.jinja +0 -1
  206. modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/typescript/bounded_contexts/{{ context_name }}/{{ module_name }}/domain/services/{{ domain_service_name }}.ts.jinja +0 -7
  207. modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/typescript/bounded_contexts/{{ context_name }}/{{ module_name }}/domain/value_objects/{{ value_object_name }}.ts.jinja +0 -9
  208. modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/typescript/bounded_contexts/{{ context_name }}/{{ module_name }}/infrastructure/persistence/InMemory{{ repository_name }}.ts.jinja +0 -14
  209. modwire-3.2.0/src/modwire/modules/scaffoldings/ddd_context/template/typescript/bounded_contexts/{{ context_name }}/{{ module_name }}/interface/http/{{ controller_name }}.ts.jinja +0 -10
  210. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/copier.yml +0 -43
  211. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/php/src/Adapters/Inbound/Amqp/{{ command_name }}Consumer.php.jinja +0 -23
  212. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/php/src/Adapters/Inbound/Web/{{ controller_name }}.php.jinja +0 -23
  213. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/php/src/Adapters/Inbound/{{ service_name }}.php.jinja +0 -25
  214. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/php/src/Adapters/Outbound/Client/{{ aggregate_name }}Client.php.jinja +0 -14
  215. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/php/src/Adapters/Outbound/Persistence/InMemory{{ repository_name }}.php.jinja +0 -24
  216. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/php/src/Domain/Events/{{ aggregate_name }}Created.php.jinja +0 -14
  217. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/php/src/Domain/Exceptions/{{ aggregate_name }}ValidationException.php.jinja +0 -11
  218. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/php/src/Domain/Models/{{ aggregate_name }}.php.jinja +0 -45
  219. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/php/src/Ports/Inbound/{{ command_name }}.php.jinja +0 -14
  220. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/php/src/Ports/Inbound/{{ service_name }}Port.php.jinja +0 -12
  221. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/php/src/Ports/Outbound/{{ repository_name }}.php.jinja +0 -14
  222. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/__init__.py.jinja +0 -3
  223. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/adapters/__init__.py.jinja +0 -3
  224. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/adapters/inbound/__init__.py.jinja +0 -3
  225. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/adapters/inbound/amqp/__init__.py.jinja +0 -3
  226. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/adapters/inbound/amqp/{{ command_name | lower }}consumer.py.jinja +0 -17
  227. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/adapters/inbound/web/__init__.py.jinja +0 -3
  228. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/adapters/inbound/web/{{ controller_name | lower }}.py.jinja +0 -13
  229. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/adapters/inbound/{{ service_name | lower }}.py.jinja +0 -15
  230. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/adapters/outbound/__init__.py.jinja +0 -3
  231. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/adapters/outbound/client/__init__.py.jinja +0 -3
  232. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/adapters/outbound/client/{{ aggregate_name | lower }}client.py.jinja +0 -6
  233. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/adapters/outbound/persistence/__init__.py.jinja +0 -3
  234. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/adapters/outbound/persistence/inmemory{{ repository_name | lower }}.py.jinja +0 -14
  235. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/domain/__init__.py.jinja +0 -3
  236. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/domain/events/__init__.py.jinja +0 -3
  237. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/domain/events/{{ aggregate_name | lower }}created.py.jinja +0 -9
  238. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/domain/exceptions/__init__.py.jinja +0 -3
  239. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/domain/exceptions/{{ aggregate_name | lower }}validationerror.py.jinja +0 -5
  240. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/domain/models/__init__.py.jinja +0 -3
  241. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/domain/models/{{ aggregate_name | lower }}.py.jinja +0 -37
  242. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/ports/__init__.py.jinja +0 -3
  243. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/ports/inbound/__init__.py.jinja +0 -3
  244. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/ports/inbound/{{ command_name | lower }}.py.jinja +0 -9
  245. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/ports/inbound/{{ service_name | lower }}.py.jinja +0 -11
  246. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/ports/outbound/__init__.py.jinja +0 -3
  247. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/python/{{ module_name }}/ports/outbound/{{ repository_name | lower }}.py.jinja +0 -13
  248. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/typescript/{{ module_name }}/adapters/inbound/amqp/{{ command_name }}Consumer.ts.jinja +0 -10
  249. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/typescript/{{ module_name }}/adapters/inbound/web/{{ controller_name }}.ts.jinja +0 -11
  250. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/typescript/{{ module_name }}/adapters/inbound/{{ service_name }}.ts.jinja +0 -13
  251. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/typescript/{{ module_name }}/adapters/outbound/client/{{ aggregate_name }}Client.ts.jinja +0 -5
  252. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/typescript/{{ module_name }}/adapters/outbound/persistence/InMemory{{ repository_name }}.ts.jinja +0 -14
  253. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/typescript/{{ module_name }}/domain/events/{{ aggregate_name }}Created.ts.jinja +0 -6
  254. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/typescript/{{ module_name }}/domain/exceptions/{{ aggregate_name }}ValidationError.ts.jinja +0 -1
  255. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/typescript/{{ module_name }}/domain/models/{{ aggregate_name }}.ts.jinja +0 -31
  256. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/typescript/{{ module_name }}/ports/inbound/{{ command_name }}.ts.jinja +0 -6
  257. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/typescript/{{ module_name }}/ports/inbound/{{ service_name }}Port.ts.jinja +0 -6
  258. modwire-3.2.0/src/modwire/modules/scaffoldings/hexagonal/template/typescript/{{ module_name }}/ports/outbound/{{ repository_name }}.ts.jinja +0 -6
  259. modwire-3.2.0/src/modwire/modules/scaffoldings/layered/copier.yml +0 -23
  260. modwire-3.2.0/src/modwire/modules/scaffoldings/layered/template/{{ module_name }}/application.py.jinja +0 -18
  261. modwire-3.2.0/src/modwire/modules/scaffoldings/layered/template/{{ module_name }}/domain.py.jinja +0 -12
  262. modwire-3.2.0/src/modwire/modules/scaffoldings/layered/template/{{ module_name }}/infrastructure.py.jinja +0 -11
  263. modwire-3.2.0/src/modwire/modules/scaffoldings/layered/template/{{ module_name }}/ui.py.jinja +0 -20
  264. modwire-3.2.0/src/modwire/projects/__init__.py +0 -13
  265. modwire-3.2.0/src/modwire/projects/_operations.py +0 -287
  266. modwire-3.2.0/src/modwire/projects/generate.py +0 -126
  267. modwire-3.2.0/src/modwire/projects/profile.py +0 -321
  268. modwire-3.2.0/src/modwire/projects/root.py +0 -70
  269. modwire-3.2.0/src/modwire/projects/scaffoldings/php-symfony-ddd-composer/copier.yml +0 -33
  270. modwire-3.2.0/src/modwire/projects/scaffoldings/php-symfony-ddd-composer/template/.gitignore.jinja +0 -5
  271. modwire-3.2.0/src/modwire/projects/scaffoldings/php-symfony-ddd-composer/template/.modwire/project.json.jinja +0 -1
  272. modwire-3.2.0/src/modwire/projects/scaffoldings/php-symfony-ddd-composer/template/README.md.jinja +0 -6
  273. modwire-3.2.0/src/modwire/projects/scaffoldings/php-symfony-ddd-composer/template/bin/console.jinja +0 -6
  274. modwire-3.2.0/src/modwire/projects/scaffoldings/php-symfony-ddd-composer/template/composer.json.jinja +0 -29
  275. modwire-3.2.0/src/modwire/projects/scaffoldings/php-symfony-ddd-composer/template/config/routes.yaml.jinja +0 -3
  276. modwire-3.2.0/src/modwire/projects/scaffoldings/php-symfony-ddd-composer/template/src/Infrastructure/Clients/Generated/.gitkeep.jinja +0 -1
  277. modwire-3.2.0/src/modwire/projects/scaffoldings/php-symfony-ddd-composer/template/src/Kernel.php.jinja +0 -13
  278. modwire-3.2.0/src/modwire/projects/scaffoldings/php-symfony-ddd-composer/template/tests/KernelTest.php.jinja +0 -16
  279. modwire-3.2.0/src/modwire/projects/scaffoldings/python-fastapi-ddd-uv/copier.yml +0 -90
  280. modwire-3.2.0/src/modwire/projects/scaffoldings/python-fastapi-ddd-uv/template/.gitignore.jinja +0 -10
  281. modwire-3.2.0/src/modwire/projects/scaffoldings/python-fastapi-ddd-uv/template/.modwire/project.json.jinja +0 -1
  282. modwire-3.2.0/src/modwire/projects/scaffoldings/python-fastapi-ddd-uv/template/README.md.jinja +0 -25
  283. modwire-3.2.0/src/modwire/projects/scaffoldings/python-fastapi-ddd-uv/template/openapi/.gitkeep.jinja +0 -1
  284. modwire-3.2.0/src/modwire/projects/scaffoldings/python-fastapi-ddd-uv/template/pyproject.toml.jinja +0 -38
  285. modwire-3.2.0/src/modwire/projects/scaffoldings/python-fastapi-ddd-uv/template/src/{{ package_name }}/__init__.py.jinja +0 -1
  286. modwire-3.2.0/src/modwire/projects/scaffoldings/python-fastapi-ddd-uv/template/src/{{ package_name }}/cli.py.jinja +0 -15
  287. modwire-3.2.0/src/modwire/projects/scaffoldings/python-fastapi-ddd-uv/template/src/{{ package_name }}/infrastructure/__init__.py.jinja +0 -1
  288. modwire-3.2.0/src/modwire/projects/scaffoldings/python-fastapi-ddd-uv/template/src/{{ package_name }}/infrastructure/clients/__init__.py.jinja +0 -1
  289. modwire-3.2.0/src/modwire/projects/scaffoldings/python-fastapi-ddd-uv/template/src/{{ package_name }}/infrastructure/clients/generated/.gitkeep.jinja +0 -1
  290. modwire-3.2.0/src/modwire/projects/scaffoldings/python-fastapi-ddd-uv/template/src/{{ package_name }}/interface/__init__.py.jinja +0 -1
  291. modwire-3.2.0/src/modwire/projects/scaffoldings/python-fastapi-ddd-uv/template/src/{{ package_name }}/interface/http/__init__.py.jinja +0 -1
  292. modwire-3.2.0/src/modwire/projects/scaffoldings/python-fastapi-ddd-uv/template/src/{{ package_name }}/interface/http/router.py.jinja +0 -8
  293. modwire-3.2.0/src/modwire/projects/scaffoldings/python-fastapi-ddd-uv/template/src/{{ package_name }}/main.py.jinja +0 -14
  294. modwire-3.2.0/src/modwire/projects/scaffoldings/python-fastapi-ddd-uv/template/src/{{ package_name }}/settings.py.jinja +0 -7
  295. modwire-3.2.0/src/modwire/projects/scaffoldings/python-fastapi-ddd-uv/template/tests/test_health.py.jinja +0 -12
  296. modwire-3.2.0/src/modwire/projects/scaffoldings/typescript-nestjs-ddd-pnpm/copier.yml +0 -33
  297. modwire-3.2.0/src/modwire/projects/scaffoldings/typescript-nestjs-ddd-pnpm/template/.gitignore.jinja +0 -5
  298. modwire-3.2.0/src/modwire/projects/scaffoldings/typescript-nestjs-ddd-pnpm/template/.modwire/project.json.jinja +0 -1
  299. modwire-3.2.0/src/modwire/projects/scaffoldings/typescript-nestjs-ddd-pnpm/template/README.md.jinja +0 -6
  300. modwire-3.2.0/src/modwire/projects/scaffoldings/typescript-nestjs-ddd-pnpm/template/nest-cli.json.jinja +0 -4
  301. modwire-3.2.0/src/modwire/projects/scaffoldings/typescript-nestjs-ddd-pnpm/template/openapi/.gitkeep.jinja +0 -1
  302. modwire-3.2.0/src/modwire/projects/scaffoldings/typescript-nestjs-ddd-pnpm/template/package.json.jinja +0 -22
  303. modwire-3.2.0/src/modwire/projects/scaffoldings/typescript-nestjs-ddd-pnpm/template/src/app.module.ts.jinja +0 -4
  304. modwire-3.2.0/src/modwire/projects/scaffoldings/typescript-nestjs-ddd-pnpm/template/src/infrastructure/clients/generated/.gitkeep.jinja +0 -1
  305. modwire-3.2.0/src/modwire/projects/scaffoldings/typescript-nestjs-ddd-pnpm/template/src/main.ts.jinja +0 -10
  306. modwire-3.2.0/src/modwire/projects/scaffoldings/typescript-nestjs-ddd-pnpm/template/test/app.spec.ts.jinja +0 -7
  307. modwire-3.2.0/src/modwire/projects/scaffoldings/typescript-nestjs-ddd-pnpm/template/tsconfig.json.jinja +0 -12
  308. modwire-3.2.0/src/modwire.egg-info/PKG-INFO +0 -247
  309. modwire-3.2.0/src/modwire.egg-info/SOURCES.txt +0 -251
  310. modwire-3.2.0/src/modwire.egg-info/requires.txt +0 -9
  311. modwire-3.2.0/tests/architecture/boundaries/test_map.py +0 -69
  312. modwire-3.2.0/tests/architecture/boundaries/test_pipeline.py +0 -122
  313. modwire-3.2.0/tests/architecture/test_report.py +0 -110
  314. modwire-3.2.0/tests/modules/test_generate.py +0 -210
  315. modwire-3.2.0/tests/projects/test_project_generate.py +0 -225
  316. modwire-3.2.0/tests/projects/test_project_operations.py +0 -156
  317. {modwire-3.2.0 → modwire-4.0.2}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  318. {modwire-3.2.0 → modwire-4.0.2}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  319. {modwire-3.2.0 → modwire-4.0.2}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  320. {modwire-3.2.0 → modwire-4.0.2}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  321. {modwire-3.2.0 → modwire-4.0.2}/LICENSE +0 -0
  322. {modwire-3.2.0 → modwire-4.0.2}/docs/wiki/Reporting-bugs.md +0 -0
  323. {modwire-3.2.0 → modwire-4.0.2}/docs/wiki/Requesting-features.md +0 -0
  324. {modwire-3.2.0 → modwire-4.0.2}/setup.cfg +0 -0
  325. {modwire-3.2.0/src/modwire/architecture/boundaries → modwire-4.0.2/src/modwire/architecture/shape/resolvers}/__init__.py +0 -0
  326. /modwire-3.2.0/src/modwire/projects/scaffoldings/php-symfony-ddd-composer/template/openapi/.gitkeep.jinja → /modwire-4.0.2/src/modwire/py.typed +0 -0
  327. {modwire-3.2.0 → modwire-4.0.2}/src/modwire.egg-info/dependency_links.txt +0 -0
  328. {modwire-3.2.0 → modwire-4.0.2}/src/modwire.egg-info/top_level.txt +0 -0
@@ -0,0 +1,171 @@
1
+ version: 2
2
+
3
+ packages:
4
+ core:
5
+ repository: 9orky/modwire
6
+ distribution: modwire
7
+ component: Core
8
+ role: coordinator
9
+ lifecycle: active
10
+ summary: Typed coordination library and ecosystem integration gate.
11
+ depends_on: [extraction, mermaid, siren]
12
+ cli:
13
+ repository: 9orky/modwire-cli
14
+ distribution: modwire-cli
15
+ component: CLI
16
+ role: runtime
17
+ lifecycle: active
18
+ summary: Command-line runtime and user-facing workflows.
19
+ depends_on: [core]
20
+ extraction:
21
+ repository: 9orky/modwire-extraction
22
+ distribution: modwire-extraction
23
+ component: Extraction
24
+ role: building_block
25
+ lifecycle: active
26
+ summary: Canonical source extraction and normalization.
27
+ mermaid:
28
+ repository: 9orky/modwire-mermaid
29
+ distribution: modwire-mermaid
30
+ component: Mermaid
31
+ role: building_block
32
+ lifecycle: active
33
+ summary: Typed, deterministic Mermaid source generation.
34
+ siren:
35
+ repository: 9orky/modwire-siren
36
+ distribution: modwire-siren
37
+ component: Siren
38
+ role: building_block
39
+ lifecycle: active
40
+ summary: Typed Siren hypermedia and OpenAPI integration.
41
+ mcp:
42
+ repository: 9orky/modwire-mcp
43
+ distribution: modwire-mcp
44
+ component: MCP
45
+ role: integration
46
+ lifecycle: incubating
47
+ summary: MCP surface and future home of scaffolding operations.
48
+ depends_on: [core]
49
+
50
+ project:
51
+ owner: 9orky
52
+ title: Modwire Ecosystem
53
+ number: 4
54
+ visibility: public
55
+ default_package: core
56
+ description: Cross-repository roadmap and release coordination for the Modwire ecosystem.
57
+ governance_url: https://github.com/9orky/modwire/blob/main/docs/governance/github-ecosystem.md
58
+
59
+ workflows:
60
+ contract_ref: workflows-v1
61
+ ci_entrypoint: .github/workflows/ci.yml
62
+ release_entrypoint: .github/workflows/release.yml
63
+ verify_reusable: .github/workflows/python-package.yml
64
+ release_build_reusable: .github/workflows/python-release-build.yml
65
+ release_assets_reusable: .github/workflows/python-release-assets.yml
66
+ release_driver: github_release
67
+ release_event: published
68
+ release_tag_pattern: ^v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$
69
+ artifact_name: python-package-distributions
70
+ pypi_environment: pypi
71
+ actions:
72
+ checkout: actions/checkout@v6
73
+ setup_python: actions/setup-python@v6
74
+ upload_artifact: actions/upload-artifact@v7
75
+ download_artifact: actions/download-artifact@v8
76
+ publish_pypi: pypa/gh-action-pypi-publish@release/v1
77
+
78
+ fields:
79
+ Status:
80
+ type: single_select
81
+ options: [Inbox, Ready, In progress, Blocked, Review, Done]
82
+ Horizon:
83
+ type: single_select
84
+ options: [Now, Next, Later]
85
+ Priority:
86
+ type: single_select
87
+ options: [P0, P1, P2, P3]
88
+ Component:
89
+ type: single_select
90
+ source: packages
91
+ Release train:
92
+ type: text
93
+ Target date:
94
+ type: date
95
+ Risk:
96
+ type: single_select
97
+ options: [Low, Medium, High]
98
+
99
+ views:
100
+ - name: Roadmap
101
+ layout: roadmap
102
+ group_by: Release train
103
+ slice_by: Component
104
+ - name: Now
105
+ layout: board
106
+ filter: "Horizon:Now -Status:Done"
107
+ group_by: Status
108
+ - name: By package
109
+ layout: table
110
+ filter: "-Status:Done"
111
+ group_by: Repository
112
+ - name: Blocked
113
+ layout: table
114
+ filter: "Status:Blocked"
115
+ group_by: Component
116
+ - name: Release readiness
117
+ layout: table
118
+ filter: "has:\"Release train\" -Status:Done"
119
+ group_by: Release train
120
+ - name: Inbox
121
+ layout: table
122
+ filter: "Status:Inbox"
123
+
124
+ labels:
125
+ "type:bug":
126
+ color: "d73a4a"
127
+ description: Incorrect existing behavior
128
+ "type:feature":
129
+ color: "0e8a16"
130
+ description: New user-facing capability
131
+ "type:maintenance":
132
+ color: "c5def5"
133
+ description: Internal maintenance
134
+ "type:docs":
135
+ color: "0075ca"
136
+ description: Documentation
137
+ ecosystem:
138
+ color: "5319e7"
139
+ description: Cross-package coordination
140
+ contract:
141
+ color: "1d76db"
142
+ description: Public contract or compatibility work
143
+ breaking:
144
+ color: "b60205"
145
+ description: Backward-incompatible change
146
+ blocked:
147
+ color: "e99695"
148
+ description: Blocked by another decision or delivery
149
+ release-gate:
150
+ color: "fbca04"
151
+ description: Must complete before a release
152
+
153
+ automation:
154
+ auto_add_filter: "is:open"
155
+ added_status: Inbox
156
+ closed_status: Done
157
+ merged_status: Done
158
+ archive_filter: "Status:Done updated:<@today-30d"
159
+
160
+ milestones:
161
+ scope: repository
162
+ naming: "<version-or-phase>: <outcome>"
163
+ close_when_complete: true
164
+ ecosystem_coordination_field: Release train
165
+ cross_repository_work: parent_issue_in_modwire_with_sub_issues
166
+
167
+ cadence:
168
+ triage: weekly
169
+ roadmap_review: monthly
170
+ release_readiness: before_each_package_release
171
+ project_status_update: monthly
@@ -0,0 +1,405 @@
1
+ #!/usr/bin/env python3
2
+ from __future__ import annotations
3
+
4
+ import argparse
5
+ import json
6
+ import re
7
+ import subprocess
8
+ from pathlib import Path
9
+ from typing import Any
10
+
11
+ from modwire.projects import EcosystemContract, EcosystemDrift, ProjectFieldType
12
+
13
+
14
+ ROOT = Path(__file__).resolve().parents[2]
15
+ DEFAULT_CONTRACT = ROOT / ".github" / "modwire-ecosystem.yml"
16
+
17
+
18
+ def gh(*arguments: str) -> str:
19
+ result = subprocess.run(
20
+ ["gh", *arguments],
21
+ check=True,
22
+ capture_output=True,
23
+ text=True,
24
+ )
25
+ return result.stdout
26
+
27
+
28
+ def gh_json(*arguments: str) -> Any:
29
+ return json.loads(gh(*arguments))
30
+
31
+
32
+ def load_contract(path: Path) -> EcosystemContract:
33
+ return EcosystemContract.load_yaml(path)
34
+
35
+
36
+ def workflow_drift(contract: EcosystemContract) -> list[str]:
37
+ errors: list[str] = []
38
+ workflow_paths = (
39
+ contract.workflows.ci_entrypoint,
40
+ contract.workflows.release_entrypoint,
41
+ contract.workflows.verify_reusable,
42
+ contract.workflows.release_build_reusable,
43
+ contract.workflows.release_assets_reusable,
44
+ )
45
+ contents: dict[str, str] = {}
46
+ for relative_path in workflow_paths:
47
+ path = ROOT / relative_path
48
+ if not path.is_file():
49
+ errors.append(f"missing workflow file {relative_path}")
50
+ continue
51
+ contents[relative_path] = path.read_text(encoding="utf-8")
52
+
53
+ expected_actions = {
54
+ "actions/checkout": contract.workflows.actions.checkout,
55
+ "actions/setup-python": contract.workflows.actions.setup_python,
56
+ "actions/upload-artifact": contract.workflows.actions.upload_artifact,
57
+ "actions/download-artifact": contract.workflows.actions.download_artifact,
58
+ "pypa/gh-action-pypi-publish": contract.workflows.actions.publish_pypi,
59
+ }
60
+ for path in sorted((ROOT / ".github" / "workflows").glob("*.yml")):
61
+ text = path.read_text(encoding="utf-8")
62
+ for action in re.findall(
63
+ r"(?:actions/(?:checkout|setup-python|upload-artifact|download-artifact)|"
64
+ r"pypa/gh-action-pypi-publish)@[^\s]+",
65
+ text,
66
+ ):
67
+ name = action.split("@", maxsplit=1)[0]
68
+ if action != expected_actions[name]:
69
+ errors.append(f"{path.name}: unmanaged action reference {action}")
70
+
71
+ release = contents.get(contract.workflows.release_entrypoint, "")
72
+ release_build = contents.get(contract.workflows.release_build_reusable, "")
73
+ verify = contents.get(contract.workflows.verify_reusable, "")
74
+ required_references = {
75
+ contract.workflows.release_entrypoint: (
76
+ contract.workflows.release_build_reusable,
77
+ contract.workflows.release_assets_reusable,
78
+ contract.workflows.actions.download_artifact,
79
+ contract.workflows.actions.publish_pypi,
80
+ ),
81
+ contract.workflows.release_build_reusable: (
82
+ contract.workflows.actions.checkout,
83
+ contract.workflows.actions.setup_python,
84
+ contract.workflows.actions.upload_artifact,
85
+ ),
86
+ contract.workflows.verify_reusable: (
87
+ contract.workflows.actions.checkout,
88
+ contract.workflows.actions.setup_python,
89
+ contract.workflows.actions.upload_artifact,
90
+ ),
91
+ contract.workflows.release_assets_reusable: (
92
+ contract.workflows.actions.download_artifact,
93
+ ),
94
+ }
95
+ for path, references in required_references.items():
96
+ text = contents.get(path, "")
97
+ for reference in references:
98
+ if reference not in text:
99
+ errors.append(f"{path}: missing required reference {reference}")
100
+
101
+ for forbidden in (
102
+ "python - <<",
103
+ "SETUPTOOLS_SCM_PRETEND_VERSION",
104
+ "softprops/",
105
+ ):
106
+ if forbidden in release or forbidden in release_build:
107
+ errors.append(f"release workflows contain forbidden pattern {forbidden}")
108
+ if contract.workflows.artifact_name not in release or contract.workflows.artifact_name not in release_build:
109
+ errors.append("release artifact name differs from the workflow contract")
110
+ release_assets = contents.get(contract.workflows.release_assets_reusable, "")
111
+ if (
112
+ "workflow_call:" not in verify
113
+ or "workflow_call:" not in release_build
114
+ or "workflow_call:" not in release_assets
115
+ ):
116
+ errors.append("reusable workflows must use workflow_call")
117
+ if "release:" not in release or "types: [published]" not in release:
118
+ errors.append("release.yml must be driven by a published GitHub Release")
119
+ if "skip-existing: true" not in release:
120
+ errors.append("release.yml must make PyPI publication idempotent")
121
+ if '--repo "$GITHUB_REPOSITORY"' not in release_assets:
122
+ errors.append("release assets must target GITHUB_REPOSITORY explicitly")
123
+ return errors
124
+
125
+
126
+ def project_fields(contract: EcosystemContract) -> dict[str, dict[str, Any]]:
127
+ query = """
128
+ query($id: ID!) {
129
+ node(id: $id) {
130
+ ... on ProjectV2 {
131
+ fields(first: 100) {
132
+ nodes {
133
+ __typename
134
+ ... on ProjectV2Field { id name dataType }
135
+ ... on ProjectV2SingleSelectField { id name options { name } }
136
+ }
137
+ }
138
+ }
139
+ }
140
+ }
141
+ """
142
+ project = gh_json(
143
+ "project",
144
+ "view",
145
+ str(contract.project.number),
146
+ "--owner",
147
+ contract.project.owner,
148
+ "--format",
149
+ "json",
150
+ )
151
+ data = gh_json(
152
+ "api",
153
+ "graphql",
154
+ "-F",
155
+ f"id={project['id']}",
156
+ "-f",
157
+ f"query={query}",
158
+ )
159
+ nodes = data["data"]["node"]["fields"]["nodes"]
160
+ return {node["name"]: node for node in nodes if node.get("name")}
161
+
162
+
163
+ def linked_repositories(contract: EcosystemContract) -> set[str]:
164
+ query = """
165
+ query($id: ID!) {
166
+ node(id: $id) {
167
+ ... on ProjectV2 { repositories(first: 100) { nodes { nameWithOwner } } }
168
+ }
169
+ }
170
+ """
171
+ project = gh_json(
172
+ "project",
173
+ "view",
174
+ str(contract.project.number),
175
+ "--owner",
176
+ contract.project.owner,
177
+ "--format",
178
+ "json",
179
+ )
180
+ data = gh_json(
181
+ "api",
182
+ "graphql",
183
+ "-F",
184
+ f"id={project['id']}",
185
+ "-f",
186
+ f"query={query}",
187
+ )
188
+ nodes = data["data"]["node"]["repositories"]["nodes"]
189
+ return {node["nameWithOwner"] for node in nodes}
190
+
191
+
192
+ def open_work_urls(contract: EcosystemContract) -> set[str]:
193
+ urls: set[str] = set()
194
+ for repository in contract.repositories():
195
+ for kind in ("issue", "pr"):
196
+ items = gh_json(
197
+ kind,
198
+ "list",
199
+ "--repo",
200
+ repository,
201
+ "--state",
202
+ "open",
203
+ "--limit",
204
+ "100",
205
+ "--json",
206
+ "url",
207
+ )
208
+ urls.update(item["url"] for item in items)
209
+ return urls
210
+
211
+
212
+ def project_item_urls(contract: EcosystemContract) -> set[str]:
213
+ data = gh_json(
214
+ "project",
215
+ "item-list",
216
+ str(contract.project.number),
217
+ "--owner",
218
+ contract.project.owner,
219
+ "--limit",
220
+ "1000",
221
+ "--format",
222
+ "json",
223
+ )
224
+ return {
225
+ item["content"]["url"]
226
+ for item in data["items"]
227
+ if item.get("content", {}).get("url")
228
+ }
229
+
230
+
231
+ def label_drift(contract: EcosystemContract) -> list[str]:
232
+ errors: list[str] = []
233
+ for repository in contract.repositories():
234
+ actual = {
235
+ label["name"]: label
236
+ for label in gh_json(
237
+ "label",
238
+ "list",
239
+ "--repo",
240
+ repository,
241
+ "--limit",
242
+ "100",
243
+ "--json",
244
+ "name,color,description",
245
+ )
246
+ }
247
+ for name, expected in contract.labels.items():
248
+ label = actual.get(name)
249
+ if label is None:
250
+ errors.append(f"{repository}: missing label {name}")
251
+ continue
252
+ if label["color"].lower() != expected.color:
253
+ errors.append(f"{repository}: label {name} has the wrong color")
254
+ if label["description"] != expected.description:
255
+ errors.append(f"{repository}: label {name} has the wrong description")
256
+ return errors
257
+
258
+
259
+ def inspect_live(contract: EcosystemContract) -> EcosystemDrift:
260
+ errors = workflow_drift(contract)
261
+ project = gh_json(
262
+ "project",
263
+ "view",
264
+ str(contract.project.number),
265
+ "--owner",
266
+ contract.project.owner,
267
+ "--format",
268
+ "json",
269
+ )
270
+ expected_project = {
271
+ "title": contract.project.title,
272
+ "public": contract.project.visibility.value == "public",
273
+ "shortDescription": contract.project.description,
274
+ "readme": contract.project_readme(),
275
+ }
276
+ for name, expected in expected_project.items():
277
+ if project[name] != expected:
278
+ errors.append(f"project {name} differs from the contract")
279
+
280
+ expected_repositories = set(contract.repositories())
281
+ actual_repositories = linked_repositories(contract)
282
+ for repository in sorted(expected_repositories - actual_repositories):
283
+ errors.append(f"project is not linked to {repository}")
284
+ for repository in sorted(actual_repositories - expected_repositories):
285
+ errors.append(f"project has unmanaged repository {repository}")
286
+
287
+ actual_fields = project_fields(contract)
288
+ for name, expected in contract.fields.items():
289
+ actual = actual_fields.get(name)
290
+ if actual is None:
291
+ errors.append(f"project is missing field {name}")
292
+ continue
293
+ if expected.type is ProjectFieldType.SINGLE_SELECT:
294
+ options = tuple(option["name"] for option in actual.get("options", ()))
295
+ if options != contract.field_options(name):
296
+ errors.append(f"project field {name} options differ from the contract")
297
+ elif actual.get("dataType", "").lower() != expected.type.value:
298
+ errors.append(f"project field {name} type differs from the contract")
299
+
300
+ missing_items = open_work_urls(contract) - project_item_urls(contract)
301
+ for url in sorted(missing_items):
302
+ errors.append(f"project is missing open work item {url}")
303
+ errors.extend(label_drift(contract))
304
+ return EcosystemDrift(
305
+ errors=tuple(errors),
306
+ manual_controls=(
307
+ "Saved Project views must be compared in the GitHub UI.",
308
+ "Project auto-add, close, merge, and archive workflows must be compared in the GitHub UI.",
309
+ ),
310
+ )
311
+
312
+
313
+ def apply_live(contract: EcosystemContract) -> None:
314
+ gh(
315
+ "project",
316
+ "edit",
317
+ str(contract.project.number),
318
+ "--owner",
319
+ contract.project.owner,
320
+ "--title",
321
+ contract.project.title,
322
+ "--visibility",
323
+ contract.project.visibility.value.upper(),
324
+ "--description",
325
+ contract.project.description,
326
+ "--readme",
327
+ contract.project_readme(),
328
+ )
329
+ linked = linked_repositories(contract)
330
+ for repository in contract.repositories():
331
+ if repository not in linked:
332
+ gh(
333
+ "project",
334
+ "link",
335
+ str(contract.project.number),
336
+ "--owner",
337
+ contract.project.owner,
338
+ "--repo",
339
+ repository,
340
+ )
341
+ for name, label in contract.labels.items():
342
+ gh(
343
+ "label",
344
+ "create",
345
+ name,
346
+ "--repo",
347
+ repository,
348
+ "--color",
349
+ label.color,
350
+ "--description",
351
+ label.description,
352
+ "--force",
353
+ )
354
+
355
+ existing_items = project_item_urls(contract)
356
+ for url in sorted(open_work_urls(contract) - existing_items):
357
+ gh(
358
+ "project",
359
+ "item-add",
360
+ str(contract.project.number),
361
+ "--owner",
362
+ contract.project.owner,
363
+ "--url",
364
+ url,
365
+ )
366
+
367
+
368
+ def parser() -> argparse.ArgumentParser:
369
+ result = argparse.ArgumentParser(description="Validate and reconcile Modwire governance")
370
+ result.add_argument(
371
+ "command",
372
+ choices=("validate", "check-live", "apply-live", "schema"),
373
+ nargs="?",
374
+ default="validate",
375
+ )
376
+ result.add_argument("--contract", type=Path, default=DEFAULT_CONTRACT)
377
+ return result
378
+
379
+
380
+ def main() -> int:
381
+ arguments = parser().parse_args()
382
+ contract = load_contract(arguments.contract)
383
+ if arguments.command == "schema":
384
+ print(json.dumps(EcosystemContract.model_json_schema(), indent=2))
385
+ return 0
386
+ if arguments.command == "validate":
387
+ errors = workflow_drift(contract)
388
+ if errors:
389
+ print(EcosystemDrift(errors=tuple(errors)).pretty())
390
+ return 1
391
+ print(
392
+ f"valid ecosystem contract: {len(contract.packages)} packages, "
393
+ f"{len(contract.fields)} project fields"
394
+ )
395
+ return 0
396
+ if arguments.command == "apply-live":
397
+ apply_live(contract)
398
+
399
+ drift = inspect_live(contract)
400
+ print(drift.pretty())
401
+ return 0 if drift.is_clean() else 1
402
+
403
+
404
+ if __name__ == "__main__":
405
+ raise SystemExit(main())
@@ -0,0 +1,30 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ pull_request:
8
+ workflow_dispatch:
9
+
10
+ permissions:
11
+ contents: read
12
+
13
+ jobs:
14
+ ecosystem-contract:
15
+ name: Ecosystem contract
16
+ runs-on: ubuntu-latest
17
+ steps:
18
+ - name: Check out repository
19
+ uses: actions/checkout@v6
20
+ - name: Set up Python
21
+ uses: actions/setup-python@v6
22
+ with:
23
+ python-version: "3.12"
24
+ - name: Install coordinator
25
+ run: python -m pip install -e .
26
+ - name: Validate ecosystem contract
27
+ run: python .github/scripts/reconcile_ecosystem.py validate
28
+
29
+ verify:
30
+ uses: ./.github/workflows/python-package.yml
@@ -0,0 +1,84 @@
1
+ name: Reusable Python package verification
2
+
3
+ on:
4
+ workflow_call:
5
+ inputs:
6
+ python-versions:
7
+ description: JSON array of supported Python versions.
8
+ required: false
9
+ type: string
10
+ default: '["3.12", "3.13", "3.14"]'
11
+ build-python-version:
12
+ description: Python version used to build distributions once.
13
+ required: false
14
+ type: string
15
+ default: "3.12"
16
+ working-directory:
17
+ description: Package directory relative to the repository root.
18
+ required: false
19
+ type: string
20
+ default: "."
21
+ upload-artifacts:
22
+ description: Upload verified distributions for later jobs.
23
+ required: false
24
+ type: boolean
25
+ default: false
26
+ artifact-name:
27
+ description: Uploaded distribution artifact name.
28
+ required: false
29
+ type: string
30
+ default: python-package-distributions
31
+
32
+ permissions:
33
+ contents: read
34
+
35
+ jobs:
36
+ verify:
37
+ name: Python ${{ matrix.python-version }}
38
+ runs-on: ubuntu-latest
39
+ strategy:
40
+ fail-fast: false
41
+ matrix:
42
+ python-version: ${{ fromJSON(inputs.python-versions) }}
43
+
44
+ defaults:
45
+ run:
46
+ working-directory: ${{ inputs.working-directory }}
47
+
48
+ steps:
49
+ - name: Check out repository
50
+ uses: actions/checkout@v6
51
+ with:
52
+ fetch-depth: 0
53
+
54
+ - name: Set up Python
55
+ uses: actions/setup-python@v6
56
+ with:
57
+ python-version: ${{ matrix.python-version }}
58
+
59
+ - name: Install package and verification tools
60
+ run: |
61
+ python -m pip install --upgrade pip
62
+ python -m pip install -e ".[dev]"
63
+
64
+ - name: Run tests
65
+ run: python -m pytest
66
+
67
+ - name: Run static checks
68
+ run: python -m ruff check .
69
+
70
+ - name: Build distributions
71
+ if: matrix.python-version == inputs.build-python-version
72
+ run: python -m build --outdir dist
73
+
74
+ - name: Check distribution metadata
75
+ if: matrix.python-version == inputs.build-python-version
76
+ run: python -m twine check dist/*
77
+
78
+ - name: Upload verified distributions
79
+ if: inputs.upload-artifacts && matrix.python-version == inputs.build-python-version
80
+ uses: actions/upload-artifact@v7
81
+ with:
82
+ name: ${{ inputs.artifact-name }}
83
+ path: ${{ inputs.working-directory }}/dist/
84
+ if-no-files-found: error