mirror of
https://github.com/fleetdm/fleet
synced 2026-04-21 13:37:30 +00:00
Improve changed app detection in CI (#37838)
This pull request improves the robustness and reliability of the script and workflows that detect changed or new maintained apps in pull requests. The main focus is on making the detection script pass validation when the test is triggered but no new FMAs are detected. **Script robustness and error handling:** * The `.github/scripts/detect-new-fmas-in-pr.sh` script is updated to always exit successfully (status 0) when no changes are detected, and only exit with error (status 1) for critical failures like missing `jq`. A new `safe_exit` function is introduced to standardize output and ensure graceful exits. [[1]](diffhunk://#diff-f9bbb0340f504713c99d610f3c64bf281fc13ed3cb8a1c06a5366272c9828a8dR7-R11) [[2]](diffhunk://#diff-f9bbb0340f504713c99d610f3c64bf281fc13ed3cb8a1c06a5366272c9828a8dL21-R39) * Improved error handling for missing files, empty variables, and failed commands throughout the script, including handling cases where `merge-base`, `git show`, or `jq` fail, and ensuring empty or missing data does not cause the script to error out. [[1]](diffhunk://#diff-f9bbb0340f504713c99d610f3c64bf281fc13ed3cb8a1c06a5366272c9828a8dL32-R66) [[2]](diffhunk://#diff-f9bbb0340f504713c99d610f3c64bf281fc13ed3cb8a1c06a5366272c9828a8dR87-R108) [[3]](diffhunk://#diff-f9bbb0340f504713c99d610f3c64bf281fc13ed3cb8a1c06a5366272c9828a8dL75-R155) **Workflow improvements:** * The `test-fma-darwin-pr-only.yml` and `test-fma-windows-pr-only.yml` workflows are updated to default to "no changes" if the detection step fails or does not set the expected output, preventing false positives or workflow failures. [[1]](diffhunk://#diff-28b30c8601cb7662d59efbfbbcf800cae91455fd3d875627659dced8c1257a24L70-R72) [[2]](diffhunk://#diff-51641fd1d2cc19348b81fd8310b62ad270ca5082ceddff2d49064e78f126a1eaL76-R78)
This commit is contained in:
parent
db4255fe47
commit
b688fe3636
4 changed files with 79 additions and 26 deletions
89
.github/scripts/detect-new-fmas-in-pr.sh
vendored
89
.github/scripts/detect-new-fmas-in-pr.sh
vendored
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue