forked from ml-explore/mlx-swift-lm
-
Notifications
You must be signed in to change notification settings - Fork 0
233 lines (210 loc) · 9.37 KB
/
Copy pathpull_request.yml
File metadata and controls
233 lines (210 loc) · 9.37 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
name: Build and Test
on: pull_request
permissions:
contents: read
jobs:
lint:
if: github.repository == 'ml-explore/mlx-swift-lm'
runs-on: ubuntu-22.04
container:
image: swift:6.2-rhel-ubi9
steps:
- uses: actions/checkout@v6
with:
submodules: recursive
- name: Setup uv
uses: astral-sh/setup-uv@v6
with:
activate-environment: true
- name: Setup pre-commit
shell: sh
run: |
uv pip install pre-commit
- name: Get swift-format tag
id: swift-format
shell: sh
run: |
# Pinned instead of releases/latest: a new swift-format release can
# change formatting rules and reformat files no PR touched, turning
# the whole-repo `pre-commit run --all` red on every open PR at once.
# Bump this deliberately (with the matching reformat) rather than
# tracking latest. 603.0.0 is what `latest` resolved to at pin time.
echo "SWIFT_FORMAT_VERSION=603.0.0" >> $GITHUB_OUTPUT
- name: Cache swift-format build
uses: actions/cache@v4
id: cache-swift-format
with:
path: /tmp/swift-format/.build
key: ${{ runner.os }}-swift-format-build-${{ steps.swift-format.outputs.SWIFT_FORMAT_VERSION }}
- name: Build swift-format
if: steps.cache-swift-format.outputs.cache-hit != 'true'
shell: sh
run: |
cd /tmp
git clone --branch ${{ steps.swift-format.outputs.SWIFT_FORMAT_VERSION }} --depth 1 https://github.com/swiftlang/swift-format.git
cd swift-format
swift build -c release
- name: Link swift-format to /usr/local/bin
shell: sh
run: |
cd /tmp/swift-format
ln -s "$(swift build --show-bin-path -c release)/swift-format" /usr/local/bin/swift-format
- name: Configure safe directory for git
shell: sh
run: |
git config --global --add safe.directory "$GITHUB_WORKSPACE"
- name: Run style checks
shell: sh
run: |
pre-commit run --all || (echo "Style checks failed, please install pre-commit and run pre-commit run --all and push the change"; echo ""; git --no-pager diff; exit 1)
mac_build_and_test:
needs: lint
if: github.repository == 'ml-explore/mlx-swift-lm'
runs-on: [self-hosted, macos]
steps:
- uses: actions/checkout@v6
with:
submodules: recursive
- name: Verify MetalToolchain installed
shell: bash
run: xcodebuild -showComponent MetalToolchain
- name: Build (Xcode, macOS)
shell: sh
run: |
xcodebuild -version
swift --version
rm -rf ~/Library/Developer/Xcode/DerivedData/*
xcodebuild build-for-testing -skipPackagePluginValidation -scheme mlx-swift-lm-Package -destination 'platform=macOS'
- name: Verify documentation
run: scripts/verify-docs.sh
- name: Run Tests (Xcode, macOS)
shell: sh
run: |
xcrun xctest ~/Library/Developer/Xcode/DerivedData/mlx-swift-lm-*/Build/Products/Debug/MLXLMTests.xctest
- name: Upload test results
if: failure()
uses: actions/upload-artifact@v4
with:
name: test-results
path: |
~/Library/Developer/Xcode/DerivedData/**/Logs/Test/*.xcresult
/Users/runner/Library/Developer/Xcode/DerivedData/**/Logs/Test/*.xcresult
~/Library/Logs/DiagnosticReports/*
retention-days: 7
# Compile the IntegrationTesting project against the macOS 27 SDK.
#
# Two gaps this closes. First, mac_build_and_test above only builds
# `-scheme mlx-swift-lm-Package`, so the IntegrationTesting Xcode project is
# never built on the PR path at all and a change that breaks it merges green
# (see #512, which left seven exhaustive switches over `Generation` unhandled
# in MTPIteratorEndToEndDiagnosticTests.swift). Second, the nightly
# integration_tests.yml pins Xcode 26, where everything behind
# `canImport(FoundationModels, _version: 2)` -- the whole
# MLXFoundationModelsIntegration/ tree and the MLXFoundationModels adapter --
# compiles out and therefore cannot break the build. This job builds both.
#
# This is a COMPILE check, and cannot be anything more on this image. The
# hosted `xcode-27` image carries the macOS 27 SDK on a macOS 26 host, and a
# test bundle built against the 27 SDK cannot run *any* test there: XCTest
# calls objc_copyClassList at startup, which realizes every class including
# the @available(macOS 27, *) `TestResponseStream`, whose metadata instantiates
# AsyncThrowingStream<MLXLanguageModel.Executor.GenerationEvent, Error> and so
# calls through weak-null FoundationModels metadata. The runner segfaults
# during test-suite construction, before any test body or #available guard
# runs, so no `-only-testing:` selection can dodge it. FM runtime coverage
# needs a macOS 27 host, which no hosted image offers yet (see #499).
integration_build_xcode27:
needs: lint
if: github.repository == 'ml-explore/mlx-swift-lm'
# Public preview label, see actions/runner-images#14404.
runs-on: xcode-27
timeout-minutes: 60
steps:
- uses: actions/checkout@v6
with:
submodules: recursive
- name: Report toolchain and host
shell: bash
run: |
xcodebuild -version
swift --version
echo "macOS SDK: $(xcrun --sdk macosx --show-sdk-version)"
sw_vers
# DeviceTier classifies on the *runtime* OS version rather than the
# SDK, so printing it here records why this job builds but does not
# test: on an OS 26 host the FM surface is unavailable at runtime.
case "$(sw_vers -productVersion)" in
27.*|2[89].*|3*) echo "Host DeviceTier would be: full (OS >= 27)" ;;
26.*) echo "Host DeviceTier would be: partial (OS 26): the FM surface is @available(macOS 27, *)" ;;
*) echo "Host DeviceTier would be: absent (OS < 26)" ;;
esac
- name: Assert Xcode 27 and the macOS 27 SDK
shell: bash
run: |
# `xcode-27` is a preview label and its default toolchain has moved
# before. On a 26 SDK the entire `_version: 2` tree compiles out and
# this job goes green while proving nothing, so fail loudly instead.
case "$(xcodebuild -version | head -1)" in
"Xcode 27"*) ;;
*)
echo "::error::Expected Xcode 27, got '$(xcodebuild -version | head -1)' (DEVELOPER_DIR=${DEVELOPER_DIR:-default})."
exit 1
;;
esac
case "$(xcrun --sdk macosx --show-sdk-version)" in
27.*) ;;
*)
echo "::error::Expected the macOS 27 SDK, got $(xcrun --sdk macosx --show-sdk-version). The MLXFoundationModels sources are gated on canImport(FoundationModels, _version: 2) and would compile out."
exit 1
;;
esac
- name: Install MetalToolchain
shell: bash
run: |
# The self-hosted mac is provisioned with this already, so the jobs
# above only assert it. The hosted image ships WITHOUT it, and
# mlx-swift compiles .metal sources during the build (mlx-swift_Cmlx).
#
# Parse `Status:` rather than trusting the exit code: -showComponent
# exits 0 and prints "Status: uninstalled" when the component is
# absent, so an exit-code guard silently succeeds and the build then
# dies much later on the first CompileMetalFile with
# "cannot execute tool 'metal'".
component_status() {
xcodebuild -showComponent MetalToolchain 2>&1 \
| awk -F': *' '/^Status:/ { print tolower($2); exit }'
}
if [ "$(component_status)" = "installed" ]; then
echo "MetalToolchain installed."
else
echo "MetalToolchain reports '$(component_status)'; downloading (839 MB)."
xcodebuild -downloadComponent MetalToolchain
if [ "$(component_status)" != "installed" ]; then
echo "::error::MetalToolchain still reports '$(component_status)' after -downloadComponent."
exit 1
fi
echo "MetalToolchain installed."
fi
- name: Build IntegrationTesting for testing (Xcode, macOS)
shell: bash
run: |
# `build-for-testing` rather than `test`: this compiles both the
# ungated suites and the `_version: 2` tree, which is the coverage this
# job exists for. Running them is not an option here (see the crash
# described above), and a cold-cache `xcodebuild test` would also spend
# 2-3 hours downloading Hugging Face models.
xcodebuild build-for-testing \
-project IntegrationTesting/IntegrationTesting.xcodeproj \
-scheme IntegrationTesting \
-destination 'platform=macOS' \
-skipPackagePluginValidation \
-resultBundlePath IntegrationTesting-build.xcresult
- name: Upload results
if: failure()
uses: actions/upload-artifact@v4
with:
name: integration-build-xcode27-results
path: |
IntegrationTesting-build.xcresult
~/Library/Logs/DiagnosticReports/*
retention-days: 7