# This workflow is a collection of "quick checks" that should be reasonable
# to run for any new commit to this repository in principle.
#
# The main purpose of this workflow is to represent checks that we want to
# run prior to reviewing and merging a pull request. We should therefore aim
# for these checks to complete in no more than a few minutes in the common
# case.
#
# The build.yml workflow includes some additional checks we run only for
# already-merged changes to release branches and tags, as a compromise to
# keep the PR feedback relatively fast. The intent is that checks.yml should
# catch most problems but that build.yml might occasionally be the one to catch
# more esoteric situations, such as architecture-specific or OS-specific
# misbehavior.

name: Quick Checks

on:
  pull_request:
  push:
    branches:
      - main
      - 'v[0-9]+.[0-9]+'
      - checks-workflow-dev/*
    tags:
      - 'v[0-9]+.[0-9]+.[0-9]+*'

# This workflow runs for not-yet-reviewed external contributions and so it
# intentionally has no write access and only limited read access to the
# repository.
permissions:
  contents: read

jobs:
  fileschanged:
    name: List files changed for pull request
    runs-on: ubuntu-latest
    steps:
      - name: "Fetch source code"
        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
      - id: diff
        env:
          BASE_REF: ${{ github.event.pull_request.base.ref }}
        run: |
          git fetch --no-tags --prune --no-recurse-submodules --depth=1 origin "$BASE_REF"
          echo "go=$(git diff --name-only origin/"$BASE_REF" | grep -e '\.go' -e '\.github' -e 'go\.mod' -e 'go\.sum' -e '\.tf' -e '\.gitattributes' | wc -l)" | tee -a "$GITHUB_OUTPUT"
    outputs:
      go: ${{ steps.diff.outputs.go }}

  unit-tests:
    name: Unit tests for ${{ matrix.goos }}_${{ matrix.goarch }}
    runs-on: ${{ matrix.runson }}
    needs: fileschanged
    if: ${{ needs.fileschanged.outputs.go != 0}}
    env:
      TF_APPEND_USER_AGENT: Integration-Test
      GOOS: ${{ matrix.goos }}
      GOARCH: ${{ matrix.goarch }}
    strategy:
      matrix:
        include:
          - { runson: ubuntu-24.04-arm, goos: linux, goarch: "arm64" }
          - { runson: ubuntu-latest, goos: linux, goarch: "amd64" }
          - { runson: ubuntu-latest, goos: linux, goarch: "386" }
          - { runson: ubuntu-latest, goos: linux, goarch: "arm" }
          - { runson: macos-latest, goos: darwin, goarch: "arm64" }
          - { runson: windows-latest, goos: windows, goarch: "amd64" }
      fail-fast: false
    steps:
      # 👇🏾 GH actions supports only "AMD64 arch", so we are using this action
      # for testing on non amd64 envs like 386, arm64 etc...
      - name: "Set up QEMU"
        if: matrix.goos == 'linux' && matrix.goarch != 'amd64' && matrix.goarch != 'arm64'
        uses: docker/setup-qemu-action@53851d14592bedcffcf25ea515637cff71ef929a # v3.3.0

      - name: "Fetch source code"
        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

      - name: Install Go toolchain
        uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
        with:
          go-version-file: 'go.mod'

      - name: "Unit tests"
        run: |
          go test ./...

  race-tests:
    name: "Race Tests"
    runs-on: ubuntu-latest
    needs: fileschanged
    if: ${{ needs.fileschanged.outputs.go != 0}}

    steps:
      - name: "Fetch source code"
        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

      - name: Install Go toolchain
        uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
        with:
          go-version-file: 'go.mod'

      # The race detector add significant time to the unit tests, so only run
      # it for select packages.
      - name: "Race detector"
        run: |
          go test -race ./internal/tofu ./internal/command ./internal/states ./internal/providercache

  e2e-tests:
    # This is an intentionally-limited form of our E2E test run which only
    # covers OpenTofu running on Linux. The build.yml workflow runs these
    # tests across various other platforms in order to catch the rare exception
    # that might leak through this.
    name: "End-to-end Tests"
    runs-on: ubuntu-latest
    needs: fileschanged
    if: ${{ needs.fileschanged.outputs.go != 0}}

    steps:
      - name: "Fetch source code"
        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

      - name: Install Go toolchain
        uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
        with:
          go-version-file: 'go.mod'

      - name: "End-to-end tests"
        run: |
          # This also includes some acceptance tests elsewhere that have
          # similar dependencies on the OpenTofu Registry and on some
          # OpenTofu-controlled GitHub repositories, just because this
          # particular job is already expected to have that kind of external
          # dependency. Note that this is appropriate only for tests that
          # make _unauthenticated_ requests to external network services,
          # because we mustn't put live credentials in a job that can be
          # triggered by community pull requests.
          TF_ACC=1 go test -v ./internal/command/e2etest ./internal/initwd ./internal/registry

  consistency-checks:
    name: "Code Consistency Checks"
    runs-on: ubuntu-latest
    needs: fileschanged
    if: ${{ needs.fileschanged.outputs.go != 0}}

    steps:
      - name: "Fetch source code"
        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
        with:
          fetch-depth: 0 # We need to do comparisons against the main branch.

      - name: Install Go toolchain
        uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
        with:
          go-version-file: 'go.mod'

      - name: "go.mod and go.sum consistency check"
        run: |
          go mod tidy
          if [[ -n "$(git status --porcelain go.mod go.sum)" ]]; then
            echo >&2 "ERROR: go.mod/go.sum are not up-to-date. Run 'go mod tidy' and then commit the updated files."
            exit 1
          fi

      - name: Cache protobuf tools
        uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0
        with:
          path: "tools/protobuf-compile/.workdir"
          key: protobuf-tools-${{ hashFiles('tools/protobuf-compile/protobuf-compile.go') }}
          restore-keys: |
            protobuf-tools-

      - name: "Code consistency checks"
        run: |
          make generate protobuf
          if [[ -n "$(git status --porcelain)" ]]; then
            echo >&2 "ERROR: Generated files are inconsistent. Run 'make generate' and 'make protobuf' locally and then commit the updated files."
            git >&2 status --porcelain
            exit 1
          fi
      - name: "Code linting"
        run: |
          # We use our own Makefile target here, rather than the
          # golangci/golangci-lint-action action, because it ought to be
          # possible for someone who encounters a failure here to replicate
          # exactly the same run in their local development environment.
          make golangci-lint

      - name: "Copyright headers"
        run: |
          go tool github.com/hashicorp/copywrite headers --plan
          if [[ $? != 0 ]]; then
            echo >&2 "ERROR: some files are missing required copyright headers. Run `scripts/add-copyright-headers.sh` locally and then commit the updated files."
            exit 1
          fi

  license-checks:
    name: "License Checks"
    runs-on: ubuntu-latest

    steps:
      - name: "Fetch source code"
        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

      - name: Install licensei
        run: |
          make deps

      - name: Restore cache license information of dependencies
        uses: actions/cache/restore@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0
        with:
          path: ".licensei.cache"
          key: licensei-cache-${{ hashFiles('go.sum') }}
          restore-keys: |
            licensei-cache-

      - name: Install Go toolchain
        uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
        with:
          go-version-file: 'go.mod'

      - name: Run licensei
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          make license-check
        if: env.LICENSE_CHECK != 'false'

      - name: Save cache license information of dependencies
        uses: actions/cache/save@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0
        if: always()
        with:
          path: ".licensei.cache"
          key: licensei-cache-${{ hashFiles('go.sum') }}
