Skip to content

Commit 2d7f682

Browse files
committed
Implement cross-platform timeout handling and improve build artifact verification
- Added a cross-platform `run_with_timeout` function in `build.sh` to handle command timeouts on macOS and Linux, enhancing the reliability of executable tests. - Updated the backend executable tests to utilize the new timeout function, improving error handling for timeouts. - Enhanced the verification process for build artifacts in the GitHub Actions workflow to ensure either a DMG or app bundle is present, providing clearer error messages and improving build reliability. These changes improve the robustness of the build and testing processes across different platforms.
1 parent 3ff605e commit 2d7f682

File tree

2 files changed

+84
-38
lines changed

2 files changed

+84
-38
lines changed

.github/workflows/release.yml

Lines changed: 46 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -588,7 +588,7 @@ jobs:
588588
exit 1
589589
fi
590590
591-
# Check file size
591+
# Check file size (macOS uses different stat syntax)
592592
FILE_SIZE=$(stat -f%z "$BACKEND_EXE")
593593
FILE_SIZE_MB=$((FILE_SIZE / 1048576))
594594
echo "Backend executable size: $FILE_SIZE bytes (${FILE_SIZE_MB} MB)"
@@ -605,13 +605,17 @@ jobs:
605605
chmod +x "$BACKEND_EXE"
606606
fi
607607
608-
# Test executable with --help
608+
# Test executable with --help (use perl for timeout on macOS since timeout command doesn't exist)
609609
echo "Testing backend executable with --help..."
610-
if timeout 30 "$BACKEND_EXE" --help > /dev/null 2>&1; then
610+
if perl -e 'alarm 30; exec @ARGV' "$BACKEND_EXE" --help > /dev/null 2>&1; then
611611
echo "✓ Backend executable runs successfully"
612612
else
613613
EXIT_CODE=$?
614-
echo "::warning::Backend executable --help test failed (exit code: $EXIT_CODE)"
614+
if [ "$EXIT_CODE" -eq 142 ]; then
615+
echo "::warning::Backend executable timed out (30s) - may be hanging"
616+
else
617+
echo "::warning::Backend executable --help test returned exit code: $EXIT_CODE (non-critical)"
618+
fi
615619
fi
616620
617621
echo "✓ Backend executable verification completed"
@@ -686,21 +690,25 @@ jobs:
686690
run: |
687691
echo "=== Building Tauri application ==="
688692
689-
# Build app bundle first (most reliable on macOS)
690-
bunx tauri build --bundles app || {
691-
echo "::warning::App bundle build had issues"
693+
# Build both app bundle and DMG together
694+
# Note: DMG bundler may clean up the .app after creating DMG
695+
bunx tauri build --bundles app,dmg 2>&1 || {
696+
echo "::warning::Some bundle builds may have had issues"
692697
}
693698
694-
# Try to build DMG (may fail due to AppleScript permissions in CI)
695-
bunx tauri build --bundles dmg 2>&1 || {
696-
echo "::warning::DMG build failed (common in CI due to AppleScript permissions)"
697-
}
699+
# Check if either app bundle or DMG was created (DMG is the primary deliverable)
700+
BUNDLE_DIR="src-tauri/target/release/bundle"
701+
APP_BUNDLE="$BUNDLE_DIR/macos/Budget Planer.app"
702+
DMG_FILE=$(find "$BUNDLE_DIR" -name "*.dmg" 2>/dev/null | head -1)
698703
699-
# Check if app bundle was created
700-
if [ -d "src-tauri/target/release/bundle/macos/Budget Planer.app" ]; then
701-
echo "✓ App bundle created successfully"
704+
if [ -n "$DMG_FILE" ] && [ -f "$DMG_FILE" ]; then
705+
echo "✓ DMG created successfully: $DMG_FILE"
706+
elif [ -d "$APP_BUNDLE" ]; then
707+
echo "✓ App bundle created successfully (DMG creation may have failed)"
702708
else
703-
echo "::error::App bundle not found - build failed"
709+
echo "::error::Neither DMG nor app bundle found - build failed"
710+
echo "Contents of bundle directory:"
711+
find "$BUNDLE_DIR" -type f 2>/dev/null || echo "Bundle directory not found"
704712
exit 1
705713
fi
706714
@@ -728,23 +736,35 @@ jobs:
728736
echo ""
729737
echo "Bundle artifacts:"
730738
731-
# App bundle
732-
if [ -d "$BUNDLE_DIR/macos/Budget Planer.app" ]; then
733-
SIZE=$(du -sm "$BUNDLE_DIR/macos/Budget Planer.app" | cut -f1)
734-
echo "✓ App bundle: $BUNDLE_DIR/macos/Budget Planer.app (${SIZE} MB)"
735-
else
736-
echo "::error::App bundle not found"
737-
exit 1
738-
fi
739+
HAS_DISTRIBUTABLE=false
739740
740-
# DMG
741+
# DMG (primary distributable for macOS)
741742
DMG=$(find "$BUNDLE_DIR" -name "*.dmg" 2>/dev/null | head -1)
742743
if [ -n "$DMG" ] && [ -f "$DMG" ]; then
743744
SIZE=$(stat -f%z "$DMG")
744745
echo "✓ DMG: $DMG ($((SIZE / 1048576)) MB)"
746+
HAS_DISTRIBUTABLE=true
745747
else
746-
echo "⚠ DMG: not found (may have failed due to CI limitations)"
748+
echo "⚠ DMG: not found"
747749
fi
750+
751+
# App bundle (may be cleaned up after DMG creation)
752+
if [ -d "$BUNDLE_DIR/macos/Budget Planer.app" ]; then
753+
SIZE=$(du -sm "$BUNDLE_DIR/macos/Budget Planer.app" | cut -f1)
754+
echo "✓ App bundle: $BUNDLE_DIR/macos/Budget Planer.app (${SIZE} MB)"
755+
HAS_DISTRIBUTABLE=true
756+
else
757+
echo "⚠ App bundle: not found (may have been cleaned up after DMG creation)"
758+
fi
759+
760+
# Fail only if we have no distributable artifacts
761+
if [ "$HAS_DISTRIBUTABLE" = false ]; then
762+
echo "::error::No distributable artifacts found (neither DMG nor app bundle)"
763+
exit 1
764+
fi
765+
766+
echo ""
767+
echo "✓ macOS build verification passed"
748768
749769
- name: Upload macOS artifacts
750770
uses: actions/upload-artifact@v4
@@ -757,7 +777,7 @@ jobs:
757777
frontend/src-tauri/target/release/bundle/**/*.pkg
758778
frontend/src-tauri/resources/backend-server
759779
backend/dist/backend-server
760-
if-no-files-found: error
780+
if-no-files-found: warn
761781

762782
publish-release:
763783
name: Publish Release

build.sh

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,23 @@ command_exists() {
136136
command -v "$1" >/dev/null 2>&1
137137
}
138138

139+
# Cross-platform timeout function (macOS doesn't have timeout by default)
140+
run_with_timeout() {
141+
local timeout_seconds="$1"
142+
shift
143+
144+
if command_exists timeout; then
145+
# Linux - use timeout command
146+
timeout "$timeout_seconds" "$@"
147+
elif command_exists gtimeout; then
148+
# macOS with coreutils installed
149+
gtimeout "$timeout_seconds" "$@"
150+
else
151+
# Fallback: use perl for timeout (available on macOS)
152+
perl -e "alarm $timeout_seconds; exec @ARGV" "$@"
153+
fi
154+
}
155+
139156
# Function to get file size in human readable format
140157
get_file_size() {
141158
local file="$1"
@@ -198,11 +215,11 @@ test_backend_executable() {
198215

199216
# Test with --help flag
200217
print_info "Testing executable with --help flag..."
201-
if timeout 30 "$exe_path" --help > /dev/null 2>&1; then
218+
if run_with_timeout 30 "$exe_path" --help > /dev/null 2>&1; then
202219
print_success "Executable runs successfully with --help"
203220
else
204221
local exit_code=$?
205-
if [ "$exit_code" -eq 124 ]; then
222+
if [ "$exit_code" -eq 124 ] || [ "$exit_code" -eq 142 ]; then
206223
print_warning "Executable timed out (30s) - may be hanging or stuck"
207224
else
208225
print_warning "Executable --help test returned exit code: $exit_code"
@@ -212,7 +229,7 @@ test_backend_executable() {
212229

213230
# Try to get version/import test
214231
print_info "Testing Django import..."
215-
if timeout 30 "$exe_path" --port 0 2>&1 | head -5 | grep -qi "django\|server\|starting" 2>/dev/null; then
232+
if run_with_timeout 30 "$exe_path" --port 0 2>&1 | head -5 | grep -qi "django\|server\|starting" 2>/dev/null; then
216233
print_success "Django imports appear to work"
217234
else
218235
print_warning "Could not verify Django imports (may still work)"
@@ -345,22 +362,31 @@ verify_build_artifacts() {
345362
fi
346363

347364
elif [ "$PLATFORM" == "macos" ]; then
348-
# App bundle
365+
local has_distributable=false
366+
367+
# DMG (primary distributable for macOS)
368+
DMG_FILE=$(find "$BUNDLE_DIR" -name "*.dmg" 2>/dev/null | head -1)
369+
if [ -n "$DMG_FILE" ] && [ -f "$DMG_FILE" ]; then
370+
print_success "DMG: $(basename "$DMG_FILE") ($(get_file_size "$DMG_FILE"))"
371+
has_distributable=true
372+
else
373+
print_warning "DMG not found"
374+
fi
375+
376+
# App bundle (may be cleaned up after DMG creation)
349377
APP_BUNDLE=$(find "$BUNDLE_DIR" -name "*.app" -type d 2>/dev/null | head -1)
350378
if [ -n "$APP_BUNDLE" ] && [ -d "$APP_BUNDLE" ]; then
351379
local size=$(du -sh "$APP_BUNDLE" 2>/dev/null | cut -f1)
352380
print_success "App bundle: $(basename "$APP_BUNDLE") ($size)"
381+
has_distributable=true
353382
else
354-
print_error "App bundle not found"
355-
all_ok=false
383+
print_warning "App bundle not found (may have been cleaned up after DMG creation)"
356384
fi
357385

358-
# DMG
359-
DMG_FILE=$(find "$BUNDLE_DIR" -name "*.dmg" 2>/dev/null | head -1)
360-
if [ -n "$DMG_FILE" ] && [ -f "$DMG_FILE" ]; then
361-
print_success "DMG: $(basename "$DMG_FILE") ($(get_file_size "$DMG_FILE"))"
362-
else
363-
print_warning "DMG not found"
386+
# Fail only if no distributable exists
387+
if [ "$has_distributable" = false ]; then
388+
print_error "No distributable artifacts found (neither DMG nor app bundle)"
389+
all_ok=false
364390
fi
365391

366392
elif [ "$PLATFORM" == "windows" ]; then

0 commit comments

Comments
 (0)