modwire 4.0.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 (106) hide show
  1. {modwire-4.0.0 → modwire-4.0.2}/.github/modwire-ecosystem.yml +3 -1
  2. {modwire-4.0.0 → modwire-4.0.2}/.github/scripts/reconcile_ecosystem.py +11 -6
  3. modwire-4.0.0/.github/workflows/python-github-release.yml → modwire-4.0.2/.github/workflows/python-release-assets.yml +7 -5
  4. {modwire-4.0.0 → modwire-4.0.2}/.github/workflows/release.yml +17 -16
  5. {modwire-4.0.0 → modwire-4.0.2}/CHANGELOG.md +14 -0
  6. {modwire-4.0.0/src/modwire.egg-info → modwire-4.0.2}/PKG-INFO +1 -1
  7. {modwire-4.0.0 → modwire-4.0.2}/docs/governance/github-ecosystem.md +5 -4
  8. {modwire-4.0.0 → modwire-4.0.2}/docs/governance/python-workflows.md +26 -22
  9. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/_version.py +3 -3
  10. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/projects/ecosystem.py +3 -1
  11. {modwire-4.0.0 → modwire-4.0.2/src/modwire.egg-info}/PKG-INFO +1 -1
  12. {modwire-4.0.0 → modwire-4.0.2}/src/modwire.egg-info/SOURCES.txt +1 -1
  13. {modwire-4.0.0 → modwire-4.0.2}/src/modwire.egg-info/scm_file_list.json +1 -1
  14. {modwire-4.0.0 → modwire-4.0.2}/src/modwire.egg-info/scm_version.json +2 -2
  15. {modwire-4.0.0 → modwire-4.0.2}/tests/test_ecosystem_contract.py +1 -0
  16. {modwire-4.0.0 → modwire-4.0.2}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  17. {modwire-4.0.0 → modwire-4.0.2}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  18. {modwire-4.0.0 → modwire-4.0.2}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  19. {modwire-4.0.0 → modwire-4.0.2}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  20. {modwire-4.0.0 → modwire-4.0.2}/.github/workflows/ci.yml +0 -0
  21. {modwire-4.0.0 → modwire-4.0.2}/.github/workflows/python-package.yml +0 -0
  22. {modwire-4.0.0 → modwire-4.0.2}/.github/workflows/python-release-build.yml +0 -0
  23. {modwire-4.0.0 → modwire-4.0.2}/.gitignore +0 -0
  24. {modwire-4.0.0 → modwire-4.0.2}/.modwire/boundaries.yaml +0 -0
  25. {modwire-4.0.0 → modwire-4.0.2}/.modwire/shape.yaml +0 -0
  26. {modwire-4.0.0 → modwire-4.0.2}/CONTRIBUTING.md +0 -0
  27. {modwire-4.0.0 → modwire-4.0.2}/LICENSE +0 -0
  28. {modwire-4.0.0 → modwire-4.0.2}/MANIFEST.in +0 -0
  29. {modwire-4.0.0 → modwire-4.0.2}/Makefile +0 -0
  30. {modwire-4.0.0 → modwire-4.0.2}/README.md +0 -0
  31. {modwire-4.0.0 → modwire-4.0.2}/docs/wiki/Development-checks.md +0 -0
  32. {modwire-4.0.0 → modwire-4.0.2}/docs/wiki/Home.md +0 -0
  33. {modwire-4.0.0 → modwire-4.0.2}/docs/wiki/Reporting-bugs.md +0 -0
  34. {modwire-4.0.0 → modwire-4.0.2}/docs/wiki/Requesting-features.md +0 -0
  35. {modwire-4.0.0 → modwire-4.0.2}/pyproject.toml +0 -0
  36. {modwire-4.0.0 → modwire-4.0.2}/setup.cfg +0 -0
  37. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/__init__.py +0 -0
  38. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/architecture/__init__.py +0 -0
  39. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/architecture/app.py +0 -0
  40. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/architecture/boundaries/__init__.py +0 -0
  41. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/architecture/boundaries/analyzer.py +0 -0
  42. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/architecture/boundaries/analyzers/__init__.py +0 -0
  43. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/architecture/boundaries/analyzers/analyzer_base.py +0 -0
  44. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/architecture/boundaries/analyzers/backward.py +0 -0
  45. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/architecture/boundaries/analyzers/no_cycles.py +0 -0
  46. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/architecture/boundaries/analyzers/no_reentry.py +0 -0
  47. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/architecture/boundaries/base.py +0 -0
  48. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/architecture/boundaries/collector.py +0 -0
  49. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/architecture/boundaries/tags/__init__.py +0 -0
  50. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/architecture/boundaries/tags/matcher.py +0 -0
  51. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/architecture/boundaries/tags/tag_map.py +0 -0
  52. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/architecture/insights/__init__.py +0 -0
  53. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/architecture/insights/base.py +0 -0
  54. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/architecture/insights/collector.py +0 -0
  55. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/architecture/insights/reporters/__init__.py +0 -0
  56. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/architecture/insights/reporters/base.py +0 -0
  57. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/architecture/insights/reporters/callables.py +0 -0
  58. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/architecture/insights/reporters/clusters.py +0 -0
  59. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/architecture/insights/reporters/coherence.py +0 -0
  60. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/architecture/insights/reporters/exports.py +0 -0
  61. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/architecture/insights/reporters/hotspots.py +0 -0
  62. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/architecture/map/__init__.py +0 -0
  63. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/architecture/map/base.py +0 -0
  64. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/architecture/map/collector.py +0 -0
  65. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/architecture/map/loader.py +0 -0
  66. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/architecture/shape/__init__.py +0 -0
  67. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/architecture/shape/base.py +0 -0
  68. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/architecture/shape/collector.py +0 -0
  69. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/architecture/shape/resolvers/__init__.py +0 -0
  70. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/architecture/shape/resolvers/abstract_class_resolver.py +0 -0
  71. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/architecture/shape/resolvers/callable_resolver.py +0 -0
  72. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/architecture/shape/resolvers/class_resolver.py +0 -0
  73. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/architecture/shape/resolvers/file_resolver.py +0 -0
  74. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/architecture/shape/resolvers/import_resolver.py +0 -0
  75. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/architecture/shape/resolvers/property_resolver.py +0 -0
  76. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/architecture/shape/resolvers/signature_resolver.py +0 -0
  77. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/architecture/shape/resolvers/symbol_resolver.py +0 -0
  78. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/code/__init__.py +0 -0
  79. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/code/package.py +0 -0
  80. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/code/reader.py +0 -0
  81. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/code/writer.py +0 -0
  82. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/facade.py +0 -0
  83. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/layers/__init__.py +0 -0
  84. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/layers/app.py +0 -0
  85. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/modules/__init__.py +0 -0
  86. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/modules/app.py +0 -0
  87. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/projects/__init__.py +0 -0
  88. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/projects/app.py +0 -0
  89. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/py.typed +0 -0
  90. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/shared/__init__.py +0 -0
  91. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/shared/base.py +0 -0
  92. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/shared/config/__init__.py +0 -0
  93. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/shared/config/architecture.py +0 -0
  94. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/shared/config/layers.py +0 -0
  95. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/shared/config/modules.py +0 -0
  96. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/shared/config/modwire.py +0 -0
  97. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/shared/config/projects.py +0 -0
  98. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/shared/config/shape.py +0 -0
  99. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/shared/report/__init__.py +0 -0
  100. {modwire-4.0.0 → modwire-4.0.2}/src/modwire/shared/report/base.py +0 -0
  101. {modwire-4.0.0 → modwire-4.0.2}/src/modwire.egg-info/dependency_links.txt +0 -0
  102. {modwire-4.0.0 → modwire-4.0.2}/src/modwire.egg-info/requires.txt +0 -0
  103. {modwire-4.0.0 → modwire-4.0.2}/src/modwire.egg-info/top_level.txt +0 -0
  104. {modwire-4.0.0 → modwire-4.0.2}/tests/test_architecture.py +0 -0
  105. {modwire-4.0.0 → modwire-4.0.2}/tests/test_models.py +0 -0
  106. {modwire-4.0.0 → modwire-4.0.2}/uv.lock +0 -0
@@ -62,7 +62,9 @@ workflows:
62
62
  release_entrypoint: .github/workflows/release.yml
63
63
  verify_reusable: .github/workflows/python-package.yml
64
64
  release_build_reusable: .github/workflows/python-release-build.yml
65
- github_release_reusable: .github/workflows/python-github-release.yml
65
+ release_assets_reusable: .github/workflows/python-release-assets.yml
66
+ release_driver: github_release
67
+ release_event: published
66
68
  release_tag_pattern: ^v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$
67
69
  artifact_name: python-package-distributions
68
70
  pypi_environment: pypi
@@ -40,7 +40,7 @@ def workflow_drift(contract: EcosystemContract) -> list[str]:
40
40
  contract.workflows.release_entrypoint,
41
41
  contract.workflows.verify_reusable,
42
42
  contract.workflows.release_build_reusable,
43
- contract.workflows.github_release_reusable,
43
+ contract.workflows.release_assets_reusable,
44
44
  )
45
45
  contents: dict[str, str] = {}
46
46
  for relative_path in workflow_paths:
@@ -74,7 +74,7 @@ def workflow_drift(contract: EcosystemContract) -> list[str]:
74
74
  required_references = {
75
75
  contract.workflows.release_entrypoint: (
76
76
  contract.workflows.release_build_reusable,
77
- contract.workflows.github_release_reusable,
77
+ contract.workflows.release_assets_reusable,
78
78
  contract.workflows.actions.download_artifact,
79
79
  contract.workflows.actions.publish_pypi,
80
80
  ),
@@ -88,7 +88,7 @@ def workflow_drift(contract: EcosystemContract) -> list[str]:
88
88
  contract.workflows.actions.setup_python,
89
89
  contract.workflows.actions.upload_artifact,
90
90
  ),
91
- contract.workflows.github_release_reusable: (
91
+ contract.workflows.release_assets_reusable: (
92
92
  contract.workflows.actions.download_artifact,
93
93
  ),
94
94
  }
@@ -102,19 +102,24 @@ def workflow_drift(contract: EcosystemContract) -> list[str]:
102
102
  "python - <<",
103
103
  "SETUPTOOLS_SCM_PRETEND_VERSION",
104
104
  "softprops/",
105
- "types: [published]",
106
105
  ):
107
106
  if forbidden in release or forbidden in release_build:
108
107
  errors.append(f"release workflows contain forbidden pattern {forbidden}")
109
108
  if contract.workflows.artifact_name not in release or contract.workflows.artifact_name not in release_build:
110
109
  errors.append("release artifact name differs from the workflow contract")
111
- github_release = contents.get(contract.workflows.github_release_reusable, "")
110
+ release_assets = contents.get(contract.workflows.release_assets_reusable, "")
112
111
  if (
113
112
  "workflow_call:" not in verify
114
113
  or "workflow_call:" not in release_build
115
- or "workflow_call:" not in github_release
114
+ or "workflow_call:" not in release_assets
116
115
  ):
117
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")
118
123
  return errors
119
124
 
120
125
 
@@ -1,10 +1,10 @@
1
- name: Reusable Python GitHub release
1
+ name: Reusable Python release assets
2
2
 
3
3
  on:
4
4
  workflow_call:
5
5
  inputs:
6
6
  release-tag:
7
- description: Existing release tag used to create the GitHub Release.
7
+ description: Published GitHub Release tag receiving the distributions.
8
8
  required: true
9
9
  type: string
10
10
  artifact-name:
@@ -18,7 +18,7 @@ permissions:
18
18
 
19
19
  jobs:
20
20
  publish:
21
- name: Create GitHub release
21
+ name: Attach distributions to GitHub release
22
22
  runs-on: ubuntu-latest
23
23
  steps:
24
24
  - name: Download release distributions
@@ -27,8 +27,10 @@ jobs:
27
27
  name: ${{ inputs.artifact-name }}
28
28
  path: dist/
29
29
 
30
- - name: Create GitHub release
30
+ - name: Upload GitHub release assets
31
31
  env:
32
32
  GH_TOKEN: ${{ github.token }}
33
33
  RELEASE_TAG: ${{ inputs.release-tag }}
34
- run: gh release create "$RELEASE_TAG" dist/* --verify-tag --generate-notes
34
+ run: >-
35
+ gh release upload "$RELEASE_TAG" dist/* --clobber
36
+ --repo "$GITHUB_REPOSITORY"
@@ -1,9 +1,8 @@
1
1
  name: Release
2
2
 
3
3
  on:
4
- push:
5
- tags:
6
- - "v*"
4
+ release:
5
+ types: [published]
7
6
 
8
7
  permissions:
9
8
  contents: read
@@ -13,11 +12,22 @@ jobs:
13
12
  name: Build release distributions
14
13
  uses: ./.github/workflows/python-release-build.yml
15
14
  with:
16
- release-tag: ${{ github.ref_name }}
15
+ release-tag: ${{ github.event.release.tag_name }}
16
+
17
+ publish-github-assets:
18
+ name: Attach distributions to GitHub release
19
+ needs: build
20
+ uses: ./.github/workflows/python-release-assets.yml
21
+ with:
22
+ release-tag: ${{ github.event.release.tag_name }}
23
+ permissions:
24
+ contents: write
17
25
 
18
26
  publish-pypi:
19
27
  name: Publish distributions to PyPI
20
- needs: build
28
+ needs:
29
+ - build
30
+ - publish-github-assets
21
31
  runs-on: ubuntu-latest
22
32
  environment:
23
33
  name: pypi
@@ -33,14 +43,5 @@ jobs:
33
43
 
34
44
  - name: Publish distributions with Trusted Publishing
35
45
  uses: pypa/gh-action-pypi-publish@release/v1
36
-
37
- publish-github:
38
- name: Publish GitHub release
39
- needs:
40
- - build
41
- - publish-pypi
42
- uses: ./.github/workflows/python-github-release.yml
43
- with:
44
- release-tag: ${{ github.ref_name }}
45
- permissions:
46
- contents: write
46
+ with:
47
+ skip-existing: true
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## 4.0.2 - 2026-07-11
4
+
5
+ ### Fixed
6
+
7
+ - Release asset uploads now target `GITHUB_REPOSITORY` explicitly when running
8
+ from a reusable workflow without a repository checkout.
9
+
10
+ ## 4.0.1 - 2026-07-11
11
+
12
+ ### Changed
13
+
14
+ - GitHub Release publication now drives distribution building, asset
15
+ attachment, and idempotent PyPI Trusted Publishing.
16
+
3
17
  ## 4.0.0 - 2026-07-11
4
18
 
5
19
  ### Breaking Changes
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modwire
3
- Version: 4.0.0
3
+ Version: 4.0.2
4
4
  Summary: Map architecture boundaries and analyze extracted code maps.
5
5
  Author: Tomasz Szpak
6
6
  License-Expression: MIT
@@ -116,7 +116,7 @@ Every coordinator epic should state:
116
116
  ## Workflow contract
117
117
 
118
118
  The complete [Python workflow contract](python-workflows.md) defines the
119
- coordinator's reusable CI, release-build, and GitHub-release workflows plus the
119
+ coordinator's reusable CI, release-build, and release-assets workflows plus the
120
120
  small repository-local entrypoints. Action versions, filenames, tag syntax,
121
121
  artifact naming, and environment naming are part of the ecosystem SSOT.
122
122
  Member repositories call a reviewed workflow-contract tag such as
@@ -132,9 +132,10 @@ The reusable workflow must always:
132
132
 
133
133
  Package release workflows remain local because publishing environments,
134
134
  package names, and PyPI Trusted Publisher identities are repository-specific.
135
- Only the credential-bearing PyPI job is local; build and GitHub Release logic
136
- come from the coordinator's reusable workflows. Releases must never require a
137
- pre-existing `.dev` directory.
135
+ Only the credential-bearing PyPI job is local; build and GitHub Release asset
136
+ logic come from the coordinator's reusable workflows. Publishing a GitHub
137
+ Release is the event that drives PyPI publication. Releases must never require
138
+ a pre-existing `.dev` directory.
138
139
 
139
140
  ## Ecosystem integration gate
140
141
 
@@ -11,29 +11,31 @@ PyPI environment are declared under `workflows` in
11
11
  | --- | --- |
12
12
  | `ci.yml` | Repository-local triggers and any package-specific supplemental checks. |
13
13
  | `python-package.yml` | Reusable Python matrix tests, Ruff, build, Twine check, and optional artifact upload. |
14
- | `release.yml` | Repository-local stable-tag trigger and PyPI Trusted Publishing job. |
14
+ | `release.yml` | Repository-local GitHub Release trigger and PyPI Trusted Publishing job. |
15
15
  | `python-release-build.yml` | Reusable strict tag validation, clean SCM-derived build, Twine check, version check, and artifact upload. |
16
- | `python-github-release.yml` | Reusable creation of the GitHub Release from the same verified artifacts. |
16
+ | `python-release-assets.yml` | Reusable attachment of verified distributions to the published GitHub Release. |
17
17
 
18
18
  CI and release entrypoints are consistently named `ci.yml` and `release.yml`.
19
19
  Reusable implementations are consistently prefixed with `python-`. Jobs use
20
- the verbs `verify`, `build`, `publish-pypi`, and `publish-github`.
20
+ the verbs `verify`, `build`, `publish-pypi`, and `publish-github-assets`.
21
21
 
22
22
  ## Release contract
23
23
 
24
24
  1. Merge only after `ci.yml` passes.
25
25
  2. Create and push a stable `vMAJOR.MINOR.PATCH` tag.
26
- 3. `release.yml` passes that existing tag to the reusable release build.
27
- 4. The build backend derives the version from the tag. Workflows never rewrite
26
+ 3. Publish a GitHub Release targeting that existing tag.
27
+ 4. The `release.published` event passes the Release tag to the reusable build.
28
+ 5. The build backend derives the version from the tag. Workflows never rewrite
28
29
  `pyproject.toml`, override setuptools-scm, or inspect wheels with embedded
29
30
  Python programs.
30
- 5. The reusable build creates one wheel and one source distribution, runs
31
+ 6. The reusable build creates one wheel and one source distribution, runs
31
32
  Twine, confirms both filenames contain the tag version, and uploads one
32
33
  immutable workflow artifact named `python-package-distributions`.
33
- 6. The repository-local `publish-pypi` job downloads that artifact and uses
34
- PyPI Trusted Publishing with only `id-token: write`.
35
- 7. After PyPI succeeds, the reusable GitHub release job creates release notes
36
- and attaches the exact same distributions.
34
+ 7. The reusable release-assets job attaches those distributions to the GitHub
35
+ Release.
36
+ 8. The repository-local `publish-pypi` job then downloads that artifact and
37
+ uses PyPI Trusted Publishing with only `id-token: write`. Publication is
38
+ idempotent so a rerun can recover a partial release without overwriting PyPI.
37
39
 
38
40
  PyPI currently does not support Trusted Publishing from a reusable workflow.
39
41
  Therefore the small `publish-pypi` job must remain directly in each
@@ -79,8 +81,8 @@ and, when necessary, reusable workflow inputs differ.
79
81
  name: Release
80
82
 
81
83
  on:
82
- push:
83
- tags: ["v*"]
84
+ release:
85
+ types: [published]
84
86
 
85
87
  permissions:
86
88
  contents: read
@@ -89,10 +91,18 @@ jobs:
89
91
  build:
90
92
  uses: 9orky/modwire/.github/workflows/python-release-build.yml@workflows-v1
91
93
  with:
92
- release-tag: ${{ github.ref_name }}
94
+ release-tag: ${{ github.event.release.tag_name }}
93
95
 
94
- publish-pypi:
96
+ publish-github-assets:
95
97
  needs: build
98
+ uses: 9orky/modwire/.github/workflows/python-release-assets.yml@workflows-v1
99
+ with:
100
+ release-tag: ${{ github.event.release.tag_name }}
101
+ permissions:
102
+ contents: write
103
+
104
+ publish-pypi:
105
+ needs: [build, publish-github-assets]
96
106
  runs-on: ubuntu-latest
97
107
  environment:
98
108
  name: pypi
@@ -105,14 +115,8 @@ jobs:
105
115
  name: python-package-distributions
106
116
  path: dist/
107
117
  - uses: pypa/gh-action-pypi-publish@release/v1
108
-
109
- publish-github:
110
- needs: [build, publish-pypi]
111
- uses: 9orky/modwire/.github/workflows/python-github-release.yml@workflows-v1
112
- with:
113
- release-tag: ${{ github.ref_name }}
114
- permissions:
115
- contents: write
118
+ with:
119
+ skip-existing: true
116
120
  ```
117
121
 
118
122
  ## Updating the standard
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '4.0.0'
22
- __version_tuple__ = version_tuple = (4, 0, 0)
21
+ __version__ = version = '4.0.2'
22
+ __version_tuple__ = version_tuple = (4, 0, 2)
23
23
 
24
- __commit_id__ = commit_id = 'g554ce1251'
24
+ __commit_id__ = commit_id = 'g614b6c4e6'
@@ -84,7 +84,9 @@ class WorkflowContract(ModwireConfigModel):
84
84
  release_entrypoint: str
85
85
  verify_reusable: str
86
86
  release_build_reusable: str
87
- github_release_reusable: str
87
+ release_assets_reusable: str
88
+ release_driver: Literal["github_release"]
89
+ release_event: Literal["published"]
88
90
  release_tag_pattern: str
89
91
  artifact_name: str
90
92
  pypi_environment: str
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modwire
3
- Version: 4.0.0
3
+ Version: 4.0.2
4
4
  Summary: Map architecture boundaries and analyze extracted code maps.
5
5
  Author: Tomasz Szpak
6
6
  License-Expression: MIT
@@ -14,8 +14,8 @@ uv.lock
14
14
  .github/ISSUE_TEMPLATE/feature_request.yml
15
15
  .github/scripts/reconcile_ecosystem.py
16
16
  .github/workflows/ci.yml
17
- .github/workflows/python-github-release.yml
18
17
  .github/workflows/python-package.yml
18
+ .github/workflows/python-release-assets.yml
19
19
  .github/workflows/python-release-build.yml
20
20
  .github/workflows/release.yml
21
21
  .modwire/boundaries.yaml
@@ -94,7 +94,7 @@
94
94
  ".github/ISSUE_TEMPLATE/feature_request.yml",
95
95
  ".github/workflows/release.yml",
96
96
  ".github/workflows/python-release-build.yml",
97
- ".github/workflows/python-github-release.yml",
97
+ ".github/workflows/python-release-assets.yml",
98
98
  ".github/workflows/ci.yml",
99
99
  ".github/workflows/python-package.yml"
100
100
  ]
@@ -1,7 +1,7 @@
1
1
  {
2
- "tag": "4.0.0",
2
+ "tag": "4.0.2",
3
3
  "distance": 0,
4
- "node": "g554ce12515b9f5d9ecbfe823166d52173117328c",
4
+ "node": "g614b6c4e6c8ae43531abb75c1caa996f7dacc3d6",
5
5
  "dirty": false,
6
6
  "branch": "HEAD",
7
7
  "node_date": "2026-07-11"
@@ -66,3 +66,4 @@ def test_workflow_contract_uses_one_action_set() -> None:
66
66
  assert "python - <<" not in contents
67
67
  assert "SETUPTOOLS_SCM_PRETEND_VERSION" not in contents
68
68
  assert "softprops/" not in contents
69
+ assert '--repo "$GITHUB_REPOSITORY"' in contents
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes