name: ci
on:
  pull_request:
  push:
    branches:
    - master
  schedule:
  - cron: '00 01 * * *'
jobs:
  test:
    name: test
    env:
      # For some builds, we use cross to test on 32-bit and big-endian
      # systems.
      CARGO: cargo
      # When CARGO is set to CROSS, this is set to `--target matrix.target`.
      TARGET_FLAGS:
      # When CARGO is set to CROSS, TARGET_DIR includes matrix.target.
      TARGET_DIR: ./target
      # Emit backtraces on panics.
      RUST_BACKTRACE: 1
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        build:
        # We test ripgrep on a pinned version of Rust, along with the moving
        # targets of 'stable' and 'beta' for good measure.
        - pinned
        - stable
        - beta
        # Our release builds are generated by a nightly compiler to take
        # advantage of the latest optimizations/compile time improvements. So
        # we test all of them here. (We don't do mips releases, but test on
        # mips for big-endian coverage.)
        - nightly
        - nightly-musl
        - nightly-32
        - nightly-mips
        - nightly-arm
        - macos
        - win-msvc
        - win-gnu
        include:
        - build: pinned
          os: ubuntu-18.04
          rust: 1.41.0
        - build: stable
          os: ubuntu-18.04
          rust: stable
        - build: beta
          os: ubuntu-18.04
          rust: beta
        - build: nightly
          os: ubuntu-18.04
          rust: nightly
        - build: nightly-musl
          os: ubuntu-18.04
          rust: nightly
          target: x86_64-unknown-linux-musl
        - build: nightly-32
          os: ubuntu-18.04
          rust: nightly
          target: i686-unknown-linux-gnu
        - build: nightly-mips
          os: ubuntu-18.04
          rust: nightly
          target: mips64-unknown-linux-gnuabi64
        - build: nightly-arm
          os: ubuntu-18.04
          rust: nightly
          # For stripping release binaries:
          # docker run --rm -v $PWD/target:/target:Z \
          #   rustembedded/cross:arm-unknown-linux-gnueabihf \
          #   arm-linux-gnueabihf-strip \
          #   /target/arm-unknown-linux-gnueabihf/debug/rg
          target: arm-unknown-linux-gnueabihf
        - build: macos
          os: macos-latest
          rust: nightly
        - build: win-msvc
          os: windows-2019
          rust: nightly
        - build: win-gnu
          os: windows-2019
          rust: nightly-x86_64-gnu
    steps:
    - name: Checkout repository
      uses: actions/checkout@v2

    - name: Install packages (Ubuntu)
      if: matrix.os == 'ubuntu-18.04'
      run: |
        ci/ubuntu-install-packages

    - name: Install packages (macOS)
      if: matrix.os == 'macos-latest'
      run: |
        ci/macos-install-packages

    - name: Install Rust
      uses: actions-rs/toolchain@v1
      with:
        toolchain: ${{ matrix.rust }}
        profile: minimal
        override: true

    - name: Use Cross
      if: matrix.target != ''
      run: |
        cargo install cross
        echo "::set-env name=CARGO::cross"
        echo "::set-env name=TARGET_FLAGS::--target ${{ matrix.target }}"
        echo "::set-env name=TARGET_DIR::./target/${{ matrix.target }}"

    - name: Show command used for Cargo
      run: |
        echo "cargo command is: ${{ env.CARGO }}"
        echo "target flag is: ${{ env.TARGET_FLAGS }}"

    - name: Build ripgrep and all crates
      run: ${{ env.CARGO }} build --verbose --all ${{ env.TARGET_FLAGS }}

    - name: Build ripgrep with PCRE2
      run: ${{ env.CARGO }} build --verbose --all --features pcre2 ${{ env.TARGET_FLAGS }}

    # This is useful for debugging problems when the expected build artifacts
    # (like shell completions and man pages) aren't generated.
    - name: Show build.rs stderr
      shell: bash
      run: |
        set +x
        stderr="$(find "${{ env.TARGET_DIR }}/debug" -name stderr -print0 | xargs -0 ls -t | head -n1)"
        if [ -s "$stderr" ]; then
          echo "===== $stderr ===== "
          cat "$stderr"
          echo "====="
        fi
        set -x

    - name: Run tests with PCRE2 (sans cross)
      if: matrix.target == ''
      run: ${{ env.CARGO }} test --verbose --all --features pcre2 ${{ env.TARGET_FLAGS }}

    - name: Run tests without PCRE2 (with cross)
      # These tests should actually work, but they almost double the runtime.
      # Every integration test spins up qemu to run 'rg', and when PCRE2 is
      # enabled, every integration test is run twice: one with the default
      # regex engine and once with PCRE2.
      if: matrix.target != ''
      run: ${{ env.CARGO }} test --verbose --all ${{ env.TARGET_FLAGS }}

    - name: Test for existence of build artifacts (Windows)
      if: matrix.os == 'windows-2019'
      shell: bash
      run: |
        outdir="$(ci/cargo-out-dir "${{ env.TARGET_DIR }}")"
        ls "$outdir/_rg.ps1" && file "$outdir/_rg.ps1"

    - name: Test for existence of build artifacts (Unix)
      if: matrix.os != 'windows-2019'
      shell: bash
      run: |
        outdir="$(ci/cargo-out-dir "${{ env.TARGET_DIR }}")"
        # TODO: Check for the man page generation here. For whatever reason,
        # it seems to be intermittently failing in CI. No idea why.
        # for f in rg.bash rg.fish rg.1; do
        for f in rg.bash rg.fish; do
          # We could use file -E here, but it isn't supported on macOS.
          ls "$outdir/$f" && file "$outdir/$f"
        done

    - name: Test zsh shell completions (Unix, sans cross)
      # We could test this when using Cross, but we'd have to execute the
      # 'rg' binary (done in test-complete) with qemu, which is a pain and
      # doesn't really gain us much. If shell completion works in one place,
      # it probably works everywhere.
      if: matrix.target == '' && matrix.os != 'windows-2019'
      shell: bash
      run: ci/test-complete

  rustfmt:
    name: rustfmt
    runs-on: ubuntu-18.04
    steps:
    - name: Checkout repository
      uses: actions/checkout@v2
    - name: Install Rust
      uses: actions-rs/toolchain@v1
      with:
        toolchain: stable
        override: true
        profile: minimal
        components: rustfmt
    - name: Check formatting
      run: |
        cargo fmt --all -- --check