Skip to content

Release

Release #88

Workflow file for this run

name: Release
on:
workflow_dispatch:
inputs:
release_type:
description: 'Release type'
required: true
default: 'patch'
type: choice
options:
- 'patch'
- 'minor'
- 'major'
# FIXME do we want a possibility to do prereleases here?
python_version:
description: 'Python version'
required: true
default: '3.12'
type: choice
options:
- '3.8'
- '3.9'
- '3.10'
- '3.11'
- '3.12'
jobs:
prepare:
runs-on: ubuntu-20.04
timeout-minutes: 5
outputs:
version: ${{ steps.bump.outputs.version }}
release_id: ${{ steps.create-release.outputs.id }}
permissions:
contents: write # To push release commit/tag
steps:
- name: Find release branch
uses: actions/github-script@v7
id: find-branch
with:
script: |
if (context.payload.inputs.release_type != 'patch') {
return 'main';
}
const branches = await github.paginate(github.rest.repos.listBranches, {
owner: context.repo.owner,
repo: context.repo.repo,
});
const branch_names = branches.map(branch => branch.name);
console.log(`branches: ${branch_names}`);
const release_branches = branch_names.filter(branch => branch.match(/^v\d+\.\d+\.x$/));
if (release_branches.length === 0) {
core.setFailed('No release branch found!');
return '';
}
console.log(`release_branches: ${release_branches}`);
// Get newest release branch (biggest version number)
const sorted = release_branches.sort((a, b) => a.localeCompare(b, undefined, { numeric: true, sensitivity: 'base' }));
console.log(`sorted: ${sorted}`);
return sorted.at(-1);
result-encoding: string
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
# Doesn't really matter what we prepare the release with, but let's
# use the same version for consistency.
python-version: ${{ github.event.inputs.python_version }}
- name: Install dependencies
run: |
python -m pip install -U pip
python -m pip install -U -r misc/requirements/requirements-tox.txt
- name: Configure git
run: |
git config --global user.name "qutebrowser bot"
git config --global user.email "[email protected]"
- name: Switch to release branch
uses: actions/checkout@v4
with:
ref: ${{ steps.find-branch.outputs.result }}
- name: Import GPG Key
run: |
gpg --import <<< "${{ secrets.QUTEBROWSER_BOT_GPGKEY }}"
- name: Bump version
id: bump
run: "tox -e update-version -- ${{ github.event.inputs.release_type }}"
- name: Check milestone
uses: actions/github-script@v7
with:
script: |
const milestones = await github.paginate(github.rest.issues.listMilestones, {
owner: context.repo.owner,
repo: context.repo.repo,
});
const names = milestones.map(milestone => milestone.title);
console.log(`milestones: ${names}`);
const milestone = milestones.find(milestone => milestone.title === "v${{ steps.bump.outputs.version }}");
if (milestone !== undefined) {
core.setFailed(`Found open milestone ${milestone.title} with ${milestone.open_issues} open and ${milestone.closed_issues} closed issues!`);
}
- name: Push release commit/tag
run: |
git push origin ${{ steps.find-branch.outputs.result }}
git push origin v${{ steps.bump.outputs.version }}
- name: Cherry-pick release commit
if: ${{ github.event.inputs.release_type == 'patch' }}
run: |
git checkout main
git cherry-pick -x v${{ steps.bump.outputs.version }}
git push origin main
git checkout v${{ steps.bump.outputs.version_x }}
- name: Create release branch
if: ${{ github.event.inputs.release_type != 'patch' }}
run: |
git checkout -b v${{ steps.bump.outputs.version_x }}
git push --set-upstream origin v${{ steps.bump.outputs.version_x }}
- name: Create GitHub draft release
id: create-release
uses: softprops/action-gh-release@v2
with:
tag_name: v${{ steps.bump.outputs.version }}
draft: true
body: "*Release artifacts for this release are currently being uploaded...*"
release:
strategy:
matrix:
include:
- os: macos-11
- os: macos-14
- os: windows-2019
- os: ubuntu-20.04
runs-on: "${{ matrix.os }}"
timeout-minutes: 45
needs: [prepare]
permissions:
contents: write # To upload release artifacts
steps:
- uses: actions/checkout@v4
with:
ref: v${{ needs.prepare.outputs.version }}
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ github.event.inputs.python_version }}
- name: Import GPG Key
if: ${{ startsWith(matrix.os, 'ubuntu-') }}
run: |
gpg --import <<< "${{ secrets.QUTEBROWSER_BOT_GPGKEY }}"
# Needed because of the following import chain:
# - scripts/dev/build_release.py
# - scripts/dev/update_3rdparty.py
# - scripts/dictcli.py
# - qutebrowser/browser/webengine/spell.py
# - utils.message -> utils.usertypes -> utils.qtutils -> qt.gui
# - PyQt6.QtGui
# Some additional packages are needed for a2x to build manpage
- name: Install apt dependencies
if: ${{ startsWith(matrix.os, 'ubuntu-') }}
run: |
sudo apt-get update
sudo apt-get install --no-install-recommends libegl1-mesa libxml2-utils docbook-xml xsltproc docbook-xsl
- name: Install dependencies
run: |
python -m pip install -U pip
python -m pip install -U -r misc/requirements/requirements-tox.txt
# FIXME consider switching to trusted publishers:
# https://blog.pypi.org/posts/2023-04-20-introducing-trusted-publishers/
- name: Build and upload release
run: "tox -e build-release -- --upload --no-confirm"
env:
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets.QUTEBROWSER_BOT_PYPI_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
finalize:
runs-on: ubuntu-20.04
timeout-minutes: 5
needs: [prepare, release]
permissions:
contents: write # To change release
steps:
- name: Publish final release
uses: actions/github-script@v7
with:
script: |
await github.rest.repos.updateRelease({
owner: context.repo.owner,
repo: context.repo.repo,
release_id: "${{ needs.prepare.outputs.release_id }}",
draft: false,
body: "Check the [changelog](https://github.com/qutebrowser/qutebrowser/blob/main/doc/changelog.asciidoc) for changes in this release.",
})
irc:
timeout-minutes: 2
continue-on-error: true
runs-on: ubuntu-20.04
needs: [prepare, release, finalize]
if: "${{ always() }}"
steps:
- name: Send success IRC notification
uses: Gottox/irc-message-action@v2
if: "${{ needs.finalize.result == 'success' }}"
with:
server: irc.libera.chat
channel: '#qutebrowser-bots'
nickname: qutebrowser-bot
message: "[${{ github.workflow }}] \u00033Success:\u0003 ${{ github.ref }} https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} (@${{ github.actor }})"
- name: Send main channel IRC notification
uses: Gottox/irc-message-action@v2
if: "${{ needs.finalize.result == 'success' && github.repository == 'qutebrowser/qutebrowser' }}"
with:
server: irc.libera.chat
channel: '#qutebrowser'
nickname: qutebrowser-bot
message: "qutebrowser v${{ needs.prepare.outputs.version }} has been released! https://github.com/${{ github.repository }}/releases/tag/v${{ needs.prepare.outputs.version }}"
- name: Send non-success IRC notification
uses: Gottox/irc-message-action@v2
if: "${{ needs.finalize.result != 'success' }}"
with:
server: irc.libera.chat
channel: '#qutebrowser-bots'
nickname: qutebrowser-bot
message: "[${{ github.workflow }}] \u00034FAIL:\u0003 ${{ github.ref }} https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} (@${{ github.actor }})\n
prepare: ${{ needs.prepare.result }}, release: ${{ needs.release.result}}, finalize: ${{ needs.finalize.result }}"