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 24, 2024
1 parent 3e81603 commit f5b3e87
Show file tree
Hide file tree
Showing 11 changed files with 631 additions and 63 deletions.
53 changes: 53 additions & 0 deletions .github/workflows/prepare-release-pr.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
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: ''

env:
FORCE_COLOR: "1"

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
env:
BRANCH: ${{ github.event.inputs.branch }}
BUMP: ${{ github.event.inputs.bump }}
PRERELEASE: ${{ github.event.inputs.prerelease }}
run: |
tox -e prepare-release-pr -- ${BRANCH} ${{ github.token }} --bump='${BUMP}' --prerelease='${PRERELEASE}'
123 changes: 61 additions & 62 deletions .github/workflows/publish.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ on:
push:
tags:
- '*'
workflow_run:
workflows: ["Tag release"]
types:
- completed
release:
types:
- published
Expand All @@ -15,85 +19,80 @@ env:

# 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
with:
fetch-depth: 0
persist-credentials: false
- uses: actions/setup-python@v5

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

outputs:
# Used to define the matrix for tests below. The value is based on
# packaging metadata (trove classifiers).
supported-python-versions: ${{ steps.baipp.outputs.supported_python_classifiers_json_array }}

github-release:
name: Make a GitHub Release
needs: [build-package]
# only publish a Github release on push tag
if: |
github.repository == 'Diaoul/subliminal'
&& (
(github.event_name == 'push' && startsWith(github.ref, 'refs/tags/'))
|| github.event_name == 'workflow_run'
)
runs-on: ubuntu-latest

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

steps:
- name: Checkout
uses: actions/checkout@v4
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

- 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/*
generate_release_notes: true
draft: true

publish-to-pypi:
needs: [deploy]
name: Publish package to pypi.
needs: [build-package]
runs-on: ubuntu-latest
environment:
name: pypi
url: https://pypi.org/p/subliminal
permissions:
# IMPORTANT: this permission is mandatory for trusted publishing
id-token: write
runs-on: ubuntu-latest
# only publish to PyPI on tag pushes
if: startsWith(github.ref, 'refs/tags/')
# only publish to PyPI on Github release published
if: |
github.repository == 'Diaoul/subliminal'
&& github.event_name == 'release'
&& github.event.action == '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
- name: Publish package
- name: Publish package distributions to PyPI
uses: pypa/gh-action-pypi-publish@release/v1

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/gh-action-sigstore-python@v2.1.1
with:
inputs: >-
./dist/*.tar.gz
./dist/*.whl
- name: Create GitHub Release Draft
env:
GITHUB_TOKEN: ${{ github.token }}
VERSION: ${{ github.ref_name }}
run: >-
gh release create
'${VERSION}'
--repo '${{ github.repository }}'
--generate-notes
--notes ""
- name: Upload artifact signatures to GitHub Release
env:
GITHUB_TOKEN: ${{ github.token }}
VERSION: ${{ github.ref_name }}
# Upload to GitHub Release using the `gh` CLI.
# `dist/` contains the built packages, and the
# sigstore-produced signatures and certificates.
run: >-
gh release upload
'${VERSION}' dist/**
--repo '${{ github.repository }}'
58 changes: 58 additions & 0 deletions .github/workflows/tag-release.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
name: Tag release

on:
pull_request:
types:
- closed
workflow_dispatch:
inputs:
version:
description: 'Release tag version.'
type: string
default: NONE
required: true

env:
FORCE_COLOR: "1"

# https://packaging.python.org/en/latest/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows/
jobs:
# Always build & lint package.
build-package:
name: Build & verify package
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

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

tag:
name: Tag a new release
# tag a release after a release PR was accepted
if: |
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:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Tag the commit
run: |
RELEASE_VERSION=${GITHUB_HEAD_REF#release-}
echo Release version: $RELEASE_VERSION
git config user.name 'subliminal bot'
git config user.email diaoulael@gmail.com
git tag --annotate --message="Release version $RELEASE_VERSION" $RELEASE_VERSION ${{ github.sha }}
git push origin $RELEASE_VERSION
2 changes: 2 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
include LICENSE
include HISTORY.rst
include CONTRIBUTING.md
include RELEASING.md
include Dockerfile
include .dockerignore
include .pre-commit-config.yaml
Expand All @@ -10,6 +11,7 @@ include tox.ini

graft docs
graft tests
graft scripts

prune changelog.d
prune */__pycache__
93 changes: 93 additions & 0 deletions RELEASING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# 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
[tag-release workflow](https://github.com/Diaoul/subliminal/actions/workflows/tag-release.yaml), that will add a release tag.

This new tag will then trigger the
[publish workflow](https://github.com/Diaoul/subliminal/actions/workflows/publish.yaml),
using the ``release-MAJOR.MINOR.PATCH`` branch as source.

This job will 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 changelog.d/1186.change.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add release scripts, documentation and Github Actions
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ name = "subliminal"
package = "subliminal"
directory = "changelog.d"
filename = "HISTORY.rst"
title_format = "`version <https://github.com/Diaoul/subliminal/tree/{version}>`_ - {project_date}"
title_format = "`v{version} <https://github.com/Diaoul/subliminal/tree/{version}>`_ ({project_date})"
issue_format = "`#{issue} <https://github.com/Diaoul/subliminal/issues/{issue}>`_"
underlines = ["^", "-", "~"]

Expand Down
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 f5b3e87

Please sign in to comment.