ci: pin frozen iOS formatter (#105242)

* ci: pin frozen iOS formatter

* docs: clarify release CI dispatch

* ci: preserve frozen iOS formatter path

* style: format CI workflow guard
This commit is contained in:
Peter Steinberger
2026-07-12 10:49:26 +01:00
committed by GitHub
parent cfe8019772
commit 265ca345a1
3 changed files with 69 additions and 5 deletions
+42 -2
View File
@@ -2322,6 +2322,8 @@ jobs:
if: needs.preflight.outputs.run_ios_build == 'true'
runs-on: ${{ github.event_name == 'workflow_dispatch' && 'macos-26' || (github.repository == 'openclaw/openclaw' && 'blacksmith-12vcpu-macos-26' || 'macos-26') }}
timeout-minutes: 45
env:
HISTORICAL_TARGET: ${{ needs.preflight.outputs.compatibility_target }}
steps:
- *platform_checkout_step
@@ -2357,9 +2359,47 @@ jobs:
echo "$swift_tools_dir" >> "$GITHUB_PATH"
"$swift_tools_dir/swiftformat" --version
"$swift_tools_dir/swiftlint" version
elif [[ "$HISTORICAL_TARGET" == "true" ]]; then
# The generated Xcode project runs SwiftFormat during the build, so
# frozen targets must keep the formatter contract they were authored for.
brew install xcodegen swiftlint
swiftformat_min_version="$(awk '$1 == "--min-version" { print $2; exit }' config/swiftformat)"
case "$swiftformat_min_version" in
""|0.61.1)
swiftformat_version="0.61.1"
swiftformat_checksum="b990400779aceb7d7020796eb9ba814d4480543f671d38fc0ff48cb72f04c584"
;;
0.62.1)
swiftformat_version="0.62.1"
swiftformat_checksum="7cb1cb1fae04932047c7015441c543848e8e60e1572d808d080e0a1f1661114a"
;;
*)
echo "Unsupported frozen-target SwiftFormat minimum: $swiftformat_min_version" >&2
exit 1
;;
esac
swiftformat_archive="$RUNNER_TEMP/swiftformat-$swiftformat_version.zip"
swift_tools_dir="$RUNNER_TEMP/openclaw-legacy-swift-tools"
curl --fail --location --silent --show-error --retry 3 \
--output "$swiftformat_archive" \
"https://github.com/nicklockwood/SwiftFormat/releases/download/$swiftformat_version/swiftformat.zip"
if [[ "$(shasum -a 256 "$swiftformat_archive" | awk '{print $1}')" != "$swiftformat_checksum" ]]; then
echo "SwiftFormat $swiftformat_version archive checksum mismatch" >&2
exit 1
fi
mkdir -p "$swift_tools_dir"
unzip -q "$swiftformat_archive" -d "$swift_tools_dir"
chmod +x "$swift_tools_dir/swiftformat"
echo "$swift_tools_dir" >> "$GITHUB_PATH"
[[ "$("$swift_tools_dir/swiftformat" --version)" == "$swiftformat_version" ]]
# Legacy generated Xcode phases prepend Homebrew ahead of GITHUB_PATH.
# Point that lookup at the verified binary or the build can bypass the pin.
swiftformat_link="$(brew --prefix)/bin/swiftformat"
ln -sfn "$swift_tools_dir/swiftformat" "$swiftformat_link"
[[ "$("$swiftformat_link" --version)" == "$swiftformat_version" ]]
else
# Frozen release targets before the pinned installer used Homebrew directly.
brew install xcodegen swiftlint swiftformat
echo "Current CI targets must provide scripts/install-swift-tools.sh." >&2
exit 1
fi
- name: Swift lint
+1
View File
@@ -186,6 +186,7 @@ Skills own workflows; root owns hard policy and routing.
- Contributor PRs: parsed context requires authored `What Problem This Solves` and `Evidence` sections. Do not require field-level proof forms; reviewers inspect code, tests, and CI for correctness.
- PR artifacts/screenshots: attach to PR/comment/external artifact store. Never push screenshots, videos, proof images, or proof assets to OpenClaw or any product repo branch, including temp artifact branches. Use Crabbox artifact publishing plus the manifest URL. Do not commit `.github/pr-assets`.
- CI polling: exact SHA, relevant checks only, minimal fields. Skip routine noise (`Auto response`, `Labeler`, docs agents, performance/stale). Logs only after failure/completion or concrete need.
- Trusted-workflow release-branch CI: pass `target_ref` + `release_candidate_ref`; never `release_gate` (requires workflow head == target).
- Agent PR landing to `main`: use only the repo-native `scripts/pr` wrapper: run `scripts/pr review-init <PR>`, follow its emitted checkout/guard guidance, initialize and complete review artifacts with `scripts/pr review-artifacts-init <PR>`, validate them with `scripts/pr review-validate-artifacts <PR>`, then run `OPENCLAW_TESTBOX=1 scripts/pr prepare-run <PR>` and `scripts/pr merge-run <PR>`. The Testbox flag is mandatory for agents so prepare verifies hosted CI/Testbox on the current head or reuses a patch-identical pre-rebase run green within 24 hours instead of running full gates locally. For owner-approved reviewed fork code without hosted Testbox, use `OPENCLAW_PR_GATES_REMOTE=testbox` instead. Do not rebase only because `main` advanced; merge drift is advisory unless strict drift is explicitly enabled, while GitHub still blocks conflicts. Do not idle on `auto-response` or `check-docs`.
## Code
+26 -3
View File
@@ -1567,10 +1567,33 @@ describe("ci workflow guards", () => {
for (const installStep of [macosInstallStep, iosInstallStep]) {
expect(installStep.run).toContain("if [[ -x ./scripts/install-swift-tools.sh ]]; then");
expect(installStep.run).toContain("brew install xcodegen swiftlint");
expect(installStep.run).not.toContain("brew install xcodegen swiftlint swiftformat");
expect(installStep.run).toContain(
"https://github.com/nicklockwood/SwiftFormat/releases/download/$swiftformat_version/swiftformat.zip",
);
expect(installStep.run).toContain(
'swiftformat_checksum="b990400779aceb7d7020796eb9ba814d4480543f671d38fc0ff48cb72f04c584"',
);
expect(installStep.run).toContain(
'swiftformat_checksum="7cb1cb1fae04932047c7015441c543848e8e60e1572d808d080e0a1f1661114a"',
);
expect(installStep.run).toContain(
'[[ "$("$swift_tools_dir/swiftformat" --version)" == "$swiftformat_version" ]]',
);
}
expect(macosInstallStep.run).toContain("brew install xcodegen swiftlint");
expect(macosInstallStep.run).not.toContain("brew install xcodegen swiftlint swiftformat");
expect(iosInstallStep.run).toContain("brew install xcodegen swiftlint swiftformat");
for (const jobName of ["macos-swift", "ios-build"]) {
expect(workflow.jobs[jobName].env.HISTORICAL_TARGET).toBe(
"${{ needs.preflight.outputs.compatibility_target }}",
);
}
expect(iosInstallStep.run).toContain('swiftformat_link="$(brew --prefix)/bin/swiftformat"');
expect(iosInstallStep.run).toContain(
'ln -sfn "$swift_tools_dir/swiftformat" "$swiftformat_link"',
);
expect(iosInstallStep.run).toContain(
'[[ "$("$swiftformat_link" --version)" == "$swiftformat_version" ]]',
);
for (const lintStep of [macosLintStep, iosLintStep]) {
expect(lintStep.run).toContain(
"if [[ -x ./scripts/lint-swift.sh && -x ./scripts/format-swift.sh ]]; then",