diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 08d9aeaf43b..f62fe0e1748 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -758,6 +758,8 @@ embed.go @grafana/grafana-as-code /.github/renovate.json5 @grafana/frontend-ops /.github/actions/setup-enterprise/action.yml @grafana/grafana-backend-group /.github/actions/setup-grafana-bench/ @Proximyst +/.github/workflows/actionlint-format.txt @Proximyst +/.github/workflows/actionlint.yml @Proximyst /.github/workflows/add-to-whats-new.yml @grafana/docs-tooling /.github/workflows/auto-triager/ @grafana/plugins-platform-frontend /.github/workflows/alerting-swagger-gen.yml @grafana/alerting-backend diff --git a/.github/workflows/actionlint-format.txt b/.github/workflows/actionlint-format.txt new file mode 100644 index 00000000000..6e60cd50399 --- /dev/null +++ b/.github/workflows/actionlint-format.txt @@ -0,0 +1,66 @@ +{ + "$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json", + "version": "2.1.0", + "runs": [ + { + "tool": { + "driver": { + "name": "GitHub Actions lint", + "version": {{ getVersion | json }}, + "informationUri": "https://github.com/rhysd/actionlint", + "rules": [ + {{$first := true}} + {{range $ := allKinds }} + {{if $first}}{{$first = false}}{{else}},{{end}} + { + "id": {{json $.Name}}, + "name": {{$.Name | toPascalCase | json}}, + "defaultConfiguration": { + "level": "error" + }, + "properties": { + "description": {{json $.Description}}, + "queryURI": "https://github.com/rhysd/actionlint/blob/main/docs/checks.md" + }, + "fullDescription": { + "text": {{json $.Description}} + }, + "helpUri": "https://github.com/rhysd/actionlint/blob/main/docs/checks.md" + } + {{end}} + ] + } + }, + "results": [ + {{$first := true}} + {{range $ := .}} + {{if $first}}{{$first = false}}{{else}},{{end}} + { + "ruleId": {{json $.Kind}}, + "message": { + "text": {{json $.Message}} + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": {{json $.Filepath}}, + "uriBaseId": "%SRCROOT%" + }, + "region": { + "startLine": {{$.Line}}, + "startColumn": {{$.Column}}, + "endColumn": {{$.EndColumn}}, + "snippet": { + "text": {{json $.Snippet}} + } + } + } + } + ] + } + {{end}} + ] + } + ] +} \ No newline at end of file diff --git a/.github/workflows/actionlint.yml b/.github/workflows/actionlint.yml new file mode 100644 index 00000000000..de1051ef729 --- /dev/null +++ b/.github/workflows/actionlint.yml @@ -0,0 +1,60 @@ +# This workflow depends on the ./actionlint-format.txt file. It is MIT licensed (thanks, rhysd!): https://github.com/rhysd/actionlint/blob/2ab3a12c7848f6c15faca9a92612ef4261d0e370/testdata/format/sarif_template.txt +name: Actionlint + +on: + push: + branches: + - main + - release-* + pull_request: + types: + - opened + - synchronize + - reopened + +permissions: {} + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ startsWith(github.ref, 'refs/pull/') }} + +jobs: + run-actionlint: + name: Lint GitHub Actions files + runs-on: ubuntu-latest + permissions: + contents: read # to check out the code + actions: read # to read the workflow files + security-events: write # for uploading the SARIF report + + env: + ACTIONLINT_VERSION: 1.7.7 + # curl -LXGET https://github.com/rhysd/actionlint/releases/download/v${ACTIONLINT_VERSION}/actionlint_${ACTIONLINT_VERSION}_checksums.txt | grep linux_amd64 + CHECKSUM: 023070a287cd8cccd71515fedc843f1985bf96c436b7effaecce67290e7e0757 + + steps: + - name: Checkout code + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 + with: + persist-credentials: false + + # GitHub Actions only runs x86_64. This will break if that assumption changes. + - name: Download Actionlint + run: | + set -euo pipefail + curl -OLXGET https://github.com/rhysd/actionlint/releases/download/v"${ACTIONLINT_VERSION}"/actionlint_"${ACTIONLINT_VERSION}"_linux_amd64.tar.gz + echo "${CHECKSUM} actionlint_${ACTIONLINT_VERSION}_linux_amd64.tar.gz" | sha256sum -c - + tar xzf actionlint_"${ACTIONLINT_VERSION}"_linux_amd64.tar.gz + test -f actionlint + chmod +x actionlint + + - name: Run Actionlint + run: ./actionlint -format "$(cat .github/workflows/actionlint-format.txt)" | tee results.sarif + + - name: Upload to GitHub security events + if: success() || failure() + # If there are security problems, GitHub will automatically comment on the PR for us. + uses: github/codeql-action/upload-sarif@28deaeda66b76a05916b6923827895f2b14ab387 # v3.28.16 + with: + sarif_file: results.sarif + category: actionlint diff --git a/.github/workflows/alerting-update-module.yml b/.github/workflows/alerting-update-module.yml index 5bbf260e64a..dce80d065e4 100644 --- a/.github/workflows/alerting-update-module.yml +++ b/.github/workflows/alerting-update-module.yml @@ -37,7 +37,7 @@ jobs: id: current-commit run: | FROM_COMMIT=$(go list -m -json github.com/grafana/alerting | jq -r '.Version' | grep -oP '(?<=-)[a-f0-9]+$') - echo "from_commit=$FROM_COMMIT" >> $GITHUB_OUTPUT + echo "from_commit=$FROM_COMMIT" >> "$GITHUB_OUTPUT" - name: Get current branch name id: current-branch-name @@ -47,14 +47,14 @@ jobs: id: latest-commit env: GH_TOKEN: ${{ github.token }} + BRANCH: ${{ steps.current-branch-name.outputs.name }} run: | - BRANCH="${{ steps.current-branch-name.outputs.name }}" - TO_COMMIT=$(gh api repos/grafana/alerting/commits/$BRANCH --jq '.sha') + TO_COMMIT="$(gh api repos/grafana/alerting/commits/"$BRANCH" --jq '.sha')" if [ -z "$TO_COMMIT" ]; then echo "Branch $BRANCH not found in alerting repo, falling back to main branch" exit 1 fi - echo "to_commit=$TO_COMMIT" >> $GITHUB_OUTPUT + echo "to_commit=$TO_COMMIT" >> "$GITHUB_OUTPUT" - name: Compare commit hashes run: | @@ -74,26 +74,31 @@ jobs: id: check-commits env: GH_TOKEN: ${{ github.token }} + FROM_COMMIT: ${{ steps.current-commit.outputs.from_commit }} + TO_COMMIT: ${{ steps.latest-commit.outputs.to_commit }} run: | - # get all commits that contains 'Alerting:' in the message - ALERTING_COMMITS=$(gh api repos/grafana/alerting/compare/${{ steps.current-commit.outputs.from_commit }}...${{ steps.latest-commit.outputs.to_commit }} \ - --jq '.commits[].commit.message | split("\n")[0]') || true - + # get all commits that contains 'Alerting:' in the message + ALERTING_COMMITS="$(gh api repos/grafana/alerting/compare/"$FROM_COMMIT"..."$TO_COMMIT" \ + --jq '.commits[].commit.message | split("\n")[0]')" || true + # Use printf instead of echo -e for better multiline handling printf "%s\n" "$ALERTING_COMMITS" - + # make the list for markdown and replace PR numbers with links - ALERTING_COMMITS_FORMATTED=$(echo "$ALERTING_COMMITS" | while read -r line; do echo "- $line" | sed -E 's/\(#([0-9]+)\)/[#\1](https:\/\/github.com\/grafana\/grafana\/pull\/\1)/g'; done) - - echo "alerting_commits<> $GITHUB_OUTPUT - echo "$ALERTING_COMMITS_FORMATTED" >> $GITHUB_OUTPUT - echo "EOF" >> $GITHUB_OUTPUT + ALERTING_COMMITS_FORMATTED="$(echo "$ALERTING_COMMITS" | while read -r line; do echo "- $line" | sed -E 's/\(#([0-9]+)\)/[#\1](https:\/\/github.com\/grafana\/grafana\/pull\/\1)/g'; done)" + + { + echo "alerting_commits<> "$GITHUB_OUTPUT" - name: Update alerting module env: GOSUMDB: off + PINNED_COMMIT: ${{ steps.latest-commit.outputs.to_commit }} run: | - go get github.com/grafana/alerting@${{ steps.latest-commit.outputs.to_commit }} + go get github.com/grafana/alerting@"$PINNED_COMMIT" make update-workspace - id: get-secrets @@ -124,7 +129,7 @@ jobs: Compare changes: https://github.com/grafana/alerting/compare/${{ steps.current-commit.outputs.from_commit }}...${{ steps.latest-commit.outputs.to_commit }}
Commits - + ${{ steps.check-commits.outputs.alerting_commits }}
@@ -132,6 +137,10 @@ jobs: Created by: [GitHub Action Job](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}) - name: Add PR URL to Summary if: steps.create-pr.outputs.pull-request-url != '' + env: + PR_URL: ${{ steps.create-pr.outputs.pull-request-url }} run: | - echo "## Pull Request Created" >> $GITHUB_STEP_SUMMARY - echo "🔗 [View Pull Request](${{ steps.create-pr.outputs.pull-request-url }})" >> $GITHUB_STEP_SUMMARY + { + echo "## Pull Request Created" + echo "🔗 [View Pull Request]($PR_URL)" + } >> "$GITHUB_STEP_SUMMARY" diff --git a/.github/workflows/bump-version.yml b/.github/workflows/bump-version.yml index 39fa0566d86..e9c902fe484 100644 --- a/.github/workflows/bump-version.yml +++ b/.github/workflows/bump-version.yml @@ -44,4 +44,4 @@ jobs: git add . git commit -m "bump version ${VERSION}" git push - 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}" + 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 0d3abeb352f..31839f88a7d 100644 --- a/.github/workflows/changelog.yml +++ b/.github/workflows/changelog.yml @@ -142,12 +142,12 @@ jobs: - name: "Commit changelog changes" run: git add CHANGELOG.md && git commit --allow-empty -m "Update changelog" CHANGELOG.md - name: "git push" - if: ${{ inputs.dry_run }} != true + if: inputs.dry_run != true run: git push - name: "Create changelog PR" run: > gh pr create \ - --dry-run=${DRY_RUN} \ + --dry-run="${DRY_RUN}" \ --label "no-backport" \ --label "no-changelog" \ -B "${TARGET}" \ diff --git a/.github/workflows/core-plugins-build-and-release.yml b/.github/workflows/core-plugins-build-and-release.yml index 66447cb9ffa..6b05b9863c8 100644 --- a/.github/workflows/core-plugins-build-and-release.yml +++ b/.github/workflows/core-plugins-build-and-release.yml @@ -48,7 +48,7 @@ jobs: persist-credentials: false - name: Verify inputs run: | - if [ -z $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 # zizmor: ignore[unpinned-uses] with: @@ -72,13 +72,13 @@ jobs: shell: bash id: get_dir run: | - dir=$(dirname \ - $(egrep -lir --include=plugin.json --exclude-dir=dist \ - '"id": "${PLUGIN_ID}"' \ + dir="$(dirname \ + "$(grep -Elir --include=plugin.json --exclude-dir=dist \ + '"id": "'"${PLUGIN_ID}"'"' \ public/app/plugins \ - ) \ - ) - echo "dir=${dir}" >> $GITHUB_OUTPUT + )" \ + )" + echo "dir=${dir}" >> "$GITHUB_OUTPUT" - name: Install frontend dependencies shell: bash working-directory: ${{ steps.get_dir.outputs.dir }} @@ -88,17 +88,17 @@ jobs: shell: sh 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$GRABPL_VERSION/grabpl + mkdir -pv ./bin + 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\("$PLUGIN_ID"' pkg/tsdb; then - echo "has_backend=true" >> $GITHUB_OUTPUT + if grep -Eqr --include=main.go 'datasource.Manage\('"$PLUGIN_ID" pkg/tsdb; then + echo "has_backend=true" >> "$GITHUB_OUTPUT" else - echo "has_backend=false" >> $GITHUB_OUTPUT + echo "has_backend=false" >> "$GITHUB_OUTPUT" fi - name: Setup golang environment uses: actions/setup-go@19bb51245e9c80abacb2e91cc42b33fa478b8639 @@ -149,6 +149,8 @@ jobs: - name: build:frontend shell: bash id: build_frontend + env: + OUTPUT_DIR: ${{ steps.get_dir.outputs.dir }} run: | command="plugin:build:commit" if [ "$GITHUB_REF" != "refs/heads/main" ]; then @@ -156,15 +158,15 @@ jobs: command="plugin:build" fi 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 + version="$(jq -r .info.version "$OUTPUT_DIR"/dist/plugin.json)" + echo "version=${version}" >> "$GITHUB_OUTPUT" - name: build:backend if: steps.check_backend.outputs.has_backend == 'true' shell: bash env: VERSION: ${{ steps.build_frontend.outputs.version }} run: | - make build-plugin-go PLUGIN_ID=$PLUGIN_ID + make build-plugin-go PLUGIN_ID="$PLUGIN_ID" - name: package working-directory: ${{ steps.get_dir.outputs.dir }} run: | @@ -177,16 +179,17 @@ jobs: env: GCOM_TOKEN: ${{ env.PLUGINS_GCOM_TOKEN }} VERSION: ${{ steps.build_frontend.outputs.version }} + GCOM_API: ${{ env.GCOM_API }} run: | - api_res=$(curl -X 'GET' -H "Authorization: Bearer $GCOM_TOKEN" \ - '${{ env.GCOM_API}}/api/plugins/$PLUGIN_ID?version=$VERSION' \ - -H 'accept: application/json') - api_res_code=$(echo $api_res | jq -r .code) + api_res="$(curl -X 'GET' -H "Authorization: Bearer $GCOM_TOKEN" \ + "$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 echo "No existing release found" else echo "Expecting a missing release, got:" - echo $api_res + echo "$api_res" exit 1 fi - name: store build artifacts @@ -197,55 +200,46 @@ jobs: - name: Publish release to Google Cloud Storage working-directory: ${{ steps.get_dir.outputs.dir }} env: - VERSION: ${{ steps.build_frontend.outputs.version }} + VERSION: ${{ steps.build_frontend.outputs.version }} + GCP_BUCKET: ${{ env.GCP_BUCKET }} run: | echo "Publish release to Google Cloud Storage:" + set -x touch ci/packages/windows ci/packages/darwin ci/packages/linux ci/packages/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 + gsutil -m cp -r ci/packages/*windows* "gs://$GCP_BUCKET/$PLUGIN_ID/release/${VERSION}/windows" + gsutil -m cp -r ci/packages/*linux* "gs://$GCP_BUCKET/$PLUGIN_ID/release/${VERSION}/linux" + gsutil -m cp -r ci/packages/*darwin* "gs://$GCP_BUCKET/$PLUGIN_ID/release/${VERSION}/darwin" + gsutil -m cp -r ci/packages/*any* "gs://$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 }} env: GCOM_TOKEN: ${{ env.PLUGINS_GCOM_TOKEN }} VERSION: ${{ steps.build_frontend.outputs.version }} + GCP_BUCKET: ${{ env.GCP_BUCKET }} + OUTPUT_DIR: ${{ steps.get_dir.outputs.dir }} + GCOM_API: ${{ env.GCOM_API }} run: | echo "Publish new plugin version on grafana.com:" echo "Plugin version: ${VERSION}" - result=`curl -H "Authorization: Bearer $GCOM_TOKEN" -H "Content-Type: application/json" ${{ env.GCOM_API}}/api/plugins -d "{ - \"url\": \"https://github.com/grafana/grafana/tree/main/${{ steps.get_dir.outputs.dir }}\", - \"download\": { - \"linux-amd64\": { - \"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 }}/$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 }}/$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 }}/$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 }}/$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 }}/$PLUGIN_ID/release/${VERSION}/darwin/$PLUGIN_ID-${VERSION}.darwin_arm64.zip\", - \"md5\": \"$(cat ci/packages/info-darwin_arm64.json | jq -r .plugin.md5)\" - } - } - }"` - if [[ "$(echo $result | jq -r .version)" == "null" ]]; then + + OUTPUT_URL="https://github.com/grafana/grafana/tree/$OUTPUT_DIR" \ + jq -n '{"url": env.OUTPUT_URL}' > body.json + osarchs=(linux_amd64 linux_arm64 linux_arm windows_amd64 darwin_amd64 darwin_arm64) + for osarch in "${osarchs[@]}"; do + echo "Processing $osarch" + KEY="${osarch//_/-}" \ + OSARCH="$osarch" \ + jq -s '. as $i | .[0] | .download[env.KEY] = { + "url": "https://storage.googleapis.com/\(env.GCP_BUCKET)/\(env.PLUGIN_ID)/release/\(env.VERSION)/linux/\(env.PLUGIN_ID)-\(env.VERSION).\(env.OSARCH).zip", + "md5": $i[1].plugin.md5 + }' body.json ci/packages/info-"$osarch".json > tmp.json && mv tmp.json body.json + done + + result="$(curl -H "Authorization: Bearer $GCOM_TOKEN" -H "Content-Type: application/json" "$GCOM_API"/api/plugins --data-binary '@body.json')" + if [[ "$(echo "$result" | jq -r .version)" == "null" ]]; then echo "Failed to publish plugin version. Got:" - echo $result + echo "$result" exit 1 fi - name: Publish new plugin version on grafana.com (frontend only) @@ -254,20 +248,29 @@ jobs: env: GCOM_TOKEN: ${{ env.PLUGINS_GCOM_TOKEN }} VERSION: ${{ steps.build_frontend.outputs.version }} + GCOM_API: ${{ env.GCOM_API }} + OUTPUT_DIR: ${{ steps.get_dir.outputs.dir }} + GCP_BUCKET: ${{ env.GCP_BUCKET }} run: | echo "Publish new plugin version on grafana.com:" echo "Plugin version: ${VERSION}" - result=`curl -H "Authorization: Bearer $GCOM_TOKEN" -H "Content-Type: application/json" ${{ env.GCOM_API}}/api/plugins -d "{ - \"url\": \"https://github.com/grafana/grafana/tree/main/${{ steps.get_dir.outputs.dir }}\", - \"download\": { - \"any\": { - \"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)\" + + OUTPUT_URL="https://github.com/grafana/grafana/tree/$OUTPUT_DIR" \ + DOWNLOAD_URL="https://storage.googleapis.com/$GCP_BUCKET/$PLUGIN_ID/release/${VERSION}/any/$PLUGIN_ID-${VERSION}.any.zip" \ + MD5_CHECKSUM="$(jq -r '.plugin.md5' ci/packages/info-any.json)" \ + jq -rn '{ + "url": env.OUTPUT_URL, + "download": { + "any": { + "url": env.DOWNLOAD_URL, + "md5": env.MD5_CHECKSUM } } - }"` - if [[ "$(echo $result | jq -r .version)" == "null" ]]; then + }' > body.json + + result="$(curl -H "Authorization: Bearer $GCOM_TOKEN" -H "Content-Type: application/json" "$GCOM_API"/api/plugins --data-binary '@body.json')" + if [[ "$(echo "$result" | jq -r .version)" == "null" ]]; then echo "Failed to publish plugin version. Got:" - echo $result + echo "$result" exit 1 fi diff --git a/.github/workflows/dashboards-issue-add-label.yml b/.github/workflows/dashboards-issue-add-label.yml index 4072f062fa7..7eea1217941 100644 --- a/.github/workflows/dashboards-issue-add-label.yml +++ b/.github/workflows/dashboards-issue-add-label.yml @@ -41,6 +41,7 @@ jobs: ISSUE_NUMBER: ${{ github.event.issue.number }} TARGET_PROJECT: ${{ env.TARGET_PROJECT }} run: | + # shellcheck disable=SC2016 # we don't want the $s to be expanded gh api graphql -f query=' query($org: String!, $repo: String!) { repository(name: $repo, owner: $org) { @@ -55,15 +56,18 @@ jobs: } } } - }' -f org=$ORGANIZATION -f repo=$REPO > projects_data.json + }' -f org="$ORGANIZATION" -f repo="$REPO" > projects_data.json - 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 + { + echo "IN_TARGET_PROJ=$(jq '.data.repository.issue.projectItems.nodes[] | select(.project.number=='"$TARGET_PROJECT"') | .project != null' projects_data.json)" + 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: | + # shellcheck disable=SC2153 # we define the variable on the line above in 'read' IFS=',' read -ra LABEL_IDs <<< "$LABEL_IDS" for item in "${LABEL_IDs[@]}"; do echo "Item: $item" @@ -74,6 +78,7 @@ jobs: GH_TOKEN: ${{ steps.generate_token.outputs.token }} LABEL_IDS: ${{ env.LABEL_IDS }} run: | + # shellcheck disable=SC2016 # we don't want the $s to be expanded gh api graphql -f query=' mutation ($labelableId: ID!, $labelIds: [ID!]!) { addLabelsToLabelable( @@ -81,4 +86,4 @@ jobs: ) { clientMutationId } - }' -f labelableId=$ITEM_ID -f labelIds=$LABEL_IDS + }' -f labelableId="$ITEM_ID" -f labelIds="$LABEL_IDS" diff --git a/.github/workflows/detect-breaking-changes-levitate.yml b/.github/workflows/detect-breaking-changes-levitate.yml index 2e6257a003c..61999c718a9 100644 --- a/.github/workflows/detect-breaking-changes-levitate.yml +++ b/.github/workflows/detect-breaking-changes-levitate.yml @@ -399,7 +399,7 @@ jobs: echo "Breaking changes detected. Please check the levitate report in your pull request. This workflow won't block merging." fi - exit ${LV_EXIT_CODE} + exit "${LV_EXIT_CODE}" shell: bash env: LV_EXIT_CODE: ${{ steps.levitate-run.outputs.exit_code }} diff --git a/.github/workflows/frontend-lint.yml b/.github/workflows/frontend-lint.yml index 425257dd67e..29910d256f0 100644 --- a/.github/workflows/frontend-lint.yml +++ b/.github/workflows/frontend-lint.yml @@ -26,13 +26,14 @@ jobs: cache-dependency-path: 'yarn.lock' - run: yarn install --immutable --check-cache - run: | + # shellcheck disable=SC2102,SC2016,SC2125 # this is just a string. we _want_ all the bash features to be disabled. extract_error_message='::error::Extraction failed. Make sure that you have no dynamic translation phrases, such as "t(`preferences.theme.{themeID}`, themeName)" and that no translation key is used twice. Search the output for '[warning]' to find the offending file.' make i18n-extract || (echo "${extract_error_message}" && false) - run: | uncommited_error_message="::error::Translation extraction has not been committed. Please run 'make i18n-extract', commit the changes and push again." file_diff=$(git diff --dirstat public/locales) if [ -n "$file_diff" ]; then - echo $file_diff + echo "$file_diff" echo "${uncommited_error_message}" exit 1 fi diff --git a/.github/workflows/i18n-crowdin-download.yml b/.github/workflows/i18n-crowdin-download.yml index 32a2ceab514..6aeddc560fb 100644 --- a/.github/workflows/i18n-crowdin-download.yml +++ b/.github/workflows/i18n-crowdin-download.yml @@ -151,20 +151,21 @@ jobs: # - the PR does not modify files other than json files under the public/locales/ directory # - the PR does not modify the en-US locale run: | - filesChanged=$(gh pr diff --name-only ${{ steps.crowdin-download.outputs.pull_request_url }}) + filesChanged="$(gh pr diff --name-only "$PR_URL")" - if [[ $(echo $filesChanged | grep -v 'public/locales/[a-zA-Z\-]*/grafana.json' | wc -l) -ne 0 ]]; then + if [[ $(echo "$filesChanged" | grep -cv 'public/locales/[a-zA-Z\-]*/grafana.json') -ne 0 ]]; then echo "Non-i18n changes detected, not approving" exit 1 fi - if [[ $(echo $filesChanged | grep "public/locales/en-US" | wc -l) -ne 0 ]]; then + if [[ $(echo "$filesChanged" | grep -c "public/locales/en-US") -ne 0 ]]; then echo "public/locales/en-US changes detected, not approving" exit 1 fi echo "Approving and enabling automerge" - gh pr review ${{ steps.crowdin-download.outputs.pull_request_url }} --approve - gh pr merge --auto --squash ${{ steps.crowdin-download.outputs.pull_request_url }} + gh pr review "$PR_URL" --approve + gh pr merge --auto --squash "$PR_URL" env: GITHUB_TOKEN: ${{ steps.generate_approver_token.outputs.token }} + PR_URL: ${{ steps.crowdin-download.outputs.pull_request_url }} diff --git a/.github/workflows/pr-dependabot-update-go-workspace.yml b/.github/workflows/pr-dependabot-update-go-workspace.yml index a83875c4644..82169bd69ac 100644 --- a/.github/workflows/pr-dependabot-update-go-workspace.yml +++ b/.github/workflows/pr-dependabot-update-go-workspace.yml @@ -65,5 +65,5 @@ jobs: if ! git diff --exit-code --quiet; then echo "Committing and pushing workspace changes" git commit -a -m "update workspace" - git push origin $BRANCH_NAME + git push origin "$BRANCH_NAME" fi diff --git a/.github/workflows/pr-e2e-tests.yml b/.github/workflows/pr-e2e-tests.yml index 37d0ff2a3a3..6f1ca7bd5d6 100644 --- a/.github/workflows/pr-e2e-tests.yml +++ b/.github/workflows/pr-e2e-tests.yml @@ -36,7 +36,7 @@ jobs: 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: mv "$(cat out.txt)" grafana.tar.gz - run: echo "artifact=grafana-e2e-${{github.run_number}}" >> "$GITHUB_OUTPUT" id: artifact - uses: actions/upload-artifact@v4 diff --git a/.github/workflows/pr-test-integration.yml b/.github/workflows/pr-test-integration.yml index 725eea0b92a..c79cc569299 100644 --- a/.github/workflows/pr-test-integration.yml +++ b/.github/workflows/pr-test-integration.yml @@ -30,8 +30,11 @@ jobs: go-version-file: go.mod cache: true - run: | + go_packages="$(find ./pkg -type f -name '*_test.go' -exec grep -l '^func TestIntegration' '{}' '+' | grep -o '\(.*\)/' | sort -u)" + IFS=' ' read -ra packages <<< "$go_packages" + 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) + go test -tags=sqlite -timeout=5m -run '^TestIntegration' "${packages[@]}" mysql: name: MySQL runs-on: ubuntu-latest-8-cores @@ -62,10 +65,13 @@ jobs: go-version-file: go.mod cache: true - run: | + go_packages="$(find ./pkg -type f -name '*_test.go' -exec grep -l '^func TestIntegration' '{}' '+' | grep -o '\(.*\)/' | sort -u)" + IFS=' ' read -ra packages <<< "$go_packages" + 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 + mariadb -h 127.0.0.1 -P 3306 -u root -prootpass --disable-ssl-verify-server-cert < devenv/docker/blocks/mysql_tests/setup.sql 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) + go test -tags=mysql -p=1 -timeout=5m -run '^TestIntegration' "${packages[@]}" postgres: name: Postgres runs-on: ubuntu-latest-8-cores @@ -95,7 +101,10 @@ jobs: PGPASSWORD: grafanatest POSTGRES_HOST: 127.0.0.1 run: | + go_packages="$(find ./pkg -type f -name '*_test.go' -exec grep -l '^func TestIntegration' '{}' '+' | grep -o '\(.*\)/' | sort -u)" + IFS=' ' read -ra packages <<< "$go_packages" + 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) + go test -p=1 -tags=postgres -timeout=5m -run '^TestIntegration' "${packages[@]}" diff --git a/.github/workflows/release-comms.yml b/.github/workflows/release-comms.yml index 4a5bedfe2e1..72acfd03b7e 100644 --- a/.github/workflows/release-comms.yml +++ b/.github/workflows/release-comms.yml @@ -44,19 +44,23 @@ jobs: steps: - if: ${{ github.event.pull_request.merged == true && startsWith(github.head_ref, 'release/') }} run: | - 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 + { + echo "VERSION=$(echo "${HEAD_REF}" | sed -e 's/release\/.*\//v/g')" + echo "DRY_RUN=${{ contains(github.event.pull_request.labels.*.name, 'release/dry-run') }}" + echo "LATEST=${{ contains(github.event.pull_request.labels.*.name, 'release/latest') && '1' || '0' }}" + } >> "$GITHUB_ENV" - id: output run: | echo "dry_run: $DRY_RUN" echo "latest: $LATEST" echo "version: $VERSION" - echo "release_branch=$(echo $VERSION | sed -s 's/^v/release-/g')" >> "$GITHUB_OUTPUT" - echo "dry_run=$DRY_RUN" >> "$GITHUB_OUTPUT" - echo "latest=$LATEST" >> "$GITHUB_OUTPUT" - echo "version=$VERSION" >> "$GITHUB_OUTPUT" + { + echo "release_branch=$(echo "$VERSION" | sed -s 's/^v/release-/g')" + echo "dry_run=$DRY_RUN" + echo "latest=$LATEST" + echo "version=$VERSION" + } >> "$GITHUB_OUTPUT" create_next_release_branch_grafana: name: Create next release branch (Grafana) needs: setup @@ -113,5 +117,5 @@ jobs: VERSION: ${{ needs.setup.outputs.version }} steps: - run: | - echo announce on slack that $VERSION has been released - echo dry run: $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 997adc59523..60cf41c771d 100644 --- a/.github/workflows/release-pr.yml +++ b/.github/workflows/release-pr.yml @@ -166,7 +166,7 @@ jobs: git commit -m "Update version to $VERSION" - name: Git push - if: ${{ inputs.dry_run }} != true + if: inputs.dry_run != true run: git push --set-upstream origin "release/${{ github.run_id }}/$VERSION" - name: Create PR without backports @@ -177,10 +177,10 @@ jobs: run: | LATEST_FLAG="" if [ "$LATEST" = "true" ]; then - LATEST_FLAG='-l "release/latest"' + LATEST_FLAG=(-l "release/latest") fi gh pr create \ - $LATEST_FLAG \ + "${LATEST_FLAG[@]}" \ -l "no-changelog" \ --dry-run="$DRY_RUN" \ -B "$BRANCH" \ @@ -195,10 +195,10 @@ jobs: run: | LATEST_FLAG="" if [ "$LATEST" = "true" ]; then - LATEST_FLAG='-l "release/latest"' + LATEST_FLAG=(-l "release/latest") fi gh pr create \ - $LATEST_FLAG \ + "${LATEST_FLAG[@]}" \ -l "product-approved" \ -l "no-changelog" \ --dry-run="$DRY_RUN" \ diff --git a/.github/workflows/run-dashboard-search-e2e.yml b/.github/workflows/run-dashboard-search-e2e.yml index fd62c1d8c42..ca1d6d4f940 100644 --- a/.github/workflows/run-dashboard-search-e2e.yml +++ b/.github/workflows/run-dashboard-search-e2e.yml @@ -40,7 +40,7 @@ jobs: cache: 'yarn' - name: Cache Node Modules id: cache-node-modules - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: | node_modules @@ -56,7 +56,7 @@ jobs: runTests: false - name: Cache Grafana Build and Dependencies id: cache-grafana - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: | bin/ @@ -74,9 +74,11 @@ jobs: - name: Get list of .ini files id: get_files + env: + WORKSPACE: ${{ github.workspace }} 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 + INI_FILES="$(find "$WORKSPACE"/e2e/dashboards-search-suite/ -type f -name '*.ini' | jq -R -s -c 'split("\n")[:-1]')" + echo "ini_files=$INI_FILES" >> "$GITHUB_OUTPUT" shell: bash run_tests: @@ -98,7 +100,7 @@ jobs: with: persist-credentials: false - name: Restore Cached Node Modules - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: | node_modules @@ -106,7 +108,7 @@ jobs: key: ${{ runner.os }}-node-${{ hashFiles('package-lock.json') }} - name: Restore Cached Grafana Build and Dependencies - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: | bin/ @@ -122,11 +124,12 @@ jobs: env: INI_NAME: ${{ matrix.ini_file }} run: | - FILE_NAME=$(basename "$env.INI_NAME" .ini) - echo "FILE_NAME=$FILE_NAME" >> $GITHUB_OUTPUT + FILE_NAME="$(basename "$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 }} + WORKSPACE: ${{ github.workspace }} run: | - cp -rf $INI_NAME ${{ github.workspace }}/scripts/grafana-server/custom.ini + cp -rf "$INI_NAME" "$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 index ae0cb4cfd3a..0aa6d292abc 100644 --- a/.github/workflows/run-e2e-suite.yml +++ b/.github/workflows/run-e2e-suite.yml @@ -26,13 +26,13 @@ jobs: args: go run ./pkg/build/e2e --package=grafana.tar.gz --suite=${{ inputs.suite }} - name: Set suite name id: set-suite-name - if: always() + if: success() || failure() env: SUITE: ${{ inputs.suite }} run: | - echo "suite=$(echo $SUITE | sed 's/\//-/g')" >> $GITHUB_OUTPUT + echo "suite=$(echo "$SUITE" | sed 's/\//-/g')" >> "$GITHUB_OUTPUT" - uses: actions/upload-artifact@v4 - if: always() + if: success() || failure() with: name: e2e-${{ steps.set-suite-name.outputs.suite }}-${{github.run_number}} path: videos diff --git a/.github/workflows/skye-add-to-project.yml b/.github/workflows/skye-add-to-project.yml index 7aee160cbcb..f0384e2eb2f 100644 --- a/.github/workflows/skye-add-to-project.yml +++ b/.github/workflows/skye-add-to-project.yml @@ -60,11 +60,11 @@ jobs: # 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 + echo "user_allowed=true" >> "$GITHUB_OUTPUT" exit 0 fi done - echo "user_allowed=false" >> $GITHUB_OUTPUT + 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 diff --git a/LICENSING.md b/LICENSING.md index 5239154d161..cfd239e7230 100644 --- a/LICENSING.md +++ b/LICENSING.md @@ -30,3 +30,13 @@ The following directories and their subdirectories are licensed under their orig ``` public/vendor/ ``` + +## MIT license + +The following files are licensed under MIT License: + +``` +.github/workflows/actionlint-format.txt + -> Vendored: https://github.com/rhysd/actionlint/blob/2ab3a12c7848f6c15faca9a92612ef4261d0e370/testdata/format/sarif_template.txt + -> The workflow that uses it is AGPL-3.0-only. +```