Skip to content

ci: pin formatter toolchain and centralize the file list - #12

Merged
jwinarske merged 2 commits into
mainfrom
jw/pin-format-toolchain
Aug 14, 2026
Merged

ci: pin formatter toolchain and centralize the file list#12
jwinarske merged 2 commits into
mainfrom
jw/pin-format-toolchain

Conversation

@jwinarske

Copy link
Copy Markdown
Contributor

Both format jobs failed on #11 without any source change causing it. This makes the formatting gate reproducible.

Why

Formatter output is version-sensitive, and neither formatter was pinned:

  • clang-format: the runner apt-installs whatever tracks the Ubuntu image (18.1.8); a Fedora dev box has 22. They format struct stat sb {} differently, and 22 additionally flags its own -i output under --dry-run --Werror — it cannot satisfy itself on that construct.
  • dart format: setup-dart resolves stable, which had rolled to 3.13.0 while the local SDK was 3.12.2. 3.13 collapses some call arguments differently.

Either one turns CI red on a commit that did not touch the affected file. A format gate is only useful if it is reproducible.

Changes

Pin the version-sensitive jobs. DART_SDK_VERSION and FLUTTER_VERSION are declared once at workflow level and consumed by the format and flutter-flathub-catalog jobs. Jobs that only build, analyze, or test still float against stable, so genuine breakage against a new SDK still surfaces in CI rather than in a user's project.

Make local runs match CI. scripts/format.sh provisions the pinned clang-format via pip, and downloads a matching Dart SDK into .cache/, when the installed versions differ. A warning would have told you the versions diverged but still left you unable to produce the formatting CI wants — this actually produces it. CI runs the same script, and hits neither download path because its toolchain already matches.

./scripts/format.sh            # apply
./scripts/format.sh --check    # verify, as CI does

Centralize the file list. It previously lived inline in the workflow, which is how it came to glob tests/ — a directory renamed to native_tests/ in 0.2.2 — with nobody noticing, silently excluding the entire native test suite from formatting. It now lives in the script that both CI jobs call. Restoring that coverage is a follow-up PR, since native_tests/ carries ~1233 violations.

README fixes. The build snippet omitted -DAPPSTREAM_BUILD_TESTS=ON, documenting a ctest invocation that finds no tests — the same defect fixed in scripts/test.sh in 0.4.0. Also documents the formatting workflow and the clang-tidy-before-clang-format ordering.

Verification

scripts/format.sh --check passes in both --cxx and --dart modes on a machine with clang-format 22 and Dart 3.12.2 installed, correctly provisioning 18.1.8 and 3.13.0 rather than using either. Apply mode is a no-op on a clean tree. Workflow YAML parses and both pins resolve.

Both format jobs failed on PR #11 without any source change causing it.
The runner's clang-format tracks the Ubuntu image (18) while a developer
machine may have 22, and setup-dart's `stable` had rolled to 3.13.0 while
local was 3.12.2. The two clang-format versions format `struct stat sb {}`
differently, and 22 flags its own -i output under --dry-run --Werror; Dart
3.13 collapses some call arguments differently than 3.12. Formatting is
only a useful gate if it is reproducible, so pin it.

- Pin the format job to DART_SDK_VERSION and the Flutter example job to
  FLUTTER_VERSION, both declared once at workflow level. Jobs that only
  build, analyze, or test still float against stable, so real breakage
  against new SDKs still surfaces here rather than in a user's project.
- Stop apt-installing clang-format. scripts/format.sh provisions the
  pinned version via pip, and downloads a matching Dart SDK into .cache/
  when the local one differs, so the script reaches CI's verdict on any
  machine instead of merely warning that the versions diverged.
- Move the list of files to format into scripts/format.sh and have both CI
  jobs call it. The list was previously inlined in the workflow, which is
  how it came to reference `tests/` — a directory renamed in 0.2.2 — with
  nobody noticing.

Also fix the README build snippet, which omitted -DAPPSTREAM_BUILD_TESTS=ON
and so documented a `ctest` invocation that finds no tests, the same defect
fixed in scripts/test.sh in 0.4.0, and document the formatting workflow.

Verified: scripts/format.sh --check passes in both modes on a machine with
clang-format 22 and Dart 3.12.2 installed, provisioning 18.1.8 and 3.13.0.
Findings from a proper reliability and security pass over the new script,
which the previous commit did not get.

- Fail loudly when a configured directory is missing. find reports the
  error, carries on with the directories that do exist, and has its
  non-zero status swallowed by the pipeline, so a renamed directory would
  silently drop out of coverage while the run reported success. That is
  exactly how native_tests/ went unformatted for three releases after
  tests/ was renamed — the script written to prevent that bug reproduced
  it. A non-empty file list is not evidence that everything was seen.
  DART_PATHS gets the same guard for symmetry.
- Verify the Dart SDK archive against its published sha256 before
  extracting it. The script downloads an archive and then executes
  binaries from it; TLS attests to the transport, not to the bytes on the
  bucket. A mismatch deletes the archive and aborts before anything is
  extracted.
- Detect the host architecture instead of hardcoding linux-x64, which
  would hand an arm64 developer an SDK that fails with a confusing exec
  format error. Unknown architectures now fail with an actionable message.
  The cache directory is keyed by architecture.
- Print only the first version match; distro strings repeat the number
  ("clang-format version 18.1.8 (Fedora 18.1.8-4.fc44)"), so the header
  read "18.1.8 18.1.8".

Verified: shellcheck clean; the missing-directory guard fires; the
checksum path was exercised end to end, including a tamper test that
corrupts the archive after download and confirms it is rejected, deleted,
and never extracted. clang-tidy reports no warnings in project sources
(the one hit is the vendored dart_api_dl.cpp including a .c file by
design). clang-format ran last. 149/149 C++ and 45/45 Dart tests pass,
dart analyze --fatal-infos clean.
jwinarske added a commit that referenced this pull request Aug 14, 2026
The CI clang-format job globbed `find src include tests`, but tests/ was
renamed native_tests/ in 0.2.2. find printed an error and moved on, and
because the pipeline's exit status comes from clang-format rather than
find, the job stayed green while silently checking nothing in the native
test suite. It had therefore never been formatted, and carried 1233
violations under both clang-format 18 and 22.

Add native_tests to CXX_DIRS in scripts/format.sh — which #12 made the
single source of truth for both CI jobs — and apply clang-format 18.1.8,
the pinned version.

This is a mechanical reformat with no behavior change. Verified per file:
every body's token stream is byte-identical with whitespace removed, and
every #include set is unchanged as a multiset, so the only differences are
line wrapping and include ordering (clang-format's SortIncludes). The C++
suite still builds and passes 149/149, the same count as before.
@jwinarske
jwinarske merged commit 0d4d458 into main Aug 14, 2026
12 checks passed
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.

1 participant