Skip to content

release

release #17

Workflow file for this run

name: release
on:
workflow_dispatch:
inputs:
version:
description: "Release version (e.g. 1.1). Leave empty to auto-increment."
required: false
permissions:
contents: write
jobs:
determine-version:
runs-on: ubuntu-latest
outputs:
version: ${{ steps.vars.outputs.version }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Determine version
id: vars
run: |
git fetch --tags
if [ -n "${{ github.event.inputs.version }}" ]; then
ver="${{ github.event.inputs.version }}"
else
latest=$(git tag --sort=-v:refname | head -n 1)
if [[ $latest =~ ^v?([0-9]+)\.([0-9]+)$ ]]; then
major=${BASH_REMATCH[1]}
minor=${BASH_REMATCH[2]}
ver="$major.$((minor+1))"
else
ver="1.0"
fi
fi
echo "version=$ver" >> $GITHUB_OUTPUT
shell: bash
build:
needs: determine-version
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- os: windows-latest
arch: x64
python-version: "3.12"
- os: windows-latest
arch: arm64
python-version: "3.12"
- os: ubuntu-latest
arch: x64
python-version: "3.12"
- os: ubuntu-24.04-arm
arch: arm64
python-version: "3.12"
- os: macos-15-intel
arch: x64
python-version: "3.12"
- os: macos-latest
arch: arm64
python-version: "3.12"
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Cache pip
uses: actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-${{ matrix.arch }}-pip-${{ hashFiles('**/requirements.txt') }}
restore-keys: |
${{ runner.os }}-${{ matrix.arch }}-pip-
- name: Setup ccache
if: runner.os != 'Windows'
uses: hendrikmuhs/ccache-action@v1.2
with:
key: ${{ runner.os }}-${{ matrix.arch }}-nuitka
max-size: 2G
save: true
restore: true
- name: Set MSVC env vars
if: runner.os == 'Windows'
run: |
echo "CL=/Zm500" >> $env:GITHUB_ENV
echo "MSYS_NO_PATHCONV=1" >> $env:GITHUB_ENV
shell: pwsh
- name: Linux deps (x64)
if: runner.os == 'Linux' && matrix.arch == 'x64'
run: |
sudo apt-get update
sudo apt-get install -y \
ccache libegl1 libopengl0 libgl1 libwayland-client0 libwayland-cursor0 \
libwayland-egl1 libxkbcommon0 libxkbcommon-x11-0 libxcb-cursor0 \
libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 \
libxcb-render-util0 libxcb-shape0 libxcb-xinerama0 libdbus-1-3 \
libpulse0 libxrender1 libxi6 libxrandr2 xvfb patchelf dpkg \
build-essential fakeroot rpm
- name: Linux deps (arm64)
if: runner.os == 'Linux' && matrix.arch == 'arm64'
run: |
sudo apt-get update
sudo apt-get install -y \
ccache libegl1 libopengl0 libgl1 libwayland-client0 libwayland-cursor0 \
libwayland-egl1 libxkbcommon0 libxkbcommon-x11-0 libxcb-cursor0 \
libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 \
libxcb-render-util0 libxcb-shape0 libxcb-xinerama0 libdbus-1-3 \
libpulse0 libxrender1 libxi6 libxrandr2 xvfb patchelf dpkg \
build-essential fakeroot rpm
- name: macOS deps
if: runner.os == 'macOS'
run: |
brew install create-dmg ccache
brew unlink openssl@3 || true
clang --version | head -1
ccache --version | head -1
- name: Configure ccache
if: runner.os != 'Windows'
run: |
chmod +x ./packaging/setup-ccache.sh ./packaging/show-ccache-stats.sh
./packaging/setup-ccache.sh
shell: bash
- name: Install Python deps
run: |
python -m pip install -U pip wheel setuptools
pip install -r requirements.txt
- name: Run tests
run: pytest -q
- name: Build with Nuitka
env:
APP_VERSION: ${{ needs.determine-version.outputs.version }}
run: python build.py
shell: bash
- name: Show ccache statistics
if: runner.os != 'Windows'
run: ./packaging/show-ccache-stats.sh
shell: bash
- name: Make executable (Linux)
if: runner.os == 'Linux'
run: chmod +x "dist/TranslatorHoi4/TranslatorHoi4"
- name: Smoke test (Windows)
if: runner.os == 'Windows'
shell: pwsh
run: '& "dist/TranslatorHoi4/TranslatorHoi4.exe" --smoke'
- name: Smoke test (Linux)
if: runner.os == 'Linux'
env:
CI: "true"
run: xvfb-run -a ./dist/TranslatorHoi4/TranslatorHoi4 --smoke
- name: Smoke test (macOS)
if: runner.os == 'macOS'
env:
CI: "true"
run: |
test -d "dist/TranslatorHoi4.app/Contents/MacOS"
test -f "dist/TranslatorHoi4.app/Contents/MacOS/TranslatorHoi4"
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: TranslatorHoi4-${{ runner.os }}-${{ matrix.arch }}
path: ${{ runner.os == 'macOS' && 'dist/TranslatorHoi4.app/' || 'dist/TranslatorHoi4/' }}
if-no-files-found: error
package-windows:
needs: [build, determine-version]
runs-on: windows-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Download Windows x64 artifact
uses: actions/download-artifact@v4
with:
name: TranslatorHoi4-Windows-x64
path: ./dist/TranslatorHoi4
- name: Create Windows x64 portable archive
shell: pwsh
run: Compress-Archive -Path ./dist/TranslatorHoi4/* -DestinationPath "dist/TranslatorHoi4_v${{ needs.determine-version.outputs.version }}_Windows_x64_Portable.zip" -Force
- name: Upload Windows x64 portable archive
uses: actions/upload-artifact@v4
with:
name: TranslatorHoi4_v${{ needs.determine-version.outputs.version }}_Windows_x64_Portable
path: dist/TranslatorHoi4_v${{ needs.determine-version.outputs.version }}_Windows_x64_Portable.zip
- name: Build Inno Setup installer (x64)
shell: pwsh
run: ./packaging/build-setup.ps1 -Version "${{ needs.determine-version.outputs.version }}" -Architecture "x64" -SourceDir "..\dist\TranslatorHoi4"
- name: Rename Inno Setup installer (x64)
shell: pwsh
run: |
$installer = Get-ChildItem -Path dist -Filter "TranslatorHoi4_Setup_*.exe" | Select-Object -First 1
if (-not $installer) { throw "Windows x64 setup installer not found" }
Move-Item -LiteralPath $installer.FullName -Destination "dist/TranslatorHoi4_v${{ needs.determine-version.outputs.version }}_Windows_x64_Setup.exe" -Force
- name: Upload Inno Setup installer
uses: actions/upload-artifact@v4
with:
name: TranslatorHoi4_v${{ needs.determine-version.outputs.version }}_Windows_x64_Setup
path: dist/TranslatorHoi4_v${{ needs.determine-version.outputs.version }}_Windows_x64_Setup.exe
- name: Download Windows arm64 artifact
if: always()
uses: actions/download-artifact@v4
with:
name: TranslatorHoi4-Windows-arm64
path: ./dist/TranslatorHoi4-arm64
- name: Create Windows arm64 portable archive
if: always()
shell: pwsh
run: Compress-Archive -Path ./dist/TranslatorHoi4-arm64/* -DestinationPath "dist/TranslatorHoi4_v${{ needs.determine-version.outputs.version }}_Windows_arm64_Portable.zip" -Force
- name: Upload Windows arm64 portable archive
if: always()
uses: actions/upload-artifact@v4
with:
name: TranslatorHoi4_v${{ needs.determine-version.outputs.version }}_Windows_arm64_Portable
path: dist/TranslatorHoi4_v${{ needs.determine-version.outputs.version }}_Windows_arm64_Portable.zip
- name: Build Inno Setup installer (arm64)
if: always()
shell: pwsh
run: ./packaging/build-setup.ps1 -Version "${{ needs.determine-version.outputs.version }}" -Architecture "arm64" -SourceDir "..\dist\TranslatorHoi4-arm64"
- name: Rename Inno Setup installer (arm64)
if: always()
shell: pwsh
run: |
$installer = Get-ChildItem -Path dist -Filter "TranslatorHoi4_Setup_arm64_*.exe" | Select-Object -First 1
if (-not $installer) { throw "Windows arm64 setup installer not found" }
Move-Item -LiteralPath $installer.FullName -Destination "dist/TranslatorHoi4_v${{ needs.determine-version.outputs.version }}_Windows_arm64_Setup.exe" -Force
- name: Upload Inno Setup installer (arm64)
if: always()
uses: actions/upload-artifact@v4
with:
name: TranslatorHoi4_v${{ needs.determine-version.outputs.version }}_Windows_arm64_Setup
path: dist/TranslatorHoi4_v${{ needs.determine-version.outputs.version }}_Windows_arm64_Setup.exe
package-linux:
needs: [build, determine-version]
runs-on: ${{ matrix.runs_on }}
strategy:
fail-fast: false
matrix:
include:
- arch: x64
runs_on: ubuntu-latest
artifact_name: TranslatorHoi4-Linux-x64
deb_glob: translatorhoi4_*_amd64.deb
rpm_glob: translatorhoi4-*.x86_64.rpm
appimage_tool: appimagetool-x86_64.AppImage
appimage_url: https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-x86_64.AppImage
appimage_glob: TranslatorHoi4-*-x86_64.AppImage
expected_binary_regex: "x86-64|x86_64"
- arch: arm64
runs_on: ubuntu-24.04-arm
artifact_name: TranslatorHoi4-Linux-arm64
deb_glob: translatorhoi4_*_arm64.deb
rpm_glob: translatorhoi4-*.aarch64.rpm
appimage_tool: appimagetool-aarch64.AppImage
appimage_url: https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-aarch64.AppImage
appimage_glob: TranslatorHoi4-*-aarch64.AppImage
expected_binary_regex: "ARM aarch64|aarch64"
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install packaging deps
run: |
sudo apt-get update
sudo apt-get install -y curl dpkg rpm fakeroot file
- name: Make packaging scripts executable
run: chmod +x ./packaging/create-appimage.sh ./packaging/create-deb.sh ./packaging/create-rpm.sh
shell: bash
- name: Download Linux artifact
uses: actions/download-artifact@v4
with:
name: ${{ matrix.artifact_name }}
path: ./dist/TranslatorHoi4
- name: Verify Linux binary architecture
run: |
file ./dist/TranslatorHoi4/TranslatorHoi4
file ./dist/TranslatorHoi4/TranslatorHoi4 | grep -Eq "${{ matrix.expected_binary_regex }}"
shell: bash
- name: Create Linux portable archive
run: tar -C ./dist -czf "TranslatorHoi4_v${{ needs.determine-version.outputs.version }}_Linux_${{ matrix.arch }}_Portable.tar.gz" TranslatorHoi4
shell: bash
- name: Upload Linux portable archive
uses: actions/upload-artifact@v4
with:
name: TranslatorHoi4_v${{ needs.determine-version.outputs.version }}_Linux_${{ matrix.arch }}_Portable
path: TranslatorHoi4_v${{ needs.determine-version.outputs.version }}_Linux_${{ matrix.arch }}_Portable.tar.gz
- name: Create .deb package
run: ./packaging/create-deb.sh ./dist/TranslatorHoi4 "${{ needs.determine-version.outputs.version }}" ${{ matrix.arch }}
shell: bash
- name: Rename .deb package
run: |
deb_file=$(ls ${{ matrix.deb_glob }} | head -n 1)
test -n "$deb_file"
mv "$deb_file" "TranslatorHoi4_v${{ needs.determine-version.outputs.version }}_Linux_${{ matrix.arch }}_DEB.deb"
shell: bash
- name: Upload .deb package
uses: actions/upload-artifact@v4
with:
name: TranslatorHoi4_v${{ needs.determine-version.outputs.version }}_Linux_${{ matrix.arch }}_DEB
path: TranslatorHoi4_v${{ needs.determine-version.outputs.version }}_Linux_${{ matrix.arch }}_DEB.deb
- name: Create .rpm package
run: ./packaging/create-rpm.sh ./dist/TranslatorHoi4 "${{ needs.determine-version.outputs.version }}" ${{ matrix.arch }}
shell: bash
- name: Rename .rpm package
run: |
rpm_file=$(ls ${{ matrix.rpm_glob }} | head -n 1)
test -n "$rpm_file"
mv "$rpm_file" "TranslatorHoi4_v${{ needs.determine-version.outputs.version }}_Linux_${{ matrix.arch }}_RPM.rpm"
shell: bash
- name: Upload .rpm package
uses: actions/upload-artifact@v4
with:
name: TranslatorHoi4_v${{ needs.determine-version.outputs.version }}_Linux_${{ matrix.arch }}_RPM
path: TranslatorHoi4_v${{ needs.determine-version.outputs.version }}_Linux_${{ matrix.arch }}_RPM.rpm
- name: Download appimagetool
run: |
curl -L -o ./${{ matrix.appimage_tool }} \
${{ matrix.appimage_url }}
chmod +x ./${{ matrix.appimage_tool }}
shell: bash
- name: Create AppImage
run: ./packaging/create-appimage.sh ./dist/TranslatorHoi4 "${{ needs.determine-version.outputs.version }}" ${{ matrix.arch }} ./${{ matrix.appimage_tool }}
shell: bash
- name: Rename AppImage
run: |
appimage_file=$(ls ${{ matrix.appimage_glob }} | head -n 1)
test -n "$appimage_file"
mv "$appimage_file" "TranslatorHoi4_v${{ needs.determine-version.outputs.version }}_Linux_${{ matrix.arch }}_AppImage.AppImage"
shell: bash
- name: Upload AppImage
uses: actions/upload-artifact@v4
with:
name: TranslatorHoi4_v${{ needs.determine-version.outputs.version }}_Linux_${{ matrix.arch }}_AppImage
path: TranslatorHoi4_v${{ needs.determine-version.outputs.version }}_Linux_${{ matrix.arch }}_AppImage.AppImage
package-macos:
needs: [build, determine-version]
runs-on: macos-latest
steps:
- name: Install create-dmg
run: brew install create-dmg
- name: Download macOS x64 artifact
uses: actions/download-artifact@v4
with:
name: TranslatorHoi4-macOS-x64
path: ./dist/TranslatorHoi4/TranslatorHoi4.app
- name: Create macOS x64 portable archive
run: ditto -c -k --sequesterRsrc --keepParent "dist/TranslatorHoi4/TranslatorHoi4.app" "TranslatorHoi4_v${{ needs.determine-version.outputs.version }}_macOS_x64_Portable.zip"
shell: bash
- name: Upload macOS x64 portable archive
uses: actions/upload-artifact@v4
with:
name: TranslatorHoi4_v${{ needs.determine-version.outputs.version }}_macOS_x64_Portable
path: TranslatorHoi4_v${{ needs.determine-version.outputs.version }}_macOS_x64_Portable.zip
- name: Create macOS x64 DMG
run: |
create-dmg \
--volname "TranslatorHoi4" \
--window-pos 200 120 \
--window-size 800 400 \
--icon-size 100 \
--icon "TranslatorHoi4.app" 200 190 \
--hide-extension "TranslatorHoi4.app" \
--app-drop-link 600 185 \
"TranslatorHoi4_v${{ needs.determine-version.outputs.version }}_macOS_x64_DMG.dmg" \
"dist/TranslatorHoi4/TranslatorHoi4.app"
shell: bash
- name: Upload macOS x64 DMG
uses: actions/upload-artifact@v4
with:
name: TranslatorHoi4_v${{ needs.determine-version.outputs.version }}_macOS_x64_DMG
path: TranslatorHoi4_v${{ needs.determine-version.outputs.version }}_macOS_x64_DMG.dmg
- name: Download macOS arm64 artifact
if: always()
uses: actions/download-artifact@v4
with:
name: TranslatorHoi4-macOS-arm64
path: ./dist/TranslatorHoi4-arm64/TranslatorHoi4.app
- name: Create macOS arm64 portable archive
if: always()
run: ditto -c -k --sequesterRsrc --keepParent "dist/TranslatorHoi4-arm64/TranslatorHoi4.app" "TranslatorHoi4_v${{ needs.determine-version.outputs.version }}_macOS_arm64_Portable.zip"
shell: bash
- name: Upload macOS arm64 portable archive
if: always()
uses: actions/upload-artifact@v4
with:
name: TranslatorHoi4_v${{ needs.determine-version.outputs.version }}_macOS_arm64_Portable
path: TranslatorHoi4_v${{ needs.determine-version.outputs.version }}_macOS_arm64_Portable.zip
- name: Create macOS arm64 DMG
if: always()
run: |
create-dmg \
--volname "TranslatorHoi4" \
--window-pos 200 120 \
--window-size 800 400 \
--icon-size 100 \
--icon "TranslatorHoi4.app" 200 190 \
--hide-extension "TranslatorHoi4.app" \
--app-drop-link 600 185 \
"TranslatorHoi4_v${{ needs.determine-version.outputs.version }}_macOS_arm64_DMG.dmg" \
"dist/TranslatorHoi4-arm64/TranslatorHoi4.app"
shell: bash
- name: Upload macOS arm64 DMG
if: always()
uses: actions/upload-artifact@v4
with:
name: TranslatorHoi4_v${{ needs.determine-version.outputs.version }}_macOS_arm64_DMG
path: TranslatorHoi4_v${{ needs.determine-version.outputs.version }}_macOS_arm64_DMG.dmg
release:
needs: [package-windows, package-linux, package-macos, determine-version]
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Download all packages
uses: actions/download-artifact@v4
with:
pattern: TranslatorHoi4_v${{ needs.determine-version.outputs.version }}_*
path: ./release
merge-multiple: true
- name: Generate changelog from commits
id: changelog
run: |
set -euo pipefail
LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
if [ -n "$LATEST_TAG" ]; then
RANGE="${LATEST_TAG}..HEAD"
INTRO="Changes since \`${LATEST_TAG}\`."
else
RANGE="HEAD"
INTRO="Initial release changelog."
fi
WORKDIR=$(mktemp -d)
trap 'rm -rf "$WORKDIR"' EXIT
declare -A SEEN=()
append_commit() {
local type="$1"
local scope="$2"
local subject="$3"
local hash="$4"
local file="$WORKDIR/changed.md"
case "$type" in
feat|feature)
file="$WORKDIR/added.md"
;;
fix|bugfix)
file="$WORKDIR/fixed.md"
;;
perf)
file="$WORKDIR/performance.md"
;;
docs)
file="$WORKDIR/docs.md"
;;
build|ci|chore|refactor|style|test)
file="$WORKDIR/maintenance.md"
;;
esac
subject=$(printf '%s' "$subject" | sed -E 's/[[:space:]]*\[(skip ci|ci skip)\][[:space:]]*$//I; s/^[[:space:]]+//; s/[[:space:]]+$//')
if [ -z "$subject" ]; then
return
fi
local key="${file}|${subject}"
if [ -n "${SEEN[$key]+x}" ]; then
return
fi
SEEN[$key]=1
if [ -n "$scope" ]; then
printf -- "- **%s:** %s (%s)\n" "$scope" "$subject" "$hash" >> "$file"
else
printf -- "- %s (%s)\n" "$subject" "$hash" >> "$file"
fi
}
while IFS=$'\t' read -r subject hash; do
[ -n "$subject" ] || continue
if [[ "$subject" =~ ^([A-Za-z]+)(\(([A-Za-z0-9_.-]+)\))?!?:[[:space:]]*(.+)$ ]]; then
type=$(printf '%s' "${BASH_REMATCH[1]}" | tr '[:upper:]' '[:lower:]')
scope="${BASH_REMATCH[3]:-}"
text="${BASH_REMATCH[4]}"
else
type="changed"
scope=""
text="$subject"
fi
append_commit "$type" "$scope" "$text" "$hash"
done < <(git log "$RANGE" --pretty=format:'%s%x09%h' --no-merges)
{
echo "$INTRO"
echo
section_written=0
for section in \
"Added|$WORKDIR/added.md" \
"Fixed|$WORKDIR/fixed.md" \
"Performance|$WORKDIR/performance.md" \
"Changed|$WORKDIR/changed.md" \
"Documentation|$WORKDIR/docs.md" \
"Build and CI|$WORKDIR/maintenance.md"; do
title="${section%%|*}"
file="${section#*|}"
if [ -s "$file" ]; then
echo "### $title"
cat "$file"
echo
section_written=1
fi
done
if [ "$section_written" -eq 0 ]; then
echo "No user-facing changes were found in commits for this release."
fi
} > "$WORKDIR/changelog.md"
{
echo "changelog<<CHANGELOG_EOF"
cat "$WORKDIR/changelog.md"
echo "CHANGELOG_EOF"
} >> "$GITHUB_OUTPUT"
shell: bash
- name: Create release
uses: softprops/action-gh-release@v2
with:
tag_name: v${{ needs.determine-version.outputs.version }}
name: v${{ needs.determine-version.outputs.version }}
body: |
## Downloads
Files are named as: `TranslatorHoi4_v<version>_<OS>_<architecture>_<type>.<extension>`.
- Windows: use `Setup.exe` for the installer, or `Portable.zip` to run without installation.
- Linux: use `AppImage` for a portable build, `DEB` for Debian/Ubuntu, or `RPM` for Fedora/RHEL.
- macOS: use `DMG.dmg` for the disk image, or `Portable.zip` for the app bundle archive.
## Changelog
${{ steps.changelog.outputs.changelog }}
files: release/*
token: ${{ secrets.GITHUB_TOKEN }}