CI/CD Pipeline #30
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: CI/CD Pipeline | |
on: | |
push: | |
branches: [main] | |
pull_request: | |
branches: [main] | |
workflow_dispatch: | |
inputs: | |
version: | |
description: 'Version to release (leave empty to use version from _version.py)' | |
required: false | |
type: string | |
jobs: | |
build: | |
runs-on: ubuntu-latest | |
strategy: | |
matrix: | |
python-version: ["3.10", "3.11", "3.12"] | |
steps: | |
- uses: actions/checkout@v4 | |
- name: Set up Python ${{ matrix.python-version }} | |
uses: actions/setup-python@v5 | |
with: | |
python-version: ${{ matrix.python-version }} | |
- name: Install dependencies | |
run: | | |
python -m pip install --upgrade pip | |
pip install hatch flake8 pytest pytest-asyncio | |
pip install . | |
- name: Lint with flake8 | |
run: | | |
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics | |
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics | |
- name: Run tests | |
run: pytest | |
publish: | |
needs: [build] | |
runs-on: ubuntu-latest | |
if: github.event_name == 'workflow_dispatch' | |
permissions: | |
id-token: write | |
contents: write | |
steps: | |
- uses: actions/checkout@v4 | |
- name: Set up Python | |
uses: actions/setup-python@v5 | |
with: | |
python-version: '3.12' | |
- name: Clean up dist folder | |
run: rm -rf dist/ | |
- name: Install package and dependencies | |
run: | | |
python -m pip install --upgrade pip | |
pip install . | |
pip install build twine | |
- name: Extract version and update if necessary | |
id: extract_version | |
run: | | |
if [ -n "${{ github.event.inputs.version }}" ]; then | |
echo "VERSION=${{ github.event.inputs.version }}" >> $GITHUB_ENV | |
sed -i "s/__version__ = .*/__version__ = \"${{ github.event.inputs.version }}\"/" src/etekcity_esf551_ble/_version.py | |
git config --local user.email "action@github.com" | |
git config --local user.name "GitHub Action" | |
git add src/etekcity_esf551_ble/_version.py | |
git commit -m "Bump version to ${{ github.event.inputs.version }}" | |
git push | |
else | |
VERSION=$(python -c "from etekcity_esf551_ble._version import __version__; print(__version__)") | |
echo "VERSION=$VERSION" >> $GITHUB_ENV | |
fi | |
- name: Build package | |
run: python -m build | |
- name: Create GitHub Release | |
id: create_release | |
uses: actions/github-script@v6 | |
with: | |
github-token: ${{secrets.GITHUB_TOKEN}} | |
script: | | |
const { data: release } = await github.rest.repos.createRelease({ | |
owner: context.repo.owner, | |
repo: context.repo.repo, | |
tag_name: `v${process.env.VERSION}`, | |
name: `Release v${process.env.VERSION}`, | |
draft: false, | |
prerelease: false | |
}); | |
core.setOutput('release_id', release.id); | |
- name: Upload to PyPI | |
env: | |
TWINE_USERNAME: __token__ | |
TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }} | |
run: | | |
twine upload dist/* | |
- name: Wait for PyPI | |
run: | | |
echo "Waiting for package to be available on PyPI..." | |
sleep 60 | |
- name: Verify installation from PyPI | |
run: | | |
python -m venv test-env | |
. test-env/bin/activate | |
pip install etekcity_esf551_ble==$VERSION | |
python -c "from etekcity_esf551_ble import EtekcitySmartFitnessScale, WeightUnit; print(EtekcitySmartFitnessScale, WeightUnit)" | |
- name: Upload Release Assets | |
uses: actions/github-script@v6 | |
with: | |
github-token: ${{secrets.GITHUB_TOKEN}} | |
script: | | |
const fs = require('fs').promises; | |
const path = require('path'); | |
const files = await fs.readdir('dist'); | |
for (const file of files) { | |
const filePath = path.join('dist', file); | |
const stats = await fs.stat(filePath); | |
if (stats.isFile()) { | |
console.log(`Uploading ${file}...`); | |
await github.rest.repos.uploadReleaseAsset({ | |
owner: context.repo.owner, | |
repo: context.repo.repo, | |
release_id: ${{ steps.create_release.outputs.release_id }}, | |
name: file, | |
data: await fs.readFile(filePath) | |
}); | |
} | |
} |