name: ci on: pull_request: 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 # macos>=14 runs exclusively on aarch64 and will thus fail to execute properly for x64 - os: macos-13 # 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-latest target: x86_64-pc-windows-msvc binary: x86-64 cargo-tool: cargo run-integration-tests: true steps: - name: Checkout repository uses: actions/checkout@v4 - name: Install musl-tools incl. musl-gcc uses: awalsh128/cache-apt-pkgs-action@v1.5.0 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@stable with: toolchain: ${{ matrix.toolchain }} target: ${{ matrix.target }} - name: Install Erlang (non-macos) uses: erlef/setup-beam@v1 with: otp-version: "26.1" elixir-version: "1.16.1" rebar3-version: "3" if: ${{ runner.os != 'macOS' }} # setup-beam does not support macOS - name: Install Erlang (macos) run: | brew install erlang rebar3 elixir mix local.hex --force if: ${{ runner.os == 'macOS' }} # setup-beam does not support macOS - name: Setup Node uses: actions/setup-node@v4 with: node-version: "22" - name: Setup Deno uses: denoland/setup-deno@v2 with: deno-version: "2.2" - name: Setup Bun uses: oven-sh/setup-bun@v2 with: bun-version: "1.2" - name: Handle Rust dependencies caching uses: Swatinem/rust-cache@v2 with: key: v1-${{ matrix.target }} - name: Install Gleam uses: clechasseur/rs-cargo@v3 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@v3 with: command: test # We only want to run the `test-output` 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' }} 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/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 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 if: ${{ matrix.run-integration-tests }} test-wasm: runs-on: ubuntu-latest timeout-minutes: 30 steps: - name: Checkout repository uses: actions/checkout@v4 - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable with: toolchain: stable target: wasm32-unknown-unknown - uses: actions/setup-node@v4 with: node-version: "22" - 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@v4 - name: Install Rust toolchain uses: dtolnay/rust-toolchain@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@v4 - name: Ensure no merge commits uses: NexusPHP/no-merge-commits@v2.2.1 if: github.event_name == 'pull_request' with: token: ${{ secrets.GITHUB_TOKEN }} - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable with: toolchain: stable - name: Install cargo-deny run: | set -e 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 - 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@v4 - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable with: toolchain: stable components: clippy - name: Handle Rust dependencies caching uses: Swatinem/rust-cache@v2 with: key: v1-linux-gnu - name: Run linter run: cargo clippy --workspace - run: cargo build - name: Upload artifact (Ubuntu) uses: actions/upload-artifact@v4 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@v4 - name: Install Deno uses: denoland/setup-deno@v2 with: deno-version: v2.x - name: Install Bun uses: oven-sh/setup-bun@v2 - name: Install Erlang uses: erlef/setup-beam@v1 with: otp-version: "26.1" elixir-version: "1.16.1" rebar3-version: "3" - name: Download Gleam binary from previous job uses: actions/download-artifact@v4 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 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 bug 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