ezcompiler 2.3.4__tar.gz → 2.4.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 (111) hide show
  1. ezcompiler-2.4.0/.github/workflows/auto-tag.yml +110 -0
  2. ezcompiler-2.4.0/.github/workflows/ci-usage.md +76 -0
  3. ezcompiler-2.4.0/.github/workflows/ci.yml +89 -0
  4. ezcompiler-2.4.0/.github/workflows/docs-usage.md +91 -0
  5. ezcompiler-2.4.0/.github/workflows/docs.yml +84 -0
  6. ezcompiler-2.4.0/.github/workflows/publish-pypi-usage.md +97 -0
  7. ezcompiler-2.4.0/.github/workflows/publish-pypi.yml +121 -0
  8. ezcompiler-2.4.0/.markdownlint.yaml +38 -0
  9. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/.pre-commit-config.yaml +40 -41
  10. ezcompiler-2.4.0/.scripts/dev/check_merge_conflict.py +33 -0
  11. ezcompiler-2.4.0/.scripts/dev/check_toml.py +26 -0
  12. ezcompiler-2.4.0/.scripts/dev/check_yaml.py +33 -0
  13. ezcompiler-2.4.0/AGENTS.md +149 -0
  14. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/PKG-INFO +36 -18
  15. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/README.md +19 -11
  16. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/mkdocs.yml +17 -3
  17. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/pyproject.toml +20 -10
  18. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/src/ezcompiler/_version.py +1 -1
  19. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/src/ezcompiler/adapters/_pyinstaller_compiler.py +3 -0
  20. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/src/ezcompiler/adapters/base_compiler.py +4 -0
  21. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/src/ezcompiler/adapters/base_uploader.py +2 -0
  22. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/src/ezcompiler/adapters/compiler_factory.py +43 -4
  23. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/src/ezcompiler/interfaces/cli_interface.py +7 -4
  24. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/src/ezcompiler/interfaces/python_api.py +10 -4
  25. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/src/ezcompiler/services/compiler_service.py +2 -2
  26. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/src/ezcompiler/services/pipeline_service.py +6 -3
  27. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/src/ezcompiler/shared/_compilation_result.py +2 -0
  28. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/src/ezcompiler/shared/exceptions/services/_base.py +4 -0
  29. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/src/ezcompiler/utils/_compiler_utils.py +3 -0
  30. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/src/ezcompiler/utils/_zip_utils.py +4 -6
  31. ezcompiler-2.4.0/uv.lock +1823 -0
  32. ezcompiler-2.4.0/uv.toml +3 -0
  33. ezcompiler-2.3.4/.clinerules +0 -29
  34. ezcompiler-2.3.4/.github/instructions/README.md +0 -1015
  35. ezcompiler-2.3.4/.github/instructions/core/advanced-cognitive-conduct.instructions.md +0 -299
  36. ezcompiler-2.3.4/.github/instructions/core/commit-standards.instructions.md +0 -139
  37. ezcompiler-2.3.4/.github/instructions/core/hexagonal-architecture-standards.instructions.md +0 -601
  38. ezcompiler-2.3.4/.github/instructions/languages/python/pyproject-standards.instructions.md +0 -402
  39. ezcompiler-2.3.4/.github/instructions/languages/python/python-development-standards.instructions.md +0 -347
  40. ezcompiler-2.3.4/.github/instructions/languages/python/python-formatting-standards.instructions.md +0 -419
  41. ezcompiler-2.3.4/.github/workflows/README_DOC.md +0 -492
  42. ezcompiler-2.3.4/.github/workflows/README_PUBLISH.md +0 -301
  43. ezcompiler-2.3.4/.github/workflows/auto-tag.yml +0 -206
  44. ezcompiler-2.3.4/.github/workflows/docs.yml +0 -80
  45. ezcompiler-2.3.4/.github/workflows/publish-pypi.yml +0 -182
  46. ezcompiler-2.3.4/AGENTS.md +0 -87
  47. ezcompiler-2.3.4/CLAUDE.md +0 -98
  48. ezcompiler-2.3.4/uv.lock +0 -2048
  49. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/.gitignore +0 -0
  50. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/.scripts/build/build_package.py +0 -0
  51. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/.scripts/build/upload_to_pypi.py +0 -0
  52. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/.scripts/dev/generate_architecture_graph.py +0 -0
  53. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/.scripts/dev/lint.py +0 -0
  54. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/.scripts/dev/update_version.py +0 -0
  55. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/LICENSE +0 -0
  56. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/MANIFEST.in +0 -0
  57. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/cliff.toml +0 -0
  58. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/herald.config.json +0 -0
  59. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/requirements-dev.in +0 -0
  60. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/requirements.in +0 -0
  61. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/src/ezcompiler/__init__.py +0 -0
  62. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/src/ezcompiler/adapters/__init__.py +0 -0
  63. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/src/ezcompiler/adapters/_cx_freeze_compiler.py +0 -0
  64. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/src/ezcompiler/adapters/_disk_file_writer.py +0 -0
  65. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/src/ezcompiler/adapters/_disk_uploader.py +0 -0
  66. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/src/ezcompiler/adapters/_nuitka_compiler.py +0 -0
  67. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/src/ezcompiler/adapters/_server_uploader.py +0 -0
  68. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/src/ezcompiler/adapters/base_file_writer.py +0 -0
  69. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/src/ezcompiler/adapters/uploader_factory.py +0 -0
  70. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/src/ezcompiler/assets/__init__.py +0 -0
  71. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/src/ezcompiler/assets/templates/__init__.py +0 -0
  72. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/src/ezcompiler/assets/templates/_template_loader.py +0 -0
  73. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/src/ezcompiler/assets/templates/config/config.json.template +0 -0
  74. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/src/ezcompiler/assets/templates/config/config.yaml.template +0 -0
  75. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/src/ezcompiler/assets/templates/setup/setup.py.template +0 -0
  76. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/src/ezcompiler/assets/templates/version/version_info.txt.template +0 -0
  77. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/src/ezcompiler/interfaces/__init__.py +0 -0
  78. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/src/ezcompiler/py.typed +0 -0
  79. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/src/ezcompiler/services/__init__.py +0 -0
  80. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/src/ezcompiler/services/config_service.py +0 -0
  81. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/src/ezcompiler/services/template_service.py +0 -0
  82. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/src/ezcompiler/services/uploader_service.py +0 -0
  83. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/src/ezcompiler/shared/__init__.py +0 -0
  84. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/src/ezcompiler/shared/_compiler_config.py +0 -0
  85. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/src/ezcompiler/shared/exceptions/__init__.py +0 -0
  86. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/src/ezcompiler/shared/exceptions/services/__init__.py +0 -0
  87. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/src/ezcompiler/shared/exceptions/services/_service_exceptions.py +0 -0
  88. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/src/ezcompiler/shared/exceptions/utils/__init__.py +0 -0
  89. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/src/ezcompiler/shared/exceptions/utils/_base.py +0 -0
  90. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/src/ezcompiler/shared/exceptions/utils/_compiler_exceptions.py +0 -0
  91. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/src/ezcompiler/shared/exceptions/utils/_config_exceptions.py +0 -0
  92. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/src/ezcompiler/shared/exceptions/utils/_file_exceptions.py +0 -0
  93. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/src/ezcompiler/shared/exceptions/utils/_template_exceptions.py +0 -0
  94. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/src/ezcompiler/shared/exceptions/utils/_uploader_exceptions.py +0 -0
  95. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/src/ezcompiler/shared/exceptions/utils/_validation_exceptions.py +0 -0
  96. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/src/ezcompiler/shared/exceptions/utils/_zip_exceptions.py +0 -0
  97. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/src/ezcompiler/types.py +0 -0
  98. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/src/ezcompiler/utils/__init__.py +0 -0
  99. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/src/ezcompiler/utils/_config_utils.py +0 -0
  100. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/src/ezcompiler/utils/_file_utils.py +0 -0
  101. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/src/ezcompiler/utils/_template_utils.py +0 -0
  102. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/src/ezcompiler/utils/_uploader_utils.py +0 -0
  103. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/src/ezcompiler/utils/validators/__init__.py +0 -0
  104. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/src/ezcompiler/utils/validators/domain_validators.py +0 -0
  105. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/src/ezcompiler/utils/validators/format_validators.py +0 -0
  106. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/src/ezcompiler/utils/validators/meta_validators.py +0 -0
  107. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/src/ezcompiler/utils/validators/path_validators.py +0 -0
  108. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/src/ezcompiler/utils/validators/schema_validators.py +0 -0
  109. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/src/ezcompiler/utils/validators/string_validators.py +0 -0
  110. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/src/ezcompiler/utils/validators/type_validators.py +0 -0
  111. {ezcompiler-2.3.4 → ezcompiler-2.4.0}/src/ezcompiler/utils/validators/value_validators.py +0 -0
@@ -0,0 +1,110 @@
1
+ name: Auto Tag
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ workflow_dispatch:
7
+
8
+ permissions: {}
9
+
10
+ concurrency:
11
+ group: auto-tag-${{ github.ref }}
12
+ cancel-in-progress: false
13
+
14
+ jobs:
15
+ auto-tag:
16
+ name: Create and Push Tags
17
+ runs-on: ubuntu-24.04
18
+ permissions:
19
+ contents: write
20
+ outputs:
21
+ tag_action: ${{ steps.create_tags.outputs.tag_action }}
22
+ version: ${{ steps.version.outputs.version }}
23
+ tag_name: ${{ steps.create_tags.outputs.tag_name }}
24
+
25
+ steps:
26
+ - uses: actions/checkout@9f698171ed81b15d1823a05fc7211befd50c8ae0 # v6.0.3
27
+ with:
28
+ fetch-depth: 0
29
+
30
+ - name: Extract version from pyproject.toml
31
+ id: version
32
+ run: |
33
+ VERSION=$(grep -E '^version\s*=\s*"' pyproject.toml | head -1 | sed 's/.*version\s*=\s*"\([^"]*\)".*/\1/')
34
+ if [ -z "$VERSION" ]; then
35
+ echo "::error::No version found in pyproject.toml"
36
+ exit 1
37
+ fi
38
+ echo "version=$VERSION" >> $GITHUB_OUTPUT
39
+ echo "Version: $VERSION"
40
+
41
+ - name: Create and push tags
42
+ id: create_tags
43
+ run: |
44
+ VERSION="${{ steps.version.outputs.version }}"
45
+ TAG_NAME="v$VERSION"
46
+ MAJOR=$(echo "$VERSION" | cut -d. -f1)
47
+ LATEST_TAG="v${MAJOR}-latest"
48
+
49
+ git config user.name "github-actions[bot]"
50
+ git config user.email "github-actions[bot]@users.noreply.github.com"
51
+
52
+ if git rev-parse "$TAG_NAME" >/dev/null 2>&1; then
53
+ TAG_SHA=$(git rev-parse "$TAG_NAME")
54
+ HEAD_SHA=$(git rev-parse HEAD)
55
+ if [ "$TAG_SHA" = "$HEAD_SHA" ]; then
56
+ echo "tag_action=none" >> $GITHUB_OUTPUT
57
+ echo "tag_name=$TAG_NAME" >> $GITHUB_OUTPUT
58
+ echo "Tag $TAG_NAME already points to HEAD — nothing to do"
59
+ else
60
+ git tag -f "$TAG_NAME"
61
+ git tag -f "$LATEST_TAG"
62
+ git push origin --force "$TAG_NAME"
63
+ git push origin --force "$LATEST_TAG"
64
+ echo "tag_action=update" >> $GITHUB_OUTPUT
65
+ echo "tag_name=$TAG_NAME" >> $GITHUB_OUTPUT
66
+ echo "🔄 Tags moved to HEAD: $TAG_NAME, $LATEST_TAG (no publish — version unchanged)"
67
+ fi
68
+ else
69
+ git tag "$TAG_NAME"
70
+ git tag -f "$LATEST_TAG"
71
+ git push origin "$TAG_NAME"
72
+ git push origin --force "$LATEST_TAG"
73
+ echo "tag_action=create" >> $GITHUB_OUTPUT
74
+ echo "tag_name=$TAG_NAME" >> $GITHUB_OUTPUT
75
+ echo "✅ Tags pushed: $TAG_NAME, $LATEST_TAG"
76
+ fi
77
+
78
+ - name: Summary
79
+ if: steps.create_tags.outputs.tag_action != 'none'
80
+ run: |
81
+ echo "## 🏷️ Auto-Tagging Summary" >> $GITHUB_STEP_SUMMARY
82
+ echo "- **Action**: ${{ steps.create_tags.outputs.tag_action }}" >> $GITHUB_STEP_SUMMARY
83
+ echo "- **Version**: ${{ steps.version.outputs.version }}" >> $GITHUB_STEP_SUMMARY
84
+ echo "- **Tag**: ${{ steps.create_tags.outputs.tag_name }}" >> $GITHUB_STEP_SUMMARY
85
+
86
+ trigger-publish:
87
+ name: Trigger Publish
88
+ needs: auto-tag
89
+ if: needs.auto-tag.outputs.tag_action == 'create'
90
+ permissions:
91
+ contents: read
92
+ id-token: write
93
+ uses: ./.github/workflows/publish-pypi.yml
94
+ with:
95
+ version: ${{ needs.auto-tag.outputs.version }}
96
+ tag: ${{ needs.auto-tag.outputs.tag_name }}
97
+
98
+ trigger-deploy-docs:
99
+ name: Trigger Deploy Docs
100
+ needs: [auto-tag, trigger-publish]
101
+ if: |
102
+ always() &&
103
+ needs.auto-tag.result == 'success' &&
104
+ needs.auto-tag.outputs.tag_action != 'none' &&
105
+ (needs.trigger-publish.result == 'success' || needs.trigger-publish.result == 'skipped')
106
+ permissions:
107
+ contents: write
108
+ uses: ./.github/workflows/docs.yml
109
+ with:
110
+ deploy: true
@@ -0,0 +1,76 @@
1
+ # CI Workflow
2
+
3
+ `ci.yml` runs on every push (all branches), every pull request, and manually via
4
+ `workflow_dispatch`. It is the primary quality gate — release workflows never run
5
+ if this one is red.
6
+
7
+ ## Triggers
8
+
9
+ | Event | Branches |
10
+ | ------------------- | -------- |
11
+ | `push` | all |
12
+ | `pull_request` | all |
13
+ | `workflow_dispatch` | manual |
14
+
15
+ Concurrent runs on the same ref are cancelled automatically (`cancel-in-progress: true`,
16
+ group `ci-$ref`). Deploy jobs are never affected because they live in separate workflows.
17
+
18
+ ## Jobs
19
+
20
+ ```text
21
+ lint ──┐
22
+ ├──► test (Python 3.13)
23
+ type-check ──┘
24
+ ```
25
+
26
+ `lint` and `type-check` run in parallel; `test` needs both.
27
+
28
+ ### `lint` — Lint & Format Check
29
+
30
+ Timeout: 15 min. Steps:
31
+
32
+ 1. `uv sync --frozen --extra dev`
33
+ 2. `ruff check .` — lint
34
+ 3. `ruff format --check .` — format check (read-only, never auto-fixes)
35
+
36
+ ### `type-check` — Type Check & Import Contracts
37
+
38
+ Timeout: 15 min. Steps:
39
+
40
+ 1. `uv sync --frozen --extra dev`
41
+ 2. `uv run ty check` — type check (configured via `[tool.ty]` in `pyproject.toml`)
42
+ 3. `uv run pyright` — type check complémentaire (configured via `[tool.pyright]`)
43
+ 4. `PYTHONPATH=src uv run lint-imports` — import-linter contracts (couches hexagonales)
44
+
45
+ ### `test` — pytest
46
+
47
+ Needs: `[lint, type-check]`. Timeout: 25 min. Python **3.13 only** (`fail-fast: false`).
48
+
49
+ Steps:
50
+
51
+ 1. `uv sync --frozen --extra dev`
52
+ 2. `uv run pytest` — reads `pyproject.toml`, applies `--cov-fail-under=70`
53
+ 3. Upload `coverage.xml` + `htmlcov/` as artifact — **always** (even on failure), retained 7 days
54
+
55
+ ## Local equivalent
56
+
57
+ ```bash
58
+ # Quality gate
59
+ uv run ruff check .
60
+ uv run ruff format --check .
61
+ uv run ty check
62
+ uv run pyright
63
+ PYTHONPATH=src uv run lint-imports
64
+
65
+ # Tests
66
+ uv run pytest
67
+ ```
68
+
69
+ ## Notes
70
+
71
+ - The install is always frozen (`uv sync --frozen`). Never mutates `uv.lock`.
72
+ - `ruff check` and `ruff format --check` are read-only — they never auto-fix.
73
+ - Both `ty` and `pyright` are configured in `pyproject.toml` and run in CI.
74
+ - Import contracts are enforced by import-linter against the hexagonal layer
75
+ contracts defined in `[tool.importlinter]`. Adding a cross-layer import
76
+ without updating the contracts will fail this job.
@@ -0,0 +1,89 @@
1
+ name: CI
2
+
3
+ # Runs on every push to main and on pull requests.
4
+ # Quality gates (lint, type-check) run first and block the test matrix.
5
+
6
+ on:
7
+ push:
8
+ branches: [main]
9
+ paths:
10
+ - "src/**"
11
+ - "tests/**"
12
+ - "pyproject.toml"
13
+ - "uv.lock"
14
+ - ".github/workflows/ci.yml"
15
+ pull_request:
16
+ branches: [main]
17
+ paths:
18
+ - "src/**"
19
+ - "tests/**"
20
+ - "pyproject.toml"
21
+ - "uv.lock"
22
+ - ".github/workflows/ci.yml"
23
+ workflow_dispatch:
24
+
25
+ permissions: {}
26
+
27
+ concurrency:
28
+ group: ci-${{ github.ref }}
29
+ cancel-in-progress: true
30
+
31
+ jobs:
32
+ lint:
33
+ name: Lint & Format Check
34
+ runs-on: ubuntu-24.04
35
+ timeout-minutes: 15
36
+ permissions:
37
+ contents: read
38
+ steps:
39
+ - uses: actions/checkout@9f698171ed81b15d1823a05fc7211befd50c8ae0 # v6.0.3
40
+ - uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
41
+ with:
42
+ enable-cache: true
43
+ - run: uv sync --frozen --extra dev
44
+ - run: uv run --frozen ruff check .
45
+ - run: uv run --frozen ruff format --check .
46
+
47
+ type-check:
48
+ name: Type Check & Import Contracts
49
+ runs-on: ubuntu-24.04
50
+ timeout-minutes: 15
51
+ permissions:
52
+ contents: read
53
+ steps:
54
+ - uses: actions/checkout@9f698171ed81b15d1823a05fc7211befd50c8ae0 # v6.0.3
55
+ - uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
56
+ with:
57
+ enable-cache: true
58
+ - run: uv sync --frozen --extra dev
59
+ - run: uv run --frozen ty check src/ezcompiler/
60
+ - run: uv run --frozen pyright
61
+ - run: PYTHONPATH=src uv run --frozen lint-imports
62
+
63
+ test:
64
+ name: Tests (Python ${{ matrix.python }})
65
+ needs: [lint, type-check]
66
+ runs-on: ubuntu-24.04
67
+ timeout-minutes: 25
68
+ permissions:
69
+ contents: read
70
+ strategy:
71
+ fail-fast: false
72
+ matrix:
73
+ python: ["3.13"]
74
+ steps:
75
+ - uses: actions/checkout@9f698171ed81b15d1823a05fc7211befd50c8ae0 # v6.0.3
76
+ - uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
77
+ with:
78
+ python-version: ${{ matrix.python }}
79
+ enable-cache: true
80
+ - run: uv sync --frozen --extra dev
81
+ - run: uv run --frozen pytest
82
+ - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
83
+ if: matrix.python == '3.13' && always()
84
+ with:
85
+ name: coverage-report
86
+ path: |
87
+ coverage.xml
88
+ htmlcov/
89
+ retention-days: 7
@@ -0,0 +1,91 @@
1
+ # Deploy Documentation Workflow
2
+
3
+ `docs.yml` builds and deploys the MkDocs Material documentation to GitHub Pages
4
+ (`https://neuraaak.github.io/ezplog/`). It is normally called by `auto-tag.yml`
5
+ after a tag is created or moved, but can also be run manually.
6
+
7
+ ## Triggers
8
+
9
+ | Event | How |
10
+ | ------------------- | ---------------------------------------------------- |
11
+ | `workflow_call` | Called by `auto-tag.yml` with boolean input `deploy` |
12
+ | `workflow_dispatch` | Manual run from the Actions tab (always deploys) |
13
+
14
+ `workflow_call` input `deploy` (boolean, default `false`):
15
+
16
+ - `true` → full deploy to GitHub Pages (release mode)
17
+ - `false` → build + checks only, no push (preview mode)
18
+
19
+ ## Job: `deploy`
20
+
21
+ Single job, runs on `ubuntu-24.04`. Steps in order:
22
+
23
+ | Step | Command / Action |
24
+ | ------------------ | ---------------------------------------------------------------------------------------------------------- |
25
+ | Checkout | Full history (`fetch-depth: 0`) required for git-cliff |
26
+ | Install | `uv sync --frozen` with `docs` and `test` extras |
27
+ | Tests | `uv run pytest --cov=src/ezplog --cov-report=html --cov-report=xml` — produces `htmlcov/` + `coverage.xml` |
28
+ | Import contracts | `PYTHONPATH=src uv run lint-imports` |
29
+ | Architecture graph | Runs `.scripts/dev/generate_architecture_graph.py` if present |
30
+ | Changelog | `git-cliff` writes `docs/changelog.md` from conventional commits |
31
+ | Resolve version | Reads `version` from `pyproject.toml`; fails if absent |
32
+ | Wait for PyPI | **Deploy mode only** — polls `pypi.org/pypi/ezplog/<version>/json` every 15 s, timeout 900 s |
33
+ | Git config | **Deploy mode only** — configures `github-actions[bot]` user for mike |
34
+ | Deploy | **Deploy mode only** — `mike deploy --push --update-aliases <version> latest` + `mike set-default latest` |
35
+ | Preview summary | **Preview mode only** — writes a step summary, no Pages push |
36
+
37
+ Deploy mode = `inputs.deploy == true` or `github.event_name == 'workflow_dispatch'`.
38
+
39
+ ## Concurrency
40
+
41
+ Group `docs-$ref` with `cancel-in-progress: true` — a new docs run on the same ref
42
+ cancels the previous one.
43
+
44
+ ## Permissions
45
+
46
+ `contents: write` is required so mike can push to the `gh-pages` branch.
47
+
48
+ ## GitHub Pages setup
49
+
50
+ Pages must be configured to serve from the `gh-pages` branch:
51
+
52
+ ```text
53
+ Repository → Settings → Pages → Source: Deploy from a branch → gh-pages / root
54
+ ```
55
+
56
+ `mike` manages versioned aliases (`latest`) and creates/updates this branch automatically.
57
+
58
+ ## Local preview
59
+
60
+ ```bash
61
+ uv sync --extra docs
62
+ uv run mkdocs serve
63
+ # Open http://127.0.0.1:8000
64
+ ```
65
+
66
+ Strict build (fails on warnings):
67
+
68
+ ```bash
69
+ uv run mkdocs build --strict
70
+ ```
71
+
72
+ ## Manual trigger
73
+
74
+ ```bash
75
+ gh workflow run docs.yml
76
+ ```
77
+
78
+ ## Troubleshooting
79
+
80
+ **Tests fail** — coverage generation fails if tests are broken. Fix the tests
81
+ and re-run. Do not add `|| true` to mask failures.
82
+
83
+ **mkdocstrings "Module not found"** — verify the module path in `docs/api/*.md`
84
+ matches the installed package. Run `uv run python -c "import ezplog"` to
85
+ confirm the package is importable.
86
+
87
+ **Permission denied on gh-pages** — check that `contents: write` is present and
88
+ that no branch-protection rule blocks force-pushes to `gh-pages`.
89
+
90
+ **Changelog not updating** — ensure `cliff.toml` exists at the repo root and
91
+ that commits follow the conventional commit format.
@@ -0,0 +1,84 @@
1
+ name: Deploy Documentation
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ workflow_call:
6
+ inputs:
7
+ deploy:
8
+ description: "Deploy docs (true) or preview-only (false)"
9
+ type: boolean
10
+ default: false
11
+
12
+ permissions:
13
+ contents: write
14
+
15
+ concurrency:
16
+ group: docs-${{ github.ref }}
17
+ cancel-in-progress: true
18
+
19
+ jobs:
20
+ deploy:
21
+ name: Build and Deploy Docs
22
+ runs-on: ubuntu-24.04
23
+
24
+ steps:
25
+ - uses: actions/checkout@9f698171ed81b15d1823a05fc7211befd50c8ae0 # v6.0.3
26
+ with:
27
+ fetch-depth: 0
28
+
29
+ - uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
30
+ with:
31
+ enable-cache: true
32
+
33
+ - run: uv sync --frozen --extra docs --extra test
34
+
35
+ - name: Generate coverage report
36
+ run: uv run --frozen pytest --cov=src/ezcompiler --cov-report=html --cov-report=xml -q
37
+
38
+ - name: Enforce import contracts
39
+ run: PYTHONPATH=src uv run --frozen lint-imports
40
+
41
+ - name: Generate architecture graph
42
+ run: |
43
+ if [ -f ".scripts/dev/generate_architecture_graph.py" ]; then
44
+ uv run --frozen python .scripts/dev/generate_architecture_graph.py
45
+ fi
46
+
47
+ - name: Generate changelog
48
+ uses: orhun/git-cliff-action@f50e11560dce63f7c33227798f90b924471a88b5 # v4
49
+ with:
50
+ config: cliff.toml
51
+ args: --output docs/changelog.md
52
+
53
+ - name: Resolve docs version
54
+ id: docs_version
55
+ run: |
56
+ VERSION=$(grep -E '^version\s*=\s*"' pyproject.toml | head -1 | sed 's/.*version\s*=\s*"\([^"]*\)".*/\1/')
57
+ if [ -z "$VERSION" ]; then
58
+ echo "::error::No version found in pyproject.toml"
59
+ exit 1
60
+ fi
61
+ echo "version=$VERSION" >> $GITHUB_OUTPUT
62
+ echo "Version: $VERSION"
63
+
64
+ - name: Configure git for mike
65
+ if: inputs.deploy || github.event_name == 'workflow_dispatch'
66
+ run: |
67
+ git config user.name "github-actions[bot]"
68
+ git config user.email "github-actions[bot]@users.noreply.github.com"
69
+
70
+ - name: Deploy documentation with mike
71
+ if: inputs.deploy || github.event_name == 'workflow_dispatch'
72
+ env:
73
+ DOCS_VERSION: ${{ steps.docs_version.outputs.version }}
74
+ run: |
75
+ uv run --frozen mike deploy --push --update-aliases "$DOCS_VERSION" latest
76
+ uv run --frozen mike set-default --push latest
77
+
78
+ - name: Preview mode summary
79
+ if: github.event_name == 'workflow_call' && !inputs.deploy
80
+ run: |
81
+ echo "## 🔎 Docs Preview Mode" >> $GITHUB_STEP_SUMMARY
82
+ echo "- Event: ${{ github.event_name }}" >> $GITHUB_STEP_SUMMARY
83
+ echo "- Build and checks completed." >> $GITHUB_STEP_SUMMARY
84
+ echo "- Documentation deploy step is intentionally skipped." >> $GITHUB_STEP_SUMMARY
@@ -0,0 +1,97 @@
1
+ # Publish to PyPI Workflow
2
+
3
+ `publish-pypi.yml` builds the package and publishes it to PyPI. It is normally
4
+ triggered by `auto-tag.yml` after a new version tag is created, but can also
5
+ be run manually.
6
+
7
+ ## Triggers
8
+
9
+ | Event | How |
10
+ | ------------------- | ------------------------------------------------------ |
11
+ | `workflow_call` | Called by `auto-tag.yml` with `version` + `tag` inputs |
12
+ | `workflow_dispatch` | Manual run from the Actions tab |
13
+
14
+ Manual runs have a `skip_tests` option (default `false`, not recommended).
15
+
16
+ ## Authentication
17
+
18
+ Publishing uses **OIDC trusted publishing** — no stored secret. The workflow
19
+ mints a short-lived token that PyPI trusts directly via the `id-token: write`
20
+ permission. The trusted publisher must be configured on pypi.org under the
21
+ ezplog project settings:
22
+
23
+ ```text
24
+ pypi.org → Manage project ezplog → Publishing → Add a new publisher
25
+ Owner: neuraaak
26
+ Repo: ezplog
27
+ Workflow: publish-pypi.yml
28
+ Environment: pypi
29
+ ```
30
+
31
+ ## Jobs
32
+
33
+ ```text
34
+ validate (build + test) ──► publish (OIDC deploy)
35
+ ```
36
+
37
+ ### `validate` — Validate & Build
38
+
39
+ 1. Resolve version: uses `inputs.version` if provided (workflow_call), otherwise reads from `pyproject.toml`
40
+ 2. Preview mode summary — printed if triggered by push/PR or preview tag (no failure, informational only)
41
+ 3. `uv sync --frozen --extra dev`
42
+ 4. `PYTHONPATH=src uv run lint-imports` — import contracts
43
+ 5. `uv run pytest` — full suite (skipped if `skip_tests=true`)
44
+ 6. `uv build` — produces `dist/*.whl` and `dist/*.tar.gz`
45
+ 7. `uv run twine check dist/*` — validates package metadata
46
+ 8. Wheel integrity check: `python -m zipfile -t dist/*.whl` + inline script verifying `ezplog/` is present in the wheel
47
+ 9. Upload `dist/` as a job artifact (retained 1 day)
48
+
49
+ ### `publish` — Publish to PyPI (OIDC)
50
+
51
+ Runs only if `validate` succeeds **and** the event is `workflow_dispatch` or a
52
+ `workflow_call` whose `tag` input does not start with `preview-`. Downloads the
53
+ artifact built upstream (no rebuild). Steps:
54
+
55
+ 1. `actions/download-artifact` — retrieves `dist/`
56
+ 2. `pypa/gh-action-pypi-publish@v1.14.0` — publishes via OIDC, no password
57
+
58
+ > **Note — attestations disabled:** when called as a reusable workflow from
59
+ > `auto-tag.yml`, the OIDC token's Build Config URI reflects the caller
60
+ > (`auto-tag.yml`) rather than `publish-pypi.yml`, causing PyPI Trusted
61
+ > Publisher verification to fail. `attestations: false` works around this.
62
+
63
+ The job runs in the `pypi` environment. Configure required reviewers there
64
+ in Repository → Settings → Environments if you want a manual gate.
65
+
66
+ ## Concurrency
67
+
68
+ A `publish` concurrency group with `cancel-in-progress: false` prevents two
69
+ simultaneous publish runs. A run in progress is never interrupted.
70
+
71
+ ## Release workflow
72
+
73
+ ```text
74
+ 1. Bump version in pyproject.toml
75
+ 2. Commit & push to main
76
+ → auto-tag.yml detects a new version, creates vX.Y.Z tag
77
+ → triggers publish-pypi.yml automatically
78
+ 3. Verify on https://pypi.org/project/ezplog/
79
+ ```
80
+
81
+ Manual trigger via gh CLI:
82
+
83
+ ```bash
84
+ gh workflow run publish-pypi.yml
85
+ ```
86
+
87
+ ## Troubleshooting
88
+
89
+ **Version mismatch** — the `version` input from auto-tag differs from
90
+ `pyproject.toml`. Bump the version, commit, and push again.
91
+
92
+ **OIDC failure** — check that the trusted publisher on pypi.org matches
93
+ the repo name, workflow filename (`publish-pypi.yml`), and environment name
94
+ (`pypi`) exactly.
95
+
96
+ **Tests fail** — run `uv run pytest` locally, fix, push. Do not use
97
+ `skip_tests=true` to work around failures.
@@ -0,0 +1,121 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ workflow_call:
6
+ inputs:
7
+ version:
8
+ required: true
9
+ type: string
10
+ tag:
11
+ required: true
12
+ type: string
13
+
14
+ permissions: {}
15
+
16
+ concurrency:
17
+ group: publish-${{ github.ref }}
18
+ cancel-in-progress: false
19
+
20
+ env:
21
+ PACKAGE_NAME: ezcompiler
22
+
23
+ jobs:
24
+ validate:
25
+ name: Validate & Build
26
+ runs-on: ubuntu-24.04
27
+ permissions:
28
+ contents: read
29
+ outputs:
30
+ version: ${{ steps.version.outputs.version }}
31
+
32
+ steps:
33
+ - uses: actions/checkout@9f698171ed81b15d1823a05fc7211befd50c8ae0 # v6.0.3
34
+
35
+ - name: Resolve version
36
+ id: version
37
+ env:
38
+ INPUT_VERSION: ${{ inputs.version || '' }}
39
+ run: |
40
+ VERSION="$INPUT_VERSION"
41
+ if [ -z "$VERSION" ]; then
42
+ VERSION=$(grep -E '^version\s*=\s*"' pyproject.toml | head -1 | sed 's/.*version\s*=\s*"\([^"]*\)".*/\1/')
43
+ fi
44
+ echo "version=$VERSION" >> $GITHUB_OUTPUT
45
+ echo "Version: $VERSION"
46
+
47
+ - uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
48
+ with:
49
+ enable-cache: true
50
+
51
+ - run: uv sync --frozen --extra dev
52
+
53
+ - name: Enforce import contracts
54
+ run: PYTHONPATH=src uv run --frozen lint-imports
55
+
56
+ - name: Build package
57
+ run: uv build
58
+
59
+ - name: Check package
60
+ run: uv run --frozen twine check dist/*
61
+
62
+ - name: Verify wheel installation
63
+ run: |
64
+ python -m zipfile -t dist/*.whl
65
+ python - <<'PY'
66
+ import glob
67
+ import sys
68
+ import zipfile
69
+
70
+ wheels = glob.glob("dist/*.whl")
71
+ if not wheels:
72
+ raise SystemExit("No wheel found in dist/")
73
+
74
+ with zipfile.ZipFile(wheels[0]) as zf:
75
+ names = zf.namelist()
76
+
77
+ if not any(name.startswith("ezcompiler/") for name in names):
78
+ raise SystemExit("Wheel does not contain ezcompiler package")
79
+
80
+ print("Wheel integrity check passed")
81
+ PY
82
+
83
+ - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
84
+ with:
85
+ name: dist
86
+ path: dist/
87
+ retention-days: 1
88
+
89
+ publish:
90
+ name: Publish to PyPI (OIDC)
91
+ needs: validate
92
+ if: github.event_name == 'workflow_dispatch' || github.event_name == 'workflow_call'
93
+ runs-on: ubuntu-24.04
94
+ permissions:
95
+ contents: read
96
+ id-token: write
97
+ environment:
98
+ name: pypi
99
+ url: https://pypi.org/project/${{ env.PACKAGE_NAME }}/${{ needs.validate.outputs.version }}/
100
+
101
+ steps:
102
+ - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
103
+ with:
104
+ name: dist
105
+ path: dist/
106
+
107
+ - uses: pypa/gh-action-pypi-publish@v1.14.0
108
+ with:
109
+ verbose: true
110
+ # Attestations disabled: when called as a reusable workflow from
111
+ # auto-tag.yml, the OIDC token's Build Config URI reflects the
112
+ # caller (auto-tag.yml) rather than this workflow, causing PyPI
113
+ # Trusted Publisher verification to fail.
114
+ attestations: false
115
+
116
+ - name: Summary
117
+ run: |
118
+ echo "## 📦 Published to PyPI" >> $GITHUB_STEP_SUMMARY
119
+ echo "- **Package**: ${{ env.PACKAGE_NAME }}" >> $GITHUB_STEP_SUMMARY
120
+ echo "- **Version**: ${{ needs.validate.outputs.version }}" >> $GITHUB_STEP_SUMMARY
121
+ echo "- **URL**: https://pypi.org/project/${{ env.PACKAGE_NAME }}/${{ needs.validate.outputs.version }}/" >> $GITHUB_STEP_SUMMARY