Files
fleet/.github/workflows
Allen HouchinsandCopilot Autofix powered by AI 9b5fc40b2e Shard FMA validation workflows and route Windows apps to arch-matched runners (#49348)
**Related issue:** N/A — CI improvement for the FMA validation
workflows.

## Summary

Restructures the Windows and macOS Fleet-maintained app validation
workflows around a cheap Linux detect/shard job, with Windows apps
additionally routed to a CI runner whose native architecture matches the
app's installer.

**Both platforms:**

- Change detection and sharding run on `ubuntu-latest`. Expensive
Windows/macOS runners only spin up when their platform actually has
changed apps — e.g. a Windows-only letter-batch PR no longer boots a
macOS runner just to discover there's nothing to do (and vice versa) —
and they check out at depth 1 instead of full history.
- A new `.github/scripts/partition-fma-apps.sh <windows|darwin>` emits
the job matrix; validation steps move unchanged into reusable workflows
(`test-fma-windows-validate.yml`, `test-fma-darwin-validate.yml`).
- Large PRs shard into parallel jobs (Windows: 25 apps/shard, macOS:
30), and the manual full-run workflows gain a `shard_size` input
(Windows default 20 → ~20 shards over 384 apps; macOS default 25 → ~39
shards over 961 apps). Neither full run could previously finish:
hundreds of sequential installs blow the 6-hour job limit.
- Pre-installed app handling is computed per shard from that shard's
slug list — Windows removals (Chrome, 7-Zip, Firefox, Node.js,
PowerShell, R, Git) and macOS steps (Chrome, Xcode for Icon Composer,
the Fleet Desktop MDM config stub) only run on the runner validating
that app. This also brings the full-run workflows to parity with the PR
gates (they previously only removed Chrome).
- Stable summary jobs (`test-fma-pr-only`, `test-fma`) aggregate the
dynamic matrix results so branch protection / PR gating keeps a fixed
check name.

**Windows arch routing:**

- Each changed `<name>/windows` slug's `installer_arch` is read from
`ee/maintained-apps/inputs/winget/<name>.json`: `arm64` apps →
`windows-11-arm`, x64/x86/neutral apps → `windows-latest` (x64). Missing
input files default to x64 with a warning. This fixes installers that
check the native OS architecture and abort under Prism emulation on the
ARM runner (Inno Setup `ArchitecturesAllowed=x64` — GOG Galaxy, Reqable
— and Docker Desktop). Future arm64 FMAs need no workflow change —
`installer_arch: arm64` in the winget input is enough.
- macOS needs no arch matrix: `macos-latest` is arm64 and x86-only casks
run under Rosetta 2, which matches how customer Macs run them.

# Checklist for submitter

- [x] 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.

## Testing

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

Manual QA:
- Partition script is shellcheck-clean and tested against the real repo
for both platforms: empty input, mixed-platform slug lists, x86/neutral
routing to the x64 runner, single-slug arrays, missing input file
fallback, arm64/x64 split with sharding (via a synthetic arm64 input),
invalid platform/shard-size rejection, and full-catalog partitions (384
Windows apps → 20 shards, 961 darwin apps → 39 shards, all slugs
accounted for, matrix outputs well under the 1 MB job-output limit).
- All six workflows pass `actionlint` and zizmor 1.25.2 (with the repo's
`.github/zizmor-gate.yml` config) with no findings.
- The rewritten Windows PR gate ran on this PR itself: the Linux detect
job correctly found no changed Windows apps, skipped the Windows
runners, and the `test-fma-pr-only` summary check passed.


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

* **New Features**
* Added sharded validation for maintained macOS and Windows apps to run
tests in parallel.
  * Added configurable `shard_size` for manual validation runs.
  * Introduced reusable validation workflows for Darwin and Windows.
  * Improved Windows testing to be architecture-aware (ARM64 vs x64).
* **Bug Fixes**
* Improved pull request gating to validate only changed apps and report
results more reliably.
* Workflows now gracefully handle scenarios where no matching apps are
found (avoid unnecessary failures).
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-07-15 16:07:36 -05:00
..
2026-07-14 12:26:24 -03:00

Github Actions

Fleet uses Github Actions for continuous integration (CI). This document describes best practices and at patterns for writing and maintaining Fleet's Github Actions workflows.

Bash

By default, Github Actions sets the shell to bash -e for linux and MacOS runners. To help write safer bash scripts in run jobs and avoid common issues, override the default by adding the following to the workflow file

defaults:
  run:
    # fail-fast using bash -eo pipefail. See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#exit-codes-and-error-action-preference
    shell: bash

By specifying the default shell to bash, some extra flags are set. The option pipefail changes the behaviour when using the pipe | operator such that if any command in a pipeline fails, that commands return code will be used a the return code for the whole pipeline. Consider the following example in test-go.yaml

    - name: Run Go Tests
      run: |
        # omitted ...
          make test-go 2>&1 | tee /tmp/gotest.log

If the pipefail option was not set, this job would always succeed because tee would always return success. This is not the intended behavior. Instead, we want the job to fail if make test-go fails.

Concurrency

Github Action runners are limited. If a lot of workflows are queued, they will wait in pending until a runner becomes available. This has caused issue in the past where workflows take an excessively long time to start. To help with this issue, use the following in workflows

# This allows a subsequently queued workflow run to interrupt previous runs
concurrency:
  group: ${{ github.workflow }}-${{ github.head_ref || github.run_id}}
  cancel-in-progress: true

When a workflow is triggered via a pull request, it will cancel previous running workflows for that pull request. This is especially useful when changes are pushed to a pull request frequently. Manually triggered workflows, workflows that run on a schedule, and workflows triggered by pushes to main are unaffected.