1name: ci
2on:
3 pull_request:
4 push:
5 branches:
6 - main
7 workflow_dispatch:
8
9env:
10 CARGO_TERM_COLOR: always
11 RUSTFLAGS: "-D warnings"
12 CARGO_INCREMENTAL: 0
13 CARGO_PROFILE_DEV_DEBUG: 0
14 CARGO_PROFILE_TEST_DEBUG: 0
15 CROSS_CONTAINER_UID: 0
16
17permissions:
18 contents: read
19
20concurrency:
21 group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
22 cancel-in-progress: true
23
24jobs:
25 test:
26 name: test
27 runs-on: ${{ matrix.os }}
28 timeout-minutes: 30
29 strategy:
30 fail-fast: false
31 matrix:
32 toolchain: [stable]
33 target:
34 - x86_64-unknown-linux-gnu
35 - x86_64-unknown-linux-musl
36 - aarch64-unknown-linux-gnu
37 - aarch64-unknown-linux-musl
38 - x86_64-apple-darwin
39 - x86_64-pc-windows-msvc
40 include:
41 - os: ubuntu-latest
42 target: x86_64-unknown-linux-gnu
43 binary: x86-64
44 cargo-tool: cargo
45 run-integration-tests: true
46 - os: ubuntu-latest
47 target: x86_64-unknown-linux-musl
48 binary: x86-64
49 cargo-tool: cross
50 run-integration-tests: true
51 - os: ubuntu-latest
52 target: aarch64-unknown-linux-gnu
53 binary: aarch64
54 cargo-tool: cross
55 run-integration-tests: false # Cannot run aarch64 binaries on x86_64
56 - os: ubuntu-latest
57 target: aarch64-unknown-linux-musl
58 binary: aarch64
59 cargo-tool: cross
60 run-integration-tests: false # Cannot run aarch64 binaries on x86_64
61 # macos>=14 runs exclusively on aarch64 and will thus fail to execute properly for x64
62 - os: macos-13 # intel
63 target: x86_64-apple-darwin
64 binary: x86_64
65 cargo-tool: cargo
66 run-integration-tests: true
67 - os: macos-latest # aarch64
68 toolchain: stable
69 target: aarch64-apple-darwin
70 binary: arm64
71 cargo-tool: cargo
72 run-integration-tests: true
73 - os: windows-latest
74 target: x86_64-pc-windows-msvc
75 binary: x86-64
76 cargo-tool: cargo
77 run-integration-tests: true
78 steps:
79 - name: Checkout repository
80 uses: actions/checkout@v4
81
82 - name: Install musl-tools incl. musl-gcc
83 uses: awalsh128/cache-apt-pkgs-action@v1.5.0
84 with:
85 # musl-tools provide `musl-gcc` which is required for `ring` which is required for `rustls` et al.
86 packages: musl-tools
87 version: 1.1
88 if: ${{ matrix.target == 'x86_64-unknown-linux-musl'}}
89
90 - name: Install Rust toolchain
91 uses: dtolnay/rust-toolchain@stable
92 with:
93 toolchain: ${{ matrix.toolchain }}
94 target: ${{ matrix.target }}
95
96 - name: Install Erlang (non-macos)
97 uses: erlef/setup-beam@v1
98 with:
99 otp-version: "26.1"
100 elixir-version: "1.16.1"
101 rebar3-version: "3"
102 if: ${{ runner.os != 'macOS' }} # setup-beam does not support macOS
103
104 - name: Install Erlang (macos)
105 run: |
106 brew install erlang rebar3 elixir
107 mix local.hex --force
108 if: ${{ runner.os == 'macOS' }} # setup-beam does not support macOS
109
110 - name: Setup Node
111 uses: actions/setup-node@v4
112 with:
113 node-version: "22"
114
115 - name: Setup Deno
116 uses: denoland/setup-deno@v2
117 with:
118 deno-version: "2.2"
119
120 - name: Setup Bun
121 uses: oven-sh/setup-bun@v2
122 with:
123 bun-version: "1.2"
124
125 - name: Handle Rust dependencies caching
126 uses: Swatinem/rust-cache@v2
127 with:
128 key: v1-${{ matrix.target }}
129
130 - name: Install Gleam
131 uses: clechasseur/rs-cargo@v3
132 with:
133 command: install
134 args: "--path gleam-bin --target ${{ matrix.target }} --debug --locked --force"
135 tool: ${{ matrix.cargo-tool }}
136 if: ${{ matrix.run-integration-tests }}
137
138 - name: Verify binary architecture
139 shell: bash
140 run: |
141 BINARY_PATH="${CARGO_HOME}/bin/gleam"
142 if [[ "${{ matrix.target }}" == *"windows"* ]]; then
143 BINARY_PATH="${BINARY_PATH}.exe"
144 fi
145
146 if ! file -b "$BINARY_PATH" | grep -q "${{ matrix.binary }}"; then
147 echo "error: Architecture mismatch"
148 echo "Expected architecture: '${{ matrix.binary }}'"
149 echo "Found binary type: '$(file -b "$BINARY_PATH")'"
150 exit 1
151 fi
152 echo "ok: Architecture match"
153 if: ${{ matrix.run-integration-tests }}
154
155 - name: Run tests
156 uses: clechasseur/rs-cargo@v3
157 with:
158 command: test
159 # We only want to run the `test-output` when running integration tests.
160 # There's a caveat though: when `cargo-tool` is `cross` it uses a container
161 # and would result in these integration tests failing due to not finding
162 # the escript binary. So, in case `cargo-tool != cargo` we'll skip the
163 # `test-output` tests as well.
164 args: >-
165 --workspace
166 --target ${{ matrix.target }}
167 ${{ ((matrix.run-integration-tests && matrix.cargo-tool == 'cargo')
168 && ' ')
169 || '--exclude test-output' }}
170 tool: ${{ matrix.cargo-tool }}
171
172 - name: test/project_erlang (non-windows)
173 run: |
174 gleam run && cd src && gleam run && cd ..
175 gleam check
176 gleam test && cd src && gleam test && cd ..
177 gleam docs build
178 working-directory: ./test/project_erlang
179 if: ${{ runner.os != 'Windows' && matrix.run-integration-tests }}
180
181 - name: test/project_erlang (windows)
182 run: |
183 gleam run && cd src && gleam run && cd ..
184 gleam check
185 gleam test && cd src && gleam test && cd ..
186 gleam docs build
187 working-directory: ./test/project_erlang_windows
188 if: ${{ runner.os == 'Windows' && matrix.run-integration-tests }}
189
190 - name: test/project_erlang export erlang-shipment (non-windows)
191 run: |
192 gleam export erlang-shipment
193 ./build/erlang-shipment/entrypoint.sh run
194 working-directory: ./test/project_erlang
195 if: ${{ runner.os != 'Windows' && matrix.run-integration-tests }}
196
197 - name: test/project_erlang export erlang-shipment (windows)
198 run: |
199 gleam export erlang-shipment
200 .\build\erlang-shipment\entrypoint.ps1 run
201 working-directory: ./test/project_erlang_windows
202 if: ${{ runner.os == 'Windows' && matrix.run-integration-tests }}
203
204 - name: test/project_erlang export package-interface (non-windows)
205 run: |
206 gleam export package-interface --out="interface.json"
207 cat interface.json
208 working-directory: ./test/project_erlang
209 if: ${{ runner.os != 'Windows' && matrix.run-integration-tests }}
210
211 - name: test/project_erlang export package-interface (windows)
212 run: |
213 gleam export package-interface --out="interface.json"
214 cat interface.json
215 working-directory: ./test/project_erlang_windows
216 if: ${{ runner.os == 'Windows' && matrix.run-integration-tests }}
217
218 - name: test/project_erlang export package-information
219 run: |
220 gleam export package-information --out="gleam.json"
221 cat gleam.json
222 working-directory: ./test/project_erlang
223 if: ${{ matrix.run-integration-tests }}
224
225 - name: test/external_only_javascript
226 run: ./test.sh
227 working-directory: ./test/external_only_javascript
228 if: ${{ matrix.run-integration-tests }}
229 env:
230 GLEAM_COMMAND: gleam
231
232 - name: test/external_only_erlang
233 run: ./test.sh
234 working-directory: ./test/external_only_erlang
235 if: ${{ matrix.run-integration-tests }}
236 env:
237 GLEAM_COMMAND: gleam
238
239 - name: test/root_package_not_compiled_when_running_dep
240 run: ./test.sh
241 working-directory: ./test/root_package_not_compiled_when_running_dep
242 if: ${{ matrix.run-integration-tests }}
243 env:
244 GLEAM_COMMAND: gleam
245
246 - name: test/project_javascript
247 run: |
248 gleam run
249 gleam check
250 gleam test
251 gleam docs build
252 working-directory: ./test/project_javascript
253 if: ${{ matrix.run-integration-tests }}
254
255 - name: test/project_path_deps
256 run: |
257 gleam update
258 gleam check
259 working-directory: ./test/project_path_deps/project_a
260 if: ${{ matrix.run-integration-tests }}
261
262 - name: test/project_git_deps
263 run: |
264 gleam update
265 gleam check
266 working-directory: ./test/project_git_deps
267 if: ${{ matrix.run-integration-tests }}
268
269 - name: Test project generation
270 run: |
271 gleam new lib_project
272 cd lib_project
273 gleam run
274 gleam test
275
276 # Test adding of deps
277 gleam add exception # No specifier
278 gleam add gleam_http@4 # Version specifier
279 gleam test
280
281 # Test documentation generation
282 gleam docs build
283
284 # Assert that module metadata has been written
285 ls build/dev/erlang/lib_project/_gleam_artefacts/lib_project.cache
286
287 # Assert that HTML docs and their assets have been written
288 ls build/dev/docs/lib_project/index.html
289 ls build/dev/docs/lib_project/lib_project.html
290 ls build/dev/docs/lib_project/css/atom-one-light.min.css
291 ls build/dev/docs/lib_project/css/atom-one-dark.min.css
292 ls build/dev/docs/lib_project/css/index.css
293 ls build/dev/docs/lib_project/js/highlight.min.js
294 ls build/dev/docs/lib_project/js/highlightjs-gleam.js
295 ls build/dev/docs/lib_project/js/highlightjs-erlang.min.js
296 ls build/dev/docs/lib_project/js/highlightjs-elixir.min.js
297 ls build/dev/docs/lib_project/js/highlightjs-javascript.min.js
298 ls build/dev/docs/lib_project/js/highlightjs-typescript.min.js
299 ls build/dev/docs/lib_project/js/lunr.min.js
300 ls build/dev/docs/lib_project/js/index.js
301 ls build/dev/docs/lib_project/fonts/karla-v23-bold-latin-ext.woff2
302 ls build/dev/docs/lib_project/fonts/karla-v23-bold-latin.woff2
303 ls build/dev/docs/lib_project/fonts/karla-v23-regular-latin-ext.woff2
304 ls build/dev/docs/lib_project/fonts/karla-v23-regular-latin.woff2
305 ls build/dev/docs/lib_project/fonts/ubuntu-mono-v15-regular-cyrillic-ext.woff2
306 ls build/dev/docs/lib_project/fonts/ubuntu-mono-v15-regular-cyrillic.woff2
307 ls build/dev/docs/lib_project/fonts/ubuntu-mono-v15-regular-greek-ext.woff2
308 ls build/dev/docs/lib_project/fonts/ubuntu-mono-v15-regular-greek.woff2
309 ls build/dev/docs/lib_project/fonts/ubuntu-mono-v15-regular-latin-ext.woff2
310 ls build/dev/docs/lib_project/fonts/ubuntu-mono-v15-regular-latin.woff2
311 if: ${{ matrix.run-integration-tests }}
312
313 test-wasm:
314 runs-on: ubuntu-latest
315 timeout-minutes: 30
316 steps:
317 - name: Checkout repository
318 uses: actions/checkout@v4
319
320 - name: Install Rust toolchain
321 uses: dtolnay/rust-toolchain@stable
322 with:
323 toolchain: stable
324 target: wasm32-unknown-unknown
325
326 - uses: actions/setup-node@v4
327 with:
328 node-version: "22"
329
330 - name: Install wasm-pack
331 run: |
332 curl -sSL https://rustwasm.github.io/wasm-pack/installer/init.sh | sh
333
334 - name: Run wasm tests
335 run: wasm-pack test --node compiler-wasm
336
337 rustfmt:
338 name: rustfmt
339 runs-on: ubuntu-latest
340 timeout-minutes: 10
341 steps:
342 - name: Checkout repository
343 uses: actions/checkout@v4
344
345 - name: Install Rust toolchain
346 uses: dtolnay/rust-toolchain@stable
347 with:
348 toolchain: stable
349 components: rustfmt
350
351 - run: cargo fmt --all -- --check
352
353 validate:
354 name: validate
355 runs-on: ubuntu-latest
356 timeout-minutes: 10
357 steps:
358 - name: Checkout repository
359 uses: actions/checkout@v4
360
361 - name: Ensure no merge commits
362 uses: NexusPHP/no-merge-commits@v2.2.1
363 if: github.event_name == 'pull_request'
364 with:
365 token: ${{ secrets.GITHUB_TOKEN }}
366
367 - name: Install Rust toolchain
368 uses: dtolnay/rust-toolchain@stable
369 with:
370 toolchain: stable
371
372 - name: Install cargo-deny
373 run: |
374 set -e
375 curl -L https://github.com/EmbarkStudios/cargo-deny/releases/download/0.14.18/cargo-deny-0.14.18-x86_64-unknown-linux-musl.tar.gz | tar xzf -
376 mv cargo-deny-*-x86_64-unknown-linux-musl/cargo-deny cargo-deny
377 echo `pwd` >> $GITHUB_PATH
378
379 - name: Validate deps
380 run: cargo deny check
381
382 lint-build:
383 name: lint-build
384 runs-on: ubuntu-latest
385 timeout-minutes: 10
386 steps:
387 - name: Checkout repository
388 uses: actions/checkout@v4
389
390 - name: Install Rust toolchain
391 uses: dtolnay/rust-toolchain@stable
392 with:
393 toolchain: stable
394 components: clippy
395
396 - name: Handle Rust dependencies caching
397 uses: Swatinem/rust-cache@v2
398 with:
399 key: v1-linux-gnu
400
401 - name: Run linter
402 run: cargo clippy --workspace
403
404 - run: cargo build
405
406 - name: Upload artifact (Ubuntu)
407 uses: actions/upload-artifact@v4
408 with:
409 name: gleam
410 path: target/debug/gleam
411
412 test-projects:
413 name: test-projects
414 needs: lint-build
415 runs-on: ubuntu-latest
416 timeout-minutes: 10
417 steps:
418 - name: Checkout repository
419 uses: actions/checkout@v4
420
421 - name: Install Deno
422 uses: denoland/setup-deno@v2
423 with:
424 deno-version: v2.x
425
426 - name: Install Bun
427 uses: oven-sh/setup-bun@v2
428
429 - name: Install Erlang
430 uses: erlef/setup-beam@v1
431 with:
432 otp-version: "26.1"
433 elixir-version: "1.16.1"
434 rebar3-version: "3"
435
436 - name: Download Gleam binary from previous job
437 uses: actions/download-artifact@v4
438 with:
439 name: gleam
440 path: ./test
441
442 - name: Configure test projects to use Gleam binary
443 run: |
444 echo $PWD/ >> $GITHUB_PATH
445 chmod +x ./gleam
446 sed -i 's/cargo run --quiet --/gleam/' */Makefile
447 sed -i 's/cargo run --/gleam/' */Makefile
448 working-directory: ./test
449
450 - name: test/language Erlang
451 run: make clean erlang
452 working-directory: ./test/language
453
454 - name: test/language JavaScript with NodeJS
455 run: make clean nodejs
456 working-directory: ./test/language
457
458 - name: test/language JavaScript with Deno
459 run: make clean deno
460 working-directory: ./test/language
461
462 - name: test/language JavaScript with Bun
463 run: make clean bun
464 working-directory: ./test/language
465
466 - name: test/compile_package0
467 run: make
468 working-directory: ./test/compile_package0
469
470 - name: test/compile_package1
471 run: make
472 working-directory: ./test/compile_package1
473
474 - name: Test JavaScript prelude
475 run: make
476 working-directory: ./test/javascript_prelude
477
478 - name: Test export of hex tarball
479 run: make test
480 working-directory: ./test/hextarball
481
482 - name: Test running modules
483 run: make test-all
484 working-directory: ./test/running_modules
485
486 - name: test/multi_namespace
487 run: ./test.sh
488 working-directory: ./test/multi_namespace
489
490 - name: Test multi namespace bug
491 run: ./test.sh
492 working-directory: ./test/multi_namespace_not_top_level
493
494 - name: Test FFI in subdirectories
495 run: make
496 working-directory: ./test/subdir_ffi
497
498 - name: test/unicode_path
499 run: make
500 working-directory: ./test/unicode_path ⭐
501
502 - name: test/assert
503 run: make test-all
504 working-directory: ./test/assert