From d13393cf7d291cb8d13422d3a5b2f5b0bafc65bc Mon Sep 17 00:00:00 2001 From: rainxchzed Date: Fri, 1 May 2026 06:45:38 +0500 Subject: [PATCH 1/2] Fail desktop installer uploads when no files match path Mirrors the existing if-no-files-found: error guard from the AppImage and Arch upload steps onto the Windows, macOS, and Linux deb/rpm uploads, so an empty gradle output now fails the matrix entry instead of silently warn-and-succeeding into an empty artifact that makes the release job's completeness guard fire much later. --- .github/workflows/build-desktop-platforms.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/build-desktop-platforms.yml b/.github/workflows/build-desktop-platforms.yml index c5901057..bf36e85a 100644 --- a/.github/workflows/build-desktop-platforms.yml +++ b/.github/workflows/build-desktop-platforms.yml @@ -68,6 +68,7 @@ jobs: path: | composeApp/build/compose/binaries/main/exe/*.exe composeApp/build/compose/binaries/main/msi/*.msi + if-no-files-found: error retention-days: 30 compression-level: 6 @@ -127,6 +128,7 @@ jobs: path: | composeApp/build/compose/binaries/main/dmg/*.dmg composeApp/build/compose/binaries/main/pkg/*.pkg + if-no-files-found: error retention-days: 30 compression-level: 6 @@ -296,6 +298,7 @@ jobs: path: | composeApp/build/compose/binaries/main/deb/*.deb composeApp/build/compose/binaries/main/rpm/*.rpm + if-no-files-found: error retention-days: 30 compression-level: 6 From caddb4073a0e82c2e41cb4da895477ed068b04a9 Mon Sep 17 00:00:00 2001 From: rainxchzed Date: Fri, 1 May 2026 06:58:39 +0500 Subject: [PATCH 2/2] Use find instead of shallow globs when staging release artifacts upload-artifact@v4 strips the longest common path prefix from matched files. For uploads spanning two sibling directories (Windows exe/msi, macOS dmg/pkg, Linux deb/rpm) the per-extension subdirectory survives inside the artifact, so files land under artifacts/windows-installers/ exe/.exe rather than artifacts/windows-installers/.exe. The previous shallow glob missed those nested files entirely and the completeness guard fired on every run despite all builds succeeding. Switching to find makes staging robust regardless of the artifact's internal layout. Also prints the downloaded artifact tree once at the top of the step so future layout drift is diagnosable from the run log. --- .github/workflows/build-desktop-platforms.yml | 53 +++++++++++-------- 1 file changed, 32 insertions(+), 21 deletions(-) diff --git a/.github/workflows/build-desktop-platforms.yml b/.github/workflows/build-desktop-platforms.yml index bf36e85a..d90ecbab 100644 --- a/.github/workflows/build-desktop-platforms.yml +++ b/.github/workflows/build-desktop-platforms.yml @@ -450,6 +450,16 @@ jobs: set -euo pipefail mkdir -p release-files + # Snapshot of what download-artifact@v4 actually produced — + # useful when build-output paths drift in the future. + # upload-artifact@v4 strips the longest common prefix, so paths + # like main/exe/*.exe + main/msi/*.msi land as exe/*.exe and + # msi/*.msi inside the artifact. Fixed shallow globs miss them; + # we use `find` below for resilience. + echo "=== Downloaded artifact tree ===" + find artifacts -maxdepth 4 -type f 2>/dev/null | sort + echo + # stage() returns 0 on a successful copy, 1 if the source is missing. # Callers use the exit status to increment per-group counters so the # completeness guard at the end can detect missing groups. @@ -473,53 +483,54 @@ jobs: linux_arch_count=0 # Windows — names already unique (.exe, .msi) - for f in artifacts/windows-installers/*.exe artifacts/windows-installers/*.msi; do - [ -f "$f" ] || continue + while IFS= read -r f; do + [ -n "$f" ] || continue stage "$f" "$(basename "$f")" && windows_count=$((windows_count + 1)) || true - done + done < <(find artifacts/windows-installers -type f \( -name '*.exe' -o -name '*.msi' \) 2>/dev/null) # macOS — disambiguate x64 vs arm64 (Compose outputs identical filenames per arch) - for f in artifacts/macos-installers-x64/*.dmg artifacts/macos-installers-x64/*.pkg; do - [ -f "$f" ] || continue + while IFS= read -r f; do + [ -n "$f" ] || continue base="$(basename "$f")" ext="${base##*.}" stem="${base%.*}" stage "$f" "${stem}-x64.${ext}" && macos_x64_count=$((macos_x64_count + 1)) || true - done - for f in artifacts/macos-installers-arm64/*.dmg artifacts/macos-installers-arm64/*.pkg; do - [ -f "$f" ] || continue + done < <(find artifacts/macos-installers-x64 -type f \( -name '*.dmg' -o -name '*.pkg' \) 2>/dev/null) + + while IFS= read -r f; do + [ -n "$f" ] || continue base="$(basename "$f")" ext="${base##*.}" stem="${base%.*}" stage "$f" "${stem}-arm64.${ext}" && macos_arm64_count=$((macos_arm64_count + 1)) || true - done + done < <(find artifacts/macos-installers-arm64 -type f \( -name '*.dmg' -o -name '*.pkg' \) 2>/dev/null) # Linux modern — default Debian/RPM (unprefixed) - for f in artifacts/linux-installers-modern/*.deb artifacts/linux-installers-modern/*.rpm; do - [ -f "$f" ] || continue + while IFS= read -r f; do + [ -n "$f" ] || continue stage "$f" "$(basename "$f")" && linux_modern_count=$((linux_modern_count + 1)) || true - done + done < <(find artifacts/linux-installers-modern -type f \( -name '*.deb' -o -name '*.rpm' \) 2>/dev/null) # Linux debian12-compat — suffix to avoid collision with modern - for f in artifacts/linux-installers-debian12-compat/*.deb artifacts/linux-installers-debian12-compat/*.rpm; do - [ -f "$f" ] || continue + while IFS= read -r f; do + [ -n "$f" ] || continue base="$(basename "$f")" ext="${base##*.}" stem="${base%.*}" stage "$f" "${stem}-debian12.${ext}" && linux_debian12_count=$((linux_debian12_count + 1)) || true - done + done < <(find artifacts/linux-installers-debian12-compat -type f \( -name '*.deb' -o -name '*.rpm' \) 2>/dev/null) # Linux AppImage + zsync (filenames already include -x86_64) - for f in artifacts/linux-appimage/*.AppImage artifacts/linux-appimage/*.AppImage.zsync; do - [ -f "$f" ] || continue + while IFS= read -r f; do + [ -n "$f" ] || continue stage "$f" "$(basename "$f")" && linux_appimage_count=$((linux_appimage_count + 1)) || true - done + done < <(find artifacts/linux-appimage -type f \( -name '*.AppImage' -o -name '*.AppImage.zsync' \) 2>/dev/null) # Linux Arch (.pkg.tar.zst already has version + arch in filename) - for f in artifacts/linux-arch/*.pkg.tar.zst; do - [ -f "$f" ] || continue + while IFS= read -r f; do + [ -n "$f" ] || continue stage "$f" "$(basename "$f")" && linux_arch_count=$((linux_arch_count + 1)) || true - done + done < <(find artifacts/linux-arch -type f -name '*.pkg.tar.zst' 2>/dev/null) echo echo "Final staged files:"