name: CI
on:
  push:
    branches: [main]
    tags-ignore: [dev]
  pull_request:
    branches: [main]
defaults:
  run:
    shell: bash

# Cancel any in-flight jobs for the same PR/branch so there's only one active
# at a time
concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

permissions:
  contents: read #  to fetch code (actions/checkout)

jobs:
  # Check Code style quickly by running `rustfmt` over all code
  rustfmt:
    name: Rustfmt
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - run: rustup update --no-self-update stable && rustup default stable
    - run: rustup component add rustfmt
    - run: cargo fmt --all -- --check

  # Run `cargo check` over everything
  check:
    name: Check
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - run: rustup update --no-self-update stable && rustup default stable
    - run: cargo check --all

  # Run `cargo clippy` over everything
  clippy:
    name: Clippy
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - run: rustup update --no-self-update stable && rustup default stable
    - run: rustup target add wasm32-unknown-unknown
    - run: cargo clippy --no-deps --all-features -p wasm-bindgen-backend -- -D warnings
    - run: cargo clippy --no-deps --all-features -p wasm-bindgen-cli -- -D warnings
    - run: cargo clippy --no-deps --all-features -p wasm-bindgen-cli-support -- -D warnings
    - run: cargo clippy --no-deps --all-features -p example-tests -- -D warnings
    - run: cargo clippy --no-deps --all-features -p wasm-bindgen-externref-xform -- -D warnings
    - run: cargo clippy --no-deps --all-features --target wasm32-unknown-unknown -p wasm-bindgen-futures -- -D warnings
    - run: cargo clippy --no-deps --all-features --target wasm32-unknown-unknown -p js-sys -- -D warnings
    - run: cargo clippy --no-deps --all-features -p wasm-bindgen-macro -- -D warnings
    - run: cargo clippy --no-deps --all-features -p wasm-bindgen-macro-support -- -D warnings
    - run: cargo clippy --no-deps --all-features -p wasm-bindgen-multi-value-xform -- -D warnings
    - run: cargo clippy --no-deps --all-features -p wasm-bindgen-shared -- -D warnings
    - run: cargo clippy --no-deps --all-features --target wasm32-unknown-unknown -p wasm-bindgen-test -- -D warnings
    - run: cargo clippy --no-deps --all-features -p wasm-bindgen-test-macro -- -D warnings
    - run: cargo clippy --no-deps --all-features -p wasm-bindgen-threads-xform -- -D warnings
    - run: cargo clippy --no-deps --all-features --target wasm32-unknown-unknown -p typescript-tests -- -D warnings
    - run: cargo clippy --no-deps --all-features -p wasm-bindgen-wasm-conventions -- -D warnings
    - run: cargo clippy --no-deps --all-features -p wasm-bindgen-wasm-interpreter -- -D warnings
    - run: cargo clippy --no-deps --all-features -p wasm-bindgen-webidl -- -D warnings
    - run: cargo clippy --no-deps --all-features -p webidl-tests -- -D warnings
    - run: cargo clippy --no-deps --all-features --target wasm32-unknown-unknown -p web-sys -- -D warnings
    - run: cargo clippy --no-deps --all-features --target wasm32-unknown-unknown -- -D warnings
    - run: cargo clippy --no-deps --all-features --target wasm32-unknown-unknown --tests -- -D warnings
    - run: cargo clippy --no-deps --all-features --target wasm32-unknown-unknown -p wasm-bindgen-benchmark -- -D warnings
    - run: for i in examples/*/; do cd "$i"; cargo +stable clippy --no-deps --all-features --target wasm32-unknown-unknown -- -D warnings || exit 1; cd ../..; done

  test_wasm_bindgen:
    name: "Run wasm-bindgen crate tests (unix)"
    runs-on: ubuntu-latest
    env:
      WASM_BINDGEN_SPLIT_LINKED_MODULES: 1
    steps:
    - uses: actions/checkout@v3
    - run: rustup update --no-self-update stable && rustup default stable
    - run: rustup target add wasm32-unknown-unknown
    - uses: actions/setup-node@v3
      with:
        node-version: '20'
    - uses: ./.github/actions/setup-geckodriver
    - run: cargo test --target wasm32-unknown-unknown
    - run: cargo test --target wasm32-unknown-unknown --features serde-serialize
    - run: cargo test --target wasm32-unknown-unknown --features enable-interning
    - run: cargo test --target wasm32-unknown-unknown -p wasm-bindgen-futures
    - run: cargo test --target wasm32-unknown-unknown --test wasm
      env:
        WASM_BINDGEN_WEAKREF: 1
    - run: cargo test --target wasm32-unknown-unknown --test wasm
      env:
        WASM_BINDGEN_WEAKREF: 1
        WASM_BINDGEN_NO_DEBUG: 1
    - run: cargo test --target wasm32-unknown-unknown --test wasm --features serde-serialize
      env:
        WASM_BINDGEN_WEAKREF: 1
    - run: cargo test --target wasm32-unknown-unknown
      env:
        WASM_BINDGEN_EXTERNREF: 1
    - run: cargo test --target wasm32-unknown-unknown
      env:
        WASM_BINDGEN_MULTI_VALUE: 1

  test_threads:
    name: "Run wasm-bindgen crate tests with multithreading enabled"
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - run: rustup default nightly-2023-05-08
    - run: rustup target add wasm32-unknown-unknown
    - run: rustup component add rust-src
    # Note: we only run the browser tests here, because wasm-bindgen doesn't support threading in Node yet.
    - run: |
        RUSTFLAGS='-C target-feature=+atomics,+bulk-memory,+mutable-globals' \
          cargo test --target wasm32-unknown-unknown --test headless -Z build-std=std,panic_abort

  # I don't know why this is failing so comment this out for now, but ideally
  # this would be figured out at some point and solved.
  # test_wasm_bindgen_windows:
  #   name: "Run wasm-bindgen crate tests (Windows)"
  #   runs-on: windows-latest
  #   steps:
  #   - uses: actions/checkout@v3
  #   - run: rustup update --no-self-update stable && rustup default stable
  #   - run: rustup target add wasm32-unknown-unknown
  #   - uses: actions/setup-node@v3
  #     with:
  #       node-version: '20'
  #   - uses: ./.github/actions/setup-geckodriver
  #   - run: cargo test --target wasm32-unknown-unknown
  #     env:
  #       RUST_LOG: wasm_bindgen_test_runner
  #       GECKODRIVER_ARGS: --log trace
  #   - run: cargo test --target wasm32-unknown-unknown -p js-sys
  #   - run: cargo test --target wasm32-unknown-unknown -p webidl-tests
  #     env:
  #       WBINDGEN_I_PROMISE_JS_SYNTAX_WORKS_IN_NODE: 1
  #   - run: cargo build --manifest-path crates/web-sys/Cargo.toml --target wasm32-unknown-unknown --features "Node Window Document"

  test_native:
    name: Run native tests
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - run: rustup update --no-self-update stable && rustup default stable
    - run: rustup target add wasm32-unknown-unknown
    - uses: actions/setup-node@v3
      with:
        node-version: '20'
    - run: cargo test
    - run: cargo test -p wasm-bindgen-cli-support
    - run: cargo test -p wasm-bindgen-cli
    - run: cargo test -p wasm-bindgen-externref-xform
    - run: cargo test -p wasm-bindgen-macro-support
    - run: cargo test -p wasm-bindgen-multi-value-xform
    - run: cargo test -p wasm-bindgen-wasm-interpreter
    - run: cargo test -p wasm-bindgen-futures
    - run: cargo test -p wasm-bindgen-shared

  test_web_sys:
    name: "Run web-sys crate tests"
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - run: rustup update --no-self-update stable && rustup default stable
    - run: rustup target add wasm32-unknown-unknown
    - uses: actions/setup-node@v3
      with:
        node-version: '20'
    - uses: ./.github/actions/setup-geckodriver
    - run: cargo build --manifest-path crates/web-sys/Cargo.toml --target wasm32-unknown-unknown
    - run: cargo build --manifest-path crates/web-sys/Cargo.toml --target wasm32-unknown-unknown --features Node
    - run: cargo build --manifest-path crates/web-sys/Cargo.toml --target wasm32-unknown-unknown --features Element
    - run: cargo build --manifest-path crates/web-sys/Cargo.toml --target wasm32-unknown-unknown --features Window
    - run: cargo test --manifest-path crates/web-sys/Cargo.toml --target wasm32-unknown-unknown --all-features
    - run: cargo test --manifest-path crates/web-sys/Cargo.toml --target wasm32-unknown-unknown --all-features
      env:
        RUSTFLAGS: --cfg=web_sys_unstable_apis

  check_web_sys:
    name: "Verify that web-sys is compiled correctly"
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - run: rustup update --no-self-update stable && rustup default stable
    - run: cd crates/web-sys && cargo run --release --package wasm-bindgen-webidl -- webidls src/features ./Cargo.toml
    - run: git diff --exit-code

  test_js_sys:
    name: "Run js-sys crate tests"
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - run: rustup update --no-self-update stable && rustup default stable
    - run: rustup target add wasm32-unknown-unknown
    - uses: actions/setup-node@v3
      with:
        node-version: '20'
    - uses: ./.github/actions/setup-geckodriver
    - run: cargo test -p js-sys --target wasm32-unknown-unknown
    - run: cargo test -p js-sys --target wasm32-unknown-unknown
      env:
        RUSTFLAGS: --cfg=js_sys_unstable_apis

  test_webidl:
    name: "Run wasm-bindgen-webidl crate tests"
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - run: rustup update --no-self-update stable && rustup default stable
    - run: rustup target add wasm32-unknown-unknown
    - uses: actions/setup-node@v3
      with:
        node-version: '20'
    - run: cargo test -p wasm-bindgen-webidl
    - run: cargo test -p webidl-tests --target wasm32-unknown-unknown
      env:
        WBINDGEN_I_PROMISE_JS_SYNTAX_WORKS_IN_NODE: 1
    - run: cargo test -p webidl-tests --target wasm32-unknown-unknown
      env:
        RUSTFLAGS: --cfg=web_sys_unstable_apis

  test_typescript_output:
    name: "Test TypeScript output of wasm-bindgen"
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - run: rustup update --no-self-update stable && rustup default stable
    - run: rustup target add wasm32-unknown-unknown
    - uses: actions/setup-node@v3
      with:
        node-version: '20'
    - run: cd crates/typescript-tests && ./run.sh

  test_deno:
    name: "Build and test the deno example"
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - run: rustup update --no-self-update stable && rustup default stable
    - run: rustup target add wasm32-unknown-unknown
    - uses: denoland/setup-deno@v1
      with:
        deno-version: v1.x
    - run: cd examples/deno && ./build.sh && deno run --allow-read test.ts

  test_ui:
    name: Run UI compile-fail tests
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - run: rustup update --no-self-update 1.69.0 && rustup default 1.69.0
    - run: cargo test -p wasm-bindgen-macro
    - run: cargo test -p wasm-bindgen-test-macro

  build_examples:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - run: rustup update --no-self-update stable && rustup default stable
    - run: rustup target add wasm32-unknown-unknown
    - run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh -s -- -f
    - run: |
        curl -L https://github.com/WebAssembly/binaryen/releases/download/version_112/binaryen-version_112-x86_64-linux.tar.gz -sSf > binaryen-version_112-x86_64-linux.tar.gz
        tar -xz -f binaryen-version_112-x86_64-linux.tar.gz binaryen-version_112/bin/wasm2js
        echo "$PWD/binaryen-version_112/bin" >> $GITHUB_PATH
    - run: |
        cargo build -p wasm-bindgen-cli
        ln -snf `pwd`/target/debug/wasm-bindgen $(dirname `which cargo`)/wasm-bindgen
    - run: mv _package.json package.json && npm install && rm package.json
    - run: |
        for dir in `ls examples | grep -v README | grep -v raytrace | grep -v deno | grep -v wasm-audio-worklet`; do
          (cd examples/$dir &&
            (npm run build -- --output-path ../../exbuild/$dir ||
              (./build.sh && mkdir -p ../../exbuild/$dir && cp -r ./* ../../exbuild/$dir && rm ../../exbuild/$dir/**/.gitignore))
          ) || exit 1;
        done
      env:
        RUSTFLAGS: --cfg=web_sys_unstable_apis
    - uses: actions/upload-artifact@v3
      with:
        name: examples1
        path: exbuild

  build_nightly:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - run: rustup default nightly-2023-05-08
    - run: rustup target add wasm32-unknown-unknown
    - run: rustup component add rust-src
    - run: |
        for dir in raytrace-parallel wasm-audio-worklet; do
          (cd examples/$dir &&
            ./build.sh && mkdir -p ../../exbuild/$dir && cp -r ./* ../../exbuild/$dir
          ) || exit 1;
        done
    - uses: actions/upload-artifact@v3
      with:
        name: examples2
        path: exbuild

  test_examples:
    needs:
    - build_examples
    - build_nightly
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - uses: actions/download-artifact@v3
      with:
        name: examples1
        path: exbuild
    - uses: actions/download-artifact@v3
      with:
        name: examples2
        path: exbuild
    - run: rustup update --no-self-update stable && rustup default stable
    - run: cargo test -p example-tests
      env:
        EXBUILD: ${{ github.workspace }}/exbuild

  build_benchmarks:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - run: rustup update --no-self-update stable && rustup default stable
    - run: rustup target add wasm32-unknown-unknown
    - run: cargo build --manifest-path benchmarks/Cargo.toml --release --target wasm32-unknown-unknown
    - run: cargo run -p wasm-bindgen-cli -- target/wasm32-unknown-unknown/release/wasm_bindgen_benchmark.wasm --out-dir benchmarks/pkg --target web
    - uses: actions/upload-artifact@v3
      with:
        name: benchmarks
        path: benchmarks

  dist_linux_x86_64_musl:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - run: rustup update --no-self-update stable && rustup default stable
    - run: rustup target add x86_64-unknown-linux-musl
    - run: sudo apt update -y && sudo apt install musl-tools -y
    - run: |
        cargo build --manifest-path crates/cli/Cargo.toml --target x86_64-unknown-linux-musl --features vendored-openssl --release
        strip -g target/x86_64-unknown-linux-musl/release/wasm-bindgen
        strip -g target/x86_64-unknown-linux-musl/release/wasm-bindgen-test-runner
        strip -g target/x86_64-unknown-linux-musl/release/wasm2es6js
    - uses: actions/upload-artifact@v3
      with:
        name: dist_linux_x86_64_musl
        path: "target/x86_64-unknown-linux-musl/release/wasm*"

  dist_linux_aarch64_gnu:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - run: rustup update --no-self-update stable && rustup default stable
    - run: rustup target add aarch64-unknown-linux-gnu
    - run: sudo apt update -y && sudo apt install gcc-aarch64-linux-gnu -y
    - run: |
        cargo build --manifest-path crates/cli/Cargo.toml --target aarch64-unknown-linux-gnu --features vendored-openssl --release
      env:
        CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc
    - uses: actions/upload-artifact@v3
      with:
        name: dist_linux_aarch64_gnu
        path: "target/aarch64-unknown-linux-gnu/release/wasm*"

  dist_macos_x86_64:
    runs-on: macos-latest
    steps:
    - uses: actions/checkout@v3
    - run: rustup update --no-self-update stable && rustup default stable
    - run: cargo build --manifest-path crates/cli/Cargo.toml --release
      env:
        MACOSX_DEPLOYMENT_TARGET: 10.7
    - uses: actions/upload-artifact@v3
      with:
        name: dist_macos_x86_64
        path: "target/release/wasm*"

  dist_macos_aarch64:
    runs-on: macos-latest
    steps:
    - uses: actions/checkout@v3
    - run: rustup update --no-self-update stable && rustup default stable
    - run: rustup target add aarch64-apple-darwin
    - run: |
        cargo build --manifest-path crates/cli/Cargo.toml --target aarch64-apple-darwin --release
      env:
        MACOSX_DEPLOYMENT_TARGET: 10.7
    - uses: actions/upload-artifact@v3
      with:
        name: dist_macos_aarch64
        path: "target/aarch64-apple-darwin/release/wasm*"

  dist_windows:
    runs-on: windows-latest
    steps:
    - uses: actions/checkout@v3
    - run: rustup update --no-self-update stable && rustup default stable
    - run: cargo build --manifest-path crates/cli/Cargo.toml --release
      env:
        RUSTFLAGS: -Ctarget-feature=+crt-static
    - uses: actions/upload-artifact@v3
      with:
        name: dist_windows
        path: "target/release/wasm*"

  doc_book:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - run: |
        curl -L https://github.com/rust-lang/mdBook/releases/download/v0.4.28/mdbook-v0.4.28-x86_64-unknown-linux-gnu.tar.gz | tar xzf -
        echo $PWD >> $GITHUB_PATH
    - run: (cd guide && mdbook build)
    - uses: actions/upload-artifact@v3
      with:
        name: doc_book
        path: guide/book/html

  doc_api:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - run: rustup update --no-self-update nightly && rustup default nightly
    - run: cargo doc --no-deps --features 'serde-serialize'
    - run: cargo doc --no-deps --manifest-path crates/js-sys/Cargo.toml
    - run: cargo doc --no-deps --manifest-path crates/web-sys/Cargo.toml --all-features
      env:
        RUSTDOCFLAGS: --cfg=web_sys_unstable_apis
    - run: cargo doc --no-deps --manifest-path crates/futures/Cargo.toml
    - run: tar czvf docs.tar.gz target/doc
    - uses: actions/upload-artifact@v3
      with:
        name: doc_api
        path: docs.tar.gz


  deploy:
    permissions:
      contents: write #  to push changes in repo (jamesives/github-pages-deploy-action)

    needs:
      - doc_api
      - doc_book
      - dist_linux_x86_64_musl
      - dist_linux_aarch64_gnu
      - dist_macos_x86_64
      - dist_macos_aarch64
      - dist_windows
      - build_examples
      - build_nightly
      - build_benchmarks
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
      with:
        fetch-depth: 0
    - run: rustup update --no-self-update nightly && rustup default nightly
    - uses: actions/download-artifact@v3
      with:
        path: artifacts
    - run: find artifacts
    - run: |
        set -ex
        mkdir -p gh-release
        tag=`git describe --tags`
        mk() {
          target=$1
          src=$2
          name=wasm-bindgen-$tag-$target
          mkdir -p tmp/$name
          rm -f artifacts/$src/*.d
          rm -f artifacts/$src/*.pdb
          cp README.md \
            LICENSE-MIT \
            LICENSE-APACHE \
            artifacts/$src/wasm* \
            tmp/$name/
          chmod +x tmp/$name/wasm*
          tar czvf gh-release/$name.tar.gz -C tmp $name
          sha256sum gh-release/$name.tar.gz > gh-release/$name.tar.gz.sha256sum
        }
        mk x86_64-unknown-linux-musl dist_linux_x86_64_musl
        mk aarch64-unknown-linux-gnu dist_linux_aarch64_gnu
        mk x86_64-apple-darwin dist_macos_x86_64
        mk aarch64-apple-darwin dist_macos_aarch64
        mk x86_64-pc-windows-msvc dist_windows
    - uses: actions/upload-artifact@v3
      with:
        name: gh-release
        path: gh-release
    - run: |
        mv artifacts/doc_book gh-pages
        tar xf artifacts/doc_api/docs.tar.gz
        mv target/doc gh-pages/api
        mv artifacts/examples1 gh-pages/exbuild
        mv artifacts/examples2/* gh-pages/exbuild
        mv artifacts/benchmarks gh-pages/benchmarks
        tar czf gh-pages.tar.gz gh-pages
    - uses: actions/upload-artifact@v3
      with:
        name: gh-pages
        path: gh-pages.tar.gz
    - uses: JamesIves/github-pages-deploy-action@v4.4.1
      with:
        branch: gh-pages
        folder: gh-pages
        single-commit: true
      if: github.event_name == 'push' && github.ref == 'refs/heads/main'
    - uses: softprops/action-gh-release@v1
      if: startsWith(github.ref, 'refs/tags/')
      with:
        files: "gh-release/*.tar.gz*"
