Skip to content

Add SwiftLint, pre-commit hooks, and CI workflow - #12

Merged
silentswordfish merged 2 commits into
mainfrom
add-lint-precommit-ci
Jul 23, 2026
Merged

silentswordfish merged 2 commits into
mainfrom
add-lint-precommit-ci

Conversation

@silentswordfish

Copy link
Copy Markdown
Contributor

Summary

  • SwiftLint (.swiftlint.yml): opts into a handful of stricter rules (force unwrapping, implicitly unwrapped optionals, empty_count, etc.), caps line length at 120/200 (warning/error), and whitelists the small set of short/underscored identifiers already used in this codebase (s, t, fm, op, and the vXX_Y version-literal test names) rather than loosening those checks globally.
  • pre-commit (.pre-commit-config.yaml): a local hook that runs swiftlint lint against staged Swift files via the pre-commit framework. Documented in the README under Development.
  • CI (.github/workflows/ci.yml): two parallel macOS jobs on push/PR — build+test (Xcode pinned via setup-xcode, SPM build cache) and lint (swiftlint lint).
  • Ran swiftlint --fix for the mechanical violations this surfaced (trailing commas, trailing newlines, one colon-spacing fix) across existing files, plus one count > 0 → !isEmpty cleanup. Everything else that remains is an advisory warning, not blocking — pre-existing structural patterns (function length/param count, an implicitly-unwrapped optional in the FSEvents callback context) are left for their own future PRs rather than a drive-by rewrite here.

Test plan

  • swift build and swift test pass (40 tests)
  • swiftlint lint exits 0
  • pre-commit install + smoke-tested that the hook actually blocks a commit with a real violation, then verified a clean commit passes
  • Confirm the ci.yml workflow runs green on GitHub (first run once this PR is opened)

🤖 Generated with Claude Code

- .swiftlint.yml: opt into a handful of stricter rules (force
  unwrapping, implicitly unwrapped optionals, empty_count, etc.),
  cap line length, and whitelist the small set of short/underscored
  identifiers already in use rather than loosening the rule globally.
- .pre-commit-config.yaml: local SwiftLint hook scoped to staged
  Swift files via the pre-commit framework.
- .github/workflows/ci.yml: build, test, and lint on macOS on push/PR.
- Autocorrect the resulting mechanical violations (trailing commas,
  trailing newlines, colon spacing) across existing files; everything
  else surfaces as an advisory warning rather than blocking.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Comment thread .github/workflows/ci.yml Outdated
uses: actions/cache@v4
with:
path: .build
key: ${{ runner.os }}-spm-${{ hashFiles('Package.resolved') }}

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.

hashFiles('Package.resolved') always hashes an empty match here because Package.resolved is not committed, so the cache key stays the same across every PR even when Package.swift or the floating branch: main deps drift. Caching the whole .build tree on top of that can also restore stale build products across PRs or toolchain changes. Would it make sense to key off Package.swift (or commit Package.resolved) and cache SwiftPM’s package caches instead of the full .build directory?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good catch. Fixed: keyed off Package.swift instead, and narrowed the cached paths to ~/Library/Caches/org.swift.swiftpm + .build/checkouts + .build/repositories (fetched sources only) rather than the whole .build tree, so a restore just saves the floating-branch deps an incremental git fetch instead of a full clone — it can no longer serve stale compiled objects across dependency or toolchain drift.

"Index.noindex",
"ModuleCache.noindex",
"CompilationCache.noindex",
"CompilationCache.noindex"

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.

SwiftLint’s default trailing_comma rule forbids trailing commas (mandatory_comma: false), which is why autocorrect dropped them on multiline arrays like this. A lot of Swift projects flip that to mandatory_comma: true so list edits stay quieter in diffs. Do we want that for this repo?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Agreed, flipped to mandatory_comma: true and re-ran autocorrect to put the trailing commas back.

Comment thread .github/workflows/ci.yml Outdated
- uses: actions/checkout@v4

- name: Install SwiftLint
run: brew install swiftlint

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.

brew install swiftlint tracks Homebrew’s latest formula, so an upstream rule change can fail this job with no repo diff. Want to pin a SwiftLint version here so the lint gate stays reproducible?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Pinned to 0.63.3 (same version installed locally) via the portable_swiftlint.zip release asset instead of brew install, so the lint gate can't go red from an upstream rule change with no diff in this repo.

- Cache key off Package.swift instead of the uncommitted
  Package.resolved (which always hashed to an empty match), and
  scope the cache to fetched dependency sources rather than the
  whole .build tree so it can't silently restore stale build
  products across dependency or toolchain changes.
- Pin the lint job's SwiftLint to an exact version (0.63.3, matching
  what contributors install locally) via the portable release
  binary, instead of `brew install swiftlint` tracking whatever
  Homebrew's formula currently points at.
- Flip trailing_comma to mandatory_comma: true per review — trailing
  commas on multiline collection literals keep future list edits to
  single-line diffs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@silentswordfish
silentswordfish merged commit 6bc0ac1 into main Jul 23, 2026
2 checks passed
@silentswordfish
silentswordfish deleted the add-lint-precommit-ci branch July 23, 2026 19:39
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.

2 participants