Automate release pipeline with towncrier-fragments version scheme #47
Workflow file for this run
This file contains hidden or 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: test | |
| on: | |
| push: | |
| branches: | |
| - main | |
| - test-me-* | |
| pull_request: | |
| branches: | |
| - main | |
| # Set permissions at the job level. | |
| permissions: {} | |
| jobs: | |
| check-package: | |
| name: Build & inspect our package. | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| fetch-depth: 0 | |
| persist-credentials: false | |
| - name: Detect release branch version | |
| id: release | |
| if: startsWith(github.head_ref || '', 'release-') | |
| run: | | |
| VERSION="${GITHUB_HEAD_REF#release-}" | |
| if [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+ ]]; then | |
| echo "version=$VERSION" >> "$GITHUB_OUTPUT" | |
| echo "SETUPTOOLS_SCM_PRETEND_VERSION_FOR_PLUGGY=$VERSION" >> "$GITHUB_ENV" | |
| fi | |
| - uses: hynek/build-and-inspect-python-package@fe0a0fb1925ca263d076ca4f2c13e93a6e92a33e # v2.17.0 | |
| test: | |
| needs: [check-package] | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| name: [ | |
| "windows-py310", | |
| "windows-py314", | |
| "windows-pypy3", | |
| "ubuntu-py310-pytestmain", | |
| "ubuntu-py310", | |
| "ubuntu-py311", | |
| "ubuntu-py312", | |
| "ubuntu-py313", | |
| "ubuntu-py314", | |
| "ubuntu-pypy3", | |
| "ubuntu-benchmark", | |
| ] | |
| include: | |
| - name: "windows-py310" | |
| python: "3.10" | |
| os: windows-latest | |
| tox_env: "py310" | |
| - name: "windows-py313" | |
| python: "3.13" | |
| os: windows-latest | |
| tox_env: "py313" | |
| - name: "windows-py314" | |
| python: "3.14" | |
| os: windows-latest | |
| tox_env: "py314" | |
| - name: "windows-pypy3" | |
| python: "pypy3.10" | |
| os: windows-latest | |
| tox_env: "pypy3" | |
| - name: "ubuntu-py310-pytestmain" | |
| python: "3.10" | |
| os: ubuntu-latest | |
| tox_env: "py310-pytestmain" | |
| use_coverage: true | |
| - name: "ubuntu-py310" | |
| python: "3.10" | |
| os: ubuntu-latest | |
| tox_env: "py310" | |
| use_coverage: true | |
| - name: "ubuntu-py311" | |
| python: "3.11" | |
| os: ubuntu-latest | |
| tox_env: "py311" | |
| use_coverage: true | |
| - name: "ubuntu-py312" | |
| python: "3.12" | |
| os: ubuntu-latest | |
| tox_env: "py312" | |
| use_coverage: true | |
| - name: "ubuntu-py313" | |
| python: "3.13" | |
| os: ubuntu-latest | |
| tox_env: "py313" | |
| use_coverage: true | |
| - name: "ubuntu-py314" | |
| python: "3.14" | |
| os: ubuntu-latest | |
| tox_env: "py314" | |
| use_coverage: true | |
| - name: "ubuntu-pypy3" | |
| python: "pypy3.10" | |
| os: ubuntu-latest | |
| tox_env: "pypy3" | |
| use_coverage: true | |
| - name: "ubuntu-benchmark" | |
| python: "3.10" | |
| os: ubuntu-latest | |
| tox_env: "benchmark" | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| persist-credentials: false | |
| - name: Download built packages from the check-package job. | |
| uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 | |
| with: | |
| name: Packages | |
| path: dist | |
| - name: Set up Python ${{ matrix.python }} | |
| uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 | |
| with: | |
| python-version: ${{ matrix.python }} | |
| allow-prereleases: true | |
| - name: Install dependencies | |
| run: | | |
| python -m pip install --upgrade pip setuptools | |
| python -m pip install tox coverage | |
| - name: Test without coverage | |
| if: "! matrix.use_coverage" | |
| shell: bash | |
| run: "tox run --installpkg dist/*.whl" | |
| env: | |
| TOX_ENV: ${{ matrix.tox_env }} | |
| - name: Test with coverage | |
| if: "matrix.use_coverage" | |
| shell: bash | |
| run: "tox run --installpkg dist/*.whl" | |
| env: | |
| TOX_ENV: ${{ matrix.tox_env }}-coverage | |
| - name: Upload coverage | |
| if: matrix.use_coverage && github.repository == 'pytest-dev/pluggy' | |
| uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # v6.0.1 | |
| continue-on-error: true | |
| with: | |
| fail_ci_if_error: true | |
| files: ./coverage.xml | |
| verbose: true | |
| release-artifacts: | |
| name: Update draft GitHub release | |
| needs: [check-package, test] | |
| if: >- | |
| github.repository == 'pytest-dev/pluggy' | |
| && github.event_name == 'pull_request' | |
| && startsWith(github.head_ref, 'release-') | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| steps: | |
| - name: Determine version from branch | |
| id: version | |
| run: | | |
| VERSION="${GITHUB_HEAD_REF#release-}" | |
| if [[ ! "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+ ]]; then | |
| echo "::notice::Branch $GITHUB_HEAD_REF is not a release version branch — skipping." | |
| exit 0 | |
| fi | |
| echo "version=$VERSION" >> "$GITHUB_OUTPUT" | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| if: steps.version.outputs.version | |
| with: | |
| persist-credentials: false | |
| - name: Download built packages | |
| if: steps.version.outputs.version | |
| uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 | |
| with: | |
| name: Packages | |
| path: dist | |
| - name: Create or update draft release | |
| if: steps.version.outputs.version | |
| uses: actions/github-script@d746ffe35508b1917358783b479e04febd2b8f71 # v9.0.0 | |
| env: | |
| VERSION: ${{ steps.version.outputs.version }} | |
| HEAD_REF: ${{ github.head_ref }} | |
| HEAD_SHA: ${{ github.event.pull_request.head.sha }} | |
| with: | |
| script: | | |
| const fs = require('fs'); | |
| const path = require('path'); | |
| const { VERSION, HEAD_REF, HEAD_SHA } = process.env; | |
| const tag = VERSION; | |
| const title = `pluggy ${VERSION}`; | |
| const body = `Release ${VERSION} — built from \`${HEAD_REF}\` at ${HEAD_SHA}.`; | |
| let release; | |
| try { | |
| const { data } = await github.rest.repos.getReleaseByTag({ | |
| ...context.repo, | |
| tag, | |
| }); | |
| release = data; | |
| } catch (e) { | |
| if (e.status !== 404) throw e; | |
| } | |
| if (release && !release.draft) { | |
| core.notice(`Release ${VERSION} is already published — skipping.`); | |
| return; | |
| } | |
| if (release) { | |
| // Update existing draft: replace assets with freshly tested ones. | |
| await github.rest.repos.updateRelease({ | |
| ...context.repo, | |
| release_id: release.id, | |
| tag_name: tag, | |
| name: title, | |
| body, | |
| draft: true, | |
| target_commitish: HEAD_SHA, | |
| }); | |
| for (const asset of release.assets) { | |
| await github.rest.repos.deleteReleaseAsset({ | |
| ...context.repo, | |
| asset_id: asset.id, | |
| }); | |
| } | |
| } else { | |
| const { data } = await github.rest.repos.createRelease({ | |
| ...context.repo, | |
| tag_name: tag, | |
| name: title, | |
| body, | |
| draft: true, | |
| target_commitish: HEAD_SHA, | |
| }); | |
| release = data; | |
| } | |
| // Upload all assets from dist/. | |
| for (const file of fs.readdirSync('dist')) { | |
| const filePath = path.join('dist', file); | |
| await github.rest.repos.uploadReleaseAsset({ | |
| ...context.repo, | |
| release_id: release.id, | |
| name: file, | |
| data: fs.readFileSync(filePath), | |
| }); | |
| core.info(`Uploaded ${file}`); | |
| } |