ferro-orm 0.2.1__tar.gz → 0.3.1__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.
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/.github/PERMISSIONS.md +61 -32
- ferro_orm-0.3.1/.github/workflows/release.yml +552 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/.gitignore +1 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/CHANGELOG.md +82 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/Cargo.lock +1 -1
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/Cargo.toml +1 -1
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/PKG-INFO +3 -4
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/README.md +2 -3
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/docs/TEST_RESULTS.md +4 -2
- ferro_orm-0.3.1/docs/api/fields.md +21 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/docs/coming-soon.md +6 -2
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/docs/concepts/architecture.md +5 -3
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/docs/concepts/performance.md +7 -3
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/docs/getting-started/tutorial.md +13 -13
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/docs/guide/migrations.md +39 -7
- ferro_orm-0.3.1/docs/guide/models-and-fields.md +231 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/docs/guide/queries.md +3 -3
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/docs/guide/relationships.md +13 -4
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/docs/howto/pagination.md +5 -3
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/docs/index.md +3 -3
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/docs/migration-sqlalchemy.md +9 -6
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/pyproject.toml +6 -2
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/src/ferro/__init__.py +2 -1
- ferro_orm-0.3.1/src/ferro/_annotation_utils.py +28 -0
- ferro_orm-0.3.1/src/ferro/_shadow_fk_types.py +137 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/src/ferro/base.py +55 -3
- ferro_orm-0.3.1/src/ferro/composite_uniques.py +98 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/src/ferro/fields.py +20 -1
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/src/ferro/metaclass.py +22 -5
- ferro_orm-0.3.1/src/ferro/migrations/alembic.py +345 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/src/ferro/models.py +26 -2
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/src/ferro/relations/__init__.py +14 -2
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/src/schema.rs +51 -0
- ferro_orm-0.3.1/tests/test_alembic_autogenerate.py +190 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/tests/test_alembic_bridge.py +42 -0
- ferro_orm-0.3.1/tests/test_alembic_nullability.py +270 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/tests/test_alembic_type_mapping.py +3 -1
- ferro_orm-0.3.1/tests/test_composite_unique.py +324 -0
- ferro_orm-0.3.1/tests/test_field_wrapper.py +95 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/tests/test_metaclass_internals.py +20 -1
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/tests/test_relationship_engine.py +2 -0
- ferro_orm-0.3.1/tests/test_shadow_fk_types.py +258 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/uv.lock +1 -1
- ferro_orm-0.2.1/.github/workflows/release.yml +0 -320
- ferro_orm-0.2.1/DOCS_COMPLETE.md +0 -226
- ferro_orm-0.2.1/DOCS_RESTRUCTURE_SUMMARY.md +0 -213
- ferro_orm-0.2.1/docs/api/fields.md +0 -21
- ferro_orm-0.2.1/docs/guide/models-and-fields.md +0 -184
- ferro_orm-0.2.1/src/ferro/migrations/alembic.py +0 -211
- ferro_orm-0.2.1/tests/test_alembic_autogenerate.py +0 -94
- ferro_orm-0.2.1/tests/test_field_wrapper.py +0 -47
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/.github/PYPI_CHECKLIST.md +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/.github/PYPI_SETUP.md +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/.github/generated/wheels.generated.yml +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/.github/pull_request_template.md +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/.github/workflows/ci.yml +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/.github/workflows/packaging-smoke.yml +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/.github/workflows/publish-docs.yml +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/.github/workflows/publish.yml +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/.pre-commit-config.yaml +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/.python-version +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/CONTRIBUTING.md +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/LICENSE +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/docs/api/model.md +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/docs/api/query.md +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/docs/api/relationships.md +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/docs/api/transactions.md +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/docs/api/utilities.md +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/docs/changelog.md +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/docs/concepts/identity-map.md +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/docs/concepts/type-safety.md +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/docs/contributing.md +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/docs/faq.md +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/docs/getting-started/installation.md +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/docs/getting-started/next-steps.md +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/docs/guide/database.md +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/docs/guide/mutations.md +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/docs/guide/transactions.md +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/docs/howto/multiple-databases.md +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/docs/howto/soft-deletes.md +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/docs/howto/testing.md +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/docs/howto/timestamps.md +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/docs/stylesheets/extra.css +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/docs/why-ferro.md +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/justfile +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/mkdocs.yml +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/scripts/demo_queries.py +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/src/connection.rs +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/src/ferro/_core.pyi +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/src/ferro/migrations/__init__.py +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/src/ferro/py.typed +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/src/ferro/query/__init__.py +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/src/ferro/query/builder.py +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/src/ferro/query/nodes.py +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/src/ferro/relations/descriptors.py +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/src/ferro/state.py +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/src/lib.rs +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/src/operations.rs +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/src/query.rs +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/src/state.rs +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/tests/conftest.py +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/tests/test_aggregation.py +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/tests/test_auto_migrate.py +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/tests/test_bulk_update.py +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/tests/test_connection.py +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/tests/test_constraints.py +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/tests/test_crud.py +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/tests/test_deletion.py +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/tests/test_docs_examples.py +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/tests/test_documentation_features.py +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/tests/test_helpers.py +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/tests/test_hydration.py +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/tests/test_metadata.py +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/tests/test_models.py +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/tests/test_one_to_one.py +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/tests/test_query_builder.py +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/tests/test_refresh.py +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/tests/test_schema.py +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/tests/test_schema_constraints.py +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/tests/test_string_search.py +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/tests/test_structural_types.py +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/tests/test_temporal_types.py +0 -0
- {ferro_orm-0.2.1 → ferro_orm-0.3.1}/tests/test_transactions.py +0 -0
|
@@ -45,7 +45,37 @@ All workflows use explicit, fine-grained permissions (principle of least privile
|
|
|
45
45
|
|
|
46
46
|
**Trigger:** Manual workflow dispatch
|
|
47
47
|
|
|
48
|
-
**
|
|
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):**
|
|
49
79
|
```yaml
|
|
50
80
|
permissions:
|
|
51
81
|
contents: write
|
|
@@ -53,32 +83,23 @@ permissions:
|
|
|
53
83
|
pull-requests: write
|
|
54
84
|
```
|
|
55
85
|
|
|
56
|
-
|
|
57
|
-
-
|
|
58
|
-
- Commit version bumps to pyproject.toml and Cargo.toml
|
|
86
|
+
- `contents: write` - Allows the job to:
|
|
87
|
+
- Commit version bumps to `pyproject.toml` and `Cargo.toml`
|
|
59
88
|
- Push commits to the `main` branch
|
|
60
|
-
- Create and push git tags (e.g., `v0.
|
|
61
|
-
- Create GitHub
|
|
89
|
+
- Create and push git tags (e.g., `v0.3.1`)
|
|
90
|
+
- Create GitHub Releases
|
|
62
91
|
|
|
63
|
-
- `issues: write` - Allows
|
|
64
|
-
|
|
65
|
-
- Close issues automatically via commit messages
|
|
66
|
-
- Add labels or comments to issues
|
|
92
|
+
- `issues: write` / `pull-requests: write` - Allows semantic-release to
|
|
93
|
+
update issue/PR references in generated release notes.
|
|
67
94
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
-
|
|
75
|
-
-
|
|
76
|
-
- Updates version in both Python and Rust files
|
|
77
|
-
- Finalizes CHANGELOG.md
|
|
78
|
-
- Creates git tag
|
|
79
|
-
- Creates GitHub release
|
|
80
|
-
- Triggers publish workflow
|
|
81
|
-
- Reports whether release commits include `CHANGELOG.md`
|
|
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
|
|
82
103
|
|
|
83
104
|
**Required Secrets:**
|
|
84
105
|
- `RELEASE_DEPLOY_KEY` (private SSH key for a write-enabled deploy key)
|
|
@@ -88,15 +109,15 @@ permissions:
|
|
|
88
109
|
|
|
89
110
|
### 2. Build & Publish (jobs in `release.yml`)
|
|
90
111
|
|
|
91
|
-
**Trigger:** Part of `release.yml`
|
|
112
|
+
**Trigger:** Part of `release.yml` — all build and publish jobs live in the same workflow file.
|
|
92
113
|
|
|
93
114
|
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).
|
|
94
115
|
|
|
95
116
|
**Permissions:**
|
|
96
117
|
|
|
97
|
-
**For build-wheels, build-sdist, test-wheels:** (default - read-only)
|
|
118
|
+
**For build-wheels, build-sdist, test-wheels, verify-docs:** (default - read-only)
|
|
98
119
|
|
|
99
|
-
**For
|
|
120
|
+
**For promote-pypi job:**
|
|
100
121
|
```yaml
|
|
101
122
|
permissions:
|
|
102
123
|
id-token: write
|
|
@@ -106,10 +127,10 @@ permissions:
|
|
|
106
127
|
- `id-token: write` - Allows the job to request an OIDC token and authenticate with PyPI using Trusted Publishing.
|
|
107
128
|
|
|
108
129
|
**What It Does:**
|
|
109
|
-
- Builds wheels for multiple platforms
|
|
110
|
-
- Builds source distribution
|
|
111
|
-
-
|
|
112
|
-
-
|
|
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
|
|
113
134
|
|
|
114
135
|
---
|
|
115
136
|
|
|
@@ -268,10 +289,18 @@ Permission to manage GitHub Pages deployments:
|
|
|
268
289
|
**Cause:** Missing `id-token: write` permission
|
|
269
290
|
|
|
270
291
|
**Solution:**
|
|
271
|
-
- Ensure `
|
|
292
|
+
- Ensure `promote-pypi` job has `id-token: write`
|
|
272
293
|
- Verify PyPI trusted publisher is configured correctly
|
|
273
294
|
- Check environment name matches (`pypi`)
|
|
274
295
|
|
|
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
|
+
|
|
275
304
|
---
|
|
276
305
|
|
|
277
306
|
## Verification
|
|
@@ -0,0 +1,552 @@
|
|
|
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
|
+
ci-gate:
|
|
18
|
+
name: CI Gate
|
|
19
|
+
uses: ./.github/workflows/ci.yml
|
|
20
|
+
|
|
21
|
+
packaging-smoke:
|
|
22
|
+
name: Packaging Smoke Gate
|
|
23
|
+
uses: ./.github/workflows/packaging-smoke.yml
|
|
24
|
+
|
|
25
|
+
# Bump versions and changelog locally only; export a patch so every later job
|
|
26
|
+
# validates the exact tree that would be released. Nothing is pushed until
|
|
27
|
+
# promote-* jobs run, after wheels, sdist, tests, and docs all pass.
|
|
28
|
+
prepare-release:
|
|
29
|
+
name: Prepare release (no push)
|
|
30
|
+
needs: [ci-gate, packaging-smoke]
|
|
31
|
+
runs-on: ubuntu-latest
|
|
32
|
+
outputs:
|
|
33
|
+
release_created: ${{ steps.verify_release.outputs.release_created }}
|
|
34
|
+
release_base_sha: ${{ steps.base_sha.outputs.release_base_sha }}
|
|
35
|
+
release_tag: ${{ steps.verify_release.outputs.release_tag }}
|
|
36
|
+
release_version: ${{ steps.verify_release.outputs.release_version }}
|
|
37
|
+
permissions:
|
|
38
|
+
contents: read
|
|
39
|
+
issues: read
|
|
40
|
+
pull-requests: read
|
|
41
|
+
|
|
42
|
+
steps:
|
|
43
|
+
- name: Record workflow base SHA
|
|
44
|
+
id: base_sha
|
|
45
|
+
run: echo "release_base_sha=${{ github.sha }}" >> "$GITHUB_OUTPUT"
|
|
46
|
+
|
|
47
|
+
- name: Checkout repository
|
|
48
|
+
uses: actions/checkout@v4
|
|
49
|
+
with:
|
|
50
|
+
fetch-depth: 0
|
|
51
|
+
# actions/checkout@v4 passes --no-tags by default, even with
|
|
52
|
+
# fetch-depth: 0. semantic-release needs tags to pick the right
|
|
53
|
+
# baseline version; without them it may bump from an older tag and
|
|
54
|
+
# land on a version that has already been released.
|
|
55
|
+
fetch-tags: true
|
|
56
|
+
|
|
57
|
+
- name: Set up Python
|
|
58
|
+
uses: actions/setup-python@v5
|
|
59
|
+
with:
|
|
60
|
+
python-version: '3.13'
|
|
61
|
+
|
|
62
|
+
- name: Install UV
|
|
63
|
+
uses: astral-sh/setup-uv@v5
|
|
64
|
+
with:
|
|
65
|
+
enable-cache: true
|
|
66
|
+
|
|
67
|
+
- name: Install dependencies
|
|
68
|
+
run: |
|
|
69
|
+
uv sync --only-group release --no-install-project --python 3.13
|
|
70
|
+
|
|
71
|
+
# Fail fast if the checkout did not materialize tags. Without this guard
|
|
72
|
+
# semantic-release silently picks an older baseline and can compute an
|
|
73
|
+
# already-released version (see PSR note: "No release will be made, X has
|
|
74
|
+
# already been released!").
|
|
75
|
+
- name: Verify tag visibility
|
|
76
|
+
env:
|
|
77
|
+
GH_TOKEN: ${{ secrets.RELEASE_TOKEN || secrets.GITHUB_TOKEN }}
|
|
78
|
+
run: |
|
|
79
|
+
set -euo pipefail
|
|
80
|
+
GIT_LATEST_TAG="$(git describe --tags --abbrev=0 2>/dev/null || echo '')"
|
|
81
|
+
PSR_LATEST_TAG="$(uv run semantic-release version --print-last-released-tag 2>/dev/null | tail -n1 || echo '')"
|
|
82
|
+
|
|
83
|
+
echo "git describe --tags --abbrev=0 -> '${GIT_LATEST_TAG}'"
|
|
84
|
+
echo "semantic-release --print-last-released-tag -> '${PSR_LATEST_TAG}'"
|
|
85
|
+
|
|
86
|
+
if [[ -n "${GIT_LATEST_TAG}" && "${GIT_LATEST_TAG}" != "${PSR_LATEST_TAG}" ]]; then
|
|
87
|
+
echo "ERROR: git and semantic-release disagree on the latest tag."
|
|
88
|
+
echo "This usually means actions/checkout did not fetch tags."
|
|
89
|
+
echo "Confirm 'fetch-tags: true' on the checkout step."
|
|
90
|
+
exit 1
|
|
91
|
+
fi
|
|
92
|
+
|
|
93
|
+
- name: Run semantic-release (local bump only)
|
|
94
|
+
env:
|
|
95
|
+
GH_TOKEN: ${{ secrets.RELEASE_TOKEN || secrets.GITHUB_TOKEN }}
|
|
96
|
+
run: |
|
|
97
|
+
PRERELEASE_FLAG=""
|
|
98
|
+
if [ "${{ github.event.inputs.prerelease }}" == "true" ]; then
|
|
99
|
+
PRERELEASE_FLAG="--prerelease"
|
|
100
|
+
fi
|
|
101
|
+
|
|
102
|
+
# Writes version files + CHANGELOG only; no commit, push, tag, or VCS
|
|
103
|
+
# release. --skip-build defers packaging to validation jobs.
|
|
104
|
+
uv run semantic-release version $PRERELEASE_FLAG \
|
|
105
|
+
--no-vcs-release --no-tag --no-commit --no-push --skip-build
|
|
106
|
+
|
|
107
|
+
- name: Verify release candidate and write patch
|
|
108
|
+
id: verify_release
|
|
109
|
+
shell: bash
|
|
110
|
+
run: |
|
|
111
|
+
set -euo pipefail
|
|
112
|
+
# Normalize to a single index-vs-HEAD patch (stable for git apply on runners).
|
|
113
|
+
git add -A
|
|
114
|
+
git diff --cached HEAD > release.patch
|
|
115
|
+
|
|
116
|
+
if [[ ! -s release.patch ]]; then
|
|
117
|
+
echo "No semantic version bump in this run (index matches HEAD)."
|
|
118
|
+
echo "release_created=false" >> "$GITHUB_OUTPUT"
|
|
119
|
+
echo "changelog_validated=skipped" >> "$GITHUB_OUTPUT"
|
|
120
|
+
echo "release_tag=" >> "$GITHUB_OUTPUT"
|
|
121
|
+
echo "release_version=" >> "$GITHUB_OUTPUT"
|
|
122
|
+
exit 0
|
|
123
|
+
fi
|
|
124
|
+
|
|
125
|
+
if ! grep -qE '^diff --git a/CHANGELOG\.md b/CHANGELOG\.md' release.patch; then
|
|
126
|
+
echo "WARNING: expected CHANGELOG.md to change for a release bump."
|
|
127
|
+
echo "release_created=false" >> "$GITHUB_OUTPUT"
|
|
128
|
+
echo "changelog_validated=missing" >> "$GITHUB_OUTPUT"
|
|
129
|
+
echo "release_tag=" >> "$GITHUB_OUTPUT"
|
|
130
|
+
echo "release_version=" >> "$GITHUB_OUTPUT"
|
|
131
|
+
exit 0
|
|
132
|
+
fi
|
|
133
|
+
|
|
134
|
+
VERSION="$(python3 -c "import tomllib; print(tomllib.load(open('pyproject.toml', 'rb'))['project']['version'])")"
|
|
135
|
+
TAG="v${VERSION}"
|
|
136
|
+
|
|
137
|
+
# Final guard: if the tag already exists on the remote, bail before
|
|
138
|
+
# any irreversible promote-* step runs (PyPI, main push, GH Release).
|
|
139
|
+
if git ls-remote --tags origin "refs/tags/${TAG}" | grep -q .; then
|
|
140
|
+
echo "ERROR: tag ${TAG} already exists on the remote."
|
|
141
|
+
echo "This means semantic-release computed a version that is already released."
|
|
142
|
+
exit 1
|
|
143
|
+
fi
|
|
144
|
+
|
|
145
|
+
echo "release_created=true" >> "$GITHUB_OUTPUT"
|
|
146
|
+
echo "changelog_validated=passed" >> "$GITHUB_OUTPUT"
|
|
147
|
+
echo "release_tag=${TAG}" >> "$GITHUB_OUTPUT"
|
|
148
|
+
echo "release_version=${VERSION}" >> "$GITHUB_OUTPUT"
|
|
149
|
+
echo "Prepared ${TAG} as patch against ${{ github.sha }}"
|
|
150
|
+
|
|
151
|
+
- name: Upload release patch
|
|
152
|
+
if: steps.verify_release.outputs.release_created == 'true'
|
|
153
|
+
uses: actions/upload-artifact@v4
|
|
154
|
+
with:
|
|
155
|
+
name: release-patch
|
|
156
|
+
path: release.patch
|
|
157
|
+
|
|
158
|
+
- name: Release summary
|
|
159
|
+
if: always()
|
|
160
|
+
shell: bash
|
|
161
|
+
run: |
|
|
162
|
+
{
|
|
163
|
+
echo "## Release workflow summary"
|
|
164
|
+
echo ""
|
|
165
|
+
echo "- Trigger: \`${{ github.event_name }}\`"
|
|
166
|
+
echo "- Base ref: \`${{ github.ref_name }}\` @ \`${{ github.sha }}\`"
|
|
167
|
+
echo "- Release candidate prepared: \`${{ steps.verify_release.outputs.release_created || 'unknown' }}\`"
|
|
168
|
+
echo "- Changelog validation: \`${{ steps.verify_release.outputs.changelog_validated || 'unknown' }}\`"
|
|
169
|
+
echo "- Tag if published: \`${{ steps.verify_release.outputs.release_tag || 'n/a' }}\`"
|
|
170
|
+
} >> "$GITHUB_STEP_SUMMARY"
|
|
171
|
+
|
|
172
|
+
# Build and publish jobs are inlined here (not in a reusable workflow) so that
|
|
173
|
+
# PyPI Trusted Publishing sees workflow_ref = release.yml. Reusable workflows
|
|
174
|
+
# are not supported by PyPI Trusted Publishing.
|
|
175
|
+
build-wheels:
|
|
176
|
+
name: Build wheels (${{ matrix.platform.name }})
|
|
177
|
+
needs: [prepare-release]
|
|
178
|
+
if: needs.prepare-release.outputs.release_created == 'true'
|
|
179
|
+
runs-on: ${{ matrix.platform.runner }}
|
|
180
|
+
strategy:
|
|
181
|
+
fail-fast: false
|
|
182
|
+
matrix:
|
|
183
|
+
platform:
|
|
184
|
+
- name: linux-x86_64
|
|
185
|
+
runner: ubuntu-latest
|
|
186
|
+
target: x86_64
|
|
187
|
+
manylinux: auto
|
|
188
|
+
- name: linux-aarch64
|
|
189
|
+
runner: ubuntu-latest
|
|
190
|
+
target: aarch64
|
|
191
|
+
manylinux: auto
|
|
192
|
+
- name: macos-aarch64
|
|
193
|
+
runner: macos-latest
|
|
194
|
+
target: aarch64
|
|
195
|
+
manylinux: ''
|
|
196
|
+
- name: windows-x64
|
|
197
|
+
runner: windows-latest
|
|
198
|
+
target: x64
|
|
199
|
+
manylinux: ''
|
|
200
|
+
|
|
201
|
+
steps:
|
|
202
|
+
- name: Disable Git CRLF conversion before checkout
|
|
203
|
+
shell: bash
|
|
204
|
+
run: git config --global core.autocrlf false
|
|
205
|
+
- name: Checkout repository
|
|
206
|
+
uses: actions/checkout@v4
|
|
207
|
+
with:
|
|
208
|
+
ref: ${{ needs.prepare-release.outputs.release_base_sha }}
|
|
209
|
+
|
|
210
|
+
- name: Download release patch
|
|
211
|
+
uses: actions/download-artifact@v4
|
|
212
|
+
with:
|
|
213
|
+
name: release-patch
|
|
214
|
+
path: release-patch
|
|
215
|
+
|
|
216
|
+
- name: Apply release patch
|
|
217
|
+
shell: bash
|
|
218
|
+
run: |
|
|
219
|
+
git config core.autocrlf false
|
|
220
|
+
git apply release-patch/release.patch
|
|
221
|
+
rm -rf release-patch
|
|
222
|
+
|
|
223
|
+
- name: Set up Python
|
|
224
|
+
uses: actions/setup-python@v5
|
|
225
|
+
with:
|
|
226
|
+
python-version: '3.13'
|
|
227
|
+
|
|
228
|
+
- name: Build wheels
|
|
229
|
+
uses: PyO3/maturin-action@v1.48.0
|
|
230
|
+
with:
|
|
231
|
+
target: ${{ matrix.platform.target }}
|
|
232
|
+
args: --release --out dist --find-interpreter
|
|
233
|
+
manylinux: ${{ matrix.platform.manylinux }}
|
|
234
|
+
sccache: 'true'
|
|
235
|
+
|
|
236
|
+
- name: Upload wheels
|
|
237
|
+
uses: actions/upload-artifact@v4
|
|
238
|
+
with:
|
|
239
|
+
name: wheels-${{ matrix.platform.name }}
|
|
240
|
+
path: dist/*.whl
|
|
241
|
+
|
|
242
|
+
build-sdist:
|
|
243
|
+
name: Build sdist
|
|
244
|
+
needs: [prepare-release]
|
|
245
|
+
if: needs.prepare-release.outputs.release_created == 'true'
|
|
246
|
+
runs-on: ubuntu-latest
|
|
247
|
+
steps:
|
|
248
|
+
- name: Disable Git CRLF conversion before checkout
|
|
249
|
+
shell: bash
|
|
250
|
+
run: git config --global core.autocrlf false
|
|
251
|
+
- name: Checkout repository
|
|
252
|
+
uses: actions/checkout@v4
|
|
253
|
+
with:
|
|
254
|
+
ref: ${{ needs.prepare-release.outputs.release_base_sha }}
|
|
255
|
+
|
|
256
|
+
- name: Download release patch
|
|
257
|
+
uses: actions/download-artifact@v4
|
|
258
|
+
with:
|
|
259
|
+
name: release-patch
|
|
260
|
+
path: release-patch
|
|
261
|
+
|
|
262
|
+
- name: Apply release patch
|
|
263
|
+
shell: bash
|
|
264
|
+
run: |
|
|
265
|
+
git config core.autocrlf false
|
|
266
|
+
git apply release-patch/release.patch
|
|
267
|
+
rm -rf release-patch
|
|
268
|
+
|
|
269
|
+
- name: Build sdist
|
|
270
|
+
uses: PyO3/maturin-action@v1.48.0
|
|
271
|
+
with:
|
|
272
|
+
command: sdist
|
|
273
|
+
args: --out dist
|
|
274
|
+
|
|
275
|
+
- name: Upload sdist
|
|
276
|
+
uses: actions/upload-artifact@v4
|
|
277
|
+
with:
|
|
278
|
+
name: sdist
|
|
279
|
+
path: dist/*.tar.gz
|
|
280
|
+
|
|
281
|
+
test-wheels:
|
|
282
|
+
name: Test wheels (${{ matrix.os }})
|
|
283
|
+
needs: [prepare-release, build-wheels]
|
|
284
|
+
if: needs.prepare-release.outputs.release_created == 'true'
|
|
285
|
+
runs-on: ${{ matrix.os }}
|
|
286
|
+
strategy:
|
|
287
|
+
fail-fast: false
|
|
288
|
+
matrix:
|
|
289
|
+
os: [ubuntu-latest, windows-latest, macos-latest]
|
|
290
|
+
steps:
|
|
291
|
+
- name: Disable Git CRLF conversion before checkout
|
|
292
|
+
shell: bash
|
|
293
|
+
run: git config --global core.autocrlf false
|
|
294
|
+
- name: Checkout repository
|
|
295
|
+
uses: actions/checkout@v4
|
|
296
|
+
with:
|
|
297
|
+
ref: ${{ needs.prepare-release.outputs.release_base_sha }}
|
|
298
|
+
|
|
299
|
+
- name: Download release patch
|
|
300
|
+
uses: actions/download-artifact@v4
|
|
301
|
+
with:
|
|
302
|
+
name: release-patch
|
|
303
|
+
path: release-patch
|
|
304
|
+
|
|
305
|
+
- name: Apply release patch
|
|
306
|
+
shell: bash
|
|
307
|
+
run: |
|
|
308
|
+
git config core.autocrlf false
|
|
309
|
+
git apply release-patch/release.patch
|
|
310
|
+
rm -rf release-patch
|
|
311
|
+
|
|
312
|
+
- name: Set up Python
|
|
313
|
+
uses: actions/setup-python@v5
|
|
314
|
+
with:
|
|
315
|
+
python-version: '3.13'
|
|
316
|
+
|
|
317
|
+
- name: Download wheels
|
|
318
|
+
uses: actions/download-artifact@v4
|
|
319
|
+
with:
|
|
320
|
+
path: dist
|
|
321
|
+
pattern: wheels-*
|
|
322
|
+
merge-multiple: true
|
|
323
|
+
|
|
324
|
+
- name: Install wheel
|
|
325
|
+
shell: bash
|
|
326
|
+
run: |
|
|
327
|
+
python -m pip install --upgrade pip
|
|
328
|
+
python -m pip install --find-links dist ferro-orm
|
|
329
|
+
|
|
330
|
+
- name: Test import
|
|
331
|
+
shell: bash
|
|
332
|
+
run: |
|
|
333
|
+
python -c "import ferro; print('Ferro imported successfully')"
|
|
334
|
+
|
|
335
|
+
- name: Run basic smoke test
|
|
336
|
+
shell: bash
|
|
337
|
+
run: |
|
|
338
|
+
python -c "
|
|
339
|
+
import asyncio
|
|
340
|
+
from ferro import Model, FerroField, connect
|
|
341
|
+
from typing import Annotated
|
|
342
|
+
|
|
343
|
+
class TestModel(Model):
|
|
344
|
+
id: Annotated[int, FerroField(primary_key=True)]
|
|
345
|
+
name: str
|
|
346
|
+
|
|
347
|
+
async def test():
|
|
348
|
+
await connect('sqlite::memory:')
|
|
349
|
+
print('Connection test passed')
|
|
350
|
+
|
|
351
|
+
asyncio.run(test())
|
|
352
|
+
"
|
|
353
|
+
|
|
354
|
+
verify-docs:
|
|
355
|
+
name: Verify documentation build
|
|
356
|
+
needs: [prepare-release]
|
|
357
|
+
if: needs.prepare-release.outputs.release_created == 'true'
|
|
358
|
+
runs-on: ubuntu-latest
|
|
359
|
+
steps:
|
|
360
|
+
- name: Disable Git CRLF conversion before checkout
|
|
361
|
+
shell: bash
|
|
362
|
+
run: git config --global core.autocrlf false
|
|
363
|
+
- name: Checkout repository
|
|
364
|
+
uses: actions/checkout@v4
|
|
365
|
+
with:
|
|
366
|
+
ref: ${{ needs.prepare-release.outputs.release_base_sha }}
|
|
367
|
+
|
|
368
|
+
- name: Download release patch
|
|
369
|
+
uses: actions/download-artifact@v4
|
|
370
|
+
with:
|
|
371
|
+
name: release-patch
|
|
372
|
+
path: release-patch
|
|
373
|
+
|
|
374
|
+
- name: Apply release patch
|
|
375
|
+
shell: bash
|
|
376
|
+
run: |
|
|
377
|
+
git config core.autocrlf false
|
|
378
|
+
git apply release-patch/release.patch
|
|
379
|
+
rm -rf release-patch
|
|
380
|
+
|
|
381
|
+
- name: Set up Python
|
|
382
|
+
uses: actions/setup-python@v5
|
|
383
|
+
with:
|
|
384
|
+
python-version: '3.13'
|
|
385
|
+
|
|
386
|
+
- name: Install UV
|
|
387
|
+
uses: astral-sh/setup-uv@v5
|
|
388
|
+
with:
|
|
389
|
+
enable-cache: true
|
|
390
|
+
|
|
391
|
+
- name: Install documentation dependencies
|
|
392
|
+
run: |
|
|
393
|
+
uv sync --only-group docs --no-install-project --python 3.13
|
|
394
|
+
|
|
395
|
+
- name: Build MkDocs site
|
|
396
|
+
run: |
|
|
397
|
+
uv run --no-sync mkdocs build
|
|
398
|
+
|
|
399
|
+
# ---------------------------------------------------------------------------
|
|
400
|
+
# Promote phase: every validation above has passed. Irreversible steps now
|
|
401
|
+
# run in a strict order:
|
|
402
|
+
# promote-pypi -> publishes to PyPI (first irreversible action)
|
|
403
|
+
# promote-git -> commits bump, pushes main, creates tag, creates GH Release
|
|
404
|
+
# promote-docs -> deploys MkDocs site pinned to the new tag
|
|
405
|
+
# If promote-pypi fails, main is untouched and the run can be re-triggered.
|
|
406
|
+
# ---------------------------------------------------------------------------
|
|
407
|
+
|
|
408
|
+
promote-pypi:
|
|
409
|
+
name: Publish to PyPI
|
|
410
|
+
needs: [prepare-release, build-wheels, build-sdist, test-wheels, verify-docs]
|
|
411
|
+
if: needs.prepare-release.outputs.release_created == 'true'
|
|
412
|
+
runs-on: ubuntu-latest
|
|
413
|
+
environment:
|
|
414
|
+
name: pypi
|
|
415
|
+
url: https://pypi.org/p/ferro-orm
|
|
416
|
+
permissions:
|
|
417
|
+
id-token: write
|
|
418
|
+
steps:
|
|
419
|
+
- name: Download sdist
|
|
420
|
+
uses: actions/download-artifact@v4
|
|
421
|
+
with:
|
|
422
|
+
name: sdist
|
|
423
|
+
path: dist
|
|
424
|
+
|
|
425
|
+
- name: Download wheels
|
|
426
|
+
uses: actions/download-artifact@v4
|
|
427
|
+
with:
|
|
428
|
+
pattern: wheels-*
|
|
429
|
+
path: dist
|
|
430
|
+
merge-multiple: true
|
|
431
|
+
|
|
432
|
+
- name: Publish to PyPI
|
|
433
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
434
|
+
with:
|
|
435
|
+
skip-existing: true
|
|
436
|
+
verbose: true
|
|
437
|
+
|
|
438
|
+
promote-git:
|
|
439
|
+
name: Commit, tag, and create GitHub Release
|
|
440
|
+
needs: [prepare-release, promote-pypi]
|
|
441
|
+
if: needs.prepare-release.outputs.release_created == 'true'
|
|
442
|
+
runs-on: ubuntu-latest
|
|
443
|
+
permissions:
|
|
444
|
+
contents: write
|
|
445
|
+
issues: write
|
|
446
|
+
pull-requests: write
|
|
447
|
+
steps:
|
|
448
|
+
- name: Disable Git CRLF conversion before checkout
|
|
449
|
+
shell: bash
|
|
450
|
+
run: git config --global core.autocrlf false
|
|
451
|
+
|
|
452
|
+
- name: Checkout repository
|
|
453
|
+
uses: actions/checkout@v4
|
|
454
|
+
with:
|
|
455
|
+
ref: ${{ needs.prepare-release.outputs.release_base_sha }}
|
|
456
|
+
fetch-depth: 0
|
|
457
|
+
fetch-tags: true
|
|
458
|
+
ssh-key: ${{ secrets.RELEASE_DEPLOY_KEY }}
|
|
459
|
+
# Required so the deploy key stays loaded for git push below.
|
|
460
|
+
persist-credentials: true
|
|
461
|
+
|
|
462
|
+
- name: Download release patch
|
|
463
|
+
uses: actions/download-artifact@v4
|
|
464
|
+
with:
|
|
465
|
+
name: release-patch
|
|
466
|
+
path: release-patch
|
|
467
|
+
|
|
468
|
+
- name: Apply release patch and push release commit
|
|
469
|
+
env:
|
|
470
|
+
VERSION: ${{ needs.prepare-release.outputs.release_version }}
|
|
471
|
+
TAG: ${{ needs.prepare-release.outputs.release_tag }}
|
|
472
|
+
run: |
|
|
473
|
+
set -euo pipefail
|
|
474
|
+
git config core.autocrlf false
|
|
475
|
+
git apply release-patch/release.patch
|
|
476
|
+
rm -rf release-patch
|
|
477
|
+
|
|
478
|
+
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
479
|
+
git config user.name "github-actions[bot]"
|
|
480
|
+
git remote set-url origin "git@github.com:${{ github.repository }}.git"
|
|
481
|
+
|
|
482
|
+
# Re-check remote (prepare-release already checked, but the window
|
|
483
|
+
# between jobs is non-zero).
|
|
484
|
+
if git ls-remote --tags origin "refs/tags/${TAG}" | grep -q .; then
|
|
485
|
+
echo "ERROR: tag ${TAG} appeared on the remote between jobs."
|
|
486
|
+
exit 1
|
|
487
|
+
fi
|
|
488
|
+
|
|
489
|
+
git add -A
|
|
490
|
+
git commit --author="semantic-release <semantic-release@github.com>" \
|
|
491
|
+
-m "chore(release): ${VERSION}" \
|
|
492
|
+
-m "Automatically generated by python-semantic-release"
|
|
493
|
+
git push origin "HEAD:refs/heads/${{ github.ref_name }}"
|
|
494
|
+
|
|
495
|
+
git tag -a "${TAG}" -m "Release ${TAG}"
|
|
496
|
+
git push origin "refs/tags/${TAG}"
|
|
497
|
+
|
|
498
|
+
# semantic-release matches branch config (e.g. branches.main); detached HEAD fails with
|
|
499
|
+
# "Detached HEAD state cannot match any release groups".
|
|
500
|
+
- name: Attach HEAD to branch for semantic-release
|
|
501
|
+
run: git switch -C "${{ github.ref_name }}"
|
|
502
|
+
|
|
503
|
+
- name: Set up Python
|
|
504
|
+
uses: actions/setup-python@v5
|
|
505
|
+
with:
|
|
506
|
+
python-version: '3.13'
|
|
507
|
+
|
|
508
|
+
- name: Install UV
|
|
509
|
+
uses: astral-sh/setup-uv@v5
|
|
510
|
+
with:
|
|
511
|
+
enable-cache: true
|
|
512
|
+
|
|
513
|
+
- name: Install dependencies
|
|
514
|
+
run: |
|
|
515
|
+
uv sync --only-group release --no-install-project --python 3.13
|
|
516
|
+
|
|
517
|
+
# semantic-release publish only uploads assets to an existing GitHub
|
|
518
|
+
# Release. Create the release with generated notes first, then attach
|
|
519
|
+
# wheels + sdist from the validation jobs.
|
|
520
|
+
- name: Download sdist for GitHub Release assets
|
|
521
|
+
uses: actions/download-artifact@v4
|
|
522
|
+
with:
|
|
523
|
+
name: sdist
|
|
524
|
+
path: dist
|
|
525
|
+
|
|
526
|
+
- name: Download wheels for GitHub Release assets
|
|
527
|
+
uses: actions/download-artifact@v4
|
|
528
|
+
with:
|
|
529
|
+
pattern: wheels-*
|
|
530
|
+
path: dist
|
|
531
|
+
merge-multiple: true
|
|
532
|
+
|
|
533
|
+
- name: Create GitHub Release and upload assets
|
|
534
|
+
env:
|
|
535
|
+
GH_TOKEN: ${{ secrets.RELEASE_TOKEN || secrets.GITHUB_TOKEN }}
|
|
536
|
+
run: |
|
|
537
|
+
set -euo pipefail
|
|
538
|
+
TAG="${{ needs.prepare-release.outputs.release_tag }}"
|
|
539
|
+
uv run semantic-release changelog --post-to-release-tag "$TAG"
|
|
540
|
+
uv run semantic-release publish --tag "$TAG"
|
|
541
|
+
|
|
542
|
+
promote-docs:
|
|
543
|
+
name: Deploy Documentation
|
|
544
|
+
needs: [prepare-release, promote-git]
|
|
545
|
+
if: needs.prepare-release.outputs.release_created == 'true'
|
|
546
|
+
uses: ./.github/workflows/publish-docs.yml
|
|
547
|
+
permissions:
|
|
548
|
+
contents: read
|
|
549
|
+
pages: write
|
|
550
|
+
id-token: write
|
|
551
|
+
with:
|
|
552
|
+
ref: ${{ needs.prepare-release.outputs.release_tag }}
|