Skip to content

Add Rtools as a Windows FMA - #50028

Merged
allenhouchins merged 3 commits into
mainfrom
add-rtools-windows-fma
Jul 29, 2026
Merged

Add Rtools as a Windows FMA#50028
allenhouchins merged 3 commits into
mainfrom
add-rtools-windows-fma

Conversation

@kitzy

@kitzy kitzy commented Jul 28, 2026

Copy link
Copy Markdown
Member

Related issue: #50020

What this does

Adds Rtools as a Windows Fleet-maintained app. One of the 11 apps split out of #48501 that failed the FMA validator; #50016 shipped the 6 that passed.

Why it was failing

The install script hit the validator's 10-minute executeScript cap exactly:

20:41:22  INFO  msg="Executing install script..." app=Rtools
20:51:22  ERROR msg="Error executing install script: exit status 1"   # exactly 10:00 later
20:51:22  WARN  msg="failed to remove rtools45-6768-6492.exe: ... Access is denied."

The locked installer in the temp dir shows a process was still alive. Start-Process -Wait waits for the process and all of its descendants, which is the same root cause as the other install-timeout apps in this batch.

Rtools is also the one app in the batch where a slow unpack is a plausible second cause — the installer is ~460 MB and expands a full toolchain. So rather than assume, the script now waits on the installer process alone with a 480s cap (under the caller's 10-minute budget) and logs elapsed time plus Add/Remove Programs registration state on every poll. If the cap is reached:

  • registered → the install finished and only a lingering child remains, so it stops that process and succeeds;
  • not registered → the unpack genuinely didn't finish, and it fails with that stated explicitly.

Either way the CI log now says which one happened instead of just timing out.

Notes

  • Identity verified against the installer, not winget metadata. The setup stub's PE version resource reads CompanyName: The R Foundation, ProductName: Rtools. Inno derives VersionInfoCompany from AppPublisher, so the ARP publisher is The R Foundation — which is what the exists query uses.
  • Versioned ARP name. The registry DisplayName is Rtools 4.5 (6768-6492), so the input uses fuzzy_match_name and the exists query is name LIKE 'Rtools %'.
  • Installs to C:\rtools45, not Program Files, so the validator's "no changes detected in C:\Program Files" line is an expected warning, not a failure.
  • Ships a new catalog icon and website asset.

Checklist for submitter

  • Input data is properly validated, SELECT * is avoided, SQL injection is prevented (using placeholders for values in statements), JS inline code is prevented especially for url redirects, and untrusted data interpolated into shell scripts/commands is validated against shell metacharacters.
  • Timeouts are implemented and retries are limited to avoid infinite loops

Testing

  • FMA CI validator (install → detect → uninstall) passes on the SYSTEM-context Windows runner — run 30384196159 (All checks passed)
  • Generated output verified locally: manifest SHA matches the winget manifest, exists/patched queries checked against the installer's PE version resource, apps.json is valid JSON with a description filled in.
  • QA'd all new/changed functionality manually

Summary by CodeRabbit

  • New Features
    • Added Rtools as a supported Windows application.
    • Added installation and uninstallation support with silent setup and silent removal.
    • Added Rtools version metadata, installer verification, and Developer tools categorization.
    • Added a dedicated Rtools icon for software listings.

Start-Process -Wait waits for descendants as well as the process itself, so the
install script never returned and the validator killed it at its 10-minute cap.
Wait on the installer process alone, with a cap under that budget, and log
progress plus registration state each poll so a slow unpack (a ~460 MB toolchain)
is distinguishable from a stuck process.
Copilot AI review requested due to automatic review settings July 28, 2026 00:13
@codecov

codecov Bot commented Jul 28, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 50.00000% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 68.03%. Comparing base (b64fdaa) to head (5bca429).
⚠️ Report is 32 commits behind head on main.

Files with missing lines Patch % Lines
...end/pages/SoftwarePage/components/icons/Rtools.tsx 50.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #50028      +/-   ##
==========================================
+ Coverage   67.97%   68.03%   +0.06%     
==========================================
  Files        3922     3930       +8     
  Lines      250032   250268     +236     
  Branches    13334    13270      -64     
==========================================
+ Hits       169949   170273     +324     
+ Misses      64781    64691      -90     
- Partials    15302    15304       +2     
Flag Coverage Δ
frontend 60.88% <50.00%> (+0.47%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds Rtools as a Windows Fleet-maintained app (FMA), including the winget input + generated output manifest, plus a new Software page catalog icon and icon mapping entry.

Changes:

  • Add Rtools winget input + install/uninstall PowerShell scripts.
  • Add generated Windows output manifest and register the app in apps.json.
  • Add Rtools catalog icon component and hook it into the software icon map.

Reviewed changes

Copilot reviewed 7 out of 8 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
frontend/pages/SoftwarePage/components/icons/Rtools.tsx Adds a new Rtools software catalog icon component.
frontend/pages/SoftwarePage/components/icons/index.ts Registers the new icon in the icon map.
ee/maintained-apps/outputs/rtools/windows.json Adds the generated Windows manifest for the Rtools maintained app.
ee/maintained-apps/outputs/apps.json Registers Rtools in the maintained apps catalog output list.
ee/maintained-apps/inputs/winget/scripts/rtools_uninstall.ps1 Adds an uninstall script for Rtools.
ee/maintained-apps/inputs/winget/scripts/rtools_install.ps1 Adds an install script with bounded wait + registration polling.
ee/maintained-apps/inputs/winget/rtools.json Adds the winget input definition for the Rtools Windows app.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +34 to +58
$elapsed = 0
while (-not $process.HasExited -and ($elapsed -lt $installTimeoutSeconds)) {
Start-Sleep -Seconds $pollSeconds
$elapsed += $pollSeconds
Write-Host "Installing... ($elapsed seconds, registered: $(Test-RtoolsRegistered))"
}

if (-not $process.HasExited) {
# The installer is still running at the cap. If Rtools has already registered
# in Add/Remove Programs the install itself finished and what is left is a
# lingering child, so stopping it is safe; otherwise the unpack genuinely did
# not finish in time and this is a real failure.
if (Test-RtoolsRegistered) {
Write-Host "Installer still running after ${installTimeoutSeconds}s but Rtools is registered; stopping the lingering process."
Stop-Process -Id $process.Id -Force -ErrorAction SilentlyContinue
Start-Sleep -Seconds 2
Exit 0
}

Write-Host "Installer did not finish within ${installTimeoutSeconds}s and Rtools is not registered."
Stop-Process -Id $process.Id -Force -ErrorAction SilentlyContinue
Exit 1
}

$exitCode = $process.ExitCode

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch — fixed. After the parent exits, registration now gets a bounded 90s settle window instead of a single check, so a descendant still finishing the unpack can't produce a false failure.

That hand-off is exactly the behavior that makes Start-Process -Wait hang here, so it's a fair thing to expect on the exit path too. run 30372960989 passes.

Comment thread ee/maintained-apps/inputs/winget/scripts/rtools_uninstall.ps1 Outdated
…tion

Addresses Copilot's review: Get-ItemProperty lacked -ErrorAction SilentlyContinue,
so one unreadable registry key could abort the scan; and the install checked
registration exactly once after the parent exited, which can lose the race when a
descendant is still finishing the unpack -- the same hand-off that makes -Wait
block. Registration now gets a bounded 90s settle window.

Uninstall also requires the publisher, verified as 'The R Foundation' from the
setup stub's PE version resource (Inno derives CompanyName from AppPublisher).
That puts the exists-query value under test, since appExists matches on name only.
Exit 0 when no entry is found, per repo convention.
Copilot AI review requested due to automatic review settings July 28, 2026 15:21
@github-actions

Copy link
Copy Markdown
Contributor

Script Diff Results

ee/maintained-apps/outputs/rtools/windows.json

=== Install // 92962266 -> 4679c4f2 ===

--- /tmp/old.R1TaBx	2026-07-28 15:23:02.856671427 +0000
+++ /tmp/new.RV7VWR	2026-07-28 15:23:02.856671427 +0000
@@ -58,6 +58,16 @@
 $exitCode = $process.ExitCode
 Write-Host "Install exit code: $exitCode"
 
+# The parent can exit while a descendant is still finishing the unpack and writing
+# the ARP entry -- the same hand-off that makes -Wait block. Give registration a
+# bounded window to appear rather than checking once.
+$settle = 0
+while (-not (Test-RtoolsRegistered) -and ($settle -lt 90)) {
+  Start-Sleep -Seconds $pollSeconds
+  $settle += $pollSeconds
+  Write-Host "Waiting for Rtools to register... ($settle seconds)"
+}
+
 if (-not (Test-RtoolsRegistered)) {
   Write-Host "Rtools did not register in Add/Remove Programs."
   Exit 1

=== Uninstall // a289eb1d -> d5432a7e ===

--- /tmp/old.K14cEa	2026-07-28 15:23:02.880671602 +0000
+++ /tmp/new.z2qwxl	2026-07-28 15:23:02.880671602 +0000
@@ -1,5 +1,13 @@
+# The registry DisplayName carries a version and build ("Rtools 4.5 (6768-6492)"),
+# so match on a prefix. Require the publisher too, mirroring the manifest's exists
+# query. Verified as "The R Foundation" against the setup stub's PE version
+# resource (CompanyName, which Inno derives from AppPublisher). Requiring it here
+# puts the value under test -- the validator's appExists looks up by name only, so
+# a wrong exists-query publisher would otherwise ship undetected (cf. the Spyder
+# finding in #50016).
 $softwareName = "Rtools"
-$softwareNameLike = "*$softwareName*"
+$softwareNameLike = "$softwareName*"
+$softwarePublisher = "The R Foundation"
 $uninstallArgs = "/VERYSILENT /SUPPRESSMSGBOXES /NORESTART"
 
 $machineKey = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*'
@@ -8,11 +16,11 @@
 
 try {
     [array]$uninstallKeys = Get-ChildItem -Path @($machineKey, $machineKey32on64) -ErrorAction SilentlyContinue |
-        ForEach-Object { Get-ItemProperty $_.PSPath }
+        ForEach-Object { Get-ItemProperty $_.PSPath -ErrorAction SilentlyContinue }
 
     $foundUninstaller = $false
     foreach ($key in $uninstallKeys) {
-        if ($key.DisplayName -like $softwareNameLike) {
+        if ($key.DisplayName -like $softwareNameLike -and $key.Publisher -eq $softwarePublisher) {
             $foundUninstaller = $true
             $uninstallCommand = if ($key.QuietUninstallString) { $key.QuietUninstallString } else { $key.UninstallString }
             if ($uninstallCommand -match '^\s*"([^"]+)"\s*(.*)$') {
@@ -27,7 +35,9 @@
             $exitCode = $process.ExitCode; Write-Host "Uninstall exit code: $exitCode"; break
         }
     }
-    if (-not $foundUninstaller) { Write-Host "Uninstaller for '$softwareName' not found."; Exit 1 }
+    # Nothing to remove is not a failure: uninstall scripts are idempotent here, as
+    # in nordpass_uninstall.ps1 and windsurf_uninstall.ps1.
+    if (-not $foundUninstaller) { Write-Host "Uninstall entry not found for '$softwareName'."; Exit 0 }
 } catch { Write-Host "Error: $_"; Exit 1 }
 
 Exit $exitCode

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 7 out of 8 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (2)

ee/maintained-apps/inputs/winget/scripts/rtools_install.ps1:23

  • Test-RtoolsRegistered checks only DisplayName. That diverges from the app identity used elsewhere (exists query + uninstall script also require publisher), and can cause the timeout path to treat an unrelated/old "Rtools*" entry as proof of a successful install. Filter by Publisher to match the manifest identity.
$machineKey = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*'
$machineKey32on64 = 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*'

function Test-RtoolsRegistered {
    $null -ne (Get-ChildItem -Path @($machineKey, $machineKey32on64) -ErrorAction SilentlyContinue |
        ForEach-Object { Get-ItemProperty $_.PSPath -ErrorAction SilentlyContinue } |
        Where-Object { $_.DisplayName -like "Rtools*" } |
        Select-Object -First 1)
}

ee/maintained-apps/outputs/rtools/windows.json:19

  • The embedded install script in refs (install_script_ref 4679c4f2) uses the same DisplayName-only registration check. If you tighten the check (e.g., require Publisher) in the source script, regenerate this output so the shipped manifest script stays consistent with the exists/uninstall identity.
    "4679c4f2": "# Learn more about .exe install scripts:\n# http://fleetdm.com/learn-more-about/exe-install-scripts\n\n$exeFilePath = \"${env:INSTALLER_PATH}\"\n\n# Rtools uses Inno Setup and unpacks a large toolchain (a ~460 MB installer) to\n# C:\\rtools45, not Program Files. Two things made the previous script hang:\n# PowerShell's \"Start-Process -Wait\" waits for the process *and all of its\n# descendants*, and the unpack itself is slow. Wait on the installer process\n# alone, with a cap below the budget the caller allows, and log progress so a\n# slow unpack is distinguishable from a stuck one.\n$installTimeoutSeconds = 480\n$pollSeconds = 15\n\n$machineKey = 'HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\*'\n$machineKey32on64 = 'HKLM:\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\*'\n\nfunction Test-RtoolsRegistered {\n    $null -ne (Get-ChildItem -Path @($machineKey, $machineKey32on64) -ErrorAction SilentlyContinue |\n        ForEach-Object { Get-ItemProperty $_.PSPath -ErrorAction SilentlyContinue } |\n        Where-Object { $_.DisplayName -like \"Rtools*\" } |\n        Select-Object -First 1)\n}\n\ntry {\n\n$process = Start-Process -FilePath \"$exeFilePath\" `\n  -ArgumentList \"/VERYSILENT /SUPPRESSMSGBOXES /NORESTART\" `\n  -PassThru\n# Touch .Handle so the exit code is still readable after the process ends:\n# Start-Process -PassThru otherwise returns $null for .ExitCode.\n$null = $process.Handle\n\n$elapsed = 0\nwhile (-not $process.HasExited -and ($elapsed -lt $installTimeoutSeconds)) {\n  Start-Sleep -Seconds $pollSeconds\n  $elapsed += $pollSeconds\n  Write-Host \"Installing... ($elapsed seconds, registered: $(Test-RtoolsRegistered))\"\n}\n\nif (-not $process.HasExited) {\n  # The installer is still running at the cap. If Rtools has already registered\n  # in Add/Remove Programs the install itself finished and what is left is a\n  # lingering child, so stopping it is safe; otherwise the unpack genuinely did\n  # not finish in time and this is a real failure.\n  if (Test-RtoolsRegistered) {\n    Write-Host \"Installer still running after ${installTimeoutSeconds}s but Rtools is registered; stopping the lingering process.\"\n    Stop-Process -Id $process.Id -Force -ErrorAction SilentlyContinue\n    Start-Sleep -Seconds 2\n    Exit 0\n  }\n\n  Write-Host \"Installer did not finish within ${installTimeoutSeconds}s and Rtools is not registered.\"\n  Stop-Process -Id $process.Id -Force -ErrorAction SilentlyContinue\n  Exit 1\n}\n\n$exitCode = $process.ExitCode\nWrite-Host \"Install exit code: $exitCode\"\n\n# The parent can exit while a descendant is still finishing the unpack and writing\n# the ARP entry -- the same hand-off that makes -Wait block. Give registration a\n# bounded window to appear rather than checking once.\n$settle = 0\nwhile (-not (Test-RtoolsRegistered) -and ($settle -lt 90)) {\n  Start-Sleep -Seconds $pollSeconds\n  $settle += $pollSeconds\n  Write-Host \"Waiting for Rtools to register... ($settle seconds)\"\n}\n\nif (-not (Test-RtoolsRegistered)) {\n  Write-Host \"Rtools did not register in Add/Remove Programs.\"\n  Exit 1\n}\n\n# 3010 (reboot required) and 1641 (reboot initiated) are successful installs.\nif ($exitCode -eq 3010 -or $exitCode -eq 1641) { Exit 0 }\n\nExit $exitCode\n\n} catch {\n  Write-Host \"Error: $_\"\n  Exit 1\n}\n",

@kitzy
kitzy marked this pull request as ready for review July 28, 2026 16:16
@kitzy
kitzy requested a review from a team as a code owner July 28, 2026 16:16
@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

Adds Windows support for Rtools 4.5.6768, including Winget metadata, silent installation and uninstallation scripts, registry-based detection, generated application records, installer checksum metadata, and a React icon mapped to the rtools software name.

Possibly related issues

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title is concise and accurately summarizes the main change: adding Rtools as a Windows Fleet-maintained app.
Description check ✅ Passed The description follows the template well, covering the issue link, what changed, testing, notes, and checklist items.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch add-rtools-windows-fma

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@ee/maintained-apps/inputs/winget/scripts/rtools_install.ps1`:
- Around line 18-23: Update Test-RtoolsRegistered in
ee/maintained-apps/inputs/winget/scripts/rtools_install.ps1 to use the target
version 4.5.6768 and require Publisher to match “The R Foundation” alongside
DisplayName and DisplayVersion in the shared predicate; parameterize or inject
the target version as appropriate. Regenerate the embedded install script in
ee/maintained-apps/outputs/rtools/windows.json at line 19 from the corrected
source; no separate logic change is needed there.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: a2116c2b-6104-4972-8e1b-940d1526e7b6

📥 Commits

Reviewing files that changed from the base of the PR and between 53b92f9 and 3a41b8a.

⛔ Files ignored due to path filters (1)
  • website/assets/images/app-icon-rtools-60x60@2x.png is excluded by !**/*.png
📒 Files selected for processing (7)
  • ee/maintained-apps/inputs/winget/rtools.json
  • ee/maintained-apps/inputs/winget/scripts/rtools_install.ps1
  • ee/maintained-apps/inputs/winget/scripts/rtools_uninstall.ps1
  • ee/maintained-apps/outputs/apps.json
  • ee/maintained-apps/outputs/rtools/windows.json
  • frontend/pages/SoftwarePage/components/icons/Rtools.tsx
  • frontend/pages/SoftwarePage/components/icons/index.ts

Comment on lines +18 to +23
function Test-RtoolsRegistered {
$null -ne (Get-ChildItem -Path @($machineKey, $machineKey32on64) -ErrorAction SilentlyContinue |
ForEach-Object { Get-ItemProperty $_.PSPath -ErrorAction SilentlyContinue } |
Where-Object { $_.DisplayName -like "Rtools*" } |
Select-Object -First 1)
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Require the requested publisher and version before declaring installation complete.

Line 21 treats any Rtools* ARP entry as success. An existing older Rtools installation can therefore bypass both the settle loop and timeout failure path, reporting success while 4.5.6768 is not installed. Match Publisher and the target DisplayVersion in the shared predicate.

  • ee/maintained-apps/inputs/winget/scripts/rtools_install.ps1#L18-L23: parameterize or inject the target version and require it plus The R Foundation in Test-RtoolsRegistered.
  • ee/maintained-apps/outputs/rtools/windows.json#L19-L19: regenerate the embedded install script from the corrected source.
📍 Affects 2 files
  • ee/maintained-apps/inputs/winget/scripts/rtools_install.ps1#L18-L23 (this comment)
  • ee/maintained-apps/outputs/rtools/windows.json#L19-L19
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ee/maintained-apps/inputs/winget/scripts/rtools_install.ps1` around lines 18
- 23, Update Test-RtoolsRegistered in
ee/maintained-apps/inputs/winget/scripts/rtools_install.ps1 to use the target
version 4.5.6768 and require Publisher to match “The R Foundation” alongside
DisplayName and DisplayVersion in the shared predicate; parameterize or inject
the target version as appropriate. Regenerate the embedded install script in
ee/maintained-apps/outputs/rtools/windows.json at line 19 from the corrected
source; no separate logic change is needed there.

@github-actions

Copy link
Copy Markdown
Contributor

Script Diff Results

ee/maintained-apps/outputs/rtools/windows.json

=== Install // 4679c4f2 -> 38f938a7 ===

--- /tmp/old.E2lEdi	2026-07-28 17:45:02.785971077 +0000
+++ /tmp/new.ZRBp6l	2026-07-28 17:45:02.785971077 +0000
@@ -3,12 +3,9 @@
 
 $exeFilePath = "${env:INSTALLER_PATH}"
 
-# Rtools uses Inno Setup and unpacks a large toolchain (a ~460 MB installer) to
-# C:\rtools45, not Program Files. Two things made the previous script hang:
-# PowerShell's "Start-Process -Wait" waits for the process *and all of its
-# descendants*, and the unpack itself is slow. Wait on the installer process
-# alone, with a cap below the budget the caller allows, and log progress so a
-# slow unpack is distinguishable from a stuck one.
+# Rtools unpacks a large toolchain (~460 MB) to C:\rtools45, not Program Files.
+# -Wait waits on descendants, so wait on the installer process alone and log
+# progress to tell a slow unpack apart from a stuck one.
 $installTimeoutSeconds = 480
 $pollSeconds = 15
 
@@ -27,8 +24,7 @@
 $process = Start-Process -FilePath "$exeFilePath" `
   -ArgumentList "/VERYSILENT /SUPPRESSMSGBOXES /NORESTART" `
   -PassThru
-# Touch .Handle so the exit code is still readable after the process ends:
-# Start-Process -PassThru otherwise returns $null for .ExitCode.
+# Keeps .ExitCode readable after the process ends.
 $null = $process.Handle
 
 $elapsed = 0
@@ -39,10 +35,7 @@
 }
 
 if (-not $process.HasExited) {
-  # The installer is still running at the cap. If Rtools has already registered
-  # in Add/Remove Programs the install itself finished and what is left is a
-  # lingering child, so stopping it is safe; otherwise the unpack genuinely did
-  # not finish in time and this is a real failure.
+  # Registered means the install finished and only a lingering child remains.
   if (Test-RtoolsRegistered) {
     Write-Host "Installer still running after ${installTimeoutSeconds}s but Rtools is registered; stopping the lingering process."
     Stop-Process -Id $process.Id -Force -ErrorAction SilentlyContinue
@@ -58,9 +51,7 @@
 $exitCode = $process.ExitCode
 Write-Host "Install exit code: $exitCode"
 
-# The parent can exit while a descendant is still finishing the unpack and writing
-# the ARP entry -- the same hand-off that makes -Wait block. Give registration a
-# bounded window to appear rather than checking once.
+# The parent can exit while a descendant is still writing the ARP entry.
 $settle = 0
 while (-not (Test-RtoolsRegistered) -and ($settle -lt 90)) {
   Start-Sleep -Seconds $pollSeconds

=== Uninstall // d5432a7e -> d5ddfa34 ===

--- /tmp/old.x3c4s4	2026-07-28 17:45:02.807971020 +0000
+++ /tmp/new.ZpQuYC	2026-07-28 17:45:02.808971018 +0000
@@ -1,10 +1,5 @@
-# The registry DisplayName carries a version and build ("Rtools 4.5 (6768-6492)"),
-# so match on a prefix. Require the publisher too, mirroring the manifest's exists
-# query. Verified as "The R Foundation" against the setup stub's PE version
-# resource (CompanyName, which Inno derives from AppPublisher). Requiring it here
-# puts the value under test -- the validator's appExists looks up by name only, so
-# a wrong exists-query publisher would otherwise ship undetected (cf. the Spyder
-# finding in #50016).
+# The ARP DisplayName carries a version and build ("Rtools 4.5 (6768-6492)"), so
+# match on a prefix, plus the publisher to avoid other products sharing it.
 $softwareName = "Rtools"
 $softwareNameLike = "$softwareName*"
 $softwarePublisher = "The R Foundation"
@@ -35,8 +30,6 @@
             $exitCode = $process.ExitCode; Write-Host "Uninstall exit code: $exitCode"; break
         }
     }
-    # Nothing to remove is not a failure: uninstall scripts are idempotent here, as
-    # in nordpass_uninstall.ps1 and windsurf_uninstall.ps1.
     if (-not $foundUninstaller) { Write-Host "Uninstall entry not found for '$softwareName'."; Exit 0 }
 } catch { Write-Host "Error: $_"; Exit 1 }

@allenhouchins allenhouchins changed the title Add Rtools Windows FMA Add Rtools as a Windows FMA Jul 29, 2026
@allenhouchins
allenhouchins merged commit f4d7064 into main Jul 29, 2026
36 checks passed
@allenhouchins
allenhouchins deleted the add-rtools-windows-fma branch July 29, 2026 04:01
@allenhouchins allenhouchins mentioned this pull request Jul 31, 2026
1 task
allenhouchins added a commit that referenced this pull request Jul 31, 2026
<!-- Add the related story/sub-task/bug number, like Resolves #123, or
remove if NA -->
**Related issue:** N/A

# What this does

Removes the **Captin** software icon: the `Captin.tsx` fallback icon
component and its
`SOFTWARE_NAME_TO_ICON_MAP` entry.

Captin is deprecated and is being removed as a Fleet-maintained app. Its
manifest fails
the FMA validator because the download at the pinned URL now installs
2.0.1 while
Homebrew still declares 1.3.1:

```
level=INFO msg="Looking for app: Captin, version: 1.3.1" app=Captin
level=INFO msg="Found app: 'Captin' at /Applications/Captin.app, Version: 2.0.1, Bundled Version: 203"
level=ERROR msg="App version '1.3.1' was not found by osquery" app=Captin
```

Split out of the FMA removal so the frontend change can be reviewed on
its own.

> [!NOTE]
> **Merge order.** The FMA removal (input, output manifest, and
`apps.json` entry) is in a
> separate PR. Merging this one first leaves the Captin FMA without a
fallback icon until
> that PR lands, so it should merge after — or at the same time as — the
FMA removal.

Verified nothing else references `Captin` after the removal. The one
remaining mention in
the repo is a row in `cmd/osquery-perf/software-library/software.sql`,
which is a
load-test software inventory corpus rather than an FMA reference, so it
is left alone.

# Checklist for submitter

- [x] QA'd all new/changed functionality manually

No changes file: this is not a user-visible change on its own, and
matches how other FMA
catalog/icon PRs ship (e.g. #50028, #50024).


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
  * Removed the obsolete Captin icon from the software listings.
  * Prevented the retired icon from appearing in software name mappings.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants