From a4b066d6cfa4b431bdb25745653424e9151a2575 Mon Sep 17 00:00:00 2001 From: Mariell Hoversholm Date: Mon, 30 Jun 2025 08:56:56 +0200 Subject: [PATCH] Actions: Detect code changes (#107326) --- .github/CODEOWNERS | 1 + .github/actions/change-detection/action.yml | 141 +++++++++++++++++++ .github/workflows/backend-unit-tests.yml | 25 +++- .github/workflows/frontend-lint.yml | 32 ++++- .github/workflows/pr-e2e-tests.yml | 22 +++ .github/workflows/pr-frontend-unit-tests.yml | 24 +++- 6 files changed, 236 insertions(+), 9 deletions(-) create mode 100644 .github/actions/change-detection/action.yml diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index e71c286f32b..5c5de6c7246 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -773,6 +773,7 @@ embed.go @grafana/grafana-as-code /.github/actions/setup-enterprise/action.yml @grafana/grafana-backend-group /.github/actions/setup-grafana-bench/ @Proximyst /.github/actions/build-package @grafana/grafana-developer-enablement-squad +/.github/actions/change-detection @grafana/grafana-developer-enablement-squad /.github/workflows/actionlint-format.txt @grafana/grafana-developer-enablement-squad /.github/workflows/actionlint.yml @grafana/grafana-developer-enablement-squad /.github/workflows/add-to-whats-new.yml @grafana/docs-tooling diff --git a/.github/actions/change-detection/action.yml b/.github/actions/change-detection/action.yml new file mode 100644 index 00000000000..b8864e985e2 --- /dev/null +++ b/.github/actions/change-detection/action.yml @@ -0,0 +1,141 @@ +name: Detect changed files +description: Detects whether any matching files have changed in the current PR +inputs: + self: + description: The path to the calling workflow (e.g. .github/workflows/backend-unit-tests.yml). It is regarded as any category. + required: true +outputs: + self: + description: Whether the calling workflow has changed in any way + value: ${{ steps.changed-files.outputs.self_any_changed || 'true' }} + backend: + description: Whether the backend or self have changed in any way + value: ${{ steps.changed-files.outputs.backend_any_changed || 'true' }} + frontend: + description: Whether the frontend or self has changed in any way + value: ${{ steps.changed-files.outputs.frontend_any_changed || 'true' }} + e2e: + description: Whether the e2e tests or self have changed in any way + value: ${{ steps.changed-files.outputs.e2e_any_changed == 'true' || + steps.changed-files.outputs.backend_any_changed == 'true' || + steps.changed-files.outputs.frontend_any_changed == 'true' || 'true' }} + dev-tooling: + description: Whether the dev tooling or self have changed in any way + value: ${{ steps.changed-files.outputs.dev_tooling_any_changed || 'true' }} + docs: + description: Whether the docs or self have changed in any way + value: ${{ steps.changed-files.outputs.docs_any_changed || 'true' }} +runs: + using: composite + steps: + # Assumption: We've done a checkout with the actions/checkout action. + # It must persist credentials to allow the changed-files action to get more history. + - name: Detect changes + id: changed-files + if: github.event_name == 'pull_request' + uses: tj-actions/changed-files@ed68ef82c095e0d48ec87eccea555d944a631a4c # v46 + with: + files_yaml: | + self: + - '.github/actions/change-detection/**' + - '${{ inputs.self }}' + backend: + - '!*.md' + - '!docs/**' + - '!.github/**' + - '.github/actions/setup-enterprise/**' + - '.github/actions/checkout/**' + - '**/go.mod' + - '**/go.sum' + - '**.go' + - 'pkg/**' + - '!pkg/**.md' + - 'apps/**' + - '!apps/**.md' + - 'build.sh' + - '.github/actions/change-detection/**' + - '**.cue' + - 'devenv/docker/blocks/*_tests/**' + - 'kindsv2/**' + - '${{ inputs.self }}' + frontend: + - '.github/actions/setup-enterprise/**' + - '.github/actions/checkout/**' + - 'public/**' + - '**.js' + - '**.jsx' + - '**.ts' + - '**.tsx' + - '**.css' + - '**.mjs' + - 'yarn.lock' + - 'package.json' + - '!**.md' + - '.github/actions/change-detection/**' + - '**.cue' + - '.prettier*' + - '.betterer*' + - '.yarnrc.yml' + - 'eslint.config.js' + - 'jest.config.js' + - 'nx.json' + - 'tsconfig.json' + - '.yarn/**' + - '${{ inputs.self }}' + e2e: + - 'e2e/**' + - '.github/actions/setup-enterprise/**' + - '.github/actions/checkout/**' + - 'emails/**' + - 'pkg/**' + - 'proto/**' + - '**/Makefile' + - 'scripts/**' + - '!scripts/drone/**' + - '!**.md' + - '.github/actions/change-detection/**' + - '**.cue' + - 'conf/**' + - 'cypress.config.js' + - '${{ inputs.self }}' + dev_tooling: + - '.github/actions/setup-enterprise/**' + - '.github/actions/checkout/**' + - '**.sh' + - '.trivyignore' + - '.prettierrc.js' + - '**/Makefile' + - 'proto/**.yaml' + - 'pkg/build/**' + - 'pkg/wire/**' + - 'scripts/**' + - '!**.md' + - '.citools/**' + - '.bingo/**' + - '.github/actions/change-detection/**' + - '${{ inputs.self }}' + docs: + - 'contribute/**' + - 'docs/**' + - '**.md' + - 'LICENSE' + - '.vale.ini' + - '.github/actions/change-detection/**' + - '${{ inputs.self }}' + - name: Print all change groups + shell: bash + run: | + echo "Self: ${{ steps.changed-files.outputs.self_any_changed || 'true' }}" + echo " --> ${{ steps.changed-files.outputs.self_all_changed_files }}" + echo "Backend: ${{ steps.changed-files.outputs.backend_any_changed || 'true' }}" + echo " --> ${{ steps.changed-files.outputs.backend_all_changed_files }}" + echo "Frontend: ${{ steps.changed-files.outputs.frontend_any_changed || 'true' }}" + echo " --> ${{ steps.changed-files.outputs.frontend_all_changed_files }}" + echo "E2E: ${{ steps.changed-files.outputs.e2e_any_changed || 'true' }}" + echo " --> ${{ steps.changed-files.outputs.e2e_all_changed_files }}" + echo " --> ${{ steps.changed-files.outputs.backend_all_changed_files }}" + echo " --> ${{ steps.changed-files.outputs.frontend_all_changed_files }}" + echo "Dev Tooling: ${{ steps.changed-files.outputs.dev_tooling_any_changed || 'true' }}" + echo " --> ${{ steps.changed-files.outputs.dev_tooling_all_changed_files }}" + echo "Docs: ${{ steps.changed-files.outputs.docs_any_changed || 'true' }}" + echo " --> ${{ steps.changed-files.outputs.docs_all_changed_files }}" diff --git a/.github/workflows/backend-unit-tests.yml b/.github/workflows/backend-unit-tests.yml index 59943c8b99f..07663eb8631 100644 --- a/.github/workflows/backend-unit-tests.yml +++ b/.github/workflows/backend-unit-tests.yml @@ -14,10 +14,29 @@ concurrency: permissions: {} jobs: + detect-changes: + name: Detect whether code changed + runs-on: ubuntu-latest + permissions: + contents: read + outputs: + changed: ${{ steps.detect-changes.outputs.backend }} + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: true # required to get more history in the changed-files action + fetch-depth: 2 + - name: Detect changes + id: detect-changes + uses: ./.github/actions/change-detection + with: + self: .github/workflows/backend-unit-tests.yml + grafana: # Run this workflow only for PRs from forks # the `pr-backend-unit-tests-enterprise` workflow will run instead - if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == true + needs: detect-changes + if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == true && needs.detect-changes.outputs.changed == 'true' strategy: matrix: shard: [ @@ -53,8 +72,8 @@ jobs: grafana-enterprise: # Run this workflow for non-PR events (like pushes to `main` or `release-*`) OR for internal PRs (PRs not from forks) - # If it gets merged into `main` or `release-*`, then a junit test result is uploaded to GCS. - if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false + needs: detect-changes + if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false && needs.detect-changes.outputs.changed == 'true' strategy: matrix: shard: [ diff --git a/.github/workflows/frontend-lint.yml b/.github/workflows/frontend-lint.yml index b9949fc74f6..e5ceb117eea 100644 --- a/.github/workflows/frontend-lint.yml +++ b/.github/workflows/frontend-lint.yml @@ -9,13 +9,32 @@ on: permissions: {} jobs: + detect-changes: + name: Detect whether code changed + runs-on: ubuntu-latest + permissions: + contents: read + outputs: + changed: ${{ steps.detect-changes.outputs.frontend }} + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: true # required to get more history in the changed-files action + fetch-depth: 2 + - name: Detect changes + id: detect-changes + uses: ./.github/actions/change-detection + with: + self: .github/workflows/frontend-lint.yml + lint-frontend-prettier: + needs: detect-changes permissions: contents: read id-token: write # Run this workflow only for PRs from forks; if it gets merged into `main` or `release-*`, # the `lint-frontend-prettier-enterprise` workflow will run instead - if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == true + if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == true && needs.detect-changes.outputs.changed == 'true' name: Lint runs-on: ubuntu-latest steps: @@ -31,11 +50,12 @@ jobs: - run: yarn run prettier:check - run: yarn run lint lint-frontend-prettier-enterprise: + needs: detect-changes permissions: contents: read id-token: write # Run this workflow for non-PR events (like pushes to `main` or `release-*`) OR for internal PRs (PRs not from forks) - if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false + if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false && needs.detect-changes.outputs.changed == 'true' name: Lint runs-on: ubuntu-latest steps: @@ -55,12 +75,13 @@ jobs: - run: yarn run prettier:check - run: yarn run lint lint-frontend-typecheck: + needs: detect-changes permissions: contents: read id-token: write # Run this workflow only for PRs from forks; if it gets merged into `main` or `release-*`, # the `lint-frontend-typecheck-enterprise` workflow will run instead - if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == true + if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == true && needs.detect-changes.outputs.changed == 'true' name: Typecheck runs-on: ubuntu-latest steps: @@ -75,11 +96,12 @@ jobs: - run: yarn install --immutable --check-cache - run: yarn run typecheck lint-frontend-typecheck-enterprise: + needs: detect-changes permissions: contents: read id-token: write # Run this workflow for non-PR events (like pushes to `main` or `release-*`) OR for internal PRs (PRs not from forks) - if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false + if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false && needs.detect-changes.outputs.changed == 'true' name: Typecheck runs-on: ubuntu-latest steps: @@ -98,9 +120,11 @@ jobs: - run: yarn install --immutable --check-cache - run: yarn run typecheck lint-frontend-betterer: + needs: detect-changes permissions: contents: read id-token: write + if: needs.detect-changes.outputs.changed == 'true' name: Betterer runs-on: ubuntu-latest steps: diff --git a/.github/workflows/pr-e2e-tests.yml b/.github/workflows/pr-e2e-tests.yml index bf663324f57..ec74716f7e3 100644 --- a/.github/workflows/pr-e2e-tests.yml +++ b/.github/workflows/pr-e2e-tests.yml @@ -14,7 +14,27 @@ concurrency: permissions: {} jobs: + detect-changes: + name: Detect whether code changed + runs-on: ubuntu-latest + permissions: + contents: read + outputs: + changed: ${{ steps.detect-changes.outputs.e2e }} + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: true # required to get more history in the changed-files action + fetch-depth: 2 + - name: Detect changes + id: detect-changes + uses: ./.github/actions/change-detection + with: + self: .github/workflows/pr-e2e-tests.yml + build-grafana: + needs: detect-changes + if: needs.detect-changes.outputs.changed == 'true' name: Build & Package Grafana runs-on: ubuntu-latest-16-cores permissions: @@ -41,6 +61,8 @@ jobs: path: grafana.tar.gz build-e2e-runner: + needs: detect-changes + if: needs.detect-changes.outputs.changed == 'true' name: Build E2E test runner runs-on: ubuntu-latest permissions: diff --git a/.github/workflows/pr-frontend-unit-tests.yml b/.github/workflows/pr-frontend-unit-tests.yml index 59eb9c794ea..9e217c6ee46 100644 --- a/.github/workflows/pr-frontend-unit-tests.yml +++ b/.github/workflows/pr-frontend-unit-tests.yml @@ -9,13 +9,32 @@ on: permissions: {} jobs: + detect-changes: + name: Detect whether code changed + runs-on: ubuntu-latest + permissions: + contents: read + outputs: + changed: ${{ steps.detect-changes.outputs.frontend }} + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: true # required to get more history in the changed-files action + fetch-depth: 2 + - name: Detect changes + id: detect-changes + uses: ./.github/actions/change-detection + with: + self: .github/workflows/pr-frontend-unit-tests.yml + frontend-unit-tests: permissions: contents: read id-token: write # Run this workflow only for PRs from forks; if it gets merged into `main` or `release-*`, # the `frontend-unit-tests-enterprise` workflow will run instead - if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == true + needs: detect-changes + if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == true && needs.detect-changes.outputs.changed == 'true' runs-on: ubuntu-latest-8-cores name: "Unit tests (${{ matrix.chunk }} / 8)" strategy: @@ -43,7 +62,8 @@ jobs: contents: read id-token: write # Run this workflow for non-PR events (like pushes to `main` or `release-*`) OR for internal PRs (PRs not from forks) - if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false + needs: detect-changes + if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false && needs.detect-changes.outputs.changed == 'true' runs-on: ubuntu-latest-8-cores name: "Unit tests (${{ matrix.chunk }} / 8)" strategy: