Build on Version Bump workflow (ChenlizheMe/Infernux)
The Build on Version Bump workflow from ChenlizheMe/Infernux, explained and optimized by Latchkey.
CI health: C - fair
Point runs-on at Latchkey and get caching, job timeouts, self-healing for flaky steps, and up to 58% lower cost, applied automatically.
What it does
This is the Build on Version Bump workflow from the ChenlizheMe/Infernux repository, a real project running GitHub Actions. It is shown here with attribution under its MIT license.
Below, Latchkey shows a faster, safer version produced by its optimization engine.
The workflow
name: Build on Version Bump
# Builds the native module + wheel whenever the project version in
# pyproject.toml changes on master/main (plus manual dispatch).
#
# Outputs:
# - Windows wheel + InfernuxHubInstaller.exe uploaded as workflow artifacts
# - GitHub Release v<version> using UpdateLog.md as the release notes
on:
push:
branches: [master, main]
paths:
- "pyproject.toml"
- "UpdateLog.md"
- ".github/workflows/build-on-version.yml"
workflow_dispatch: {}
permissions:
contents: write
concurrency:
group: build-on-version-${{ github.ref }}
cancel-in-progress: true
jobs:
detect-version-change:
runs-on: ubuntu-latest
env:
GH_TOKEN: ${{ github.token }}
outputs:
changed: ${{ steps.check.outputs.changed }}
version: ${{ steps.check.outputs.version }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 2
- name: Compare project version with parent commit
id: check
shell: bash
run: |
get_ver() { python3 -c "import tomllib,sys; print(tomllib.load(open(sys.argv[1],'rb'))['project']['version'])" "$1"; }
NEW_VER=$(get_ver pyproject.toml)
OLD_VER=""
if git rev-parse HEAD^ >/dev/null 2>&1; then
git show HEAD^:pyproject.toml > /tmp/old_pyproject.toml 2>/dev/null && \
OLD_VER=$(get_ver /tmp/old_pyproject.toml) || OLD_VER=""
fi
echo "version=$NEW_VER" >> "$GITHUB_OUTPUT"
UPDATELOG_CHANGED=false
if git rev-parse HEAD^ >/dev/null 2>&1; then
if git diff --name-only HEAD^ HEAD | grep -qx "UpdateLog.md"; then
UPDATELOG_CHANGED=true
fi
fi
RELEASE_EXISTS=false
if gh release view "v$NEW_VER" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then
RELEASE_EXISTS=true
fi
if [ "${{ github.event_name }}" = "workflow_dispatch" ] || [ "$NEW_VER" != "$OLD_VER" ] || [ "$UPDATELOG_CHANGED" = "true" ] || [ "$RELEASE_EXISTS" != "true" ]; then
echo "changed=true" >> "$GITHUB_OUTPUT"
echo "Build requested. event='${{ github.event_name }}', old='$OLD_VER', new='$NEW_VER', update_log_changed='$UPDATELOG_CHANGED', release_exists='$RELEASE_EXISTS'"
else
echo "changed=false" >> "$GITHUB_OUTPUT"
echo "Version unchanged and release v$NEW_VER already exists; skipping build."
fi
build-windows:
needs: detect-version-change
if: needs.detect-version-change.outputs.changed == 'true'
runs-on: windows-2022
timeout-minutes: 120
env:
VULKAN_SDK_VERSION: "1.3.296.0"
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Cache Vulkan SDK
id: cache-vulkan
uses: actions/cache@v4
with:
path: C:\VulkanSDK\${{ env.VULKAN_SDK_VERSION }}
key: vulkan-sdk-${{ env.VULKAN_SDK_VERSION }}-windows
- name: Install Vulkan SDK (silent, with SPIRV-Cross)
if: steps.cache-vulkan.outputs.cache-hit != 'true'
shell: pwsh
run: |
$url = "https://sdk.lunarg.com/sdk/download/$env:VULKAN_SDK_VERSION/windows/VulkanSDK-$env:VULKAN_SDK_VERSION-Installer.exe"
Invoke-WebRequest -Uri $url -OutFile vulkan_sdk.exe
Start-Process -Wait -FilePath .\vulkan_sdk.exe -ArgumentList `
"--accept-licenses","--default-answer","--confirm-command","install"
- name: Install Python build dependencies
run: python -m pip install "pybind11>=2.11" numpy build wheel setuptools pyinstaller PySide6 Pillow
- name: Configure (CMake preset release)
shell: pwsh
run: |
$env:VULKAN_SDK = "C:\VulkanSDK\$env:VULKAN_SDK_VERSION"
cmake --preset release
- name: Build native module
shell: pwsh
run: |
$env:VULKAN_SDK = "C:\VulkanSDK\$env:VULKAN_SDK_VERSION"
cmake --build --preset release --target _Infernux --parallel
- name: Build wheel
env:
INFERNUX_SOURCE_DIR: ${{ github.workspace }}
run: python -m build --wheel --no-isolation --outdir dist
- name: Build Hub installer
shell: pwsh
run: |
$env:VULKAN_SDK = "C:\VulkanSDK\$env:VULKAN_SDK_VERSION"
cmake --build --preset release --target infernux_hub_installer --parallel
if (!(Test-Path "dist/installer/InfernuxHubInstaller.exe")) {
throw "Expected installer not found: dist/installer/InfernuxHubInstaller.exe"
}
- uses: actions/upload-artifact@v4
with:
name: infernux-${{ needs.detect-version-change.outputs.version }}-windows
path: dist/*.whl
if-no-files-found: error
- uses: actions/upload-artifact@v4
with:
name: infernux-${{ needs.detect-version-change.outputs.version }}-hub-installer
path: dist/installer/InfernuxHubInstaller.exe
if-no-files-found: error
publish-github-release:
needs: [detect-version-change, build-windows]
if: needs.detect-version-change.outputs.changed == 'true'
runs-on: ubuntu-latest
timeout-minutes: 15
env:
GH_TOKEN: ${{ github.token }}
VERSION: ${{ needs.detect-version-change.outputs.version }}
steps:
- uses: actions/checkout@v4
- name: Download wheel artifacts
uses: actions/download-artifact@v4
with:
pattern: infernux-${{ needs.detect-version-change.outputs.version }}-windows
path: release-dist
merge-multiple: true
- name: Download Hub installer artifact
uses: actions/download-artifact@v4
with:
pattern: infernux-${{ needs.detect-version-change.outputs.version }}-hub-installer
path: release-dist
merge-multiple: true
- name: Verify release assets
shell: bash
run: |
find release-dist -type f \( -name '*.whl' -o -name 'InfernuxHubInstaller.exe' \) -print | sort
wheel_count=$(find release-dist -type f -name '*.whl' | wc -l | tr -d ' ')
installer_count=$(find release-dist -type f -name 'InfernuxHubInstaller.exe' | wc -l | tr -d ' ')
if [ "$wheel_count" -lt 1 ]; then
echo "Expected at least 1 Windows wheel file, found $wheel_count" >&2
exit 1
fi
if [ "$installer_count" -lt 1 ]; then
echo "Expected InfernuxHubInstaller.exe, found $installer_count" >&2
exit 1
fi
if [ ! -s UpdateLog.md ]; then
echo "UpdateLog.md is required and must not be empty; it is used as the GitHub Release body." >&2
exit 1
fi
- name: Create or update GitHub Release
shell: bash
run: |
tag="v${VERSION}"
mapfile -t files < <(find release-dist -type f \( -name '*.whl' -o -name 'InfernuxHubInstaller.exe' \) | sort)
if gh release view "$tag" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then
echo "Release $tag already exists; uploading assets with --clobber."
gh release upload "$tag" "${files[@]}" --clobber --repo "$GITHUB_REPOSITORY"
gh release edit "$tag" --notes-file UpdateLog.md --latest --repo "$GITHUB_REPOSITORY"
else
echo "Creating release $tag."
gh release create "$tag" "${files[@]}" \
--repo "$GITHUB_REPOSITORY" \
--target "$GITHUB_SHA" \
--title "Infernux v${VERSION}" \
--notes-file UpdateLog.md \
--latest
fi
The same workflow, on Latchkey
Estimated ~20% faster on cache hits, plus fewer wasted runs and a safer supply chain. Added and changed lines are highlighted.
name: Build on Version Bump # Builds the native module + wheel whenever the project version in # pyproject.toml changes on master/main (plus manual dispatch). # # Outputs: # - Windows wheel + InfernuxHubInstaller.exe uploaded as workflow artifacts # - GitHub Release v<version> using UpdateLog.md as the release notes on: push: branches: [master, main] paths: - "pyproject.toml" - "UpdateLog.md" - ".github/workflows/build-on-version.yml" workflow_dispatch: {} permissions: contents: write concurrency: group: build-on-version-${{ github.ref }} cancel-in-progress: true jobs: detect-version-change: timeout-minutes: 30 runs-on: latchkey-small env: GH_TOKEN: ${{ github.token }} outputs: changed: ${{ steps.check.outputs.changed }} version: ${{ steps.check.outputs.version }} steps: - uses: actions/checkout@v4 with: fetch-depth: 2 - name: Compare project version with parent commit id: check shell: bash run: | get_ver() { python3 -c "import tomllib,sys; print(tomllib.load(open(sys.argv[1],'rb'))['project']['version'])" "$1"; } NEW_VER=$(get_ver pyproject.toml) OLD_VER="" if git rev-parse HEAD^ >/dev/null 2>&1; then git show HEAD^:pyproject.toml > /tmp/old_pyproject.toml 2>/dev/null && \ OLD_VER=$(get_ver /tmp/old_pyproject.toml) || OLD_VER="" fi echo "version=$NEW_VER" >> "$GITHUB_OUTPUT" UPDATELOG_CHANGED=false if git rev-parse HEAD^ >/dev/null 2>&1; then if git diff --name-only HEAD^ HEAD | grep -qx "UpdateLog.md"; then UPDATELOG_CHANGED=true fi fi RELEASE_EXISTS=false if gh release view "v$NEW_VER" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then RELEASE_EXISTS=true fi if [ "${{ github.event_name }}" = "workflow_dispatch" ] || [ "$NEW_VER" != "$OLD_VER" ] || [ "$UPDATELOG_CHANGED" = "true" ] || [ "$RELEASE_EXISTS" != "true" ]; then echo "changed=true" >> "$GITHUB_OUTPUT" echo "Build requested. event='${{ github.event_name }}', old='$OLD_VER', new='$NEW_VER', update_log_changed='$UPDATELOG_CHANGED', release_exists='$RELEASE_EXISTS'" else echo "changed=false" >> "$GITHUB_OUTPUT" echo "Version unchanged and release v$NEW_VER already exists; skipping build." fi build-windows: needs: detect-version-change if: needs.detect-version-change.outputs.changed == 'true' runs-on: windows-2022 timeout-minutes: 120 env: VULKAN_SDK_VERSION: "1.3.296.0" steps: - uses: actions/checkout@v4 with: submodules: recursive - uses: actions/setup-python@v5 with: cache: 'pip' python-version: "3.12" - name: Cache Vulkan SDK id: cache-vulkan uses: actions/cache@v4 with: path: C:\VulkanSDK\${{ env.VULKAN_SDK_VERSION }} key: vulkan-sdk-${{ env.VULKAN_SDK_VERSION }}-windows - name: Install Vulkan SDK (silent, with SPIRV-Cross) if: steps.cache-vulkan.outputs.cache-hit != 'true' shell: pwsh run: | $url = "https://sdk.lunarg.com/sdk/download/$env:VULKAN_SDK_VERSION/windows/VulkanSDK-$env:VULKAN_SDK_VERSION-Installer.exe" Invoke-WebRequest -Uri $url -OutFile vulkan_sdk.exe Start-Process -Wait -FilePath .\vulkan_sdk.exe -ArgumentList ` "--accept-licenses","--default-answer","--confirm-command","install" - name: Install Python build dependencies run: python -m pip install "pybind11>=2.11" numpy build wheel setuptools pyinstaller PySide6 Pillow - name: Configure (CMake preset release) shell: pwsh run: | $env:VULKAN_SDK = "C:\VulkanSDK\$env:VULKAN_SDK_VERSION" cmake --preset release - name: Build native module shell: pwsh run: | $env:VULKAN_SDK = "C:\VulkanSDK\$env:VULKAN_SDK_VERSION" cmake --build --preset release --target _Infernux --parallel - name: Build wheel env: INFERNUX_SOURCE_DIR: ${{ github.workspace }} run: python -m build --wheel --no-isolation --outdir dist - name: Build Hub installer shell: pwsh run: | $env:VULKAN_SDK = "C:\VulkanSDK\$env:VULKAN_SDK_VERSION" cmake --build --preset release --target infernux_hub_installer --parallel if (!(Test-Path "dist/installer/InfernuxHubInstaller.exe")) { throw "Expected installer not found: dist/installer/InfernuxHubInstaller.exe" } - uses: actions/upload-artifact@v4 with: name: infernux-${{ needs.detect-version-change.outputs.version }}-windows path: dist/*.whl if-no-files-found: error - uses: actions/upload-artifact@v4 with: name: infernux-${{ needs.detect-version-change.outputs.version }}-hub-installer path: dist/installer/InfernuxHubInstaller.exe if-no-files-found: error publish-github-release: needs: [detect-version-change, build-windows] if: needs.detect-version-change.outputs.changed == 'true' runs-on: latchkey-small timeout-minutes: 15 env: GH_TOKEN: ${{ github.token }} VERSION: ${{ needs.detect-version-change.outputs.version }} steps: - uses: actions/checkout@v4 - name: Download wheel artifacts uses: actions/download-artifact@v4 with: pattern: infernux-${{ needs.detect-version-change.outputs.version }}-windows path: release-dist merge-multiple: true - name: Download Hub installer artifact uses: actions/download-artifact@v4 with: pattern: infernux-${{ needs.detect-version-change.outputs.version }}-hub-installer path: release-dist merge-multiple: true - name: Verify release assets shell: bash run: | find release-dist -type f \( -name '*.whl' -o -name 'InfernuxHubInstaller.exe' \) -print | sort wheel_count=$(find release-dist -type f -name '*.whl' | wc -l | tr -d ' ') installer_count=$(find release-dist -type f -name 'InfernuxHubInstaller.exe' | wc -l | tr -d ' ') if [ "$wheel_count" -lt 1 ]; then echo "Expected at least 1 Windows wheel file, found $wheel_count" >&2 exit 1 fi if [ "$installer_count" -lt 1 ]; then echo "Expected InfernuxHubInstaller.exe, found $installer_count" >&2 exit 1 fi if [ ! -s UpdateLog.md ]; then echo "UpdateLog.md is required and must not be empty; it is used as the GitHub Release body." >&2 exit 1 fi - name: Create or update GitHub Release shell: bash run: | tag="v${VERSION}" mapfile -t files < <(find release-dist -type f \( -name '*.whl' -o -name 'InfernuxHubInstaller.exe' \) | sort) if gh release view "$tag" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then echo "Release $tag already exists; uploading assets with --clobber." gh release upload "$tag" "${files[@]}" --clobber --repo "$GITHUB_REPOSITORY" gh release edit "$tag" --notes-file UpdateLog.md --latest --repo "$GITHUB_REPOSITORY" else echo "Creating release $tag." gh release create "$tag" "${files[@]}" \ --repo "$GITHUB_REPOSITORY" \ --target "$GITHUB_SHA" \ --title "Infernux v${VERSION}" \ --notes-file UpdateLog.md \ --latest fi
What changed
- Run on Latchkey managed runners with one line (
runs-on), which apply the fixes below automatically and self-heal transient failures. This example useslatchkey-small; pick the runner size that fits the job. - Cache dependency installs on the setup step so they are served from cache.
- Add a job timeout so a hung step cannot burn hours of runner time.
What Latchkey heals here
This workflow has steps that commonly fail on transient issues (network, registries, flaky browsers). On Latchkey managed runners they are detected, retried, and self-healed instead of failing your build:
- Dependency installs
This workflow runs 3 jobs per trigger. On Latchkey the same minutes cost up to 58% less than GitHub-hosted, with zero queue time.