diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 64363540c79..107396a4ee3 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -754,6 +754,9 @@ embed.go @grafana/grafana-as-code /.github/pr-checks.json @tolzhabayev /.github/pr-commands.json @tolzhabayev /.github/renovate.json5 @grafana/frontend-ops +/.github/actions/report-coverage @grafana/grafana-backend-group +/.github/actions/run-backend-tests @grafana/grafana-backend-group +/.github/actions/setup-enterprise @grafana/grafana-backend-group /.github/workflows/add-to-whats-new.yml @grafana/docs-tooling /.github/workflows/auto-triager/ @grafana/plugins-platform-frontend /.github/workflows/alerting-swagger-gen.yml @grafana/alerting-backend @@ -761,7 +764,6 @@ embed.go @grafana/grafana-as-code /.github/workflows/auto-milestone.yml @grafana/grafana-developer-enablement-squad /.github/workflows/backport.yml @grafana/grafana-developer-enablement-squad /.github/workflows/bump-version.yml @grafana/grafana-developer-enablement-squad -/.github/workflows/backend-coverage.yml @Proximyst /.github/workflows/close-milestone.yml @grafana/grafana-developer-enablement-squad /.github/workflows/release-pr.yml @grafana/grafana-developer-enablement-squad /.github/workflows/release-comms.yml @grafana/grafana-developer-enablement-squad @@ -787,6 +789,7 @@ embed.go @grafana/grafana-as-code /.github/workflows/pr-codeql-analysis-python.yml @DanCech /.github/workflows/pr-commands.yml @tolzhabayev /.github/workflows/pr-patch-check.yml @grafana/grafana-developer-enablement-squad +/.github/workflows/pr-test-backend.yml @grafana/grafana-backend-group /.github/workflows/sync-mirror.yml @grafana/grafana-developer-enablement-squad /.github/workflows/publish-technical-documentation-next.yml @grafana/docs-tooling /.github/workflows/publish-technical-documentation-release.yml @grafana/docs-tooling diff --git a/.github/actions/report-coverage/action.yml b/.github/actions/report-coverage/action.yml new file mode 100644 index 00000000000..c84aa806d7e --- /dev/null +++ b/.github/actions/report-coverage/action.yml @@ -0,0 +1,46 @@ +name: 'Report Coverage' +description: 'Processes and uploads coverage reports from Go tests' + +inputs: + unit-cov-path: + description: 'Path to unit test coverage file' + required: true + integration-cov-path: + description: 'Path to integration test coverage file' + required: true + +runs: + using: "composite" + steps: + - name: Join coverage outputs + shell: bash + run: | + cp ${{ inputs.unit-cov-path }} backend.cov + tail -n+2 ${{ inputs.integration-cov-path }} >> backend.cov + + - name: Convert coverage info to per-func stats + shell: bash + run: go tool cover -func backend.cov > backend-funcs.log + + - name: Convert coverage info to HTML + shell: bash + run: go tool cover -html backend.cov -o backend.html + + - name: Upload coverage file + uses: actions/upload-artifact@v4 + with: + name: backend-cov + path: | + backend.cov + backend-funcs.log + backend.html + retention-days: 30 + compression-level: 9 + + - name: Set summary to total coverage + shell: bash + run: | + echo '# Coverage' >> $GITHUB_STEP_SUMMARY + echo '```' >> $GITHUB_STEP_SUMMARY + grep 'total:' backend-funcs.log | tr '\t' ' ' >> $GITHUB_STEP_SUMMARY + echo '```' >> $GITHUB_STEP_SUMMARY diff --git a/.github/actions/run-backend-tests/action.yml b/.github/actions/run-backend-tests/action.yml new file mode 100644 index 00000000000..6ae930fa489 --- /dev/null +++ b/.github/actions/run-backend-tests/action.yml @@ -0,0 +1,24 @@ +name: 'Run Backend Tests' +description: 'Runs Grafana backend test suites' + +inputs: + coverage-opts: + description: 'Coverage options to pass to the test command (empty for no coverage)' + required: false + default: '' + test-command: + description: 'The test command to run' + required: false + default: 'make gen-go test-go-unit' + +runs: + using: "composite" + steps: + - name: Run tests + shell: bash + run: | + if [ -n "${{ inputs.coverage-opts }}" ]; then + COVER_OPTS="${{ inputs.coverage-opts }}" ${{ inputs.test-command }} + else + ${{ inputs.test-command }} + fi diff --git a/.github/actions/setup-enterprise/action.yml b/.github/actions/setup-enterprise/action.yml new file mode 100644 index 00000000000..e87d3d7bae9 --- /dev/null +++ b/.github/actions/setup-enterprise/action.yml @@ -0,0 +1,48 @@ +name: 'Setup Grafana Enterprise' +description: 'Clones and sets up Grafana Enterprise repository for testing' + +inputs: + github-app-name: + description: 'Name of the GitHub App in Vault' + required: false + default: 'grafana-ci-bot' + +runs: + using: "composite" + steps: + - name: Retrieve GitHub App secrets + id: get-secrets + uses: grafana/shared-workflows/actions/get-vault-secrets@get-vault-secrets-v1.0.1 + with: + repo_secrets: | + APP_ID=${{ inputs.github-app-name }}:app-id + APP_INSTALLATION_ID=${{ inputs.github-app-name }}:app-installation-id + PRIVATE_KEY=${{ inputs.github-app-name }}:private-key + + - name: Generate GitHub App token + id: generate_token + uses: actions/create-github-app-token@v1 + with: + app-id: ${{ env.APP_ID }} + private-key: ${{ env.PRIVATE_KEY }} + repositories: "grafana-enterprise" + owner: "grafana" + + - name: Setup Enterprise + shell: bash + env: + GH_TOKEN: ${{ steps.generate_token.outputs.token }} + run: | + git clone https://x-access-token:${GH_TOKEN}@github.com/grafana/grafana-enterprise.git ../grafana-enterprise; + + cd ../grafana-enterprise + + if git checkout ${GITHUB_HEAD_REF}; then + echo "checked out ${GITHUB_HEAD_REF}" + elif git checkout ${GITHUB_BASE_REF}; then + echo "checked out ${GITHUB_BASE_REF}" + else + git checkout main + fi + + ./build.sh diff --git a/.github/workflows/backend-coverage.yml b/.github/workflows/backend-coverage.yml deleted file mode 100644 index f103e5b1eed..00000000000 --- a/.github/workflows/backend-coverage.yml +++ /dev/null @@ -1,109 +0,0 @@ -name: Backend Coverage (OSS) -on: - push: - paths: - - pkg/** - - .github/workflows/backend-coverage.yml - - go.* - branches: - - main - pull_request: - -jobs: - unit-tests: - name: Run unit tests (OSS) - runs-on: ubuntu-latest - if: github.repository == 'grafana/grafana' - steps: - - name: Check out repository - uses: actions/checkout@v4.2.2 - - name: Setup Go environment - uses: actions/setup-go@v5.3.0 - with: - go-version-file: go.work - - name: Run tests - run: make gen-go test-go-unit - - name: Upload coverage file - uses: actions/upload-artifact@v4 - if: success() || failure() - with: - name: unit-cov - path: unit.cov - retention-days: 1 - compression-level: 9 # this is raw text, and includes a _lot_ of repetition. compressing it should yield pretty good results. - integration-tests: - name: Run integration tests (OSS) - runs-on: ubuntu-latest - if: github.repository == 'grafana/grafana' - steps: - - name: Check out repository - uses: actions/checkout@v4.2.2 - - name: Setup Go environment - uses: actions/setup-go@v5.3.0 - with: - go-version-file: go.work - - name: Run tests - run: make gen-go test-go-integration - - name: Upload coverage file - uses: actions/upload-artifact@v4 - if: success() || failure() - with: - name: integration-cov - path: integration.cov - retention-days: 1 - compression-level: 9 # this is raw text, and includes a _lot_ of repetition. compressing it should yield pretty good results. - report-coverage: - name: Report coverage from unit and integration tests (OSS) - needs: [unit-tests, integration-tests] - runs-on: ubuntu-latest - # we don't do always() so as to not run even if the workflow is cancelled - if: github.repository == 'grafana/grafana' && (success() || failure()) - steps: - - name: Check out repository - uses: actions/checkout@v4.2.2 - - name: Setup Go environment - uses: actions/setup-go@v5.3.0 - with: - go-version-file: go.work - - name: Generate Go - run: make gen-go - - uses: actions/download-artifact@v4 - with: - pattern: '*-cov' - path: . - merge-multiple: true - - name: Join coverage outputs - run: | - cp unit.cov backend.cov - tail -n+2 integration.cov >> backend.cov - - name: Convert coverage info to per-func stats - run: go tool cover -func backend.cov > backend-funcs.log - # The HTML can be useful in some UI to browse the artifacts easily. - - name: Convert coverage info to HTML - run: go tool cover -html backend.cov -o backend.html - - name: Upload coverage file - uses: actions/upload-artifact@v4 - with: - name: backend-cov - path: | - backend.cov - backend-funcs.log - backend.html - retention-days: 30 - compression-level: 9 # this is raw text, and includes a _lot_ of repetition. compressing it should yield pretty good results. - - name: Delete old coverage files - # This is a community tool, not one provided by GitHub. Hence it shall be pinned to a hash. - # https://github.com/GeekyEggo/delete-artifact/tree/v5 - uses: GeekyEggo/delete-artifact@f275313e70c08f6120db482d7a6b98377786765b - with: - name: | - unit-cov - integration-cov - failOnError: false # oh well, we'll just have the extra artifacts... - - name: Set summary to total coverage - # We use single quotes here to disable the bash backtick behaviour of executing commands. - run: | - echo '# Coverage' >> $GITHUB_STEP_SUMMARY - echo '```' >> $GITHUB_STEP_SUMMARY - grep 'total:' backend-funcs.log | tr '\t' ' ' >> $GITHUB_STEP_SUMMARY - echo '```' >> $GITHUB_STEP_SUMMARY \ No newline at end of file diff --git a/.github/workflows/pr-test-backend.yml b/.github/workflows/pr-test-backend.yml new file mode 100644 index 00000000000..da7e3450a54 --- /dev/null +++ b/.github/workflows/pr-test-backend.yml @@ -0,0 +1,106 @@ +name: Test Backend + +on: + workflow_dispatch: + push: + branches: + - main + paths-ignore: + - 'docs/**' + - '**/*.md' + pull_request: + paths-ignore: + - 'docs/**' + - '**/*.md' + +permissions: + contents: read + id-token: write + +env: + EDITION: 'oss' + +jobs: + test-backend: + name: Test Backend + runs-on: ubuntu-latest + continue-on-error: true + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version: '1.23.5' + cache: true + + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y build-essential shared-mime-info make + + - name: Get runner name + run: echo ${{ runner.name }} + + - name: Setup Enterprise (PR only) + if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == false + uses: ./.github/actions/setup-enterprise + + - name: Verify CUE generation + run: CODEGEN_VERIFY=1 make gen-cue + + - name: Verify Jsonnet generation + run: CODEGEN_VERIFY=1 make gen-jsonnet + + - name: Check if coverage should be generated + id: check-coverage + env: + GH_TOKEN: ${{ github.token }} + run: | + echo "Event: ${{ github.event_name }}" + echo "Ref: ${{ github.ref }}" + + if [[ "${{ github.event_name }}" == "pull_request" ]]; then + echo "PR changed files:" + files=$(gh api repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/files --jq '.[].filename') + echo "$files" + if echo "$files" | grep -E "(pkg/|go\.)"; then + echo "Coverage will be generated: true (PR changes)" + echo "generate=true" >> $GITHUB_OUTPUT + else + echo "Coverage will be generated: false" + echo "generate=false" >> $GITHUB_OUTPUT + fi + elif [[ "${{ github.event_name }}" == "push" && "${{ github.ref }}" == "refs/heads/main" ]] && \ + [[ "${{ github.event.head_commit.modified }}" =~ (pkg/|go\.|\.github/workflows/pr-test-backend\.yml) ]]; then + echo "Coverage will be generated: true (push to main)" + echo "generate=true" >> $GITHUB_OUTPUT + else + echo "Coverage will be generated: false" + echo "generate=false" >> $GITHUB_OUTPUT + fi + + - name: Run backend tests + uses: ./.github/actions/run-backend-tests + with: + coverage-opts: ${{ steps.check-coverage.outputs.generate == 'true' && '-coverprofile=unit.cov -coverpkg=github.com/grafana/grafana/...' || '' }} + test-command: 'make gen-go test-go-unit' + + - name: Run backend integration tests + uses: ./.github/actions/run-backend-tests + with: + coverage-opts: ${{ steps.check-coverage.outputs.generate == 'true' && '-coverprofile=integration.cov -coverpkg=github.com/grafana/grafana/...' || '' }} + test-command: 'make gen-go test-go-integration' + + - name: Generate Coverage Report + if: steps.check-coverage.outputs.generate == 'true' + uses: ./.github/actions/report-coverage + with: + unit-cov-path: unit.cov + integration-cov-path: integration.cov + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true