1+ name : Release
2+
3+ on :
4+ push :
5+ tags :
6+ - ' v*-rc*' # RC versions (e.g., v0.3.1-rc1) → Production PyPI
7+ - ' v*' # Final versions (e.g., v0.3.1) → Test PyPI first, then manual production
8+ workflow_dispatch :
9+ inputs :
10+ environment :
11+ description : ' Deploy to environment'
12+ required : true
13+ default : ' test'
14+ type : choice
15+ options :
16+ - test
17+ - production
18+
19+ jobs :
20+ build :
21+ runs-on : ubuntu-latest
22+ outputs :
23+ version : ${{ steps.version.outputs.version }}
24+ steps :
25+ - uses : actions/checkout@v4
26+ with :
27+ fetch-depth : 0
28+
29+ - name : Set up Python
30+ uses : actions/setup-python@v4
31+ with :
32+ python-version : ' 3.11'
33+
34+ - name : Install Poetry
35+ uses : snok/install-poetry@v1
36+ with :
37+ version : latest
38+ virtualenvs-create : true
39+ virtualenvs-in-project : true
40+
41+ - name : Install dependencies
42+ run : poetry install --with dev
43+
44+ - name : Get version
45+ id : version
46+ run : |
47+ # Build first to trigger dynamic versioning
48+ poetry build
49+ # Extract version from built wheel filename
50+ VERSION=$(ls dist/*.whl | head -1 | sed 's/.*-\([0-9][^-]*\)-.*/\1/')
51+ echo "version=$VERSION" >> $GITHUB_OUTPUT
52+ echo "Version: $VERSION"
53+
54+ - name : Run tests
55+ run : poetry run python scripts/run_tests.py --layer smoke --layer unit
56+
57+ - name : Upload build artifacts
58+ uses : actions/upload-artifact@v4
59+ with :
60+ name : dist-${{ steps.version.outputs.version }}
61+ path : dist/
62+
63+ deploy-test :
64+ needs : build
65+ runs-on : ubuntu-latest
66+ if : (github.event_name == 'workflow_dispatch' && github.event.inputs.environment == 'test') || (github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') && !contains(github.ref, '-rc'))
67+ environment : test-pypi
68+ permissions :
69+ id-token : write
70+ contents : read
71+ steps :
72+ - name : Download build artifacts
73+ uses : actions/download-artifact@v4
74+ with :
75+ name : dist-${{ needs.build.outputs.version }}
76+ path : dist/
77+
78+ - name : Publish to Test PyPI
79+ uses : pypa/gh-action-pypi-publish@release/v1
80+ with :
81+ repository-url : https://test.pypi.org/legacy/
82+
83+ - name : Test installation from Test PyPI
84+ run : |
85+ sleep 60 # Wait for package to be available
86+ pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ memfuse==${{ needs.build.outputs.version }}
87+ python -c "import memfuse; print(f'Installed version: {memfuse.__version__}')"
88+
89+ deploy-production :
90+ needs : [build]
91+ runs-on : ubuntu-latest
92+ if : (github.event_name == 'workflow_dispatch' && github.event.inputs.environment == 'production') || (github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') && contains(github.ref, '-rc'))
93+ environment : production-pypi
94+ permissions :
95+ id-token : write
96+ contents : read
97+ steps :
98+ - name : Download build artifacts
99+ uses : actions/download-artifact@v4
100+ with :
101+ name : dist-${{ needs.build.outputs.version }}
102+ path : dist/
103+
104+ - name : Publish to PyPI
105+ uses : pypa/gh-action-pypi-publish@release/v1
106+
107+ create-release :
108+ needs : [build, deploy-production]
109+ runs-on : ubuntu-latest
110+ if : github.event_name == 'workflow_dispatch' && github.event.inputs.environment == 'production'
111+ permissions :
112+ contents : write
113+ steps :
114+ - uses : actions/checkout@v4
115+
116+ - name : Generate changelog
117+ id : changelog
118+ run : |
119+ # Get the previous tag
120+ PREV_TAG=$(git describe --tags --abbrev=0 HEAD~1 2>/dev/null || echo "")
121+ if [ -n "$PREV_TAG" ]; then
122+ echo "## Changes since $PREV_TAG" > changelog.md
123+ git log --pretty=format:"- %s (%h)" $PREV_TAG..HEAD >> changelog.md
124+ else
125+ echo "## Initial Release" > changelog.md
126+ fi
127+ cat changelog.md
128+
129+ - name : Create GitHub Release
130+ uses : softprops/action-gh-release@v1
131+ with :
132+ tag_name : ${{ github.ref_name }}
133+ name : Release ${{ github.ref_name }}
134+ body_path : changelog.md
135+ draft : false
136+ prerelease : false
0 commit comments