diff --git a/.github/scripts/detect-new-fmas-in-pr.sh b/.github/scripts/detect-new-fmas-in-pr.sh index bd68d02c7d..f6a592efb5 100755 --- a/.github/scripts/detect-new-fmas-in-pr.sh +++ b/.github/scripts/detect-new-fmas-in-pr.sh @@ -4,8 +4,11 @@ # This script compares the PR branch with the base branch to find: # 1. New apps added to apps.json # 2. Apps with changed manifest files +# +# This script always exits successfully (0) when no changes are detected. +# It only exits with error (1) for critical failures like missing jq. -set -euo pipefail +set -uo pipefail # Get repository root REPO_ROOT="${GITHUB_WORKSPACE:-$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)}" @@ -18,9 +21,22 @@ BASE_BRANCH="${GITHUB_BASE_REF:-main}" # Use origin/ prefix for remote branch reference BASE_BRANCH_REF="origin/${BASE_BRANCH}" -# Check if jq is available +# Ensure GITHUB_OUTPUT exists +GITHUB_OUTPUT="${GITHUB_OUTPUT:-${REPO_ROOT}/.github_output}" + +# Function to safely set outputs and exit +safe_exit() { + local has_changes="${1:-false}" + local changed_apps="${2:-[]}" + echo "CHANGED_APPS=${changed_apps}" >> "$GITHUB_OUTPUT" + echo "HAS_CHANGES=${has_changes}" >> "$GITHUB_OUTPUT" + exit 0 +} + +# Check if jq is available - this is a critical failure if ! command -v jq &> /dev/null; then echo "Error: jq is required but not installed" >&2 + safe_exit "false" "[]" exit 1 fi @@ -29,9 +45,9 @@ extract_slugs() { local apps_file="$1" if [ ! -f "$apps_file" ]; then echo "" - return + return 0 fi - jq -r '.apps[].slug' "$apps_file" | sort + jq -r '.apps[].slug' "$apps_file" 2>/dev/null | sort || echo "" } # Function to extract app slugs from changed manifest files @@ -39,7 +55,15 @@ extract_slugs_from_changed_manifests() { local changed_files="$1" local slugs=() + if [ -z "$changed_files" ]; then + echo "" + return 0 + fi + while IFS= read -r file; do + # Skip empty lines + [ -z "$file" ] && continue + # Extract slug from path like: outputs/app-name/darwin.json or outputs/app-name/windows.json if [[ "$file" =~ outputs/([^/]+)/(darwin|windows)\.json$ ]]; then app_name="${BASH_REMATCH[1]}" @@ -60,9 +84,28 @@ extract_slugs_from_changed_manifests() { # Get changed files in outputs directory echo "Detecting changed files in outputs directory..." echo "Comparing HEAD with ${BASE_BRANCH_REF}..." + # Use merge-base to find the common ancestor for comparison -MERGE_BASE=$(git merge-base "${BASE_BRANCH_REF}" HEAD 2>/dev/null || echo "${BASE_BRANCH_REF}") -CHANGED_FILES=$(git diff --name-only "$MERGE_BASE" HEAD -- "ee/maintained-apps/outputs/" 2>/dev/null || echo "") +# If merge-base fails, try using the base branch ref directly +MERGE_BASE="" +if git merge-base "${BASE_BRANCH_REF}" HEAD &>/dev/null; then + MERGE_BASE=$(git merge-base "${BASE_BRANCH_REF}" HEAD 2>/dev/null || echo "") +fi + +# If merge-base still failed, try the base branch ref directly +if [ -z "$MERGE_BASE" ]; then + echo "Warning: Could not find merge-base, using ${BASE_BRANCH_REF} directly" + MERGE_BASE="${BASE_BRANCH_REF}" +fi + +# Get changed files, handling errors gracefully +CHANGED_FILES="" +if git diff --name-only "$MERGE_BASE" HEAD -- "ee/maintained-apps/outputs/" &>/dev/null; then + CHANGED_FILES=$(git diff --name-only "$MERGE_BASE" HEAD -- "ee/maintained-apps/outputs/" 2>/dev/null || echo "") +else + echo "Warning: Could not get changed files, assuming no changes" + CHANGED_FILES="" +fi # Extract slugs from changed manifest files CHANGED_MANIFEST_SLUGS=$(extract_slugs_from_changed_manifests "$CHANGED_FILES") @@ -72,37 +115,43 @@ CURRENT_SLUGS=$(extract_slugs "$APPS_JSON") # Get base branch apps.json slugs echo "Fetching base branch apps.json from ${MERGE_BASE}..." -BASE_APPS_JSON=$(git show "${MERGE_BASE}:ee/maintained-apps/outputs/apps.json" 2>/dev/null || echo "") +BASE_APPS_JSON="" BASE_SLUGS="" -if [ -n "$BASE_APPS_JSON" ]; then - BASE_SLUGS=$(echo "$BASE_APPS_JSON" | jq -r '.apps[].slug' | sort) -else - echo "Warning: Could not find apps.json in base branch, treating all current apps as new" +if git show "${MERGE_BASE}:ee/maintained-apps/outputs/apps.json" &>/dev/null; then + BASE_APPS_JSON=$(git show "${MERGE_BASE}:ee/maintained-apps/outputs/apps.json" 2>/dev/null || echo "") + if [ -n "$BASE_APPS_JSON" ]; then + BASE_SLUGS=$(echo "$BASE_APPS_JSON" | jq -r '.apps[].slug' 2>/dev/null | sort || echo "") + fi fi -# Find new slugs in apps.json -NEW_SLUGS=$(comm -13 <(echo "$BASE_SLUGS" || echo "") <(echo "$CURRENT_SLUGS" || echo "") || echo "") +if [ -z "$BASE_SLUGS" ]; then + echo "Warning: Could not find apps.json in base branch, only checking manifest file changes" + # If we can't get base slugs, only use manifest changes (don't assume all apps are new) + NEW_SLUGS="" +else + # Find new slugs in apps.json + NEW_SLUGS=$(comm -13 <(echo "$BASE_SLUGS" || echo "") <(echo "$CURRENT_SLUGS" || echo "") 2>/dev/null || echo "") +fi # Combine all changed slugs (from manifest changes and new apps) -ALL_CHANGED_SLUGS=$(printf '%s\n' "$CHANGED_MANIFEST_SLUGS" "$NEW_SLUGS" | grep -v '^$' | sort -u) +ALL_CHANGED_SLUGS=$(printf '%s\n' "$CHANGED_MANIFEST_SLUGS" "$NEW_SLUGS" | grep -v '^$' | sort -u || echo "") -# Output results +# Output results - always exit successfully if [ -z "$ALL_CHANGED_SLUGS" ]; then echo "No changed apps detected." - echo "CHANGED_APPS=" >> "$GITHUB_OUTPUT" - echo "HAS_CHANGES=false" >> "$GITHUB_OUTPUT" - exit 0 + safe_exit "false" "[]" fi echo "Detected changed apps:" echo "$ALL_CHANGED_SLUGS" | while read -r slug; do - echo " - $slug" + [ -n "$slug" ] && echo " - $slug" done # Output as JSON array for GitHub Actions -CHANGED_APPS_JSON=$(echo "$ALL_CHANGED_SLUGS" | jq -R -s -c 'split("\n") | map(select(length > 0))') +CHANGED_APPS_JSON=$(echo "$ALL_CHANGED_SLUGS" | jq -R -s -c 'split("\n") | map(select(length > 0))' 2>/dev/null || echo "[]") echo "CHANGED_APPS=$CHANGED_APPS_JSON" >> "$GITHUB_OUTPUT" echo "HAS_CHANGES=true" >> "$GITHUB_OUTPUT" +exit 0 diff --git a/.github/workflows/test-fma-darwin-pr-only.yml b/.github/workflows/test-fma-darwin-pr-only.yml index 4f3145cb35..ee52b267f2 100644 --- a/.github/workflows/test-fma-darwin-pr-only.yml +++ b/.github/workflows/test-fma-darwin-pr-only.yml @@ -67,7 +67,9 @@ jobs: - name: Check if there are changes id: check-changes run: | - if [ "${{ steps.detect-changed.outputs.HAS_CHANGES }}" == "true" ]; then + # Default to no changes if detection step failed or didn't set output + HAS_CHANGES="${{ steps.detect-changed.outputs.HAS_CHANGES }}" + if [ "$HAS_CHANGES" == "true" ]; then echo "has_changes=true" >> $GITHUB_OUTPUT echo "Changed apps detected: ${{ steps.detect-changed.outputs.CHANGED_APPS }}" else diff --git a/.github/workflows/test-fma-windows-pr-only.yml b/.github/workflows/test-fma-windows-pr-only.yml index 15e54b24b2..34879bff7c 100644 --- a/.github/workflows/test-fma-windows-pr-only.yml +++ b/.github/workflows/test-fma-windows-pr-only.yml @@ -73,7 +73,9 @@ jobs: - name: Check if there are changes id: check-changes run: | - if ("${{ steps.detect-changed.outputs.HAS_CHANGES }}" -eq "true") { + # Default to no changes if detection step failed or didn't set output + $hasChanges = "${{ steps.detect-changed.outputs.HAS_CHANGES }}" + if ($hasChanges -eq "true") { "has_changes=true" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append Write-Host "Changed apps detected: ${{ steps.detect-changed.outputs.CHANGED_APPS }}" } else { diff --git a/ee/maintained-apps/outputs/rectangle/darwin.json b/ee/maintained-apps/outputs/rectangle/darwin.json index 9639221ba8..24e1c93f9b 100644 --- a/ee/maintained-apps/outputs/rectangle/darwin.json +++ b/ee/maintained-apps/outputs/rectangle/darwin.json @@ -1,14 +1,14 @@ { "versions": [ { - "version": "0.92", + "version": "0.93", "queries": { "exists": "SELECT 1 FROM apps WHERE bundle_identifier = 'com.knollsoft.Rectangle';" }, - "installer_url": "https://github.com/rxhanson/Rectangle/releases/download/v0.92/Rectangle0.92.dmg", + "installer_url": "https://github.com/rxhanson/Rectangle/releases/download/v0.93/Rectangle0.93.dmg", "install_script_ref": "9acc05e6", "uninstall_script_ref": "fd2d2084", - "sha256": "d18bf60eba0dbe4d94d7b539bf3ae17c472bf71015a55d22bc55480ef888d75b", + "sha256": "848817526f3f7bd41f73cce295582523ff7bb4746ed64723575659574f298a76", "default_categories": [ "Productivity" ] @@ -18,4 +18,4 @@ "9acc05e6": "#!/bin/sh\n\n# variables\nAPPDIR=\"/Applications/\"\nTMPDIR=$(dirname \"$(realpath $INSTALLER_PATH)\")\n# functions\n\nquit_application() {\n local bundle_id=\"$1\"\n local timeout_duration=10\n\n # check if the application is running\n if ! osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ $EUID -eq 0 && \"$console_user\" == \"root\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\n# extract contents\nMOUNT_POINT=$(mktemp -d /tmp/dmg_mount_XXXXXX)\nhdiutil attach -plist -nobrowse -readonly -mountpoint \"$MOUNT_POINT\" \"$INSTALLER_PATH\"\nsudo cp -R \"$MOUNT_POINT\"/* \"$TMPDIR\"\nhdiutil detach \"$MOUNT_POINT\"\n# copy to the applications folder\nquit_application 'com.knollsoft.Rectangle'\nif [ -d \"$APPDIR/Rectangle.app\" ]; then\n\tsudo mv \"$APPDIR/Rectangle.app\" \"$TMPDIR/Rectangle.app.bkp\"\nfi\nsudo cp -R \"$TMPDIR/Rectangle.app\" \"$APPDIR\"\n", "fd2d2084": "#!/bin/sh\n\n# variables\nAPPDIR=\"/Applications/\"\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\n\nquit_application() {\n local bundle_id=\"$1\"\n local timeout_duration=10\n\n # check if the application is running\n if ! osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ $EUID -eq 0 && \"$console_user\" == \"root\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\ntrash() {\n local logged_in_user=\"$1\"\n local target_file=\"$2\"\n local timestamp=\"$(date +%Y-%m-%d-%s)\"\n local rand=\"$(jot -r 1 0 99999)\"\n\n # replace ~ with /Users/$logged_in_user\n if [[ \"$target_file\" == ~* ]]; then\n target_file=\"/Users/$logged_in_user${target_file:1}\"\n fi\n\n local trash=\"/Users/$logged_in_user/.Trash\"\n local file_name=\"$(basename \"${target_file}\")\"\n\n if [[ -e \"$target_file\" ]]; then\n echo \"removing $target_file.\"\n mv -f \"$target_file\" \"$trash/${file_name}_${timestamp}_${rand}\"\n else\n echo \"$target_file doesn't exist.\"\n fi\n}\n\nquit_application 'com.knollsoft.Rectangle'\nsudo rm -rf \"$APPDIR/Rectangle.app\"\ntrash $LOGGED_IN_USER '~/Library/Application Scripts/com.knollsoft.RectangleLauncher'\ntrash $LOGGED_IN_USER '~/Library/Application Support/Rectangle'\ntrash $LOGGED_IN_USER '~/Library/Caches/com.knollsoft.Rectangle'\ntrash $LOGGED_IN_USER '~/Library/Containers/com.knollsoft.RectangleLauncher'\ntrash $LOGGED_IN_USER '~/Library/HTTPStorages/com.knollsoft.Rectangle'\ntrash $LOGGED_IN_USER '~/Library/Preferences/com.knollsoft.Rectangle.plist'\ntrash $LOGGED_IN_USER '~/Library/WebKit/com.knollsoft.Rectangle'\n" } -} +} \ No newline at end of file