Skip to content

Add SwiftLint build phase to SwiftUI App template#65

Open
ssestak wants to merge 3 commits into
feature/state-management-templatesfrom
feature/swiftlint-build-step
Open

Add SwiftLint build phase to SwiftUI App template#65
ssestak wants to merge 3 commits into
feature/state-management-templatesfrom
feature/swiftlint-build-step

Conversation

@ssestak

@ssestak ssestak commented May 12, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds a SwiftLint Run Script build phase to the SwiftUI App Xcode project template. Generated projects autocorrect on every build and surface remaining warnings in Xcode's issue navigator — no manual install of the phase itself needed after project creation.

Stacked on #64. PR base will retarget to main automatically once #64 merges.

Flow

flowchart LR
    A[Build starts] --> B[Compile Sources]
    B --> C[Link Frameworks]
    C --> D[Copy Resources]
    D --> E[SwiftLint phase]
    E --> F{swiftlint on PATH?}
    F -- yes --> G[swiftlint --fix --quiet]
    G --> H[swiftlint]
    H --> I[Warnings in Xcode]
    F -- no --> J[Build-log warning:<br/>'brew install swiftlint']
Loading

Key Changes

  • Templates/SwiftUI App.xctemplate/TemplateInfo.plist
    • New BuildPhases array on the app target with a single ShellScript phase named SwiftLint.
    • ENABLE_USER_SCRIPT_SANDBOXING = NO added to SharedSettings — Xcode 15+ sandboxes script phases by default, which blocks SwiftLint from reading project files (Sandbox: swiftlint deny file-read-data …).
  • Templates/SwiftUI App.xctemplate/App.swift — new #warning instructing the developer to drag the SwiftLint phase above Compile Sources.
  • Script exports /opt/homebrew/bin for Apple Silicon, runs swiftlint --fix --quiet then swiftlint. Graceful fallback emits a build-log warning when SwiftLint isn't installed.

Known Limitation — Phase Position

Xcode project templates can only append custom phases to a target — there is no documented key (InsertBefore, Position, ReplaceBuildPhases, …) to insert before phases inherited from com.apple.dt.unit.applicationBase. Confirmed empirically (declaring Sources/Frameworks/Resources in the child array creates duplicate empty phases instead of replacing the inherited ones) and via research of public Xcode templates on disk and community projects (surfstudio, GoodRequest) — all of them rely on the same after-Sources position.

Consequence: as generated, the SwiftLint phase runs after Compile Sources, so --fix corrections apply to the next build. The new #warning in App.swift tells the developer to drag the phase above Compile Sources once — the reorder persists in project.pbxproj.

Out of Scope

  • Shipping a default .swiftlint.yml inside the template — left to the developer.
  • Build phase for the Scene file template — file templates can't inject build phases.
  • Programmatic post-creation reordering of project.pbxproj — would require shipping a Ruby/Python script with the template.

Test Plan

  • Generate a project from the SwiftUI App template with SwiftLint installed; confirm the SwiftLint build phase appears on the target (one, not duplicated)
  • Introduce a deliberate style violation; confirm it appears as an Xcode warning
  • Manually drag the SwiftLint phase above Compile Sources, introduce an autocorrectable violation; confirm --fix corrects it on the same build
  • Generate on a machine without SwiftLint; confirm the build succeeds with the install-hint warning
  • Confirm no Sandbox: swiftlint deny … errors in the build log
  • Confirm the #warning about reordering appears in the issue navigator on first build

Šimon Šesták added 3 commits May 12, 2026 14:08
Adds a Run Script build phase that runs swiftlint --fix followed by
swiftlint, so generated projects autocorrect and surface remaining
warnings in Xcode's issue navigator. Falls back to a friendly warning
when SwiftLint is not installed.
Declare the full BuildPhases array so SwiftLint runs first, ensuring
--fix corrects sources before they are compiled. Also disable
ENABLE_USER_SCRIPT_SANDBOXING so SwiftLint can read project files
under Xcode 15+'s default sandbox.
Xcode template inheritance only appends BuildPhases — declaring
Sources/Frameworks/Resources in the child template creates empty
duplicates instead of replacing the inherited ones. Keep only the
SwiftLint phase and surface a #warning telling the developer to drag
it above Compile Sources so --fix corrections apply to the current
build instead of the next one.
@ssestak ssestak force-pushed the feature/swiftlint-build-step branch from 5fb78e5 to cc2e525 Compare May 12, 2026 13:08
@ssestak ssestak requested a review from jmarek41 May 12, 2026 13:10
<string>___VARIABLE_bundleIdentifierPrefix:bundleIdentifier___.___PACKAGENAMEASRFC1034IDENTIFIER___.beta</string>
</dict>
</dict>
<key>BuildPhases</key>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Na iRozhlase jsem si ten script upravoval takto:

if [[ "${BUILD_DIR}" =~ "Previews" ]]; then
    echo "SwiftLint not enabled when compiling for previews"
    exit
fi

if test -d "/opt/homebrew/bin/"; then
  PATH="/opt/homebrew/bin/:${PATH}"
fi

export PATH

if which swiftlint >/dev/null; then
    swiftlint --fix --quiet
    swiftlint
else
    echo "error: SwiftLint not installed, run: brew install swiftlint"
fi

Aby se to nedělalo když buildíš pro previews. Dává ti to smysl?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Dále jsem přidával i ten SwiftFormat, nedáme to taky by default do všech projektů? Já bych byl za.

if [[ "${BUILD_DIR}" =~ "Previews" ]]; then
    echo "SwiftFormat not enabled when compiling for previews"
    exit
fi

if test -d "/opt/homebrew/bin/"; then
  PATH="/opt/homebrew/bin/:${PATH}"
fi

export PATH

if which swiftformat >/dev/null; then
    swiftformat "$SRCROOT"
else
    echo "warning: SwiftFormat not installed, run: brew install swiftformat"
fi

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