name: ci on: pull_request: paths-ignore: - "CHANGELOG.md" - "docs/**" push: branches: - main workflow_dispatch: env: CARGO_TERM_COLOR: always RUSTFLAGS: "-D warnings" CARGO_INCREMENTAL: 0 CARGO_PROFILE_DEV_DEBUG: 0 CARGO_PROFILE_TEST_DEBUG: 0 CROSS_CONTAINER_UID: 0 permissions: contents: read concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} cancel-in-progress: true jobs: test: name: test runs-on: ${{ matrix.os }} timeout-minutes: 30 strategy: fail-fast: false matrix: toolchain: [stable] target: - x86_64-unknown-linux-gnu - x86_64-unknown-linux-musl - aarch64-unknown-linux-gnu - aarch64-unknown-linux-musl - x86_64-apple-darwin - x86_64-pc-windows-msvc include: - os: ubuntu-latest target: x86_64-unknown-linux-gnu binary: x86-64 cargo-tool: cargo run-integration-tests: true - os: ubuntu-latest target: x86_64-unknown-linux-musl binary: x86-64 cargo-tool: cross run-integration-tests: true - os: ubuntu-latest target: aarch64-unknown-linux-gnu binary: aarch64 cargo-tool: cross run-integration-tests: false # Cannot run aarch64 binaries on x86_64 - os: ubuntu-latest target: aarch64-unknown-linux-musl binary: aarch64 cargo-tool: cross run-integration-tests: false # Cannot run aarch64 binaries on x86_64 - os: macos-15-intel # intel target: x86_64-apple-darwin binary: x86_64 cargo-tool: cargo run-integration-tests: true - os: macos-latest # aarch64 toolchain: stable target: aarch64-apple-darwin binary: arm64 cargo-tool: cargo run-integration-tests: true - os: windows-2022 target: x86_64-pc-windows-msvc binary: x86-64 cargo-tool: cargo run-integration-tests: true steps: - name: Checkout repository uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false - name: Install musl-tools incl. musl-gcc uses: awalsh128/cache-apt-pkgs-action@5513791f75b039e2a79653b1a92238d3fb8d99b4 # v1.6.2 with: # musl-tools provide `musl-gcc` which is required for `ring` which is required for `rustls` et al. packages: musl-tools version: 1.1 if: ${{ matrix.target == 'x86_64-unknown-linux-musl'}} - name: Install Rust toolchain uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable with: toolchain: ${{ matrix.toolchain }} target: ${{ matrix.target }} - name: Install Erlang uses: erlef/setup-beam@fc68ffb90438ef2936bbb3251622353b3dcb2f93 # v1.24.0 with: otp-version: "29" elixir-version: "1.19" rebar3-version: "3" - name: Setup Node uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: "25" - name: Setup Deno uses: denoland/setup-deno@667a34cdef165d8d2b2e98dde39547c9daac7282 # v2.0.4 with: deno-version: "2.2" - name: Setup Bun uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 with: bun-version: "1.2" - name: Handle Rust dependencies caching uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 with: key: v1-${{ matrix.target }} - name: Install Gleam uses: clechasseur/rs-cargo@b897b7d2f083c6274295825fdbd5a39b825c3f82 # v5.0.6 with: command: install args: "--path gleam-bin --target ${{ matrix.target }} --debug --locked --force" tool: ${{ matrix.cargo-tool }} if: ${{ matrix.run-integration-tests }} - name: Verify binary architecture shell: bash run: | BINARY_PATH="${CARGO_HOME}/bin/gleam" if [[ "${{ matrix.target }}" == *"windows"* ]]; then BINARY_PATH="${BINARY_PATH}.exe" fi if ! file -b "$BINARY_PATH" | grep -q "${{ matrix.binary }}"; then echo "error: Architecture mismatch" echo "Expected architecture: '${{ matrix.binary }}'" echo "Found binary type: '$(file -b "$BINARY_PATH")'" exit 1 fi echo "ok: Architecture match" if: ${{ matrix.run-integration-tests }} - name: Run tests uses: clechasseur/rs-cargo@b897b7d2f083c6274295825fdbd5a39b825c3f82 # v5.0.6 with: command: test # We only want to run `test-{output,commands}` when running integration tests. # There's a caveat though: when `cargo-tool` is `cross` it uses a container # and would result in these integration tests failing due to not finding # the escript binary. So, in case `cargo-tool != cargo` we'll skip the # `test-output` tests as well. args: >- --workspace --target ${{ matrix.target }} ${{ ((matrix.run-integration-tests && matrix.cargo-tool == 'cargo') && ' ') || '--exclude test-output --exclude test-commands' }} tool: ${{ matrix.cargo-tool }} - name: test/project_erlang (non-windows) run: | gleam run && cd src && gleam run && cd .. gleam check gleam test && cd src && gleam test && cd .. gleam docs build working-directory: ./test/project_erlang if: ${{ runner.os != 'Windows' && matrix.run-integration-tests }} - name: test/project_erlang (windows) run: | gleam run && cd src && gleam run && cd .. gleam check gleam test && cd src && gleam test && cd .. gleam docs build working-directory: ./test/project_erlang_windows if: ${{ runner.os == 'Windows' && matrix.run-integration-tests }} - name: test/project_erlang export erlang-shipment (non-windows) run: | gleam export erlang-shipment ./build/erlang-shipment/entrypoint.sh run working-directory: ./test/project_erlang if: ${{ runner.os != 'Windows' && matrix.run-integration-tests }} - name: test/project_erlang export erlang-shipment (windows) run: | gleam export erlang-shipment .\build\erlang-shipment\entrypoint.ps1 run working-directory: ./test/project_erlang_windows if: ${{ runner.os == 'Windows' && matrix.run-integration-tests }} - name: test/project_erlang export package-interface (non-windows) run: | gleam export package-interface --out="interface.json" cat interface.json working-directory: ./test/project_erlang if: ${{ runner.os != 'Windows' && matrix.run-integration-tests }} - name: test/project_erlang export package-interface (windows) run: | gleam export package-interface --out="interface.json" cat interface.json working-directory: ./test/project_erlang_windows if: ${{ runner.os == 'Windows' && matrix.run-integration-tests }} - name: test/project_erlang export package-information run: | gleam export package-information --out="gleam.json" cat gleam.json working-directory: ./test/project_erlang if: ${{ matrix.run-integration-tests }} - name: test/external_only_javascript run: ./test.sh working-directory: ./test/external_only_javascript if: ${{ matrix.run-integration-tests }} env: GLEAM_COMMAND: gleam - name: test/external_only_erlang run: ./test.sh working-directory: ./test/external_only_erlang if: ${{ matrix.run-integration-tests }} env: GLEAM_COMMAND: gleam - name: test/root_package_not_compiled_when_running_dep run: ./test.sh working-directory: ./test/root_package_not_compiled_when_running_dep if: ${{ matrix.run-integration-tests }} env: GLEAM_COMMAND: gleam - name: test/erlang_shipment_no_dev_deps run: ./test.sh working-directory: ./test/erlang_shipment_no_dev_deps if: ${{ matrix.run-integration-tests }} env: GLEAM_COMMAND: gleam - name: test/project_javascript run: | gleam run gleam check gleam test gleam docs build working-directory: ./test/project_javascript if: ${{ matrix.run-integration-tests }} - name: test/project_path_deps run: | gleam update gleam check working-directory: ./test/project_path_deps/project_a if: ${{ matrix.run-integration-tests }} - name: test/project_git_deps run: | gleam update gleam check working-directory: ./test/project_git_deps if: ${{ matrix.run-integration-tests }} - name: test/project_git_deps_path run: ./test.sh working-directory: ./test/project_git_deps_path if: ${{ matrix.run-integration-tests }} env: GLEAM_COMMAND: gleam - name: Test project generation run: | gleam new lib_project cd lib_project gleam run gleam test # Test adding of deps gleam add exception # No specifier gleam add gleam_http@4 # Version specifier gleam test # Test documentation generation gleam docs build # Assert that module metadata has been written ls build/dev/erlang/lib_project/_gleam_artefacts/lib_project.cache # Assert that HTML docs and their assets have been written ls build/dev/docs/lib_project/index.html ls build/dev/docs/lib_project/lib_project.html ls build/dev/docs/lib_project/css/atom-one-light.min.css ls build/dev/docs/lib_project/css/atom-one-dark.min.css ls build/dev/docs/lib_project/css/index.css ls build/dev/docs/lib_project/js/highlight.min.js ls build/dev/docs/lib_project/js/highlightjs-gleam.js ls build/dev/docs/lib_project/js/highlightjs-erlang.min.js ls build/dev/docs/lib_project/js/highlightjs-elixir.min.js ls build/dev/docs/lib_project/js/highlightjs-javascript.min.js ls build/dev/docs/lib_project/js/highlightjs-typescript.min.js ls build/dev/docs/lib_project/js/lunr.min.js ls build/dev/docs/lib_project/js/index.js ls build/dev/docs/lib_project/fonts/karla-v23-bold-latin-ext.woff2 ls build/dev/docs/lib_project/fonts/karla-v23-bold-latin.woff2 ls build/dev/docs/lib_project/fonts/karla-v23-regular-latin-ext.woff2 ls build/dev/docs/lib_project/fonts/karla-v23-regular-latin.woff2 ls build/dev/docs/lib_project/fonts/ubuntu-mono-v15-regular-cyrillic-ext.woff2 ls build/dev/docs/lib_project/fonts/ubuntu-mono-v15-regular-cyrillic.woff2 ls build/dev/docs/lib_project/fonts/ubuntu-mono-v15-regular-greek-ext.woff2 ls build/dev/docs/lib_project/fonts/ubuntu-mono-v15-regular-greek.woff2 ls build/dev/docs/lib_project/fonts/ubuntu-mono-v15-regular-latin-ext.woff2 ls build/dev/docs/lib_project/fonts/ubuntu-mono-v15-regular-latin.woff2 ls build/dev/docs/lib_project/fonts/ubuntu-mono-v15-regular-box.woff2 if: ${{ matrix.run-integration-tests }} test-wasm: runs-on: ubuntu-latest timeout-minutes: 30 steps: - name: Checkout repository uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false - name: Install Rust toolchain uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable with: toolchain: stable target: wasm32-unknown-unknown - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: "25" - name: Install wasm-pack run: | curl -sSL https://rustwasm.github.io/wasm-pack/installer/init.sh | sh - name: Run wasm tests run: wasm-pack test --node compiler-wasm rustfmt: name: rustfmt runs-on: ubuntu-latest timeout-minutes: 10 steps: - name: Checkout repository uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false - name: Install Rust toolchain uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable with: toolchain: stable components: rustfmt - run: cargo fmt --all -- --check validate: name: validate runs-on: ubuntu-latest timeout-minutes: 10 steps: - name: Checkout repository uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false - name: Ensure no merge commits uses: NexusPHP/no-merge-commits@109a3342781ddcf26b2fa739f29e8ee9f68b7d8e # v2.4.1 if: github.event_name == 'pull_request' with: token: ${{ secrets.GITHUB_TOKEN }} - name: Install Rust toolchain uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable with: toolchain: stable - name: Install cargo-deny run: | set -e curl -L https://github.com/EmbarkStudios/cargo-deny/releases/download/0.18.6/cargo-deny-0.18.6-x86_64-unknown-linux-musl.tar.gz | tar xzf - mv cargo-deny-*-x86_64-unknown-linux-musl/cargo-deny cargo-deny echo `pwd` >> $GITHUB_PATH - name: Validate deps run: cargo deny check lint-build: name: lint-build runs-on: ubuntu-latest timeout-minutes: 10 steps: - name: Checkout repository uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false - name: Install Rust toolchain uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable with: toolchain: stable components: clippy - name: Handle Rust dependencies caching uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 with: key: v1-linux-gnu - name: Run linter run: cargo clippy --workspace - run: cargo build - name: Upload artifact (Ubuntu) uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: gleam path: target/debug/gleam test-projects: name: test-projects needs: lint-build runs-on: ubuntu-latest timeout-minutes: 10 steps: - name: Checkout repository uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false - name: Install Deno uses: denoland/setup-deno@667a34cdef165d8d2b2e98dde39547c9daac7282 # v2.0.4 with: deno-version: v2.x - name: Install Bun uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 - name: Install Erlang uses: erlef/setup-beam@fc68ffb90438ef2936bbb3251622353b3dcb2f93 # v1.24.0 with: otp-version: "29" elixir-version: "1.19" rebar3-version: "3" - name: Download Gleam binary from previous job uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: gleam path: ./test - name: Configure test projects to use Gleam binary run: | echo $PWD/ >> $GITHUB_PATH chmod +x ./gleam sed -i 's/cargo run --quiet --/gleam/' */Makefile sed -i 's/cargo run --/gleam/' */Makefile working-directory: ./test - name: test/language Erlang run: make clean erlang working-directory: ./test/language - name: test/language JavaScript with NodeJS run: make clean nodejs working-directory: ./test/language - name: test/language JavaScript with Deno run: make clean deno working-directory: ./test/language - name: test/language JavaScript with Bun run: make clean bun working-directory: ./test/language - name: test/compile_package0 run: make working-directory: ./test/compile_package0 - name: test/compile_package1 run: make working-directory: ./test/compile_package1 - name: Test JavaScript prelude run: make working-directory: ./test/javascript_prelude - name: Test generated TypeScript declarations run: make test working-directory: ./test/typescript_declarations - name: Test export of hex tarball run: make test working-directory: ./test/hextarball - name: test/running_modules run: make test-all working-directory: ./test/running_modules - name: test/multi_namespace run: ./test.sh working-directory: ./test/multi_namespace - name: test/multi_namespace_not_top_level run: ./test.sh working-directory: ./test/multi_namespace_not_top_level - name: Test FFI in subdirectories run: make working-directory: ./test/subdir_ffi - name: test/unicode_path run: make working-directory: ./test/unicode_path ⭐ - name: test/assert run: make test-all working-directory: ./test/assert - name: Test publishing with default main run: ./test.sh working-directory: ./test/publishing_default_main - name: Test publishing with src symlink escape run: ./test.sh working-directory: ./test/publishing_src_symlink_escape - name: Test publishing with priv symlink escape run: ./test.sh working-directory: ./test/publishing_priv_symlink_escape