name: tidy-check-generate

on:
  workflow_dispatch:
  push:
    branches:
      - main
      - "release/**"
  pull_request:

jobs:
  tidycheck:
    name: tidy, check and generate
    runs-on: [arc-runner-set]
    permissions:
      id-token: write
      contents: read
    steps:
      - name: Checkout
        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
        with:
          ref: ${{ !github.event.pull_request.head.repo.fork && github.head_ref || '' }}
          # No token available for forks, so we can't push changes
          token: ${{ !github.event.pull_request.head.repo.fork && secrets.CI_COMMIT_PUSH_PR || '' }}

      - name: Install Dependencies
        run: |
          echo "::group::Install Dependencies"
          sudo apt-get update && sudo apt-get -y install libcryptsetup-dev libvirt-dev
          echo "::endgroup::"

      - name: Setup Bazel
        uses: ./.github/actions/setup_bazel_nix
        with:
          useCache: "rbe"
          rbePlatform: "ubuntu-22.04"

      - name: Assume AWS role to upload Bazel dependencies to S3
        if: startsWith(github.head_ref, 'renovate/')
        uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
        with:
          role-to-assume: arn:aws:iam::795746500882:role/GithubConstellationMirrorWrite
          aws-region: eu-central-1

      - name: Upload Bazel dependencies to the mirror
        if: startsWith(github.head_ref, 'renovate/')
        shell: bash
        run: |
          bazel run //bazel/ci:deps_mirror_upgrade
          bazel run //bazel/ci:deps_mirror_upload

      - name: Run Bazel tidy
        shell: bash
        run: |
          bazel run //:tidy
          bazel mod deps --lockfile_mode=update

      - name: Check if untidy
        id: untidy
        shell: bash
        run: |
          diff=$(git diff)
          if [[ -z "$diff" ]]; then
            echo "Everything is tidy."
            echo "untidy=false" | tee -a "$GITHUB_OUTPUT"
            exit 0
          fi
          echo "Detected changes after tidy"
          echo "untidy=true" | tee -a "$GITHUB_OUTPUT"
          diffsum=$(echo "$diff" | sha256sum | cut -d' ' -f1)
          echo "diffsum=${diffsum}" | tee -a "$GITHUB_OUTPUT"

      - name: Run Bazel generate
        shell: bash
        run: bazel run //:generate

      - name: Check if ungenerated
        id: ungenerated
        shell: bash
        run: |
          diff=$(git diff)
          diffsum=$(echo "$diff" | sha256sum| cut -d' ' -f1)
          if [[ "${{ steps.untidy.outputs.diffsum }}" == "${diffsum}" ]]; then
            echo "Everything is tidy."
            echo "ungenerated=false" | tee -a "$GITHUB_OUTPUT"
            exit 0
          fi
          echo "Detected changes after tidy"
          echo "ungenerated=true" | tee -a "$GITHUB_OUTPUT"

      - name: Check if tidy or generate made modifications
        id: modified
        shell: bash
        run: |
          diff=$(git diff)
          if [[ -z "$diff" ]]; then
            echo "Everything is tidy and generated."
            exit 0
          fi

          # Use quadruple backticks to escape triple backticks in diff'ed files.
          cat << EOF >> "${GITHUB_STEP_SUMMARY}"
          \`\`\`\`diff
          ${diff}
          \`\`\`\`
          EOF

          if [[ "${{ steps.untidy.outputs.untidy }}" == "true" ]] &&
             [[ "${{ steps.ungenerated.outputs.ungenerated }}" == "true" ]]; then
            suggestCmd="'bazel run //:generate' &&' bazel run //:tidy'"
          elif [[ "${{ steps.untidy.outputs.untidy }}" == "true" ]]; then
            suggestCmd="'bazel run //:tidy'"
          elif [[ "${{ steps.ungenerated.outputs.ungenerated }}" == "true" ]]; then
            suggestCmd="'bazel run //:generate'"
          fi

          echo "::error::The repo is not tidy. Please run ${suggestCmd} and commit the changes."
          exit 1

      - name: Run Bazel check
        shell: bash
        run: bazel run //:check

      # The following steps are only executed if the previous tidy check failed
      # and the action runs on an renovate branch. In this case, we tidy all
      # modules again and commit the changes, so the user doesn't need to do it.

      - name: Push changes
        if: |
          failure() &&
          (steps.modified.conclusion == 'failure') &&
          startsWith(github.head_ref, 'renovate/') &&
          !github.event.pull_request.head.repo.fork
        shell: bash
        run: |
          git config --global user.name "edgelessci"
          git config --global user.email "edgelessci@users.noreply.github.com"
          git commit -am "deps: tidy all modules"
          git push