* CI: move grafana-build into pkg/build (#105640) * move grafana-build into pkg/build * Update go.mod/go.sum files after cherry-pick build - Updates from workspace sync after cherry-picking daggerbuild package - Resolves dependency conflicts from pkg/build integration - Required for successful build after CI migration backport * CI Migration: Replace .github with main branch version - Complete replacement of .github directory from main branch - Includes updated workflows, actions, and configuration files - Ensures all CI improvements from main are included - Next step: fix branch-specific issues in separate commits * Fix branch triggers: Update workflows to target release branches - Update 8 workflows to trigger on release-* instead of main - Ensures workflows run on pull requests to release branches - Workflows updated: documentation-ci, pr-codeql-analysis-*, pr-dependabot-update-go-workspace, pr-go-workspace-check, pr-k8s-codegen-check, verify-kinds, codeowners-validator * Fix branch triggers: Update workflows to target both main and release branches - CORRECTED: Include both main and release-* branch patterns - Ensures workflows run on both main branch (original functionality) and release branches (needed for backport) - Previous commit incorrectly removed main branch support - Workflows updated: documentation-ci, pr-codeql-analysis-*, pr-dependabot-update-go-workspace, pr-go-workspace-check, pr-k8s-codegen-check, verify-kinds, codeowners-validator * CI Migration: Update .gitignore to allow OSS wire file to be committed - Remove **/wire_gen.go (allow pkg/server/wire_gen.go to be committed) - Add /pkg/server/enterprise_wire_gen.go (keep enterprise wire file ignored) - This enables the new committed wire files architecture for CI * CI Migration: Add enhanced wire tool with automatic build constraints - Backport enhanced wire tool from main branch with -gen_tags flag - This enables automatic regeneration with proper constraints to prevent conflicts - Wire file contains all required functions: Initialize, InitializeDocumentBuilders, etc. - Solves the missing wire functions issue causing CI failures - Enhanced tool ensures build constraints persist on regeneration * CI Migration: Update Makefile to use enhanced wire tool with build constraints - Update gen-go target to use -gen_tags flag for automatic build constraints - Ensures future engineers get proper build constraints when running 'make gen-go' - Matches main branch approach for consistent wire file generation - Removes dependency on WIRE_TAGS variable and GO_RACE_FLAG for simplicity * Add gen-enterprise-go target to Makefile for release-12.0.3 - Backports gen-enterprise-go target from main branch - Enables enterprise wire file generation in release branches - Part of CI migration backport wire infrastructure fixes - Resolves CI issues where enterprise wire functions were missing * Fix wire tool golden file format for Drone CI compatibility - Update all 43 golden test files to match main branch format - Change go:generate command from github.com/google/wire/cmd/wire to ./pkg/build/wire/cmd/wire/main.go - Remove legacy '// +build !wireinject' constraints - Fixes Drone CI test failures that were blocking OSS PR merge - All wire tests now pass successfully This aligns the backport branch with the golden file format updates that were made in main branch when the wire tool was enhanced. * Update swagger specs to include enterprise APIs - Regenerated api-enterprise-spec.json with enterprise API definitions - Updated api-merged.json with merged OSS and enterprise specs - Regenerated openapi3.json with complete API specifications - Fixes enterprise CI swagger generation validation failures - Enterprise APIs now properly detected and documented * Fix OSS integration tests missing enterprise build tags in Drone CI - Add -tags=enterprise to all integration test steps in lib.star - Fixes test-backend-integration, postgres-integration-tests, and mysql-integration-tests - Regenerate .drone.yml with proper enterprise build tags - Resolves 'server could not find the requested resource' errors for enterprise APIs - Ensures enterprise APIs (querylibrary, reporting, banners, scim) are registered during tests - Aligns OSS Drone CI with GitHub Actions behavior and enterprise repository * Fix CODEOWNERS for release-12.0.3 compatibility - Remove 21 entries that reference files/directories not present in release branch - Resolves File Exist Checker failures in codeowners-validator workflow - Maintains team ownership assignments from main branch for existing files - Lines removed: .air.toml, apps/secret/, apps/iam/, e2e-playwright/, packages/grafana-alerting/, etc. * baldm0mma/ update releasefinder * Add i18n-extract script for release branch compatibility - Add 'i18n-extract': 'make i18n-extract' to package.json scripts - Resolves i18n-verify workflow failure that expects this script - The make target already exists and handles OSS + enterprise i18n extraction - Maintains i18n verification functionality from main branch workflows - Simple safe addition that calls existing make infrastructure * Phase 4: Fix GitHub Actions workflow branch triggers - Add release-*.*.* pattern to 8 workflows missing it - Fix duplicate release branch patterns in 3 workflows - Ensure consistent branch trigger format across all workflows - Critical workflows now properly trigger on release branches Fixes workflows: actionlint, backend-code-checks, go-lint, reject-gh-secrets, run-schema-v2-e2e, shellcheck, swagger-gen, trivy-scan * Fix: Backport E2E runner infrastructure for Enterprise CI - Add e2e/main.go and e2e/internal/ directory from main branch - Add urfave/cli/v3 dependency required by E2E runner - Fixes Enterprise CI failure: 'Build E2E test runner' and 'Build & package Grafana for e2e tests' - Root cause: E2E runner infrastructure was added to main after release-12.0.3 branch creation - Solution: Backport missing E2E runner files to enable Enterprise CI completion Resolves: no Go files in /opt/actions-runner/_work/grafana-enterprise/grafana-enterprise/grafana/e2e * Fix: Update go.mod dependency classification for urfave/cli/v3 - Change urfave/cli/v3 from indirect to direct dependency - Fixes Go Workspace Check failure in CI - Required after adding E2E runner infrastructure that directly imports urfave/cli/v3 - Resolves: make update-workspace corrects dependency classification * Fix: Add team ownership for urfave/cli/v3 dependency - Assign @grafana/grafana-backend-group as owner for github.com/urfave/cli/v3@v3.3.8 - Follows existing pattern: urfave/cli v1 and v2 also owned by grafana-backend-group - Resolves Backend Code Checks / Validate Backend Configs CI failure - Required for E2E runner infrastructure dependency ownership compliance Fixes: modowners check requiring team assignment for newly added dependencies * Fix: Revert experimental E2E playwright infrastructure to stable version - Revert pr-e2e-tests.yml to stable Cypress-based E2E testing - Remove experimental storybook-verification-playwright.yml workflow - Revert run-dashboard-search-e2e.yml and release-pr.yml to use e2e/test-plugins/ - Keep stable E2E runner infrastructure (e2e/main.go + e2e/internal/) - Remove experimental playwright features per team recommendation Team feedback: Playwright tests are experimental and shouldn't be backported to stable release branches * Fix: Complete cleanup of experimental playwright dependencies - Revert package.json to stable version (remove e2e-playwright scripts and path references) - Revert playwright.config.ts to stable plugin-e2e configuration - Remove all experimental playwright infrastructure dependencies - Ensure clean stable E2E testing environment All experimental features removed per team recommendation for stable release branches * Fix: Restore working package.json configuration - Revert package.json to version 12.0.3 (working release branch version) - Fix workspace dependency resolution issues caused by incorrect revert to main branch version - FE tests, betterer, and linting should now work correctly Issue was caused by reverting package.json to main branch (12.1.0-pre) instead of keeping the working release branch configuration (12.0.3) * CI: mirror some CI dependencies (#106148) * mirror some CI dependencies * remove -v from go build * Fix: Backport missing e2e/run-suite script for daggerbuild E2E system The daggerbuild E2E system (used by OSS workflows) expects ./e2e/run-suite to exist, but we only backported the new E2E runner infrastructure. This script is needed for: - OSS workflow: 'go run ./pkg/build/e2e --suite=dashboards-suite' - Legacy Cypress configuration with video support - Integration between daggerbuild and existing Cypress test suites Resolves E2E test failures in OSS workflows where videos directory cannot be found because run-suite script was missing. * Fix: Resolve daggerbuild E2E path doubling issue - Extract just suite name from full path using filepath.Base() - Prevents doubled paths like './e2e/e2e/dashboards-suite/videos' - Resolves 'no spec files found' and 'no such file or directory' errors - GitHub Actions passes full paths like 'e2e/dashboards-suite' but run-suite script expects just 'dashboards-suite' * Infrastructure: Wholesale copy pkg/build/ from main COMPLETE DAGGERBUILD SYSTEM UPDATE: - Modern E2E system with CLI framework and --flags support - New accessibility testing system (a11y/) - New Playwright E2E testing system (e2e-playwright/) - External infrastructure improvements (musl.cc → dl.grafana.com/ci) - Updated daggerbuild core components with latest fixes - Updated Go dependencies and wire modules ARCHITECTURAL COMPATIBILITY VERIFIED: - Modern pkg/build calls: ./e2e-runner cypress --start-grafana=false --cypress-video - Our e2e runner supports: All required parameters including --suite, --env flags - GitHub Actions workflows: Pass compatible arguments - Binary builds: Successfully creates working e2e-runner RESOLVES ISSUES: - Fixes --flags parameter compatibility with GitHub Actions - Includes all follow-up infrastructure improvements - Provides complete, tested system with modern CLI framework - Eliminates external dependency failures (musl.cc timeouts) - Removes need for path doubling workarounds (modern system handles full paths correctly) Replaces incremental cherry-picking with complete, tested system from main. * Dependencies: Update Go modules after pkg/build wholesale copy DEPENDENCY UPDATES: - Updated go.work.sum with new dependencies from modern pkg/build system - Updated all workspace module dependencies (go.mod/go.sum files) - Removed pkg/build/cmd/enterprise.go (enterprise-only file, gets copied during enterprise development) ENTERPRISE INTEGRATION FIX: - enterprise.go file doesn't belong in OSS repository - Gets copied from grafana-enterprise during development mode - Main branch doesn't have this file, explaining module compatibility All Go modules now properly resolved and compatible with modern pkg/build architecture. * Dependencies: Update workspace Go module checksums after pkg/build wholesale copy - Synchronizes all go.sum files across workspace modules - Adds missing .mod.h1 entries that were required after infrastructure update - Resolves Go Workspace Check CI failures - Updates 22 modules: .citools/, apps/, pkg/ subdirectories plus go.work.sum Addresses CI error: 'Please run make update-workspace and commit the changes' * Infrastructure: Revert to pre-Playwright E2E system for release branch compatibility Strategic combination of modern daggerbuild with stable E2E infrastructure: **Modern Daggerbuild (from main):** - Latest CLI framework (github.com/urfave/cli/v3) - External infrastructure fixes (musl.cc → dl.grafana.com/ci) - Complete pkg/build/ system with all enhancements - Updated dependencies and architecture improvements **Stable E2E Infrastructure (pre-Playwright):** - pkg/build/e2e/service.go: Reverted to version before commitb6580ccb10- pkg/build/a11y/: Reverted to stable version compatible with existing infrastructure - Removed experimental pkg/build/e2e-playwright/ system - Removed experimental e2e-playwright/ test infrastructure **Why This Approach:** - GitHub Actions workflows call 'go run ./pkg/build/e2e' (modern system) - Modern system now expects only standard e2e/ directory (compatible) - Release branches have standard e2e/ infrastructure (dashboards-suite, various-suite, etc.) - Eliminates dependency on experimental Playwright infrastructure **Key Dependencies Met:** - e2e/pa11yci.conf.js: Added for a11y test compatibility - /src/e2e directory: Standard directory structure (no e2e-playwright needed) - Existing test plugins: Uses stable e2e/test-plugins/ **Result:** Best of both worlds - modern, reliable daggerbuild infrastructure with proven E2E testing that works across all release branches without requiring experimental dependencies. * Fix: Remove unused embed.go file causing golangci-lint failure - Removes pkg/build/daggerbuild/msi/embed.go with unused embed.FS variable - MSI build process uses directory mounting instead of embedded filesystem - Resolves 'var resources is unused (unused)' linting error * Fix: Update Node.js version to match working E2E configuration - Changes from v22.11.0 to v22.16.0 to match commit17952d45e4- Working commit had all E2E tests passing with same daggerbuild infrastructure - Node.js version differences can affect frontend builds and UI rendering - Ensures consistent environment between working reference and current branch * Fix: Use conditional container base for E2E compatibility - Alpine for OSS tests (better old arch dashboardScene=false compatibility) - Ubuntu for Enterprise tests (when image renderer needed) - Restores original release-12.0.3 Alpine behavior for OSS - Should resolve old arch E2E test failures * Fix: Go fmt formatting for conditional container logic * Revert: Remove unnecessary Alpine/Ubuntu conditional logic - Real issue was wrong environment variable name (dashboardScene vs DISABLE_SCENES) - Keep Ubuntu base (original main branch behavior) for simplicity - Container base was not the root cause of old arch failures * Experiment: Copy scripts/ from pre-Playwright commit (ea0ddb3fc9) - Copied scripts directory from commitea0ddb3fc9(just before Playwright migration) - This overwrites some CI migration fixes but testing if it's actually needed - Can revert back tob9b4602dbdif CI breaks Test commit to see real impact on GitHub Actions workflows. * trigger ci 01 * Fix: Copy .drone.star from main to match scripts structure - Resolves Starlark evaluation error for missing integration_test_pipelines - Aligns .drone.star with main branch scripts structure - Same fix applied to both OSS and Enterprise repositories * make drone * Fix ARM/v7 Docker build failures by using dagger run for cross-compilation - Change artifacts_cmd() in scripts/drone/steps/rgm.star to use 'dagger run go run' instead of 'go run' - Add --max-execution-steps 100000 to make drone target in Makefile to properly regenerate .drone.yml - This fixes CGO cross-compilation issues with SQLite for ARM/v7 Docker builds - Matches the approach already used successfully in Enterprise builds * Fix Docker base image references in rgm build steps - Change from symbolic names (alpine-base, ubuntu-base) to actual Docker images - alpine-base → alpine:3.21.3 - ubuntu-base → ubuntu:22.04 - Add ubuntu and alpine parameters to rgm_artifacts_step and rgm_build_docker_step functions - Fixes Docker pull errors: 'repository does not exist or may require authorization' - Aligns OSS configuration with Enterprise approach --------- Co-authored-by: Kevin Minehart <5140827+kminehart@users.noreply.github.com>
1190 lines
38 KiB
Plaintext
1190 lines
38 KiB
Plaintext
"""
|
|
This module is a library of Drone steps and other pipeline components.
|
|
"""
|
|
|
|
load(
|
|
"scripts/drone/steps/github.star",
|
|
"github_app_generate_token_step",
|
|
"github_app_step_volumes",
|
|
)
|
|
load(
|
|
"scripts/drone/steps/rgm.star",
|
|
"rgm_build_backend_step",
|
|
)
|
|
load(
|
|
"scripts/drone/utils/images.star",
|
|
"images",
|
|
)
|
|
load(
|
|
"scripts/drone/variables.star",
|
|
"grabpl_version",
|
|
)
|
|
load(
|
|
"scripts/drone/vault.star",
|
|
"from_secret",
|
|
"gcp_grafanauploads",
|
|
"gcp_grafanauploads_base64",
|
|
"gcp_upload_artifacts_key",
|
|
"npm_token",
|
|
"prerelease_bucket",
|
|
)
|
|
|
|
trigger_oss = {
|
|
"repo": [
|
|
"grafana/grafana",
|
|
],
|
|
}
|
|
|
|
def yarn_install_step():
|
|
return {
|
|
"name": "yarn-install",
|
|
"image": images["node"],
|
|
"commands": [
|
|
"yarn install --immutable || yarn install --immutable",
|
|
],
|
|
"depends_on": [],
|
|
}
|
|
|
|
def wire_install_step():
|
|
return {
|
|
"name": "wire-install",
|
|
"image": images["go"],
|
|
"commands": [
|
|
"apk add --update make",
|
|
"make gen-go",
|
|
],
|
|
"depends_on": [
|
|
"verify-gen-cue",
|
|
],
|
|
}
|
|
|
|
def identify_runner_step():
|
|
return {
|
|
"name": "identify-runner",
|
|
"image": images["alpine"],
|
|
"commands": [
|
|
"echo $DRONE_RUNNER_NAME",
|
|
],
|
|
}
|
|
|
|
def enterprise_setup_step(source = "${DRONE_SOURCE_BRANCH}", canFail = True, isPromote = False):
|
|
"""Setup the enterprise source into the ./grafana-enterprise directory.
|
|
|
|
Args:
|
|
source: controls which revision of grafana-enterprise is checked out, if it exists. The name 'source' derives from the 'source branch' of a pull request.
|
|
canFail: controls whether the step can fail. This is useful for pull requests where the enterprise source may not exist.
|
|
isPromote: controls whether or not this step is being used in a promote pipeline. If it is, then the clone enterprise step will not check if the pull request is a fork.
|
|
Returns:
|
|
Drone step.
|
|
"""
|
|
step = clone_enterprise_step_pr(source = source, target = "${DRONE_TARGET_BRANCH}", canFail = canFail, location = "../grafana-enterprise", isPromote = isPromote)
|
|
step["commands"] += [
|
|
"cd ../",
|
|
"ln -s src grafana",
|
|
"cd ./grafana-enterprise",
|
|
"./build.sh",
|
|
]
|
|
|
|
return step
|
|
|
|
def clone_enterprise_step_pr(source = "${DRONE_COMMIT}", target = "main", canFail = False, location = "grafana-enterprise", isPromote = False):
|
|
"""Clone the enterprise source into the ./grafana-enterprise directory.
|
|
|
|
Args:
|
|
source: controls which revision of grafana-enterprise is checked out, if it exists. The name 'source' derives from the 'source branch' of a pull request.
|
|
target: controls which revision of grafana-enterprise is checked out, if it 'source' does not exist. The name 'target' derives from the 'target branch' of a pull request. If this does not exist, then 'main' will be checked out.
|
|
canFail: controls whether or not this step is allowed to fail. If it fails and this is true, then the pipeline will continue. canFail is used in pull request pipelines where enterprise may be cloned but may not clone in forks.
|
|
location: the path where grafana-enterprise is cloned.
|
|
isPromote: controls whether or not this step is being used in a promote pipeline. If it is, then the step will not check if the pull request is a fork.
|
|
Returns:
|
|
Drone step.
|
|
"""
|
|
|
|
if isPromote:
|
|
check = []
|
|
else:
|
|
check = [
|
|
'is_fork=$(curl --retry 5 "https://$${GITHUB_TOKEN}@api.github.com/repos/grafana/grafana/pulls/$DRONE_PULL_REQUEST" | jq .head.repo.fork)',
|
|
'if [ "$is_fork" != false ]; then return 1; fi', # Only clone if we're confident that 'fork' is 'false'. Fail if it's also empty.
|
|
]
|
|
|
|
step = {
|
|
"name": "clone-enterprise",
|
|
"image": images["git"],
|
|
"commands": [
|
|
"apk add --update curl jq bash",
|
|
"GITHUB_TOKEN=$(cat /github-app/token)",
|
|
] + check + [
|
|
'git clone "https://x-access-token:$${GITHUB_TOKEN}@github.com/grafana/grafana-enterprise.git" ' + location,
|
|
"cd {}".format(location),
|
|
'if git checkout {0}; then echo "checked out {0}"; elif git checkout {1}; then echo "git checkout {1}"; else git checkout main; fi'.format(source, target),
|
|
],
|
|
"depends_on": [
|
|
github_app_generate_token_step()["name"],
|
|
],
|
|
"volumes": github_app_step_volumes(),
|
|
}
|
|
|
|
if canFail:
|
|
step["failure"] = "ignore"
|
|
|
|
return step
|
|
|
|
def download_grabpl_step():
|
|
return {
|
|
"name": "grabpl",
|
|
"image": images["curl"],
|
|
"commands": [
|
|
"mkdir -p bin",
|
|
"curl -fL -o bin/grabpl https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/{}/grabpl".format(
|
|
grabpl_version,
|
|
),
|
|
"chmod +x bin/grabpl",
|
|
],
|
|
}
|
|
|
|
def lint_drone_step():
|
|
return {
|
|
"name": "lint-drone",
|
|
"image": images["curl"],
|
|
"commands": [
|
|
"./bin/build verify-drone",
|
|
],
|
|
"depends_on": [
|
|
"compile-build-cmd",
|
|
],
|
|
}
|
|
|
|
def lint_starlark_step():
|
|
return {
|
|
"name": "lint-starlark",
|
|
"image": images["go"],
|
|
"commands": [
|
|
"go install github.com/bazelbuild/buildtools/buildifier@latest",
|
|
"buildifier --lint=warn -mode=check -r .",
|
|
],
|
|
"depends_on": [],
|
|
}
|
|
|
|
def enterprise_downstream_step(ver_mode):
|
|
"""Triggers a downstream pipeline in the grafana-enterprise repository.
|
|
|
|
Args:
|
|
ver_mode: indirectly controls the revision used for downstream pipelines.
|
|
It also used to allow the step to fail for pull requests without blocking merging.
|
|
|
|
Returns:
|
|
Drone step.
|
|
"""
|
|
repo = "grafana/grafana-enterprise@"
|
|
if ver_mode == "pr" or ver_mode == "rrc":
|
|
repo += "${DRONE_SOURCE_BRANCH}"
|
|
else:
|
|
repo += "main"
|
|
|
|
step = {
|
|
"name": "trigger-enterprise-downstream",
|
|
"image": images["drone_downstream"],
|
|
"settings": {
|
|
"server": "https://drone.grafana.net",
|
|
"token": from_secret("drone_token"),
|
|
"repositories": [
|
|
repo,
|
|
],
|
|
"params": [
|
|
"SOURCE_BUILD_NUMBER=${DRONE_COMMIT}",
|
|
"SOURCE_COMMIT=${DRONE_COMMIT}",
|
|
],
|
|
},
|
|
}
|
|
|
|
if ver_mode == "pr":
|
|
step.update({"failure": "ignore"})
|
|
step["settings"]["params"].append("OSS_PULL_REQUEST=${DRONE_PULL_REQUEST}")
|
|
|
|
if ver_mode == "rrc":
|
|
step["settings"]["params"].append("SOURCE_TAG=${DRONE_TAG}")
|
|
|
|
return step
|
|
|
|
def validate_modfile_step():
|
|
return {
|
|
"name": "validate-modfile",
|
|
"image": images["go"],
|
|
"commands": [
|
|
"go run scripts/modowners/modowners.go check go.mod",
|
|
],
|
|
}
|
|
|
|
def validate_openapi_spec_step():
|
|
return {
|
|
"name": "validate-openapi-spec",
|
|
"image": images["go"],
|
|
"commands": [
|
|
"apk add --update make",
|
|
"make swagger-validate",
|
|
],
|
|
}
|
|
|
|
def dockerize_step(name, hostname, port, canFail = False):
|
|
step = {
|
|
"name": name,
|
|
"image": images["dockerize"],
|
|
"commands": [
|
|
"dockerize -wait tcp://{}:{} -timeout 120s".format(hostname, port),
|
|
],
|
|
}
|
|
|
|
if canFail:
|
|
step["failure"] = "ignore"
|
|
|
|
return step
|
|
|
|
def build_storybook_step(ver_mode):
|
|
return {
|
|
"name": "build-storybook",
|
|
"image": images["node"],
|
|
"depends_on": [
|
|
# Best to ensure that this step doesn't mess with what's getting built and packaged
|
|
"rgm-package",
|
|
"build-frontend-packages",
|
|
],
|
|
"environment": {
|
|
"NODE_OPTIONS": "--max_old_space_size=4096",
|
|
},
|
|
"commands": [
|
|
"yarn storybook:build",
|
|
"./bin/build verify-storybook",
|
|
],
|
|
"when": get_trigger_storybook(ver_mode),
|
|
}
|
|
|
|
def store_storybook_step(ver_mode, trigger = None):
|
|
"""Publishes the Grafana UI components storybook.
|
|
|
|
Args:
|
|
ver_mode: controls whether a release or canary version is published.
|
|
trigger: a Drone trigger for the step.
|
|
Defaults to None.
|
|
|
|
Returns:
|
|
Drone step.
|
|
"""
|
|
commands = []
|
|
if ver_mode == "release":
|
|
commands.extend(
|
|
[
|
|
"./bin/build store-storybook --deployment latest",
|
|
"./bin/build store-storybook --deployment ${DRONE_TAG}",
|
|
],
|
|
)
|
|
|
|
else:
|
|
# main pipelines should deploy storybook to grafana-storybook/canary public bucket
|
|
commands = [
|
|
"./bin/build store-storybook --deployment canary",
|
|
]
|
|
|
|
step = {
|
|
"name": "store-storybook",
|
|
"image": images["publish"],
|
|
"depends_on": [
|
|
"build-storybook",
|
|
] +
|
|
end_to_end_tests_deps(),
|
|
"environment": {
|
|
"GCP_KEY": from_secret(gcp_grafanauploads),
|
|
"PRERELEASE_BUCKET": from_secret(prerelease_bucket),
|
|
},
|
|
"commands": commands,
|
|
"when": get_trigger_storybook(ver_mode),
|
|
}
|
|
if trigger and ver_mode in ("release-branch", "main"):
|
|
# no dict merge operation available, https://github.com/harness/drone-cli/pull/220
|
|
when_cond = {
|
|
"repo": [
|
|
"grafana/grafana",
|
|
],
|
|
"paths": {
|
|
"include": [
|
|
"packages/grafana-ui/**",
|
|
],
|
|
},
|
|
}
|
|
step = dict(step, when = when_cond)
|
|
return step
|
|
|
|
def e2e_tests_artifacts():
|
|
# Note: This function is kept for backward compatibility but now only handles
|
|
# artifacts from the remaining E2E tests that haven't been migrated to GitHub Actions
|
|
return {
|
|
"name": "e2e-tests-artifacts-upload",
|
|
"image": images["cloudsdk"],
|
|
"depends_on": [
|
|
# Note: Main E2E tests have been migrated to GitHub Actions
|
|
# Only depend on remaining Drone E2E tests
|
|
"end-to-end-tests-cloud-plugins-suite-azure",
|
|
"playwright-plugin-e2e",
|
|
github_app_generate_token_step()["name"],
|
|
],
|
|
"failure": "ignore",
|
|
"when": {
|
|
"status": [
|
|
"success",
|
|
"failure",
|
|
],
|
|
},
|
|
"environment": {
|
|
"GCP_GRAFANA_UPLOAD_ARTIFACTS_KEY": from_secret(gcp_upload_artifacts_key),
|
|
"E2E_TEST_ARTIFACTS_BUCKET": "releng-pipeline-artifacts-dev",
|
|
},
|
|
"commands": [
|
|
"export GITHUB_TOKEN=$(cat /github-app/token)",
|
|
# if no videos found do nothing (may be fewer videos now that main tests are in GitHub Actions)
|
|
"if [ -z `find ./e2e -type f -name *spec.ts.mp4` ]; then echo 'no e2e videos found from remaining tests'; exit 0; fi",
|
|
"apt-get update",
|
|
"apt-get install -yq zip",
|
|
"printenv GCP_GRAFANA_UPLOAD_ARTIFACTS_KEY > /tmp/gcpkey_upload_artifacts.json",
|
|
"gcloud auth activate-service-account --key-file=/tmp/gcpkey_upload_artifacts.json",
|
|
# we want to only include files in e2e folder that end with .spec.ts.mp4
|
|
'find ./e2e -type f -name "*spec.ts.mp4" | zip e2e/videos.zip -@',
|
|
"gsutil cp e2e/videos.zip gs://$${E2E_TEST_ARTIFACTS_BUCKET}/${DRONE_BUILD_NUMBER}/artifacts/videos/videos.zip",
|
|
"export E2E_ARTIFACTS_VIDEO_ZIP=https://storage.googleapis.com/$${E2E_TEST_ARTIFACTS_BUCKET}/${DRONE_BUILD_NUMBER}/artifacts/videos/videos.zip",
|
|
'echo "E2E Test artifacts uploaded to: $${E2E_ARTIFACTS_VIDEO_ZIP}"',
|
|
'curl -X POST https://api.github.com/repos/${DRONE_REPO}/statuses/${DRONE_COMMIT_SHA} -H "Authorization: token $${GITHUB_TOKEN}" -d ' +
|
|
'"{\\"state\\":\\"success\\",\\"target_url\\":\\"$${E2E_ARTIFACTS_VIDEO_ZIP}\\", \\"description\\": \\"Click on the details to download e2e recording videos\\", \\"context\\": \\"e2e_artifacts\\"}"',
|
|
],
|
|
"volumes": github_app_step_volumes(),
|
|
}
|
|
|
|
def playwright_e2e_report_upload():
|
|
return {
|
|
"name": "playwright-e2e-report-upload",
|
|
"image": images["cloudsdk"],
|
|
"depends_on": [
|
|
"playwright-plugin-e2e",
|
|
],
|
|
"failure": "ignore",
|
|
"when": {
|
|
"status": [
|
|
"success",
|
|
"failure",
|
|
],
|
|
},
|
|
"environment": {
|
|
"GCP_GRAFANA_UPLOAD_ARTIFACTS_KEY": from_secret(gcp_upload_artifacts_key),
|
|
},
|
|
"commands": [
|
|
"apt-get update",
|
|
"apt-get install -yq zip",
|
|
"printenv GCP_GRAFANA_UPLOAD_ARTIFACTS_KEY > /tmp/gcpkey_upload_artifacts.json",
|
|
"gcloud auth activate-service-account --key-file=/tmp/gcpkey_upload_artifacts.json",
|
|
"gsutil cp -r ./playwright-report/. gs://releng-pipeline-artifacts-dev/${DRONE_BUILD_NUMBER}/playwright-report",
|
|
"export E2E_PLAYWRIGHT_REPORT_URL=https://storage.googleapis.com/releng-pipeline-artifacts-dev/${DRONE_BUILD_NUMBER}/playwright-report/index.html",
|
|
'echo "E2E Playwright report uploaded to: \n $${E2E_PLAYWRIGHT_REPORT_URL}"',
|
|
],
|
|
}
|
|
|
|
def playwright_e2e_report_post_link():
|
|
return {
|
|
"name": "playwright-e2e-report-post-link",
|
|
"image": images["curl"],
|
|
"depends_on": [
|
|
"playwright-e2e-report-upload",
|
|
github_app_generate_token_step()["name"],
|
|
],
|
|
"failure": "ignore",
|
|
"when": {
|
|
"status": [
|
|
"success",
|
|
"failure",
|
|
],
|
|
},
|
|
"commands": [
|
|
"GITHUB_TOKEN=$(cat /github-app/token)",
|
|
# if the trace doesn't folder exists, it means that there are no failed tests.
|
|
"if [ ! -d ./playwright-report/trace ]; then echo 'all tests passed'; exit 0; fi",
|
|
# if it exists, we will post a comment on the PR with the link to the report
|
|
"export E2E_PLAYWRIGHT_REPORT_URL=https://storage.googleapis.com/releng-pipeline-artifacts-dev/${DRONE_BUILD_NUMBER}/playwright-report/index.html",
|
|
"curl -L " +
|
|
"-X POST https://api.github.com/repos/grafana/grafana/issues/${DRONE_PULL_REQUEST}/comments " +
|
|
'-H "Accept: application/vnd.github+json" ' +
|
|
'-H "Authorization: Bearer $${GITHUB_TOKEN}" ' +
|
|
'-H "X-GitHub-Api-Version: 2022-11-28" -d ' +
|
|
'"{\\"body\\":\\"❌ Failed to run Playwright plugin e2e tests. <br /> <br /> Click [here]($${E2E_PLAYWRIGHT_REPORT_URL}) to browse the Playwright report and trace viewer. <br /> For information on how to run Playwright tests locally, refer to the [Developer guide](https://github.com/grafana/grafana/blob/main/contribute/developer-guide.md#to-run-the-playwright-tests). \\"}"',
|
|
],
|
|
"volumes": github_app_step_volumes(),
|
|
}
|
|
|
|
def upload_cdn_step(ver_mode, trigger = None, depends_on = ["grafana-server"]):
|
|
"""Uploads CDN assets using the Grafana build tool.
|
|
|
|
Args:
|
|
ver_mode: only uses the step trigger when ver_mode == 'release-branch' or 'main'
|
|
trigger: a Drone trigger for the step.
|
|
Defaults to None.
|
|
depends_on: drone steps that this step depends on
|
|
|
|
Returns:
|
|
Drone step.
|
|
"""
|
|
|
|
step = {
|
|
"name": "upload-cdn-assets",
|
|
"image": images["publish"],
|
|
"depends_on": depends_on,
|
|
"environment": {
|
|
"GCP_KEY": from_secret(gcp_grafanauploads),
|
|
"PRERELEASE_BUCKET": from_secret(prerelease_bucket),
|
|
},
|
|
"commands": [
|
|
"./bin/build upload-cdn --edition oss",
|
|
],
|
|
}
|
|
if trigger and ver_mode in ("release-branch", "main"):
|
|
step = dict(step, when = trigger)
|
|
return step
|
|
|
|
def build_backend_step(distros = "linux/amd64,linux/arm64"):
|
|
"""Build the backend code using the Grafana build tool.
|
|
|
|
Args:
|
|
distros: a list of distributes to be built. For a full list, see `go tool dist list`.
|
|
|
|
Returns:
|
|
Drone step.
|
|
"""
|
|
|
|
return rgm_build_backend_step(distros)
|
|
|
|
def build_frontend_step():
|
|
"""Build the frontend code to ensure it's compilable
|
|
|
|
Returns:
|
|
Drone step.
|
|
"""
|
|
return {
|
|
"name": "build-frontend",
|
|
"image": images["node"],
|
|
"environment": {
|
|
"NODE_OPTIONS": "--max_old_space_size=8192",
|
|
},
|
|
"depends_on": [
|
|
"compile-build-cmd",
|
|
"yarn-install",
|
|
],
|
|
"commands": [
|
|
"yarn build",
|
|
],
|
|
}
|
|
|
|
def build_test_plugins_step():
|
|
"""Build the test plugins used in e2e tests
|
|
|
|
Returns:
|
|
Drone step.
|
|
"""
|
|
return {
|
|
"name": "build-test-plugins",
|
|
"image": images["node"],
|
|
"environment": {
|
|
"NODE_OPTIONS": "--max_old_space_size=8192",
|
|
},
|
|
"depends_on": [
|
|
"yarn-install",
|
|
],
|
|
"commands": [
|
|
"yarn e2e:plugin:build",
|
|
],
|
|
}
|
|
|
|
def update_package_json_version():
|
|
"""Updates the packages/ to use a version that has the build ID in it: 10.0.0pre -> 10.0.0-5432pre
|
|
|
|
Returns:
|
|
Drone step that updates the 'version' key in package.json
|
|
"""
|
|
|
|
return {
|
|
"name": "update-package-json-version",
|
|
"image": images["node"],
|
|
"depends_on": [
|
|
"yarn-install",
|
|
],
|
|
"commands": [
|
|
"apk add --update jq",
|
|
"new_version=$(cat package.json | jq -r .version | sed s/pre/${DRONE_BUILD_NUMBER}/g)",
|
|
"echo \"New version: $new_version\"",
|
|
"yarn run lerna version $new_version --exact --no-git-tag-version --no-push --force-publish -y",
|
|
"yarn install --mode=update-lockfile",
|
|
],
|
|
}
|
|
|
|
def build_frontend_package_step(depends_on = []):
|
|
"""Build the frontend packages using the Grafana build tool.
|
|
|
|
Args:
|
|
depends_on: a list of step names (strings) that must complete before this step runs.
|
|
|
|
Returns:
|
|
Drone step.
|
|
"""
|
|
|
|
cmds = [
|
|
"apk add --update jq bash", # bash is needed for the validate-npm-packages.sh script since it has a 'bash'
|
|
# shebang.
|
|
"yarn packages:build",
|
|
"yarn packages:pack",
|
|
"./scripts/validate-npm-packages.sh",
|
|
]
|
|
|
|
return {
|
|
"name": "build-frontend-packages",
|
|
"image": images["node"],
|
|
"environment": {
|
|
"NODE_OPTIONS": "--max_old_space_size=8192",
|
|
},
|
|
"depends_on": [
|
|
"yarn-install",
|
|
] + depends_on,
|
|
"commands": cmds,
|
|
}
|
|
|
|
def build_plugins_step(ver_mode):
|
|
if ver_mode != "pr":
|
|
env = {
|
|
"GRAFANA_API_KEY": from_secret("grafana_api_key"),
|
|
}
|
|
else:
|
|
env = None
|
|
return {
|
|
"name": "build-plugins",
|
|
"image": images["node"],
|
|
"environment": env,
|
|
"depends_on": [
|
|
"yarn-install",
|
|
],
|
|
"commands": [
|
|
"apk add --update findutils", # Replaces the busybox 'find' with the GNU one.
|
|
"yarn plugins:build",
|
|
],
|
|
}
|
|
|
|
def betterer_frontend_step():
|
|
"""Run betterer on frontend code.
|
|
|
|
Returns:
|
|
Drone step.
|
|
"""
|
|
|
|
return {
|
|
"name": "betterer-frontend",
|
|
"image": images["node"],
|
|
"depends_on": [
|
|
"yarn-install",
|
|
],
|
|
"commands": [
|
|
"apk add --update git bash",
|
|
"yarn betterer:ci",
|
|
],
|
|
}
|
|
|
|
def verify_i18n_step():
|
|
extract_error_message = "\nExtraction 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."
|
|
uncommited_error_message = "\nTranslation extraction has not been committed. Please run 'make i18n-extract', commit the changes and push again."
|
|
return {
|
|
"name": "verify-i18n",
|
|
"image": images["node_deb"],
|
|
"depends_on": [
|
|
"yarn-install",
|
|
],
|
|
"commands": [
|
|
"make i18n-extract || (echo \"{}\" && false)".format(extract_error_message),
|
|
# Verify that translation extraction has been committed
|
|
'''
|
|
file_diff=$(git diff --dirstat public/locales)
|
|
if [ -n "$file_diff" ]; then
|
|
echo $file_diff
|
|
echo "{}"
|
|
exit 1
|
|
fi
|
|
'''.format(uncommited_error_message),
|
|
],
|
|
}
|
|
|
|
def verify_api_clients_step():
|
|
uncommited_error_message = "\nAPI client generation has not been committed. Please run 'yarn generate-apis', commit the changes and push again."
|
|
return {
|
|
"name": "verify-api-clients",
|
|
"image": images["node_deb"],
|
|
"depends_on": [
|
|
"yarn-install",
|
|
],
|
|
"commands": [
|
|
"yarn generate-apis",
|
|
# Verify that client generation has been run and committed
|
|
'''
|
|
file_diff=$(git diff ':!conf')
|
|
if [ -n "$file_diff" ]; then
|
|
echo $file_diff
|
|
echo "{}"
|
|
exit 1
|
|
fi
|
|
'''.format(uncommited_error_message),
|
|
],
|
|
}
|
|
|
|
def test_a11y_frontend_step(ver_mode, port = 3001):
|
|
"""Runs automated accessiblity tests against the frontend.
|
|
|
|
Args:
|
|
ver_mode: controls whether the step is blocking or just reporting.
|
|
If ver_mode == 'pr', the step causes the pipeline to fail.
|
|
port: which port to grafana-server is expected to be listening on.
|
|
Defaults to 3001.
|
|
|
|
Returns:
|
|
Drone step.
|
|
"""
|
|
commands = [
|
|
# Note - this runs in a container running node 14, which does not support the -y option to npx
|
|
"npx wait-on@7.0.1 http://$HOST:$PORT",
|
|
"pa11y-ci --config e2e/pa11yci.conf.js",
|
|
]
|
|
failure = "ignore"
|
|
no_thresholds = "true"
|
|
if ver_mode == "pr":
|
|
failure = "always"
|
|
no_thresholds = "false"
|
|
|
|
return {
|
|
"name": "test-a11y-frontend",
|
|
# TODO which image should be used?
|
|
"image": images["docker_puppeteer"],
|
|
"depends_on": [
|
|
"grafana-server",
|
|
],
|
|
"environment": {
|
|
"GRAFANA_MISC_STATS_API_KEY": from_secret("grafana_misc_stats_api_key"),
|
|
"HOST": "grafana-server",
|
|
"PORT": port,
|
|
"NO_THRESHOLDS": no_thresholds,
|
|
},
|
|
"failure": failure,
|
|
"commands": commands,
|
|
}
|
|
|
|
def frontend_metrics_step(trigger = None):
|
|
"""Reports frontend metrics to Grafana Cloud.
|
|
|
|
Args:
|
|
trigger: a Drone trigger for the step.
|
|
Defaults to None.
|
|
|
|
Returns:
|
|
Drone step.
|
|
"""
|
|
|
|
step = {
|
|
"name": "publish-frontend-metrics",
|
|
"image": images["node"],
|
|
"depends_on": [
|
|
"test-a11y-frontend",
|
|
],
|
|
"environment": {
|
|
"GRAFANA_MISC_STATS_API_KEY": from_secret("grafana_misc_stats_api_key"),
|
|
},
|
|
"failure": "ignore",
|
|
"commands": [
|
|
"apk add --update bash grep git",
|
|
"./scripts/ci-frontend-metrics.sh ./grafana/public/build | ./bin/build publish-metrics $$GRAFANA_MISC_STATS_API_KEY",
|
|
],
|
|
}
|
|
if trigger:
|
|
step = dict(step, when = trigger)
|
|
return step
|
|
|
|
def grafana_server_step():
|
|
"""Runs the grafana-server binary as a service.
|
|
|
|
Returns:
|
|
Drone step.
|
|
"""
|
|
environment = {
|
|
"GF_SERVER_HTTP_PORT": "3001",
|
|
"GF_SERVER_ROUTER_LOGGING": "1",
|
|
"GF_APP_MODE": "development",
|
|
}
|
|
|
|
return {
|
|
"name": "grafana-server",
|
|
"image": images["alpine"],
|
|
"detach": True,
|
|
"depends_on": [
|
|
"rgm-package",
|
|
],
|
|
"environment": environment,
|
|
"commands": [
|
|
"apk add --update tar bash",
|
|
"mkdir grafana",
|
|
"tar --strip-components=1 -xvf ./dist/*amd64.tar.gz -C grafana",
|
|
"cp -r devenv scripts tools grafana && cd grafana && ./scripts/grafana-server/start-server",
|
|
],
|
|
}
|
|
|
|
def e2e_tests_step(suite, port = 3001, tries = None):
|
|
cmd = "./bin/build e2e-tests --port {} --suite {}".format(port, suite)
|
|
if tries:
|
|
cmd += " --tries {}".format(tries)
|
|
return {
|
|
"name": "end-to-end-tests-{}".format(suite),
|
|
"image": images["cypress"],
|
|
"depends_on": [
|
|
"grafana-server",
|
|
"build-test-plugins",
|
|
],
|
|
"environment": {
|
|
"HOST": "grafana-server",
|
|
},
|
|
"commands": [
|
|
cmd,
|
|
],
|
|
}
|
|
|
|
def start_storybook_step():
|
|
return {
|
|
"name": "start-storybook",
|
|
"image": images["node"],
|
|
"depends_on": [
|
|
"yarn-install",
|
|
],
|
|
"commands": [
|
|
"yarn storybook --quiet",
|
|
],
|
|
"detach": True,
|
|
}
|
|
|
|
def cloud_plugins_e2e_tests_step(suite, cloud, trigger = None):
|
|
"""Run cloud plugins end-to-end tests.
|
|
|
|
Args:
|
|
suite: affects the pipeline name.
|
|
TODO: check if this actually affects step behavior.
|
|
cloud: used to determine cloud provider specific tests.
|
|
trigger: a Drone trigger for the step.
|
|
Defaults to None.
|
|
|
|
Returns:
|
|
Drone step.
|
|
"""
|
|
environment = {}
|
|
when = {}
|
|
if trigger:
|
|
when = trigger
|
|
if cloud == "azure":
|
|
environment = {
|
|
"CYPRESS_CI": "true",
|
|
"HOST": "grafana-server",
|
|
"AZURE_SP_APP_ID": from_secret("azure_sp_app_id"),
|
|
"AZURE_SP_PASSWORD": from_secret("azure_sp_app_pw"),
|
|
"AZURE_TENANT": from_secret("azure_tenant"),
|
|
}
|
|
when = dict(
|
|
when,
|
|
paths = {
|
|
"include": [
|
|
"pkg/tsdb/azuremonitor/**",
|
|
"public/app/plugins/datasource/azuremonitor/**",
|
|
"e2e/cloud-plugins-suite/azure-monitor.spec.ts",
|
|
],
|
|
},
|
|
)
|
|
branch = "${DRONE_SOURCE_BRANCH}".replace("/", "-")
|
|
step = {
|
|
"name": "end-to-end-tests-{}-{}".format(suite, cloud),
|
|
"image": "us-docker.pkg.dev/grafanalabs-dev/docker-oss-plugin-partnerships-dev/e2e-14.3.2:1.0.0",
|
|
"depends_on": [
|
|
"grafana-server",
|
|
github_app_generate_token_step()["name"],
|
|
],
|
|
"environment": environment,
|
|
"commands": [
|
|
"GITHUB_TOKEN=$(cat /github-app/token)",
|
|
"cd /",
|
|
"./cpp-e2e/scripts/ci-run.sh {} {}".format(cloud, branch),
|
|
],
|
|
"volumes": github_app_step_volumes(),
|
|
}
|
|
step = dict(step, when = when)
|
|
return step
|
|
|
|
def playwright_e2e_tests_step():
|
|
return {
|
|
"environment": {
|
|
"PORT": "3001",
|
|
"HOST": "grafana-server",
|
|
"PROV_DIR": "/grafana/scripts/grafana-server/tmp/conf/provisioning",
|
|
},
|
|
"name": "playwright-plugin-e2e",
|
|
"image": images["node_deb"],
|
|
"depends_on": [
|
|
"grafana-server",
|
|
"build-test-plugins",
|
|
],
|
|
"commands": [
|
|
"npx wait-on@7.0.1 http://$HOST:$PORT",
|
|
"yarn playwright install --with-deps chromium",
|
|
"yarn e2e:playwright",
|
|
],
|
|
}
|
|
|
|
def build_docs_website_step():
|
|
return {
|
|
"name": "build-docs-website",
|
|
# Use latest revision here, since we want to catch if it breaks
|
|
"image": images["docs"],
|
|
"pull": "always",
|
|
"commands": [
|
|
"mkdir -p /hugo/content/docs/grafana/latest",
|
|
"echo -e '---\\nredirectURL: /docs/grafana/latest/\\ntype: redirect\\nversioned: true\\n---\\n' > /hugo/content/docs/grafana/_index.md",
|
|
"cp -r docs/sources/* /hugo/content/docs/grafana/latest/",
|
|
"cd /hugo && make prod",
|
|
],
|
|
}
|
|
|
|
def fetch_images_step():
|
|
return {
|
|
"name": "fetch-images",
|
|
"image": images["cloudsdk"],
|
|
"environment": {
|
|
"GCP_KEY": from_secret(gcp_grafanauploads),
|
|
"DOCKER_USER": from_secret("docker_username"),
|
|
"DOCKER_PASSWORD": from_secret("docker_password"),
|
|
},
|
|
"commands": ["./bin/build artifacts docker fetch --edition oss"],
|
|
"depends_on": ["compile-build-cmd"],
|
|
"volumes": [{"name": "docker", "path": "/var/run/docker.sock"}],
|
|
}
|
|
|
|
def publish_images_step(ver_mode, docker_repo, trigger = None, depends_on = ["rgm-build-docker"]):
|
|
"""Generates a step for publishing public Docker images with grabpl.
|
|
|
|
Args:
|
|
ver_mode: controls whether the image needs to be built or retrieved from a previous build.
|
|
If ver_mode == 'release', the previously built image is fetched instead of being built again.
|
|
docker_repo: the Docker image name.
|
|
It is combined with the 'grafana/' library prefix.
|
|
trigger: a Drone trigger for the pipeline.
|
|
Defaults to None.
|
|
depends_on: drone steps that this step depends on
|
|
|
|
Returns:
|
|
Drone step.
|
|
"""
|
|
name = docker_repo
|
|
docker_repo = "grafana/{}".format(docker_repo)
|
|
|
|
environment = {
|
|
"GCP_KEY": from_secret(gcp_grafanauploads),
|
|
"DOCKER_USER": from_secret("docker_username"),
|
|
"DOCKER_PASSWORD": from_secret("docker_password"),
|
|
"GITHUB_APP_ID": "329617",
|
|
"GITHUB_APP_INSTALLATION_ID": "37346161",
|
|
"GITHUB_APP_PRIVATE_KEY": from_secret("delivery-bot-app-private-key"),
|
|
}
|
|
|
|
cmd = "./bin/grabpl artifacts docker publish --dockerhub-repo {}".format(
|
|
docker_repo,
|
|
)
|
|
|
|
deps = depends_on
|
|
if ver_mode == "release":
|
|
deps = ["fetch-images"]
|
|
cmd += " --version-tag ${DRONE_TAG}"
|
|
|
|
if ver_mode == "pr":
|
|
environment = {
|
|
"DOCKER_USER": from_secret("docker_username"),
|
|
"DOCKER_PASSWORD": from_secret("docker_password"),
|
|
"GITHUB_APP_ID": "329617",
|
|
"GITHUB_APP_INSTALLATION_ID": "37346161",
|
|
"GITHUB_APP_PRIVATE_KEY": from_secret("delivery-bot-app-private-key"),
|
|
}
|
|
|
|
step = {
|
|
"name": "publish-images-{}".format(name),
|
|
"image": images["cloudsdk"],
|
|
"environment": environment,
|
|
"commands": [cmd],
|
|
"depends_on": deps,
|
|
"volumes": [{"name": "docker", "path": "/var/run/docker.sock"}],
|
|
}
|
|
if trigger and ver_mode in ("release-branch", "main"):
|
|
step = dict(step, when = trigger)
|
|
if ver_mode == "pr":
|
|
step = dict(step, failure = "ignore")
|
|
|
|
return step
|
|
|
|
def release_canary_npm_packages_step(trigger = None):
|
|
"""Releases canary NPM packages.
|
|
|
|
Args:
|
|
trigger: a Drone trigger for the step.
|
|
Defaults to None.
|
|
|
|
Returns:
|
|
Drone step.
|
|
"""
|
|
step = {
|
|
"name": "release-canary-npm-packages",
|
|
"image": images["node"],
|
|
"depends_on": end_to_end_tests_deps() + ["build-frontend-packages"],
|
|
"environment": {
|
|
"NPM_TOKEN": from_secret(npm_token),
|
|
},
|
|
"commands": [
|
|
"apk add --update bash git",
|
|
"./scripts/publish-npm-packages.sh --dist-tag 'canary' --registry 'https://registry.npmjs.org'",
|
|
],
|
|
}
|
|
|
|
if trigger:
|
|
step = dict(
|
|
step,
|
|
when = dict(
|
|
trigger,
|
|
paths = {
|
|
"include": [
|
|
"packages/**",
|
|
],
|
|
},
|
|
),
|
|
)
|
|
|
|
return step
|
|
|
|
def upload_packages_step(
|
|
ver_mode,
|
|
trigger = None,
|
|
depends_on = [
|
|
# Note: Main E2E tests have been migrated to GitHub Actions
|
|
# Updated dependencies to only include remaining Drone E2E tests
|
|
"end-to-end-tests-cloud-plugins-suite-azure",
|
|
"playwright-plugin-e2e",
|
|
]):
|
|
"""Upload packages to object storage.
|
|
|
|
Args:
|
|
ver_mode: when ver_mode == 'main', inhibit upload of enterprise
|
|
edition packages when executed.
|
|
trigger: a Drone trigger for the step.
|
|
Defaults to None.
|
|
depends_on: drone steps that this step depends on
|
|
|
|
Returns:
|
|
Drone step.
|
|
"""
|
|
step = {
|
|
"name": "upload-packages",
|
|
"image": images["publish"],
|
|
"depends_on": depends_on,
|
|
"environment": {
|
|
"GCP_KEY": from_secret(gcp_grafanauploads_base64),
|
|
"PRERELEASE_BUCKET": from_secret("prerelease_bucket"),
|
|
},
|
|
"commands": [
|
|
"./bin/build upload-packages --edition oss",
|
|
],
|
|
}
|
|
if trigger and ver_mode in ("release-branch", "main"):
|
|
step = dict(step, when = trigger)
|
|
return step
|
|
|
|
def publish_grafanacom_step(ver_mode, depends_on = ["publish-linux-packages-deb", "publish-linux-packages-rpm"]):
|
|
"""Publishes Grafana packages to grafana.com.
|
|
|
|
Args:
|
|
ver_mode: if ver_mode == 'main', pass the DRONE_BUILD_NUMBER environment
|
|
variable as the value for the --build-id option.
|
|
TODO: is this actually used by the grafanacom subcommand? I think it might
|
|
just use the environment variable directly.
|
|
depends_on: what other steps this one depends on (strings)
|
|
|
|
Returns:
|
|
Drone step.
|
|
"""
|
|
if ver_mode == "release":
|
|
cmd = "./bin/build publish grafana-com --edition oss ${DRONE_TAG}"
|
|
elif ver_mode == "main":
|
|
build_no = "${DRONE_BUILD_NUMBER}"
|
|
cmd = "./bin/build publish grafana-com --edition oss --build-id {}".format(
|
|
build_no,
|
|
)
|
|
else:
|
|
fail("Unexpected version mode {}".format(ver_mode))
|
|
|
|
return {
|
|
"name": "publish-grafanacom",
|
|
"image": images["publish"],
|
|
"depends_on": depends_on,
|
|
"environment": {
|
|
"GRAFANA_COM_API_KEY": from_secret("grafana_api_key"),
|
|
"GCP_KEY": from_secret(gcp_grafanauploads_base64),
|
|
},
|
|
"commands": [
|
|
cmd,
|
|
],
|
|
}
|
|
|
|
def verify_grafanacom_step(depends_on = ["publish-grafanacom"]):
|
|
return {
|
|
"name": "verify-grafanacom",
|
|
"image": images["node"],
|
|
"commands": [
|
|
# Download and install `curl` and `bash` - both of which aren't available inside of the `node:{version}-alpine` docker image.
|
|
"apk add curl bash",
|
|
|
|
# There may be a slight lag between when artifacts are uploaded to Google Storage,
|
|
# and when they become available on the website. This `for` loop sould account for that discrepancy.
|
|
# We attempt the verification up to 5 times. If successful, exit the loop with a success (0) status.
|
|
# If any attempt fails, but it's not the final attempt, wait 60 seconds before the next attempt.
|
|
# If the 5th (final) attempt fails, exit with error (1) status.
|
|
"""
|
|
for i in {1..5}; do
|
|
if ./scripts/drone/verify-grafanacom.sh; then
|
|
exit 0
|
|
elif [ $i -eq 5 ]; then
|
|
exit 1
|
|
else
|
|
sleep 60
|
|
fi
|
|
done
|
|
""",
|
|
],
|
|
"depends_on": depends_on,
|
|
}
|
|
|
|
def publish_linux_packages_step(package_manager = "deb"):
|
|
return {
|
|
"name": "publish-linux-packages-{}".format(package_manager),
|
|
# See https://github.com/grafana/deployment_tools/blob/master/docker/package-publish/README.md for docs on that image
|
|
"image": images["package_publish"],
|
|
"depends_on": ["compile-build-cmd"],
|
|
"privileged": True,
|
|
"settings": {
|
|
"access_key_id": from_secret("packages_access_key_id"),
|
|
"secret_access_key": from_secret("packages_secret_access_key"),
|
|
"service_account_json": from_secret("packages_service_account"),
|
|
"target_bucket": "grafana-packages",
|
|
"deb_distribution": "auto",
|
|
"gpg_passphrase": from_secret("packages_gpg_passphrase"),
|
|
"gpg_public_key": from_secret("packages_gpg_public_key"),
|
|
"gpg_private_key": from_secret("packages_gpg_private_key"),
|
|
"package_path": "gs://grafana-prerelease/artifacts/downloads/*${{DRONE_TAG}}/oss/**.{}".format(
|
|
package_manager,
|
|
),
|
|
},
|
|
}
|
|
|
|
# This retry will currently continue for 30 minutes until fail, unless successful.
|
|
def retry_command(command, attempts = 60, delay = 30):
|
|
return [
|
|
"for i in $(seq 1 %d); do" % attempts,
|
|
" if %s; then" % command,
|
|
' echo "Command succeeded on attempt $i"',
|
|
" break",
|
|
" else",
|
|
' echo "Attempt $i failed"',
|
|
" if [ $i -eq %d ]; then" % attempts,
|
|
" echo 'All attempts failed'",
|
|
" exit 1",
|
|
" fi",
|
|
' echo "Waiting %d seconds before next attempt..."' % delay,
|
|
" sleep %d" % delay,
|
|
" fi",
|
|
"done",
|
|
]
|
|
|
|
def verify_gen_cue_step():
|
|
return {
|
|
"name": "verify-gen-cue",
|
|
"image": images["go"],
|
|
"depends_on": [],
|
|
"commands": [
|
|
"# It is required that code generated from Thema/CUE be committed and in sync with its inputs.",
|
|
"# The following command will fail if running code generators produces any diff in output.",
|
|
"apk add --update make",
|
|
"CODEGEN_VERIFY=1 make gen-cue",
|
|
],
|
|
}
|
|
|
|
def verify_gen_jsonnet_step():
|
|
return {
|
|
"name": "verify-gen-jsonnet",
|
|
"image": images["go"],
|
|
"depends_on": [],
|
|
"commands": [
|
|
"# It is required that generated jsonnet is committed and in sync with its inputs.",
|
|
"# The following command will fail if running code generators produces any diff in output.",
|
|
"apk add --update make",
|
|
"CODEGEN_VERIFY=1 make gen-jsonnet",
|
|
],
|
|
}
|
|
|
|
def end_to_end_tests_deps():
|
|
# Note: Main E2E tests have been migrated to GitHub Actions
|
|
# Only return dependencies for E2E tests that still run in Drone
|
|
return [
|
|
"end-to-end-tests-cloud-plugins-suite-azure",
|
|
"playwright-plugin-e2e",
|
|
]
|
|
|
|
def compile_build_cmd():
|
|
dependencies = []
|
|
|
|
return {
|
|
"name": "compile-build-cmd",
|
|
"image": images["go"],
|
|
"commands": [
|
|
"go build -o ./bin/build -ldflags '-extldflags -static' ./pkg/build/cmd",
|
|
],
|
|
"depends_on": dependencies,
|
|
"environment": {
|
|
"CGO_ENABLED": 0,
|
|
},
|
|
}
|
|
|
|
def get_trigger_storybook(ver_mode):
|
|
"""Generate a Drone trigger for UI changes that affect the Grafana UI storybook.
|
|
|
|
Args:
|
|
ver_mode: affects whether the trigger is event tags or changed files.
|
|
|
|
Returns:
|
|
Drone trigger.
|
|
"""
|
|
trigger_storybook = ""
|
|
if ver_mode == "release":
|
|
trigger_storybook = {"event": ["tag"]}
|
|
else:
|
|
trigger_storybook = {
|
|
"paths": {
|
|
"include": [
|
|
"packages/grafana-ui/**",
|
|
],
|
|
},
|
|
}
|
|
return trigger_storybook
|
|
|
|
def slack_step(channel, template, secret):
|
|
return {
|
|
"name": "slack",
|
|
"image": images["plugins_slack"],
|
|
"settings": {
|
|
"webhook": from_secret(secret),
|
|
"channel": channel,
|
|
"template": template,
|
|
},
|
|
}
|