modwire 3.2.0__tar.gz → 4.0.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 (328) hide show
  1. modwire-4.0.0/.github/modwire-ecosystem.yml +169 -0
  2. modwire-4.0.0/.github/scripts/reconcile_ecosystem.py +400 -0
  3. modwire-4.0.0/.github/workflows/ci.yml +30 -0
  4. modwire-4.0.0/.github/workflows/python-github-release.yml +34 -0
  5. modwire-4.0.0/.github/workflows/python-package.yml +84 -0
  6. modwire-4.0.0/.github/workflows/python-release-build.yml +86 -0
  7. modwire-4.0.0/.github/workflows/release.yml +46 -0
  8. {modwire-3.2.0 → modwire-4.0.0}/.gitignore +1 -0
  9. modwire-4.0.0/.modwire/boundaries.yaml +44 -0
  10. modwire-4.0.0/.modwire/shape.yaml +5 -0
  11. modwire-4.0.0/CHANGELOG.md +88 -0
  12. {modwire-3.2.0 → modwire-4.0.0}/CONTRIBUTING.md +3 -1
  13. modwire-4.0.0/MANIFEST.in +1 -0
  14. modwire-4.0.0/Makefile +6 -0
  15. modwire-4.0.0/PKG-INFO +119 -0
  16. modwire-4.0.0/README.md +81 -0
  17. modwire-4.0.0/docs/governance/github-ecosystem.md +182 -0
  18. modwire-4.0.0/docs/governance/python-workflows.md +123 -0
  19. modwire-4.0.0/docs/wiki/Development-checks.md +25 -0
  20. modwire-4.0.0/docs/wiki/Home.md +27 -0
  21. {modwire-3.2.0 → modwire-4.0.0}/pyproject.toml +16 -18
  22. modwire-4.0.0/src/modwire/__init__.py +12 -0
  23. {modwire-3.2.0 → modwire-4.0.0}/src/modwire/_version.py +3 -3
  24. modwire-4.0.0/src/modwire/architecture/__init__.py +10 -0
  25. modwire-4.0.0/src/modwire/architecture/app.py +137 -0
  26. modwire-4.0.0/src/modwire/architecture/boundaries/__init__.py +8 -0
  27. modwire-4.0.0/src/modwire/architecture/boundaries/analyzer.py +56 -0
  28. modwire-4.0.0/src/modwire/architecture/boundaries/analyzers/__init__.py +1 -0
  29. modwire-4.0.0/src/modwire/architecture/boundaries/analyzers/analyzer_base.py +41 -0
  30. {modwire-3.2.0 → modwire-4.0.0}/src/modwire/architecture/boundaries/analyzers/backward.py +10 -6
  31. {modwire-3.2.0 → modwire-4.0.0}/src/modwire/architecture/boundaries/analyzers/no_cycles.py +10 -9
  32. {modwire-3.2.0 → modwire-4.0.0}/src/modwire/architecture/boundaries/analyzers/no_reentry.py +10 -9
  33. modwire-4.0.0/src/modwire/architecture/boundaries/base.py +54 -0
  34. modwire-4.0.0/src/modwire/architecture/boundaries/collector.py +32 -0
  35. modwire-4.0.0/src/modwire/architecture/boundaries/tags/__init__.py +9 -0
  36. modwire-4.0.0/src/modwire/architecture/boundaries/tags/matcher.py +135 -0
  37. {modwire-3.2.0 → modwire-4.0.0}/src/modwire/architecture/boundaries/tags/tag_map.py +6 -3
  38. modwire-4.0.0/src/modwire/architecture/insights/__init__.py +8 -0
  39. modwire-4.0.0/src/modwire/architecture/insights/base.py +14 -0
  40. modwire-4.0.0/src/modwire/architecture/insights/collector.py +31 -0
  41. modwire-4.0.0/src/modwire/architecture/insights/reporters/__init__.py +7 -0
  42. modwire-4.0.0/src/modwire/architecture/insights/reporters/base.py +43 -0
  43. modwire-4.0.0/src/modwire/architecture/insights/reporters/callables.py +60 -0
  44. {modwire-3.2.0/src/modwire/architecture/insight/reports → modwire-4.0.0/src/modwire/architecture/insights/reporters}/clusters.py +21 -19
  45. {modwire-3.2.0/src/modwire/architecture/insight/reports → modwire-4.0.0/src/modwire/architecture/insights/reporters}/coherence.py +24 -15
  46. {modwire-3.2.0/src/modwire/architecture/insight/reports → modwire-4.0.0/src/modwire/architecture/insights/reporters}/exports.py +18 -22
  47. {modwire-3.2.0/src/modwire/architecture/insight/reports → modwire-4.0.0/src/modwire/architecture/insights/reporters}/hotspots.py +25 -20
  48. modwire-4.0.0/src/modwire/architecture/map/__init__.py +11 -0
  49. modwire-4.0.0/src/modwire/architecture/map/base.py +20 -0
  50. modwire-4.0.0/src/modwire/architecture/map/collector.py +40 -0
  51. modwire-4.0.0/src/modwire/architecture/map/loader.py +63 -0
  52. modwire-4.0.0/src/modwire/architecture/shape/__init__.py +8 -0
  53. modwire-4.0.0/src/modwire/architecture/shape/base.py +92 -0
  54. modwire-4.0.0/src/modwire/architecture/shape/collector.py +42 -0
  55. {modwire-3.2.0/src/modwire/architecture/shape/rules → modwire-4.0.0/src/modwire/architecture/shape/resolvers}/abstract_class_resolver.py +22 -18
  56. {modwire-3.2.0/src/modwire/architecture/shape/rules → modwire-4.0.0/src/modwire/architecture/shape/resolvers}/callable_resolver.py +31 -31
  57. {modwire-3.2.0/src/modwire/architecture/shape/rules → modwire-4.0.0/src/modwire/architecture/shape/resolvers}/class_resolver.py +25 -22
  58. modwire-4.0.0/src/modwire/architecture/shape/resolvers/file_resolver.py +77 -0
  59. {modwire-3.2.0/src/modwire/architecture/shape/rules → modwire-4.0.0/src/modwire/architecture/shape/resolvers}/import_resolver.py +19 -12
  60. modwire-4.0.0/src/modwire/architecture/shape/resolvers/property_resolver.py +92 -0
  61. {modwire-3.2.0/src/modwire/architecture/shape/rules → modwire-4.0.0/src/modwire/architecture/shape/resolvers}/signature_resolver.py +28 -24
  62. modwire-4.0.0/src/modwire/architecture/shape/resolvers/symbol_resolver.py +33 -0
  63. modwire-4.0.0/src/modwire/code/__init__.py +10 -0
  64. modwire-4.0.0/src/modwire/code/package.py +48 -0
  65. modwire-4.0.0/src/modwire/code/reader.py +9 -0
  66. modwire-4.0.0/src/modwire/code/writer.py +27 -0
  67. modwire-4.0.0/src/modwire/facade.py +30 -0
  68. modwire-4.0.0/src/modwire/layers/__init__.py +11 -0
  69. modwire-4.0.0/src/modwire/layers/app.py +9 -0
  70. modwire-4.0.0/src/modwire/modules/__init__.py +4 -0
  71. modwire-4.0.0/src/modwire/modules/app.py +9 -0
  72. modwire-4.0.0/src/modwire/projects/__init__.py +43 -0
  73. modwire-4.0.0/src/modwire/projects/app.py +9 -0
  74. modwire-4.0.0/src/modwire/projects/ecosystem.py +267 -0
  75. modwire-4.0.0/src/modwire/shared/__init__.py +19 -0
  76. modwire-4.0.0/src/modwire/shared/base.py +76 -0
  77. modwire-4.0.0/src/modwire/shared/config/__init__.py +36 -0
  78. modwire-4.0.0/src/modwire/shared/config/architecture.py +67 -0
  79. modwire-4.0.0/src/modwire/shared/config/layers.py +30 -0
  80. modwire-4.0.0/src/modwire/shared/config/modules.py +18 -0
  81. modwire-4.0.0/src/modwire/shared/config/modwire.py +54 -0
  82. modwire-4.0.0/src/modwire/shared/config/projects.py +27 -0
  83. modwire-3.2.0/src/modwire/architecture/shape/config.py → modwire-4.0.0/src/modwire/shared/config/shape.py +8 -13
  84. modwire-4.0.0/src/modwire/shared/report/__init__.py +18 -0
  85. modwire-4.0.0/src/modwire/shared/report/base.py +105 -0
  86. modwire-4.0.0/src/modwire.egg-info/PKG-INFO +119 -0
  87. modwire-4.0.0/src/modwire.egg-info/SOURCES.txt +104 -0
  88. modwire-4.0.0/src/modwire.egg-info/requires.txt +11 -0
  89. modwire-4.0.0/src/modwire.egg-info/scm_file_list.json +101 -0
  90. modwire-4.0.0/src/modwire.egg-info/scm_version.json +8 -0
  91. modwire-4.0.0/tests/test_architecture.py +19 -0
  92. modwire-4.0.0/tests/test_ecosystem_contract.py +68 -0
  93. modwire-4.0.0/tests/test_models.py +60 -0
  94. {modwire-3.2.0 → modwire-4.0.0}/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.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  318. {modwire-3.2.0 → modwire-4.0.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  319. {modwire-3.2.0 → modwire-4.0.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  320. {modwire-3.2.0 → modwire-4.0.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  321. {modwire-3.2.0 → modwire-4.0.0}/LICENSE +0 -0
  322. {modwire-3.2.0 → modwire-4.0.0}/docs/wiki/Reporting-bugs.md +0 -0
  323. {modwire-3.2.0 → modwire-4.0.0}/docs/wiki/Requesting-features.md +0 -0
  324. {modwire-3.2.0 → modwire-4.0.0}/setup.cfg +0 -0
  325. {modwire-3.2.0/src/modwire/architecture/boundaries → modwire-4.0.0/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.0/src/modwire/py.typed +0 -0
  327. {modwire-3.2.0 → modwire-4.0.0}/src/modwire.egg-info/dependency_links.txt +0 -0
  328. {modwire-3.2.0 → modwire-4.0.0}/src/modwire.egg-info/top_level.txt +0 -0
@@ -0,0 +1,169 @@
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
+ github_release_reusable: .github/workflows/python-github-release.yml
66
+ release_tag_pattern: ^v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$
67
+ artifact_name: python-package-distributions
68
+ pypi_environment: pypi
69
+ actions:
70
+ checkout: actions/checkout@v6
71
+ setup_python: actions/setup-python@v6
72
+ upload_artifact: actions/upload-artifact@v7
73
+ download_artifact: actions/download-artifact@v8
74
+ publish_pypi: pypa/gh-action-pypi-publish@release/v1
75
+
76
+ fields:
77
+ Status:
78
+ type: single_select
79
+ options: [Inbox, Ready, In progress, Blocked, Review, Done]
80
+ Horizon:
81
+ type: single_select
82
+ options: [Now, Next, Later]
83
+ Priority:
84
+ type: single_select
85
+ options: [P0, P1, P2, P3]
86
+ Component:
87
+ type: single_select
88
+ source: packages
89
+ Release train:
90
+ type: text
91
+ Target date:
92
+ type: date
93
+ Risk:
94
+ type: single_select
95
+ options: [Low, Medium, High]
96
+
97
+ views:
98
+ - name: Roadmap
99
+ layout: roadmap
100
+ group_by: Release train
101
+ slice_by: Component
102
+ - name: Now
103
+ layout: board
104
+ filter: "Horizon:Now -Status:Done"
105
+ group_by: Status
106
+ - name: By package
107
+ layout: table
108
+ filter: "-Status:Done"
109
+ group_by: Repository
110
+ - name: Blocked
111
+ layout: table
112
+ filter: "Status:Blocked"
113
+ group_by: Component
114
+ - name: Release readiness
115
+ layout: table
116
+ filter: "has:\"Release train\" -Status:Done"
117
+ group_by: Release train
118
+ - name: Inbox
119
+ layout: table
120
+ filter: "Status:Inbox"
121
+
122
+ labels:
123
+ "type:bug":
124
+ color: "d73a4a"
125
+ description: Incorrect existing behavior
126
+ "type:feature":
127
+ color: "0e8a16"
128
+ description: New user-facing capability
129
+ "type:maintenance":
130
+ color: "c5def5"
131
+ description: Internal maintenance
132
+ "type:docs":
133
+ color: "0075ca"
134
+ description: Documentation
135
+ ecosystem:
136
+ color: "5319e7"
137
+ description: Cross-package coordination
138
+ contract:
139
+ color: "1d76db"
140
+ description: Public contract or compatibility work
141
+ breaking:
142
+ color: "b60205"
143
+ description: Backward-incompatible change
144
+ blocked:
145
+ color: "e99695"
146
+ description: Blocked by another decision or delivery
147
+ release-gate:
148
+ color: "fbca04"
149
+ description: Must complete before a release
150
+
151
+ automation:
152
+ auto_add_filter: "is:open"
153
+ added_status: Inbox
154
+ closed_status: Done
155
+ merged_status: Done
156
+ archive_filter: "Status:Done updated:<@today-30d"
157
+
158
+ milestones:
159
+ scope: repository
160
+ naming: "<version-or-phase>: <outcome>"
161
+ close_when_complete: true
162
+ ecosystem_coordination_field: Release train
163
+ cross_repository_work: parent_issue_in_modwire_with_sub_issues
164
+
165
+ cadence:
166
+ triage: weekly
167
+ roadmap_review: monthly
168
+ release_readiness: before_each_package_release
169
+ project_status_update: monthly
@@ -0,0 +1,400 @@
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.github_release_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.github_release_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.github_release_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
+ "types: [published]",
106
+ ):
107
+ if forbidden in release or forbidden in release_build:
108
+ errors.append(f"release workflows contain forbidden pattern {forbidden}")
109
+ if contract.workflows.artifact_name not in release or contract.workflows.artifact_name not in release_build:
110
+ errors.append("release artifact name differs from the workflow contract")
111
+ github_release = contents.get(contract.workflows.github_release_reusable, "")
112
+ if (
113
+ "workflow_call:" not in verify
114
+ or "workflow_call:" not in release_build
115
+ or "workflow_call:" not in github_release
116
+ ):
117
+ errors.append("reusable workflows must use workflow_call")
118
+ return errors
119
+
120
+
121
+ def project_fields(contract: EcosystemContract) -> dict[str, dict[str, Any]]:
122
+ query = """
123
+ query($id: ID!) {
124
+ node(id: $id) {
125
+ ... on ProjectV2 {
126
+ fields(first: 100) {
127
+ nodes {
128
+ __typename
129
+ ... on ProjectV2Field { id name dataType }
130
+ ... on ProjectV2SingleSelectField { id name options { name } }
131
+ }
132
+ }
133
+ }
134
+ }
135
+ }
136
+ """
137
+ project = gh_json(
138
+ "project",
139
+ "view",
140
+ str(contract.project.number),
141
+ "--owner",
142
+ contract.project.owner,
143
+ "--format",
144
+ "json",
145
+ )
146
+ data = gh_json(
147
+ "api",
148
+ "graphql",
149
+ "-F",
150
+ f"id={project['id']}",
151
+ "-f",
152
+ f"query={query}",
153
+ )
154
+ nodes = data["data"]["node"]["fields"]["nodes"]
155
+ return {node["name"]: node for node in nodes if node.get("name")}
156
+
157
+
158
+ def linked_repositories(contract: EcosystemContract) -> set[str]:
159
+ query = """
160
+ query($id: ID!) {
161
+ node(id: $id) {
162
+ ... on ProjectV2 { repositories(first: 100) { nodes { nameWithOwner } } }
163
+ }
164
+ }
165
+ """
166
+ project = gh_json(
167
+ "project",
168
+ "view",
169
+ str(contract.project.number),
170
+ "--owner",
171
+ contract.project.owner,
172
+ "--format",
173
+ "json",
174
+ )
175
+ data = gh_json(
176
+ "api",
177
+ "graphql",
178
+ "-F",
179
+ f"id={project['id']}",
180
+ "-f",
181
+ f"query={query}",
182
+ )
183
+ nodes = data["data"]["node"]["repositories"]["nodes"]
184
+ return {node["nameWithOwner"] for node in nodes}
185
+
186
+
187
+ def open_work_urls(contract: EcosystemContract) -> set[str]:
188
+ urls: set[str] = set()
189
+ for repository in contract.repositories():
190
+ for kind in ("issue", "pr"):
191
+ items = gh_json(
192
+ kind,
193
+ "list",
194
+ "--repo",
195
+ repository,
196
+ "--state",
197
+ "open",
198
+ "--limit",
199
+ "100",
200
+ "--json",
201
+ "url",
202
+ )
203
+ urls.update(item["url"] for item in items)
204
+ return urls
205
+
206
+
207
+ def project_item_urls(contract: EcosystemContract) -> set[str]:
208
+ data = gh_json(
209
+ "project",
210
+ "item-list",
211
+ str(contract.project.number),
212
+ "--owner",
213
+ contract.project.owner,
214
+ "--limit",
215
+ "1000",
216
+ "--format",
217
+ "json",
218
+ )
219
+ return {
220
+ item["content"]["url"]
221
+ for item in data["items"]
222
+ if item.get("content", {}).get("url")
223
+ }
224
+
225
+
226
+ def label_drift(contract: EcosystemContract) -> list[str]:
227
+ errors: list[str] = []
228
+ for repository in contract.repositories():
229
+ actual = {
230
+ label["name"]: label
231
+ for label in gh_json(
232
+ "label",
233
+ "list",
234
+ "--repo",
235
+ repository,
236
+ "--limit",
237
+ "100",
238
+ "--json",
239
+ "name,color,description",
240
+ )
241
+ }
242
+ for name, expected in contract.labels.items():
243
+ label = actual.get(name)
244
+ if label is None:
245
+ errors.append(f"{repository}: missing label {name}")
246
+ continue
247
+ if label["color"].lower() != expected.color:
248
+ errors.append(f"{repository}: label {name} has the wrong color")
249
+ if label["description"] != expected.description:
250
+ errors.append(f"{repository}: label {name} has the wrong description")
251
+ return errors
252
+
253
+
254
+ def inspect_live(contract: EcosystemContract) -> EcosystemDrift:
255
+ errors = workflow_drift(contract)
256
+ project = gh_json(
257
+ "project",
258
+ "view",
259
+ str(contract.project.number),
260
+ "--owner",
261
+ contract.project.owner,
262
+ "--format",
263
+ "json",
264
+ )
265
+ expected_project = {
266
+ "title": contract.project.title,
267
+ "public": contract.project.visibility.value == "public",
268
+ "shortDescription": contract.project.description,
269
+ "readme": contract.project_readme(),
270
+ }
271
+ for name, expected in expected_project.items():
272
+ if project[name] != expected:
273
+ errors.append(f"project {name} differs from the contract")
274
+
275
+ expected_repositories = set(contract.repositories())
276
+ actual_repositories = linked_repositories(contract)
277
+ for repository in sorted(expected_repositories - actual_repositories):
278
+ errors.append(f"project is not linked to {repository}")
279
+ for repository in sorted(actual_repositories - expected_repositories):
280
+ errors.append(f"project has unmanaged repository {repository}")
281
+
282
+ actual_fields = project_fields(contract)
283
+ for name, expected in contract.fields.items():
284
+ actual = actual_fields.get(name)
285
+ if actual is None:
286
+ errors.append(f"project is missing field {name}")
287
+ continue
288
+ if expected.type is ProjectFieldType.SINGLE_SELECT:
289
+ options = tuple(option["name"] for option in actual.get("options", ()))
290
+ if options != contract.field_options(name):
291
+ errors.append(f"project field {name} options differ from the contract")
292
+ elif actual.get("dataType", "").lower() != expected.type.value:
293
+ errors.append(f"project field {name} type differs from the contract")
294
+
295
+ missing_items = open_work_urls(contract) - project_item_urls(contract)
296
+ for url in sorted(missing_items):
297
+ errors.append(f"project is missing open work item {url}")
298
+ errors.extend(label_drift(contract))
299
+ return EcosystemDrift(
300
+ errors=tuple(errors),
301
+ manual_controls=(
302
+ "Saved Project views must be compared in the GitHub UI.",
303
+ "Project auto-add, close, merge, and archive workflows must be compared in the GitHub UI.",
304
+ ),
305
+ )
306
+
307
+
308
+ def apply_live(contract: EcosystemContract) -> None:
309
+ gh(
310
+ "project",
311
+ "edit",
312
+ str(contract.project.number),
313
+ "--owner",
314
+ contract.project.owner,
315
+ "--title",
316
+ contract.project.title,
317
+ "--visibility",
318
+ contract.project.visibility.value.upper(),
319
+ "--description",
320
+ contract.project.description,
321
+ "--readme",
322
+ contract.project_readme(),
323
+ )
324
+ linked = linked_repositories(contract)
325
+ for repository in contract.repositories():
326
+ if repository not in linked:
327
+ gh(
328
+ "project",
329
+ "link",
330
+ str(contract.project.number),
331
+ "--owner",
332
+ contract.project.owner,
333
+ "--repo",
334
+ repository,
335
+ )
336
+ for name, label in contract.labels.items():
337
+ gh(
338
+ "label",
339
+ "create",
340
+ name,
341
+ "--repo",
342
+ repository,
343
+ "--color",
344
+ label.color,
345
+ "--description",
346
+ label.description,
347
+ "--force",
348
+ )
349
+
350
+ existing_items = project_item_urls(contract)
351
+ for url in sorted(open_work_urls(contract) - existing_items):
352
+ gh(
353
+ "project",
354
+ "item-add",
355
+ str(contract.project.number),
356
+ "--owner",
357
+ contract.project.owner,
358
+ "--url",
359
+ url,
360
+ )
361
+
362
+
363
+ def parser() -> argparse.ArgumentParser:
364
+ result = argparse.ArgumentParser(description="Validate and reconcile Modwire governance")
365
+ result.add_argument(
366
+ "command",
367
+ choices=("validate", "check-live", "apply-live", "schema"),
368
+ nargs="?",
369
+ default="validate",
370
+ )
371
+ result.add_argument("--contract", type=Path, default=DEFAULT_CONTRACT)
372
+ return result
373
+
374
+
375
+ def main() -> int:
376
+ arguments = parser().parse_args()
377
+ contract = load_contract(arguments.contract)
378
+ if arguments.command == "schema":
379
+ print(json.dumps(EcosystemContract.model_json_schema(), indent=2))
380
+ return 0
381
+ if arguments.command == "validate":
382
+ errors = workflow_drift(contract)
383
+ if errors:
384
+ print(EcosystemDrift(errors=tuple(errors)).pretty())
385
+ return 1
386
+ print(
387
+ f"valid ecosystem contract: {len(contract.packages)} packages, "
388
+ f"{len(contract.fields)} project fields"
389
+ )
390
+ return 0
391
+ if arguments.command == "apply-live":
392
+ apply_live(contract)
393
+
394
+ drift = inspect_live(contract)
395
+ print(drift.pretty())
396
+ return 0 if drift.is_clean() else 1
397
+
398
+
399
+ if __name__ == "__main__":
400
+ 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,34 @@
1
+ name: Reusable Python GitHub release
2
+
3
+ on:
4
+ workflow_call:
5
+ inputs:
6
+ release-tag:
7
+ description: Existing release tag used to create the GitHub Release.
8
+ required: true
9
+ type: string
10
+ artifact-name:
11
+ description: Name of the verified distribution artifact.
12
+ required: false
13
+ type: string
14
+ default: python-package-distributions
15
+
16
+ permissions:
17
+ contents: write
18
+
19
+ jobs:
20
+ publish:
21
+ name: Create GitHub release
22
+ runs-on: ubuntu-latest
23
+ steps:
24
+ - name: Download release distributions
25
+ uses: actions/download-artifact@v8
26
+ with:
27
+ name: ${{ inputs.artifact-name }}
28
+ path: dist/
29
+
30
+ - name: Create GitHub release
31
+ env:
32
+ GH_TOKEN: ${{ github.token }}
33
+ RELEASE_TAG: ${{ inputs.release-tag }}
34
+ run: gh release create "$RELEASE_TAG" dist/* --verify-tag --generate-notes