Small fixes; Assets #24
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Build | |
| on: | |
| push: | |
| branches: | |
| - main | |
| tags: | |
| - "v*" | |
| pull_request: | |
| workflow_dispatch: | |
| inputs: | |
| tag: | |
| description: "Tag Name" | |
| required: false | |
| type: string | |
| prerelease: | |
| description: "Mark as pre-release." | |
| required: false | |
| type: boolean | |
| default: false | |
| permissions: | |
| contents: read | |
| env: | |
| JAVA_VERSION: "21" | |
| APP_NAME: Tritium | |
| MAIN_CLASS: io.github.footermandev.tritium.Main | |
| jobs: | |
| build: | |
| name: Build ${{ matrix.platform }}-${{ matrix.arch }} | |
| runs-on: ${{ matrix.runner }} | |
| permissions: | |
| contents: read | |
| continue-on-error: ${{ matrix.experimental }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - runner: ubuntu-24.04 | |
| platform: linux | |
| arch: x64 | |
| experimental: false | |
| - runner: ubuntu-24.04-arm | |
| platform: linux | |
| arch: arm64 | |
| experimental: false | |
| - runner: windows-2025 | |
| platform: windows | |
| arch: x64 | |
| experimental: false | |
| - runner: windows-11-arm | |
| platform: windows | |
| arch: arm64 | |
| experimental: true | |
| - runner: macos-15-intel | |
| platform: macos | |
| arch: x64 | |
| experimental: false | |
| - runner: macos-15 | |
| platform: macos | |
| arch: arm64 | |
| experimental: false | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Set Up Java | |
| uses: actions/setup-java@v4 | |
| with: | |
| distribution: temurin | |
| java-version: ${{ env.JAVA_VERSION }} | |
| - name: Set Up Gradle | |
| uses: gradle/actions/setup-gradle@v4 | |
| - name: Resolve App Version | |
| id: version | |
| shell: bash | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| DISPATCH_TAG: ${{ github.event.inputs.tag }} | |
| run: | | |
| set -euo pipefail | |
| raw="" | |
| if [[ "${GITHUB_REF:-}" == refs/tags/v* ]]; then | |
| raw="${GITHUB_REF#refs/tags/v}" | |
| fi | |
| if [[ -z "$raw" && "${GITHUB_EVENT_NAME:-}" == "workflow_dispatch" && -n "${DISPATCH_TAG:-}" ]]; then | |
| raw="${DISPATCH_TAG#v}" | |
| fi | |
| if [[ -z "$raw" ]]; then | |
| raw="$(sed -nE 's/^version[[:space:]]*=[[:space:]]*"([^"]+)".*/\1/p' build.gradle.kts | head -n1 || true)" | |
| fi | |
| cleaned="$(echo "$raw" | sed -E 's/[^0-9.]+/./g; s/\.+/./g; s/^\.//; s/\.$//')" | |
| if [[ -z "$cleaned" ]]; then | |
| cleaned="0.1" | |
| fi | |
| IFS='.' read -r -a parts <<< "$cleaned" | |
| major="${parts[0]:-0}" | |
| minor="${parts[1]:-0}" | |
| build_from_source="${parts[2]:-}" | |
| major_num="$((10#$major))" | |
| minor_num="$((10#$minor))" | |
| is_release_build=false | |
| if [[ "${GITHUB_REF:-}" == refs/tags/v* ]]; then | |
| is_release_build=true | |
| fi | |
| if [[ "${GITHUB_EVENT_NAME:-}" == "workflow_dispatch" && -n "${DISPATCH_TAG:-}" ]]; then | |
| is_release_build=true | |
| fi | |
| next_series_build() { | |
| local major_series="$1" | |
| local minor_series="$2" | |
| local page=1 | |
| local max_seen=0 | |
| while :; do | |
| local payload | |
| if ! payload="$(curl -fsSL \ | |
| -H "Authorization: Bearer $GH_TOKEN" \ | |
| -H "Accept: application/vnd.github+json" \ | |
| "https://api.github.com/repos/${GITHUB_REPOSITORY}/releases?per_page=100&page=${page}")"; then | |
| break | |
| fi | |
| local page_count | |
| page_count="$(echo "$payload" | sed -nE 's/^[[:space:]]*"tag_name":[[:space:]]*"([^"]+)".*/\1/p' | wc -l | tr -d '[:space:]')" | |
| while IFS= read -r tag; do | |
| if [[ "$tag" =~ ^v${major_series}\.${minor_series}\.([0-9]+)($|[^0-9].*) ]]; then | |
| local build_patch="${BASH_REMATCH[1]}" | |
| local build_patch_num="$((10#$build_patch))" | |
| if [[ "$build_patch_num" -gt "$max_seen" ]]; then | |
| max_seen="$build_patch_num" | |
| fi | |
| fi | |
| done < <(echo "$payload" | sed -nE 's/^[[:space:]]*"tag_name":[[:space:]]*"([^"]+)".*/\1/p') | |
| if [[ ! "$page_count" =~ ^[0-9]+$ || "$page_count" -lt 100 ]]; then | |
| break | |
| fi | |
| page=$((page + 1)) | |
| done | |
| echo "$((max_seen + 1))" | |
| } | |
| build_number="" | |
| if [[ "$is_release_build" == "true" ]]; then | |
| if [[ "$build_from_source" =~ ^[0-9]+$ ]]; then | |
| build_number="$((10#$build_from_source))" | |
| else | |
| build_number="$(next_series_build "$major_num" "$minor_num")" | |
| fi | |
| elif [[ "$build_from_source" =~ ^[0-9]+$ ]]; then | |
| build_number="$((10#$build_from_source))" | |
| else | |
| build_number="${GITHUB_RUN_NUMBER:-0}" | |
| fi | |
| build_num="$((10#$build_number))" | |
| app_version="${major_num}.${minor_num}.${build_num}" | |
| mac_major_num="$major_num" | |
| if [[ "$mac_major_num" -eq 0 ]]; then | |
| mac_major_num=1 | |
| fi | |
| mac_app_version="${mac_major_num}.${minor_num}.${build_num}" | |
| echo "app_version=$app_version" >> "$GITHUB_OUTPUT" | |
| echo "mac_app_version=$mac_app_version" >> "$GITHUB_OUTPUT" | |
| echo "Resolved app version: $app_version" | |
| echo "Resolved macOS package version: $mac_app_version" | |
| - name: Resolve Qt Version | |
| id: qtver | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| qt_version="$(sed -nE 's/^qt[[:space:]]*=[[:space:]]*"([^"]+)".*/\1/p' gradle/libs.versions.toml | head -n1 || true)" | |
| if [[ -z "$qt_version" ]]; then | |
| echo "Failed to resolve Qt version from gradle/libs.versions.toml" >&2 | |
| exit 1 | |
| fi | |
| echo "value=$qt_version" >> "$GITHUB_OUTPUT" | |
| echo "Resolved Qt version: $qt_version" | |
| - name: Build Shadow Jar (Windows) | |
| if: runner.os == 'Windows' | |
| shell: pwsh | |
| run: .\gradlew.bat --no-daemon clean shadowJar | |
| - name: Build Shadow Jar (Non-Windows) | |
| if: runner.os != 'Windows' | |
| run: ./gradlew --no-daemon clean shadowJar | |
| - name: Bundle Qt Libraries (Windows) | |
| if: runner.os == 'Windows' | |
| shell: pwsh | |
| env: | |
| QT_VERSION: ${{ steps.qtver.outputs.value }} | |
| run: | | |
| $ErrorActionPreference = "Stop" | |
| python -m pip install --upgrade pip | |
| python -m pip install --upgrade aqtinstall | |
| if ("${{ matrix.arch }}" -eq "arm64") { | |
| $qtHost = "windows_arm64" | |
| } else { | |
| $qtHost = "windows" | |
| } | |
| $archOutput = python -m aqt list-qt $qtHost desktop --arch $env:QT_VERSION | |
| $archs = $archOutput -split '\s+' | Where-Object { $_ -ne '' } | |
| if ("${{ matrix.arch }}" -eq "arm64") { | |
| $qtArch = $archs | Where-Object { $_ -match 'arm64' } | Select-Object -First 1 | |
| $qtPlatform = "windows-arm64" | |
| } else { | |
| $qtArch = $archs | Where-Object { $_ -match 'msvc' -and $_ -match '64' -and $_ -notmatch 'arm64' } | Select-Object -First 1 | |
| if (-not $qtArch) { | |
| $qtArch = $archs | Where-Object { $_ -match '64' -and $_ -notmatch 'arm64' } | Select-Object -First 1 | |
| } | |
| $qtPlatform = "windows-x64" | |
| } | |
| if (-not $qtArch) { | |
| throw "Unable to resolve Qt architecture for windows/${{ matrix.arch }}. Available: $($archs -join ', ')" | |
| } | |
| $modulesOutput = python -m aqt list-qt $qtHost desktop --modules $env:QT_VERSION $qtArch | |
| if ($modulesOutput -match '\bqtsvg\b') { | |
| Write-Host "Installing Qt with optional module qtsvg" | |
| python -m aqt install-qt $qtHost desktop $env:QT_VERSION $qtArch -m qtsvg -O "$PWD\\.qt" | |
| } else { | |
| Write-Host "qtsvg module not available for $qtHost/$qtArch on Qt $env:QT_VERSION; installing base Qt only" | |
| python -m aqt install-qt $qtHost desktop $env:QT_VERSION $qtArch -O "$PWD\\.qt" | |
| } | |
| $qtRoot = "$PWD\\.qt\\$env:QT_VERSION" | |
| $qtDir = Join-Path $qtRoot $qtArch | |
| $qtLibDir = Join-Path $qtDir "bin" | |
| if (-not (Test-Path $qtLibDir)) { | |
| $candidate = Get-ChildItem -Path $qtRoot -Directory -ErrorAction SilentlyContinue | | |
| Where-Object { Test-Path (Join-Path $_.FullName "bin") } | | |
| Select-Object -First 1 | |
| if ($candidate) { | |
| $qtDir = $candidate.FullName | |
| $qtLibDir = Join-Path $qtDir "bin" | |
| } | |
| } | |
| if (-not (Test-Path $qtLibDir)) { | |
| $dirs = Get-ChildItem -Path $qtRoot -Directory -ErrorAction SilentlyContinue | Select-Object -ExpandProperty FullName | |
| throw "Qt library path not found under $qtRoot (initial: $qtArch). Candidates: $($dirs -join ', ')" | |
| } | |
| Write-Host "Resolved Qt directory: $qtDir" | |
| $toolsDir = "$PWD\\.qtjambi-deployer" | |
| New-Item -ItemType Directory -Force $toolsDir | Out-Null | |
| $base = "https://repo1.maven.org/maven2/io/qtjambi" | |
| Invoke-WebRequest "$base/qtjambi/$env:QT_VERSION/qtjambi-$env:QT_VERSION.jar" -OutFile "$toolsDir\\qtjambi-$env:QT_VERSION.jar" | |
| Invoke-WebRequest "$base/qtjambi-deployer/$env:QT_VERSION/qtjambi-deployer-$env:QT_VERSION.jar" -OutFile "$toolsDir\\qtjambi-deployer-$env:QT_VERSION.jar" | |
| Invoke-WebRequest "$base/qtjambi-native-$qtPlatform/$env:QT_VERSION/qtjambi-native-$qtPlatform-$env:QT_VERSION.jar" -OutFile "$toolsDir\\qtjambi-native-$qtPlatform-$env:QT_VERSION.jar" | |
| $cp = "$toolsDir\\qtjambi-deployer-$env:QT_VERSION.jar;$toolsDir\\qtjambi-$env:QT_VERSION.jar;$toolsDir\\qtjambi-native-$qtPlatform-$env:QT_VERSION.jar" | |
| java "-Djava.library.path=$qtLibDir" -cp $cp io.qt.qtjambi.deployer.Main qt "--qtdir=$qtDir" "--platform=$qtPlatform" "--target-version=$env:QT_VERSION" -d "$PWD\\build\\libs" | |
| Get-ChildItem "$PWD\\build\\libs\\qt-lib-*.jar" | ForEach-Object { Write-Host "Bundled: $($_.Name)" } | |
| - name: Bundle Qt Libraries (Non-Windows) | |
| if: runner.os != 'Windows' | |
| shell: bash | |
| env: | |
| QT_VERSION: ${{ steps.qtver.outputs.value }} | |
| run: | | |
| set -euo pipefail | |
| python3 -m pip install --user --break-system-packages --upgrade pip aqtinstall | |
| if [[ "${{ matrix.platform }}" == "linux" ]]; then | |
| if [[ "${{ matrix.arch }}" == "arm64" ]]; then | |
| host="linux_arm64" | |
| else | |
| host="linux" | |
| fi | |
| qt_platform="linux-${{ matrix.arch }}" | |
| if [[ "${{ matrix.arch }}" == "x64" ]]; then | |
| arch_pattern='(linux_)?gcc_64' | |
| else | |
| arch_pattern='(arm64|aarch64)' | |
| fi | |
| else | |
| host="mac" | |
| qt_platform="macos" | |
| if [[ "${{ matrix.arch }}" == "x64" ]]; then | |
| arch_pattern='clang_64' | |
| else | |
| arch_pattern='(clang_arm64|arm64|clang_64)' | |
| fi | |
| fi | |
| if ! archs="$(python3 -m aqt list-qt "$host" desktop --arch "$QT_VERSION" | tr ' \r\t' '\n' | sed '/^$/d')"; then | |
| echo "Failed to query Qt architectures for host '$host'." >&2 | |
| exit 1 | |
| fi | |
| qt_arch="$(echo "$archs" | grep -E "$arch_pattern" | head -n1 || true)" | |
| if [[ -z "$qt_arch" ]]; then | |
| echo "Unable to resolve Qt architecture for $host/${{ matrix.arch }}." >&2 | |
| echo "$archs" >&2 | |
| exit 1 | |
| fi | |
| modules="$(python3 -m aqt list-qt "$host" desktop --modules "$QT_VERSION" "$qt_arch" | tr ' \r\t' '\n' | sed '/^$/d' || true)" | |
| if echo "$modules" | grep -qx "qtsvg"; then | |
| echo "Installing Qt with optional module qtsvg" | |
| python3 -m aqt install-qt "$host" desktop "$QT_VERSION" "$qt_arch" -m qtsvg -O "$PWD/.qt" | |
| else | |
| echo "qtsvg module not available for $host/$qt_arch on Qt $QT_VERSION; installing base Qt only" | |
| python3 -m aqt install-qt "$host" desktop "$QT_VERSION" "$qt_arch" -O "$PWD/.qt" | |
| fi | |
| qt_root="$PWD/.qt/$QT_VERSION" | |
| qt_dir="$qt_root/$qt_arch" | |
| if [[ ! -d "$qt_dir/lib" ]]; then | |
| qt_dir="$(find "$qt_root" -mindepth 1 -maxdepth 2 -type d | while read -r d; do [[ -d "$d/lib" ]] && { echo "$d"; break; }; done)" | |
| fi | |
| qt_lib_dir="$qt_dir/lib" | |
| if [[ ! -d "$qt_lib_dir" ]]; then | |
| echo "Qt library path not found under: $qt_root (initial: $qt_arch)" >&2 | |
| find "$qt_root" -maxdepth 3 -type d | sed 's/^/ /' >&2 || true | |
| exit 1 | |
| fi | |
| echo "Resolved Qt directory: $qt_dir" | |
| tools_dir="$PWD/.qtjambi-deployer" | |
| mkdir -p "$tools_dir" | |
| base="https://repo1.maven.org/maven2/io/qtjambi" | |
| curl -fsSL -o "$tools_dir/qtjambi-$QT_VERSION.jar" "$base/qtjambi/$QT_VERSION/qtjambi-$QT_VERSION.jar" | |
| curl -fsSL -o "$tools_dir/qtjambi-deployer-$QT_VERSION.jar" "$base/qtjambi-deployer/$QT_VERSION/qtjambi-deployer-$QT_VERSION.jar" | |
| curl -fsSL -o "$tools_dir/qtjambi-native-$qt_platform-$QT_VERSION.jar" "$base/qtjambi-native-$qt_platform/$QT_VERSION/qtjambi-native-$qt_platform-$QT_VERSION.jar" | |
| java -Djava.library.path="$qt_lib_dir" \ | |
| -cp "$tools_dir/qtjambi-deployer-$QT_VERSION.jar:$tools_dir/qtjambi-$QT_VERSION.jar:$tools_dir/qtjambi-native-$qt_platform-$QT_VERSION.jar" \ | |
| io.qt.qtjambi.deployer.Main qt \ | |
| --qtdir="$qt_dir" \ | |
| --platform="$qt_platform" \ | |
| --target-version="$QT_VERSION" \ | |
| -d "$PWD/build/libs" | |
| ls -1 build/libs/qt-lib-*.jar | |
| - name: Prepare Dist | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| mkdir -p dist | |
| - name: Package Windows Portable Bundle | |
| if: runner.os == 'Windows' | |
| shell: pwsh | |
| run: | | |
| New-Item -ItemType Directory -Force package | Out-Null | |
| jpackage ` | |
| --type app-image ` | |
| --name "${{ env.APP_NAME }}" ` | |
| --input build/libs ` | |
| --main-jar tritium.jar ` | |
| --main-class "${{ env.MAIN_CLASS }}" ` | |
| --app-version "${{ steps.version.outputs.app_version }}" ` | |
| --dest package | |
| $cfgFile = Get-ChildItem -Path "package" -Recurse -Filter "${{ env.APP_NAME }}.cfg" | Select-Object -First 1 | |
| if ($cfgFile) { | |
| $appDir = $cfgFile.DirectoryName | |
| $qtLibJars = Get-ChildItem -Path $appDir -Filter "qt-lib-*.jar" | Sort-Object Name | |
| if ($qtLibJars.Count -gt 0) { | |
| $classpath = '$APPDIR/tritium.jar' | |
| foreach ($jar in $qtLibJars) { | |
| $classpath += ';$APPDIR/' + $jar.Name | |
| } | |
| $lines = Get-Content $cfgFile.FullName | |
| $replaced = $false | |
| $newLines = foreach ($line in $lines) { | |
| if ($line -match '^app\.classpath=') { | |
| $replaced = $true | |
| "app.classpath=$classpath" | |
| } else { | |
| $line | |
| } | |
| } | |
| if (-not $replaced) { | |
| $newLines += "app.classpath=$classpath" | |
| } | |
| Set-Content -Path $cfgFile.FullName -Value $newLines -Encoding utf8 | |
| Write-Host "Updated launcher classpath in $($cfgFile.FullName)" | |
| } else { | |
| Write-Host "No qt-lib-*.jar files found in launcher app dir: $appDir" | |
| } | |
| } else { | |
| Write-Host "Launcher config file not found for classpath patching." | |
| } | |
| New-Item -ItemType Directory -Force "package/${{ env.APP_NAME }}/licenses" | Out-Null | |
| Copy-Item "LICENSE" "package/${{ env.APP_NAME }}/" | |
| Copy-Item "THIRD_PARTY_NOTICES.md" "package/${{ env.APP_NAME }}/" | |
| Copy-Item "third_party/licenses/*" "package/${{ env.APP_NAME }}/licenses/" | |
| Compress-Archive -Path "package/${{ env.APP_NAME }}/*" -DestinationPath "dist/tritium-${{ matrix.platform }}-${{ matrix.arch }}.zip" -Force | |
| - name: Package macOS Portable Bundle | |
| if: runner.os == 'macOS' | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| mkdir -p package | |
| jpackage \ | |
| --type app-image \ | |
| --name "${{ env.APP_NAME }}" \ | |
| --input build/libs \ | |
| --main-jar tritium.jar \ | |
| --main-class "${{ env.MAIN_CLASS }}" \ | |
| --app-version "${{ steps.version.outputs.mac_app_version }}" \ | |
| --dest package | |
| cfg_file="$(find package -type f -name "${{ env.APP_NAME }}.cfg" | head -n1 || true)" | |
| if [[ -n "$cfg_file" ]]; then | |
| app_dir="$(dirname "$cfg_file")" | |
| qt_lib_jars="$(find "$app_dir" -maxdepth 1 -type f -name 'qt-lib-*.jar' -exec basename {} \; | sort || true)" | |
| if [[ -n "$qt_lib_jars" ]]; then | |
| classpath="\$APPDIR/tritium.jar" | |
| while IFS= read -r jar; do | |
| [[ -z "$jar" ]] && continue | |
| classpath="${classpath}:\$APPDIR/${jar}" | |
| done <<< "$qt_lib_jars" | |
| awk -v cp="$classpath" 'BEGIN{r=0} /^app\.classpath=/{print "app.classpath=" cp; r=1; next} {print} END{if(!r) print "app.classpath=" cp}' "$cfg_file" > "${cfg_file}.tmp" | |
| mv "${cfg_file}.tmp" "$cfg_file" | |
| echo "Updated launcher classpath in $cfg_file" | |
| else | |
| echo "No qt-lib-*.jar files found in launcher app dir: $app_dir" | |
| fi | |
| else | |
| echo "Launcher config file not found for classpath patching." | |
| fi | |
| mkdir -p "package/${{ env.APP_NAME }}.app/Contents/Resources/licenses" | |
| cp LICENSE "package/${{ env.APP_NAME }}.app/Contents/Resources/" | |
| cp THIRD_PARTY_NOTICES.md "package/${{ env.APP_NAME }}.app/Contents/Resources/" | |
| cp third_party/licenses/* "package/${{ env.APP_NAME }}.app/Contents/Resources/licenses/" | |
| tar -C package -czf "dist/tritium-${{ matrix.platform }}-${{ matrix.arch }}.tar.gz" "${{ env.APP_NAME }}.app" | |
| - name: Package Linux Portable Bundles | |
| if: runner.os == 'Linux' | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| mkdir -p package | |
| jpackage \ | |
| --type app-image \ | |
| --name "${{ env.APP_NAME }}" \ | |
| --input build/libs \ | |
| --main-jar tritium.jar \ | |
| --main-class "${{ env.MAIN_CLASS }}" \ | |
| --app-version "${{ steps.version.outputs.app_version }}" \ | |
| --dest package | |
| cfg_file="$(find package -type f -name "${{ env.APP_NAME }}.cfg" | head -n1 || true)" | |
| if [[ -n "$cfg_file" ]]; then | |
| app_dir="$(dirname "$cfg_file")" | |
| qt_lib_jars="$(find "$app_dir" -maxdepth 1 -type f -name 'qt-lib-*.jar' -exec basename {} \; | sort || true)" | |
| if [[ -n "$qt_lib_jars" ]]; then | |
| classpath="\$APPDIR/tritium.jar" | |
| while IFS= read -r jar; do | |
| [[ -z "$jar" ]] && continue | |
| classpath="${classpath}:\$APPDIR/${jar}" | |
| done <<< "$qt_lib_jars" | |
| awk -v cp="$classpath" 'BEGIN{r=0} /^app\.classpath=/{print "app.classpath=" cp; r=1; next} {print} END{if(!r) print "app.classpath=" cp}' "$cfg_file" > "${cfg_file}.tmp" | |
| mv "${cfg_file}.tmp" "$cfg_file" | |
| echo "Updated launcher classpath in $cfg_file" | |
| else | |
| echo "No qt-lib-*.jar files found in launcher app dir: $app_dir" | |
| fi | |
| else | |
| echo "Launcher config file not found for classpath patching." | |
| fi | |
| mkdir -p "package/${{ env.APP_NAME }}/licenses" | |
| cp LICENSE "package/${{ env.APP_NAME }}/" | |
| cp THIRD_PARTY_NOTICES.md "package/${{ env.APP_NAME }}/" | |
| cp third_party/licenses/* "package/${{ env.APP_NAME }}/licenses/" | |
| tar -C package -czf "dist/tritium-${{ matrix.platform }}-${{ matrix.arch }}.tar.gz" "${{ env.APP_NAME }}" | |
| if [[ "${{ matrix.arch }}" == "arm64" ]]; then | |
| appimage_arch="aarch64" | |
| else | |
| appimage_arch="x86_64" | |
| fi | |
| if curl -fsSL -o appimagetool.AppImage \ | |
| "https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-${appimage_arch}.AppImage"; then | |
| chmod +x appimagetool.AppImage | |
| rm -rf AppDir | |
| mkdir -p AppDir | |
| cp -a "package/${{ env.APP_NAME }}/." AppDir/ | |
| printf '%s\n' \ | |
| '#!/bin/sh' \ | |
| 'HERE="$(dirname "$(readlink -f "$0")")"' \ | |
| 'exec "$HERE/bin/Tritium" "$@"' \ | |
| > AppDir/AppRun | |
| chmod +x AppDir/AppRun | |
| printf '%s\n' \ | |
| '[Desktop Entry]' \ | |
| 'Type=Application' \ | |
| 'Name=Tritium' \ | |
| 'Exec=Tritium' \ | |
| 'Icon=tritium' \ | |
| 'Categories=Development;' \ | |
| 'Terminal=false' \ | |
| > AppDir/Tritium.desktop | |
| cp src/main/resources/icons/tritium.png AppDir/tritium.png | |
| ln -sf tritium.png AppDir/.DirIcon | |
| ARCH="$appimage_arch" APPIMAGE_EXTRACT_AND_RUN=1 \ | |
| ./appimagetool.AppImage AppDir "dist/tritium-${{ matrix.platform }}-${{ matrix.arch }}.AppImage" | |
| chmod +x "dist/tritium-${{ matrix.platform }}-${{ matrix.arch }}.AppImage" | |
| else | |
| echo "AppImage tooling unavailable for $appimage_arch, skipping AppImage artifact." | |
| fi | |
| - name: Upload Artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: tritium-${{ matrix.platform }}-${{ matrix.arch }} | |
| path: dist/* | |
| if-no-files-found: error | |
| release: | |
| name: Publish Release | |
| runs-on: ubuntu-24.04 | |
| permissions: | |
| contents: write | |
| needs: build | |
| if: github.event_name != 'pull_request' | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Download Build Artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: release-assets | |
| merge-multiple: true | |
| - name: Generate Checksums | |
| run: | | |
| set -euo pipefail | |
| cd release-assets | |
| sha256sum * > SHA256SUMS.txt | |
| - name: Resolve Release Tag | |
| id: tag | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| raw="$(sed -nE 's/^version[[:space:]]*=[[:space:]]*"([^"]+)".*/\1/p' build.gradle.kts | head -n1 || true)" | |
| numeric="$(echo "$raw" | sed -E 's/[^0-9.]+/./g; s/\.+/./g; s/^\.//; s/\.$//')" | |
| if [[ -z "$numeric" ]]; then | |
| echo "Unable to resolve numeric version from build.gradle.kts version='$raw'" >&2 | |
| exit 1 | |
| fi | |
| IFS='.' read -r -a parts <<< "$numeric" | |
| major="${parts[0]:-0}" | |
| minor="${parts[1]:-0}" | |
| patch="${parts[2]:-0}" | |
| major_num="$((10#$major))" | |
| minor_num="$((10#$minor))" | |
| patch_num="$((10#$patch))" | |
| echo "name=v${major_num}.${minor_num}.${patch_num}" >> "$GITHUB_OUTPUT" | |
| - name: Create GitHub Release | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| tag_name: ${{ steps.tag.outputs.name }} | |
| target_commitish: ${{ github.sha }} | |
| name: Tritium ${{ steps.tag.outputs.name }} | |
| prerelease: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.prerelease == 'true' }} | |
| generate_release_notes: true | |
| files: | | |
| release-assets/* |