Releaser
Releaser is a Docker GitHub Action written in Python.
Releaser allows to keep a GitHub Release of type pre-release and its artifacts up to date with latest builds. Combined with a workflow that is executed periodically, Releaser allows to provide a fixed release name for users willing to use daily/nightly artifacts of a project.
Furthermore, when any semver compliant tagged commit is pushed, Releaser can create a release and upload assets.
Context
GitHub provides official clients for the GitHub API through github.com/octokit:
When GitHub Actions was released in 2019, two Actions were made available through github.com/actions for dealing with GitHub Releases:
However, those Actions were contributed by an employee in spare time, not officially supported by GitHub. Therefore, they were unmaintained before GitHub Actions was out of the private beta (see actions/upload-release-asset#58) and, a year later, archived. Those Actions are based on actions/toolkit’s hydrated version of octokit.js.
From a practical point of view, actions/github-script is the natural replacement to those Actions, since it allows to use a pre-authenticated octokit.js client along with the workflow run context. Still, it requires writing plain JavaScript.
Alternatively, there are non-official GitHub API libraries available in other languages (see docs.github.com: rest/overview/libraries). Releaser is based on PyGithub/PyGithub, a Python client for the GitHub API.
Releaser was originally created in eine/tip, as an enhanced alternative to using
actions/create-release
and actions/upload-release-asset
, in order to cover certain use cases that were being
migrated from Travis CI to GitHub Actions.
The main limitation of GitHub’s Actions was/is verbosity and not being possible to dynamically define the list of assets
to be uploaded.
On the other hand, GitHub Actions artifacts do require login in order to download them. Conversely, assets of GitHub Releases can be downloaded without login. Therefore, in order to make CI results available to the widest audience, some projects prefer having tarballs available as assets. In this context, one of the main use cases of Releaser is pushing artifacts as release assets. Thus, the name of the Action.
GitHub provides an official CLI tool, written in golang: cli/cli.
When the Python version of Releaser was written, cli
was evaluated as an alternative to PyGitHub.
gh release
was (and still is) not flexible enough to update the reference of a release, without deleting and
recreating it (see cli.github.com: manual/gh_release_create).
Deletion and recreation is unfortunate, because it notifies all the watchers of a repository
(see eine/tip#111).
However, cli.github.com: manual/gh_release_upload handles uploading
artifacts as assets faster and with better stability for larger files than PyGitHub
(see msys2/msys2-installer#36).
Furthermore, the GitHub CLI is installed on GitHub Actions’ default virtual environments.
Although gh
does not support login through SSH (see cli/cli#3715), on GitHub
Actions a token is available ${{ github.token }}
.
Therefore, Releaser uses gh release upload
internally.
Usage
The following block shows a minimal YAML workflow file:
name: 'workflow'
on:
schedule:
- cron: '0 0 * * 5'
jobs:
mwe:
runs-on: ubuntu-24.04
steps:
# Clone repository
- uses: actions/checkout@v4
# Build your application, tool, artifacts, etc.
- name: Build
run: |
echo "Build some tool and generate some artifacts" > artifact.txt
# Update tag and pre-release
# - Update (force-push) tag to the commit that is used in the workflow.
# - Upload artifacts defined by the user.
- uses: pyTooling/Actions/releaser@r0
with:
token: ${{ secrets.GITHUB_TOKEN }}
files: |
artifact.txt
README.md
Composite Action
The default implementation of Releaser is a Container Action.
Therefore, a pre-built container image is pulled before starting the job.
Alternatively, a Composite Action version is available: uses: pyTooling/Actions/releaser/composite@main
.
The Composite version installs the dependencies on the host (the runner environment), instead of using a container.
Both implementations are functionally equivalent from Releaser’s point of view; however, the Composite Action allows
users to tweak the version of Python by using actions/setup-python before.
Options
All options can be optionally provided as environment variables: INPUT_TOKEN
, INPUT_FILES
, INPUT_TAG
, INPUT_RM
and/or INPUT_SNAPSHOTS
.
token (required)
Token to make authenticated API calls; can be passed in using {{ secrets.GITHUB_TOKEN }}
.
files (required)
Either a single filename/pattern or a multi-line list can be provided. All the artifacts are uploaded regardless of the hierarchy.
For creating/updating a release without uploading assets, set files: none
.
tag
The default tag name for the tip/nightly pre-release is tip
, but it can be optionally overriden through option tag
.
rm
Set option rm
to true
for systematically removing previous artifacts (e.g. old versions).
Otherwise (by default), all previours artifacts are preserved or overwritten.
- Note:
If all the assets are removed, or if the release itself is removed, tip/nightly assets won’t be available for users until the workflow is successfully run. For instance, Action setup-ghdl-ci uses assets from ghdl/ghdl: releases/tag/nightly. Hence, it is recommended to try removing the conflictive assets only, in order to maximise the availability.
snapshots
Whether to create releases from any tag or to treat some as snapshots.
By default, all the tags with non-empty prerelease
field (see semver.org: Is there a suggested regular expression (RegEx) to check a SemVer string?)
are considered snapshots; neither a release is created nor assets are uploaded.
Advanced/complex use cases
Releaser is essentially a very thin wrapper to use the GitHub Actions context data along with the classes and methods of PyGithub.
Similarly to actions/github-script, users with advanced/complex requirements
might find it desirable to write their own Python script, instead of using Releaser.
In fact, since shell: python
is supported in GitHub Actions, using Python does not require any Action.
For prototyping purposes, the following job might be useful:
Release:
name: '📦 Release'
runs-on: ubuntu-24.04
needs:
- ...
if: github.event_name != 'pull_request' && (github.ref == 'refs/heads/master' || contains(github.ref, 'refs/tags/'>`__)
steps:
- uses: actions/download-artifact@v3
- shell: bash
run: pip install PyGithub --progress-bar off
- name: Set list of files for uploading
id: files
shell: python
run: |
from github import Github
print("· Get GitHub API handler (authenticate)")
gh = Github('${{ github.token }}')
print("· Get Repository handler")
gh_repo = gh.get_repo('${{ github.repository }}')
Find a non-trivial use case at msys2/msys2-autobuild.