From dd548db1ae714b555bf5f11901882489b58a5ad5 Mon Sep 17 00:00:00 2001 From: "Dan K. Snelson" <24623109+dan-snelson@users.noreply.github.com> Date: Tue, 18 Aug 2026 11:14:17 -0400 Subject: [PATCH 1/6] FR #14 (#15) * 1.2.0b1 Addresses FR #14; thanks for the suggestion, @jeffmw777) * 1.2.0b2 Updated 'codex' Validation Path --- CHANGELOG.md | 4 ++++ README.md | 5 ++++- SYM-Lite.zsh | 22 ++++++++++++++-------- 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3913b8c..b2b9a9b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ All notable changes to this project are documented in this file. +## 1.2.0b2 - 18-Aug-2026 +- Added `selectionDialogDefaultChecked` to configure default selection for interactive-mode items (while keeping already-installed items disabled and unchecked; thanks for FR #14, @jeffmw777!) +- Updated `codex` Validation Path + ## 1.1.0 - 04-Aug-2026 - Normalize surrounding straight and smart quotes in silent-mode CSV item IDs before lookup (thanks for the heads-up, @applegurutim!) - Clarify that Silent Mode Parameter 5 expects configured item identifiers, not Jamf command strings. diff --git a/README.md b/README.md index cb1cf63..6f30e65 100644 --- a/README.md +++ b/README.md @@ -155,12 +155,14 @@ sudo ~/Downloads/SYM-Lite.zsh ``` **User experience:** -1. Selection dialog appears with all configured items +1. Selection dialog appears with all configured items; selectable items start checked when `selectionDialogDefaultChecked="true"` 2. User selects one or more items using checkboxes 3. Inspect Mode dialog launches showing real-time progress 4. Completion report shows one row per selected item 5. Optional restart prompt +`selectionDialogDefaultChecked` affects interactive mode only. Users can deselect prechecked items before continuing, and already-installed items disabled by status sublabels remain unchecked. Silent mode continues to select items exclusively from `operationsCSV`. + If the user clicks `Cancel` in the selection dialog, interactive mode exits cleanly without launching Inspect Mode. If `selectionDialogStatusSublabelsEnabled="true"` and every remaining valid item is already installed, interactive mode shows an informational dialog and exits without launching Inspect Mode. If no valid items remain after configuration validation, interactive mode exits cleanly with a generic unavailable-items message. **Interactive mode requirements:** @@ -330,6 +332,7 @@ swiftDialog's [Inspect Mode](https://swiftdialog.app/advanced/inspect-mode/) use | `organizationOverlayiconURL` | swiftDialog logo | Overlay icon URL | | `mainDialogIcon` | GitHub raw `SYM_icon.png` URL | Main dialog icon | | `fontSize` | `"14"` | Dialog message font size | +| `selectionDialogDefaultChecked` | `"false"` | Start selectable interactive-mode items checked | | `selectionDialogStatusSublabelsEnabled` | `"true"` | Show install-state sublabels, disable already-installed items, and exit cleanly if no selectable items remain | | `restartPromptEnabled` | `"true"` | Show restart prompt after completion | | `scriptLog` | `/var/log/...log` | Client-side log path | diff --git a/SYM-Lite.zsh b/SYM-Lite.zsh index 887c88e..9462d24 100644 --- a/SYM-Lite.zsh +++ b/SYM-Lite.zsh @@ -16,11 +16,9 @@ # # HISTORY # -# Version 1.1.0, 04-Aug-2026, Dan K. Snelson (@dan-snelson) -# - Normalize surrounding straight and smart quotes in silent-mode CSV item IDs before lookup (thanks for the heads-up, @applegurutim!) -# - Clarify that Silent Mode Parameter 5 expects configured item identifiers, not Jamf command strings. -# - Fix silent-mode Parameter 5 parsing when Jamf passes multiple comma-separated item IDs wrapped in one quoted CSV string (thanks for another heads-up, @applegurutim!) -# - Updates for OpenAI renaming "Codex.app" to "ChatGPT.app" +# Version 1.2.0b2, 18-Aug-2026, Dan K. Snelson (@dan-snelson) +# - Added `selectionDialogDefaultChecked` to configure default selection for interactive-mode items (while keeping already-installed items disabled and unchecked; thanks for FR #14, @jeffmw777!) +# - Updated `codex` Validation Path # #################################################################################################### @@ -37,7 +35,7 @@ setopt NONOMATCH setopt TYPESET_SILENT # Script Version -scriptVersion="1.1.0" +scriptVersion="1.2.0b2" # Script Human-readable Name humanReadableScriptName="Setup Your Mac Lite: Developer Edition" @@ -105,6 +103,7 @@ mainDialogIcon="https://raw.githubusercontent.com/setup-your-mac/Setup-Your-Mac/ # Dialog presentation defaults fontSize="14" +selectionDialogDefaultChecked="true" selectionDialogStatusSublabelsEnabled="true" # Restart prompt behavior @@ -123,7 +122,7 @@ installomatorLabels=( "awsvpnclient | AWS VPN Client | /Applications/AWS VPN Client/AWS VPN Client.app | https://usw2.ics.services.jamfcloud.com/icon/hash_1d1bef5523d9f7eca5a45f2db9a63732e85edb5f914220807ca740ba7c4881b9" "bruno | Bruno | /Applications/Bruno.app | https://usw2.ics.services.jamfcloud.com/icon/hash_48501630ad2f5dd5de3e055d6acdda07682895440cad366ee7befac71cab1399" "charles | Charles Proxy | /Applications/Charles.app | https://use2.ics.services.jamfcloud.com/icon/hash_59b395ca81889a6d83deda8e6babc5ae4bc5931d36a72b738fe30b84d027593d" - "codex | OpenAI ChatGPT Codex | /Applications/ChatGPT.app | https://usw2.ics.services.jamfcloud.com/icon/hash_be9d2917e81980484f875d9056e5e4aa45d59dffa7b03c20f8dbb5137e96ee26" + "codex | OpenAI ChatGPT Codex | /Applications/ChatGPT.localized/ChatGPT.app | https://usw2.ics.services.jamfcloud.com/icon/hash_be9d2917e81980484f875d9056e5e4aa45d59dffa7b03c20f8dbb5137e96ee26" "docker | Docker | /Applications/Docker.app | https://usw2.ics.services.jamfcloud.com/icon/hash_a344dca5fdc0e86822e8f21ec91088e6591b1e292bdcebdee1281fbd794c2724" "jetbrainsintellijidea | IntelliJ IDEA | /Applications/IntelliJ IDEA.app | https://usw2.ics.services.jamfcloud.com/icon/hash_f669d73acc06297e1fc2f65245cfbdace03263f81aebf95444a8360a101b239d" "pique | Pique | /Applications/Pique.app | https://usw2.ics.services.jamfcloud.com/icon/hash_7d2539860cca6ec5ea5a71cba2aee7d93b9534e4267c16f73c7035f3dc025b9c" @@ -426,6 +425,7 @@ function getSelectionDialogCheckboxesJSON() { local checkboxLabel="" local escapedCheckboxLabel="" local escapedIconURL="" + local checkboxChecked="false" local checkboxDisabled="false" local itemID="" local existingLabel="" @@ -482,10 +482,16 @@ function getSelectionDialogCheckboxesJSON() { selectionDialogOptionRecords+=("${itemID}") fi + if [[ "${selectionDialogDefaultChecked:l}" == "true" ]] && [[ "${checkboxDisabled}" == "false" ]]; then + checkboxChecked="true" + else + checkboxChecked="false" + fi + escapedCheckboxLabel=$(escapeJSONString "${checkboxLabel}") escapedItemID=$(escapeJSONString "${itemID}") escapedIconURL=$(escapeJSONString "${itemIconURL}") - checkboxItemsJSON="${checkboxItemsJSON}${separator}{\"label\":\"${escapedCheckboxLabel}\",\"name\":\"${escapedItemID}\",\"checked\":false,\"disabled\":${checkboxDisabled},\"icon\":\"${escapedIconURL}\"}" + checkboxItemsJSON="${checkboxItemsJSON}${separator}{\"label\":\"${escapedCheckboxLabel}\",\"name\":\"${escapedItemID}\",\"checked\":${checkboxChecked},\"disabled\":${checkboxDisabled},\"icon\":\"${escapedIconURL}\"}" separator="," done From 74668f80bee7606269979b9e973adae73489c8ce Mon Sep 17 00:00:00 2001 From: "Dan K. Snelson" <24623109+dan-snelson@users.noreply.github.com> Date: Tue, 18 Aug 2026 11:24:38 -0400 Subject: [PATCH 2/6] 1.2.0b2 --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 6f30e65..a0a8c0e 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ ![GitHub release (latest by date)](https://img.shields.io/github/v/release/Setup-Your-Mac/SYM-Lite?display_name=tag) ![GitHub issues](https://img.shields.io/github/issues-raw/Setup-Your-Mac/SYM-Lite) ![GitHub closed issues](https://img.shields.io/github/issues-closed-raw/Setup-Your-Mac/SYM-Lite) ![GitHub pull requests](https://img.shields.io/github/issues-pr-raw/Setup-Your-Mac/SYM-Lite) ![GitHub closed pull requests](https://img.shields.io/github/issues-pr-closed-raw/Setup-Your-Mac/SYM-Lite) [![swiftDialog](https://img.shields.io/badge/swiftDialog-Enabled-blue)](https://swiftdialog.app) [![Semgrep Security Scan](https://img.shields.io/badge/security%20scanned%20by-Semgrep-00C7B7?style=flat&logo=semgrep&logoColor=white)](https://semgrep.dev) -# SYM-Lite (1.1.0) +# SYM-Lite (1.2.0b2) > **SYM-Lite** is a lean, purpose-built script for executing MDM-agnostic [Installomator labels](https://github.com/Installomator/Installomator/tree/main/fragments/labels) and [Homebrew](https://brew.sh) casks / formulas, as well as Jamf Pro-specific [policy triggers](https://learn.jamf.com/r/en-US/jamf-pro-documentation-current/Triggers_for_Policies), all through a unified [swiftDialog](https://swiftdialog.app) selection and reporting interface. @@ -332,7 +332,7 @@ swiftDialog's [Inspect Mode](https://swiftdialog.app/advanced/inspect-mode/) use | `organizationOverlayiconURL` | swiftDialog logo | Overlay icon URL | | `mainDialogIcon` | GitHub raw `SYM_icon.png` URL | Main dialog icon | | `fontSize` | `"14"` | Dialog message font size | -| `selectionDialogDefaultChecked` | `"false"` | Start selectable interactive-mode items checked | +| `selectionDialogDefaultChecked` | `"true"` | Start selectable interactive-mode items checked | | `selectionDialogStatusSublabelsEnabled` | `"true"` | Show install-state sublabels, disable already-installed items, and exit cleanly if no selectable items remain | | `restartPromptEnabled` | `"true"` | Show restart prompt after completion | | `scriptLog` | `/var/log/...log` | Client-side log path | @@ -341,6 +341,6 @@ swiftDialog's [Inspect Mode](https://swiftdialog.app/advanced/inspect-mode/) use (The rest of the document — Logging, Troubleshooting, Testing Checklist, Next Steps, and Support — remains unchanged as the reordering was already applied where relevant.) -**Version:** 1.1.0 -**Date:** 04-Aug-2026 +**Version:** 1.2.0b2 +**Date:** 18-Aug-2026 **Author:** Dan K. Snelson (@dan-snelson) From fa282e495e1d80389b66626e524659e5b2d60c68 Mon Sep 17 00:00:00 2001 From: "Dan K. Snelson" <24623109+dan-snelson@users.noreply.github.com> Date: Tue, 18 Aug 2026 12:17:34 -0400 Subject: [PATCH 3/6] 1.2.0b3 (#17) Addresses Bug Report #16 --- .github/workflows/security-scan.yml | 17 +++++++---- CHANGELOG.md | 3 +- README.md | 6 ++-- SYM-Lite.zsh | 44 +++++++++++++++++++++++++++-- 4 files changed, 59 insertions(+), 11 deletions(-) diff --git a/.github/workflows/security-scan.yml b/.github/workflows/security-scan.yml index ffc759a..137af1a 100644 --- a/.github/workflows/security-scan.yml +++ b/.github/workflows/security-scan.yml @@ -269,12 +269,18 @@ jobs: set -e echo "status=${status}" >> "${GITHUB_OUTPUT}" - - name: Finalize Zsh Syntax Result + - name: Run Zsh Regression Tests + id: zsh_tests + if: steps.zsh_syntax.outputs.status == '0' + run: zsh tests/installomator-label-parser.zsh + + - name: Finalize Zsh Validation Result if: success() || failure() shell: bash run: | target_count="${{ steps.collect_targets.outputs.count }}" syntax_status="${{ steps.zsh_syntax.outputs.status }}" + tests_outcome="${{ steps.zsh_tests.outcome }}" if [[ "${target_count}" == "0" ]]; then { @@ -286,19 +292,20 @@ jobs: fi { - echo "### Zsh Syntax" + echo "### Zsh Validation" echo echo "- Files scanned: ${target_count}" + echo "- Regression tests: ${tests_outcome}" } >> "${GITHUB_STEP_SUMMARY}" - if [[ "${syntax_status}" == "0" ]]; then + if [[ "${syntax_status}" == "0" && "${tests_outcome}" == "success" ]]; then echo "" >> "${GITHUB_STEP_SUMMARY}" - echo "✅ All zsh files passed \`zsh -n\`" >> "${GITHUB_STEP_SUMMARY}" + echo "✅ Zsh syntax and regression tests passed" >> "${GITHUB_STEP_SUMMARY}" exit 0 fi echo "" >> "${GITHUB_STEP_SUMMARY}" - echo "❌ zsh syntax errors found" >> "${GITHUB_STEP_SUMMARY}" + echo "❌ Zsh validation failed" >> "${GITHUB_STEP_SUMMARY}" exit 1 shellcheck: diff --git a/CHANGELOG.md b/CHANGELOG.md index b2b9a9b..68b90cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,8 @@ All notable changes to this project are documented in this file. -## 1.2.0b2 - 18-Aug-2026 +## 1.2.0b3 - 18-Aug-2026 +- Fixed validation of Installomator labels declared in multiline alias arms (Bug Report #16) - Added `selectionDialogDefaultChecked` to configure default selection for interactive-mode items (while keeping already-installed items disabled and unchecked; thanks for FR #14, @jeffmw777!) - Updated `codex` Validation Path diff --git a/README.md b/README.md index a0a8c0e..b7b583c 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ ![GitHub release (latest by date)](https://img.shields.io/github/v/release/Setup-Your-Mac/SYM-Lite?display_name=tag) ![GitHub issues](https://img.shields.io/github/issues-raw/Setup-Your-Mac/SYM-Lite) ![GitHub closed issues](https://img.shields.io/github/issues-closed-raw/Setup-Your-Mac/SYM-Lite) ![GitHub pull requests](https://img.shields.io/github/issues-pr-raw/Setup-Your-Mac/SYM-Lite) ![GitHub closed pull requests](https://img.shields.io/github/issues-pr-closed-raw/Setup-Your-Mac/SYM-Lite) [![swiftDialog](https://img.shields.io/badge/swiftDialog-Enabled-blue)](https://swiftdialog.app) [![Semgrep Security Scan](https://img.shields.io/badge/security%20scanned%20by-Semgrep-00C7B7?style=flat&logo=semgrep&logoColor=white)](https://semgrep.dev) -# SYM-Lite (1.2.0b2) +# SYM-Lite (1.2.0b3) > **SYM-Lite** is a lean, purpose-built script for executing MDM-agnostic [Installomator labels](https://github.com/Installomator/Installomator/tree/main/fragments/labels) and [Homebrew](https://brew.sh) casks / formulas, as well as Jamf Pro-specific [policy triggers](https://learn.jamf.com/r/en-US/jamf-pro-documentation-current/Triggers_for_Policies), all through a unified [swiftDialog](https://swiftdialog.app) selection and reporting interface. @@ -71,7 +71,7 @@ installomatorLabels=( ) ``` -At runtime, SYM-Lite validates each configured label against `organizationInstallomatorFile` before building the picker or accepting silent-mode CSV input. If a label is missing from that Installomator file, or if the Installomator file is unavailable or unreadable, SYM-Lite logs a warning or error and removes Installomator labels from the current run while leaving other item types available. +At runtime, SYM-Lite validates each configured label against single-line and continued top-level alias arms in `organizationInstallomatorFile` before building the picker or accepting silent-mode CSV input. If a label is missing from that Installomator file, or if the Installomator file is unavailable, unreadable, or cannot be parsed, SYM-Lite logs a warning or error and removes Installomator labels from the current run while leaving other item types available. ### Adding Homebrew Items @@ -341,6 +341,6 @@ swiftDialog's [Inspect Mode](https://swiftdialog.app/advanced/inspect-mode/) use (The rest of the document — Logging, Troubleshooting, Testing Checklist, Next Steps, and Support — remains unchanged as the reordering was already applied where relevant.) -**Version:** 1.2.0b2 +**Version:** 1.2.0b3 **Date:** 18-Aug-2026 **Author:** Dan K. Snelson (@dan-snelson) diff --git a/SYM-Lite.zsh b/SYM-Lite.zsh index 9462d24..033fb0c 100644 --- a/SYM-Lite.zsh +++ b/SYM-Lite.zsh @@ -16,7 +16,8 @@ # # HISTORY # -# Version 1.2.0b2, 18-Aug-2026, Dan K. Snelson (@dan-snelson) +# Version 1.2.0b3, 18-Aug-2026, Dan K. Snelson (@dan-snelson) +# - Fixed validation of Installomator labels declared in multiline alias arms (Bug Report #16) # - Added `selectionDialogDefaultChecked` to configure default selection for interactive-mode items (while keeping already-installed items disabled and unchecked; thanks for FR #14, @jeffmw777!) # - Updated `codex` Validation Path # @@ -35,7 +36,7 @@ setopt NONOMATCH setopt TYPESET_SILENT # Script Version -scriptVersion="1.2.0b2" +scriptVersion="1.2.0b3" # Script Human-readable Name humanReadableScriptName="Setup Your Mac Lite: Developer Edition" @@ -516,6 +517,7 @@ function getAvailableInstallomatorLabels() { BEGIN { inLabelCase = 0 caseDepth = 0 + continuedArm = "" } /^[[:space:]]*case[[:space:]]+\$label[[:space:]]+in[[:space:]]*$/ { @@ -525,6 +527,31 @@ function getAvailableInstallomatorLabels() { } inLabelCase { + if (continuedArm != "") { + if (caseDepth != 1) { + exit 2 + } + + if ($0 ~ /^[[:space:]]*[A-Za-z0-9_*][A-Za-z0-9_|-]*\|\\[[:space:]]*$/) { + labelFragment = $0 + sub(/^[[:space:]]*/, "", labelFragment) + sub(/\\[[:space:]]*$/, "", labelFragment) + continuedArm = continuedArm labelFragment + next + } + + if ($0 ~ /^[[:space:]]*[A-Za-z0-9_*][A-Za-z0-9_|-]*\)[[:space:]]*$/) { + labelFragment = $0 + sub(/^[[:space:]]*/, "", labelFragment) + sub(/\)[[:space:]]*$/, "", labelFragment) + print continuedArm labelFragment + continuedArm = "" + next + } + + exit 2 + } + if ($0 ~ /^[[:space:]]*case[[:space:]].*[[:space:]]+in[[:space:]]*$/) { caseDepth++ next @@ -538,6 +565,13 @@ function getAvailableInstallomatorLabels() { next } + if (caseDepth == 1 && $0 ~ /^[[:space:]]*[A-Za-z0-9_*][A-Za-z0-9_|-]*\|\\[[:space:]]*$/) { + continuedArm = $0 + sub(/^[[:space:]]*/, "", continuedArm) + sub(/\\[[:space:]]*$/, "", continuedArm) + next + } + if (caseDepth == 1 && $0 ~ /^[[:space:]]*[A-Za-z0-9_*][A-Za-z0-9_|-]*\)[[:space:]]*$/) { labelArm = $0 sub(/^[[:space:]]*/, "", labelArm) @@ -545,6 +579,12 @@ function getAvailableInstallomatorLabels() { print labelArm } } + + END { + if (continuedArm != "") { + exit 2 + } + } ' "${organizationInstallomatorFile}"); then return 1 fi From e040da04e08e98438bd2a1189d7031b83ac78b27 Mon Sep 17 00:00:00 2001 From: "Dan K. Snelson" <24623109+dan-snelson@users.noreply.github.com> Date: Wed, 19 Aug 2026 12:51:56 -0400 Subject: [PATCH 4/6] 1.2.0 --- CHANGELOG.md | 2 +- README.md | 6 +++--- SYM-Lite.zsh | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 68b90cb..66139fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ All notable changes to this project are documented in this file. -## 1.2.0b3 - 18-Aug-2026 +## 1.2.0 - 19-Aug-2026 - Fixed validation of Installomator labels declared in multiline alias arms (Bug Report #16) - Added `selectionDialogDefaultChecked` to configure default selection for interactive-mode items (while keeping already-installed items disabled and unchecked; thanks for FR #14, @jeffmw777!) - Updated `codex` Validation Path diff --git a/README.md b/README.md index b7b583c..f204620 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ ![GitHub release (latest by date)](https://img.shields.io/github/v/release/Setup-Your-Mac/SYM-Lite?display_name=tag) ![GitHub issues](https://img.shields.io/github/issues-raw/Setup-Your-Mac/SYM-Lite) ![GitHub closed issues](https://img.shields.io/github/issues-closed-raw/Setup-Your-Mac/SYM-Lite) ![GitHub pull requests](https://img.shields.io/github/issues-pr-raw/Setup-Your-Mac/SYM-Lite) ![GitHub closed pull requests](https://img.shields.io/github/issues-pr-closed-raw/Setup-Your-Mac/SYM-Lite) [![swiftDialog](https://img.shields.io/badge/swiftDialog-Enabled-blue)](https://swiftdialog.app) [![Semgrep Security Scan](https://img.shields.io/badge/security%20scanned%20by-Semgrep-00C7B7?style=flat&logo=semgrep&logoColor=white)](https://semgrep.dev) -# SYM-Lite (1.2.0b3) +# SYM-Lite (1.2.0) > **SYM-Lite** is a lean, purpose-built script for executing MDM-agnostic [Installomator labels](https://github.com/Installomator/Installomator/tree/main/fragments/labels) and [Homebrew](https://brew.sh) casks / formulas, as well as Jamf Pro-specific [policy triggers](https://learn.jamf.com/r/en-US/jamf-pro-documentation-current/Triggers_for_Policies), all through a unified [swiftDialog](https://swiftdialog.app) selection and reporting interface. @@ -341,6 +341,6 @@ swiftDialog's [Inspect Mode](https://swiftdialog.app/advanced/inspect-mode/) use (The rest of the document — Logging, Troubleshooting, Testing Checklist, Next Steps, and Support — remains unchanged as the reordering was already applied where relevant.) -**Version:** 1.2.0b3 -**Date:** 18-Aug-2026 +**Version:** 1.2.0 +**Date:** 19-Aug-2026 **Author:** Dan K. Snelson (@dan-snelson) diff --git a/SYM-Lite.zsh b/SYM-Lite.zsh index 033fb0c..c2a1ec3 100644 --- a/SYM-Lite.zsh +++ b/SYM-Lite.zsh @@ -16,7 +16,7 @@ # # HISTORY # -# Version 1.2.0b3, 18-Aug-2026, Dan K. Snelson (@dan-snelson) +# Version 1.2.0, 19-Aug-2026, Dan K. Snelson (@dan-snelson) # - Fixed validation of Installomator labels declared in multiline alias arms (Bug Report #16) # - Added `selectionDialogDefaultChecked` to configure default selection for interactive-mode items (while keeping already-installed items disabled and unchecked; thanks for FR #14, @jeffmw777!) # - Updated `codex` Validation Path @@ -36,7 +36,7 @@ setopt NONOMATCH setopt TYPESET_SILENT # Script Version -scriptVersion="1.2.0b3" +scriptVersion="1.2.0" # Script Human-readable Name humanReadableScriptName="Setup Your Mac Lite: Developer Edition" From c38bf4ea97e44346ba68096da44fbad57ff17a22 Mon Sep 17 00:00:00 2001 From: "Dan K. Snelson" <24623109+dan-snelson@users.noreply.github.com> Date: Wed, 19 Aug 2026 13:13:37 -0400 Subject: [PATCH 5/6] 1.2.0 Post-Copilot review of PR #18 --- .gitignore | 1 + README.md | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 0a1ee44..77d14e2 100644 --- a/.gitignore +++ b/.gitignore @@ -29,6 +29,7 @@ Icon? # Local deployment script (contains versioning logic) .deploy* +tests/ # Version tracking (local only) VERSION.txt diff --git a/README.md b/README.md index f204620..d8e614c 100644 --- a/README.md +++ b/README.md @@ -341,6 +341,6 @@ swiftDialog's [Inspect Mode](https://swiftdialog.app/advanced/inspect-mode/) use (The rest of the document — Logging, Troubleshooting, Testing Checklist, Next Steps, and Support — remains unchanged as the reordering was already applied where relevant.) -**Version:** 1.2.0 +**Version:** 1.2.0 **Date:** 19-Aug-2026 **Author:** Dan K. Snelson (@dan-snelson) From ea31d8e92ca551767c6c3559361f6b38516028a6 Mon Sep 17 00:00:00 2001 From: "Dan K. Snelson" <24623109+dan-snelson@users.noreply.github.com> Date: Wed, 19 Aug 2026 16:13:04 -0400 Subject: [PATCH 6/6] 1.2.0 Post-Copilot review of PR #18 --- .gitignore | 1 - tests/installomator-label-parser.zsh | 136 +++++++++++++++++++++++++++ 2 files changed, 136 insertions(+), 1 deletion(-) create mode 100644 tests/installomator-label-parser.zsh diff --git a/.gitignore b/.gitignore index 77d14e2..0a1ee44 100644 --- a/.gitignore +++ b/.gitignore @@ -29,7 +29,6 @@ Icon? # Local deployment script (contains versioning logic) .deploy* -tests/ # Version tracking (local only) VERSION.txt diff --git a/tests/installomator-label-parser.zsh b/tests/installomator-label-parser.zsh new file mode 100644 index 0000000..246b6fc --- /dev/null +++ b/tests/installomator-label-parser.zsh @@ -0,0 +1,136 @@ +#!/bin/zsh --no-rcs + +setopt ERR_EXIT +setopt NO_UNSET +setopt PIPE_FAIL + +repoRoot="${0:A:h:h}" +scriptPath="${repoRoot}/SYM-Lite.zsh" +temporaryDirectory="$(/usr/bin/mktemp -d "${TMPDIR:-/tmp}/sym-lite-parser-tests.XXXXXX")" +validFixture="${temporaryDirectory}/Installomator-valid.zsh" +incompleteFixture="${temporaryDirectory}/Installomator-incomplete.zsh" + +function cleanup() { + /bin/rm -rf -- "${temporaryDirectory}" +} +trap cleanup EXIT + +function fail() { + print -u2 -r -- "FAIL: $1" + exit 1 +} + +function extractFunction() { + local functionName="$1" + + /usr/bin/awk -v functionName="${functionName}" ' + $0 == "function " functionName "() {" { + capture = 1 + } + + capture { + print + } + + capture && /^}$/ { + exit + } + ' "${scriptPath}" +} + +function loadProductionFunction() { + local functionName="$1" + local functionSource="" + + functionSource="$(extractFunction "${functionName}")" + [[ -n "${functionSource}" ]] || fail "Unable to extract ${functionName} from SYM-Lite.zsh" + eval "${functionSource}" +} + +function assertOutputContains() { + local output="$1" + local expected="$2" + + print -r -- "${output}" | /usr/bin/grep -Fqx -- "${expected}" \ + || fail "Expected parsed label '${expected}'" +} + +function assertOutputExcludes() { + local output="$1" + local unexpected="$2" + + if print -r -- "${output}" | /usr/bin/grep -Fqx -- "${unexpected}"; then + fail "Unexpected parsed label '${unexpected}'" + fi +} + +loadProductionFunction "parseInstallomatorItem" +loadProductionFunction "getAvailableInstallomatorLabels" +loadProductionFunction "normalizeInstallomatorLabels" + +function preFlight() { :; } +function warning() { :; } +function errorOut() { :; } + +/bin/cat > "${validFixture}" <<'FIXTURE' +case $label in + singlelabel|singlealias) + ;; + multilinefirst|\ + multilinesecond|\ + multilinethird) + ;; + parentlabel) + case "${nestedValue}" in + nestedalias) + ;; + esac + ;; + longversion) + ;; + valuesfromarguments) + ;; + *) + ;; +esac +FIXTURE +/bin/chmod +x "${validFixture}" + +organizationInstallomatorFile="${validFixture}" +parsedLabels="$(getAvailableInstallomatorLabels)" \ + || fail "Valid fixture returned a parse failure" + +assertOutputContains "${parsedLabels}" "singlelabel" +assertOutputContains "${parsedLabels}" "singlealias" +assertOutputContains "${parsedLabels}" "multilinefirst" +assertOutputContains "${parsedLabels}" "multilinesecond" +assertOutputContains "${parsedLabels}" "multilinethird" +assertOutputContains "${parsedLabels}" "parentlabel" +assertOutputExcludes "${parsedLabels}" "nestedalias" +assertOutputExcludes "${parsedLabels}" "longversion" +assertOutputExcludes "${parsedLabels}" "valuesfromarguments" +assertOutputExcludes "${parsedLabels}" "*" + +configuredInstallomatorLabels=( + "multilinefirst | Multiline Label | /Applications/Multiline.app | https://example.invalid/icon.png" +) +installomatorLabels=("${configuredInstallomatorLabels[@]}") +normalizeInstallomatorLabels + +[[ ${#installomatorLabels[@]} -eq 1 ]] \ + || fail "Normalization removed a configured multiline alias" +[[ "${installomatorLabels[1]}" == "${configuredInstallomatorLabels[1]}" ]] \ + || fail "Normalization changed the configured multiline alias" + +/bin/cat > "${incompleteFixture}" <<'FIXTURE' +case $label in + incompletealias|\ +FIXTURE +/bin/chmod +x "${incompleteFixture}" + +organizationInstallomatorFile="${incompleteFixture}" +if getAvailableInstallomatorLabels >/dev/null 2>&1; then + fail "Incomplete continuation arm did not return a parse failure" +fi + +print -r -- "PASS: Installomator label parser regression tests" \ No newline at end of file