name: Renovate Dependency Artifacts

on:
  pull_request:
    types: [opened, reopened, synchronize, ready_for_review]
    paths:
      - '.bazelversion'
      - 'MODULE.bazel'
      - 'MODULE.bazel.lock'
      - 'maven_install.json'
      - 'renovate.json'
      - 'ci/github_actions/ensure_bazel_installed.sh'
      - 'ci/github_actions/update_llvm_distributions.py'
      - '.github/actions/setup-bazel/**'
      - '.github/workflows/renovate_dependency_artifacts.yml'

  pull_request_target:
    types: [opened, reopened, synchronize, ready_for_review]
    paths:
      - '.bazelversion'
      - 'MODULE.bazel'
      - 'MODULE.bazel.lock'
      - 'maven_install.json'
      - 'go.mod'
      - 'go.sum'
      - 'renovate.json'
      - 'ci/github_actions/ensure_bazel_installed.sh'
      - 'ci/github_actions/update_llvm_distributions.py'
      - '.github/actions/setup-bazel/**'
      - '.github/workflows/renovate_dependency_artifacts.yml'

concurrency:
  group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.event.pull_request.head.ref }}
  cancel-in-progress: true

permissions:
  contents: write
  pull-requests: read

jobs:
  changes:
    runs-on: ubuntu-latest
    outputs:
      bazel: ${{ steps.changed-files.outputs.bazel }}
      go: ${{ steps.changed-files.outputs.go }}
      update_matrix: ${{ steps.changed-files.outputs.update_matrix }}
    steps:
      - name: Detect changed dependency files
        id: changed-files
        uses: actions/github-script@v9
        with:
          script: |
            const files = await github.paginate(
              github.rest.pulls.listFiles,
              {
                owner: context.repo.owner,
                repo: context.repo.repo,
                pull_number: context.payload.pull_request.number,
                per_page: 100,
              },
            );

            const changed = files.map((file) => file.filename);
            const bazelPatterns = [
              /^\.bazelversion$/,
              /^MODULE\.bazel$/,
              /^MODULE\.bazel\.lock$/,
              /^maven_install\.json$/,
              /^renovate\.json$/,
              /^ci\/github_actions\/ensure_bazel_installed\.sh$/,
              /^ci\/github_actions\/update_llvm_distributions\.py$/,
              /^\.github\/actions\/setup-bazel\//,
              /^\.github\/workflows\/renovate_dependency_artifacts\.yml$/,
            ];
            const goPatterns = [
              /^go\.mod$/,
              /^go\.sum$/,
              /^renovate\.json$/,
              /^\.github\/workflows\/renovate_dependency_artifacts\.yml$/,
            ];

            core.setOutput(
              'bazel',
              changed.some((file) => bazelPatterns.some((pattern) => pattern.test(file))),
            );
            core.setOutput(
              'go',
              changed.some((file) => goPatterns.some((pattern) => pattern.test(file))),
            );

            const include = [];
            if (changed.some((file) => bazelPatterns.some((pattern) => pattern.test(file)))) {
              include.push({
                artifact: 'bazel',
                name: 'Bazel lockfiles',
                changed_files: 'MODULE.bazel MODULE.bazel.lock maven_install.json',
                commit_message: 'Update generated dependency lockfiles',
              });
            }
            if (changed.some((file) => goPatterns.some((pattern) => pattern.test(file)))) {
              include.push({
                artifact: 'go',
                name: 'Go artifacts',
                changed_files: 'go.sum',
                commit_message: 'Update generated Go artifacts',
              });
            }
            core.setOutput('update_matrix', JSON.stringify({include}));

  check-lockfile:
    if: >-
      github.event_name == 'pull_request' &&
      github.event.pull_request.user.login != 'renovate[bot]'
    runs-on: [self-hosted, bazel]
    permissions:
      contents: read

    steps:
      - name: Checkout PR
        uses: actions/checkout@v7
        with:
          lfs: false

      - name: Ensure Bazel installed
        uses: ./.github/actions/setup-bazel

      - name: Refresh LLVM distribution metadata
        env:
          GITHUB_TOKEN: ${{ github.token }}
        run: python3 ci/github_actions/update_llvm_distributions.py

      - name: Update Maven lockfile
        env:
          REPIN: "1"
        run: bazel run @maven//:pin

      - name: Refresh Bazel lockfile
        run: bazel build --nobuild //src/main/scala/net/eagle0/eagle:eagle_server //src/main/cpp/net/eagle0/shardok:shardok-server

      - name: Verify generated lockfiles are current
        run: |
          if git diff --quiet -- MODULE.bazel MODULE.bazel.lock maven_install.json; then
            echo "Generated dependency lockfiles are current"
            exit 0
          fi

          echo "Generated dependency lockfiles are stale. Run the lockfile update commands and commit the result:"
          echo "  python3 ci/github_actions/update_llvm_distributions.py"
          echo "  REPIN=1 bazel run @maven//:pin"
          echo "  bazel build --nobuild //src/main/scala/net/eagle0/eagle:eagle_server //src/main/cpp/net/eagle0/shardok:shardok-server"
          git diff -- MODULE.bazel MODULE.bazel.lock maven_install.json
          exit 1

  update-artifacts:
    name: Update ${{ matrix.name }}
    needs: changes
    if: >-
      github.event_name == 'pull_request_target' &&
      github.event.pull_request.user.login == 'renovate[bot]' &&
      github.event.pull_request.head.repo.full_name == github.repository &&
      startsWith(github.event.pull_request.head.ref, 'renovate/') &&
      needs.changes.outputs.update_matrix != '{"include":[]}'
    runs-on: [self-hosted, bazel]
    strategy:
      fail-fast: false
      matrix: ${{ fromJSON(needs.changes.outputs.update_matrix) }}

    steps:
      - name: Ensure Git LFS available for checkout
        run: |
          COMMON_PATHS=(/opt/homebrew/bin /usr/local/bin)
          for path in "${COMMON_PATHS[@]}"; do
            if [ -d "$path" ]; then
              echo "$path" >> "$GITHUB_PATH"
              export PATH="$path:$PATH"
            fi
          done

          if command -v git-lfs >/dev/null 2>&1; then
            git-lfs version
            exit 0
          fi

          brew install git-lfs
          git-lfs version

      - name: Checkout Renovate branch
        uses: actions/checkout@v7
        with:
          ref: ${{ github.event.pull_request.head.ref }}
          repository: ${{ github.event.pull_request.head.repo.full_name }}
          token: ${{ secrets.RENOVATE_LOCKFILE_TOKEN || github.token }}
          lfs: false

      - name: Refresh LLVM distribution metadata
        if: matrix.artifact == 'bazel'
        env:
          GITHUB_TOKEN: ${{ github.token }}
        run: python3 ci/github_actions/update_llvm_distributions.py

      - name: Ensure Bazel installed
        if: matrix.artifact == 'bazel'
        uses: ./.github/actions/setup-bazel

      - name: Update Maven lockfile
        if: matrix.artifact == 'bazel'
        env:
          REPIN: "1"
        run: bazel run @maven//:pin

      - name: Refresh Bazel lockfile
        if: matrix.artifact == 'bazel'
        run: bazel build --nobuild //src/main/scala/net/eagle0/eagle:eagle_server //src/main/cpp/net/eagle0/shardok:shardok-server

      - name: Set up Go
        if: matrix.artifact == 'go'
        uses: actions/setup-go@v6
        with:
          go-version-file: go.mod
          cache: false

      - name: Update Go module sums
        if: matrix.artifact == 'go'
        run: go mod download all

      - name: Commit generated artifact updates
        run: |
          if git diff --quiet -- ${{ matrix.changed_files }}; then
            echo "${{ matrix.name }} are already up to date"
            exit 0
          fi

          git config user.name "github-actions[bot]"
          git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
          git add ${{ matrix.changed_files }}
          git commit -m "${{ matrix.commit_message }}"
          git push origin "HEAD:${{ github.event.pull_request.head.ref }}"
