ferro-orm 0.1.1__tar.gz → 0.2.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/.github/ISSUE_TEMPLATE/bug_report.md +43 -0
- ferro_orm-0.2.1/.github/ISSUE_TEMPLATE/feature_request.md +37 -0
- {ferro_orm-0.1.1 → ferro_orm-0.2.1}/.github/PERMISSIONS.md +51 -58
- {ferro_orm-0.1.1 → ferro_orm-0.2.1}/.github/PYPI_CHECKLIST.md +8 -11
- {ferro_orm-0.1.1 → ferro_orm-0.2.1}/.github/PYPI_SETUP.md +17 -10
- ferro_orm-0.2.1/.github/pull_request_template.md +36 -0
- {ferro_orm-0.1.1 → ferro_orm-0.2.1}/.github/workflows/ci.yml +7 -56
- ferro_orm-0.2.1/.github/workflows/packaging-smoke.yml +62 -0
- {ferro_orm-0.1.1 → ferro_orm-0.2.1}/.github/workflows/publish-docs.yml +10 -2
- {ferro_orm-0.1.1 → ferro_orm-0.2.1}/.github/workflows/publish.yml +15 -58
- ferro_orm-0.2.1/.github/workflows/release.yml +320 -0
- {ferro_orm-0.1.1 → ferro_orm-0.2.1}/.gitignore +3 -2
- ferro_orm-0.2.1/CHANGELOG.md +172 -0
- {ferro_orm-0.1.1 → ferro_orm-0.2.1}/Cargo.lock +330 -229
- {ferro_orm-0.1.1 → ferro_orm-0.2.1}/Cargo.toml +1 -1
- ferro_orm-0.2.1/DOCS_COMPLETE.md +226 -0
- ferro_orm-0.2.1/DOCS_RESTRUCTURE_SUMMARY.md +213 -0
- {ferro_orm-0.1.1 → ferro_orm-0.2.1}/PKG-INFO +3 -3
- {ferro_orm-0.1.1 → ferro_orm-0.2.1}/README.md +2 -2
- ferro_orm-0.2.1/docs/TEST_RESULTS.md +208 -0
- ferro_orm-0.2.1/docs/api/fields.md +21 -0
- ferro_orm-0.2.1/docs/api/model.md +29 -0
- ferro_orm-0.2.1/docs/api/query.md +24 -0
- ferro_orm-0.2.1/docs/api/relationships.md +28 -0
- ferro_orm-0.2.1/docs/api/transactions.md +36 -0
- ferro_orm-0.2.1/docs/api/utilities.md +75 -0
- ferro_orm-0.2.1/docs/changelog.md +36 -0
- ferro_orm-0.2.1/docs/coming-soon.md +514 -0
- ferro_orm-0.2.1/docs/concepts/architecture.md +330 -0
- ferro_orm-0.2.1/docs/concepts/identity-map.md +285 -0
- ferro_orm-0.2.1/docs/concepts/performance.md +221 -0
- ferro_orm-0.2.1/docs/concepts/type-safety.md +159 -0
- ferro_orm-0.2.1/docs/faq.md +255 -0
- ferro_orm-0.2.1/docs/getting-started/installation.md +90 -0
- ferro_orm-0.2.1/docs/getting-started/next-steps.md +159 -0
- ferro_orm-0.2.1/docs/getting-started/tutorial.md +388 -0
- ferro_orm-0.2.1/docs/guide/database.md +266 -0
- ferro_orm-0.2.1/docs/guide/migrations.md +411 -0
- ferro_orm-0.2.1/docs/guide/models-and-fields.md +184 -0
- ferro_orm-0.2.1/docs/guide/mutations.md +461 -0
- ferro_orm-0.2.1/docs/guide/queries.md +329 -0
- ferro_orm-0.2.1/docs/guide/relationships.md +332 -0
- ferro_orm-0.2.1/docs/guide/transactions.md +357 -0
- ferro_orm-0.2.1/docs/howto/multiple-databases.md +74 -0
- ferro_orm-0.2.1/docs/howto/pagination.md +353 -0
- ferro_orm-0.2.1/docs/howto/soft-deletes.md +86 -0
- ferro_orm-0.2.1/docs/howto/testing.md +123 -0
- ferro_orm-0.2.1/docs/howto/timestamps.md +57 -0
- ferro_orm-0.2.1/docs/index.md +142 -0
- ferro_orm-0.2.1/docs/migration-sqlalchemy.md +150 -0
- ferro_orm-0.2.1/docs/stylesheets/extra.css +27 -0
- ferro_orm-0.2.1/docs/why-ferro.md +206 -0
- ferro_orm-0.2.1/mkdocs.yml +161 -0
- {ferro_orm-0.1.1 → ferro_orm-0.2.1}/pyproject.toml +20 -3
- {ferro_orm-0.1.1 → ferro_orm-0.2.1}/scripts/demo_queries.py +3 -3
- {ferro_orm-0.1.1 → ferro_orm-0.2.1}/src/ferro/__init__.py +4 -2
- ferro_orm-0.2.1/src/ferro/fields.py +496 -0
- ferro_orm-0.2.1/src/ferro/metaclass.py +391 -0
- {ferro_orm-0.1.1 → ferro_orm-0.2.1}/src/ferro/models.py +9 -0
- ferro_orm-0.2.1/src/ferro/query/__init__.py +6 -0
- {ferro_orm-0.1.1 → ferro_orm-0.2.1}/src/ferro/query/builder.py +2 -2
- {ferro_orm-0.1.1 → ferro_orm-0.2.1}/src/ferro/relations/__init__.py +15 -13
- {ferro_orm-0.1.1 → ferro_orm-0.2.1}/src/ferro/relations/descriptors.py +22 -24
- {ferro_orm-0.1.1 → ferro_orm-0.2.1}/tests/conftest.py +4 -3
- {ferro_orm-0.1.1 → ferro_orm-0.2.1}/tests/test_alembic_bridge.py +4 -4
- ferro_orm-0.2.1/tests/test_auto_migrate.py +78 -0
- {ferro_orm-0.1.1 → ferro_orm-0.2.1}/tests/test_crud.py +25 -25
- {ferro_orm-0.1.1 → ferro_orm-0.2.1}/tests/test_docs_examples.py +3 -0
- ferro_orm-0.2.1/tests/test_documentation_features.py +830 -0
- ferro_orm-0.2.1/tests/test_field_wrapper.py +47 -0
- ferro_orm-0.2.1/tests/test_metaclass_internals.py +340 -0
- {ferro_orm-0.1.1 → ferro_orm-0.2.1}/tests/test_one_to_one.py +2 -2
- {ferro_orm-0.1.1 → ferro_orm-0.2.1}/tests/test_relationship_engine.py +76 -11
- {ferro_orm-0.1.1 → ferro_orm-0.2.1}/tests/test_schema_constraints.py +8 -6
- {ferro_orm-0.1.1 → ferro_orm-0.2.1}/uv.lock +31 -1
- ferro_orm-0.1.1/.github/workflows/release.yml +0 -76
- ferro_orm-0.1.1/.github/workflows/update-changelog.yml +0 -76
- ferro_orm-0.1.1/CHANGELOG.md +0 -48
- ferro_orm-0.1.1/docs/api/core-models.md +0 -6
- ferro_orm-0.1.1/docs/api/field-metadata.md +0 -13
- ferro_orm-0.1.1/docs/api/global-functions.md +0 -21
- ferro_orm-0.1.1/docs/api/query-builder.md +0 -11
- ferro_orm-0.1.1/docs/api.md +0 -10
- ferro_orm-0.1.1/docs/connection.md +0 -48
- ferro_orm-0.1.1/docs/fields.md +0 -59
- ferro_orm-0.1.1/docs/index.md +0 -3
- ferro_orm-0.1.1/docs/migrations.md +0 -52
- ferro_orm-0.1.1/docs/models.md +0 -53
- ferro_orm-0.1.1/docs/queries.md +0 -89
- ferro_orm-0.1.1/docs/relations.md +0 -85
- ferro_orm-0.1.1/docs/transactions.md +0 -57
- ferro_orm-0.1.1/mkdocs.yml +0 -104
- ferro_orm-0.1.1/src/ferro/metaclass.py +0 -200
- ferro_orm-0.1.1/src/ferro/query/__init__.py +0 -6
- ferro_orm-0.1.1/tests/test_auto_migrate.py +0 -37
- {ferro_orm-0.1.1 → ferro_orm-0.2.1}/.github/generated/wheels.generated.yml +0 -0
- {ferro_orm-0.1.1 → ferro_orm-0.2.1}/.pre-commit-config.yaml +0 -0
- {ferro_orm-0.1.1 → ferro_orm-0.2.1}/.python-version +0 -0
- {ferro_orm-0.1.1 → ferro_orm-0.2.1}/CONTRIBUTING.md +0 -0
- {ferro_orm-0.1.1 → ferro_orm-0.2.1}/LICENSE +0 -0
- {ferro_orm-0.1.1 → ferro_orm-0.2.1}/docs/contributing.md +0 -0
- {ferro_orm-0.1.1 → ferro_orm-0.2.1}/justfile +0 -0
- {ferro_orm-0.1.1 → ferro_orm-0.2.1}/src/connection.rs +0 -0
- {ferro_orm-0.1.1 → ferro_orm-0.2.1}/src/ferro/_core.pyi +0 -0
- {ferro_orm-0.1.1 → ferro_orm-0.2.1}/src/ferro/base.py +0 -0
- {ferro_orm-0.1.1 → ferro_orm-0.2.1}/src/ferro/migrations/__init__.py +0 -0
- {ferro_orm-0.1.1 → ferro_orm-0.2.1}/src/ferro/migrations/alembic.py +0 -0
- {ferro_orm-0.1.1 → ferro_orm-0.2.1}/src/ferro/py.typed +0 -0
- {ferro_orm-0.1.1 → ferro_orm-0.2.1}/src/ferro/query/nodes.py +0 -0
- {ferro_orm-0.1.1 → ferro_orm-0.2.1}/src/ferro/state.py +0 -0
- {ferro_orm-0.1.1 → ferro_orm-0.2.1}/src/lib.rs +0 -0
- {ferro_orm-0.1.1 → ferro_orm-0.2.1}/src/operations.rs +0 -0
- {ferro_orm-0.1.1 → ferro_orm-0.2.1}/src/query.rs +0 -0
- {ferro_orm-0.1.1 → ferro_orm-0.2.1}/src/schema.rs +0 -0
- {ferro_orm-0.1.1 → ferro_orm-0.2.1}/src/state.rs +0 -0
- {ferro_orm-0.1.1 → ferro_orm-0.2.1}/tests/test_aggregation.py +0 -0
- {ferro_orm-0.1.1 → ferro_orm-0.2.1}/tests/test_alembic_autogenerate.py +0 -0
- {ferro_orm-0.1.1 → ferro_orm-0.2.1}/tests/test_alembic_type_mapping.py +0 -0
- {ferro_orm-0.1.1 → ferro_orm-0.2.1}/tests/test_bulk_update.py +0 -0
- {ferro_orm-0.1.1 → ferro_orm-0.2.1}/tests/test_connection.py +0 -0
- {ferro_orm-0.1.1 → ferro_orm-0.2.1}/tests/test_constraints.py +0 -0
- {ferro_orm-0.1.1 → ferro_orm-0.2.1}/tests/test_deletion.py +0 -0
- {ferro_orm-0.1.1 → ferro_orm-0.2.1}/tests/test_helpers.py +0 -0
- {ferro_orm-0.1.1 → ferro_orm-0.2.1}/tests/test_hydration.py +0 -0
- {ferro_orm-0.1.1 → ferro_orm-0.2.1}/tests/test_metadata.py +0 -0
- {ferro_orm-0.1.1 → ferro_orm-0.2.1}/tests/test_models.py +0 -0
- {ferro_orm-0.1.1 → ferro_orm-0.2.1}/tests/test_query_builder.py +0 -0
- {ferro_orm-0.1.1 → ferro_orm-0.2.1}/tests/test_refresh.py +0 -0
- {ferro_orm-0.1.1 → ferro_orm-0.2.1}/tests/test_schema.py +0 -0
- {ferro_orm-0.1.1 → ferro_orm-0.2.1}/tests/test_string_search.py +0 -0
- {ferro_orm-0.1.1 → ferro_orm-0.2.1}/tests/test_structural_types.py +0 -0
- {ferro_orm-0.1.1 → ferro_orm-0.2.1}/tests/test_temporal_types.py +0 -0
- {ferro_orm-0.1.1 → ferro_orm-0.2.1}/tests/test_transactions.py +0 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Bug report
|
|
3
|
+
about: Report a bug or unexpected behavior
|
|
4
|
+
title: "`bug` "
|
|
5
|
+
labels: bug
|
|
6
|
+
assignees: Ox54
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## Summary
|
|
11
|
+
|
|
12
|
+
<!-- Brief description of the bug. -->
|
|
13
|
+
|
|
14
|
+
## Environment
|
|
15
|
+
|
|
16
|
+
- **Ferro version:** <!-- e.g. 0.1.0 or git commit -->
|
|
17
|
+
- **Python version:**
|
|
18
|
+
- **OS:** <!-- e.g. macOS 14, Ubuntu 22.04 -->
|
|
19
|
+
- **Database:** <!-- e.g. SQLite 3.43, PostgreSQL 15 -->
|
|
20
|
+
|
|
21
|
+
## Steps to reproduce
|
|
22
|
+
|
|
23
|
+
1.
|
|
24
|
+
2.
|
|
25
|
+
3.
|
|
26
|
+
|
|
27
|
+
## Expected behavior
|
|
28
|
+
|
|
29
|
+
<!-- What should happen. -->
|
|
30
|
+
|
|
31
|
+
## Actual behavior
|
|
32
|
+
|
|
33
|
+
<!-- What actually happens. Include error messages or tracebacks if relevant. -->
|
|
34
|
+
|
|
35
|
+
## Minimal example (optional)
|
|
36
|
+
|
|
37
|
+
```python
|
|
38
|
+
# Minimal code that reproduces the issue
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Additional context
|
|
42
|
+
|
|
43
|
+
<!-- Logs, screenshots, or other details that might help. -->
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Feature request
|
|
3
|
+
about: Suggest a new feature or enhancement for Ferro
|
|
4
|
+
title: "`feat` "
|
|
5
|
+
labels: feature
|
|
6
|
+
assignees: Ox54
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## Summary
|
|
11
|
+
|
|
12
|
+
<!-- One or two sentences describing the feature and why it would be useful. -->
|
|
13
|
+
|
|
14
|
+
## Current state
|
|
15
|
+
|
|
16
|
+
**Status:** <!-- e.g. Not implemented / Partially implemented -->
|
|
17
|
+
|
|
18
|
+
<!-- If partially implemented, list what works and what does not. -->
|
|
19
|
+
|
|
20
|
+
**Documentation references:**
|
|
21
|
+
- <!-- e.g. docs/coming-soon.md, docs/guide/queries.md (lines X–Y) -->
|
|
22
|
+
|
|
23
|
+
**Current workaround:** <!-- How can users achieve this today, if at all? -->
|
|
24
|
+
|
|
25
|
+
## Proposed API (examples)
|
|
26
|
+
|
|
27
|
+
```python
|
|
28
|
+
# Example of how the feature would be used
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
<!-- Describe how this would integrate with the existing API (query builder, models, etc.). -->
|
|
32
|
+
|
|
33
|
+
## Acceptance criteria
|
|
34
|
+
|
|
35
|
+
- [ ]
|
|
36
|
+
- [ ]
|
|
37
|
+
- [ ] Docs updated (e.g. remove from Coming Soon, add to relevant guide).
|
|
@@ -41,31 +41,9 @@ All workflows use explicit, fine-grained permissions (principle of least privile
|
|
|
41
41
|
|
|
42
42
|
---
|
|
43
43
|
|
|
44
|
-
### 1.
|
|
44
|
+
### 1. Release (`release.yml`)
|
|
45
45
|
|
|
46
|
-
**Trigger:**
|
|
47
|
-
|
|
48
|
-
**Permissions:**
|
|
49
|
-
```yaml
|
|
50
|
-
permissions:
|
|
51
|
-
contents: write
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
**Why These Permissions:**
|
|
55
|
-
- `contents: write` - Allows the workflow to:
|
|
56
|
-
- Commit updated CHANGELOG.md back to the repository
|
|
57
|
-
- Push changes to the `main` branch
|
|
58
|
-
|
|
59
|
-
**What It Does:**
|
|
60
|
-
- Reads conventional commits since last release
|
|
61
|
-
- Updates the `[Unreleased]` section of CHANGELOG.md
|
|
62
|
-
- Commits and pushes the updated changelog
|
|
63
|
-
|
|
64
|
-
---
|
|
65
|
-
|
|
66
|
-
### 2. Release (`release.yml`)
|
|
67
|
-
|
|
68
|
-
**Trigger:** Manual workflow dispatch OR release published
|
|
46
|
+
**Trigger:** Manual workflow dispatch
|
|
69
47
|
|
|
70
48
|
**Permissions:**
|
|
71
49
|
```yaml
|
|
@@ -100,22 +78,23 @@ permissions:
|
|
|
100
78
|
- Creates git tag
|
|
101
79
|
- Creates GitHub release
|
|
102
80
|
- Triggers publish workflow
|
|
81
|
+
- Reports whether release commits include `CHANGELOG.md`
|
|
82
|
+
|
|
83
|
+
**Required Secrets:**
|
|
84
|
+
- `RELEASE_DEPLOY_KEY` (private SSH key for a write-enabled deploy key)
|
|
85
|
+
- `RELEASE_TOKEN` (recommended PAT for release API actions and downstream workflow triggering, falls back to `GITHUB_TOKEN`)
|
|
103
86
|
|
|
104
87
|
---
|
|
105
88
|
|
|
106
|
-
###
|
|
89
|
+
### 2. Build & Publish (jobs in `release.yml`)
|
|
90
|
+
|
|
91
|
+
**Trigger:** Part of `release.yml` after the release job (no reusable workflow).
|
|
107
92
|
|
|
108
|
-
|
|
93
|
+
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).
|
|
109
94
|
|
|
110
95
|
**Permissions:**
|
|
111
96
|
|
|
112
|
-
**For build
|
|
113
|
-
```yaml
|
|
114
|
-
# No explicit permissions needed
|
|
115
|
-
# Uses default read permissions to:
|
|
116
|
-
# - Checkout code
|
|
117
|
-
# - Read repository contents
|
|
118
|
-
```
|
|
97
|
+
**For build-wheels, build-sdist, test-wheels:** (default - read-only)
|
|
119
98
|
|
|
120
99
|
**For publish-pypi job:**
|
|
121
100
|
```yaml
|
|
@@ -123,6 +102,27 @@ permissions:
|
|
|
123
102
|
id-token: write
|
|
124
103
|
```
|
|
125
104
|
|
|
105
|
+
**Why These Permissions:**
|
|
106
|
+
- `id-token: write` - Allows the job to request an OIDC token and authenticate with PyPI using Trusted Publishing.
|
|
107
|
+
|
|
108
|
+
**What It Does:**
|
|
109
|
+
- Builds wheels for multiple platforms from the release tag
|
|
110
|
+
- Builds source distribution
|
|
111
|
+
- Tests built packages
|
|
112
|
+
- Publishes to PyPI using OIDC authentication
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
### 3. Publish Docs (`publish-docs.yml`)
|
|
117
|
+
|
|
118
|
+
**Trigger:** Workflow call from `release.yml`
|
|
119
|
+
|
|
120
|
+
**Permissions:**
|
|
121
|
+
```yaml
|
|
122
|
+
permissions:
|
|
123
|
+
contents: read
|
|
124
|
+
```
|
|
125
|
+
|
|
126
126
|
**For deploy-docs job:**
|
|
127
127
|
```yaml
|
|
128
128
|
permissions:
|
|
@@ -131,21 +131,13 @@ permissions:
|
|
|
131
131
|
```
|
|
132
132
|
|
|
133
133
|
**Why These Permissions:**
|
|
134
|
-
- `id-token: write` - Allows the workflow to:
|
|
135
|
-
- Request an OIDC token from GitHub
|
|
136
|
-
- Authenticate with PyPI using Trusted Publishing
|
|
137
|
-
- Publish packages without API tokens
|
|
138
|
-
|
|
139
134
|
- `pages: write` - Allows the workflow to:
|
|
140
135
|
- Deploy the generated MkDocs static site to GitHub Pages
|
|
141
136
|
- Update the Pages deployment for the repository
|
|
137
|
+
- `id-token: write` - Allows secure OIDC auth for Pages deployment
|
|
142
138
|
|
|
143
139
|
**What It Does:**
|
|
144
|
-
- Builds
|
|
145
|
-
- Builds source distribution
|
|
146
|
-
- Tests built packages
|
|
147
|
-
- Publishes to PyPI using OIDC authentication
|
|
148
|
-
- Builds MkDocs docs on release
|
|
140
|
+
- Builds MkDocs docs
|
|
149
141
|
- Deploys docs to GitHub Pages
|
|
150
142
|
|
|
151
143
|
---
|
|
@@ -254,14 +246,22 @@ Permission to manage GitHub Pages deployments:
|
|
|
254
246
|
- `pull-requests: write` for PR comments
|
|
255
247
|
- `issues: write` for issue comments
|
|
256
248
|
|
|
257
|
-
### Release
|
|
249
|
+
### Release Completed But Publish/Docs Did Not Run
|
|
258
250
|
|
|
259
|
-
**Cause:**
|
|
251
|
+
**Cause:** `release.yml` gates downstream jobs. If CI, packaging smoke, or release creation fails, publish/docs are skipped.
|
|
260
252
|
|
|
261
253
|
**Solution:**
|
|
262
|
-
-
|
|
263
|
-
-
|
|
264
|
-
|
|
254
|
+
- Open the failed `release.yml` run and inspect the first failed job.
|
|
255
|
+
- Re-run `release.yml` after fixing the upstream failure.
|
|
256
|
+
|
|
257
|
+
### Release Fails to Push to `main` with GH013 Ruleset Error
|
|
258
|
+
|
|
259
|
+
**Cause:** Repository rules require pull requests for `main`, and the release actor is not allowed to bypass.
|
|
260
|
+
|
|
261
|
+
**Solution:**
|
|
262
|
+
- Ensure the workflow uses the `RELEASE_DEPLOY_KEY` secret (configured in `release.yml`).
|
|
263
|
+
- In repo rulesets for `main`, add the deploy key actor (or your release bot user) to bypass "Changes must be made through a pull request".
|
|
264
|
+
- Re-run the Release workflow.
|
|
265
265
|
|
|
266
266
|
### PyPI Publishing Fails with Authentication Error
|
|
267
267
|
|
|
@@ -278,13 +278,6 @@ Permission to manage GitHub Pages deployments:
|
|
|
278
278
|
|
|
279
279
|
To verify permissions are working:
|
|
280
280
|
|
|
281
|
-
### Test Update Changelog
|
|
282
|
-
```bash
|
|
283
|
-
git commit --allow-empty -m "feat: test changelog workflow"
|
|
284
|
-
git push
|
|
285
|
-
# Check Actions tab - should see commit from github-actions[bot]
|
|
286
|
-
```
|
|
287
|
-
|
|
288
281
|
### Test Release
|
|
289
282
|
```bash
|
|
290
283
|
gh workflow run release.yml
|
|
@@ -293,8 +286,8 @@ gh workflow run release.yml
|
|
|
293
286
|
|
|
294
287
|
### Test Publish
|
|
295
288
|
```bash
|
|
296
|
-
# Triggered
|
|
297
|
-
|
|
289
|
+
# Triggered by release.yml after a successful release
|
|
290
|
+
gh run list --workflow=release.yml
|
|
298
291
|
```
|
|
299
292
|
|
|
300
293
|
---
|
|
@@ -321,5 +314,5 @@ gh workflow run release.yml
|
|
|
321
314
|
|
|
322
315
|
---
|
|
323
316
|
|
|
324
|
-
**Last Updated:** 2026-
|
|
317
|
+
**Last Updated:** 2026-02-13
|
|
325
318
|
**Status:** ✅ All workflows properly configured with fine-grained permissions
|
|
@@ -15,7 +15,7 @@ Use this checklist to track your progress setting up PyPI Trusted Publishing.
|
|
|
15
15
|
- [ ] Added trusted publisher with correct details:
|
|
16
16
|
- [ ] Owner: `syn54x`
|
|
17
17
|
- [ ] Repository: `ferro-orm`
|
|
18
|
-
- [ ] Workflow: `publish.yml`
|
|
18
|
+
- [ ] Workflow: `release.yml` (must be the top-level workflow that runs the job; do not use `publish.yml` when it is called from release.yml)
|
|
19
19
|
- [ ] Environment: `pypi` (optional)
|
|
20
20
|
- [ ] Verified configuration appears in publisher list
|
|
21
21
|
|
|
@@ -33,14 +33,14 @@ Use this checklist to track your progress setting up PyPI Trusted Publishing.
|
|
|
33
33
|
|
|
34
34
|
## Workflow Verification
|
|
35
35
|
|
|
36
|
-
- [ ] Confirmed `.github/workflows/publish.yml`
|
|
37
|
-
- [ ] Verified
|
|
38
|
-
- [ ] Verified
|
|
36
|
+
- [ ] Confirmed `.github/workflows/release.yml` and `.github/workflows/publish.yml` exist
|
|
37
|
+
- [ ] Verified the job that publishes to PyPI has `id-token: write` (in publish.yml, used by release.yml)
|
|
38
|
+
- [ ] Verified publish-pypi job has `environment: pypi` (if using environment)
|
|
39
39
|
- [ ] All workflows pass pre-commit hooks
|
|
40
40
|
|
|
41
41
|
## Testing
|
|
42
42
|
|
|
43
|
-
- [ ] Test workflow triggered manually
|
|
43
|
+
- [ ] Test release workflow triggered manually
|
|
44
44
|
- [ ] Reviewed workflow logs for authentication
|
|
45
45
|
- [ ] No OIDC errors in logs
|
|
46
46
|
|
|
@@ -64,14 +64,11 @@ Use this checklist to track your progress setting up PyPI Trusted Publishing.
|
|
|
64
64
|
## Quick Commands
|
|
65
65
|
|
|
66
66
|
```bash
|
|
67
|
-
# Manual workflow trigger
|
|
68
|
-
gh workflow run
|
|
69
|
-
|
|
70
|
-
# Create a test release
|
|
71
|
-
gh release create v0.1.1 --generate-notes
|
|
67
|
+
# Manual release workflow trigger
|
|
68
|
+
gh workflow run release.yml
|
|
72
69
|
|
|
73
70
|
# Check workflow status
|
|
74
|
-
gh run list --workflow=
|
|
71
|
+
gh run list --workflow=release.yml
|
|
75
72
|
|
|
76
73
|
# Install and test
|
|
77
74
|
pip install ferro-orm
|
|
@@ -61,9 +61,10 @@ If you want to reserve the package name before publishing:
|
|
|
61
61
|
PyPI Project Name: ferro-orm
|
|
62
62
|
Owner: syn54x
|
|
63
63
|
Repository name: ferro-orm
|
|
64
|
-
Workflow filename:
|
|
64
|
+
Workflow filename: release.yml
|
|
65
65
|
Environment name: pypi (optional but recommended)
|
|
66
66
|
```
|
|
67
|
+
**Important:** Use `release.yml`, not `publish.yml`. The release workflow calls publish.yml; PyPI's OIDC token reflects the top-level workflow (release.yml), so the trusted publisher must match.
|
|
67
68
|
|
|
68
69
|
4. **Click "Add"**
|
|
69
70
|
|
|
@@ -86,9 +87,10 @@ If you want to reserve the package name before publishing:
|
|
|
86
87
|
```
|
|
87
88
|
Owner: syn54x
|
|
88
89
|
Repository: ferro-orm
|
|
89
|
-
Workflow:
|
|
90
|
+
Workflow: release.yml
|
|
90
91
|
Environment: pypi (optional)
|
|
91
92
|
```
|
|
93
|
+
Use `release.yml` (the workflow that triggers the run). Do not use `publish.yml` when it is invoked via workflow_call from release.yml, or uploads will fail with "Build Config URI does not match expected Trusted Publisher".
|
|
92
94
|
|
|
93
95
|
6. **Click "Add"**
|
|
94
96
|
|
|
@@ -103,7 +105,7 @@ After adding the trusted publisher, you should see:
|
|
|
103
105
|
|
|
104
106
|
Owner: syn54x
|
|
105
107
|
Repository: ferro-orm
|
|
106
|
-
Workflow:
|
|
108
|
+
Workflow: release.yml
|
|
107
109
|
Environment: pypi
|
|
108
110
|
```
|
|
109
111
|
|
|
@@ -175,7 +177,7 @@ Before doing a real release, test the workflow:
|
|
|
175
177
|
|
|
176
178
|
2. **Trigger the workflow manually:**
|
|
177
179
|
```bash
|
|
178
|
-
gh workflow run
|
|
180
|
+
gh workflow run release.yml
|
|
179
181
|
```
|
|
180
182
|
|
|
181
183
|
3. **Check the logs:**
|
|
@@ -208,6 +210,12 @@ Before doing a real release, test the workflow:
|
|
|
208
210
|
|
|
209
211
|
## Troubleshooting
|
|
210
212
|
|
|
213
|
+
### Error: "Certificate's Build Config URI ... does not match expected Trusted Publisher (publish.yml @ ...)"
|
|
214
|
+
|
|
215
|
+
**Cause:** PyPI Trusted Publishing uses the **top-level** workflow for OIDC. This repo runs `publish.yml` via `workflow_call` from `release.yml`, so the token identifies `release.yml`, not `publish.yml`. If PyPI is configured for `publish.yml`, uploads fail.
|
|
216
|
+
|
|
217
|
+
**Solution:** On PyPI, set the trusted publisher **Workflow** to `release.yml` (not `publish.yml`). Update or add the publisher: Owner `syn54x`, Repository `ferro-orm`, Workflow **release.yml**, Environment `pypi` (optional).
|
|
218
|
+
|
|
211
219
|
### Error: "Trusted publishing authentication failed"
|
|
212
220
|
|
|
213
221
|
**Cause:** OIDC token is rejected by PyPI
|
|
@@ -216,7 +224,7 @@ Before doing a real release, test the workflow:
|
|
|
216
224
|
1. Verify all fields match exactly on PyPI:
|
|
217
225
|
- Owner name (case-sensitive)
|
|
218
226
|
- Repository name (case-sensitive)
|
|
219
|
-
- Workflow filename (
|
|
227
|
+
- Workflow filename: use **release.yml** (the workflow that starts the run)
|
|
220
228
|
- Environment name (if specified)
|
|
221
229
|
|
|
222
230
|
2. Check GitHub environment exists:
|
|
@@ -241,10 +249,9 @@ Before doing a real release, test the workflow:
|
|
|
241
249
|
**Cause:** PyPI can't find the workflow file
|
|
242
250
|
|
|
243
251
|
**Solutions:**
|
|
244
|
-
1. Ensure `
|
|
245
|
-
2. Verify filename matches exactly (case-sensitive)
|
|
252
|
+
1. Ensure `release.yml` exists in `.github/workflows/` (this is the workflow PyPI should reference)
|
|
253
|
+
2. Verify the workflow filename on PyPI matches exactly (case-sensitive): `release.yml`
|
|
246
254
|
3. Check workflow is committed to `main` branch
|
|
247
|
-
4. Workflow must be in the repository (not a reusable workflow)
|
|
248
255
|
|
|
249
256
|
### Error: "Environment not found"
|
|
250
257
|
|
|
@@ -318,7 +325,7 @@ After completing setup, verify:
|
|
|
318
325
|
- [ ] PyPI trusted publisher configured
|
|
319
326
|
- [ ] GitHub environment `pypi` created (if using)
|
|
320
327
|
- [ ] Workflow permissions set to read/write
|
|
321
|
-
- [ ] Workflow file `
|
|
328
|
+
- [ ] Workflow file `release.yml` exists (trusted publisher must use this name)
|
|
322
329
|
- [ ] Workflow has `id-token: write` permission
|
|
323
330
|
- [ ] Test workflow runs successfully
|
|
324
331
|
- [ ] Can authenticate with PyPI (check logs)
|
|
@@ -342,7 +349,7 @@ After completing setup, verify:
|
|
|
342
349
|
Project: ferro-orm
|
|
343
350
|
Owner: syn54x
|
|
344
351
|
Repository: ferro-orm
|
|
345
|
-
Workflow:
|
|
352
|
+
Workflow: release.yml
|
|
346
353
|
Environment: pypi (optional)
|
|
347
354
|
```
|
|
348
355
|
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
## Description
|
|
2
|
+
|
|
3
|
+
<!-- What problem does this PR solve? Why is this change needed? -->
|
|
4
|
+
|
|
5
|
+
## Changes
|
|
6
|
+
|
|
7
|
+
-
|
|
8
|
+
-
|
|
9
|
+
-
|
|
10
|
+
|
|
11
|
+
## Bridge and Schema Impact
|
|
12
|
+
|
|
13
|
+
<!-- Complete if this PR touches model/schema/FFI behavior -->
|
|
14
|
+
|
|
15
|
+
- [ ] No Rust/Python bridge changes
|
|
16
|
+
- [ ] Python model/schema changed
|
|
17
|
+
- [ ] Rust core or SQL generation changed
|
|
18
|
+
- [ ] `src/ferro/_core.pyi` updated (if needed)
|
|
19
|
+
- [ ] Integration test added first for new behavior
|
|
20
|
+
|
|
21
|
+
## Migration / Breaking Changes
|
|
22
|
+
|
|
23
|
+
- [ ] No breaking changes
|
|
24
|
+
- [ ] Breaking changes included (details below)
|
|
25
|
+
|
|
26
|
+
<!-- If breaking, describe user impact and upgrade path -->
|
|
27
|
+
|
|
28
|
+
## Documentation and Changelog
|
|
29
|
+
|
|
30
|
+
- [ ] No docs update needed
|
|
31
|
+
- [ ] Docs updated (README/docs/inline docs)
|
|
32
|
+
- [ ] Changelog entry needed
|
|
33
|
+
|
|
34
|
+
## Related Issues
|
|
35
|
+
|
|
36
|
+
<!-- Example: Closes #123 -->
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
name: CI
|
|
2
2
|
|
|
3
3
|
on:
|
|
4
|
+
workflow_call:
|
|
4
5
|
pull_request:
|
|
5
6
|
branches: [main]
|
|
6
7
|
push:
|
|
@@ -53,11 +54,11 @@ jobs:
|
|
|
53
54
|
|
|
54
55
|
- name: Install dependencies
|
|
55
56
|
run: |
|
|
56
|
-
uv sync --group
|
|
57
|
+
uv sync --only-group ci-lint --no-install-project --python 3.13
|
|
57
58
|
|
|
58
59
|
- name: Run all pre-commit hooks
|
|
59
60
|
run: |
|
|
60
|
-
uv run prek run --all-files
|
|
61
|
+
uv run --no-sync --python 3.13 prek run --all-files
|
|
61
62
|
|
|
62
63
|
test-rust:
|
|
63
64
|
name: Rust tests
|
|
@@ -108,7 +109,7 @@ jobs:
|
|
|
108
109
|
|
|
109
110
|
- name: Install dependencies
|
|
110
111
|
run: |
|
|
111
|
-
uv sync --group
|
|
112
|
+
uv sync --only-group ci-test --no-install-project --python 3.13
|
|
112
113
|
|
|
113
114
|
- name: Build Rust extension
|
|
114
115
|
run: |
|
|
@@ -151,7 +152,7 @@ jobs:
|
|
|
151
152
|
|
|
152
153
|
- name: Install dependencies
|
|
153
154
|
run: |
|
|
154
|
-
uv sync --group
|
|
155
|
+
uv sync --only-group ci-test --no-install-project --python ${{ matrix.python-version }}
|
|
155
156
|
|
|
156
157
|
- name: Build Rust extension
|
|
157
158
|
run: |
|
|
@@ -170,55 +171,6 @@ jobs:
|
|
|
170
171
|
name: python-${{ matrix.python-version }}
|
|
171
172
|
continue-on-error: true
|
|
172
173
|
|
|
173
|
-
packaging-smoke:
|
|
174
|
-
name: Packaging smoke check (${{ matrix.platform.name }})
|
|
175
|
-
# Only run the cross-OS packaging check on main / manual.
|
|
176
|
-
if: github.event_name != 'pull_request'
|
|
177
|
-
runs-on: ${{ matrix.platform.runner }}
|
|
178
|
-
strategy:
|
|
179
|
-
fail-fast: false
|
|
180
|
-
matrix:
|
|
181
|
-
platform:
|
|
182
|
-
- name: linux
|
|
183
|
-
runner: ubuntu-latest
|
|
184
|
-
target: x86_64
|
|
185
|
-
manylinux: auto
|
|
186
|
-
- name: macos
|
|
187
|
-
runner: macos-latest
|
|
188
|
-
target: aarch64
|
|
189
|
-
manylinux: ''
|
|
190
|
-
- name: windows
|
|
191
|
-
runner: windows-latest
|
|
192
|
-
target: x64
|
|
193
|
-
manylinux: ''
|
|
194
|
-
steps:
|
|
195
|
-
- name: Checkout repository
|
|
196
|
-
uses: actions/checkout@v4
|
|
197
|
-
|
|
198
|
-
- name: Set up Python
|
|
199
|
-
uses: actions/setup-python@v5
|
|
200
|
-
with:
|
|
201
|
-
python-version: '3.13'
|
|
202
|
-
|
|
203
|
-
- name: Build wheel
|
|
204
|
-
uses: PyO3/maturin-action@v1.48.0
|
|
205
|
-
with:
|
|
206
|
-
target: ${{ matrix.platform.target }}
|
|
207
|
-
args: --release --out dist --find-interpreter
|
|
208
|
-
manylinux: ${{ matrix.platform.manylinux }}
|
|
209
|
-
sccache: 'true'
|
|
210
|
-
|
|
211
|
-
- name: Install wheel
|
|
212
|
-
shell: bash
|
|
213
|
-
run: |
|
|
214
|
-
python -m pip install --upgrade pip
|
|
215
|
-
python -m pip install --find-links dist ferro-orm
|
|
216
|
-
|
|
217
|
-
- name: Import check
|
|
218
|
-
shell: bash
|
|
219
|
-
run: |
|
|
220
|
-
python -c "import ferro; print('Ferro imported successfully')"
|
|
221
|
-
|
|
222
174
|
check-conventional-commits:
|
|
223
175
|
name: Check Conventional Commits
|
|
224
176
|
runs-on: ubuntu-latest
|
|
@@ -258,7 +210,7 @@ jobs:
|
|
|
258
210
|
fi
|
|
259
211
|
|
|
260
212
|
echo "Checking commit: $MESSAGE"
|
|
261
|
-
if ! uv run cz check --commit-msg-file <(git log -1 --pretty=format:"%s%n%n%b" $commit); then
|
|
213
|
+
if ! uv run --no-sync --python 3.13 cz check --commit-msg-file <(git log -1 --pretty=format:"%s%n%n%b" $commit); then
|
|
262
214
|
echo "❌ Commit message does not follow conventional format: $MESSAGE"
|
|
263
215
|
exit 1
|
|
264
216
|
fi
|
|
@@ -268,7 +220,7 @@ jobs:
|
|
|
268
220
|
|
|
269
221
|
all-checks:
|
|
270
222
|
name: All Checks Passed
|
|
271
|
-
needs: [lint-and-format, test-python-pr, test-python-main, test-rust
|
|
223
|
+
needs: [lint-and-format, test-python-pr, test-python-main, test-rust]
|
|
272
224
|
runs-on: ubuntu-latest
|
|
273
225
|
if: always()
|
|
274
226
|
steps:
|
|
@@ -281,6 +233,5 @@ jobs:
|
|
|
281
233
|
if ! ok "${{ needs.test-python-pr.result }}"; then exit 1; fi
|
|
282
234
|
if ! ok "${{ needs.test-python-main.result }}"; then exit 1; fi
|
|
283
235
|
if ! ok "${{ needs.test-rust.result }}"; then exit 1; fi
|
|
284
|
-
if ! ok "${{ needs.packaging-smoke.result }}"; then exit 1; fi
|
|
285
236
|
|
|
286
237
|
echo "All checks passed!"
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
name: Packaging Smoke
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_call:
|
|
5
|
+
push:
|
|
6
|
+
branches: [main]
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
|
|
9
|
+
concurrency:
|
|
10
|
+
group: packaging-${{ github.workflow }}-${{ github.ref }}
|
|
11
|
+
cancel-in-progress: true
|
|
12
|
+
|
|
13
|
+
permissions:
|
|
14
|
+
contents: read
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
packaging-smoke:
|
|
18
|
+
name: Packaging smoke check (${{ matrix.platform.name }})
|
|
19
|
+
runs-on: ${{ matrix.platform.runner }}
|
|
20
|
+
strategy:
|
|
21
|
+
fail-fast: false
|
|
22
|
+
matrix:
|
|
23
|
+
platform:
|
|
24
|
+
- name: linux
|
|
25
|
+
runner: ubuntu-latest
|
|
26
|
+
target: x86_64
|
|
27
|
+
manylinux: auto
|
|
28
|
+
- name: macos
|
|
29
|
+
runner: macos-latest
|
|
30
|
+
target: aarch64
|
|
31
|
+
manylinux: ''
|
|
32
|
+
- name: windows
|
|
33
|
+
runner: windows-latest
|
|
34
|
+
target: x64
|
|
35
|
+
manylinux: ''
|
|
36
|
+
steps:
|
|
37
|
+
- name: Checkout repository
|
|
38
|
+
uses: actions/checkout@v4
|
|
39
|
+
|
|
40
|
+
- name: Set up Python
|
|
41
|
+
uses: actions/setup-python@v5
|
|
42
|
+
with:
|
|
43
|
+
python-version: '3.13'
|
|
44
|
+
|
|
45
|
+
- name: Build wheel
|
|
46
|
+
uses: PyO3/maturin-action@v1.48.0
|
|
47
|
+
with:
|
|
48
|
+
target: ${{ matrix.platform.target }}
|
|
49
|
+
args: --release --out dist --find-interpreter
|
|
50
|
+
manylinux: ${{ matrix.platform.manylinux }}
|
|
51
|
+
sccache: 'true'
|
|
52
|
+
|
|
53
|
+
- name: Install wheel
|
|
54
|
+
shell: bash
|
|
55
|
+
run: |
|
|
56
|
+
python -m pip install --upgrade pip
|
|
57
|
+
python -m pip install --find-links dist ferro-orm
|
|
58
|
+
|
|
59
|
+
- name: Import check
|
|
60
|
+
shell: bash
|
|
61
|
+
run: |
|
|
62
|
+
python -c "import ferro; print('Ferro imported successfully')"
|
|
@@ -2,6 +2,12 @@ name: Publish Docs
|
|
|
2
2
|
|
|
3
3
|
on:
|
|
4
4
|
workflow_dispatch:
|
|
5
|
+
workflow_call:
|
|
6
|
+
inputs:
|
|
7
|
+
ref:
|
|
8
|
+
description: Git ref (branch, tag, or SHA) to build docs from
|
|
9
|
+
required: true
|
|
10
|
+
type: string
|
|
5
11
|
|
|
6
12
|
concurrency:
|
|
7
13
|
group: docs-${{ github.workflow }}-${{ github.ref }}
|
|
@@ -17,6 +23,8 @@ jobs:
|
|
|
17
23
|
steps:
|
|
18
24
|
- name: Checkout repository
|
|
19
25
|
uses: actions/checkout@v4
|
|
26
|
+
with:
|
|
27
|
+
ref: ${{ inputs.ref }}
|
|
20
28
|
|
|
21
29
|
- name: Set up Python
|
|
22
30
|
uses: actions/setup-python@v5
|
|
@@ -30,11 +38,11 @@ jobs:
|
|
|
30
38
|
|
|
31
39
|
- name: Install documentation dependencies
|
|
32
40
|
run: |
|
|
33
|
-
uv sync --group
|
|
41
|
+
uv sync --only-group docs --no-install-project --python 3.13
|
|
34
42
|
|
|
35
43
|
- name: Build MkDocs site
|
|
36
44
|
run: |
|
|
37
|
-
uv run mkdocs build
|
|
45
|
+
uv run --no-sync mkdocs build
|
|
38
46
|
|
|
39
47
|
- name: Upload Pages artifact
|
|
40
48
|
uses: actions/upload-pages-artifact@v3
|