Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add release scripts, actions and documentation #1186

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions .github/workflows/prepare-release-pr.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
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
persist-credentials: false

- 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}'
124 changes: 62 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,81 @@ 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
persist-credentials: false

- 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/[email protected]
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 }}'
60 changes: 60 additions & 0 deletions .github/workflows/tag-release.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
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
persist-credentials: false

- 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
persist-credentials: false

- 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 [email protected]
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
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ ignore = [
"docs/conf*.py" = ["ALL"]
"src/subliminal/__init__.py" = ["E402"]
"tests/*.py" = ["D", "S", "RUF012", "ANN", "FBT"]
"scripts/*.py" = ["T201"]

# https://docs.astral.sh/ruff/formatter/
[tool.ruff.format]
Expand All @@ -226,7 +227,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
Loading
Loading