Skip to content

Commit d15a2d5

Browse files
chore: python-client autorelease flow
1 parent 4bc3c7b commit d15a2d5

14 files changed

+1975
-377
lines changed

.github/workflows/README.md

Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
# GitHub Actions Workflows
2+
3+
This directory contains the CI/CD workflows for the Tidy3D Python client.
4+
5+
## Release Workflows
6+
7+
The release process is composed of modular, manually-triggered workflows:
8+
9+
### Main Release Workflow
10+
11+
**`tidy3d-python-client-release.yml`**
12+
13+
Orchestrates the complete release process through three stages:
14+
15+
1. **Tag Creation** - Calls `tidy3d-python-client-create-tag.yml`
16+
2. **Testing** - Validates code quality, runs test suites
17+
3. **Deployment** - Calls `tidy3d-python-client-deploy.yml` if tests pass
18+
19+
**Trigger**: Manual via GitHub Actions UI
20+
21+
**Key Parameters**:
22+
- `release_tag` (required): Version tag (e.g., `v2.10.0`, `v2.10.0rc1`)
23+
- `release_type`: `draft` (testing, no PyPI) or `final` (production, publishes to PyPI)
24+
- `workflow_control`: Stage control for resuming partial releases
25+
- `start-tag`: Full release from beginning (default)
26+
- `start-tests`: Resume from testing
27+
- `start-deploy`: Resume from deployment
28+
- `only-tag`, `only-tests`, `only-tag-tests`, `only-tag-deploy`: Run specific stages
29+
- `deploy_testpypi`, `deploy_pypi`: Control deployment targets
30+
- `client_tests`, `cli_tests`, `submodule_tests`: Enable/disable specific test suites
31+
32+
**Release Types**:
33+
- **Draft**: Creates GitHub draft release, no PyPI publish, for validation
34+
- **Final**: Publishes to PyPI, creates public release, syncs branches and documentation
35+
- **Non-RC Final** (e.g., `v2.10.0`): Automatically runs submodule tests, pushes to `latest` branch
36+
- **RC Release** (e.g., `v2.10.0rc1`): Pre-release candidate, no `latest` push
37+
38+
### Component Workflows
39+
40+
**`tidy3d-python-client-create-tag.yml`**
41+
42+
Creates and pushes git tags with validation:
43+
- For `release_type: final`, validates `pyproject.toml` version matches tag
44+
- Supports tag recreation (deletes existing if present)
45+
- Tag format: `v{major}.{minor}.{patch}[rc{num}]`
46+
- Can be called independently or as part of release workflow
47+
48+
**`tidy3d-python-client-deploy.yml`**
49+
50+
Handles package deployment:
51+
- **TestPyPI**: Validation before production (`deploy_testpypi: true`)
52+
- **PyPI**: Production package distribution (`deploy_pypi: true`)
53+
- Creates GitHub releases (draft or final)
54+
- Syncs documentation to ReadTheDocs mirror
55+
- Syncs branches for final releases (maintains `latest`, `develop` consistency)
56+
- Can be called independently or as part of release workflow
57+
58+
**`tidy3d-python-client-release-tests.yml`**
59+
60+
Specialized release validation tests:
61+
- **Submodule tests**: Integration tests with dependent packages
62+
- **Version match tests**: Validates version consistency
63+
- Auto-enabled for non-RC final releases
64+
- Can be toggled via workflow parameters
65+
66+
## Test Workflows
67+
68+
**`tidy3d-python-client-tests.yml`**
69+
70+
Main CI test workflow that runs on PRs, manual triggers, and workflow calls:
71+
72+
- **Code quality**: Linting (ruff), type checking (mypy), schema validation, security (zizmor)
73+
- **Local tests**: Fast tests on self-hosted runners (Python 3.10, 3.13)
74+
- **Remote tests**: Full matrix on GitHub runners (Python 3.10-3.13, Windows/Linux/macOS)
75+
- **PR review tests**: Branch naming, commit message validation
76+
- **Workflow validation**: Centralized job that validates all test results
77+
78+
Test scope determined dynamically based on:
79+
- PR approval state
80+
- Code changes (files modified)
81+
- Manual workflow inputs
82+
- Workflow call parameters
83+
84+
**`tidy3d-python-client-develop-cli.yml`**
85+
86+
Tests for the Tidy3D develop CLI functionality:
87+
- Can be called as part of main test workflow
88+
- Validates CLI commands and functionality
89+
90+
## Maintenance Workflows
91+
92+
**`tidy3d-python-client-daily.yml`**
93+
94+
Scheduled daily workflow for ongoing validation.
95+
96+
**`tidy3d-python-client-update-lockfile.yml`**
97+
98+
Updates Poetry lockfile with latest dependencies:
99+
- Configured with AWS CodeArtifact authentication for private dependencies
100+
- Uses secrets: `AWS_CODEARTIFACT_ACCESS_KEY`, `AWS_CODEARTIFACT_ACCESS_SECRET`
101+
- Creates PR with updated lockfile
102+
103+
## Documentation Workflows
104+
105+
**`tidy3d-docs-sync-readthedocs-repo.yml`**
106+
107+
Syncs documentation to ReadTheDocs mirror repository:
108+
109+
- **Manual trigger**: Specify `source_ref` and optional `target_ref`
110+
- **Workflow call**: Invoked by release workflow for automated sync
111+
- **Outputs**: `workflow_success` and `synced_ref` for validation
112+
- Supports custom source/target ref mapping
113+
114+
## Best Practices
115+
116+
### For Releases
117+
118+
1. **Always test first**: Run `draft` release before `final`
119+
2. **Use TestPyPI**: Enable `deploy_testpypi` to validate package before PyPI
120+
3. **Version matching**: Update `pyproject.toml` version before final releases
121+
4. **RC versioning**: Use RC versions (`v2.10.0rc1`) for pre-release testing
122+
5. **Resume capability**: Use `workflow_control` stages to resume failed releases
123+
6. **Monitor validation**: Check `workflow-validation` job for centralized test status
124+
125+
### Version Validation
126+
127+
For `release_type: final`, the tag creation validates:
128+
129+
```bash
130+
# pyproject.toml must contain:
131+
version = "2.10.0"
132+
133+
# To match release tag (minus 'v' prefix):
134+
release_tag: v2.10.0
135+
```
136+
137+
Mismatches will fail with descriptive error.
138+
139+
### Recommended Release Flow
140+
141+
1. **Draft + TestPyPI** - Initial validation
142+
```yaml
143+
release_tag: v2.10.0rc1
144+
release_type: draft
145+
deploy_testpypi: true
146+
```
147+
148+
2. **Final RC** - Release candidate
149+
```yaml
150+
release_tag: v2.10.0rc1
151+
release_type: final
152+
deploy_pypi: true
153+
```
154+
155+
3. **Final Stable** - Production release
156+
```yaml
157+
release_tag: v2.10.0
158+
release_type: final
159+
deploy_pypi: true
160+
# Submodule tests auto-enabled (non-RC)
161+
```
162+
163+
### Troubleshooting
164+
165+
**Version Mismatch**
166+
```
167+
Version mismatch!
168+
pyproject.toml: 2.9.0
169+
Release tag: 2.10.0
170+
```
171+
Solution: Update `pyproject.toml` version to match release tag.
172+
173+
**Tag Already Exists**
174+
175+
The workflow automatically handles by deleting and recreating.
176+
177+
**Test Failures Block Deployment**
178+
179+
Check `workflow-validation` job status. Use `workflow_control: start-deploy` to bypass after fixing externally.
180+
181+
**Resume from Failure**
182+
183+
If deployment fails:
184+
```yaml
185+
release_tag: v2.10.0
186+
release_type: final
187+
workflow_control: start-deploy
188+
```
189+
190+
## Workflow Outputs
191+
192+
### Release Workflow
193+
- `tag_created`: Whether tag was successfully created
194+
- `workflow_success`: Overall workflow success status
195+
- `synced_ref`: Documentation ref that was synced
196+
197+
### Docs Sync Workflow
198+
- `workflow_success`: Sync success status
199+
- `synced_ref`: The ref synced to the mirror
200+
201+
## AWS CodeArtifact Integration
202+
203+
Private dependencies are accessed via AWS CodeArtifact:
204+
- Authentication in `tidy3d-python-client-update-lockfile.yml`
205+
- Credentials injected via GitHub secrets
206+
- Automatically configured for Poetry operations
207+
208+
## Related Documentation
209+
210+
- Release workflow details: `docs/development/release/version.rst`
211+
- Development guidelines: `AGENTS.md`
212+
- General repository info: `README.md`

.github/workflows/tidy3d-docs-sync-readthedocs-repo.yml

Lines changed: 50 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,35 @@ name: "docs/tidy3d/sync-to-readthedocs-repo"
33
on:
44
workflow_dispatch:
55
inputs:
6-
target_branch:
7-
description: 'Target mirror repo branch. Defaults to source branch/tag.'
6+
source_ref:
7+
description: 'Source ref (branch/tag) to sync. Defaults to current ref.'
88
required: false
99
type: string
10-
push:
11-
branches:
12-
- main
13-
- latest
14-
- develop
15-
- 'pre/*'
16-
- 'demo/*'
17-
tags:
18-
- 'v*'
19-
- 'demo/*'
10+
default: ''
11+
target_ref:
12+
description: 'Target mirror repo ref. Defaults to source ref.'
13+
required: false
14+
type: string
15+
default: ''
16+
17+
workflow_call:
18+
inputs:
19+
source_ref:
20+
description: 'Source ref (branch/tag) to sync. Required for workflow_call.'
21+
required: true
22+
type: string
23+
target_ref:
24+
description: 'Target mirror repo ref. Defaults to source ref.'
25+
required: false
26+
type: string
27+
default: ''
28+
outputs:
29+
workflow_success:
30+
description: 'Sync workflow success status'
31+
value: ${{ jobs.build-and-deploy.result == 'success' }}
32+
synced_ref:
33+
description: 'The ref that was synced to the mirror'
34+
value: ${{ jobs.build-and-deploy.outputs.synced_ref }}
2035

2136
permissions:
2237
contents: read
@@ -30,16 +45,26 @@ jobs:
3045
- id: extract
3146
name: Extract branch or tag name
3247
shell: bash
48+
env:
49+
INPUT_SOURCE_REF: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.source_ref || inputs.source_ref }}
3350
run: |
34-
REF_NAME="${GITHUB_REF#refs/*/}"
51+
if [[ -n "$INPUT_SOURCE_REF" ]]; then
52+
REF_NAME="$INPUT_SOURCE_REF"
53+
echo "Using provided source_ref: $REF_NAME"
54+
else
55+
REF_NAME="${GITHUB_REF#refs/*/}"
56+
echo "Extracted ref from GITHUB_REF: $REF_NAME"
57+
fi
3558
echo "ref_name=$REF_NAME" >> $GITHUB_OUTPUT
36-
echo "Extracted ref: $REF_NAME"
59+
echo "Final ref: $REF_NAME"
3760
3861
build-and-deploy:
3962
permissions:
4063
contents: write
4164
needs: extract_branch_or_tag
4265
runs-on: ubuntu-latest
66+
outputs:
67+
synced_ref: ${{ steps.sync-result.outputs.synced_ref }}
4368
steps:
4469
- name: full-checkout
4570
uses: actions/checkout@v4
@@ -52,20 +77,25 @@ jobs:
5277
persist-credentials: true
5378

5479
- name: push-mirror-repo
80+
id: sync-result
5581
env:
5682
GITHUB_TOKEN: ${{ secrets.GH_PAT }}
5783
SOURCE_REF: ${{ needs.extract_branch_or_tag.outputs.ref_name }}
58-
TARGET_BRANCH_INPUT: ${{ github.event.inputs.target_branch }}
84+
TARGET_REF: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.target_ref || inputs.target_ref }}
5985
run: |
6086
echo "Source reference: $SOURCE_REF"
6187
git pull origin "$SOURCE_REF"
6288
git remote add mirror https://github.com/flexcompute-readthedocs/tidy3d-docs.git
6389
64-
if [[ -n "$TARGET_BRANCH_INPUT" && "${{ github.event_name }}" == "workflow_dispatch" ]]; then
65-
echo "Manual trigger detected. Pushing contents of '$SOURCE_REF' to remote branch '$TARGET_BRANCH_INPUT'."
66-
git push mirror "$SOURCE_REF:refs/heads/$TARGET_BRANCH_INPUT" --force
90+
if [[ -n "$TARGET_REF" ]]; then
91+
echo "Pushing contents of '$SOURCE_REF' to remote ref '$TARGET_REF'."
92+
git push mirror "$SOURCE_REF:refs/heads/$TARGET_REF" --force
93+
SYNCED_REF="$TARGET_REF"
6794
else
68-
echo "Automatic trigger or manual run without target. Pushing '$SOURCE_REF' to the same ref on the mirror."
69-
# This preserves the original behavior: pushes a branch to a branch, or a tag to a tag.
95+
echo "Pushing '$SOURCE_REF' to the same ref on the mirror."
7096
git push mirror "$SOURCE_REF" --force
97+
SYNCED_REF="$SOURCE_REF"
7198
fi
99+
100+
echo "synced_ref=$SYNCED_REF" >> $GITHUB_OUTPUT
101+
echo "? Successfully synced to: $SYNCED_REF"

0 commit comments

Comments
 (0)