ferro-orm 0.3.1__tar.gz → 0.3.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 (118) hide show
  1. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/.github/PERMISSIONS.md +34 -62
  2. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/.github/workflows/publish.yml +4 -0
  3. ferro_orm-0.3.2/.github/workflows/release.yml +374 -0
  4. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/CHANGELOG.md +37 -0
  5. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/Cargo.lock +158 -11
  6. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/Cargo.toml +2 -2
  7. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/PKG-INFO +4 -1
  8. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/docs/guide/database.md +43 -0
  9. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/pyproject.toml +10 -10
  10. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/uv.lock +10 -7
  11. ferro_orm-0.3.1/.github/workflows/release.yml +0 -552
  12. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  13. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  14. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/.github/PYPI_CHECKLIST.md +0 -0
  15. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/.github/PYPI_SETUP.md +0 -0
  16. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/.github/generated/wheels.generated.yml +0 -0
  17. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/.github/pull_request_template.md +0 -0
  18. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/.github/workflows/ci.yml +0 -0
  19. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/.github/workflows/packaging-smoke.yml +0 -0
  20. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/.github/workflows/publish-docs.yml +0 -0
  21. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/.gitignore +0 -0
  22. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/.pre-commit-config.yaml +0 -0
  23. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/.python-version +0 -0
  24. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/CONTRIBUTING.md +0 -0
  25. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/LICENSE +0 -0
  26. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/README.md +0 -0
  27. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/docs/TEST_RESULTS.md +0 -0
  28. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/docs/api/fields.md +0 -0
  29. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/docs/api/model.md +0 -0
  30. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/docs/api/query.md +0 -0
  31. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/docs/api/relationships.md +0 -0
  32. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/docs/api/transactions.md +0 -0
  33. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/docs/api/utilities.md +0 -0
  34. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/docs/changelog.md +0 -0
  35. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/docs/coming-soon.md +0 -0
  36. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/docs/concepts/architecture.md +0 -0
  37. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/docs/concepts/identity-map.md +0 -0
  38. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/docs/concepts/performance.md +0 -0
  39. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/docs/concepts/type-safety.md +0 -0
  40. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/docs/contributing.md +0 -0
  41. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/docs/faq.md +0 -0
  42. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/docs/getting-started/installation.md +0 -0
  43. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/docs/getting-started/next-steps.md +0 -0
  44. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/docs/getting-started/tutorial.md +0 -0
  45. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/docs/guide/migrations.md +0 -0
  46. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/docs/guide/models-and-fields.md +0 -0
  47. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/docs/guide/mutations.md +0 -0
  48. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/docs/guide/queries.md +0 -0
  49. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/docs/guide/relationships.md +0 -0
  50. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/docs/guide/transactions.md +0 -0
  51. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/docs/howto/multiple-databases.md +0 -0
  52. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/docs/howto/pagination.md +0 -0
  53. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/docs/howto/soft-deletes.md +0 -0
  54. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/docs/howto/testing.md +0 -0
  55. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/docs/howto/timestamps.md +0 -0
  56. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/docs/index.md +0 -0
  57. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/docs/migration-sqlalchemy.md +0 -0
  58. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/docs/stylesheets/extra.css +0 -0
  59. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/docs/why-ferro.md +0 -0
  60. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/justfile +0 -0
  61. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/mkdocs.yml +0 -0
  62. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/scripts/demo_queries.py +0 -0
  63. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/src/connection.rs +0 -0
  64. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/src/ferro/__init__.py +0 -0
  65. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/src/ferro/_annotation_utils.py +0 -0
  66. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/src/ferro/_core.pyi +0 -0
  67. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/src/ferro/_shadow_fk_types.py +0 -0
  68. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/src/ferro/base.py +0 -0
  69. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/src/ferro/composite_uniques.py +0 -0
  70. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/src/ferro/fields.py +0 -0
  71. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/src/ferro/metaclass.py +0 -0
  72. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/src/ferro/migrations/__init__.py +0 -0
  73. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/src/ferro/migrations/alembic.py +0 -0
  74. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/src/ferro/models.py +0 -0
  75. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/src/ferro/py.typed +0 -0
  76. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/src/ferro/query/__init__.py +0 -0
  77. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/src/ferro/query/builder.py +0 -0
  78. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/src/ferro/query/nodes.py +0 -0
  79. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/src/ferro/relations/__init__.py +0 -0
  80. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/src/ferro/relations/descriptors.py +0 -0
  81. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/src/ferro/state.py +0 -0
  82. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/src/lib.rs +0 -0
  83. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/src/operations.rs +0 -0
  84. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/src/query.rs +0 -0
  85. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/src/schema.rs +0 -0
  86. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/src/state.rs +0 -0
  87. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/tests/conftest.py +0 -0
  88. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/tests/test_aggregation.py +0 -0
  89. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/tests/test_alembic_autogenerate.py +0 -0
  90. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/tests/test_alembic_bridge.py +0 -0
  91. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/tests/test_alembic_nullability.py +0 -0
  92. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/tests/test_alembic_type_mapping.py +0 -0
  93. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/tests/test_auto_migrate.py +0 -0
  94. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/tests/test_bulk_update.py +0 -0
  95. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/tests/test_composite_unique.py +0 -0
  96. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/tests/test_connection.py +0 -0
  97. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/tests/test_constraints.py +0 -0
  98. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/tests/test_crud.py +0 -0
  99. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/tests/test_deletion.py +0 -0
  100. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/tests/test_docs_examples.py +0 -0
  101. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/tests/test_documentation_features.py +0 -0
  102. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/tests/test_field_wrapper.py +0 -0
  103. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/tests/test_helpers.py +0 -0
  104. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/tests/test_hydration.py +0 -0
  105. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/tests/test_metaclass_internals.py +0 -0
  106. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/tests/test_metadata.py +0 -0
  107. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/tests/test_models.py +0 -0
  108. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/tests/test_one_to_one.py +0 -0
  109. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/tests/test_query_builder.py +0 -0
  110. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/tests/test_refresh.py +0 -0
  111. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/tests/test_relationship_engine.py +0 -0
  112. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/tests/test_schema.py +0 -0
  113. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/tests/test_schema_constraints.py +0 -0
  114. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/tests/test_shadow_fk_types.py +0 -0
  115. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/tests/test_string_search.py +0 -0
  116. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/tests/test_structural_types.py +0 -0
  117. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/tests/test_temporal_types.py +0 -0
  118. {ferro_orm-0.3.1 → ferro_orm-0.3.2}/tests/test_transactions.py +0 -0
@@ -45,37 +45,7 @@ All workflows use explicit, fine-grained permissions (principle of least privile
45
45
 
46
46
  **Trigger:** Manual workflow dispatch
47
47
 
48
- **Job graph (top to bottom is execution order):**
49
-
50
- ```
51
- ci-gate packaging-smoke
52
- \ /
53
- prepare-release (computes bump, writes release.patch; no pushes)
54
- / | | \
55
- build-wheels build-sdist test-wheels verify-docs
56
- \ | /
57
- promote-pypi (PyPI Trusted Publishing; first irreversible step)
58
- |
59
- promote-git (commit bump, push main, tag, create GH Release + assets)
60
- |
61
- promote-docs (deploys MkDocs site pinned to the new tag)
62
- ```
63
-
64
- Nothing is pushed, tagged, or published until every validation job above
65
- `promote-pypi` has succeeded. PyPI is published first so that if anything
66
- fails, `main` is never advanced to an "orphan" version.
67
-
68
- **Permissions (prepare-release):**
69
- ```yaml
70
- permissions:
71
- contents: read
72
- issues: read
73
- pull-requests: read
74
- ```
75
-
76
- Prepare-release only needs read access because it just computes the bump and uploads a patch artifact — it does not push anything.
77
-
78
- **Permissions (promote-git):**
48
+ **Permissions:**
79
49
  ```yaml
80
50
  permissions:
81
51
  contents: write
@@ -83,23 +53,33 @@ permissions:
83
53
  pull-requests: write
84
54
  ```
85
55
 
86
- - `contents: write` - Allows the job to:
87
- - Commit version bumps to `pyproject.toml` and `Cargo.toml`
56
+ **Why These Permissions:**
57
+ - `contents: write` - Allows the workflow to:
58
+ - Commit version bumps to pyproject.toml and Cargo.toml
88
59
  - Push commits to the `main` branch
89
- - Create and push git tags (e.g., `v0.3.1`)
90
- - Create GitHub Releases
60
+ - Create and push git tags (e.g., `v0.2.0`)
61
+ - Create GitHub releases
91
62
 
92
- - `issues: write` / `pull-requests: write` - Allows semantic-release to
93
- update issue/PR references in generated release notes.
63
+ - `issues: write` - Allows the workflow to:
64
+ - Update issue references in release notes
65
+ - Close issues automatically via commit messages
66
+ - Add labels or comments to issues
94
67
 
95
- **What the release flow does:**
96
- - Analyzes conventional commits since the latest tag (fetched explicitly via `fetch-tags: true`)
97
- - Fails fast if the computed version collides with an existing tag (indicates a tag-fetch bug)
98
- - Bumps version in `pyproject.toml` and `Cargo.toml` and finalizes `CHANGELOG.md`
99
- - Validates the bumped tree across wheel builds, sdist, install smoke tests, and `mkdocs build`
100
- - Publishes to PyPI before touching `main`
101
- - Commits bump to `main`, creates the tag, creates the GitHub Release with generated notes, attaches wheels + sdist
102
- - Deploys the MkDocs site pinned to the new tag
68
+ - `pull-requests: write` - Allows the workflow to:
69
+ - Update PR references in release notes
70
+ - Close PRs automatically via commit messages
71
+ - Add labels or comments to PRs
72
+
73
+ **What It Does:**
74
+ - **Preflight** builds all release wheels at the workflow SHA (same matrix as post-release wheel builds), in parallel with the CI gate and packaging smoke jobs. If any platform fails, the Create Release job does not run.
75
+ - Analyzes conventional commits
76
+ - Determines next version
77
+ - Updates version in both Python and Rust files
78
+ - Finalizes CHANGELOG.md
79
+ - Creates git tag
80
+ - Creates GitHub release
81
+ - Triggers publish workflow
82
+ - Reports whether release commits include `CHANGELOG.md`
103
83
 
104
84
  **Required Secrets:**
105
85
  - `RELEASE_DEPLOY_KEY` (private SSH key for a write-enabled deploy key)
@@ -109,15 +89,15 @@ permissions:
109
89
 
110
90
  ### 2. Build & Publish (jobs in `release.yml`)
111
91
 
112
- **Trigger:** Part of `release.yml` all build and publish jobs live in the same workflow file.
92
+ **Trigger:** Part of `release.yml` after the Create Release job (no reusable workflow). Wheel preflight runs in parallel with CI and packaging smoke, before that job.
113
93
 
114
94
  Build, test, and publish jobs are defined directly in `release.yml` so PyPI Trusted Publishing receives a token with `workflow_ref: release.yml` (reusable workflows are not supported by PyPI).
115
95
 
116
96
  **Permissions:**
117
97
 
118
- **For build-wheels, build-sdist, test-wheels, verify-docs:** (default - read-only)
98
+ **For build-wheels, build-sdist, test-wheels:** (default - read-only)
119
99
 
120
- **For promote-pypi job:**
100
+ **For publish-pypi job:**
121
101
  ```yaml
122
102
  permissions:
123
103
  id-token: write
@@ -127,10 +107,10 @@ permissions:
127
107
  - `id-token: write` - Allows the job to request an OIDC token and authenticate with PyPI using Trusted Publishing.
128
108
 
129
109
  **What It Does:**
130
- - Builds wheels for multiple platforms against the patched (bumped) tree
131
- - Builds source distribution against the patched tree
132
- - Installs wheels and runs a smoke import + in-memory SQLite check
133
- - `promote-pypi` publishes the validated wheels + sdist to PyPI via OIDC
110
+ - Builds wheels for multiple platforms from the release tag
111
+ - Builds source distribution
112
+ - Tests built packages
113
+ - Publishes to PyPI using OIDC authentication
134
114
 
135
115
  ---
136
116
 
@@ -269,7 +249,7 @@ Permission to manage GitHub Pages deployments:
269
249
 
270
250
  ### Release Completed But Publish/Docs Did Not Run
271
251
 
272
- **Cause:** `release.yml` gates downstream jobs. If CI, packaging smoke, or release creation fails, publish/docs are skipped.
252
+ **Cause:** `release.yml` gates downstream jobs. If CI, packaging smoke, preflight wheel builds, or release creation fails, publish/docs are skipped.
273
253
 
274
254
  **Solution:**
275
255
  - Open the failed `release.yml` run and inspect the first failed job.
@@ -289,18 +269,10 @@ Permission to manage GitHub Pages deployments:
289
269
  **Cause:** Missing `id-token: write` permission
290
270
 
291
271
  **Solution:**
292
- - Ensure `promote-pypi` job has `id-token: write`
272
+ - Ensure `publish-pypi` job has `id-token: write`
293
273
  - Verify PyPI trusted publisher is configured correctly
294
274
  - Check environment name matches (`pypi`)
295
275
 
296
- ### Release says "0.3.0 has already been released!" for a version that was already shipped
297
-
298
- **Cause:** `actions/checkout@v4` runs `git fetch --no-tags` by default, even with `fetch-depth: 0`. Without tags, `semantic-release` picks an older baseline tag, computes a minor/patch bump, and lands on the same version number as a prior release.
299
-
300
- **Solution:**
301
- - The `prepare-release` job sets `fetch-tags: true` on its checkout step and then runs a `git describe` vs `semantic-release --print-last-released-tag` comparison as a guard. Both must be present.
302
- - If this check fails in a run, confirm no one has removed `fetch-tags: true` from the checkout step.
303
-
304
276
  ---
305
277
 
306
278
  ## Verification
@@ -60,6 +60,10 @@ jobs:
60
60
 
61
61
  - name: Build wheels
62
62
  uses: PyO3/maturin-action@v1.48.0
63
+ env:
64
+ # ring (via rustls/sqlx): manylinux2014-cross gcc does not define __ARM_ARCH for .S asm.
65
+ # https://github.com/briansmith/ring/issues/1728
66
+ CFLAGS_aarch64_unknown_linux_gnu: ${{ matrix.platform.name == 'linux-aarch64' && '-D__ARM_ARCH=8' || '' }}
63
67
  with:
64
68
  target: ${{ matrix.platform.target }}
65
69
  args: --release --out dist --find-interpreter
@@ -0,0 +1,374 @@
1
+ name: Release
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ inputs:
6
+ prerelease:
7
+ description: 'Create a pre-release'
8
+ required: false
9
+ type: boolean
10
+ default: false
11
+
12
+ concurrency:
13
+ group: release-${{ github.workflow }}-${{ github.ref }}
14
+ cancel-in-progress: true
15
+
16
+ jobs:
17
+ # Same maturin targets as build-wheels, but against the current ref *before*
18
+ # semantic-release mutates the repo. Runs in parallel with CI gate and
19
+ # packaging smoke so the wall-clock pipeline stays shorter.
20
+ preflight-build-wheels:
21
+ name: Preflight build wheels (${{ matrix.platform.name }})
22
+ runs-on: ${{ matrix.platform.runner }}
23
+ strategy:
24
+ fail-fast: false
25
+ matrix:
26
+ platform:
27
+ - name: linux-x86_64
28
+ runner: ubuntu-latest
29
+ target: x86_64
30
+ manylinux: auto
31
+ - name: linux-aarch64
32
+ runner: ubuntu-latest
33
+ target: aarch64
34
+ manylinux: auto
35
+ - name: macos-aarch64
36
+ runner: macos-latest
37
+ target: aarch64
38
+ manylinux: ''
39
+ - name: windows-x64
40
+ runner: windows-latest
41
+ target: x64
42
+ manylinux: ''
43
+
44
+ steps:
45
+ - name: Checkout repository
46
+ uses: actions/checkout@v4
47
+ with:
48
+ ref: ${{ github.sha }}
49
+
50
+ - name: Set up Python
51
+ uses: actions/setup-python@v5
52
+ with:
53
+ python-version: '3.13'
54
+
55
+ - name: Build wheels (preflight)
56
+ uses: PyO3/maturin-action@v1.48.0
57
+ env:
58
+ # ring (via rustls/sqlx): manylinux2014-cross gcc does not define __ARM_ARCH for .S asm.
59
+ # https://github.com/briansmith/ring/issues/1728
60
+ CFLAGS_aarch64_unknown_linux_gnu: ${{ matrix.platform.name == 'linux-aarch64' && '-D__ARM_ARCH=8' || '' }}
61
+ with:
62
+ target: ${{ matrix.platform.target }}
63
+ args: --release --out dist --find-interpreter
64
+ manylinux: ${{ matrix.platform.manylinux }}
65
+ sccache: 'true'
66
+
67
+ ci-gate:
68
+ name: CI Gate
69
+ uses: ./.github/workflows/ci.yml
70
+
71
+ packaging-smoke:
72
+ name: Packaging Smoke Gate
73
+ uses: ./.github/workflows/packaging-smoke.yml
74
+
75
+ release:
76
+ name: Create Release
77
+ needs: [ci-gate, packaging-smoke, preflight-build-wheels]
78
+ runs-on: ubuntu-latest
79
+ outputs:
80
+ release_created: ${{ steps.verify_release.outputs.release_created }}
81
+ release_ref: ${{ steps.release_ref.outputs.release_ref }}
82
+ permissions:
83
+ contents: write
84
+ issues: write
85
+ pull-requests: write
86
+
87
+ steps:
88
+ - name: Checkout repository
89
+ uses: actions/checkout@v4
90
+ with:
91
+ fetch-depth: 0
92
+ ssh-key: ${{ secrets.RELEASE_DEPLOY_KEY }}
93
+ persist-credentials: false
94
+
95
+ - name: Set up Python
96
+ uses: actions/setup-python@v5
97
+ with:
98
+ python-version: '3.13'
99
+
100
+ - name: Install UV
101
+ uses: astral-sh/setup-uv@v5
102
+ with:
103
+ enable-cache: true
104
+
105
+ - name: Set up Rust
106
+ uses: dtolnay/rust-toolchain@stable
107
+
108
+ - name: Cache Rust dependencies
109
+ uses: Swatinem/rust-cache@v2
110
+ with:
111
+ prefix-key: "v1-rust"
112
+
113
+ - name: Install dependencies
114
+ run: |
115
+ uv sync --only-group release --no-install-project --python 3.13
116
+
117
+ - name: Configure Git
118
+ run: |
119
+ git config --local user.email "github-actions[bot]@users.noreply.github.com"
120
+ git config --local user.name "github-actions[bot]"
121
+ git remote set-url origin "git@github.com:${{ github.repository }}.git"
122
+
123
+ - name: Run semantic-release
124
+ env:
125
+ # Prefer a PAT so release events can trigger downstream workflows.
126
+ GH_TOKEN: ${{ secrets.RELEASE_TOKEN || secrets.GITHUB_TOKEN }}
127
+ run: |
128
+ # Use the --prerelease flag if requested via manual trigger
129
+ PRERELEASE_FLAG=""
130
+ if [ "${{ github.event.inputs.prerelease }}" == "true" ]; then
131
+ PRERELEASE_FLAG="--prerelease"
132
+ fi
133
+
134
+ # This command will:
135
+ # 1. Bump version in pyproject.toml and Cargo.toml
136
+ # 2. Update CHANGELOG.md
137
+ # 3. Create a commit and push it
138
+ # 4. Create a tag and push it
139
+ # 5. Create a GitHub Release (publishing is handled by the wheels/publish workflow)
140
+ uv run semantic-release version $PRERELEASE_FLAG
141
+
142
+ - name: Verify release commit updates changelog
143
+ id: verify_release
144
+ shell: bash
145
+ run: |
146
+ LAST_SUBJECT="$(git log -1 --pretty=%s)"
147
+ if [[ "$LAST_SUBJECT" != chore\(release\):* ]]; then
148
+ echo "No release commit created in this run; skipping changelog validation."
149
+ echo "release_created=false" >> "$GITHUB_OUTPUT"
150
+ echo "changelog_validated=skipped" >> "$GITHUB_OUTPUT"
151
+ echo "release_subject=$LAST_SUBJECT" >> "$GITHUB_OUTPUT"
152
+ exit 0
153
+ fi
154
+
155
+ echo "release_created=true" >> "$GITHUB_OUTPUT"
156
+ echo "release_subject=$LAST_SUBJECT" >> "$GITHUB_OUTPUT"
157
+
158
+ CHANGED_FILES="$(git show --name-only --pretty='' HEAD)"
159
+ if [[ "$CHANGED_FILES" != *"CHANGELOG.md"* ]]; then
160
+ echo "WARNING: release commit does not include CHANGELOG.md update."
161
+ echo "Changed files:"
162
+ echo "$CHANGED_FILES"
163
+ echo "changelog_validated=missing" >> "$GITHUB_OUTPUT"
164
+ exit 0
165
+ fi
166
+
167
+ echo "changelog_validated=passed" >> "$GITHUB_OUTPUT"
168
+ echo "Validated: release commit includes CHANGELOG.md."
169
+
170
+ - name: Capture released ref
171
+ id: release_ref
172
+ shell: bash
173
+ run: |
174
+ if [[ "${{ steps.verify_release.outputs.release_created }}" != "true" ]]; then
175
+ echo "release_ref=" >> "$GITHUB_OUTPUT"
176
+ exit 0
177
+ fi
178
+
179
+ RELEASE_TAG="$(git tag --points-at HEAD | head -n1)"
180
+ if [[ -z "$RELEASE_TAG" ]]; then
181
+ echo "ERROR: expected release tag on HEAD but none was found."
182
+ exit 1
183
+ fi
184
+
185
+ echo "release_ref=$RELEASE_TAG" >> "$GITHUB_OUTPUT"
186
+ echo "Using release ref: $RELEASE_TAG"
187
+
188
+ - name: Release summary
189
+ if: always()
190
+ shell: bash
191
+ run: |
192
+ {
193
+ echo "## Release workflow summary"
194
+ echo ""
195
+ echo "- Trigger: \`${{ github.event_name }}\`"
196
+ echo "- Ref: \`${{ github.ref_name }}\`"
197
+ echo "- Release commit created: \`${{ steps.verify_release.outputs.release_created || 'unknown' }}\`"
198
+ echo "- Changelog validation: \`${{ steps.verify_release.outputs.changelog_validated || 'unknown' }}\`"
199
+ echo "- Release ref: \`${{ steps.release_ref.outputs.release_ref || 'n/a' }}\`"
200
+ echo "- Last commit subject: \`${{ steps.verify_release.outputs.release_subject || 'n/a' }}\`"
201
+ } >> "$GITHUB_STEP_SUMMARY"
202
+
203
+ # Build and publish jobs are inlined here (not in a reusable workflow) so that
204
+ # PyPI Trusted Publishing sees workflow_ref = release.yml. Reusable workflows
205
+ # are not supported by PyPI Trusted Publishing.
206
+ build-wheels:
207
+ name: Build wheels (${{ matrix.platform.name }})
208
+ needs: [release]
209
+ if: needs.release.outputs.release_created == 'true'
210
+ runs-on: ${{ matrix.platform.runner }}
211
+ strategy:
212
+ fail-fast: false
213
+ matrix:
214
+ platform:
215
+ - name: linux-x86_64
216
+ runner: ubuntu-latest
217
+ target: x86_64
218
+ manylinux: auto
219
+ - name: linux-aarch64
220
+ runner: ubuntu-latest
221
+ target: aarch64
222
+ manylinux: auto
223
+ - name: macos-aarch64
224
+ runner: macos-latest
225
+ target: aarch64
226
+ manylinux: ''
227
+ - name: windows-x64
228
+ runner: windows-latest
229
+ target: x64
230
+ manylinux: ''
231
+
232
+ steps:
233
+ - name: Checkout repository
234
+ uses: actions/checkout@v4
235
+ with:
236
+ ref: ${{ needs.release.outputs.release_ref }}
237
+
238
+ - name: Set up Python
239
+ uses: actions/setup-python@v5
240
+ with:
241
+ python-version: '3.13'
242
+
243
+ - name: Build wheels
244
+ uses: PyO3/maturin-action@v1.48.0
245
+ env:
246
+ # ring (via rustls/sqlx): manylinux2014-cross gcc does not define __ARM_ARCH for .S asm.
247
+ # https://github.com/briansmith/ring/issues/1728
248
+ CFLAGS_aarch64_unknown_linux_gnu: ${{ matrix.platform.name == 'linux-aarch64' && '-D__ARM_ARCH=8' || '' }}
249
+ with:
250
+ target: ${{ matrix.platform.target }}
251
+ args: --release --out dist --find-interpreter
252
+ manylinux: ${{ matrix.platform.manylinux }}
253
+ sccache: 'true'
254
+
255
+ - name: Upload wheels
256
+ uses: actions/upload-artifact@v4
257
+ with:
258
+ name: wheels-${{ matrix.platform.name }}
259
+ path: dist/*.whl
260
+
261
+ build-sdist:
262
+ name: Build sdist
263
+ needs: [release]
264
+ if: needs.release.outputs.release_created == 'true'
265
+ runs-on: ubuntu-latest
266
+ steps:
267
+ - name: Checkout repository
268
+ uses: actions/checkout@v4
269
+ with:
270
+ ref: ${{ needs.release.outputs.release_ref }}
271
+
272
+ - name: Build sdist
273
+ uses: PyO3/maturin-action@v1.48.0
274
+ with:
275
+ command: sdist
276
+ args: --out dist
277
+
278
+ - name: Upload sdist
279
+ uses: actions/upload-artifact@v4
280
+ with:
281
+ name: sdist
282
+ path: dist/*.tar.gz
283
+
284
+ test-wheels:
285
+ name: Test wheels (${{ matrix.os }})
286
+ needs: [release, build-wheels]
287
+ if: needs.release.outputs.release_created == 'true'
288
+ runs-on: ${{ matrix.os }}
289
+ strategy:
290
+ fail-fast: false
291
+ matrix:
292
+ os: [ubuntu-latest, windows-latest, macos-latest]
293
+ steps:
294
+ - name: Checkout repository
295
+ uses: actions/checkout@v4
296
+ with:
297
+ ref: ${{ needs.release.outputs.release_ref }}
298
+
299
+ - name: Set up Python
300
+ uses: actions/setup-python@v5
301
+ with:
302
+ python-version: '3.13'
303
+
304
+ - name: Download wheels
305
+ uses: actions/download-artifact@v4
306
+ with:
307
+ path: dist
308
+ pattern: wheels-*
309
+ merge-multiple: true
310
+
311
+ - name: Install wheel
312
+ shell: bash
313
+ run: |
314
+ python -m pip install --upgrade pip
315
+ python -m pip install --find-links dist ferro-orm
316
+
317
+ - name: Test import
318
+ shell: bash
319
+ run: |
320
+ python -c "import ferro; print('Ferro imported successfully')"
321
+
322
+ - name: Run basic smoke test
323
+ shell: bash
324
+ run: |
325
+ python -c "
326
+ import asyncio
327
+ from ferro import Model, FerroField, connect
328
+ from typing import Annotated
329
+
330
+ class TestModel(Model):
331
+ id: Annotated[int, FerroField(primary_key=True)]
332
+ name: str
333
+
334
+ async def test():
335
+ await connect('sqlite::memory:')
336
+ print('Connection test passed')
337
+
338
+ asyncio.run(test())
339
+ "
340
+
341
+ publish-pypi:
342
+ name: Publish to PyPI
343
+ needs: [release, build-wheels, build-sdist, test-wheels]
344
+ if: needs.release.outputs.release_created == 'true'
345
+ runs-on: ubuntu-latest
346
+ environment:
347
+ name: pypi
348
+ url: https://pypi.org/p/ferro-orm
349
+ permissions:
350
+ id-token: write
351
+ steps:
352
+ - name: Download all artifacts
353
+ uses: actions/download-artifact@v4
354
+ with:
355
+ path: dist
356
+ merge-multiple: true
357
+
358
+ - name: Publish to PyPI
359
+ uses: pypa/gh-action-pypi-publish@release/v1
360
+ with:
361
+ skip-existing: true
362
+ verbose: true
363
+
364
+ deploy-docs:
365
+ name: Deploy Documentation
366
+ needs: [release, publish-pypi]
367
+ if: needs.release.outputs.release_created == 'true'
368
+ uses: ./.github/workflows/publish-docs.yml
369
+ permissions:
370
+ contents: read
371
+ pages: write
372
+ id-token: write
373
+ with:
374
+ ref: ${{ needs.release.outputs.release_ref }}
@@ -1,6 +1,43 @@
1
1
  # CHANGELOG
2
2
 
3
3
 
4
+ ## v0.3.2 (2026-04-24)
5
+
6
+ ### Bug Fixes
7
+
8
+ - Move alembic reqs to optional dependencies
9
+ ([`87f0e81`](https://github.com/syn54x/ferro-orm/commit/87f0e8157640ac9984da20e0c4c7290dbfcf4bfd))
10
+
11
+ ### Build System
12
+
13
+ - **sqlx**: Enable rustls TLS for PostgreSQL connections
14
+ ([`807fa81`](https://github.com/syn54x/ferro-orm/commit/807fa8196a3742a5a50380fe6dbf727045798cc3))
15
+
16
+ ### Chores
17
+
18
+ - Sync uv.lock with project version 0.3.1
19
+ ([`c3c9f91`](https://github.com/syn54x/ferro-orm/commit/c3c9f91907a3ece8ce7bc70f08979f1dd269a87c))
20
+
21
+ ### Continuous Integration
22
+
23
+ - Build preflight wheels earlier to fail faster
24
+ ([`475c93c`](https://github.com/syn54x/ferro-orm/commit/475c93caa1d51fb07d7eda875205086761d64e8f))
25
+
26
+ - Fix linux-aarch64 wheel builds for ring/rustls asm
27
+ ([`5eadddc`](https://github.com/syn54x/ferro-orm/commit/5eadddc922b51448ad4da3841a84fd4931b19814))
28
+
29
+ - Gate release on preflight wheel builds for all platforms
30
+ ([`6ec48a2`](https://github.com/syn54x/ferro-orm/commit/6ec48a275b8dc9868612a3f374595ce63fe151ca))
31
+
32
+ - Restore legacy release workflow
33
+ ([`d3ee87c`](https://github.com/syn54x/ferro-orm/commit/d3ee87c68995a1163480eb9be8a3111032e94842))
34
+
35
+ ### Documentation
36
+
37
+ - Add Supabase PostgreSQL connection and TLS guidance
38
+ ([`b1d61ad`](https://github.com/syn54x/ferro-orm/commit/b1d61ad4395a17c7c2270c1d4776500c436c22d1))
39
+
40
+
4
41
  ## v0.3.1 (2026-04-23)
5
42
 
6
43
  ### Bug Fixes