From eadfdaa413d98e5a61f499ed937dbaa1b7bf88d3 Mon Sep 17 00:00:00 2001 From: evgeny Date: Thu, 18 Sep 2025 18:02:49 +0100 Subject: [PATCH] chore: add GitHub Actions workflow for publishing to PyPI and TestPyPI - Introduced a release workflow triggered on tag pushes matching semantic versioning. - Includes steps for building distributions, caching, publishing to PyPI and TestPyPI. - Utilizes poetry for dependency management and distribution building. --- .github/workflows/release.yml | 124 ++++++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..3eda7ae2 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,124 @@ +name: Publish Python distribution to PyPI + +on: + workflow_dispatch: + push: + tags: + - 'v[0-9]+.[0-9]+.[0-9]+*' + +jobs: + build: + name: Build distribution 📦 + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + with: + submodules: 'recursive' + - name: Set up Python 3.12 + uses: actions/setup-python@v5 + id: setup-python + with: + python-version: 3.12 + + - name: Setup poetry + uses: abatilo/actions-poetry@v4 + with: + poetry-version: '2.1.4' + + - name: Setup a local virtual environment + run: | + poetry env use ${{ steps.setup-python.outputs.python-path }} + poetry run python --version + poetry config virtualenvs.create true --local + poetry config virtualenvs.in-project true --local + + - uses: actions/cache@v4 + name: Define a cache for the virtual environment based on the dependencies lock file + id: cache + with: + path: ./.venv + key: venv-${{ runner.os }}-${{ matrix.python-version }}-${{ hashFiles('poetry.lock') }} + + - name: Ensure cache is healthy + if: steps.cache.outputs.cache-hit == 'true' + shell: bash + run: poetry run pip --version >/dev/null 2>&1 || (echo "Cache is broken, skip it" && rm -rf .venv) + + - name: Install dependencies + run: poetry install -E crypto + - name: Generate rest sync code and tests + run: poetry run unasync + - name: Build a binary wheel and a source tarball + run: poetry build + - name: Store the distribution packages + uses: actions/upload-artifact@v4 + with: + name: python-package-distributions + path: dist/ + + publish-to-pypi: + name: Publish Python distribution to PyPI + if: startsWith(github.ref, 'refs/tags/v') # only publish to PyPI on tag pushes + needs: + - build + runs-on: ubuntu-latest + environment: + name: pypi + url: https://pypi.org/p/ably + permissions: + id-token: write # IMPORTANT: mandatory for trusted publishing + + steps: + - name: Extract tag + id: tag + run: | + TAG=${GITHUB_REF#refs/tags/v} + echo "tag=$TAG" >> $GITHUB_OUTPUT + + - name: Read VERSION_NAME from pyproject.toml + id: version + run: | + VERSION_NAME=$(grep '^version' pyproject.toml | cut -d'=' -f2 | tr -d '[:space:]') + echo "version=$VERSION_NAME" >> $GITHUB_OUTPUT + + - name: Compare version with tag + run: | + if [ "$VERSION" != "$TAG" ]; then + echo "VERSION ($VERSION) does not match tag ($TAG)." + exit 1 + fi + env: + VERSION: ${{ steps.version.outputs.version }} + TAG: ${{ steps.tag.outputs.tag }} + - name: Download all the dists + uses: actions/download-artifact@v4 + with: + name: python-package-distributions + path: dist/ + - name: Publish distribution 📦 to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + + publish-to-testpypi: + name: Publish Python distribution to TestPyPI + needs: + - build + runs-on: ubuntu-latest + + environment: + name: testpypi + url: https://test.pypi.org/p/ably + + permissions: + id-token: write # IMPORTANT: mandatory for trusted publishing + + steps: + - name: Download all the dists + uses: actions/download-artifact@v4 + with: + name: python-package-distributions + path: dist/ + - name: Publish distribution 📦 to TestPyPI + uses: pypa/gh-action-pypi-publish@release/v1 + with: + repository-url: https://test.pypi.org/legacy/ \ No newline at end of file