name: Continuous Integration

on:
  pull_request:
  push:
    branches:
      - master
      - 3.5.x
      - 3.4.x
      - 3.3.x
      - 3.2.x

jobs:
  ci:
    name: ci
    strategy:
      matrix:
        system: ["ubuntu-20.04"]
        jvm: ["adopt@1.8"]
        scala: ["2.13.10", "2.12.17"]
        espresso: ["2.4"]
        circt: ["sifive/1/15/0"]
    runs-on: ${{ matrix.system }}

    steps:
      - name: Checkout
        uses: actions/checkout@v2

      - name: Install Tabby OSS Cad Suite (from YosysHQ)
        uses: YosysHQ/setup-oss-cad-suite@v1
        with:
          osscadsuite-version: '2021-11-09'

      - name: Install Espresso
        run: |
          cd /tmp
          wget https://github.com/chipsalliance/espresso/releases/download/v${{ matrix.espresso }}/x86_64-linux-gnu-espresso
          chmod +x x86_64-linux-gnu-espresso
          sudo mv x86_64-linux-gnu-espresso /usr/local/bin/espresso
          espresso || true

      - name: Setup Scala
        uses: olafurpg/setup-scala@v10
        with:
          java-version: ${{ matrix.jvm }}
      - name: Install CIRCT
        run: |
          mkdir usr
          # Escape version forward slashes for use in URL
          VERSION=$(echo ${{ matrix.circt }} | sed 's|/|%2F|g')
          wget https://github.com/llvm/circt/releases/download/${VERSION}/circt-bin-ubuntu-20.04.tar.gz -O - | tar -zx -C usr/
          echo "$(pwd)/usr/bin" >> $GITHUB_PATH
      - name: Cache Scala
        uses: coursier/cache-action@v5
      - name: Use Treadle for Pull Requests
        if: github.event_name == 'pull_request'
        run: echo "CHISEL3_CI_USE_TREADLE=1" >> $GITHUB_ENV
      - name: Test
        run: sbt ++${{ matrix.scala }} test
      - name: Binary compatibility
        run: sbt ++${{ matrix.scala }} mimaReportBinaryIssues

  doc:
    name: Formatting and Documentation
    runs-on: ubuntu-20.04
    steps:
      - name: Checkout
        uses: actions/checkout@v2
      - name: Setup Scala
        uses: olafurpg/setup-scala@v10
        with:
          java-version: "adopt@1.11"
      - name: Cache Scala
        uses: coursier/cache-action@v5
      - name: Check Formatting
        run: sbt scalafmtCheckAll
      - name: Documentation
        run: sbt docs/mdoc unidoc

  integration:
    name: Integration Tests (w/ chiseltest)
    runs-on: ubuntu-20.04
    steps:
      - name: Checkout
        uses: actions/checkout@v2
      - name: Install Tabby OSS Cad Suite (from YosysHQ)
        uses: YosysHQ/setup-oss-cad-suite@v1
        with:
          osscadsuite-version: '2021-11-09'
      - name: Install Espresso
        run: |
          cd /tmp
          wget https://github.com/chipsalliance/espresso/releases/download/v2.4/x86_64-linux-gnu-espresso
          chmod +x x86_64-linux-gnu-espresso
          sudo mv x86_64-linux-gnu-espresso /usr/local/bin/espresso
          espresso || true
      - name: Setup Scala
        uses: olafurpg/setup-scala@v10
        with:
          java-version: "adopt@1.11"
      - name: Cache Scala
        uses: coursier/cache-action@v5
      - name: Integration Tests
        run: sbt integrationTests/test

  std:
    name: Standard Library Tests
    runs-on: ubuntu-20.04
    strategy:
      matrix:
        scala: [ "2.13.10", "2.12.17" ]
    steps:
      - name: Checkout
        uses: actions/checkout@v2
      - name: Install Tabby OSS Cad Suite (from YosysHQ)
        uses: YosysHQ/setup-oss-cad-suite@v1
        with:
          osscadsuite-version: '2021-11-09'
      - name: Setup Scala
        uses: olafurpg/setup-scala@v10
        with:
          java-version: "adopt@1.11"
      - name: Cache Scala
        uses: coursier/cache-action@v5
      - name: Check Formatting (Scala 2.12 only)
        if: startsWith(matrix.scala, '2.12')
        run: sbt ++${{ matrix.scala }} standardLibrary/scalafmtCheckAll
      - name: Unit Tests
        run: sbt ++${{ matrix.scala }} standardLibrary/test

  # Sentinel job to simplify how we specify which checks need to pass in branch
  # protection and in Mergify. This job checks that all jobs were successful.
  #
  # When adding new jobs, please add them to `needs` below
  check-tests:
    name: "check tests"
    needs: [ci, integration, std, doc]
    runs-on: ubuntu-20.04
    if: success() # only run if all tests have passed
    outputs:
      success: ${{ steps.setoutput.outputs.success }}
    steps:
      - id: setoutput
        run: echo "::set-output name=success::true"

  # Related to check-tests above, this job _always_ runs (even if tests fail
  # and thus check-steps is skipped). This two sentinel job approach avoids an
  # issue where failing tests causes a single sentinel job to be skipped which
  # counts as passing for purposes of branch protection.
  #
  # See: https://brunoscheufler.com/blog/2022-04-09-the-required-github-status-check-that-wasnt
  all_tests_passed:
    name: "all tests passed"
    runs-on: ubuntu-20.04
    if: always() # Always run so that we never skip this check
    needs: check-tests
      # Pass only if check-tests set its output value
    steps:
      - run: |
          PASSED="${{ needs.check-tests.outputs.success }}"
          if [[ $PASSED == "true" ]]; then
            echo "All tests passed!"
            exit 0
          else
            echo "One or more tests FAILED!"
            exit 1
          fi

  # sbt ci-release publishes all cross versions so this job needs to be
  # separate from a Scala versions build matrix to avoid duplicate publishing
  publish:
    needs: [all_tests_passed]
    runs-on: ubuntu-20.04
    if: github.event_name == 'push'

    steps:
      - name: Checkout
        uses: actions/checkout@v2
      - name: Setup Scala
        uses: olafurpg/setup-scala@v10
        with:
          java-version: adopt@1.8
      - name: Cache Scala
        uses: coursier/cache-action@v5
      - name: Setup GPG (for Publish)
        uses: olafurpg/setup-gpg@v3
      - name: Publish
        run: sbt ci-release
        env:
          PGP_PASSPHRASE: ${{ secrets.PGP_PASSPHRASE }}
          PGP_SECRET: ${{ secrets.PGP_SECRET }}
          SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }}
          SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }}


