diff --git a/.github/actions/setup-enterprise/action.yml b/.github/actions/setup-enterprise/action.yml new file mode 100644 index 00000000000..37c09911fc8 --- /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 # zizmor: ignore[unpinned-uses] + 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/actions/setup-grafana-bench/action.yml b/.github/actions/setup-grafana-bench/action.yml index 624ad243b7b..f30cc37221d 100644 --- a/.github/actions/setup-grafana-bench/action.yml +++ b/.github/actions/setup-grafana-bench/action.yml @@ -16,7 +16,7 @@ runs: steps: - name: Retrieve GitHub App secrets id: get-secrets - uses: grafana/shared-workflows/actions/get-vault-secrets@get-vault-secrets-v1.0.1 + uses: grafana/shared-workflows/actions/get-vault-secrets@get-vault-secrets-v1.0.1 # zizmor: ignore[unpinned-uses] with: repo_secrets: | APP_ID=${{ inputs.github-app-name }}:app-id @@ -36,9 +36,10 @@ runs: shell: bash env: GH_TOKEN: ${{ steps.generate_token.outputs.token }} + BRANCH: ${{ inputs.branch }} run: | git clone https://x-access-token:${GH_TOKEN}@github.com/grafana/grafana-bench.git ../grafana-bench cd ../grafana-bench - git switch ${{ inputs.branch }} + git switch "$BRANCH" go install . diff --git a/.github/actions/test-coverage-processor/action.yml b/.github/actions/test-coverage-processor/action.yml index 7560031e846..bd2458020c3 100644 --- a/.github/actions/test-coverage-processor/action.yml +++ b/.github/actions/test-coverage-processor/action.yml @@ -28,15 +28,17 @@ runs: steps: - name: Process Go coverage output shell: bash + env: + COVERAGE_FILE: ${{ inputs.coverage-file }} run: | # Ensure valid coverage file even if empty - if [ ! -s ${{ inputs.coverage-file }} ]; then + if [ ! -s "$COVERAGE_FILE" ]; then echo "Coverage file is empty, creating a minimal valid file" - echo "mode: set" > ${{ inputs.coverage-file }} + echo "mode: set" > "$COVERAGE_FILE" fi - name: Report coverage to CodeCov - uses: codecov/codecov-action@v5 + uses: codecov/codecov-action@ad3126e916f78f00edff4ed0317cf185271ccc2d # v5 if: inputs.codecov-token != '' with: files: ${{ inputs.coverage-file }} diff --git a/.github/workflows/alerting-swagger-gen.yml b/.github/workflows/alerting-swagger-gen.yml index 7c3af87837f..2526d924d5e 100644 --- a/.github/workflows/alerting-swagger-gen.yml +++ b/.github/workflows/alerting-swagger-gen.yml @@ -10,18 +10,19 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 with: fetch-depth: 2 + persist-credentials: false - name: Set go version - uses: actions/setup-go@v4 + uses: actions/setup-go@19bb51245e9c80abacb2e91cc42b33fa478b8639 with: go-version-file: go.mod - name: Build swagger run: | make -C pkg/services/ngalert/api/tooling post.json api.json - name: Open Pull Request - uses: peter-evans/create-pull-request@v5 + uses: peter-evans/create-pull-request@4e1beaa7521e8b457b572c090b25bd3db56bf1c5 with: token: ${{ secrets.GITHUB_TOKEN }} commit-message: "chore: update alerting swagger spec" @@ -34,4 +35,3 @@ jobs: labels: 'area/alerting,type/docs,no-changelog' team-reviewers: 'grafana/alerting-backend' draft: false - diff --git a/.github/workflows/alerting-update-module.yml b/.github/workflows/alerting-update-module.yml index 213b243f9b1..d1646d21718 100644 --- a/.github/workflows/alerting-update-module.yml +++ b/.github/workflows/alerting-update-module.yml @@ -18,7 +18,8 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # 4.2.2 - + with: + persist-credentials: false - name: Check if update branch exists run: | if git ls-remote --heads origin update-alerting-module | grep -q 'update-alerting-module'; then @@ -96,7 +97,7 @@ jobs: make update-workspace - id: get-secrets - uses: grafana/shared-workflows/actions/get-vault-secrets@28361cdb22223e5f1e34358c86c20908e7248760 # 1.1.0 + uses: grafana/shared-workflows/actions/get-vault-secrets@main # zizmor: ignore[unpinned-uses] with: repo_secrets: | GITHUB_APP_ID=alerting-team:app-id diff --git a/.github/workflows/analytics-events-report.yml b/.github/workflows/analytics-events-report.yml index 9d4d6907256..9c5c6f3ef09 100644 --- a/.github/workflows/analytics-events-report.yml +++ b/.github/workflows/analytics-events-report.yml @@ -8,10 +8,12 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + persist-credentials: false - name: Setup Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e with: node-version-file: '.nvmrc' cache: 'yarn' diff --git a/.github/workflows/auto-milestone.yml b/.github/workflows/auto-milestone.yml index 0697888fba0..77daec36bca 100644 --- a/.github/workflows/auto-milestone.yml +++ b/.github/workflows/auto-milestone.yml @@ -21,7 +21,7 @@ jobs: # Note: Github will not trigger other actions from this because it uses # the GITHUB_TOKEN token - name: Run auto-milestone - uses: grafana/grafana-github-actions-go/auto-milestone@main + uses: grafana/grafana-github-actions-go/auto-milestone@d4c452f92ed826d515dccf1f62923e537953acd8 # main with: pr: ${{ github.event.pull_request.number }} token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/auto-triager/labels.txt b/.github/workflows/auto-triager/labels.txt index 1a33cf676dc..517a6ad867d 100644 --- a/.github/workflows/auto-triager/labels.txt +++ b/.github/workflows/auto-triager/labels.txt @@ -33,7 +33,6 @@ area/dashboard/variable area/dashboards/panel area/data/export area/explore -area/exploremetrics area/expressions area/field/overrides area/frontend/library-panels @@ -42,6 +41,7 @@ area/image-rendering area/internationalization area/legend area/library-panel +area/metricsdrilldown area/navigation area/panel/annotation-list area/panel/barchart diff --git a/.github/workflows/backend-code-checks.yml b/.github/workflows/backend-code-checks.yml new file mode 100644 index 00000000000..b55c07aed22 --- /dev/null +++ b/.github/workflows/backend-code-checks.yml @@ -0,0 +1,74 @@ +name: Backend Code Checks +description: Validate go.mod and OpenAPI specifications + +on: + pull_request: + paths-ignore: + - '*.md' + - 'docs/**' + - 'latest.json' + push: + branches: + - main + paths-ignore: + - '*.md' + - 'docs/**' + - 'latest.json' + +permissions: + contents: read + id-token: write + +jobs: + validate-configs: + name: Validate Backend Configs + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + persist-credentials: false + - name: Setup Go + uses: actions/setup-go@111f3307d8850f501ac008e886eec1fd1932a34 + with: + # Explicitly set Go version to 1.24.1 to ensure consistent OpenAPI spec generation + # The crypto/x509 package has additional fields in Go 1.24.1 that affect the generated specs + # This ensures the GHAs environment matches what we use in the Drone pipeline + go-version: 1.24.1 + cache: true + + - name: Verify code generation + run: | + CODEGEN_VERIFY=1 make gen-cue + CODEGEN_VERIFY=1 make gen-jsonnet + + - name: Validate go.mod + run: go run scripts/modowners/modowners.go check go.mod + + # Enterprise setup is needed for complete OpenAPI spec generation + # We only do this for internal PRs + - name: Setup Grafana Enterprise + if: github.event.pull_request.head.repo.fork == false + uses: ./.github/actions/setup-enterprise + + - name: Generate and Validate OpenAPI Specs + run: | + # For PRs from forks, we'll just run the basic swagger-gen without validation + if [[ "${{ github.event_name }}" == "pull_request" && "${{ github.event.pull_request.head.repo.fork }}" == "true" ]]; then + echo "PR is from a fork, skipping enterprise-based validation" + make swagger-gen + exit 0 + fi + + # Clean and regenerate OpenAPI specs + make swagger-clean && make openapi3-gen + + # Check if the generated specs differ from what's in the repository + for f in public/api-merged.json public/openapi3.json; do git add $f; done + if [ -z "$(git diff --name-only --cached)" ]; then + echo "OpenAPI specs are up to date!" + else + echo "OpenAPI specs are OUT OF DATE!" + git diff --cached + echo "Please ensure the branch is up-to-date, then regenerate the specification by running make swagger-clean && make openapi3-gen" + exit 1 + fi diff --git a/.github/workflows/backend-unit-tests.yml b/.github/workflows/backend-unit-tests.yml new file mode 100644 index 00000000000..2c0c238d502 --- /dev/null +++ b/.github/workflows/backend-unit-tests.yml @@ -0,0 +1,71 @@ +name: Backend Unit Tests + +on: + pull_request: + paths-ignore: + - 'docs/**' + - '**/*.md' + push: + branches: + - main + - release-*.*.* + paths-ignore: + - 'docs/**' + - '**/*.md' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ startsWith(github.ref, 'refs/pull/') }} + +permissions: {} + +jobs: + grafana: + # Run this workflow only for PRs from forks; if it gets merged into `main` or `release-*`, + # the `pr-backend-unit-tests-enterprise` workflow will run instead + if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == true + name: Grafana + runs-on: ubuntu-latest-8-cores + continue-on-error: true + permissions: + contents: read + id-token: write + steps: + - name: Checkout code + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + persist-credentials: false + - name: Setup Go + uses: actions/setup-go@111f3307d8850f501ac008e886eec1fd1932a34 + with: + go-version-file: go.mod + - name: Generate Go code + run: make gen-go + - name: Run unit tests + run: make test-go-unit + + grafana-enterprise: + # 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 + name: Grafana Enterprise + runs-on: ubuntu-latest-8-cores + permissions: + contents: read + id-token: write + steps: + - name: Checkout code + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + persist-credentials: false + - name: Setup Go + uses: actions/setup-go@111f3307d8850f501ac008e886eec1fd1932a34 + with: + go-version-file: go.mod + - name: Setup Enterprise + uses: ./.github/actions/setup-enterprise + with: + github-app-name: 'grafana-ci-bot' + - name: Generate Go code + run: make gen-go + - name: Run unit tests + run: make test-go-unit diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml index 5f21ab276ee..fc65898f652 100644 --- a/.github/workflows/backport.yml +++ b/.github/workflows/backport.yml @@ -5,23 +5,28 @@ on: - closed - labeled +permissions: + contents: write + pull-requests: write + jobs: main: if: github.repository == 'grafana/grafana' runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4 - - name: "Generate token" - id: generate_token - uses: tibdex/github-app-token@b62528385c34dbc9f38e5f4225ac829252d1ea92 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # 4.2.2 with: - app_id: ${{ secrets.GRAFANA_DELIVERY_BOT_APP_ID }} - private_key: ${{ secrets.GRAFANA_DELIVERY_BOT_APP_PEM }} - - run: git config --global user.email '132647405+grafana-delivery-bot[bot]@users.noreply.github.com' - - run: git config --global user.name 'grafana-delivery-bot[bot]' - - run: git remote set-url origin "https://grafana-delivery-bot:${{ steps.generate_token.outputs.token }}@github.com/grafana/grafana.git" + persist-credentials: false + - run: git config --local user.name "github-actions[bot]" + - run: git config --local user.email "github-actions[bot]@users.noreply.github.com" + - run: git config --local --add --bool push.autoSetupRemote true + - name: Set remote URL + env: + GIT_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + git remote set-url origin "https://grafana-delivery-bot:$GIT_TOKEN@github.com/grafana/grafana.git" - name: Run backport - uses: grafana/grafana-github-actions-go/backport@main + uses: grafana/grafana-github-actions-go/backport@main # zizmor: ignore[unpinned-uses] with: - token: ${{ steps.generate_token.outputs.token }} + token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/bump-version.yml b/.github/workflows/bump-version.yml index 5f0b7cf3020..8db9fb1e5c3 100644 --- a/.github/workflows/bump-version.yml +++ b/.github/workflows/bump-version.yml @@ -11,33 +11,37 @@ on: dry_run: default: false required: false + +permissions: + contents: write + pull-requests: write + jobs: - main: + bump-version: runs-on: ubuntu-latest steps: - name: Checkout Grafana - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + persist-credentials: false - name: Update package.json versions uses: ./pkg/build/actions/bump-version with: version: ${{ inputs.version }} - - if: ${{ inputs.push }} - name: Generate token - id: generate_token - uses: tibdex/github-app-token@b62528385c34dbc9f38e5f4225ac829252d1ea92 - with: - app_id: ${{ secrets.GRAFANA_DELIVERY_BOT_APP_ID }} - private_key: ${{ secrets.GRAFANA_DELIVERY_BOT_APP_PEM }} - if: ${{ inputs.push }} name: Push & Create PR + env: + VERSION: ${{ inputs.version }} + DRY_RUN: ${{ inputs.dry_run }} + REF_NAME: ${{ github.ref_name }} + RUN_ID: ${{ github.run_id }} + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | git config --local user.name "github-actions[bot]" git config --local user.email "github-actions[bot]@users.noreply.github.com" git config --local --add --bool push.autoSetupRemote true - git checkout -b "bump-version/${{ github.run_id }}/${{ inputs.version }}" + git checkout -b "bump-version/${RUN_ID}/${VERSION}" git add . - git commit -m "bump version ${{ inputs.version }}" + git commit -m "bump version ${VERSION}" git push - gh pr create --dry-run=${{ inputs.dry_run }} -l "type/ci" -l "no-changelog" -B "${{ github.ref_name }}" --title "Release: Bump version to ${{ inputs.version }}" --body "Updated version to ${{ inputs.version }}" - env: - GH_TOKEN: ${{ steps.generate_token.outputs.token }} + gh pr create --dry-run=$DRY_RUN -l "type/ci" -l "no-changelog" -B "$REF_NAME" --title "Release: Bump version to ${VERSION}" --body "Updated version to ${VERSION}" diff --git a/.github/workflows/changelog.yml b/.github/workflows/changelog.yml index d23ca18e612..094279e0c9a 100644 --- a/.github/workflows/changelog.yml +++ b/.github/workflows/changelog.yml @@ -51,15 +51,20 @@ on: default: false type: boolean -permissions: - contents: write - pull-requests: write +permissions: {} jobs: main: + env: + RUN_ID: ${{ github.run_id }} + VERSION: ${{ inputs.version }} + PREVIOUS_VERISON: ${{ inputs.previous_version }} + TARGET: ${{ inputs.target }} + DRY_RUN: ${{ inputs.dry_run }} runs-on: ubuntu-latest permissions: contents: write + pull-requests: write steps: - name: "Generate token" id: generate_token @@ -68,7 +73,7 @@ jobs: app_id: ${{ secrets.GRAFANA_DELIVERY_BOT_APP_ID }} private_key: ${{ secrets.GRAFANA_DELIVERY_BOT_APP_PEM }} - name: "Checkout Grafana repo" - uses: "actions/checkout@v4" + uses: "actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683" with: ref: main sparse-checkout: | @@ -79,8 +84,9 @@ jobs: .prettierrc.js fetch-depth: 0 fetch-tags: true + persist-credentials: false - name: Setup nodejs environment - uses: actions/setup-node@v4 + uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e with: node-version-file: .nvmrc - name: "Configure git user" @@ -89,7 +95,7 @@ jobs: git config --local user.email "github-actions[bot]@users.noreply.github.com" git config --local --add --bool push.autoSetupRemote true - name: "Create branch" - run: git checkout -b "changelog/${{ github.run_id }}/${{ inputs.version }}" + run: git checkout -b "changelog/${RUN_ID}/${VERSION}" - name: "Generate changelog" id: changelog uses: ./.github/workflows/actions/changelog @@ -103,24 +109,24 @@ jobs: # Prepare CHANGELOG.md content with version delimiters ( echo - echo "# ${{ inputs.version}} ($(date '+%F'))" + echo "# ${VERSION} ($(date '+%F'))" echo cat changelog_items.md ) > CHANGELOG.part # Check if a version exists in the changelog - if grep -q "" + echo "" cat CHANGELOG.part - echo "" + echo "" cat CHANGELOG.md ) > CHANGELOG.tmp mv CHANGELOG.tmp CHANGELOG.md @@ -138,11 +144,11 @@ jobs: - name: "Create changelog PR" run: > gh pr create \ - --dry-run=${{ inputs.dry_run }} \ + --dry-run=${DRY_RUN} \ --label "no-backport" \ --label "no-changelog" \ - -B "${{ inputs.target }}" \ - --title "Release: update changelog for ${{ inputs.version }}" \ - --body "Changelog changes for release ${{ inputs.version }}" + -B "${TARGET}" \ + --title "Release: update changelog for ${VERSION}" \ + --body "Changelog changes for release ${VERSION}" env: - GH_TOKEN: ${{ steps.generate_token.outputs.token }} + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/close-milestone.yml b/.github/workflows/close-milestone.yml deleted file mode 100644 index 11613b5fab9..00000000000 --- a/.github/workflows/close-milestone.yml +++ /dev/null @@ -1,44 +0,0 @@ -name: Close milestone -on: - workflow_dispatch: - inputs: - version: - required: true - description: Needs to match, exactly, the name of a milestone - workflow_call: - inputs: - version_call: - description: Needs to match, exactly, the name of a milestone - required: true - type: string - -jobs: - main: - if: github.repository == 'grafana/grafana' - runs-on: ubuntu-latest - steps: - - name: Checkout Actions - uses: actions/checkout@v4 - with: - repository: "grafana/grafana-github-actions" - path: ./actions - ref: main - - name: Install Actions - run: npm install --production --prefix ./actions - - name: "Generate token" - id: generate_token - uses: tibdex/github-app-token@b62528385c34dbc9f38e5f4225ac829252d1ea92 - with: - app_id: ${{ secrets.GRAFANA_DELIVERY_BOT_APP_ID }} - private_key: ${{ secrets.GRAFANA_DELIVERY_BOT_APP_PEM }} - - name: Close milestone (manually invoked) - if: ${{ github.event.inputs.version != '' }} - uses: ./actions/close-milestone - with: - token: ${{ steps.generate_token.outputs.token }} - - name: Close milestone (workflow invoked) - if: ${{ inputs.version_call != '' }} - uses: ./actions/close-milestone - with: - version_call: ${{ inputs.version_call }} - token: ${{ steps.generate_token.outputs.token }} diff --git a/.github/workflows/codeowners-validator.yml b/.github/workflows/codeowners-validator.yml index 12184b2f680..f98bee4e213 100644 --- a/.github/workflows/codeowners-validator.yml +++ b/.github/workflows/codeowners-validator.yml @@ -9,9 +9,11 @@ jobs: runs-on: ubuntu-latest steps: # Checks-out your repository, which is validated in the next step - - uses: actions/checkout@v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + persist-credentials: false - name: GitHub CODEOWNERS Validator - uses: mszostok/codeowners-validator@v0.7.4 + uses: mszostok/codeowners-validator@7f3f5e28c6d7b8dfae5731e54ce2272ca384592f # input parameters with: # ==== GitHub Auth ==== diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index c1f90ceb831..06772bac55c 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -3,18 +3,19 @@ # # You may wish to alter this file to override the set of languages analyzed, # or to provide custom queries or build logic. -name: "CodeQL" +name: "CodeQL checks" on: workflow_dispatch: push: - branches: [main, v1.8.x, v2.0.x, v2.1.x, v2.6.x, v3.0.x, v3.1.x, v4.0.x, v4.1.x, v4.2.x, v4.3.x, v4.4.x, v4.5.x, v4.6.x, v4.7.x, v5.0.x, v5.1.x, v5.2.x, v5.3.x, v5.4.x, v6.0.x, v6.1.x, v6.2.x, v6.3.x, v6.4.x, v6.5.x, v6.6.x, v6.7.x, v7.0.x, v7.1.x, v7.2.x] + branches: ['**'] # run on all branches paths-ignore: - '**/*.cue' - '**/*.json' - '**/*.md' - '**/*.txt' - '**/*.yml' + - pkg/storage/unified/sql/db/dbimpl/db.go # Ignoring warnings on the whole file for now while inline comments is not supported in Go (https://github.com/github/codeql/issues/11427) schedule: - cron: '0 4 * * 6' @@ -25,6 +26,7 @@ jobs: analyze: name: Analyze runs-on: ubuntu-latest + continue-on-error: true # doesn't block PRs from being merged if this fails if: github.repository == 'grafana/grafana' strategy: @@ -38,15 +40,16 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 with: # We must fetch at least the immediate parents so that if this is # a pull request then we can checkout the head. fetch-depth: 2 + persist-credentials: false - if: matrix.language == 'go' name: Set go version - uses: actions/setup-go@v4 + uses: actions/setup-go@19bb51245e9c80abacb2e91cc42b33fa478b8639 with: go-version-file: go.mod diff --git a/.github/workflows/commands.yml b/.github/workflows/commands.yml index f733b2f244d..cf61d859443 100644 --- a/.github/workflows/commands.yml +++ b/.github/workflows/commands.yml @@ -12,9 +12,7 @@ on: concurrency: group: issue-commands-${{ github.event.issue.number }} -permissions: - contents: read - id-token: write +permissions: {} jobs: config: @@ -34,10 +32,13 @@ jobs: needs: config if: needs.config.outputs.has-secrets runs-on: ubuntu-latest + permissions: + contents: read + id-token: write steps: - name: "Get vault secrets" id: vault-secrets - uses: grafana/shared-workflows/actions/get-vault-secrets@main + uses: grafana/shared-workflows/actions/get-vault-secrets@main # zizmor: ignore[unpinned-uses] with: # Secrets placed in the ci/repo/grafana/grafana/plugins_platform_issue_commands_github_bot path in Vault repo_secrets: | @@ -52,11 +53,12 @@ jobs: private_key: ${{ env.GH_APP_PEM }} - name: Checkout Actions - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: repository: "grafana/grafana-github-actions" path: ./actions ref: main + persist-credentials: false - name: Install Actions run: npm install --production --prefix ./actions diff --git a/.github/workflows/community-release.yml b/.github/workflows/community-release.yml index 86e7703e5c4..73c72749baa 100644 --- a/.github/workflows/community-release.yml +++ b/.github/workflows/community-release.yml @@ -36,7 +36,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Run community-release (manually invoked) - uses: grafana/grafana-github-actions-go/community-release@main + uses: grafana/grafana-github-actions-go/community-release@main # zizmor: ignore[unpinned-uses] with: token: ${{ secrets.GITHUB_TOKEN }} version: ${{ inputs.version }} diff --git a/.github/workflows/core-plugins-build-and-release.yml b/.github/workflows/core-plugins-build-and-release.yml index e4803a2208f..d2aebbc41e8 100644 --- a/.github/workflows/core-plugins-build-and-release.yml +++ b/.github/workflows/core-plugins-build-and-release.yml @@ -33,6 +33,8 @@ permissions: jobs: build-and-publish: + env: + PLUGIN_ID: ${{ inputs.plugin_id }} name: Build and publish ${{ inputs.plugin_id }} runs-on: ubuntu-latest outputs: @@ -41,12 +43,14 @@ jobs: version: ${{ steps.build_frontend.outputs.version }} steps: - name: checkout - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + persist-credentials: false - name: Verify inputs run: | - if [ -z ${{ inputs.plugin_id }} ]; then echo "Missing plugin ID"; exit 1; fi + if [ -z $PLUGIN_ID ]; then echo "Missing plugin ID"; exit 1; fi - id: get-secrets - uses: grafana/shared-workflows/actions/get-vault-secrets@main + uses: grafana/shared-workflows/actions/get-vault-secrets@main # zizmor: ignore[unpinned-uses] with: # Secrets placed in the ci/repo/grafana// path in Vault repo_secrets: | @@ -54,13 +58,13 @@ jobs: PLUGINS_GRAFANA_API_KEY=core-plugins-build-and-release:PLUGINS_GRAFANA_API_KEY PLUGINS_GCOM_TOKEN=core-plugins-build-and-release:PLUGINS_GCOM_TOKEN - name: 'Authenticate to Google Cloud' - uses: 'google-github-actions/auth@v2' + uses: 'google-github-actions/auth@6fc4af4b145ae7821d527454aa9bd537d1f2dc5f' with: credentials_json: '${{ env.PLUGINS_GOOGLE_CREDENTIALS }}' - name: 'Set up Cloud SDK' - uses: 'google-github-actions/setup-gcloud@v2' + uses: 'google-github-actions/setup-gcloud@6189d56e4096ee891640bb02ac264be376592d6a' - name: Setup nodejs environment - uses: actions/setup-node@v4 + uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e with: node-version-file: .nvmrc cache: yarn @@ -70,7 +74,7 @@ jobs: run: | dir=$(dirname \ $(egrep -lir --include=plugin.json --exclude-dir=dist \ - '"id": "${{ inputs.plugin_id }}"' \ + '"id": "${PLUGIN_ID}"' \ public/app/plugins \ ) \ ) @@ -85,19 +89,19 @@ jobs: working-directory: ${{ steps.get_dir.outputs.dir }} run: | [ ! -d ./bin ] && mkdir -pv ./bin || true - curl -fL -o ./bin/grabpl https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v${{ env.GRABPL_VERSION }}/grabpl + curl -fL -o ./bin/grabpl https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v$GRABPL_VERSION/grabpl chmod 0755 ./bin/grabpl - name: Check backend id: check_backend shell: bash run: | - if egrep -qr --include=main.go 'datasource.Manage\("${{ inputs.plugin_id }}"' pkg/tsdb; then + if egrep -qr --include=main.go 'datasource.Manage\("$PLUGIN_ID"' pkg/tsdb; then echo "has_backend=true" >> $GITHUB_OUTPUT else echo "has_backend=false" >> $GITHUB_OUTPUT fi - name: Setup golang environment - uses: actions/setup-go@v4 + uses: actions/setup-go@19bb51245e9c80abacb2e91cc42b33fa478b8639 if: steps.check_backend.outputs.has_backend == 'true' with: go-version-file: go.mod @@ -151,7 +155,7 @@ jobs: # Release branch, do not add commit hash to version command="plugin:build" fi - yarn $command --scope="@grafana-plugins/${{ inputs.plugin_id }}" + yarn $command --scope="@grafana-plugins/$PLUGIN_ID" version=$(cat ${{ steps.get_dir.outputs.dir }}/dist/plugin.json | jq -r .info.version) echo "version=${version}" >> $GITHUB_OUTPUT - name: build:backend @@ -160,7 +164,7 @@ jobs: env: VERSION: ${{ steps.build_frontend.outputs.version }} run: | - make build-plugin-go PLUGIN_ID=${{ inputs.plugin_id }} + make build-plugin-go PLUGIN_ID=$PLUGIN_ID - name: package working-directory: ${{ steps.get_dir.outputs.dir }} run: | @@ -175,7 +179,7 @@ jobs: VERSION: ${{ steps.build_frontend.outputs.version }} run: | api_res=$(curl -X 'GET' -H "Authorization: Bearer $GCOM_TOKEN" \ - '${{ env.GCOM_API}}/api/plugins/${{ inputs.plugin_id }}?version=$VERSION' \ + '${{ env.GCOM_API}}/api/plugins/$PLUGIN_ID?version=$VERSION' \ -H 'accept: application/json') api_res_code=$(echo $api_res | jq -r .code) if [ "$api_res_code" = "NotFound" ]; then @@ -197,10 +201,10 @@ jobs: run: | echo "Publish release to Google Cloud Storage:" touch ci/packages/windows ci/packages/darwin ci/packages/linux ci/packages/any - gsutil -m cp -r ci/packages/*windows* gs://${{ env.GCP_BUCKET }}/${{ inputs.plugin_id }}/release/${VERSION}/windows - gsutil -m cp -r ci/packages/*linux* gs://${{ env.GCP_BUCKET }}/${{ inputs.plugin_id }}/release/${VERSION}/linux - gsutil -m cp -r ci/packages/*darwin* gs://${{ env.GCP_BUCKET }}/${{ inputs.plugin_id }}/release/${VERSION}/darwin - gsutil -m cp -r ci/packages/*any* gs://${{ env.GCP_BUCKET }}/${{ inputs.plugin_id }}/release/${VERSION}/any + gsutil -m cp -r ci/packages/*windows* gs://${{ env.GCP_BUCKET }}/$PLUGIN_ID/release/${VERSION}/windows + gsutil -m cp -r ci/packages/*linux* gs://${{ env.GCP_BUCKET }}/$PLUGIN_ID/release/${VERSION}/linux + gsutil -m cp -r ci/packages/*darwin* gs://${{ env.GCP_BUCKET }}/$PLUGIN_ID/release/${VERSION}/darwin + gsutil -m cp -r ci/packages/*any* gs://${{ env.GCP_BUCKET }}/$PLUGIN_ID/release/${VERSION}/any - name: Publish new plugin version on grafana.com if: steps.check_backend.outputs.has_backend == 'true' working-directory: ${{ steps.get_dir.outputs.dir }} @@ -214,27 +218,27 @@ jobs: \"url\": \"https://github.com/grafana/grafana/tree/main/${{ steps.get_dir.outputs.dir }}\", \"download\": { \"linux-amd64\": { - \"url\": \"https://storage.googleapis.com/${{ env.GCP_BUCKET }}/${{ inputs.plugin_id }}/release/${VERSION}/linux/${{ inputs.plugin_id }}-${VERSION}.linux_amd64.zip\", + \"url\": \"https://storage.googleapis.com/${{ env.GCP_BUCKET }}/$PLUGIN_ID/release/${VERSION}/linux/$PLUGIN_ID-${VERSION}.linux_amd64.zip\", \"md5\": \"$(cat ci/packages/info-linux_amd64.json | jq -r .plugin.md5)\" }, \"linux-arm64\": { - \"url\": \"https://storage.googleapis.com/${{ env.GCP_BUCKET }}/${{ inputs.plugin_id }}/release/${VERSION}/linux/${{ inputs.plugin_id }}-${VERSION}.linux_arm64.zip\", + \"url\": \"https://storage.googleapis.com/${{ env.GCP_BUCKET }}/$PLUGIN_ID/release/${VERSION}/linux/$PLUGIN_ID-${VERSION}.linux_arm64.zip\", \"md5\": \"$(cat ci/packages/info-linux_arm64.json | jq -r .plugin.md5)\" }, \"linux-arm\": { - \"url\": \"https://storage.googleapis.com/${{ env.GCP_BUCKET }}/${{ inputs.plugin_id }}/release/${VERSION}/linux/${{ inputs.plugin_id }}-${VERSION}.linux_arm.zip\", + \"url\": \"https://storage.googleapis.com/${{ env.GCP_BUCKET }}/$PLUGIN_ID/release/${VERSION}/linux/$PLUGIN_ID-${VERSION}.linux_arm.zip\", \"md5\": \"$(cat ci/packages/info-linux_arm.json | jq -r .plugin.md5)\" }, \"windows-amd64\": { - \"url\": \"https://storage.googleapis.com/${{ env.GCP_BUCKET }}/${{ inputs.plugin_id }}/release/${VERSION}/windows/${{ inputs.plugin_id }}-${VERSION}.windows_amd64.zip\", + \"url\": \"https://storage.googleapis.com/${{ env.GCP_BUCKET }}/$PLUGIN_ID/release/${VERSION}/windows/$PLUGIN_ID-${VERSION}.windows_amd64.zip\", \"md5\": \"$(cat ci/packages/info-windows_amd64.json | jq -r .plugin.md5)\" }, \"darwin-amd64\": { - \"url\": \"https://storage.googleapis.com/${{ env.GCP_BUCKET }}/${{ inputs.plugin_id }}/release/${VERSION}/darwin/${{ inputs.plugin_id }}-${VERSION}.darwin_amd64.zip\", + \"url\": \"https://storage.googleapis.com/${{ env.GCP_BUCKET }}/$PLUGIN_ID/release/${VERSION}/darwin/$PLUGIN_ID-${VERSION}.darwin_amd64.zip\", \"md5\": \"$(cat ci/packages/info-darwin_amd64.json | jq -r .plugin.md5)\" }, \"darwin-arm64\": { - \"url\": \"https://storage.googleapis.com/${{ env.GCP_BUCKET }}/${{ inputs.plugin_id }}/release/${VERSION}/darwin/${{ inputs.plugin_id }}-${VERSION}.darwin_arm64.zip\", + \"url\": \"https://storage.googleapis.com/${{ env.GCP_BUCKET }}/$PLUGIN_ID/release/${VERSION}/darwin/$PLUGIN_ID-${VERSION}.darwin_arm64.zip\", \"md5\": \"$(cat ci/packages/info-darwin_arm64.json | jq -r .plugin.md5)\" } } @@ -257,7 +261,7 @@ jobs: \"url\": \"https://github.com/grafana/grafana/tree/main/${{ steps.get_dir.outputs.dir }}\", \"download\": { \"any\": { - \"url\": \"https://storage.googleapis.com/${{ env.GCP_BUCKET }}/${{ inputs.plugin_id }}/release/${VERSION}/any/${{ inputs.plugin_id }}-${VERSION}.any.zip\", + \"url\": \"https://storage.googleapis.com/${{ env.GCP_BUCKET }}/$PLUGIN_ID/release/${VERSION}/any/$PLUGIN_ID-${VERSION}.any.zip\", \"md5\": \"$(cat ci/packages/info-any.json | jq -r .plugin.md5)\" } } diff --git a/.github/workflows/create-next-release-branch.yml b/.github/workflows/create-next-release-branch.yml index 8fc01cd442d..1107842a765 100644 --- a/.github/workflows/create-next-release-branch.yml +++ b/.github/workflows/create-next-release-branch.yml @@ -46,7 +46,7 @@ jobs: private_key: ${{ secrets.GRAFANA_DELIVERY_BOT_APP_PEM }} - name: Create release branch id: branch - uses: grafana/grafana-github-actions-go/bump-release@main + uses: grafana/grafana-github-actions-go/bump-release@main # zizmor: ignore[unpinned-uses] with: ownerRepo: ${{ inputs.ownerRepo }} source: ${{ inputs.source }} diff --git a/.github/workflows/create-security-patch-from-security-mirror.yml b/.github/workflows/create-security-patch-from-security-mirror.yml index f85239241ad..7499d925236 100644 --- a/.github/workflows/create-security-patch-from-security-mirror.yml +++ b/.github/workflows/create-security-patch-from-security-mirror.yml @@ -17,7 +17,7 @@ on: jobs: trigger_downstream_create_security_patch: concurrency: create-patch-${{ github.ref_name }} - uses: grafana/security-patch-actions/.github/workflows/create-patch.yml@main + uses: grafana/security-patch-actions/.github/workflows/create-patch.yml@main # zizmor: ignore[unpinned-uses] if: github.repository == 'grafana/grafana-security-mirror' with: repo: "${{ github.repository }}" @@ -25,5 +25,4 @@ jobs: patch_ref: "${{ github.base_ref }}" # this is the target branch name, Ex: "main" patch_repo: "grafana/grafana-security-patches" patch_prefix: "${{ github.event.pull_request.number }}" - secrets: inherit - + secrets: inherit # zizmor: ignore[secrets-inherit] diff --git a/.github/workflows/dashboards-issue-add-label.yml b/.github/workflows/dashboards-issue-add-label.yml index 95abce4355b..4072f062fa7 100644 --- a/.github/workflows/dashboards-issue-add-label.yml +++ b/.github/workflows/dashboards-issue-add-label.yml @@ -22,7 +22,7 @@ jobs: steps: - name: "Get vault secrets" id: vault-secrets - uses: grafana/shared-workflows/actions/get-vault-secrets@main + uses: grafana/shared-workflows/actions/get-vault-secrets@main # zizmor: ignore[unpinned-uses] with: # Secrets placed in the ci/repo/grafana/grafana/plugins_platform_issue_commands_github_bot path in Vault repo_secrets: | @@ -38,11 +38,13 @@ jobs: - name: Check if issue is in target project env: GH_TOKEN: ${{ steps.generate_token.outputs.token }} + ISSUE_NUMBER: ${{ github.event.issue.number }} + TARGET_PROJECT: ${{ env.TARGET_PROJECT }} run: | gh api graphql -f query=' query($org: String!, $repo: String!) { repository(name: $repo, owner: $org) { - issue (number: ${{ github.event.issue.number }}) { + issue (number: $ISSUE_NUMBER) { id projectItems(first:20) { nodes { @@ -55,12 +57,14 @@ jobs: } }' -f org=$ORGANIZATION -f repo=$REPO > projects_data.json - echo 'IN_TARGET_PROJ='$(jq '.data.repository.issue.projectItems.nodes[] | select(.project.number==${{ env.TARGET_PROJECT }}) | .project != null' projects_data.json) >> $GITHUB_ENV + echo 'IN_TARGET_PROJ='$(jq '.data.repository.issue.projectItems.nodes[] | select(.project.number=='"$TARGET_PROJECT"') | .project != null' projects_data.json) >> $GITHUB_ENV echo 'ITEM_ID='$(jq '.data.repository.issue.id' projects_data.json) >> $GITHUB_ENV - name: Set up label array if: env.IN_TARGET_PROJ + env: + LABEL_IDS: ${{ env.LABEL_IDS }} run: | - IFS=',' read -ra LABEL_IDs <<< "${{ env.LABEL_IDs }}" + IFS=',' read -ra LABEL_IDs <<< "$LABEL_IDS" for item in "${LABEL_IDs[@]}"; do echo "Item: $item" done @@ -68,6 +72,7 @@ jobs: if: env.IN_TARGET_PROJ env: GH_TOKEN: ${{ steps.generate_token.outputs.token }} + LABEL_IDS: ${{ env.LABEL_IDS }} run: | gh api graphql -f query=' mutation ($labelableId: ID!, $labelIds: [ID!]!) { @@ -76,4 +81,4 @@ jobs: ) { clientMutationId } - }' -f labelableId=$ITEM_ID -f labelIds=${{ env.LABEL_IDs }} + }' -f labelableId=$ITEM_ID -f labelIds=$LABEL_IDS diff --git a/.github/workflows/deploy-pr-preview.yml b/.github/workflows/deploy-pr-preview.yml index bfad92ebf73..5c8f4733eeb 100644 --- a/.github/workflows/deploy-pr-preview.yml +++ b/.github/workflows/deploy-pr-preview.yml @@ -12,7 +12,7 @@ on: jobs: deploy-pr-preview: if: "!github.event.pull_request.head.repo.fork" - uses: grafana/writers-toolkit/.github/workflows/deploy-preview.yml@main + uses: grafana/writers-toolkit/.github/workflows/deploy-preview.yml@main # zizmor: ignore[unpinned-uses] with: branch: ${{ github.head_ref }} event_number: ${{ github.event.number }} diff --git a/.github/workflows/detect-breaking-changes-levitate.yml b/.github/workflows/detect-breaking-changes-levitate.yml index 70c823483d9..a2517d5e0a2 100644 --- a/.github/workflows/detect-breaking-changes-levitate.yml +++ b/.github/workflows/detect-breaking-changes-levitate.yml @@ -6,9 +6,7 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true -permissions: - contents: read - id-token: write +permissions: {} on: pull_request: @@ -24,12 +22,16 @@ jobs: defaults: run: working-directory: './pr' + permissions: + contents: read + id-token: write steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 with: path: './pr' - - uses: actions/setup-node@v4 + persist-credentials: false + - uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e with: node-version: 22.11.0 @@ -67,17 +69,20 @@ jobs: buildBase: name: Build Base packages artifacts runs-on: ubuntu-latest + permissions: + contents: read + id-token: write defaults: run: working-directory: './base' steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 with: path: './base' ref: ${{ github.event.pull_request.base.ref }} - - uses: actions/setup-node@v4 + - uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e with: node-version: 22.11.0 @@ -123,8 +128,8 @@ jobs: id-token: 'write' steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + - uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e with: node-version: 22.11.0 @@ -145,14 +150,14 @@ jobs: run: unzip -j base_built_packages.zip -d ./base && rm base_built_packages.zip - id: 'auth' - uses: 'google-github-actions/auth@v2' + uses: 'google-github-actions/auth@6fc4af4b145ae7821d527454aa9bd537d1f2dc5f' with: workload_identity_provider: ${{ secrets.WIF_PROVIDER }} service_account: ${{ secrets.LEVITATE_SA }} project_id: 'grafanalabs-global' - name: 'Set up Cloud SDK' - uses: 'google-github-actions/setup-gcloud@v2' + uses: 'google-github-actions/setup-gcloud@6189d56e4096ee891640bb02ac264be376592d6a' with: version: '>= 363.0.0' project_id: 'grafanalabs-global' @@ -180,6 +185,9 @@ jobs: name: Report breaking changes in PR comment runs-on: ubuntu-latest needs: ['Detect'] + permissions: + contents: read + id-token: write steps: - name: "Generate token" @@ -189,7 +197,7 @@ jobs: app_id: ${{ secrets.GRAFANA_PR_AUTOMATION_APP_ID }} private_key: ${{ secrets.GRAFANA_PR_AUTOMATION_APP_PEM }} - - uses: actions/checkout@v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - name: 'Download artifact' uses: actions/download-artifact@v4 @@ -238,7 +246,7 @@ jobs: # Comment on the PR - name: Comment on PR if: steps.levitate-run.outputs.exit_code == 1 - uses: marocchino/sticky-pull-request-comment@v2 + uses: marocchino/sticky-pull-request-comment@52423e01640425a022ef5fd42c6fb5f633a02728 with: header: levitate-breaking-change-comment number: ${{ github.event.pull_request.number }} @@ -255,7 +263,7 @@ jobs: # Remove comment from the PR (no more breaking changes) - name: Remove comment from PR if: steps.levitate-run.outputs.exit_code == 0 - uses: marocchino/sticky-pull-request-comment@v2 + uses: marocchino/sticky-pull-request-comment@52423e01640425a022ef5fd42c6fb5f633a02728 with: header: levitate-breaking-change-comment number: ${{ github.event.pull_request.number }} diff --git a/.github/workflows/doc-validator.yml b/.github/workflows/doc-validator.yml deleted file mode 100644 index 0e6f613da9b..00000000000 --- a/.github/workflows/doc-validator.yml +++ /dev/null @@ -1,26 +0,0 @@ -name: "doc-validator" -on: - workflow_dispatch: - inputs: - include: - description: | - Regular expression that matches paths to include in linting. - - For example: docs/sources/(?:alerting|fundamentals)/.+\.md - required: true -jobs: - doc-validator: - runs-on: "ubuntu-latest" - container: - image: "grafana/doc-validator:v5.2.0" - steps: - - name: "Checkout code" - uses: "actions/checkout@v4" - - name: "Run doc-validator tool" - # Only run doc-validator on specific directories. - run: > - doc-validator - '--include=${{ inputs.include }}' - '--skip-checks=^(?:image.+|canonical-does-not-match-pretty-URL)$' - ./docs/sources - /docs/grafana/latest diff --git a/.github/workflows/documentation-ci.yml b/.github/workflows/documentation-ci.yml index 4c688968a09..9b8bc7dc53b 100644 --- a/.github/workflows/documentation-ci.yml +++ b/.github/workflows/documentation-ci.yml @@ -10,10 +10,10 @@ jobs: container: image: grafana/vale:latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 with: persist-credentials: false - - uses: grafana/writers-toolkit/vale-action@vale-action/v1 + - uses: grafana/writers-toolkit/vale-action@vale-action/v1 # zizmor: ignore[unpinned-uses] with: - filter: '.Name in ["Grafana.WordList", "Grafana.Spelling", "Grafana.ProductPossessives"]' + filter: '.Name in ["Grafana.GrafanaCom", "Grafana.WordList", "Grafana.Spelling", "Grafana.ProductPossessives"]' token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/ephemeral-instances-pr-comment.yml b/.github/workflows/ephemeral-instances-pr-comment.yml index be07b7ef6ac..e60eca1bad4 100644 --- a/.github/workflows/ephemeral-instances-pr-comment.yml +++ b/.github/workflows/ephemeral-instances-pr-comment.yml @@ -41,12 +41,13 @@ jobs: private_key: ${{ secrets.EI_APP_PRIVATE_KEY }} - name: Checkout ephemeral instances repository - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 with: repository: grafana/ephemeral-grafana-instances-github-action token: ${{ steps.generate_token.outputs.token }} ref: main path: ephemeral + persist-credentials: false - name: build and deploy ephemeral instance uses: ./ephemeral diff --git a/.github/workflows/epic-add-to-platform-ux-parent-project.yml b/.github/workflows/epic-add-to-platform-ux-parent-project.yml deleted file mode 100644 index 97462269fce..00000000000 --- a/.github/workflows/epic-add-to-platform-ux-parent-project.yml +++ /dev/null @@ -1,149 +0,0 @@ -name: When epic issues changed in Platform UX squad projects, check if epic is part of specified child projects and update on Platform UX parent project - -on: - issues: - types: [opened, closed, edited, reopened, assigned, unassigned, labeled, unlabeled] - labels: - - 'type/epic' - -env: - GH_TOKEN: ${{ secrets.GH_BOT_PROJECTS_ACCESS_TOKEN }} - ORGANIZATION: ${{ github.repository_owner }} - REPO: ${{ github.event.repository.name }} - PARENT_PROJECT: 304 - CHILD_PROJECT_1: 78 - CHILD_PROJECT_2: 111 - CHILD_PROJECT_3: 202 - -concurrency: - group: issue-add-to-parent-project-${{ github.event.number }} -jobs: - config: - runs-on: "ubuntu-latest" - outputs: - has-secrets: ${{ steps.check.outputs.has-secrets }} - steps: - - name: "Check for secrets" - id: check - shell: bash - run: | - if [ -n "${{ (secrets.GH_BOT_PROJECTS_ACCESS_TOKEN != '') || '' }}" ]; then - echo "has-secrets=1" >> "$GITHUB_OUTPUT" - fi - - main: - needs: config - if: needs.config.outputs.has-secrets && contains(github.event.issue.labels.*.name, 'type/epic') - runs-on: ubuntu-latest - steps: - - name: Check if issue is in child or parent projects - run: | - gh api graphql -f query=' - query($org: String!, $repo: String!) { - repository(name: $repo, owner: $org) { - issue (number: ${{ github.event.issue.number }}) { - projectItems(first:20) { - nodes { - id, - project { - number, - title - }, - fieldValueByName(name:"Status") { - ... on ProjectV2ItemFieldSingleSelectValue { - optionId - name - } - } - } - } - } - } - }' -f org=$ORGANIZATION -f repo=$REPO > projects_data.json - - echo 'IN_PARENT_PROJ='$(jq '.data.repository.issue.projectItems.nodes[] | select(.project.number==${{ env.PARENT_PROJECT }}) | .project != null' projects_data.json) >> $GITHUB_ENV - echo 'PARENT_PROJ_STATUS_ID='$(jq '.data.repository.issue.projectItems.nodes[] | select(.project.number==${{ env.PARENT_PROJECT }}) | select(.fieldValueByName != null) | .fieldValueByName.optionId' projects_data.json) >> $GITHUB_ENV - echo 'ITEM_ID='$(jq '.data.repository.issue.projectItems.nodes[] | select(.project.number==${{ env.PARENT_PROJECT }}) | .id' projects_data.json) >> $GITHUB_ENV - echo 'IN_CHILD_PROJ='$(jq 'first(.data.repository.issue.projectItems.nodes[] | select(.project.number==${{ env.CHILD_PROJECT_1 }} or .project.number==${{ env.CHILD_PROJECT_2 }} or .project.number==${{ env.CHILD_PROJECT_3 }}) | .project != null)' projects_data.json) >> $GITHUB_ENV - echo 'CHILD_PROJ_STATUS='$(jq -r '.data.repository.issue.projectItems.nodes[] | select(.project.number==${{ env.CHILD_PROJECT_1 }} or .project.number==${{ env.CHILD_PROJECT_2 }} or .project.number==${{ env.CHILD_PROJECT_3 }}) | select(.fieldValueByName != null) | .fieldValueByName.name' projects_data.json) >> $GITHUB_ENV - - name: Get parent project project data - if: env.IN_CHILD_PROJ - run: | - gh api graphql -f query=' - query($org: String!, $number: Int!) { - organization(login: $org){ - projectV2(number: $number) { - id - fields(first:20) { - nodes { - ... on ProjectV2Field { - id - name - } - ... on ProjectV2SingleSelectField { - id - name - options { - id - name - } - } - } - } - } - } - }' -f org=$ORGANIZATION -F number=$PARENT_PROJECT > project_data.json - - echo 'PROJECT_ID='$(jq '.data.organization.projectV2.id' project_data.json) >> $GITHUB_ENV - echo 'STATUS_FIELD_ID='$(jq '.data.organization.projectV2.fields.nodes[] | select(.name== "Status") | .id' project_data.json) >> $GITHUB_ENV - echo 'TODO_OPTION_ID='$(jq '.data.organization.projectV2.fields.nodes[] | select(.name== "Status") | .options[] | select(.name=="Todo") |.id' project_data.json) >> $GITHUB_ENV - echo 'PROGRESS_OPTION_ID='$(jq '.data.organization.projectV2.fields.nodes[] | select(.name== "Status") | .options[] | select(.name=="In Progress") |.id' project_data.json) >> $GITHUB_ENV - echo 'DONE_OPTION_ID='$(jq '.data.organization.projectV2.fields.nodes[] | select(.name== "Status") | .options[] | select(.name=="Done") |.id' project_data.json) >> $GITHUB_ENV - - name: Add issue to parent project - if: env.IN_CHILD_PROJ && !env.IN_PARENT_PROJ - run: | - item_id="$( gh api graphql -f query=' - mutation($project:ID!, $issue:ID!) { - addProjectV2ItemById(input: {projectId: $project, contentId: $issue}) { - item { - id - } - } - }' -f project=$PROJECT_ID -f issue=${{ github.event.issue.node_id }} --jq '.data.addProjectV2ItemById.item.id')" - - echo 'ITEM_ID='$item_id >> $GITHUB_ENV - - name: Set parent project status Done - if: contains(env.CHILD_PROJ_STATUS, 'Done') - run: | - echo 'OPTION_ID='$DONE_OPTION_ID >> $GITHUB_ENV - - name: Set parent project status In Progress - if: contains(env.CHILD_PROJ_STATUS, 'In ') || contains(env.CHILD_PROJ_STATUS, 'Blocked') - run: | - echo 'OPTION_ID='$PROGRESS_OPTION_ID >> $GITHUB_ENV - - name: Set parent project status To do - if: env.CHILD_PROJ_STATUS && !contains(env.CHILD_PROJ_STATUS, 'In ') && !contains(env.CHILD_PROJ_STATUS, 'Blocked') && ! contains(env.CHILD_PROJ_STATUS, 'Done') - run: | - echo 'OPTION_ID='$TODO_OPTION_ID >> $GITHUB_ENV - - name: Set issue status in parent project - if: env.OPTION_ID && (env.OPTION_ID != env.PARENT_PROJ_STATUS_ID) - run: | - gh api graphql -f query=' - mutation ( - $project: ID! - $item: ID! - $status_field: ID! - $status_value: String! - ) { - set_status: updateProjectV2ItemFieldValue(input: { - projectId: $project - itemId: $item - fieldId: $status_field - value: { - singleSelectOptionId: $status_value - } - }) { - projectV2Item { - id - } - } - }' -f project=$PROJECT_ID -f item=$ITEM_ID -f status_field=$STATUS_FIELD_ID -f status_value=${{ env.OPTION_ID }} --silent diff --git a/.github/workflows/feature-toggles-ci.yml b/.github/workflows/feature-toggles-ci.yml index a6c9f5c52dc..7aa1dbd0b42 100644 --- a/.github/workflows/feature-toggles-ci.yml +++ b/.github/workflows/feature-toggles-ci.yml @@ -11,12 +11,12 @@ jobs: test: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 with: persist-credentials: false - name: Set up Go - uses: actions/setup-go@v5 + uses: actions/setup-go@111f3307d8850f501ac008e886eec1fd1932a34 with: go-version-file: 'go.mod' cache: true diff --git a/.github/workflows/frontend-lint.yml b/.github/workflows/frontend-lint.yml index a9b65b247fb..42533e0127d 100644 --- a/.github/workflows/frontend-lint.yml +++ b/.github/workflows/frontend-lint.yml @@ -6,13 +6,20 @@ on: - main - release-*.*.* +permissions: {} + jobs: - verify-i18n: + lint-frontend-verify-i18n: name: Verify i18n runs-on: ubuntu-latest + permissions: + contents: read + id-token: write steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + persist-credentials: false + - uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e with: node-version-file: '.nvmrc' cache: 'yarn' @@ -29,27 +36,98 @@ jobs: echo "${uncommited_error_message}" exit 1 fi - prettier: - name: Prettier + lint-frontend-prettier: + 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 + name: Lint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + - uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e + with: + node-version-file: '.nvmrc' + cache: 'yarn' + cache-dependency-path: 'yarn.lock' + - run: yarn install --immutable --check-cache + - run: yarn run prettier:check + - run: yarn run lint + lint-frontend-prettier-enterprise: + 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 + name: Lint runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + - uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e with: node-version-file: '.nvmrc' cache: 'yarn' cache-dependency-path: 'yarn.lock' + - name: Setup Enterprise + uses: ./.github/actions/setup-enterprise + with: + github-app-name: 'grafana-ci-bot' - run: yarn install --immutable --check-cache - run: yarn run prettier:check - typecheck: + - run: yarn run lint + lint-frontend-typecheck: + 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 + name: Typecheck + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + - uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e + with: + node-version-file: '.nvmrc' + cache: 'yarn' + cache-dependency-path: 'yarn.lock' + - run: yarn install --immutable --check-cache + - run: yarn run typecheck + lint-frontend-typecheck-enterprise: + 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 name: Typecheck runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + - uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e with: node-version-file: '.nvmrc' cache: 'yarn' cache-dependency-path: 'yarn.lock' + - name: Setup Enterprise + uses: ./.github/actions/setup-enterprise + with: + github-app-name: 'grafana-ci-bot' - run: yarn install --immutable --check-cache - run: yarn run typecheck + lint-frontend-betterer: + permissions: + contents: read + id-token: write + name: Betterer + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + - uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e + with: + node-version-file: '.nvmrc' + cache: 'yarn' + cache-dependency-path: 'yarn.lock' + - run: yarn install --immutable --check-cache + - run: yarn run betterer:ci diff --git a/.github/workflows/frontend-unit-tests.yml b/.github/workflows/frontend-unit-tests.yml deleted file mode 100644 index 495bb647233..00000000000 --- a/.github/workflows/frontend-unit-tests.yml +++ /dev/null @@ -1,29 +0,0 @@ -name: Frontend tests -on: - pull_request: - push: - branches: - - main - - release-*.*.* - -jobs: - test-frontend: - runs-on: ubuntu-latest-8-cores - name: "Unit tests (${{ matrix.chunk }} / 8)" - strategy: - fail-fast: true - matrix: - chunk: [1, 2, 3, 4, 5, 6, 7, 8] - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version-file: '.nvmrc' - cache: 'yarn' - cache-dependency-path: 'yarn.lock' - - run: yarn install --immutable --check-cache - - run: yarn run test:ci - env: - TEST_MAX_WORKERS: 2 - TEST_SHARD: ${{ matrix.chunk }} - TEST_SHARD_TOTAL: 8 diff --git a/.github/workflows/github-release.yml b/.github/workflows/github-release.yml index 8cbe3030ffe..211c9d90fd2 100644 --- a/.github/workflows/github-release.yml +++ b/.github/workflows/github-release.yml @@ -40,7 +40,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Create GitHub release (manually invoked) - uses: grafana/grafana-github-actions-go/github-release@main + uses: grafana/grafana-github-actions-go/github-release@main # zizmor: ignore[unpinned-uses] with: token: ${{ secrets.GITHUB_TOKEN }} version: ${{ inputs.version }} diff --git a/.github/workflows/go-lint.yml b/.github/workflows/go-lint.yml index 0925dcf02d0..0c65982f9c8 100644 --- a/.github/workflows/go-lint.yml +++ b/.github/workflows/go-lint.yml @@ -16,15 +16,17 @@ jobs: lint-go: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: actions/setup-go@v5 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + persist-credentials: false + - uses: actions/setup-go@111f3307d8850f501ac008e886eec1fd1932a34 with: go-version-file: ./go.mod - run: make gen-go - name: golangci-lint - uses: golangci/golangci-lint-action@v6 + uses: golangci/golangci-lint-action@1481404843c368bc19ca9406f87d6e0fc97bdcfd with: - version: v1.64.2 + version: v2.0.2 args: | --verbose $(go list -m -f '{{.Dir}}' | xargs -I{} sh -c 'test ! -f {}/.nolint && echo {}/...') install-mode: binary diff --git a/.github/workflows/i18n-crowdin-create-tasks.yml b/.github/workflows/i18n-crowdin-create-tasks.yml new file mode 100644 index 00000000000..dbe2be9a5b8 --- /dev/null +++ b/.github/workflows/i18n-crowdin-create-tasks.yml @@ -0,0 +1,27 @@ +name: Crowdin Create Tasks + +on: + workflow_dispatch: + # schedule: + # - cron: "0 0 * * *" + +jobs: + create-tasks-in-crowdin: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + persist-credentials: false + + - name: Setup Node.js + uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e + with: + node-version-file: '.nvmrc' + + - name: Create tasks + env: + CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }} + CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }} + run: node ./.github/workflows/scripts/crowdin/create-tasks.js diff --git a/.github/workflows/i18n-crowdin-download.yml b/.github/workflows/i18n-crowdin-download.yml index e0c3c50b9bb..d287c7ee06f 100644 --- a/.github/workflows/i18n-crowdin-download.yml +++ b/.github/workflows/i18n-crowdin-download.yml @@ -22,14 +22,15 @@ jobs: app_id: ${{ secrets.GRAFANA_PR_AUTOMATION_APP_ID }} private_key: ${{ secrets.GRAFANA_PR_AUTOMATION_APP_PEM }} - - uses: actions/checkout@v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 with: ref: ${{ github.head_ref }} token: ${{ steps.generate_token.outputs.token }} + persist-credentials: false - name: Download sources id: crowdin-download - uses: crowdin/github-action@v2 + uses: crowdin/github-action@b8012bd5491b8aa8578b73ab5b5f5e7c94aaa6e2 with: upload_sources: false upload_translations: false @@ -72,7 +73,7 @@ jobs: GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }} - name: Get project board ID - uses: octokit/graphql-action@v2.x + uses: octokit/graphql-action@51bf543c240dcd14761320e2efc625dc32ec0d32 id: get-project-id if: steps.crowdin-download.outputs.pull_request_url with: @@ -92,7 +93,7 @@ jobs: GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }} - name: Add to project board - uses: octokit/graphql-action@v2.x + uses: octokit/graphql-action@51bf543c240dcd14761320e2efc625dc32ec0d32 if: steps.crowdin-download.outputs.pull_request_url with: projectid: ${{ fromJson(steps.get-project-id.outputs.data).organization.projectV2.id }} @@ -109,7 +110,7 @@ jobs: GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }} - name: Run auto-milestone - uses: grafana/grafana-github-actions-go/auto-milestone@main + uses: grafana/grafana-github-actions-go/auto-milestone@main # zizmor: ignore[unpinned-uses] if: steps.crowdin-download.outputs.pull_request_url with: pr: ${{ steps.crowdin-download.outputs.pull_request_number }} @@ -117,7 +118,7 @@ jobs: - name: Get vault secrets id: vault-secrets - uses: grafana/shared-workflows/actions/get-vault-secrets@main + uses: grafana/shared-workflows/actions/get-vault-secrets@main # zizmor: ignore[unpinned-uses] with: # Secrets placed in ci/repo/grafana/grafana/grafana-pr-approver repo_secrets: | diff --git a/.github/workflows/i18n-crowdin-upload.yml b/.github/workflows/i18n-crowdin-upload.yml index 39a89c5aad2..d7d1a130fcd 100644 --- a/.github/workflows/i18n-crowdin-upload.yml +++ b/.github/workflows/i18n-crowdin-upload.yml @@ -14,10 +14,12 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + persist-credentials: false - name: Upload sources - uses: crowdin/github-action@v2 + uses: crowdin/github-action@b8012bd5491b8aa8578b73ab5b5f5e7c94aaa6e2 with: upload_sources: true upload_sources_args: '--dest=public/locales/en-US/grafana.json' diff --git a/.github/workflows/issue-opened.yml b/.github/workflows/issue-opened.yml index 4de94070072..91767a5310b 100644 --- a/.github/workflows/issue-opened.yml +++ b/.github/workflows/issue-opened.yml @@ -10,22 +10,24 @@ on: concurrency: group: issue-opened-${{ github.event.issue.number }} -permissions: - contents: read - id-token: write +permissions: {} jobs: main: runs-on: ubuntu-latest if: github.repository == 'grafana/grafana' + permissions: + contents: read + id-token: write steps: - name: Checkout Actions - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: repository: "grafana/grafana-github-actions" path: ./actions ref: main + persist-credentials: false - name: Install Actions run: npm install --production --prefix ./actions @@ -37,7 +39,7 @@ jobs: - name: "Get vault secrets" id: vault-secrets - uses: grafana/shared-workflows/actions/get-vault-secrets@main + uses: grafana/shared-workflows/actions/get-vault-secrets@main # zizmor: ignore[unpinned-uses] with: # Secrets placed in the ci/repo/grafana/grafana/plugins_platform_issue_commands_github_bot path in Vault repo_secrets: | @@ -60,13 +62,16 @@ jobs: auto-triage: needs: [main] + permissions: + contents: read + id-token: write if: github.repository == 'grafana/grafana' && github.event.issue.author_association != 'MEMBER' && github.event.issue.author_association != 'OWNER' runs-on: ubuntu-latest steps: - name: "Get vault secrets" id: vault-secrets - uses: grafana/shared-workflows/actions/get-vault-secrets@main + uses: grafana/shared-workflows/actions/get-vault-secrets@main # zizmor: ignore[unpinned-uses] with: # Secrets placed in the ci/repo/grafana/grafana/plugins_platform_issue_triager path in Vault repo_secrets: | @@ -83,11 +88,11 @@ jobs: private_key: ${{ env.GH_APP_PEM }} - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Send issue to the auto triager action id: auto_triage - uses: grafana/auto-triager@main + uses: grafana/auto-triager@main # zizmor: ignore[unpinned-uses] with: token: ${{ steps.generate_token.outputs.token }} issue_number: ${{ github.event.issue.number }} @@ -99,7 +104,7 @@ jobs: - name: "Send Slack notification" if: ${{ steps.auto_triage.outputs.triage_labels != '' }} - uses: slackapi/slack-github-action@v1.27.0 + uses: slackapi/slack-github-action@37ebaef184d7626c5f204ab8d3baff4262dd30f0 # v1.27.0 with: payload: > { diff --git a/.github/workflows/lint-build-docs.yml b/.github/workflows/lint-build-docs.yml new file mode 100644 index 00000000000..1477cb2797a --- /dev/null +++ b/.github/workflows/lint-build-docs.yml @@ -0,0 +1,62 @@ +name: Documentation + +on: + pull_request: + paths: + - '*.md' + - 'docs/**' + - 'packages/**/*.md' + - 'latest.json' + push: + branches: + - main + paths: + - '*.md' + - 'docs/**' + - 'packages/**/*.md' + - 'latest.json' + +jobs: + docs: + name: Build & Verify Docs + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + persist-credentials: false + + - name: Setup Node.js + uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e + with: + node-version: '22.11.0' + cache: 'yarn' + + - name: Install dependencies + run: yarn install --immutable + + - name: Lint docs + run: yarn run prettier:checkDocs + env: + # Increase memory for prettier due to large number of files + NODE_OPTIONS: --max_old_space_size=8192 + + - name: Build docs website + run: | + # Create and start a container from the docs-base image in detached mode + docker run -d --name docs-builder grafana/docs-base:latest tail -f /dev/null + + # Create the directory structure inside the container + docker exec docs-builder mkdir -p /hugo/content/docs/grafana/latest + + # Create the _index.md file + docker exec docs-builder /bin/sh -c "echo -e '---\nredirectURL: /docs/grafana/latest/\ntype: redirect\nversioned: true\n---\n' > /hugo/content/docs/grafana/_index.md" + + # Copy the docs sources from the host to the container + docker cp docs/sources/. docs-builder:/hugo/content/docs/grafana/latest/ + + # Run the make prod command inside the container + docker exec -w /hugo docs-builder make prod || echo "Build completed with warnings" + + # Clean up the container + docker rm -f docs-builder diff --git a/.github/workflows/metrics-collector.yml b/.github/workflows/metrics-collector.yml index 2e22a830a88..281dc6fb350 100644 --- a/.github/workflows/metrics-collector.yml +++ b/.github/workflows/metrics-collector.yml @@ -15,6 +15,9 @@ on: issues: types: [opened, closed] +permissions: + contents: read + jobs: config: runs-on: "ubuntu-latest" @@ -35,11 +38,12 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout Actions - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: repository: "grafana/grafana-github-actions" path: ./actions ref: main + persist-credentials: false - name: Install Actions run: npm install --production --prefix ./actions - name: Run metrics collector diff --git a/.github/workflows/migrate-prs.yml b/.github/workflows/migrate-prs.yml index 31bb8f9f9da..c40a34a6ebb 100644 --- a/.github/workflows/migrate-prs.yml +++ b/.github/workflows/migrate-prs.yml @@ -51,7 +51,7 @@ jobs: app_id: ${{ secrets.GRAFANA_DELIVERY_BOT_APP_ID }} private_key: ${{ secrets.GRAFANA_DELIVERY_BOT_APP_PEM }} - name: Migrate PRs - uses: grafana/grafana-github-actions-go/migrate-open-prs@main + uses: grafana/grafana-github-actions-go/migrate-open-prs@main # zizmor: ignore[unpinned-uses] with: token: ${{ steps.generate_token.outputs.token }} ownerRepo: ${{ inputs.ownerRepo }} diff --git a/.github/workflows/milestone.yml b/.github/workflows/milestone.yml deleted file mode 100644 index f686dee7d55..00000000000 --- a/.github/workflows/milestone.yml +++ /dev/null @@ -1,19 +0,0 @@ -name: Close Milestone -on: - workflow_dispatch: - inputs: - version_input: - description: 'The version to be released please respect: major.minor.patch, major.minor.patch-preview or major.minor.patch-preview format. example: 7.4.3, 7.4.3-preview or 7.4.3-preview1' - required: true -jobs: - call-remove-milestone: - uses: grafana/grafana/.github/workflows/remove-milestone.yml@main - with: - version_call: ${{ github.event.inputs.version_input }} - secrets: inherit - call-close-milestone: - uses: grafana/grafana/.github/workflows/close-milestone.yml@main - with: - version_call: ${{ github.event.inputs.version_input }} - secrets: inherit - needs: call-remove-milestone diff --git a/.github/workflows/pr-backend-code-checks.yml b/.github/workflows/pr-backend-code-checks.yml deleted file mode 100644 index 37073dc28c4..00000000000 --- a/.github/workflows/pr-backend-code-checks.yml +++ /dev/null @@ -1,37 +0,0 @@ -name: Backend Code Checks -description: Validate go.mod and OpenAPI specifications - -on: - pull_request: - paths-ignore: - - '*.md' - - 'docs/**' - - 'latest.json' - -permissions: - contents: read - -jobs: - validate-configs: - name: Validate Backend Configs - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - name: Setup Go - uses: actions/setup-go@v5 - with: - go-version-file: go.mod - cache: true - - - name: Verify code generation - run: | - CODEGEN_VERIFY=1 make gen-cue - CODEGEN_VERIFY=1 make gen-jsonnet - - - name: Validate go.mod - run: go run scripts/modowners/modowners.go check go.mod - - - name: Generate and Validate OpenAPI Specs - run: | - make swagger-gen diff --git a/.github/workflows/pr-backend-unit-tests.yml b/.github/workflows/pr-backend-coverage.yml similarity index 83% rename from .github/workflows/pr-backend-unit-tests.yml rename to .github/workflows/pr-backend-coverage.yml index 99ec9b0ea49..4d95497e3ec 100644 --- a/.github/workflows/pr-backend-unit-tests.yml +++ b/.github/workflows/pr-backend-coverage.yml @@ -1,4 +1,4 @@ -name: Backend Unit Tests +name: Coverage on: workflow_dispatch: @@ -8,10 +8,6 @@ on: paths-ignore: - 'docs/**' - '**/*.md' - pull_request: - paths-ignore: - - 'docs/**' - - '**/*.md' permissions: contents: read @@ -22,31 +18,28 @@ env: WIRE_TAGS: 'oss' jobs: - backend-testing-coverage: - name: Backend Testing & Coverage - runs-on: ubuntu-latest + main: + name: Backend Unit Tests + runs-on: ubuntu-latest-8-cores steps: - name: Checkout code - uses: actions/checkout@v4 - + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + persist-credentials: false - name: Setup Go - uses: actions/setup-go@v5 + uses: actions/setup-go@111f3307d8850f501ac008e886eec1fd1932a34 with: go-version-file: go.mod cache: true - - name: Install dependencies run: | sudo apt-get update sudo apt-get install -y build-essential shared-mime-info go install github.com/mfridman/tparse@c1754a1f484ac5cd422697b0fec635177ddc8507 # v0.17.0 - - name: Generate Go code run: make gen-go - - name: Run unit tests - run: COVER_OPTS="-coverprofile=be-unit.cov -coverpkg=github.com/grafana/grafana/..." GO_TEST_OUTPUT="/tmp/unit.log" make test-go-unit - + run: COVER_OPTS="-coverprofile=be-unit.cov -coverpkg=github.com/grafana/grafana/..." GO_TEST_OUTPUT="/tmp/unit.log" make test-go-unit-cov - name: Process and upload coverage uses: ./.github/actions/test-coverage-processor with: @@ -71,8 +64,8 @@ jobs: --report-output log \ --grafana-version "$(git rev-parse HEAD)" \ --suite-name grafana-oss-unit-tests \ - /tmp/unit.log + /tmp/unit.log || true concurrency: group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true + cancel-in-progress: false diff --git a/.github/workflows/pr-checks.yml b/.github/workflows/pr-checks.yml index ae2b0898f73..68317f57a0e 100644 --- a/.github/workflows/pr-checks.yml +++ b/.github/workflows/pr-checks.yml @@ -31,11 +31,12 @@ jobs: if: github.event.pull_request.draft == false steps: - name: Checkout Actions - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: repository: "grafana/grafana-github-actions" path: ./actions ref: main + persist-credentials: false - name: Install Actions run: npm install --production --prefix ./actions - name: Run PR Checks diff --git a/.github/workflows/pr-codeql-analysis-go.yml b/.github/workflows/pr-codeql-analysis-go.yml deleted file mode 100644 index ce9082f4400..00000000000 --- a/.github/workflows/pr-codeql-analysis-go.yml +++ /dev/null @@ -1,53 +0,0 @@ -name: "CodeQL for PR / go" - -on: - workflow_dispatch: - pull_request: - branches: [main] - paths: - - '**/*.go' - -permissions: - security-events: write - -jobs: - analyze: - name: Analyze - runs-on: ubuntu-latest - if: github.repository == 'grafana/grafana' - - steps: - - name: "Generate token" - id: generate_token - continue-on-error: true - uses: tibdex/github-app-token@3beb63f4bd073e61482598c45c71c1019b59b73a - with: - app_id: ${{ secrets.GRAFANA_DELIVERY_BOT_APP_ID }} - private_key: ${{ secrets.GRAFANA_DELIVERY_BOT_APP_PEM }} - - - name: Checkout repository - uses: actions/checkout@v4 - with: - # We must fetch at least the immediate parents so that if this is - # a pull request then we can checkout the head. - fetch-depth: 2 - token: ${{ steps.generate_token.outputs.token }} - - - name: Set go version - uses: actions/setup-go@v4 - with: - go-version-file: go.mod - - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v2 - with: - languages: "go" - - - name: Build go files - run: | - go mod verify - make build-go - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 diff --git a/.github/workflows/pr-codeql-analysis-javascript.yml b/.github/workflows/pr-codeql-analysis-javascript.yml index 6c5264c926a..43457ad4af0 100644 --- a/.github/workflows/pr-codeql-analysis-javascript.yml +++ b/.github/workflows/pr-codeql-analysis-javascript.yml @@ -20,17 +20,18 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 with: # We must fetch at least the immediate parents so that if this is # a pull request then we can checkout the head. fetch-depth: 2 + persist-credentials: false # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v3 with: languages: "javascript" - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@v3 diff --git a/.github/workflows/pr-codeql-analysis-python.yml b/.github/workflows/pr-codeql-analysis-python.yml index aea55365afc..992a886497d 100644 --- a/.github/workflows/pr-codeql-analysis-python.yml +++ b/.github/workflows/pr-codeql-analysis-python.yml @@ -18,17 +18,18 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 with: # We must fetch at least the immediate parents so that if this is # a pull request then we can checkout the head. fetch-depth: 2 + persist-credentials: false # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v3 with: languages: "python" - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@v3 diff --git a/.github/workflows/pr-commands.yml b/.github/workflows/pr-commands.yml index 51838dc7ae7..db93ad7e70b 100644 --- a/.github/workflows/pr-commands.yml +++ b/.github/workflows/pr-commands.yml @@ -30,11 +30,12 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout Actions - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: repository: "grafana/grafana-github-actions" path: ./actions ref: main + persist-credentials: false - name: Install Actions run: npm install --production --prefix ./actions - name: "Generate token" diff --git a/.github/workflows/pr-dependabot-update-go-workspace.yml b/.github/workflows/pr-dependabot-update-go-workspace.yml index 9fd36a20082..48a005ba6f7 100644 --- a/.github/workflows/pr-dependabot-update-go-workspace.yml +++ b/.github/workflows/pr-dependabot-update-go-workspace.yml @@ -22,7 +22,7 @@ jobs: steps: - name: Retrieve GitHub App secrets id: get-secrets - uses: grafana/shared-workflows/actions/get-vault-secrets@get-vault-secrets-v1.0.1 + uses: grafana/shared-workflows/actions/get-vault-secrets@get-vault-secrets-v1.0.1 # zizmor: ignore[unpinned-uses] with: repo_secrets: | APP_ID=grafana-go-workspace-bot:app-id @@ -37,14 +37,15 @@ jobs: private-key: ${{ env.PRIVATE_KEY }} - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 with: repository: ${{ github.event.pull_request.head.repo.full_name }} ref: ${{ github.event.pull_request.head.ref }} token: ${{ steps.generate_token.outputs.token }} + persist-credentials: false - name: Set go version - uses: actions/setup-go@v4 + uses: actions/setup-go@19bb51245e9c80abacb2e91cc42b33fa478b8639 with: go-version-file: go.mod @@ -65,4 +66,4 @@ jobs: echo "Committing and pushing workspace changes" git commit -a -m "update workspace" git push origin $BRANCH_NAME - fi \ No newline at end of file + fi diff --git a/.github/workflows/pr-e2e-tests.yml b/.github/workflows/pr-e2e-tests.yml new file mode 100644 index 00000000000..74e64e5bf38 --- /dev/null +++ b/.github/workflows/pr-e2e-tests.yml @@ -0,0 +1,72 @@ +name: End-to-end tests + +on: + pull_request: + push: + branches: + - main + - release-*.*.* + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ startsWith(github.ref, 'refs/pull/') }} + +jobs: + build-grafana: + name: Build & Package Grafana + runs-on: ubuntu-latest-16-cores + outputs: + artifact: ${{ steps.artifact.outputs.artifact }} + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + repository: 'grafana/grafana-build' + ref: 'main' + persist-credentials: false + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + path: ./grafana + - run: echo "GRAFANA_GO_VERSION=$(grep "go 1." grafana/go.work | cut -d\ -f2)" >> "$GITHUB_ENV" + - uses: dagger/dagger-for-github@e47aba410ef9bb9ed81a4d2a97df31061e5e842e + with: + verb: run + args: go run ./cmd artifacts -a targz:grafana:linux/amd64 --grafana-dir=grafana --go-version=${GRAFANA_GO_VERSION} > out.txt + - run: mv $(cat out.txt) grafana.tar.gz + - run: echo "artifact=grafana-e2e-${{github.run_number}}" >> "$GITHUB_OUTPUT" + id: artifact + - uses: actions/upload-artifact@v4 + id: upload + with: + retention-days: 1 + name: ${{ steps.artifact.outputs.artifact }} + path: grafana.tar.gz + e2e-matrix: + name: ${{ matrix.suite }} + strategy: + matrix: + suite: + - various-suite + - dashboards-suite + - smoke-tests-suite + - panels-suite + needs: + - build-grafana + uses: ./.github/workflows/run-e2e-suite.yml + with: + package: ${{ needs.build-grafana.outputs.artifact }} + suite: ${{ matrix.suite }} + e2e-matrix-old-arch: + name: ${{ matrix.suite }} (old arch) + strategy: + matrix: + suite: + - old-arch/various-suite + - old-arch/dashboards-suite + - old-arch/smoke-tests-suite + - old-arch/panels-suite + needs: + - build-grafana + uses: ./.github/workflows/run-e2e-suite.yml + with: + package: ${{ needs.build-grafana.outputs.artifact }} + suite: ${{ matrix.suite }} diff --git a/.github/workflows/pr-frontend-unit-tests.yml b/.github/workflows/pr-frontend-unit-tests.yml new file mode 100644 index 00000000000..e26e3847f8c --- /dev/null +++ b/.github/workflows/pr-frontend-unit-tests.yml @@ -0,0 +1,69 @@ +name: Frontend tests +on: + pull_request: + push: + branches: + - main + - release-*.*.* + +permissions: {} + +jobs: + 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 + runs-on: ubuntu-latest-8-cores + name: "Unit tests (${{ matrix.chunk }} / 8)" + strategy: + fail-fast: false + matrix: + chunk: [1, 2, 3, 4, 5, 6, 7, 8] + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + persist-credentials: false + - uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e + with: + node-version-file: '.nvmrc' + cache: 'yarn' + cache-dependency-path: 'yarn.lock' + - run: yarn install --immutable --check-cache + - run: yarn run test:ci + env: + TEST_MAX_WORKERS: 2 + TEST_SHARD: ${{ matrix.chunk }} + TEST_SHARD_TOTAL: 8 + + frontend-unit-tests-enterprise: + 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 + runs-on: ubuntu-latest-8-cores + name: "Unit tests (${{ matrix.chunk }} / 8)" + strategy: + fail-fast: false + matrix: + chunk: [1, 2, 3, 4, 5, 6, 7, 8] + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + - uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e + with: + node-version-file: '.nvmrc' + cache: 'yarn' + cache-dependency-path: 'yarn.lock' + - name: Setup Enterprise + uses: ./.github/actions/setup-enterprise + with: + github-app-name: 'grafana-ci-bot' + - run: yarn install --immutable --check-cache + - run: yarn run test:ci + env: + TEST_MAX_WORKERS: 2 + TEST_SHARD: ${{ matrix.chunk }} + TEST_SHARD_TOTAL: 8 diff --git a/.github/workflows/pr-go-workspace-check.yml b/.github/workflows/pr-go-workspace-check.yml index 889e7653ec0..d54178f2e35 100644 --- a/.github/workflows/pr-go-workspace-check.yml +++ b/.github/workflows/pr-go-workspace-check.yml @@ -21,11 +21,14 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + persist-credentials: false - name: Set go version - uses: actions/setup-go@v4 + uses: actions/setup-go@19bb51245e9c80abacb2e91cc42b33fa478b8639 with: + cache: false go-version-file: go.mod - name: Update workspace @@ -41,4 +44,4 @@ jobs: exit 1 fi - name: Ensure Dockerfile contains submodule COPY commands - run: ./scripts/go-workspace/validate-dockerfile.sh \ No newline at end of file + run: ./scripts/go-workspace/validate-dockerfile.sh diff --git a/.github/workflows/pr-k8s-codegen-check.yml b/.github/workflows/pr-k8s-codegen-check.yml index 71dd29b6354..9a72f469caa 100644 --- a/.github/workflows/pr-k8s-codegen-check.yml +++ b/.github/workflows/pr-k8s-codegen-check.yml @@ -9,6 +9,7 @@ on: - "pkg/aggregator/apis/**" - "pkg/apimachinery/apis/**" - "hack/**" + - "apps/**" - "*.sum" jobs: @@ -18,10 +19,12 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + persist-credentials: false - name: Set go version - uses: actions/setup-go@v4 + uses: actions/setup-go@19bb51245e9c80abacb2e91cc42b33fa478b8639 with: go-version-file: go.mod @@ -35,4 +38,4 @@ jobs: git diff echo "Please run './hack/update-codegen.sh' and commit the changes." exit 1 - fi \ No newline at end of file + fi diff --git a/.github/workflows/pr-patch-check-event.yml b/.github/workflows/pr-patch-check-event.yml index 03dd31a7539..f7605f033ce 100644 --- a/.github/workflows/pr-patch-check-event.yml +++ b/.github/workflows/pr-patch-check-event.yml @@ -3,7 +3,7 @@ name: Dispatch check for patch conflicts run-name: dispatch-check-patch-conflicts-${{ github.base_ref }}-${{ github.head_ref }} on: - pull_request: + pull_request_target: types: - opened - reopened @@ -13,10 +13,22 @@ on: - "v*.*.*" - "release-*" +permissions: {} + # Since this is run on a pull request, we want to apply the patches intended for the # target branch onto the source branch, to verify compatibility before merging. jobs: dispatch-job: + permissions: + contents: read + actions: write + env: + HEAD_REF: ${{ github.head_ref }} + BASE_REF: ${{ github.base_ref }} + REPO: ${{ github.repository }} + SENDER: ${{ github.event.sender.login }} + SHA: ${{ github.sha }} + PR_COMMIT_SHA: ${{ github.event.pull_request.head.sha }} runs-on: ubuntu-latest steps: - name: "Generate token" @@ -26,24 +38,25 @@ jobs: # App needs Actions: Read/Write for the grafana/security-patch-actions repo app_id: ${{ secrets.GRAFANA_DELIVERY_BOT_APP_ID }} private_key: ${{ secrets.GRAFANA_DELIVERY_BOT_APP_PEM }} - - name: "Dispatch job" uses: actions/github-script@v7 with: github-token: ${{ steps.generate_token.outputs.token }} script: | + const {HEAD_REF, BASE_REF, REPO, SENDER, SHA, PR_COMMIT_SHA} = process.env; + await github.rest.actions.createWorkflowDispatch({ owner: 'grafana', repo: 'security-patch-actions', workflow_id: 'test-patches-event.yml', ref: 'main', inputs: { - src_repo: "${{ github.repository }}", - src_ref: "${{ github.head_ref }}", - src_merge_sha: "${{ github.sha }}", - src_pr_commit_sha: "${{ github.event.pull_request.head.sha }}", - patch_repo: "${{ github.repository }}-security-patches", - patch_ref: "${{ github.base_ref }}", - triggering_github_handle: "${{ github.event.sender.login }}" + src_repo: REPO, + src_ref: HEAD_REF, + src_merge_sha: SHA, + src_pr_commit_sha: PR_COMMIT_SHA, + patch_repo: REPO + '-security-patches', + patch_ref: BASE_REF, + triggering_github_handle: SENDER } }) diff --git a/.github/workflows/pr-test-integration.yml b/.github/workflows/pr-test-integration.yml new file mode 100644 index 00000000000..b49183889d5 --- /dev/null +++ b/.github/workflows/pr-test-integration.yml @@ -0,0 +1,89 @@ +name: Integration Tests + +on: + push: + branches: + - main + - release-*.*.* + pull_request: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ startsWith(github.ref, 'refs/pull/') }} + +jobs: + sqlite: + name: Sqlite + runs-on: ubuntu-latest-8-cores + steps: + - name: Checkout code + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + persist-credentials: false + - name: Setup Go + uses: actions/setup-go@111f3307d8850f501ac008e886eec1fd1932a34 + with: + go-version-file: go.mod + cache: true + - run: | + make gen-go + go test -tags=sqlite -timeout=5m -run '^TestIntegration' $(find ./pkg -type f -name '*_test.go' -exec grep -l '^func TestIntegration' '{}' '+' | grep -o '\(.*\)/' | sort -u) + mysql: + name: MySQL + runs-on: ubuntu-latest-8-cores + env: + GRAFANA_TEST_DB: mysql + MYSQL_HOST: 127.0.0.1 + services: + mysql: + image: mysql:8.0.32 + env: + MYSQL_ROOT_PASSWORD: rootpass + MYSQL_DATABASE: grafana_tests + MYSQL_USER: grafana + MYSQL_PASSWORD: password + options: --health-cmd="mysqladmin ping --silent" --health-interval=10s --health-timeout=5s --health-retries=3 + ports: + - 3306:3306 + steps: + - name: Checkout code + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + - name: Setup Go + uses: actions/setup-go@111f3307d8850f501ac008e886eec1fd1932a34 + with: + go-version-file: go.mod + cache: true + - run: | + sudo apt-get update -yq && sudo apt-get install mariadb-client + cat devenv/docker/blocks/mysql_tests/setup.sql | mariadb -h 127.0.0.1 -P 3306 -u root -prootpass --disable-ssl-verify-server-cert + make gen-go + go test -tags=mysql -p=1 -timeout=5m -run '^TestIntegration' $(find ./pkg -type f -name '*_test.go' -exec grep -l '^func TestIntegration' '{}' '+' | grep -o '\(.*\)/' | sort -u) + postgres: + name: Postgres + runs-on: ubuntu-latest-8-cores + services: + postgres: + image: postgres:12.3-alpine + env: + POSTGRES_USER: grafanatest + POSTGRES_PASSWORD: grafanatest + POSTGRES_DB: grafanatest + ports: + - 5432:5432 + steps: + - name: Checkout code + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + - name: Setup Go + uses: actions/setup-go@111f3307d8850f501ac008e886eec1fd1932a34 + with: + go-version-file: go.mod + cache: true + - env: + GRAFANA_TEST_DB: postgres + PGPASSWORD: grafanatest + POSTGRES_HOST: 127.0.0.1 + run: | + sudo apt-get update -yq && sudo apt-get install postgresql-client + psql -p 5432 -h 127.0.0.1 -U grafanatest -d grafanatest -f devenv/docker/blocks/postgres_tests/setup.sql + make gen-go + go test -p=1 -tags=postgres -timeout=5m -run '^TestIntegration' $(find ./pkg -type f -name '*_test.go' -exec grep -l '^func TestIntegration' '{}' '+' | grep -o '\(.*\)/' | sort -u) diff --git a/.github/workflows/publish-kinds-next.yml b/.github/workflows/publish-kinds-next.yml index 4aed6cf36c3..ed290abbd2d 100644 --- a/.github/workflows/publish-kinds-next.yml +++ b/.github/workflows/publish-kinds-next.yml @@ -29,12 +29,13 @@ jobs: runs-on: "ubuntu-latest" steps: - name: "Checkout Grafana repo" - uses: "actions/checkout@v4" + uses: "actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683" with: fetch-depth: 0 + persist-credentials: false - name: "Setup Go" - uses: "actions/setup-go@v4" + uses: "actions/setup-go@19bb51245e9c80abacb2e91cc42b33fa478b8639" with: go-version-file: go.mod diff --git a/.github/workflows/publish-kinds-release.yml b/.github/workflows/publish-kinds-release.yml index 691cdff3867..1e60f72ed79 100644 --- a/.github/workflows/publish-kinds-release.yml +++ b/.github/workflows/publish-kinds-release.yml @@ -31,13 +31,14 @@ jobs: runs-on: "ubuntu-latest" steps: - name: "Checkout Grafana repo" - uses: "actions/checkout@v4" + uses: "actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683" with: # required for the `grafana/grafana-github-actions/has-matching-release-tag` action to work fetch-depth: 0 + persist-credentials: false - name: "Setup Go" - uses: "actions/setup-go@v4" + uses: "actions/setup-go@19bb51245e9c80abacb2e91cc42b33fa478b8639" with: go-version-file: go.mod @@ -45,7 +46,7 @@ jobs: run: go run .github/workflows/scripts/kinds/verify-kinds.go - name: "Checkout Actions library" - uses: "actions/checkout@v4" + uses: "actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683" with: repository: "grafana/grafana-github-actions" path: "./actions" diff --git a/.github/workflows/publish-technical-documentation-next.yml b/.github/workflows/publish-technical-documentation-next.yml index 6b2cd7489b3..9d67f1724c5 100644 --- a/.github/workflows/publish-technical-documentation-next.yml +++ b/.github/workflows/publish-technical-documentation-next.yml @@ -15,7 +15,7 @@ jobs: id-token: write runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: grafana/writers-toolkit/publish-technical-documentation@publish-technical-documentation/v1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + - uses: grafana/writers-toolkit/publish-technical-documentation@publish-technical-documentation/v1 # zizmor: ignore[unpinned-uses] with: website_directory: content/docs/grafana/next diff --git a/.github/workflows/publish-technical-documentation-release.yml b/.github/workflows/publish-technical-documentation-release.yml index 57d779660c5..d5f597686ca 100644 --- a/.github/workflows/publish-technical-documentation-release.yml +++ b/.github/workflows/publish-technical-documentation-release.yml @@ -17,10 +17,11 @@ jobs: id-token: write runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 with: fetch-depth: 0 - - uses: grafana/writers-toolkit/publish-technical-documentation-release@publish-technical-documentation-release/v2 + persist-credentials: false + - uses: grafana/writers-toolkit/publish-technical-documentation-release@publish-technical-documentation-release/v2 # zizmor: ignore[unpinned-uses] with: release_tag_regexp: "^v(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)$" release_branch_regexp: "^release-(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)$" diff --git a/.github/workflows/release-comms.yml b/.github/workflows/release-comms.yml index 008b6552883..e5532ca12ca 100644 --- a/.github/workflows/release-comms.yml +++ b/.github/workflows/release-comms.yml @@ -30,18 +30,16 @@ jobs: release_branch: ${{ steps.output.outputs.release_branch }} dry_run: ${{ steps.output.outputs.dry_run }} latest: ${{ steps.output.outputs.latest }} + env: + HEAD_REF: ${{ github.head_ref }} + DRY_RUN: ${{ inputs.dry_run }} + LATEST: ${{ inputs.latest && '1' || '0' }} + VERSION: ${{ inputs.version }} runs-on: ubuntu-latest steps: - # The github-release action expects a `LATEST` value of a string of either '1' or '0' - - if: ${{ github.event_name == 'workflow_dispatch' }} - run: | - echo setting up GITHUB_ENV for ${{ github.event_name }} - echo "VERSION=${{ inputs.version }}" >> $GITHUB_ENV - echo "DRY_RUN=${{ inputs.dry_run }}" >> $GITHUB_ENV - echo "LATEST=${{ inputs.latest && '1' || '0' }}" >> $GITHUB_ENV - if: ${{ github.event.pull_request.merged == true && startsWith(github.head_ref, 'release/') }} run: | - echo "VERSION=$(echo ${{ github.head_ref }} | sed -e 's/release\/.*\//v/g')" >> $GITHUB_ENV + echo "VERSION=$(echo ${HEAD_REF} | sed -e 's/release\/.*\//v/g')" >> $GITHUB_ENV echo "DRY_RUN=${{ contains(github.event.pull_request.labels.*.name, 'release/dry-run') }}" >> $GITHUB_ENV echo "LATEST=${{ contains(github.event.pull_request.labels.*.name, 'release/latest') && '1' || '0' }}" >> $GITHUB_ENV - id: output @@ -120,7 +118,10 @@ jobs: post_on_slack: needs: setup runs-on: ubuntu-latest + env: + DRY_RUN: ${{ needs.setup.outputs.dry_run }} + VERSION: ${{ needs.setup.outputs.version }} steps: - run: | - echo announce on slack that ${{ needs.setup.outputs.version }} has been released - echo dry run: ${{ needs.setup.outputs.dry_run }} + echo announce on slack that $VERSION has been released + echo dry run: $DRY_RUN diff --git a/.github/workflows/release-pr.yml b/.github/workflows/release-pr.yml index 1234cdc75ef..4d66838b7ec 100644 --- a/.github/workflows/release-pr.yml +++ b/.github/workflows/release-pr.yml @@ -33,12 +33,13 @@ on: default: false type: boolean -permissions: - contents: write - pull-requests: write +permissions: {} jobs: push-changelog-to-main: + permissions: + contents: write + pull-requests: write name: Create PR to main to update the changelog uses: ./.github/workflows/changelog.yml with: @@ -50,41 +51,44 @@ jobs: secrets: GRAFANA_DELIVERY_BOT_APP_ID: ${{ secrets.GRAFANA_DELIVERY_BOT_APP_ID }} GRAFANA_DELIVERY_BOT_APP_PEM: ${{ secrets.GRAFANA_DELIVERY_BOT_APP_PEM }} + create-prs: + permissions: + contents: write + pull-requests: write name: Create Release PR runs-on: ubuntu-latest if: github.repository == 'grafana/grafana' + env: + VERSION: ${{ inputs.version }} + LATEST: ${{ inputs.latest }} + DRY_RUN: ${{ inputs.dry_run }} steps: - - name: Generate bot token - id: generate_token - uses: tibdex/github-app-token@b62528385c34dbc9f38e5f4225ac829252d1ea92 - with: - app_id: ${{ secrets.GRAFANA_DELIVERY_BOT_APP_ID }} - private_key: ${{ secrets.GRAFANA_DELIVERY_BOT_APP_PEM }} - name: Get release branch id: branch - uses: grafana/grafana-github-actions-go/latest-release-branch@main + uses: grafana/grafana-github-actions-go/latest-release-branch@main # zizmor: ignore[unpinned-uses] with: - token: ${{ steps.generate_token.outputs.token }} + token: ${{ secrets.GITHUB_TOKEN }} ownerRepo: 'grafana/grafana' pattern: ${{ inputs.target }} - name: Checkout Grafana - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 with: ref: ${{ steps.branch.outputs.branch }} - fetch-depth: 0 fetch-tags: true - token: ${{ steps.generate_token.outputs.token }} + token: ${{ secrets.GITHUB_TOKEN }} + persist-credentials: false - name: Checkout Grafana (main) - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 with: ref: main fetch-depth: '0' fetch-tags: 'false' path: .grafana-main - token: ${{ steps.generate_token.outputs.token }} + token: ${{ secrets.GITHUB_TOKEN }} + persist-credentials: false - name: Setup nodejs environment - uses: actions/setup-node@v4 + uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e with: node-version-file: .nvmrc - name: Configure git user @@ -94,37 +98,43 @@ jobs: git config --local --add --bool push.autoSetupRemote true - name: Create branch - run: git checkout -b "release/${{ github.run_id }}/${{ inputs.version }}" + run: git checkout -b "release/${{ github.run_id }}/$VERSION" + - name: Generate changelog token + id: generate_changelog_token + uses: tibdex/github-app-token@b62528385c34dbc9f38e5f4225ac829252d1ea92 + with: + app_id: ${{ secrets.GRAFANA_DELIVERY_BOT_APP_ID }} + private_key: ${{ secrets.GRAFANA_DELIVERY_BOT_APP_PEM }} - name: Generate changelog id: changelog uses: ./.grafana-main/.github/workflows/actions/changelog with: - github_token: ${{ steps.generate_token.outputs.token }} - target: v${{ inputs.version }} + github_token: ${{ steps.generate_changelog_token.outputs.token }} + target: v${{ env.VERSION }} output_file: changelog_items.md - name: Patch CHANGELOG.md run: | # Prepare CHANGELOG.md content with version delimiters ( echo - echo "# ${{ inputs.version}} ($(date '+%F'))" + echo "# $VERSION ($(date '+%F'))" echo cat changelog_items.md ) > CHANGELOG.part # Check if a version exists in the changelog - if grep -q "" + echo "" cat CHANGELOG.part - echo "" + echo "" cat CHANGELOG.md ) > CHANGELOG.tmp mv CHANGELOG.tmp CHANGELOG.md @@ -147,35 +157,45 @@ jobs: run: | git add package.json lerna.json yarn.lock packages public test -e e2e/test-plugins && git add e2e/test-plugins - git commit -m "Update version to ${{ inputs.version }}" + git commit -m "Update version to $VERSION" - name: Git push if: ${{ inputs.dry_run }} != true - run: git push --set-upstream origin release/${{ github.run_id }}/${{ inputs.version }} + run: git push --set-upstream origin "release/${{ github.run_id }}/$VERSION" - name: Create PR without backports if: "${{ inputs.backport == '' }}" - run: > + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + BRANCH: ${{ steps.branch.outputs.branch }} + run: | + LATEST_FLAG="" + if [ "$LATEST" = "true" ]; then + LATEST_FLAG='-l "release/latest"' + fi gh pr create \ - $( [ "x${{ inputs.latest }}" == "xtrue" ] && printf %s '-l "release/latest"') \ + $LATEST_FLAG \ -l "no-changelog" \ - --dry-run=${{ inputs.dry_run }} \ - -B "${{ steps.branch.outputs.branch }}" \ - --title "Release: ${{ inputs.version }}" \ + --dry-run="$DRY_RUN" \ + -B "$BRANCH" \ + --title "Release: $VERSION" \ --body "These code changes must be merged after a release is complete" - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Create PR with backports if: "${{ inputs.backport != '' }}" - run: > + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + BRANCH: ${{ steps.branch.outputs.branch }} + run: | + LATEST_FLAG="" + if [ "$LATEST" = "true" ]; then + LATEST_FLAG='-l "release/latest"' + fi gh pr create \ - $( [ "x${{ inputs.latest }}" == "xtrue" ] && printf %s '-l "release/latest"') \ + $LATEST_FLAG \ -l "product-approved" \ -l "no-changelog" \ - --dry-run=${{ inputs.dry_run }} \ - -B "${{ steps.branch.outputs.branch }}" \ - --title "Release: ${{ inputs.version }}" \ + --dry-run="$DRY_RUN" \ + -B "$BRANCH" \ + --title "Release: $VERSION" \ --body "These code changes must be merged after a release is complete" - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/remove-milestone.yml b/.github/workflows/remove-milestone.yml deleted file mode 100644 index d41b63f1f51..00000000000 --- a/.github/workflows/remove-milestone.yml +++ /dev/null @@ -1,60 +0,0 @@ -name: Remove milestone -on: - workflow_dispatch: - inputs: - version: - required: true - description: Needs to match, exactly, the name of a milestone - workflow_call: - inputs: - version_call: - description: Needs to match, exactly, the name of a milestone - required: true - type: string - -jobs: - config: - runs-on: "ubuntu-latest" - outputs: - has-secrets: ${{ steps.check.outputs.has-secrets }} - steps: - - name: "Check for secrets" - id: check - shell: bash - run: | - if [ -n "${{ (secrets.GRAFANA_DELIVERY_BOT_APP_ID != '' && secrets.GRAFANA_DELIVERY_BOT_APP_PEM != '') || '' }}" ]; then - echo "has-secrets=1" >> "$GITHUB_OUTPUT" - fi - - main: - needs: config - if: needs.config.outputs.has-secrets - permissions: - issues: write - runs-on: ubuntu-latest - steps: - - name: Checkout Actions - uses: actions/checkout@v4 - with: - repository: "grafana/grafana-github-actions" - path: ./actions - ref: main - - name: Install Actions - run: npm install --production --prefix ./actions - - name: "Generate token" - id: generate_token - uses: tibdex/github-app-token@b62528385c34dbc9f38e5f4225ac829252d1ea92 - with: - app_id: ${{ secrets.GRAFANA_DELIVERY_BOT_APP_ID }} - private_key: ${{ secrets.GRAFANA_DELIVERY_BOT_APP_PEM }} - - name: Remove milestone from open issues (manually invoked) - if: ${{ github.event.inputs.version != '' }} - uses: ./actions/remove-milestone - with: - token: ${{ steps.generate_token.outputs.token }} - - name: Remove milestone from open issues (workflow invoked) - if: ${{ inputs.version_call != '' }} - uses: ./actions/remove-milestone - with: - version_call: ${{ inputs.version_call }} - token: ${{ steps.generate_token.outputs.token }} diff --git a/.github/workflows/run-dashboard-search-e2e.yml b/.github/workflows/run-dashboard-search-e2e.yml new file mode 100644 index 00000000000..7d59bd49fb5 --- /dev/null +++ b/.github/workflows/run-dashboard-search-e2e.yml @@ -0,0 +1,130 @@ +name: run-dashboard-search-e2e + +on: + workflow_run: + workflows: + - trigger-dashboard-search-e2e + types: + - completed + workflow_dispatch: + +env: + ARCH: linux-amd64 + +permissions: {} + +jobs: + setup: + runs-on: ubuntu-latest + if: github.event.pull_request.draft == false + outputs: + ini_files: ${{ steps.get_files.outputs.ini_files }} + + permissions: + contents: read + id-token: write + steps: + - name: Checkout + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + persist-credentials: false + - name: Pin Go version to mod file + uses: actions/setup-go@111f3307d8850f501ac008e886eec1fd1932a34 + with: + go-version-file: 'go.mod' + cache: true + - run: go version + - uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e + with: + node-version: 20 + cache: 'yarn' + - name: Cache Node Modules + id: cache-node-modules + uses: actions/cache@v3 + with: + path: | + node_modules + /home/runner/.cache/Cypress + key: ${{ runner.os }}-node-${{ hashFiles('package-lock.json') }} + - name: Install dependencies + if: steps.cache-node-modules.outputs.cache-hit != 'true' + run: yarn install --immutable + - name: Install Cypress dependencies + if: steps.cache-node-modules.outputs.cache-hit != 'true' + uses: cypress-io/github-action@108b8684ae52e735ff7891524cbffbcd4be5b19f + with: + runTests: false + - name: Cache Grafana Build and Dependencies + id: cache-grafana + uses: actions/cache@v3 + with: + path: | + bin/ + scripts/grafana-server/ + tools/ + public/ + conf/ + e2e/test-plugins/ + devenv/ + key: ${{ runner.os }}-grafana-${{ hashFiles('go.mod', 'package-lock.json', 'Makefile', 'pkg/storage/**/*.go', 'public/app/features/search/**/*.ts', 'public/app/features/search/**/*.tsx') }} + # only rebuild grafana if search files have changed ( or dependencies ) + - name: Build Grafana (Runs Only If Not Cached) + if: steps.cache-grafana.outputs.cache-hit != 'true' + run: make build + + - name: Get list of .ini files + id: get_files + run: | + INI_FILES=$(ls ${{ github.workspace }}/e2e/dashboards-search-suite/*.ini | jq -R -s -c 'split("\n")[:-1]') + echo "ini_files=$INI_FILES" >> $GITHUB_OUTPUT + shell: bash + + run_tests: + needs: setup + runs-on: ubuntu-latest + continue-on-error: true + if: github.event.pull_request.draft == false + strategy: + matrix: + ini_file: ${{ fromJson(needs.setup.outputs.ini_files) }} + + permissions: + contents: read + id-token: write + + steps: + - name: Checkout repository + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + - name: Restore Cached Node Modules + uses: actions/cache@v3 + with: + path: | + node_modules + /home/runner/.cache/Cypress + key: ${{ runner.os }}-node-${{ hashFiles('package-lock.json') }} + + - name: Restore Cached Grafana Build and Dependencies + uses: actions/cache@v3 + with: + path: | + bin/ + scripts/grafana-server/ + tools/ + public/ + conf/ + e2e/test-plugins/ + devenv/ + key: ${{ runner.os }}-grafana-${{ hashFiles('go.mod', 'package-lock.json', 'Makefile', 'pkg/storage/**/*.go', 'public/app/features/search/**/*.ts', 'public/app/features/search/**/*.tsx') }} + - name: Set the step name + id: set_file_name + env: + INI_NAME: ${{ matrix.ini_file }} + run: | + FILE_NAME=$(basename "$env.INI_NAME" .ini) + echo "FILE_NAME=$FILE_NAME" >> $GITHUB_OUTPUT + - name: Run tests for ${{ steps.set_file_name.outputs.FILE_NAME }} + env: + INI_NAME: ${{ matrix.ini_file }} + run: | + cp -rf $INI_NAME ${{ github.workspace }}/scripts/grafana-server/custom.ini + yarn e2e:dashboards-search || echo "Test failed but marking as success since unified search is behind a feature flag and should not block PRs" diff --git a/.github/workflows/run-e2e-suite.yml b/.github/workflows/run-e2e-suite.yml new file mode 100644 index 00000000000..b99d0ea0b30 --- /dev/null +++ b/.github/workflows/run-e2e-suite.yml @@ -0,0 +1,39 @@ +name: e2e suite + +on: + workflow_call: + inputs: + package: + type: string + required: true + suite: + type: string + required: true + +jobs: + main: + runs-on: ubuntu-latest-8-cores + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + persist-credentials: false + - uses: actions/download-artifact@v4 + with: + name: ${{ inputs.package }} + - uses: dagger/dagger-for-github@e47aba410ef9bb9ed81a4d2a97df31061e5e842e + if: inputs.old-arch == false + with: + verb: run + args: go run ./pkg/build/e2e --package=grafana.tar.gz --suite=${{ inputs.suite }} + - name: Set suite name + id: set-suite-name + env: + SUITE: ${{ inputs.suite }} + run: | + echo "suite=$(echo $SUITE | sed 's/\//-/g')" >> $GITHUB_OUTPUT + - uses: actions/upload-artifact@v4 + if: ${{ always() && inputs.old-arch != true }} + with: + name: e2e-${{ steps.set-suite-name.outputs.suite }}-${{github.run_number}} + path: videos + retention-days: 1 diff --git a/.github/workflows/run-schema-v2-e2e.yml b/.github/workflows/run-schema-v2-e2e.yml index 8b55aa4c430..62975992acb 100644 --- a/.github/workflows/run-schema-v2-e2e.yml +++ b/.github/workflows/run-schema-v2-e2e.yml @@ -18,13 +18,15 @@ jobs: if: github.event.pull_request.draft == false steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + persist-credentials: false - name: Pin Go version to mod file - uses: actions/setup-go@v5 + uses: actions/setup-go@111f3307d8850f501ac008e886eec1fd1932a34 with: go-version-file: 'go.mod' - run: go version - - uses: actions/setup-node@v4 + - uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e with: node-version: 20 cache: 'yarn' @@ -33,7 +35,7 @@ jobs: - name: Build grafana run: make build - name: Install Cypress dependencies - uses: cypress-io/github-action@v6 + uses: cypress-io/github-action@108b8684ae52e735ff7891524cbffbcd4be5b19f with: runTests: false - name: Run dashboard scenes e2e @@ -41,4 +43,4 @@ jobs: - name: Always succeed # This is a workaround to make the job pass even if the previous step fails if: failure() - run: exit 0 \ No newline at end of file + run: exit 0 diff --git a/.github/workflows/scripts/crowdin/create-tasks.js b/.github/workflows/scripts/crowdin/create-tasks.js new file mode 100644 index 00000000000..d3085f8afa0 --- /dev/null +++ b/.github/workflows/scripts/crowdin/create-tasks.js @@ -0,0 +1,84 @@ +const crowdin = require('@crowdin/crowdin-api-client'); +const TRANSLATED_CONNECTOR_DESCRIPTION = '{{tos_service_type: premium}}'; + +const API_TOKEN = process.env.CROWDIN_PERSONAL_TOKEN; +if (!API_TOKEN) { + console.error('Error: CROWDIN_PERSONAL_TOKEN environment variable is not set'); + process.exit(1); +} + +const PROJECT_ID = process.env.CROWDIN_PROJECT_ID; +if (!PROJECT_ID) { + console.error('Error: CROWDIN_PROJECT_ID environment variable is not set'); + process.exit(1); +} + +const { tasksApi, projectsGroupsApi, sourceFilesApi } = new crowdin.default({ + token: API_TOKEN, + organization: 'grafana' +}); + +const languages = await getLanguages(); +const fileIds = await getFileIds(); +console.log('Languages: ', languages); +console.log('File IDs: ', fileIds); + +// for (const language of languages) { +// const { name, id } = language; +// await createTask(`Translate to ${name}`, id, fileIds); +// } + +async function getLanguages() { + try { + const project = await projectsGroupsApi.getProject(PROJECT_ID); + const languages = project.data.targetLanguages; + return languages; + } catch (error) { + console.error('Failed to fetch languages: ', error.message); + if (error.response && error.response.data) { + console.error('Error details: ', JSON.stringify(error.response.data, null, 2)); + } + process.exit(1); + } +} + +async function getFileIds() { + try { + const response = await sourceFilesApi.listProjectFiles(PROJECT_ID); + const files = response.data; + const fileIds = files.map(file => file.data.id); + return fileIds; + } catch (error) { + console.error('Failed to fetch file IDs: ', error.message); + if (error.response && error.response.data) { + console.error('Error details: ', JSON.stringify(error.response.data, null, 2)); + } + process.exit(1); + } +} + +async function createTask(title, languageId, fileIds) { + try { + const taskParams = { + title, + description: TRANSLATED_CONNECTOR_DESCRIPTION, + languageId, + type: 2, // Translation by vendor + workflowStepId: 78, // Translation step ID + skipAssignedStrings: true, + fileIds, + }; + + console.log(`Creating Crowdin task: "${title}" for language ${languageId}`); + + const response = await tasksApi.addTask(PROJECT_ID, taskParams); + console.log(`Task created successfully! Task ID: ${response.data.id}`); + return response.data; + } catch (error) { + console.error('Failed to create Crowdin task: ', error.message); + if (error.response && error.response.data) { + console.error('Error details: ', JSON.stringify(error.response.data, null, 2)); + } + process.exit(1); + } +} diff --git a/.github/workflows/skye-add-to-project.yml b/.github/workflows/skye-add-to-project.yml new file mode 100644 index 00000000000..321f4c40b2a --- /dev/null +++ b/.github/workflows/skye-add-to-project.yml @@ -0,0 +1,106 @@ +name: Add issues and PRs to Skye project board +on: + workflow_dispatch: + inputs: + manual_issue_number: + description: 'Issue/PR number to add to project' + required: false + type: number + issues: + types: [opened] + pull_request: + types: [opened] + +permissions: + contents: read + id-token: write + +env: + ORGANIZATION: grafana + REPO: grafana + PROJECT_ID: "PVT_kwDOAG3Mbc4AxfcI" # Retrieved manually from GitHub GraphQL Explorer + +concurrency: + group: skye-add-to-project-${{ github.event.number }} + +jobs: + main: + if: github.repository == 'grafana/grafana' + runs-on: ubuntu-latest + steps: + - name: "Get vault secrets" + id: vault-secrets + uses: grafana/shared-workflows/actions/get-vault-secrets@main # zizmor: ignore[unpinned-uses] + with: + # Vault secret paths: + # - ci/repo/grafana/grafana/plugins_platform_issue_commands_github_bot + # - ci/repo/grafana/grafana/frontend_platform_skye_usernames (comma separated list of usernames) + repo_secrets: | + GH_APP_ID=plugins_platform_issue_commands_github_bot:app_id + GH_APP_PEM=plugins_platform_issue_commands_github_bot:app_pem + ALLOWED_USERS=frontend_platform_skye_usernames:allowed_users + + - name: Generate token + id: generate_token + uses: tibdex/github-app-token@b62528385c34dbc9f38e5f4225ac829252d1ea92 + with: + app_id: ${{ env.GH_APP_ID }} + private_key: ${{ env.GH_APP_PEM }} + + # Check if the user is in the list from the secret + - name: Check if user is allowed + id: check_user + env: + ALLOWED_USERS: ${{ env.ALLOWED_USERS }} + USERNAME: ${{ github.event.sender.login }} + run: | + # Convert the comma-separated list to an array + IFS=',' read -ra ALLOWED_USERS <<< "$ALLOWED_USERS" + + # Check if user is in the allowed list + for allowed_user in "${ALLOWED_USERS[@]}"; do + if [ "$allowed_user" = "$USERNAME" ]; then + echo "user_allowed=true" >> $GITHUB_OUTPUT + exit 0 + fi + done + echo "user_allowed=false" >> $GITHUB_OUTPUT + + # Convert the issue/PR number to a node ID for the GraphQL API + - name: Get node ID for item + if: steps.check_user.outputs.user_allowed == 'true' + id: get_node_id + uses: octokit/graphql-action@51bf543c240dcd14761320e2efc625dc32ec0d32 + with: + query: | + query getNodeId($owner: String!, $repo: String!, $number: Int!) { + repository(owner: $owner, name: $repo) { + issueOrPullRequest(number: $number) { + ... on Issue { id } + ... on PullRequest { id } + } + } + } + variables: | + owner: ${{ env.ORGANIZATION }} + repo: ${{ env.REPO }} + number: ${{ github.event.number || github.event.inputs.manual_issue_number }} + env: + GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }} + + # Finally, add the issue/PR to the project board + - name: Add to project board + if: steps.check_user.outputs.user_allowed == 'true' + uses: octokit/graphql-action@51bf543c240dcd14761320e2efc625dc32ec0d32 + with: + query: | + mutation addItem($projectid: ID!, $itemid: ID!) { + addProjectV2ItemById(input: {projectId: $projectid, contentId: $itemid}) { + item { id } + } + } + variables: | + projectid: ${{ env.PROJECT_ID }} + itemid: ${{ fromJSON(steps.get_node_id.outputs.data).repository.issueOrPullRequest.id }} + env: + GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }} diff --git a/.github/workflows/storybook-verification.yml b/.github/workflows/storybook-verification.yml new file mode 100644 index 00000000000..99f0c6dfe82 --- /dev/null +++ b/.github/workflows/storybook-verification.yml @@ -0,0 +1,48 @@ +name: Verify Storybook + +on: + pull_request: + paths: + - 'packages/grafana-ui/**' + - '!docs/**' + - '!*.md' + push: + branches: + - main + paths: + - 'packages/grafana-ui/**' + - '!docs/**' + - '!*.md' + +jobs: + verify-storybook: + name: Verify Storybook + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + persist-credentials: false + + - name: Setup Node.js + uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e + with: + node-version-file: 'package.json' + cache: 'yarn' + + - name: Install dependencies + run: yarn install --immutable + + - name: Run Storybook and E2E tests + uses: cypress-io/github-action@108b8684ae52e735ff7891524cbffbcd4be5b19f + with: + browser: chrome + start: yarn storybook --quiet + wait-on: 'http://localhost:9001' + wait-on-timeout: 60 + command: yarn e2e:storybook + install: false + env: + HOST: localhost + PORT: 9001 diff --git a/.github/workflows/sync-mirror-event.yml b/.github/workflows/sync-mirror-event.yml index b1a1466fdf9..b9387e02069 100644 --- a/.github/workflows/sync-mirror-event.yml +++ b/.github/workflows/sync-mirror-event.yml @@ -10,10 +10,21 @@ on: - "v*.*.*" - "release-*" +permissions: {} + # This is run after the pull request has been merged, so we'll run against the target branch jobs: dispatch-job: runs-on: ubuntu-latest + permissions: + contents: read + actions: write + env: + REF_NAME: ${{ github.ref_name }} + REPO: ${{ github.repository }} + SENDER: ${{ github.event.sender.login }} + SHA: ${{ github.sha }} + PR_COMMIT_SHA: ${{ github.event.pull_request.head.sha }} steps: - name: "Generate token" id: generate_token @@ -28,16 +39,18 @@ jobs: with: github-token: ${{ steps.generate_token.outputs.token }} script: | + const {HEAD_REF, BASE_REF, REPO, SENDER, SHA} = process.env; + await github.rest.actions.createWorkflowDispatch({ owner: 'grafana', repo: 'security-patch-actions', workflow_id: 'mirror-branch-and-apply-patches-event.yml', ref: 'main', inputs: { - src_ref: "${{ github.ref_name }}", - src_repo: "${{ github.repository }}", - src_sha: "${{ github.sha }}", - dest_repo: "${{ github.repository }}-security-mirror", - patch_repo: "${{ github.repository }}-security-patches" + src_ref: REF_NAME, + src_repo: REPO, + src_sha: SHA, + dest_repo: REPO + "-security-mirror", + patch_repo: REPO + "-security-patches" } }) diff --git a/.github/workflows/trigger-dashboard-search-e2e.yml b/.github/workflows/trigger-dashboard-search-e2e.yml new file mode 100644 index 00000000000..db7025f17c1 --- /dev/null +++ b/.github/workflows/trigger-dashboard-search-e2e.yml @@ -0,0 +1,28 @@ +name: trigger-dashboard-search-e2e +# triggers the dashboard search e2e tests which runs async +# doesn't block prs, allows setting up notifications from grafana +on: + push: + branches: + - main + paths: + - public/app/features/search/**/*.ts + - public/app/features/search/**/*.tsx + - pkg/storage/**/*.go + pull_request: + branches: + - main + paths: + - public/app/features/search/**/*.ts + - public/app/features/search/**/*.tsx + - pkg/storage/**/*.go +env: + ARCH: linux-amd64 + +jobs: + trigger-search-e2e: + runs-on: ubuntu-latest + if: github.event.pull_request.draft == false + steps: + - name: Trigger Dashboard Search E2E + run: echo "Triggered Dashboard Search e2e..." \ No newline at end of file diff --git a/.github/workflows/trivy-scan.yml b/.github/workflows/trivy-scan.yml index 25104af8f29..921d25b76ff 100644 --- a/.github/workflows/trivy-scan.yml +++ b/.github/workflows/trivy-scan.yml @@ -16,9 +16,11 @@ jobs: trivy-scan: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + persist-credentials: false - name: Install Trivy - uses: aquasecurity/setup-trivy@v0.2.2 + uses: aquasecurity/setup-trivy@9ea583eb67910444b1f64abf338bd2e105a0a93d with: version: v0.56.2 cache: true diff --git a/.github/workflows/update-changelog.yml b/.github/workflows/update-changelog.yml deleted file mode 100644 index db22ab1fb96..00000000000 --- a/.github/workflows/update-changelog.yml +++ /dev/null @@ -1,52 +0,0 @@ -name: Update changelog -on: - workflow_dispatch: - inputs: - version: - required: true - description: 'Needs to match, exactly, the name of a milestone. The version to be released please respect: major.minor.patch, major.minor.patch-preview or major.minor.patch-preview format. example: 7.4.3, 7.4.3-preview or 7.4.3-preview1' - skip_pr: - required: false - default: "0" - skip_community_post: - required: false - default: "0" -jobs: - config: - runs-on: "ubuntu-latest" - outputs: - has-secrets: ${{ steps.check.outputs.has-secrets }} - steps: - - name: "Check for secrets" - id: check - shell: bash - run: | - if [ -n "${{ (secrets.GRAFANA_DELIVERY_BOT_APP_ID != '' && - secrets.GRAFANA_DELIVERY_BOT_APP_PEM != '' && - secrets.GRAFANA_MISC_STATS_API_KEY != '' && - secrets.GRAFANABOT_FORUM_KEY != '' - ) || '' }}" ]; then - echo "has-secrets=1" >> "$GITHUB_OUTPUT" - fi - - main: - needs: config - if: needs.config.outputs.has-secrets - runs-on: ubuntu-latest - steps: - - name: "Generate token" - id: generate_token - uses: tibdex/github-app-token@b62528385c34dbc9f38e5f4225ac829252d1ea92 - with: - app_id: ${{ secrets.GRAFANA_DELIVERY_BOT_APP_ID }} - private_key: ${{ secrets.GRAFANA_DELIVERY_BOT_APP_PEM }} - - name: Run update changelog (manually invoked) - uses: grafana/grafana-github-actions-go/update-changelog@main - with: - token: ${{ steps.generate_token.outputs.token }} - version: ${{ inputs.version }} - metrics_api_key: ${{ secrets.GRAFANA_MISC_STATS_API_KEY }} - community_api_key: ${{ secrets.GRAFANABOT_FORUM_KEY }} - community_api_username: grafanabot - skip_pr: ${{ inputs.skip_pr }} - skip_community_post: ${{ inputs.skip_community_post }} diff --git a/.github/workflows/update-make-docs.yml b/.github/workflows/update-make-docs.yml index 49b64504bd0..7d727f284df 100644 --- a/.github/workflows/update-make-docs.yml +++ b/.github/workflows/update-make-docs.yml @@ -8,8 +8,10 @@ jobs: if: github.repository == 'grafana/grafana' runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: grafana/writers-toolkit/update-make-docs@update-make-docs/v1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + persist-credentials: false + - uses: grafana/writers-toolkit/update-make-docs@update-make-docs/v1 # zizmor: ignore[unpinned-uses] with: pr_options: > --label 'backport v10.1.x' diff --git a/.github/workflows/verify-kinds.yml b/.github/workflows/verify-kinds.yml index 88b45660d45..ce0a7a00b8a 100644 --- a/.github/workflows/verify-kinds.yml +++ b/.github/workflows/verify-kinds.yml @@ -11,12 +11,13 @@ jobs: runs-on: "ubuntu-latest" steps: - name: "Checkout Grafana repo" - uses: "actions/checkout@v4" + uses: "actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683" with: fetch-depth: 0 + persist-credentials: false - name: "Setup Go" - uses: "actions/setup-go@v4" + uses: "actions/setup-go@19bb51245e9c80abacb2e91cc42b33fa478b8639" with: go-version-file: go.mod diff --git a/.github/workflows/zizmor.yml b/.github/workflows/zizmor.yml new file mode 100644 index 00000000000..7b8321cce14 --- /dev/null +++ b/.github/workflows/zizmor.yml @@ -0,0 +1,23 @@ +name: Zizmor GitHub Actions static analysis +on: + pull_request: + push: + branches: + - main + +jobs: + zizmor: + name: Analyse with Zizmor + + permissions: + actions: read + contents: read + # required to comment on pull requests with the results of the check + pull-requests: write + # required to upload the results to GitHub's code scanning service + security-events: write + + uses: grafana/shared-workflows/.github/workflows/reusable-zizmor.yml@main # zizmor: ignore[unpinned-uses] + with: + fail-severity: high + min-severity: high diff --git a/.github/zizmor.yml b/.github/zizmor.yml new file mode 100644 index 00000000000..fba4a80be24 --- /dev/null +++ b/.github/zizmor.yml @@ -0,0 +1,31 @@ +rules: + unpinned-uses: + config: + policies: + "*": hash-pin + actions/*: any + github/*: any + grafana/*: any + forbidden-uses: + config: + deny: + # Policy-banned by our security team due to CVE-2025-30066 & CVE-2025-30154. + # https://www.cisa.gov/news-events/alerts/2025/03/18/supply-chain-compromise-third-party-tj-actionschanged-files-cve-2025-30066-and-reviewdogaction + # https://nvd.nist.gov/vuln/detail/cve-2025-30066 + # https://nvd.nist.gov/vuln/detail/cve-2025-30154 + - reviewdog/* + cache-poisoning: + ignore: + - backend-unit-tests.yml + - frontend-lint.yml + - pr-frontend-unit-tests.yml + - pr-test-integration.yml + - publish-kinds-release.yml + dangerous-triggers: + ignore: + - auto-milestone.yml + - backport.yml + - pr-checks.yml + - pr-commands.yml + - pr-patch-check-event.yml + - run-dashboard-search-e2e.yml diff --git a/pkg/build/actions/bump-version/action.yml b/pkg/build/actions/bump-version/action.yml index 783145097a2..24ae182daf2 100644 --- a/pkg/build/actions/bump-version/action.yml +++ b/pkg/build/actions/bump-version/action.yml @@ -11,7 +11,7 @@ runs: with: go-version-file: go.mod - name: Bump versions - uses: dagger/dagger-for-github@v5 + uses: dagger/dagger-for-github@e47aba410ef9bb9ed81a4d2a97df31061e5e842e with: verb: run args: go run ./pkg/build/actions/bump-version -version=${{ inputs.version }}