1+ name : Build and Publish to PyPI
2+
3+ on :
4+ push :
5+ tags :
6+ - ' v*'
7+
8+ permissions :
9+ contents : read
10+ id-token : write # Required for trusted publishing to PyPI
11+
12+ env :
13+ PYTHON_VERSION : " 3.11"
14+
15+ jobs :
16+ validate-version :
17+ name : Validate Version Match
18+ runs-on : ubuntu-latest
19+ outputs :
20+ version : ${{ steps.get-version.outputs.version }}
21+ tag-version : ${{ steps.get-tag.outputs.tag-version }}
22+
23+ steps :
24+ - uses : actions/checkout@v4
25+
26+ - name : Get tag version
27+ id : get-tag
28+ run : |
29+ TAG_VERSION=${GITHUB_REF#refs/tags/v}
30+ echo "tag-version=$TAG_VERSION" >> $GITHUB_OUTPUT
31+ echo "Tag version: $TAG_VERSION"
32+
33+ - name : Get pyproject.toml version
34+ id : get-version
35+ run : |
36+ VERSION=$(grep '^version = ' pyproject.toml | sed 's/version = "\(.*\)"/\1/')
37+ echo "version=$VERSION" >> $GITHUB_OUTPUT
38+ echo "pyproject.toml version: $VERSION"
39+
40+ - name : Validate version match
41+ run : |
42+ TAG_VERSION="${{ steps.get-tag.outputs.tag-version }}"
43+ PYPROJECT_VERSION="${{ steps.get-version.outputs.version }}"
44+
45+ echo "Comparing versions:"
46+ echo " Git tag: v$TAG_VERSION"
47+ echo " pyproject.toml: $PYPROJECT_VERSION"
48+
49+ if [ "$TAG_VERSION" != "$PYPROJECT_VERSION" ]; then
50+ echo "❌ ERROR: Version mismatch!"
51+ echo " Git tag version: $TAG_VERSION"
52+ echo " pyproject.toml version: $PYPROJECT_VERSION"
53+ echo ""
54+ echo "To fix this:"
55+ echo "1. Update version in pyproject.toml to match tag, or"
56+ echo "2. Create a new tag that matches pyproject.toml version"
57+ exit 1
58+ fi
59+
60+ echo "✅ Versions match! Proceeding with release of version $PYPROJECT_VERSION"
61+
62+ build :
63+ name : Build Distribution
64+ runs-on : ubuntu-latest
65+ needs : validate-version
66+
67+ steps :
68+ - uses : actions/checkout@v4
69+
70+ - name : Set up Python ${{ env.PYTHON_VERSION }}
71+ uses : actions/setup-python@v4
72+ with :
73+ python-version : ${{ env.PYTHON_VERSION }}
74+
75+ - name : Install uv
76+ uses : astral-sh/setup-uv@v3
77+ with :
78+ enable-cache : true
79+
80+ - name : Install build dependencies
81+ run : |
82+ python -m pip install --upgrade pip
83+ python -m pip install build twine check-manifest
84+
85+ - name : Validate MANIFEST.in
86+ run : |
87+ check-manifest --verbose
88+
89+ - name : Build sdist and wheel
90+ run : |
91+ echo "Building distributions for asyncmiele v${{ needs.validate-version.outputs.version }}"
92+ python -m build --sdist --wheel --outdir dist/
93+
94+ - name : Verify distributions
95+ run : |
96+ echo "Built distributions:"
97+ ls -la dist/
98+ echo "Checking distributions:"
99+ python -m twine check dist/*
100+
101+ - name : Upload build artifacts
102+ uses : actions/upload-artifact@v4
103+ with :
104+ name : python-distributions
105+ path : dist/
106+ retention-days : 7
107+
108+ test-install :
109+ name : Test Installation
110+ runs-on : ubuntu-latest
111+ needs : build
112+ strategy :
113+ matrix :
114+ python-version : ["3.11", "3.12"]
115+
116+ steps :
117+ - name : Set up Python ${{ matrix.python-version }}
118+ uses : actions/setup-python@v4
119+ with :
120+ python-version : ${{ matrix.python-version }}
121+
122+ - name : Download build artifacts
123+ uses : actions/download-artifact@v4
124+ with :
125+ name : python-distributions
126+ path : dist/
127+
128+ - name : Test wheel installation
129+ run : |
130+ echo "Testing wheel installation on Python ${{ matrix.python-version }}"
131+ pip install dist/*.whl
132+ python -c "import asyncmiele; print('✅ Import successful')"
133+
134+ publish-pypi :
135+ name : Publish to PyPI
136+ runs-on : ubuntu-latest
137+ needs : [validate-version, build, test-install]
138+
139+ steps :
140+ - name : Download build artifacts
141+ uses : actions/download-artifact@v4
142+ with :
143+ name : python-distributions
144+ path : dist/
145+
146+ - name : Publish to PyPI
147+ uses : pypa/gh-action-pypi-publish@release/v1
148+ with :
149+ print-hash : true
150+ verbose : true
151+
152+ github-release :
153+ name : Create GitHub Release
154+ runs-on : ubuntu-latest
155+ needs : [validate-version, publish-pypi]
156+ permissions :
157+ contents : write
158+
159+ steps :
160+ - uses : actions/checkout@v4
161+ with :
162+ fetch-depth : 0
163+
164+ - name : Download build artifacts
165+ uses : actions/download-artifact@v4
166+ with :
167+ name : python-distributions
168+ path : dist/
169+
170+ - name : Generate changelog
171+ id : changelog
172+ run : |
173+ echo "Generating changelog since last release..."
174+ PREVIOUS_TAG=$(git tag --sort=-version:refname | grep -v "^${{ github.ref_name }}$" | head -1)
175+
176+ if [ -z "$PREVIOUS_TAG" ]; then
177+ CHANGELOG=$(git log --pretty=format:"- %s (%h)" --no-merges)
178+ else
179+ CHANGELOG=$(git log $PREVIOUS_TAG..${{ github.ref_name }} --pretty=format:"- %s (%h)" --no-merges)
180+ fi
181+
182+ if [ -z "$CHANGELOG" ]; then
183+ CHANGELOG="- No notable changes in this release"
184+ fi
185+
186+ echo "changelog<<EOF" >> $GITHUB_OUTPUT
187+ echo "$CHANGELOG" >> $GITHUB_OUTPUT
188+ echo "EOF" >> $GITHUB_OUTPUT
189+
190+ - name : Create GitHub Release
191+ uses : softprops/action-gh-release@v2
192+ with :
193+ tag_name : ${{ github.ref_name }}
194+ name : Release ${{ github.ref_name }}
195+ body : |
196+ # AsyncMiele ${{ needs.validate-version.outputs.version }}
197+
198+ ## What's Changed
199+ ${{ steps.changelog.outputs.changelog }}
200+
201+ ## Installation
202+ ```bash
203+ pip install asyncmiele==${{ needs.validate-version.outputs.version }}
204+ ```
205+
206+ ## Requirements
207+ - Python 3.11+
208+ draft : false
209+ prerelease : ${{ contains(needs.validate-version.outputs.version, 'rc') || contains(needs.validate-version.outputs.version, 'beta') || contains(needs.validate-version.outputs.version, 'alpha') }}
210+ files : |
211+ dist/asyncmiele-${{ needs.validate-version.outputs.version }}-py3-none-any.whl
212+ dist/asyncmiele-${{ needs.validate-version.outputs.version }}.tar.gz
213+
214+
0 commit comments