Skip to content

Commit

Permalink
add release scripts, actions and documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
getzze committed Nov 5, 2024
1 parent 3e1dc07 commit 2cbb8aa
Show file tree
Hide file tree
Showing 7 changed files with 573 additions and 57 deletions.
49 changes: 49 additions & 0 deletions .github/workflows/prepare-release-pr.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
name: prepare release pr

on:
workflow_dispatch:
inputs:
branch:
description: 'Branch to base the release from'
required: false
default: 'main'
bump:
description: |
'Release type: major, minor or patch. '
'Leave empty for autommatic detection based on changelog segments.'
required: false
default: ''
prerelease:
description: 'Prerelease (ex: rc1). Leave empty if not a pre-release.'
required: false
default: ''

# Set permissions at the job level.
permissions: {}

jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write

steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version-file: .python-version-default
cache: pip

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install --upgrade setuptools tox
- name: Prepare release PR
run: |
tox -e prepare-release-pr -- ${{ github.event.inputs.branch }} ${{ github.token }} --bump='${{ github.event.inputs.bump }}' --prerelease='${{ github.event.inputs.prerelease }}'
133 changes: 76 additions & 57 deletions .github/workflows/publish.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,46 +2,108 @@ name: Publish

on:
push:
branches:
- main
tags:
- '*'
pull_request:
types:
- closed
release:
types:
- published
workflow_dispatch:

permissions:
contents: read
id-token: write

# https://packaging.python.org/en/latest/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows/
jobs:
deploy:
# Always build & lint package.
build-package:
name: Build & verify package
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.x"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install build
- name: Build package
run: python -m build
- uses: actions/upload-artifact@v4
fetch-depth: 0

- uses: hynek/build-and-inspect-python-package@v2

tag:
if: |
github.repository == 'Diaoul/subliminal'
&& github.event_name == 'pull_request'
&& github.event.action == 'closed'
&& github.event.pull_request.merged == true
&& startsWith(github.head_ref, 'release-')
needs: [build-package]
env:
GITHUB_HEAD_REF: ${{ github.head_ref }}
runs-on: ubuntu-latest
permissions:
id-token: write
contents: write
steps:
- name: Fetch version
id: version
run: |
VERSION=${GITHUB_HEAD_REF#release-}
echo Version: $VERSION
echo "VERSION=$VERSION" >> $GITHUB_ENV
- name: Push tag with version
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Tag the commit
run: |
git tag --annotate --message="Release version ${{ VERSION }}" ${{ VERSION }} ${{ github.sha }}
git push origin ${{ VERSION }}
github-release:
name: Make a GitHub Release and upload Python package.
needs: [build-package]
if: github.repository == 'Diaoul/subliminal' && startsWith(github.ref, 'refs/tags/') # only publish a Github release on push tag
runs-on: ubuntu-latest

permissions:
contents: write # IMPORTANT: mandatory for making GitHub Releases

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Download packages built by build-and-inspect-python-package
uses: actions/download-artifact@v4
with:
name: Packages
path: dist/*
path: dist

- name: Publish GitHub Release
uses: softprops/action-gh-release@v2
with:
files: dist/*
tag_name: ${{ github.event.inputs.version }}
generate_release_notes: true
draft: true

publish-to-pypi:
needs: [deploy]
needs: [build-package]
environment:
name: pypi
url: https://pypi.org/p/subliminal
permissions:
id-token: write
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/') # only publish to PyPI on tag pushes
if: github.repository == 'Diaoul/subliminal' && github.event.action == 'published' # only publish to PyPI on Github release published
steps:
- uses: actions/download-artifact@v4
- name: Download packages built by build-and-inspect-python-package
uses: actions/download-artifact@v4
with:
name: Packages
path: dist
Expand All @@ -50,46 +112,3 @@ jobs:
with:
user: __token__
password: ${{ secrets.PYPI_API_TOKEN }}

github-release:
name: >-
Sign the Python 🐍 distribution 📦 with Sigstore
and upload them to GitHub Release
needs: [publish-to-pypi]
runs-on: ubuntu-latest

permissions:
contents: write # IMPORTANT: mandatory for making GitHub Releases
id-token: write # IMPORTANT: mandatory for sigstore

steps:
- name: Download all the dists
uses: actions/download-artifact@v4
with:
name: Packages
path: dist/
- name: Sign the dists with Sigstore
uses: sigstore/[email protected]
with:
inputs: >-
./dist/*.tar.gz
./dist/*.whl
- name: Create GitHub Release Draft
env:
GITHUB_TOKEN: ${{ github.token }}
run: >-
gh release create
'${{ github.ref_name }}'
--repo '${{ github.repository }}'
--generate-notes
--notes ""
- name: Upload artifact signatures to GitHub Release
env:
GITHUB_TOKEN: ${{ github.token }}
# Upload to GitHub Release using the `gh` CLI.
# `dist/` contains the built packages, and the
# sigstore-produced signatures and certificates.
run: >-
gh release upload
'${{ github.ref_name }}' dist/**
--repo '${{ github.repository }}'
90 changes: 90 additions & 0 deletions RELEASING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# Release procedure

The git commands assume the following remotes are setup:

* ``origin``: your own fork of the repository.
* ``upstream``: the ``Diaoul/subliminal`` official repository.

## Preparing a new release: Manual method

There are few steps to follow when making a new release:

1. Lint the code, check types, test, check the coverage is high enough
and build and test the documentation.

2. Bump the version number, wherever it is, and update ``HISTORY.rst``
with the changelog fragments.

3. Tag the new version with ``git``.

4. Publish the source distribution and wheel to Pypi.

Although this can all be done manually, there is an automated way,
to limit errors.

## Preparing a new release: Automatic method

We use an automated workflow for releases, that uses GitHub workflows and is triggered
by [manually running](https://docs.github.com/en/actions/managing-workflow-runs/manually-running-a-workflow)
the [prepare-release-pr workflow](https://github.com/Diaoul/subliminal/actions/workflows/prepare-release-pr.yaml)
on GitHub Actions.

1. The automation will decide the new version number based on the following criteria:

- If there is any ``.breaking.rst`` files in the ``changelog.d`` directory, release a new major release
(e.g. 7.0.0 -> 8.0.0)
- If there are any ``.change.rst`` files in the
``changelog.d`` directory, release a new minor release
(e.g. 7.0.0 -> 7.1.0)
- Otherwise, release a patch release
(e.g. 7.0.0 -> 7.0.1)
- If the "prerelease" input is set, append the string to the version number
(e.g. 7.0.0 -> 8.0.0rc1, if "major" is set, and "prerelease" is set to `rc1`)

The choice of the bumped version can be bypassed by the "bump" input
(empty choice means automatic bumped version detection).

2. Trigger the workflow with the following inputs:

- branch: **main**
- bump: [**empty**, major, minor, patch]
- prerelease: empty

Or via the commandline::

gh workflow run prepare-release-pr.yml -f branch=main -f bump=major -f prerelease=

The automated workflow will publish a PR for a branch ``release-8.0.0``.


## Preparing a new release: Semi-automatic method

To release a version ``MAJOR.MINOR.PATCH-PRERELEASE``, follow these steps:

* Create a branch ``release-MAJOR.MINOR.PATCH-PRERELEASE`` from the ``upstream/main`` branch.

Ensure your are updated and in a clean working tree.

* Using ``tox``, generate docs, changelog, announcements::

$ tox -e release -- MAJOR.MINOR.PATCH-PRERELEASE

This will generate a commit with all the changes ready for pushing.

* Push the ``release-MAJOR.MINOR.PATCH-PRERELEASE`` local branch to the remote
``upstream/release-MAJOR.MINOR.PATCH-PRERELEASE``

* Open a PR for the ``release-MAJOR.MINOR.PATCH-PRERELEASE`` branch targeting ``upstream/main``.


## Releasing

Both automatic and manual processes described above follow the same steps from this point onward.

* After all tests pass and the PR has been approved, merge the PR.
Merging the PR will trigger the
[publish workflow](https://github.com/pytest-dev/pytest/actions/workflows/publish.yaml),
using the ``release-MAJOR.MINOR.PATCH`` branch as source.

This job will tag the new version and publish a draft for a Github release.
When the Github release draft is published, the same workflow will publish to PyPI.
1 change: 1 addition & 0 deletions scripts/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
latest-release-notes.md
Loading

0 comments on commit 2cbb8aa

Please sign in to comment.