Skip to content

Release v4.7.2

Release v4.7.2 #4929

Workflow file for this run

---
name: Build & release
# Read https://github.com/actions/runner/issues/491 for insights on complex workflow execution logic.
"on":
workflow_call:
secrets:
PYPI_TOKEN:
required: false
outputs:
nuitka_matrix:
description: Nuitka build matrix
value: ${{ jobs.project-metadata.outputs.nuitka_matrix }}
# Target are chosen so that all commits get a chance to have their build tested.
push:
branches:
- main
pull_request:
jobs:
project-metadata:
name: Project metadata
runs-on: ubuntu-24.04
outputs:
# There's a design issue with GitHub actions: matrix outputs are not cumulative. The last job wins
# (see: https://github.community/t/bug-jobs-output-should-return-a-list-for-a-matrix-job/128626).
# This means in a graph of jobs, a matrix-based one is terminal, and cannot be depended on. Same goes for
# (reusable) workflows. We use this preliminary job to produce all matrix we need to trigger depending jobs
# over the dimensions.
new_commits_matrix: ${{ steps.project-metadata.outputs.new_commits_matrix }}
release_commits_matrix: ${{ steps.project-metadata.outputs.release_commits_matrix }}
# Export Python project metadata.
nuitka_matrix: ${{ steps.project-metadata.outputs.nuitka_matrix }}
is_python_project: ${{ steps.project-metadata.outputs.is_python_project }}
package_name: ${{ steps.project-metadata.outputs.package_name }}
release_notes: ${{ steps.project-metadata.outputs.release_notes }}
steps:
- uses: actions/checkout@v4.2.2
with:
# Checkout pull request HEAD commit to ignore actions/checkout's merge commit. Fallback to push SHA.
ref: ${{ github.event.pull_request.head.sha || github.sha }}
# We're going to browse all new commits.
fetch-depth: 0
- name: List all branches
run: |
git branch --all
- name: List all commits
run: |
git log --decorate=full --oneline
- uses: actions/setup-python@v5.3.0
with:
python-version: "3.12"
cache: "pip"
cache-dependency-path: |
**/pyproject.toml
*requirements.txt
requirements/*.txt
- name: Install uv
run: |
python -m pip install -r https://raw.githubusercontent.com/kdeldycke/workflows/main/requirements/uv.txt
- name: Install gha-utils
run: >
uv tool install --with-requirements
https://raw.githubusercontent.com/kdeldycke/workflows/main/requirements/gha-utils.txt gha-utils
- name: Project metadata
id: project-metadata
env:
GITHUB_CONTEXT: ${{ toJSON(github) }}
run: |
gha-utils --verbosity DEBUG metadata --overwrite "$GITHUB_OUTPUT"
package-build:
name: "Build & check package"
needs:
- project-metadata
if: fromJSON(needs.project-metadata.outputs.is_python_project)
strategy:
matrix: ${{ fromJSON(needs.project-metadata.outputs.new_commits_matrix) }}
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4.2.2
with:
ref: ${{ matrix.commit }}
- uses: actions/setup-python@v5.3.0
with:
python-version: "3.12"
cache: "pip"
cache-dependency-path: |
**/pyproject.toml
*requirements.txt
requirements/*.txt
- name: Install uv
run: |
python -m pip install -r https://raw.githubusercontent.com/kdeldycke/workflows/main/requirements/uv.txt
- name: Install build dependencies
run: |
uv --no-progress venv
uv --no-progress pip install \
--requirement https://raw.githubusercontent.com/kdeldycke/workflows/main/requirements/build.txt
- name: Build package
run: |
uv --no-progress build
- name: Upload artifacts
uses: actions/upload-artifact@v4.4.3
with:
name: ${{ github.event.repository.name }}-build-${{ matrix.short_sha }}
path: ./dist/*
- name: Validates package metadata
# XXX These checks might be replaced by uv one day:
# https://github.com/astral-sh/uv/issues/8641
# https://github.com/astral-sh/uv/issues/8774
run: |
uv --no-progress run --frozen -- twine check ./dist/*
uv --no-progress run --frozen -- check-wheel-contents ./dist/*.whl
compile-binaries:
name: "Nuitka: generate binaries"
needs:
- project-metadata
if: needs.project-metadata.outputs.nuitka_matrix
strategy:
matrix: ${{ fromJSON(needs.project-metadata.outputs.nuitka_matrix) }}
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4.2.2
with:
ref: ${{ matrix.commit }}
- uses: actions/setup-python@v5.3.0
with:
python-version: "3.12"
cache: "pip"
cache-dependency-path: |
**/pyproject.toml
*requirements.txt
requirements/*.txt
- name: Install uv
run: |
python -m pip install -r https://raw.githubusercontent.com/kdeldycke/workflows/main/requirements/uv.txt
- name: Install Nuitka
# XXX We cannot break the long "pip install" line below with a class "\" because it will not be able to run on
# Windows' shell:
# ParserError: D:\a\_temp\330d7ec7-c0bf-4856-b2d8-407b69be9ee2.ps1:4
# Line |
# 4 | --requirement https://raw.githubusercontent.com/kdeldycke/workflows/m …
# | ~
# | Missing expression after unary operator '--'.
# yamllint disable rule:line-length
run: |
uv --no-progress venv
uv --no-progress pip install --requirement https://raw.githubusercontent.com/kdeldycke/workflows/main/requirements/nuitka.txt
# yamllint enable
- name: List uv CLIs
continue-on-error: true
run: |
uv run
- name: Nuitka + compilers versions - Linux & macOS
if: runner.os != 'Windows'
run: |
uv --no-progress run --frozen -- nuitka --version
- name: Build binary - Linux & macOS
if: runner.os != 'Windows'
run: >
uv --no-progress run --frozen -- nuitka
--onefile --assume-yes-for-downloads --output-filename=${{ matrix.bin_name }}
${{ matrix.module_path }}
# XXX We need to call "uv run python -m nuitka" instead of "uv run nuitka" on Windows because of this bug:
# https://github.com/Nuitka/Nuitka/issues/3173
# https://github.com/astral-sh/uv/issues/8770
- name: Nuitka + compilers versions - Windows
if: runner.os == 'Windows'
run: |
uv --no-progress run --frozen -- python -m nuitka --version
- name: Build binary - Windows
if: runner.os == 'Windows'
env:
# Sets sys.flags.utf8_mode to True, which is like calling Python with the "-X utf8" parameter.
# This is a workaround for Windows runners, on redirecting the output of commands to files. See:
# https://github.com/databrickslabs/dbx/issues/455#issuecomment-1312770919
# https://github.com/pallets/click/issues/2121#issuecomment-1312773882
# https://gist.github.com/NodeJSmith/e7e37f2d3f162456869f015f842bcf15
# https://github.com/Nuitka/Nuitka/blob/ca1ec9e/nuitka/utils/ReExecute.py#L73-L74
PYTHONUTF8: 1
run: >
uv --no-progress run --frozen -- python -m nuitka
--onefile --assume-yes-for-downloads --output-filename=${{ matrix.bin_name }}
${{ matrix.module_path }}
- name: Upload binaries
uses: actions/upload-artifact@v4.4.3
with:
name: ${{ matrix.bin_name }}
if-no-files-found: error
path: ${{ matrix.bin_name }}
git-tag:
name: Tag release
needs:
- project-metadata
# Only consider pushes to main branch as triggers for releases.
if: github.ref == 'refs/heads/main' && needs.project-metadata.outputs.release_commits_matrix
strategy:
matrix: ${{ fromJSON(needs.project-metadata.outputs.release_commits_matrix) }}
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4.2.2
with:
ref: ${{ matrix.commit }}
- name: Check if tag exists
id: tag_exists
run: |
echo "tag_exists=$(git show-ref --tags "v${{ matrix.current_version }}" --quiet )" >> "$GITHUB_OUTPUT"
- name: Tag search results
run: |
echo "Does tag exist? ${{ steps.tag_exists.outputs.tag_exists && true || false }}"
- name: Push tag
# If for whatever reason the workflow is re-run because it failed the first time, just
# skip the tag creation if it already exists.
if: ${{ ! steps.tag_exists.outputs.tag_exists }}
uses: tvdias/github-tagger@v0.0.2
with:
# XXX We need custom PAT with workflows permissions BECAUSE ??? in .github/workflows/*.yaml files.
repo-token: ${{ secrets.WORKFLOW_UPDATE_GITHUB_PAT || secrets.GITHUB_TOKEN }}
tag: v${{ matrix.current_version }}
commit-sha: ${{ matrix.commit }}
pypi-publish:
name: Publish to PyPi
needs:
- project-metadata
- package-build
- git-tag
if: needs.project-metadata.outputs.package_name
strategy:
matrix: ${{ fromJSON(needs.project-metadata.outputs.release_commits_matrix) }}
runs-on: ubuntu-24.04
steps:
- name: Install uv
run: |
python -m pip install -r https://raw.githubusercontent.com/kdeldycke/workflows/main/requirements/uv.txt
- name: Download build artifacts
uses: actions/download-artifact@v4.1.8
id: download
with:
name: ${{ github.event.repository.name }}-build-${{ matrix.short_sha }}
- name: Push to PyPi
run: |
uv --no-progress publish --token "${{ secrets.PYPI_TOKEN }}" "${{ steps.download.outputs.download-path }}/*"
github-release:
name: Publish GitHub release
needs:
- project-metadata
- compile-binaries
- git-tag
- pypi-publish
# Make sure this job always starts if git-tag ran and succeeded.
if: always() && needs.git-tag.result == 'success'
strategy:
matrix: ${{ fromJSON(needs.project-metadata.outputs.release_commits_matrix) }}
runs-on: ubuntu-24.04
steps:
- name: Download all artifacts
# Do not try to fetch build artifacts if any of the job producing them was skipped.
if: needs.pypi-publish.result != 'skipped' || needs.compile-binaries.result != 'skipped'
uses: actions/download-artifact@v4.1.8
id: artifacts
with:
path: release_artifact
# Only consider artifacts produced by the release commit.
pattern: "*-build-${{ matrix.short_sha }}*"
merge-multiple: true
- name: Rename binary artifacts, collect all others
# Do not try to rename artifacts if the job producing them was skipped.
if: needs.compile-binaries.result != 'skipped'
id: rename_artifacts
shell: python
run: |
import json
import os
from pathlib import Path
from random import randint
download_folder = Path("""${{ steps.artifacts.outputs.download-path }}""")
nuitka_matrix = json.loads("""${{ needs.project-metadata.outputs.nuitka_matrix }}""")
binaries = {entry["bin_name"] for entry in nuitka_matrix["include"] if "bin_name" in entry}
artifacts_path = []
for artifact in download_folder.glob("*"):
print(f"Processing {artifact} ...")
assert artifact.is_file()
# Rename binary artifacts to remove the build ID.
if artifact.name in binaries:
new_name = f'{artifact.stem.split("""-build-${{ matrix.short_sha }}""", 1)[0]}{artifact.suffix}'
new_path = artifact.with_name(new_name)
print(f"Renaming {artifact} to {new_path} ...")
assert not new_path.exists()
artifact.rename(new_path)
artifacts_path.append(new_path)
# Collect other artifacts as-is.
else:
print(f"Collecting {artifact} ...")
artifacts_path.append(artifact)
# Produce a unique delimiter to feed multiline content to GITHUB_OUTPUT:
# https://github.com/orgs/community/discussions/26288#discussioncomment-3876281
delimiter = f"ghadelimiter_{randint(10**8, (10**9) - 1)}"
output = f"artifacts_path<<{delimiter}\n"
output += "\n".join(str(p) for p in artifacts_path)
output += f"\n{delimiter}"
env_file = Path(os.getenv("GITHUB_OUTPUT"))
env_file.write_text(output)
- name: Create GitHub release
uses: softprops/action-gh-release@v2.0.9
env:
# XXX We need custom PAT with workflows permissions BECAUSE ??? in .github/workflows/*.yaml files.
GITHUB_TOKEN: ${{ secrets.WORKFLOW_UPDATE_GITHUB_PAT || secrets.GITHUB_TOKEN }}
with:
tag_name: v${{ matrix.current_version }}
target_commitish: ${{ matrix.commit }}
files: ${{ steps.rename_artifacts.outputs.artifacts_path }}
body: ${{ needs.project-metadata.outputs.release_notes }}