Compare commits
7 Commits
release-11
...
release-11
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f92418478f | ||
|
|
d502b5458b | ||
|
|
14508cb359 | ||
|
|
a21ddff270 | ||
|
|
b483d40882 | ||
|
|
8ab94e1553 | ||
|
|
086b47f098 |
426
.drone.yml
426
.drone.yml
File diff suppressed because it is too large
Load Diff
@@ -3,7 +3,7 @@
|
||||
ARG BASE_IMAGE=alpine:3.19.1
|
||||
ARG JS_IMAGE=node:20-alpine
|
||||
ARG JS_PLATFORM=linux/amd64
|
||||
ARG GO_IMAGE=golang:1.22.4-alpine
|
||||
ARG GO_IMAGE=golang:1.22.7-alpine
|
||||
|
||||
ARG GO_SRC=go-builder
|
||||
ARG JS_SRC=js-builder
|
||||
|
||||
2
Makefile
2
Makefile
@@ -8,7 +8,7 @@ WIRE_TAGS = "oss"
|
||||
include .bingo/Variables.mk
|
||||
|
||||
GO = go
|
||||
GO_VERSION = 1.22.4
|
||||
GO_VERSION = 1.22.7
|
||||
GO_LINT_FILES ?= $(shell ./scripts/go-workspace/golangci-lint-includes.sh)
|
||||
GO_TEST_FILES ?= $(shell ./scripts/go-workspace/test-includes.sh)
|
||||
SH_FILES ?= $(shell find ./scripts -name *.sh)
|
||||
|
||||
2
go.mod
2
go.mod
@@ -1,6 +1,6 @@
|
||||
module github.com/grafana/grafana
|
||||
|
||||
go 1.22.4
|
||||
go 1.22.7
|
||||
|
||||
// contains openapi encoder fixes. remove ASAP
|
||||
replace cuelang.org/go => github.com/grafana/cue v0.0.0-20230926092038-971951014e3f // @grafana/grafana-as-code
|
||||
|
||||
2
go.work
2
go.work
@@ -1,4 +1,4 @@
|
||||
go 1.22.4
|
||||
go 1.22.7
|
||||
|
||||
// The `skip:golangci-lint` comment tag is used to exclude the package from the `golangci-lint` GitHub Action.
|
||||
// The module at the root of the repo (`.`) is excluded because ./pkg/... is included manually in the `golangci-lint` configuration.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module github.com/grafana/grafana/pkg/apimachinery
|
||||
|
||||
go 1.22.4
|
||||
go 1.22.7
|
||||
|
||||
require (
|
||||
github.com/grafana/authlib v0.0.0-20240730122259-a0d13672efb1
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module github.com/grafana/grafana/pkg/apiserver
|
||||
|
||||
go 1.22.4
|
||||
go 1.22.7
|
||||
|
||||
require (
|
||||
github.com/google/go-cmp v0.6.0
|
||||
|
||||
@@ -11,6 +11,8 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -30,6 +32,12 @@ func logError(message string, err error) int {
|
||||
return 1
|
||||
}
|
||||
|
||||
func RunCmdCLI(c *cli.Context) error {
|
||||
os.Exit(RunCmd())
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RunCmd runs the build command and returns the exit code
|
||||
func RunCmd() int {
|
||||
opts := BuildOptsFromFlags()
|
||||
|
||||
@@ -2,20 +2,6 @@ package main
|
||||
|
||||
import "github.com/urfave/cli/v2"
|
||||
|
||||
// ArgCountWrapper will cause the action to fail if there were not exactly `num` args provided.
|
||||
func ArgCountWrapper(num int, action cli.ActionFunc) cli.ActionFunc {
|
||||
return func(ctx *cli.Context) error {
|
||||
if ctx.NArg() != num {
|
||||
if err := cli.ShowSubcommandHelp(ctx); err != nil {
|
||||
return cli.Exit(err.Error(), 1)
|
||||
}
|
||||
return cli.Exit("", 1)
|
||||
}
|
||||
|
||||
return action(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
// ArgCountWrapper will cause the action to fail if there were more than `num` args provided.
|
||||
func MaxArgCountWrapper(max int, action cli.ActionFunc) cli.ActionFunc {
|
||||
return func(ctx *cli.Context) error {
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
|
||||
"github.com/grafana/grafana/pkg/build/compilers"
|
||||
"github.com/grafana/grafana/pkg/build/config"
|
||||
"github.com/grafana/grafana/pkg/build/errutil"
|
||||
"github.com/grafana/grafana/pkg/build/grafana"
|
||||
"github.com/grafana/grafana/pkg/build/syncutil"
|
||||
)
|
||||
|
||||
func BuildBackend(ctx *cli.Context) error {
|
||||
metadata, err := config.GenerateMetadata(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
version := metadata.GrafanaVersion
|
||||
|
||||
var (
|
||||
edition = config.Edition(ctx.String("edition"))
|
||||
cfg = config.Config{
|
||||
NumWorkers: ctx.Int("jobs"),
|
||||
}
|
||||
)
|
||||
|
||||
buildConfig, err := config.GetBuildConfig(metadata.ReleaseMode.Mode)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not get version / package info for mode '%s': %w", metadata.ReleaseMode.Mode, err)
|
||||
}
|
||||
|
||||
const grafanaDir = "."
|
||||
|
||||
log.Printf("Building Grafana back-end, version %q, %s edition, variants [%v]",
|
||||
version, edition, buildConfig.Variants)
|
||||
|
||||
p := syncutil.NewWorkerPool(cfg.NumWorkers)
|
||||
defer p.Close()
|
||||
|
||||
if err := compilers.Install(); err != nil {
|
||||
return cli.Exit(err.Error(), 1)
|
||||
}
|
||||
|
||||
g, _ := errutil.GroupWithContext(ctx.Context)
|
||||
for _, variant := range buildConfig.Variants {
|
||||
variant := variant
|
||||
|
||||
opts := grafana.BuildVariantOpts{
|
||||
Variant: variant,
|
||||
Edition: edition,
|
||||
Version: version,
|
||||
GrafanaDir: grafanaDir,
|
||||
}
|
||||
|
||||
p.Schedule(g.Wrap(func() error {
|
||||
return grafana.BuildVariant(ctx.Context, opts)
|
||||
}))
|
||||
}
|
||||
if err := g.Wait(); err != nil {
|
||||
return cli.Exit(err.Error(), 1)
|
||||
}
|
||||
|
||||
log.Println("Successfully built back-end binaries!")
|
||||
return nil
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
|
||||
"github.com/grafana/grafana/pkg/build/config"
|
||||
"github.com/grafana/grafana/pkg/build/docker"
|
||||
"github.com/grafana/grafana/pkg/build/gcloud"
|
||||
)
|
||||
|
||||
func BuildDocker(c *cli.Context) error {
|
||||
if err := docker.Init(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
metadata, err := config.GenerateMetadata(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
useUbuntu := c.Bool("ubuntu")
|
||||
buildConfig, err := config.GetBuildConfig(metadata.ReleaseMode.Mode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
shouldSave := buildConfig.Docker.ShouldSave
|
||||
if shouldSave {
|
||||
if err := gcloud.ActivateServiceAccount(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
edition := config.Edition(c.String("edition"))
|
||||
|
||||
version := metadata.GrafanaVersion
|
||||
|
||||
log.Printf("Building Docker images, version %s, %s edition, Ubuntu based: %v...", version, edition,
|
||||
useUbuntu)
|
||||
|
||||
for _, arch := range buildConfig.Docker.Architectures {
|
||||
if _, err := docker.BuildImage(version, arch, ".", useUbuntu, shouldSave, edition, metadata.ReleaseMode.Mode); err != nil {
|
||||
return cli.Exit(err.Error(), 1)
|
||||
}
|
||||
}
|
||||
|
||||
log.Println("Successfully built Docker images!")
|
||||
return nil
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
|
||||
"github.com/grafana/grafana/pkg/build/config"
|
||||
"github.com/grafana/grafana/pkg/build/errutil"
|
||||
"github.com/grafana/grafana/pkg/build/frontend"
|
||||
"github.com/grafana/grafana/pkg/build/syncutil"
|
||||
)
|
||||
|
||||
func BuildFrontend(c *cli.Context) error {
|
||||
metadata, err := config.GenerateMetadata(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cfg, mode, err := frontend.GetConfig(c, metadata)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p := syncutil.NewWorkerPool(cfg.NumWorkers)
|
||||
defer p.Close()
|
||||
|
||||
g, _ := errutil.GroupWithContext(c.Context)
|
||||
if err := frontend.Build(mode, frontend.GrafanaDir, p, g); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := g.Wait(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Println("Successfully built Grafana front-end!")
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/grafana/grafana/pkg/build/config"
|
||||
"github.com/grafana/grafana/pkg/build/errutil"
|
||||
"github.com/grafana/grafana/pkg/build/frontend"
|
||||
"github.com/grafana/grafana/pkg/build/syncutil"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
func BuildFrontendPackages(c *cli.Context) error {
|
||||
metadata, err := config.GenerateMetadata(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cfg, mode, err := frontend.GetConfig(c, metadata)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p := syncutil.NewWorkerPool(cfg.NumWorkers)
|
||||
defer p.Close()
|
||||
|
||||
g, _ := errutil.GroupWithContext(c.Context)
|
||||
if err := frontend.BuildFrontendPackages(cfg.PackageVersion, mode, frontend.GrafanaDir, p, g); err != nil {
|
||||
return cli.Exit(err.Error(), 1)
|
||||
}
|
||||
if err := g.Wait(); err != nil {
|
||||
return cli.Exit(err.Error(), 1)
|
||||
}
|
||||
|
||||
log.Println("Successfully built Grafana front-end packages!")
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
|
||||
"github.com/grafana/grafana/pkg/build/config"
|
||||
"github.com/grafana/grafana/pkg/build/errutil"
|
||||
"github.com/grafana/grafana/pkg/build/plugins"
|
||||
"github.com/grafana/grafana/pkg/build/syncutil"
|
||||
)
|
||||
|
||||
func BuildInternalPlugins(c *cli.Context) error {
|
||||
cfg := config.Config{
|
||||
NumWorkers: c.Int("jobs"),
|
||||
}
|
||||
|
||||
const grafanaDir = "."
|
||||
metadata, err := config.GenerateMetadata(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
buildConfig, err := config.GetBuildConfig(metadata.ReleaseMode.Mode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Println("Building internal Grafana plug-ins...")
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
p := syncutil.NewWorkerPool(cfg.NumWorkers)
|
||||
defer p.Close()
|
||||
|
||||
var g *errutil.Group
|
||||
g, ctx = errutil.GroupWithContext(ctx)
|
||||
if err := plugins.Build(ctx, grafanaDir, p, g, buildConfig); err != nil {
|
||||
return cli.Exit(err.Error(), 1)
|
||||
}
|
||||
if err := g.Wait(); err != nil {
|
||||
return cli.Exit(err.Error(), 1)
|
||||
}
|
||||
|
||||
if err := plugins.Download(ctx, grafanaDir, p); err != nil {
|
||||
return cli.Exit(err.Error(), 1)
|
||||
}
|
||||
|
||||
log.Println("Successfully built Grafana plug-ins!")
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,133 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
|
||||
"github.com/grafana/grafana/pkg/build/env"
|
||||
"github.com/grafana/grafana/pkg/build/git"
|
||||
)
|
||||
|
||||
// checkOpts are options used to create a new GitHub check for the enterprise downstream test.
|
||||
type checkOpts struct {
|
||||
SHA string
|
||||
URL string
|
||||
Branch string
|
||||
PR int
|
||||
}
|
||||
|
||||
func getCheckOpts(args []string) (*checkOpts, error) {
|
||||
branch, ok := env.Lookup("DRONE_SOURCE_BRANCH", args)
|
||||
if !ok {
|
||||
return nil, cli.Exit("Unable to retrieve build source branch", 1)
|
||||
}
|
||||
|
||||
var (
|
||||
rgx = git.PRCheckRegexp()
|
||||
matches = rgx.FindStringSubmatch(branch)
|
||||
)
|
||||
|
||||
sha, ok := env.Lookup("SOURCE_COMMIT", args)
|
||||
if !ok {
|
||||
if matches == nil || len(matches) <= 1 {
|
||||
return nil, cli.Exit("Unable to retrieve source commit", 1)
|
||||
}
|
||||
sha = matches[2]
|
||||
}
|
||||
|
||||
url, ok := env.Lookup("DRONE_BUILD_LINK", args)
|
||||
if !ok {
|
||||
return nil, cli.Exit(`missing environment variable "DRONE_BUILD_LINK"`, 1)
|
||||
}
|
||||
|
||||
prStr, ok := env.Lookup("OSS_PULL_REQUEST", args)
|
||||
if !ok {
|
||||
if matches == nil || len(matches) <= 1 {
|
||||
return nil, cli.Exit("Unable to retrieve PR number", 1)
|
||||
}
|
||||
|
||||
prStr = matches[1]
|
||||
}
|
||||
|
||||
pr, err := strconv.Atoi(prStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &checkOpts{
|
||||
Branch: branch,
|
||||
PR: pr,
|
||||
SHA: sha,
|
||||
URL: url,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// EnterpriseCheckBegin creates the GitHub check and signals the beginning of the downstream build / test process
|
||||
func EnterpriseCheckBegin(c *cli.Context) error {
|
||||
var (
|
||||
ctx = c.Context
|
||||
client = git.NewGitHubClient(ctx, c.String("github-token"))
|
||||
)
|
||||
|
||||
opts, err := getCheckOpts(os.Environ())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err = git.CreateEnterpriseStatus(ctx, client.Repositories, opts.SHA, opts.URL, "pending"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func EnterpriseCheckSuccess(c *cli.Context) error {
|
||||
return completeEnterpriseCheck(c, true)
|
||||
}
|
||||
|
||||
func EnterpriseCheckFail(c *cli.Context) error {
|
||||
return completeEnterpriseCheck(c, false)
|
||||
}
|
||||
|
||||
func completeEnterpriseCheck(c *cli.Context, success bool) error {
|
||||
var (
|
||||
ctx = c.Context
|
||||
client = git.NewGitHubClient(ctx, c.String("github-token"))
|
||||
)
|
||||
|
||||
// Update the pull request labels
|
||||
opts, err := getCheckOpts(os.Environ())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
status := "failure"
|
||||
if success {
|
||||
status = "success"
|
||||
}
|
||||
|
||||
// Update the GitHub check...
|
||||
if _, err := git.CreateEnterpriseStatus(ctx, client.Repositories, opts.SHA, opts.URL, status); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Delete branch if needed
|
||||
log.Printf("Checking branch '%s' against '%s'", git.PRCheckRegexp().String(), opts.Branch)
|
||||
if git.PRCheckRegexp().MatchString(opts.Branch) {
|
||||
log.Println("Deleting branch", opts.Branch)
|
||||
if err := git.DeleteEnterpriseBranch(ctx, client.Git, opts.Branch); err != nil {
|
||||
return fmt.Errorf("error deleting enterprise branch: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
label := "enterprise-failed"
|
||||
if success {
|
||||
label = "enterprise-ok"
|
||||
}
|
||||
|
||||
return git.AddLabelToPR(ctx, client.Issues, opts.PR, label)
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestGetCheckOpts(t *testing.T) {
|
||||
t.Run("it should return the checkOpts if the correct environment variables are set", func(t *testing.T) {
|
||||
args := []string{
|
||||
"SOURCE_COMMIT=1234",
|
||||
"DRONE_SOURCE_BRANCH=test",
|
||||
"DRONE_BUILD_LINK=http://example.com",
|
||||
"OSS_PULL_REQUEST=1",
|
||||
}
|
||||
|
||||
opts, err := getCheckOpts(args)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, opts.SHA, "1234")
|
||||
require.Equal(t, opts.URL, "http://example.com")
|
||||
})
|
||||
t.Run("it should return an error if SOURCE_COMMIT is not set", func(t *testing.T) {
|
||||
args := []string{
|
||||
"DRONE_BUILD_LINK=http://example.com",
|
||||
"DRONE_SOURCE_BRANCH=test",
|
||||
"DRONE_BUILD_LINK=http://example.com",
|
||||
"OSS_PULL_REQUEST=1",
|
||||
}
|
||||
|
||||
opts, err := getCheckOpts(args)
|
||||
require.Nil(t, opts)
|
||||
require.Error(t, err)
|
||||
})
|
||||
t.Run("it should return an error if DRONE_BUILD_LINK is not set", func(t *testing.T) {
|
||||
args := []string{
|
||||
"SOURCE_COMMIT=1234",
|
||||
"DRONE_SOURCE_BRANCH=test",
|
||||
"OSS_PULL_REQUEST=1",
|
||||
}
|
||||
|
||||
opts, err := getCheckOpts(args)
|
||||
require.Nil(t, opts)
|
||||
require.Error(t, err)
|
||||
})
|
||||
t.Run("it should return an error if OSS_PULL_REQUEST is not set", func(t *testing.T) {
|
||||
args := []string{
|
||||
"SOURCE_COMMIT=1234",
|
||||
"DRONE_SOURCE_BRANCH=test",
|
||||
"DRONE_BUILD_LINK=http://example.com",
|
||||
}
|
||||
|
||||
opts, err := getCheckOpts(args)
|
||||
require.Nil(t, opts)
|
||||
require.Error(t, err)
|
||||
})
|
||||
t.Run("it should return an error if OSS_PULL_REQUEST is not an integer", func(t *testing.T) {
|
||||
args := []string{
|
||||
"SOURCE_COMMIT=1234",
|
||||
"DRONE_SOURCE_BRANCH=test",
|
||||
"DRONE_BUILD_LINK=http://example.com",
|
||||
"OSS_PULL_REQUEST=http://example.com",
|
||||
}
|
||||
|
||||
opts, err := getCheckOpts(args)
|
||||
require.Nil(t, opts)
|
||||
require.Error(t, err)
|
||||
})
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
|
||||
"github.com/grafana/grafana/pkg/build/config"
|
||||
)
|
||||
|
||||
func ExportVersion(c *cli.Context) error {
|
||||
metadata, err := config.GenerateMetadata(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
const distDir = "dist"
|
||||
if err := os.RemoveAll(distDir); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.Mkdir(distDir, 0750); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// nolint:gosec
|
||||
if err := os.WriteFile(filepath.Join(distDir, "grafana.version"), []byte(metadata.GrafanaVersion), 0664); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
|
||||
@@ -18,6 +18,25 @@ const (
|
||||
ubuntu = "ubuntu"
|
||||
)
|
||||
|
||||
// GetImageFiles returns the list of image (.img, but should be .tar because they are tar archives) files that are
|
||||
// created in the 'tag' process and stored in the prerelease bucket, waiting to be released.
|
||||
func GetImageFiles(grafana string, version string, architectures []config.Architecture) []string {
|
||||
bases := []string{alpine, ubuntu}
|
||||
images := []string{}
|
||||
for _, base := range bases {
|
||||
for _, arch := range architectures {
|
||||
image := fmt.Sprintf("%s-%s-%s.img", grafana, version, arch)
|
||||
if base == "ubuntu" {
|
||||
image = fmt.Sprintf("%s-%s-ubuntu-%s.img", grafana, version, arch)
|
||||
}
|
||||
|
||||
images = append(images, image)
|
||||
}
|
||||
}
|
||||
|
||||
return images
|
||||
}
|
||||
|
||||
func FetchImages(c *cli.Context) error {
|
||||
if c.NArg() > 0 {
|
||||
if err := cli.ShowSubcommandHelp(c); err != nil {
|
||||
@@ -44,74 +63,65 @@ func FetchImages(c *cli.Context) error {
|
||||
Tag: metadata.GrafanaVersion,
|
||||
}
|
||||
|
||||
edition := fmt.Sprintf("-%s", cfg.Edition)
|
||||
grafana := "grafana"
|
||||
if cfg.Edition == "enterprise" {
|
||||
grafana = "grafana-enterprise"
|
||||
}
|
||||
if cfg.Edition == "enterprise2" {
|
||||
grafana = "grafana-enterprise2"
|
||||
}
|
||||
if cfg.Edition == "grafana" || cfg.Edition == "oss" {
|
||||
grafana = "grafana-oss"
|
||||
}
|
||||
|
||||
err = gcloud.ActivateServiceAccount()
|
||||
if err != nil {
|
||||
baseURL := fmt.Sprintf("gs://%s/%s/", cfg.Bucket, cfg.Tag)
|
||||
images := GetImageFiles(grafana, cfg.Tag, cfg.Archs)
|
||||
|
||||
log.Printf("Fetching images [%v]", images)
|
||||
|
||||
if err := gcloud.ActivateServiceAccount(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var basesStr []string
|
||||
for _, base := range cfg.Distribution {
|
||||
switch base {
|
||||
case alpine:
|
||||
basesStr = append(basesStr, "")
|
||||
case ubuntu:
|
||||
basesStr = append(basesStr, "-ubuntu")
|
||||
default:
|
||||
return fmt.Errorf("unrecognized base %q", base)
|
||||
}
|
||||
}
|
||||
|
||||
err = downloadFromGCS(cfg, basesStr, edition)
|
||||
if err != nil {
|
||||
if err := DownloadImages(baseURL, images, "."); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = loadImages(cfg, basesStr, edition)
|
||||
if err != nil {
|
||||
if err := LoadImages(images, "."); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func loadImages(cfg docker.Config, basesStr []string, edition string) error {
|
||||
log.Println("Loading fetched image files to local docker registry...")
|
||||
log.Printf("Number of images to be loaded: %d\n", len(basesStr)*len(cfg.Archs))
|
||||
for _, base := range basesStr {
|
||||
for _, arch := range cfg.Archs {
|
||||
imageFilename := fmt.Sprintf("grafana%s-%s%s-%s.img", edition, cfg.Tag, base, arch)
|
||||
log.Printf("image file name: %s\n", imageFilename)
|
||||
//nolint:gosec
|
||||
cmd := exec.Command("docker", "load", "-i", imageFilename)
|
||||
cmd.Dir = "."
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
log.Printf("out: %s\n", out)
|
||||
return fmt.Errorf("error loading image: %q", err)
|
||||
}
|
||||
log.Printf("Successfully loaded %s!\n %s\n", fmt.Sprintf("grafana%s-%s%s-%s", edition, cfg.Tag, base, arch), out)
|
||||
// LoadImages uses the `docker load -i` command to load the image tar file into the docker daemon so that it can be
|
||||
// tagged and pushed.
|
||||
func LoadImages(images []string, source string) error {
|
||||
p := filepath.Clean(source)
|
||||
for _, image := range images {
|
||||
image := filepath.Join(p, image)
|
||||
log.Println("Loading image", image)
|
||||
//nolint:gosec
|
||||
cmd := exec.Command("docker", "load", "-i", image)
|
||||
cmd.Dir = "."
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
log.Printf("out: %s\n", out)
|
||||
return fmt.Errorf("error loading image: %q", err)
|
||||
}
|
||||
log.Println("Loaded image", image)
|
||||
}
|
||||
log.Println("Images successfully loaded!")
|
||||
return nil
|
||||
}
|
||||
|
||||
func downloadFromGCS(cfg docker.Config, basesStr []string, edition string) error {
|
||||
log.Printf("Downloading Docker images from GCS bucket: %s\n", cfg.Bucket)
|
||||
|
||||
for _, base := range basesStr {
|
||||
for _, arch := range cfg.Archs {
|
||||
src := fmt.Sprintf("gs://%s/%s/grafana%s-%s%s-%s.img", cfg.Bucket, cfg.Tag, edition, cfg.Tag, base, arch)
|
||||
args := strings.Split(fmt.Sprintf("-m cp -r %s .", src), " ")
|
||||
//nolint:gosec
|
||||
cmd := exec.Command("gsutil", args...)
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to download: %w\n%s", err, out)
|
||||
}
|
||||
func DownloadImages(baseURL string, images []string, destination string) error {
|
||||
for _, image := range images {
|
||||
p := baseURL + image
|
||||
log.Println("Downloading image", p)
|
||||
//nolint:gosec
|
||||
cmd := exec.Command("gsutil", "-m", "cp", "-r", p, destination)
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to download: %w\n%s", err, out)
|
||||
}
|
||||
}
|
||||
log.Printf("Successfully fetched image files from %s bucket!\n", cfg.Bucket)
|
||||
return nil
|
||||
}
|
||||
|
||||
48
pkg/build/cmd/fetchimages_test.go
Normal file
48
pkg/build/cmd/fetchimages_test.go
Normal file
@@ -0,0 +1,48 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/grafana/grafana/pkg/build/config"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestGetImageFiles(t *testing.T) {
|
||||
var (
|
||||
architectures = []config.Architecture{
|
||||
config.ArchAMD64,
|
||||
config.ArchARM64,
|
||||
config.ArchARMv7,
|
||||
}
|
||||
)
|
||||
|
||||
t.Run("1.2.3", func(t *testing.T) {
|
||||
expect := []string{
|
||||
"grafana-oss-1.2.3-amd64.img",
|
||||
"grafana-oss-1.2.3-arm64.img",
|
||||
"grafana-oss-1.2.3-armv7.img",
|
||||
"grafana-oss-1.2.3-ubuntu-amd64.img",
|
||||
"grafana-oss-1.2.3-ubuntu-arm64.img",
|
||||
"grafana-oss-1.2.3-ubuntu-armv7.img",
|
||||
}
|
||||
|
||||
res := GetImageFiles("grafana-oss", "1.2.3", architectures)
|
||||
|
||||
require.Equal(t, expect, res)
|
||||
})
|
||||
|
||||
t.Run("1.2.3+example-01", func(t *testing.T) {
|
||||
expect := []string{
|
||||
"grafana-oss-1.2.3+example-01-amd64.img",
|
||||
"grafana-oss-1.2.3+example-01-arm64.img",
|
||||
"grafana-oss-1.2.3+example-01-armv7.img",
|
||||
"grafana-oss-1.2.3+example-01-ubuntu-amd64.img",
|
||||
"grafana-oss-1.2.3+example-01-ubuntu-arm64.img",
|
||||
"grafana-oss-1.2.3+example-01-ubuntu-armv7.img",
|
||||
}
|
||||
|
||||
res := GetImageFiles("grafana-oss", "1.2.3+example-01", architectures)
|
||||
|
||||
require.Equal(t, expect, res)
|
||||
})
|
||||
}
|
||||
@@ -16,37 +16,15 @@ var (
|
||||
Usage: "The edition of Grafana to build (oss or enterprise)",
|
||||
Value: "oss",
|
||||
}
|
||||
variantsFlag = cli.StringFlag{
|
||||
Name: "variants",
|
||||
Usage: "Comma-separated list of variants to build",
|
||||
}
|
||||
triesFlag = cli.IntFlag{
|
||||
Name: "tries",
|
||||
Usage: "Specify number of tries before failing",
|
||||
Value: 1,
|
||||
}
|
||||
noInstallDepsFlag = cli.BoolFlag{
|
||||
Name: "no-install-deps",
|
||||
Usage: "Don't install dependencies",
|
||||
}
|
||||
signingAdminFlag = cli.BoolFlag{
|
||||
Name: "signing-admin",
|
||||
Usage: "Use manifest signing admin API endpoint?",
|
||||
}
|
||||
signFlag = cli.BoolFlag{
|
||||
Name: "sign",
|
||||
Usage: "Enable plug-in signing (you must set GRAFANA_API_KEY)",
|
||||
}
|
||||
dryRunFlag = cli.BoolFlag{
|
||||
Name: "dry-run",
|
||||
Usage: "Only simulate actions",
|
||||
}
|
||||
gitHubTokenFlag = cli.StringFlag{
|
||||
Name: "github-token",
|
||||
Value: "",
|
||||
EnvVars: []string{"GITHUB_TOKEN"},
|
||||
Usage: "GitHub token",
|
||||
}
|
||||
tagFlag = cli.StringFlag{
|
||||
Name: "tag",
|
||||
Usage: "Grafana version tag",
|
||||
|
||||
@@ -19,6 +19,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/build/config"
|
||||
"github.com/grafana/grafana/pkg/build/gcloud"
|
||||
"github.com/grafana/grafana/pkg/build/gcloud/storage"
|
||||
"github.com/grafana/grafana/pkg/build/gcom"
|
||||
"github.com/grafana/grafana/pkg/build/packaging"
|
||||
)
|
||||
|
||||
@@ -125,6 +126,48 @@ func getReleaseURLs() (string, string, error) {
|
||||
return pconf.Grafana.WhatsNewURL, pconf.Grafana.ReleaseNotesURL, nil
|
||||
}
|
||||
|
||||
func Builds(baseURL *url.URL, grafana, version string, packages []packaging.BuildArtifact) ([]GCOMPackage, error) {
|
||||
builds := make([]GCOMPackage, len(packages))
|
||||
for i, v := range packages {
|
||||
var (
|
||||
os = v.Distro
|
||||
arch = v.Arch
|
||||
)
|
||||
|
||||
if v.Distro == "windows" {
|
||||
os = "win"
|
||||
if v.Ext == "msi" {
|
||||
os = "win-installer"
|
||||
}
|
||||
}
|
||||
|
||||
if v.Distro == "rhel" {
|
||||
if arch == "aarch64" {
|
||||
arch = "arm64"
|
||||
}
|
||||
}
|
||||
|
||||
if v.Distro == "deb" {
|
||||
if arch == "armhf" {
|
||||
arch = "armv7"
|
||||
if v.RaspberryPi {
|
||||
log.Println(v.Distro, arch, "raspberrypi == true")
|
||||
arch = "armv6"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u := gcom.GetURL(baseURL, version, grafana, v.Distro, v.Arch, v.Ext, v.Musl, v.RaspberryPi)
|
||||
builds[i] = GCOMPackage{
|
||||
OS: os,
|
||||
URL: u.String(),
|
||||
Arch: arch,
|
||||
}
|
||||
}
|
||||
|
||||
return builds, nil
|
||||
}
|
||||
|
||||
// publishPackages publishes packages to grafana.com.
|
||||
func publishPackages(cfg packaging.PublishConfig) error {
|
||||
log.Printf("Publishing Grafana packages, version %s, %s edition, %s mode, dryRun: %v, simulating: %v...\n",
|
||||
@@ -133,14 +176,17 @@ func publishPackages(cfg packaging.PublishConfig) error {
|
||||
versionStr := fmt.Sprintf("v%s", cfg.Version)
|
||||
log.Printf("Creating release %s at grafana.com...\n", versionStr)
|
||||
|
||||
var sfx string
|
||||
var pth string
|
||||
var (
|
||||
pth string
|
||||
grafana = "grafana"
|
||||
)
|
||||
|
||||
switch cfg.Edition {
|
||||
case config.EditionOSS:
|
||||
pth = "oss"
|
||||
case config.EditionEnterprise:
|
||||
grafana = "grafana-enterprise"
|
||||
pth = "enterprise"
|
||||
sfx = packaging.EnterpriseSfx
|
||||
default:
|
||||
return fmt.Errorf("unrecognized edition %q", cfg.Edition)
|
||||
}
|
||||
@@ -152,28 +198,19 @@ func publishPackages(cfg packaging.PublishConfig) error {
|
||||
pth = path.Join(pth, packaging.ReleaseFolder)
|
||||
}
|
||||
|
||||
product := fmt.Sprintf("grafana%s", sfx)
|
||||
pth = path.Join(pth, product)
|
||||
baseArchiveURL := fmt.Sprintf("https://dl.grafana.com/%s", pth)
|
||||
|
||||
builds := make([]buildRepr, len(packaging.ArtifactConfigs))
|
||||
for i, ba := range packaging.ArtifactConfigs {
|
||||
u := ba.GetURL(baseArchiveURL, cfg)
|
||||
|
||||
sha256, err := getSHA256(u)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
builds[i] = buildRepr{
|
||||
OS: ba.Os,
|
||||
URL: u,
|
||||
SHA256: string(sha256),
|
||||
Arch: ba.Arch,
|
||||
}
|
||||
pth = path.Join(pth)
|
||||
baseArchiveURL := &url.URL{
|
||||
Scheme: "https",
|
||||
Host: "dl.grafana.com",
|
||||
Path: pth,
|
||||
}
|
||||
|
||||
r := releaseRepr{
|
||||
builds, err := Builds(baseArchiveURL, grafana, cfg.Version, packaging.ArtifactConfigs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
r := Release{
|
||||
Version: cfg.Version,
|
||||
ReleaseDate: time.Now().UTC(),
|
||||
Builds: builds,
|
||||
@@ -195,6 +232,15 @@ func publishPackages(cfg packaging.PublishConfig) error {
|
||||
return err
|
||||
}
|
||||
|
||||
for i, v := range r.Builds {
|
||||
sha, err := getSHA256(v.URL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
r.Builds[i].SHA256 = string(sha)
|
||||
}
|
||||
|
||||
for _, b := range r.Builds {
|
||||
if err := postRequest(cfg, fmt.Sprintf("versions/%s/packages", cfg.Version), b,
|
||||
fmt.Sprintf("create build %s %s", b.OS, b.Arch)); err != nil {
|
||||
@@ -211,6 +257,7 @@ func publishPackages(cfg packaging.PublishConfig) error {
|
||||
|
||||
func getSHA256(u string) ([]byte, error) {
|
||||
shaURL := fmt.Sprintf("%s.sha256", u)
|
||||
|
||||
// nolint:gosec
|
||||
resp, err := http.Get(shaURL)
|
||||
if err != nil {
|
||||
@@ -232,7 +279,7 @@ func getSHA256(u string) ([]byte, error) {
|
||||
return sha256, nil
|
||||
}
|
||||
|
||||
func postRequest(cfg packaging.PublishConfig, pth string, obj any, descr string) error {
|
||||
func postRequest(cfg packaging.PublishConfig, pth string, body any, descr string) error {
|
||||
var sfx string
|
||||
switch cfg.Edition {
|
||||
case config.EditionOSS:
|
||||
@@ -243,7 +290,7 @@ func postRequest(cfg packaging.PublishConfig, pth string, obj any, descr string)
|
||||
}
|
||||
product := fmt.Sprintf("grafana%s", sfx)
|
||||
|
||||
jsonB, err := json.Marshal(obj)
|
||||
jsonB, err := json.Marshal(body)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to JSON encode release: %w", err)
|
||||
}
|
||||
@@ -303,20 +350,20 @@ func constructURL(product string, pth string) (string, error) {
|
||||
return u.String(), err
|
||||
}
|
||||
|
||||
type buildRepr struct {
|
||||
type GCOMPackage struct {
|
||||
OS string `json:"os"`
|
||||
URL string `json:"url"`
|
||||
SHA256 string `json:"sha256"`
|
||||
Arch string `json:"arch"`
|
||||
}
|
||||
|
||||
type releaseRepr struct {
|
||||
Version string `json:"version"`
|
||||
ReleaseDate time.Time `json:"releaseDate"`
|
||||
Stable bool `json:"stable"`
|
||||
Beta bool `json:"beta"`
|
||||
Nightly bool `json:"nightly"`
|
||||
WhatsNewURL string `json:"whatsNewUrl"`
|
||||
ReleaseNotesURL string `json:"releaseNotesUrl"`
|
||||
Builds []buildRepr `json:"-"`
|
||||
type Release struct {
|
||||
Version string `json:"version"`
|
||||
ReleaseDate time.Time `json:"releaseDate"`
|
||||
Stable bool `json:"stable"`
|
||||
Beta bool `json:"beta"`
|
||||
Nightly bool `json:"nightly"`
|
||||
WhatsNewURL string `json:"whatsNewUrl"`
|
||||
ReleaseNotesURL string `json:"releaseNotesUrl"`
|
||||
Builds []GCOMPackage `json:"-"`
|
||||
}
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
"github.com/grafana/grafana/pkg/build/packaging"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func Test_constructURL(t *testing.T) {
|
||||
@@ -33,3 +40,221 @@ func Test_constructURL(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilds(t *testing.T) {
|
||||
baseURL := &url.URL{
|
||||
Scheme: "https",
|
||||
Host: "dl.example.com",
|
||||
Path: path.Join("oss", "release"),
|
||||
}
|
||||
|
||||
version := "1.2.3"
|
||||
grafana := "grafana"
|
||||
packages := []packaging.BuildArtifact{
|
||||
{
|
||||
Distro: "deb",
|
||||
Arch: "arm64",
|
||||
Ext: "deb",
|
||||
},
|
||||
{
|
||||
Distro: "rhel",
|
||||
Arch: "aarch64",
|
||||
Ext: "rpm",
|
||||
},
|
||||
{
|
||||
Distro: "linux",
|
||||
Arch: "arm64",
|
||||
Ext: "tar.gz",
|
||||
},
|
||||
{
|
||||
Distro: "deb",
|
||||
Arch: "armhf",
|
||||
Ext: "deb",
|
||||
RaspberryPi: true,
|
||||
},
|
||||
{
|
||||
Distro: "deb",
|
||||
Arch: "armhf",
|
||||
Ext: "deb",
|
||||
},
|
||||
{
|
||||
Distro: "linux",
|
||||
Arch: "armv7",
|
||||
Ext: "tar.gz",
|
||||
},
|
||||
{
|
||||
Distro: "windows",
|
||||
Arch: "amd64",
|
||||
Ext: "zip",
|
||||
},
|
||||
{
|
||||
Distro: "windows",
|
||||
Arch: "amd64",
|
||||
Ext: "msi",
|
||||
},
|
||||
}
|
||||
|
||||
expect := []GCOMPackage{
|
||||
{
|
||||
URL: "https://dl.example.com/oss/release/grafana_1.2.3_arm64.deb",
|
||||
OS: "deb",
|
||||
Arch: "arm64",
|
||||
},
|
||||
{
|
||||
URL: "https://dl.example.com/oss/release/grafana-1.2.3-1.aarch64.rpm",
|
||||
OS: "rhel",
|
||||
Arch: "arm64",
|
||||
},
|
||||
{
|
||||
URL: "https://dl.example.com/oss/release/grafana-1.2.3.linux-arm64.tar.gz",
|
||||
OS: "linux",
|
||||
Arch: "arm64",
|
||||
},
|
||||
{
|
||||
URL: "https://dl.example.com/oss/release/grafana-rpi_1.2.3_armhf.deb",
|
||||
OS: "deb",
|
||||
Arch: "armv6",
|
||||
},
|
||||
{
|
||||
URL: "https://dl.example.com/oss/release/grafana_1.2.3_armhf.deb",
|
||||
OS: "deb",
|
||||
Arch: "armv7",
|
||||
},
|
||||
{
|
||||
URL: "https://dl.example.com/oss/release/grafana-1.2.3.linux-armv7.tar.gz",
|
||||
OS: "linux",
|
||||
Arch: "armv7",
|
||||
},
|
||||
{
|
||||
URL: "https://dl.example.com/oss/release/grafana-1.2.3.windows-amd64.zip",
|
||||
OS: "win",
|
||||
Arch: "amd64",
|
||||
},
|
||||
{
|
||||
URL: "https://dl.example.com/oss/release/grafana-1.2.3.windows-amd64.msi",
|
||||
OS: "win-installer",
|
||||
Arch: "amd64",
|
||||
},
|
||||
}
|
||||
|
||||
builds, err := Builds(baseURL, grafana, version, packages)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, len(expect), len(builds))
|
||||
|
||||
for i := range builds {
|
||||
t.Run(fmt.Sprintf("[%d/%d] %s", i+1, len(builds), expect[i].URL), func(t *testing.T) {
|
||||
assert.Equal(t, expect[i].URL, builds[i].URL)
|
||||
assert.Equal(t, expect[i].OS, builds[i].OS)
|
||||
assert.Equal(t, expect[i].Arch, builds[i].Arch)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildsWithPlus(t *testing.T) {
|
||||
baseURL := &url.URL{
|
||||
Scheme: "https",
|
||||
Host: "dl.example.com",
|
||||
Path: path.Join("oss", "release"),
|
||||
}
|
||||
|
||||
version := "1.2.3+example-01"
|
||||
grafana := "grafana"
|
||||
packages := []packaging.BuildArtifact{
|
||||
{
|
||||
Distro: "deb",
|
||||
Arch: "arm64",
|
||||
Ext: "deb",
|
||||
},
|
||||
{
|
||||
Distro: "rhel",
|
||||
Arch: "aarch64",
|
||||
Ext: "rpm",
|
||||
},
|
||||
{
|
||||
Distro: "linux",
|
||||
Arch: "arm64",
|
||||
Ext: "tar.gz",
|
||||
},
|
||||
{
|
||||
Distro: "deb",
|
||||
Arch: "armhf",
|
||||
Ext: "deb",
|
||||
RaspberryPi: true,
|
||||
},
|
||||
{
|
||||
Distro: "deb",
|
||||
Arch: "armhf",
|
||||
Ext: "deb",
|
||||
},
|
||||
{
|
||||
Distro: "linux",
|
||||
Arch: "armv7",
|
||||
Ext: "tar.gz",
|
||||
},
|
||||
{
|
||||
Distro: "windows",
|
||||
Arch: "amd64",
|
||||
Ext: "zip",
|
||||
},
|
||||
{
|
||||
Distro: "windows",
|
||||
Arch: "amd64",
|
||||
Ext: "msi",
|
||||
},
|
||||
}
|
||||
|
||||
expect := []GCOMPackage{
|
||||
{
|
||||
URL: "https://dl.example.com/oss/release/grafana_1.2.3+example~01_arm64.deb",
|
||||
OS: "deb",
|
||||
Arch: "arm64",
|
||||
},
|
||||
{
|
||||
URL: "https://dl.example.com/oss/release/grafana-1.2.3+example~01-1.aarch64.rpm",
|
||||
OS: "rhel",
|
||||
Arch: "arm64",
|
||||
},
|
||||
{
|
||||
URL: "https://dl.example.com/oss/release/grafana-1.2.3+example-01.linux-arm64.tar.gz",
|
||||
OS: "linux",
|
||||
Arch: "arm64",
|
||||
},
|
||||
{
|
||||
URL: "https://dl.example.com/oss/release/grafana-rpi_1.2.3+example~01_armhf.deb",
|
||||
OS: "deb",
|
||||
Arch: "armv6",
|
||||
},
|
||||
{
|
||||
URL: "https://dl.example.com/oss/release/grafana_1.2.3+example~01_armhf.deb",
|
||||
OS: "deb",
|
||||
Arch: "armv7",
|
||||
},
|
||||
{
|
||||
URL: "https://dl.example.com/oss/release/grafana-1.2.3+example-01.linux-armv7.tar.gz",
|
||||
OS: "linux",
|
||||
Arch: "armv7",
|
||||
},
|
||||
{
|
||||
URL: "https://dl.example.com/oss/release/grafana-1.2.3+example-01.windows-amd64.zip",
|
||||
OS: "win",
|
||||
Arch: "amd64",
|
||||
},
|
||||
{
|
||||
URL: "https://dl.example.com/oss/release/grafana-1.2.3+example-01.windows-amd64.msi",
|
||||
OS: "win-installer",
|
||||
Arch: "amd64",
|
||||
},
|
||||
}
|
||||
|
||||
builds, err := Builds(baseURL, grafana, version, packages)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, len(expect), len(builds))
|
||||
|
||||
for i := range builds {
|
||||
t.Run(fmt.Sprintf("[%d/%d] %s", i+1, len(builds), expect[i].URL), func(t *testing.T) {
|
||||
assert.Equal(t, expect[i].URL, builds[i].URL)
|
||||
assert.Equal(t, expect[i].OS, builds[i].OS)
|
||||
assert.Equal(t, expect[i].Arch, builds[i].Arch)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,11 +3,9 @@ package main
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/grafana/grafana/pkg/build"
|
||||
"github.com/urfave/cli/v2"
|
||||
|
||||
"github.com/grafana/grafana/pkg/build/docker"
|
||||
)
|
||||
|
||||
var additionalCommands []*cli.Command = make([]*cli.Command, 0, 5)
|
||||
@@ -21,28 +19,8 @@ func main() {
|
||||
app := cli.NewApp()
|
||||
app.Commands = cli.Commands{
|
||||
{
|
||||
Name: "build-backend",
|
||||
Usage: "Build one or more variants of back-end binaries",
|
||||
ArgsUsage: "[version]",
|
||||
Action: MaxArgCountWrapper(1, BuildBackend),
|
||||
Flags: []cli.Flag{
|
||||
&jobsFlag,
|
||||
&variantsFlag,
|
||||
&editionFlag,
|
||||
&buildIDFlag,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "build-frontend-packages",
|
||||
Usage: "Build front-end packages",
|
||||
ArgsUsage: "[version]",
|
||||
Action: BuildFrontendPackages,
|
||||
Flags: []cli.Flag{
|
||||
&jobsFlag,
|
||||
&editionFlag,
|
||||
&buildIDFlag,
|
||||
&noInstallDepsFlag,
|
||||
},
|
||||
Name: "build",
|
||||
Action: build.RunCmdCLI,
|
||||
},
|
||||
{
|
||||
Name: "e2e-tests",
|
||||
@@ -71,44 +49,11 @@ func main() {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "build-frontend",
|
||||
Usage: "Build front-end artifacts",
|
||||
ArgsUsage: "[version]",
|
||||
Action: MaxArgCountWrapper(1, BuildFrontend),
|
||||
Flags: []cli.Flag{
|
||||
&jobsFlag,
|
||||
&editionFlag,
|
||||
&buildIDFlag,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "whatsnew-checker",
|
||||
Usage: "Checks whatsNewUrl in package.json for differences between the tag and the docs version",
|
||||
Action: WhatsNewChecker,
|
||||
},
|
||||
{
|
||||
Name: "build-docker",
|
||||
Usage: "Build Grafana Docker images",
|
||||
Action: MaxArgCountWrapper(1, BuildDocker),
|
||||
Flags: []cli.Flag{
|
||||
&jobsFlag,
|
||||
&editionFlag,
|
||||
&cli.BoolFlag{
|
||||
Name: "ubuntu",
|
||||
Usage: "Use Ubuntu base image",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "shouldSave",
|
||||
Usage: "Should save docker image to tarball",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "archs",
|
||||
Value: strings.Join(docker.AllArchs, ","),
|
||||
Usage: "Comma separated architectures to build",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "upload-cdn",
|
||||
Usage: "Upload public/* to a cdn bucket",
|
||||
@@ -117,23 +62,6 @@ func main() {
|
||||
&editionFlag,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "shellcheck",
|
||||
Usage: "Run shellcheck on shell scripts",
|
||||
Action: Shellcheck,
|
||||
},
|
||||
{
|
||||
Name: "build-plugins",
|
||||
Usage: "Build internal plug-ins",
|
||||
Action: MaxArgCountWrapper(1, BuildInternalPlugins),
|
||||
Flags: []cli.Flag{
|
||||
&jobsFlag,
|
||||
&editionFlag,
|
||||
&signingAdminFlag,
|
||||
&signFlag,
|
||||
&noInstallDepsFlag,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "publish-metrics",
|
||||
Usage: "Publish a set of metrics from stdin",
|
||||
@@ -145,30 +73,6 @@ func main() {
|
||||
Usage: "Verify Drone configuration",
|
||||
Action: VerifyDrone,
|
||||
},
|
||||
{
|
||||
Name: "verify-starlark",
|
||||
Usage: "Verify Starlark configuration",
|
||||
ArgsUsage: "<workspace path>",
|
||||
Action: VerifyStarlark,
|
||||
},
|
||||
{
|
||||
Name: "export-version",
|
||||
Usage: "Exports version in dist/grafana.version",
|
||||
Action: ExportVersion,
|
||||
},
|
||||
{
|
||||
Name: "package",
|
||||
Usage: "Package one or more Grafana variants",
|
||||
ArgsUsage: "[version]",
|
||||
Action: MaxArgCountWrapper(1, Package),
|
||||
Flags: []cli.Flag{
|
||||
&jobsFlag,
|
||||
&variantsFlag,
|
||||
&editionFlag,
|
||||
&buildIDFlag,
|
||||
&signFlag,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "store-storybook",
|
||||
Usage: "Stores storybook to GCS buckets",
|
||||
@@ -279,18 +183,6 @@ func main() {
|
||||
&editionFlag,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "publish-enterprise2",
|
||||
Usage: "Handle Grafana Enterprise2 Docker images",
|
||||
ArgsUsage: "[version]",
|
||||
Action: Enterprise2,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "dockerhub-repo",
|
||||
Usage: "DockerHub repo to push images",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -399,36 +291,6 @@ func main() {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "enterprise-check",
|
||||
Usage: "Commands for testing against Grafana Enterprise",
|
||||
Subcommands: cli.Commands{
|
||||
{
|
||||
Name: "begin",
|
||||
Usage: "Creates the GitHub check in a pull request and begins the tests",
|
||||
Action: EnterpriseCheckBegin,
|
||||
Flags: []cli.Flag{
|
||||
&gitHubTokenFlag,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "success",
|
||||
Usage: "Updates the GitHub check in a pull request to show a successful build and updates the pull request labels",
|
||||
Action: EnterpriseCheckSuccess,
|
||||
Flags: []cli.Flag{
|
||||
&gitHubTokenFlag,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "fail",
|
||||
Usage: "Updates the GitHub check in a pull request to show a failed build and updates the pull request labels",
|
||||
Action: EnterpriseCheckFail,
|
||||
Flags: []cli.Flag{
|
||||
&gitHubTokenFlag,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
app.Commands = append(app.Commands, additionalCommands...)
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
|
||||
"github.com/grafana/grafana/pkg/build/config"
|
||||
"github.com/grafana/grafana/pkg/build/gpg"
|
||||
"github.com/grafana/grafana/pkg/build/packaging"
|
||||
"github.com/grafana/grafana/pkg/build/syncutil"
|
||||
)
|
||||
|
||||
func Package(c *cli.Context) error {
|
||||
metadata, err := config.GenerateMetadata(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
edition := config.Edition(c.String("edition"))
|
||||
|
||||
releaseMode, err := metadata.GetReleaseMode()
|
||||
if err != nil {
|
||||
return cli.Exit(err.Error(), 1)
|
||||
}
|
||||
|
||||
releaseModeConfig, err := config.GetBuildConfig(metadata.ReleaseMode.Mode)
|
||||
if err != nil {
|
||||
return cli.Exit(err.Error(), 1)
|
||||
}
|
||||
|
||||
cfg := config.Config{
|
||||
NumWorkers: c.Int("jobs"),
|
||||
SignPackages: c.Bool("sign"),
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
variants := []config.Variant{}
|
||||
variantStrs := strings.Split(c.String("variants"), ",")
|
||||
if c.String("variants") != "" {
|
||||
for _, varStr := range variantStrs {
|
||||
if varStr == "" {
|
||||
continue
|
||||
}
|
||||
variants = append(variants, config.Variant(varStr))
|
||||
}
|
||||
} else {
|
||||
variants = releaseModeConfig.Variants
|
||||
}
|
||||
|
||||
if len(variants) == 0 {
|
||||
variants = config.AllVariants
|
||||
}
|
||||
|
||||
log.Printf("Packaging Grafana version %q, version mode %s, %s edition, variants %s", metadata.GrafanaVersion, releaseMode.Mode,
|
||||
edition, strings.Join(variantStrs, ","))
|
||||
|
||||
if cfg.SignPackages {
|
||||
if err := gpg.LoadGPGKeys(&cfg); err != nil {
|
||||
return cli.Exit(err, 1)
|
||||
}
|
||||
defer gpg.RemoveGPGFiles(cfg)
|
||||
if err := gpg.Import(cfg); err != nil {
|
||||
return cli.Exit(err, 1)
|
||||
}
|
||||
}
|
||||
|
||||
p := syncutil.NewWorkerPool(cfg.NumWorkers)
|
||||
defer p.Close()
|
||||
|
||||
if err := packaging.PackageGrafana(ctx, metadata.GrafanaVersion, ".", cfg, edition, variants, releaseModeConfig.PluginSignature.Sign, p); err != nil {
|
||||
return cli.Exit(err, 1)
|
||||
}
|
||||
|
||||
log.Println("Successfully packaged Grafana!")
|
||||
return nil
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
|
||||
"github.com/grafana/grafana/pkg/build/config"
|
||||
"github.com/grafana/grafana/pkg/build/docker"
|
||||
"github.com/grafana/grafana/pkg/build/gcloud"
|
||||
)
|
||||
|
||||
func Enterprise2(c *cli.Context) error {
|
||||
if c.NArg() > 0 {
|
||||
if err := cli.ShowSubcommandHelp(c); err != nil {
|
||||
return cli.Exit(err.Error(), 1)
|
||||
}
|
||||
return cli.Exit("", 1)
|
||||
}
|
||||
|
||||
if err := gcloud.ActivateServiceAccount(); err != nil {
|
||||
return fmt.Errorf("couldn't activate service account, err: %w", err)
|
||||
}
|
||||
|
||||
metadata, err := config.GenerateMetadata(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
buildConfig, err := config.GetBuildConfig(metadata.ReleaseMode.Mode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cfg := docker.Config{
|
||||
Archs: buildConfig.Docker.Architectures,
|
||||
Distribution: buildConfig.Docker.Distribution,
|
||||
DockerHubRepo: c.String("dockerhub-repo"),
|
||||
Tag: metadata.GrafanaVersion,
|
||||
}
|
||||
|
||||
err = dockerLoginEnterprise2()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var distributionStr []string
|
||||
for _, distribution := range cfg.Distribution {
|
||||
switch distribution {
|
||||
case alpine:
|
||||
distributionStr = append(distributionStr, "")
|
||||
case ubuntu:
|
||||
distributionStr = append(distributionStr, "-ubuntu")
|
||||
default:
|
||||
return fmt.Errorf("unrecognized distribution %q", distribution)
|
||||
}
|
||||
}
|
||||
|
||||
for _, distribution := range distributionStr {
|
||||
var imageFileNames []string
|
||||
for _, arch := range cfg.Archs {
|
||||
imageFilename := fmt.Sprintf("%s:%s%s-%s", cfg.DockerHubRepo, cfg.Tag, distribution, arch)
|
||||
err := docker.PushImage(imageFilename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
imageFileNames = append(imageFileNames, imageFilename)
|
||||
}
|
||||
manifest := fmt.Sprintf("%s:%s%s", cfg.DockerHubRepo, cfg.Tag, distribution)
|
||||
args := []string{"manifest", "create", manifest}
|
||||
args = append(args, imageFileNames...)
|
||||
|
||||
//nolint:gosec
|
||||
cmd := exec.Command("docker", args...)
|
||||
cmd.Env = append(os.Environ(), "DOCKER_CLI_EXPERIMENTAL=enabled")
|
||||
if output, err := cmd.CombinedOutput(); err != nil {
|
||||
return fmt.Errorf("failed to create Docker manifest: %w\n%s", err, output)
|
||||
}
|
||||
|
||||
err = docker.PushManifest(manifest)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func dockerLoginEnterprise2() error {
|
||||
log.Println("Docker login...")
|
||||
cmd := exec.Command("gcloud", "auth", "configure-docker")
|
||||
if out, err := cmd.CombinedOutput(); err != nil {
|
||||
return fmt.Errorf("error logging in to DockerHub: %s %q", out, err)
|
||||
}
|
||||
|
||||
log.Println("Successful login!")
|
||||
return nil
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
func Shellcheck(c *cli.Context) error {
|
||||
log.Println("Running shellcheck...")
|
||||
|
||||
fpaths := []string{}
|
||||
if err := filepath.Walk("scripts", func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if strings.HasSuffix(path, ".sh") {
|
||||
fpaths = append(fpaths, path)
|
||||
}
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
return fmt.Errorf("couldn't traverse scripts/: %w", err)
|
||||
}
|
||||
|
||||
log.Printf("Running shellcheck on %s", strings.Join(fpaths, ","))
|
||||
args := append([]string{"-e", "SC1071", "-e", "SC2162"}, fpaths...)
|
||||
//nolint:gosec
|
||||
cmd := exec.Command("shellcheck", args...)
|
||||
if output, err := cmd.CombinedOutput(); err != nil {
|
||||
return fmt.Errorf("shellcheck failed: %s", output)
|
||||
}
|
||||
|
||||
log.Println("Successfully ran shellcheck!")
|
||||
return nil
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
@@ -14,9 +15,28 @@ import (
|
||||
"github.com/grafana/grafana/pkg/build/config"
|
||||
"github.com/grafana/grafana/pkg/build/droneutil"
|
||||
"github.com/grafana/grafana/pkg/build/gcloud"
|
||||
"github.com/grafana/grafana/pkg/build/packaging"
|
||||
)
|
||||
|
||||
// PackageRegexp returns a regexp for matching packages corresponding to a certain Grafana edition.
|
||||
func PackageRegexp(edition config.Edition) *regexp.Regexp {
|
||||
var sfx string
|
||||
switch edition {
|
||||
case config.EditionOSS:
|
||||
case config.EditionEnterprise:
|
||||
sfx = "-enterprise"
|
||||
case config.EditionEnterprise2:
|
||||
sfx = "-enterprise2"
|
||||
default:
|
||||
panic(fmt.Sprintf("unrecognized edition %q", edition))
|
||||
}
|
||||
rePkg, err := regexp.Compile(fmt.Sprintf(`^grafana%s(?:-rpi)?[-_][^-_]+.*$`, sfx))
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("Failed to compile regexp: %s", err))
|
||||
}
|
||||
|
||||
return rePkg
|
||||
}
|
||||
|
||||
const releaseFolder = "release"
|
||||
const mainFolder = "main"
|
||||
const releaseBranchFolder = "prerelease"
|
||||
@@ -181,7 +201,7 @@ func uploadPackages(cfg uploadConfig) error {
|
||||
return fmt.Errorf("failed to list packages: %w", err)
|
||||
}
|
||||
fpaths := []string{}
|
||||
rePkg := packaging.PackageRegexp(cfg.edition)
|
||||
rePkg := PackageRegexp(cfg.edition)
|
||||
for _, fpath := range matches {
|
||||
fname := filepath.Base(fpath)
|
||||
if strings.Contains(fname, "latest") || !rePkg.MatchString(fname) {
|
||||
|
||||
@@ -1,142 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
func mapSlice[I any, O any](a []I, f func(I) O) []O {
|
||||
o := make([]O, len(a))
|
||||
for i, e := range a {
|
||||
o[i] = f(e)
|
||||
}
|
||||
return o
|
||||
}
|
||||
|
||||
// VerifyStarlark is the CLI Action for verifying Starlark files in a workspace.
|
||||
// It expects a single context argument which is the path to the workspace.
|
||||
// The actual verification procedure can return multiple errors which are
|
||||
// joined together to be one holistic error for the action.
|
||||
func VerifyStarlark(c *cli.Context) error {
|
||||
if c.NArg() != 1 {
|
||||
var message string
|
||||
if c.NArg() == 0 {
|
||||
message = "ERROR: missing required argument <workspace path>"
|
||||
}
|
||||
if c.NArg() > 1 {
|
||||
message = "ERROR: too many arguments"
|
||||
}
|
||||
|
||||
if err := cli.ShowSubcommandHelp(c); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return cli.Exit(message, 1)
|
||||
}
|
||||
|
||||
workspace := c.Args().Get(0)
|
||||
verificationErrs, executionErr := verifyStarlark(c.Context, workspace, buildifierLintCommand)
|
||||
if executionErr != nil {
|
||||
return executionErr
|
||||
}
|
||||
|
||||
if len(verificationErrs) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
noun := "file"
|
||||
if len(verificationErrs) > 1 {
|
||||
noun += "s"
|
||||
}
|
||||
|
||||
return fmt.Errorf("verification failed for %d %s:\n%s",
|
||||
len(verificationErrs),
|
||||
noun,
|
||||
strings.Join(
|
||||
mapSlice(verificationErrs, func(e error) string { return e.Error() }),
|
||||
"\n",
|
||||
))
|
||||
}
|
||||
|
||||
type commandFunc = func(path string) (command string, args []string)
|
||||
|
||||
func buildifierLintCommand(path string) (string, []string) {
|
||||
return "buildifier", []string{"-lint", "warn", "-mode", "check", path}
|
||||
}
|
||||
|
||||
// verifyStarlark walks all directories starting at provided workspace path and
|
||||
// verifies any Starlark files it finds.
|
||||
// Starlark files are assumed to end with the .star extension.
|
||||
// The verification relies on linting frovided by the 'buildifier' binary which
|
||||
// must be in the PATH.
|
||||
// A slice of verification errors are returned, one for each file that failed verification.
|
||||
// If any execution of the `buildifier` command fails, this is returned separately.
|
||||
// commandFn is executed on every Starlark file to determine the command and arguments to be executed.
|
||||
// The caller is trusted and it is the callers responsibility to ensure that the resulting command is safe to execute.
|
||||
func verifyStarlark(ctx context.Context, workspace string, commandFn commandFunc) ([]error, error) {
|
||||
var verificationErrs []error
|
||||
|
||||
// All errors from filepath.WalkDir are filtered by the fs.WalkDirFunc.
|
||||
// Lstat or ReadDir errors are reported as verificationErrors.
|
||||
// If any execution of the `buildifier` command fails or if the context is cancelled,
|
||||
// it is reported as an error and any verification of subsequent files is skipped.
|
||||
err := filepath.WalkDir(workspace, func(path string, d fs.DirEntry, err error) error {
|
||||
// Skip verification of the file or files within the directory if there is an error
|
||||
// returned by Lstat or ReadDir.
|
||||
if err != nil {
|
||||
verificationErrs = append(verificationErrs, err)
|
||||
return nil
|
||||
}
|
||||
|
||||
if d.IsDir() {
|
||||
return nil
|
||||
}
|
||||
|
||||
if filepath.Ext(path) == ".star" {
|
||||
command, args := commandFn(path)
|
||||
// The caller is trusted.
|
||||
//nolint:gosec
|
||||
cmd := exec.CommandContext(ctx, command, args...)
|
||||
cmd.Dir = workspace
|
||||
|
||||
_, err = cmd.Output()
|
||||
if err == nil { // No error, early return.
|
||||
return nil
|
||||
}
|
||||
|
||||
// The error returned from cmd.Output() is never wrapped.
|
||||
//nolint:errorlint
|
||||
if err, ok := err.(*exec.ExitError); ok {
|
||||
switch err.ExitCode() {
|
||||
// Case comments are informed by the output of `buildifier --help`
|
||||
case 1: // syntax errors in input
|
||||
verificationErrs = append(verificationErrs, errors.New(string(err.Stderr)))
|
||||
return nil
|
||||
case 2: // usage errors: invoked incorrectly
|
||||
return fmt.Errorf("command %q: %s", cmd, err.Stderr)
|
||||
case 3: // unexpected runtime errors: file I/O problems or internal bugs
|
||||
return fmt.Errorf("command %q: %s", cmd, err.Stderr)
|
||||
case 4: // check mode failed (reformat is needed)
|
||||
verificationErrs = append(verificationErrs, errors.New(string(err.Stderr)))
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("command %q: %s", cmd, err.Stderr)
|
||||
}
|
||||
}
|
||||
|
||||
// Error was not an exit error from the command.
|
||||
return fmt.Errorf("command %q: %v", cmd, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
return verificationErrs, err
|
||||
}
|
||||
@@ -1,137 +0,0 @@
|
||||
//go:build requires_buildifier
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestVerifyStarlark(t *testing.T) {
|
||||
t.Run("execution errors", func(t *testing.T) {
|
||||
t.Run("invalid usage", func(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
workspace := t.TempDir()
|
||||
err := os.WriteFile(filepath.Join(workspace, "ignored.star"), []byte{}, os.ModePerm)
|
||||
if err != nil {
|
||||
t.Fatalf(err.Error())
|
||||
}
|
||||
|
||||
_, executionErr := verifyStarlark(ctx, workspace, func(string) (string, []string) { return "buildifier", []string{"--invalid"} })
|
||||
if executionErr == nil {
|
||||
t.Fatalf("Expected execution error but got none")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("context cancellation", func(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
workspace := t.TempDir()
|
||||
err := os.WriteFile(filepath.Join(workspace, "ignored.star"), []byte{}, os.ModePerm)
|
||||
if err != nil {
|
||||
t.Fatalf(err.Error())
|
||||
}
|
||||
err = os.WriteFile(filepath.Join(workspace, "other-ignored.star"), []byte{}, os.ModePerm)
|
||||
if err != nil {
|
||||
t.Fatalf(err.Error())
|
||||
}
|
||||
cancel()
|
||||
|
||||
_, executionErr := verifyStarlark(ctx, workspace, buildifierLintCommand)
|
||||
if executionErr == nil {
|
||||
t.Fatalf("Expected execution error but got none")
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("verification errors", func(t *testing.T) {
|
||||
t.Run("a single file with lint", func(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
workspace := t.TempDir()
|
||||
|
||||
invalidContent := []byte(`load("scripts/drone/other.star", "function")
|
||||
|
||||
function()`)
|
||||
err := os.WriteFile(filepath.Join(workspace, "has-lint.star"), invalidContent, os.ModePerm)
|
||||
if err != nil {
|
||||
t.Fatalf(err.Error())
|
||||
}
|
||||
|
||||
verificationErrs, executionErr := verifyStarlark(ctx, workspace, buildifierLintCommand)
|
||||
if executionErr != nil {
|
||||
t.Fatalf("Unexpected execution error: %v", executionErr)
|
||||
}
|
||||
if len(verificationErrs) == 0 {
|
||||
t.Fatalf(`"has-lint.star" requires linting but the verifyStarlark function provided no linting error`)
|
||||
}
|
||||
if len(verificationErrs) > 1 {
|
||||
t.Fatalf(`verifyStarlark returned multiple errors for the "has-lint.star" file but only one was expected: %v`, verificationErrs)
|
||||
}
|
||||
if !strings.Contains(verificationErrs[0].Error(), "has-lint.star:1: module-docstring: The file has no module docstring.") {
|
||||
t.Fatalf(`"has-lint.star" is missing a module docstring but the verifyStarlark function linting error did not mention this, instead we got: %v`, verificationErrs[0])
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("no files with lint", func(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
workspace := t.TempDir()
|
||||
|
||||
content := []byte(`"""
|
||||
This module does nothing.
|
||||
"""
|
||||
|
||||
load("scripts/drone/other.star", "function")
|
||||
|
||||
function()
|
||||
`)
|
||||
require.NoError(t, os.WriteFile(filepath.Join(workspace, "no-lint.star"), content, os.ModePerm))
|
||||
|
||||
verificationErrs, executionErr := verifyStarlark(ctx, workspace, buildifierLintCommand)
|
||||
if executionErr != nil {
|
||||
t.Fatalf("Unexpected execution error: %v", executionErr)
|
||||
}
|
||||
if len(verificationErrs) != 0 {
|
||||
t.Log(`"no-lint.star" has no lint but the verifyStarlark function provided at least one error`)
|
||||
for _, err := range verificationErrs {
|
||||
t.Log(err)
|
||||
}
|
||||
t.FailNow()
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("multiple files with lint", func(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
workspace := t.TempDir()
|
||||
|
||||
invalidContent := []byte(`load("scripts/drone/other.star", "function")
|
||||
|
||||
function()`)
|
||||
require.NoError(t, os.WriteFile(filepath.Join(workspace, "has-lint.star"), invalidContent, os.ModePerm))
|
||||
require.NoError(t, os.WriteFile(filepath.Join(workspace, "has-lint2.star"), invalidContent, os.ModePerm))
|
||||
|
||||
verificationErrs, executionErr := verifyStarlark(ctx, workspace, buildifierLintCommand)
|
||||
if executionErr != nil {
|
||||
t.Fatalf("Unexpected execution error: %v", executionErr)
|
||||
}
|
||||
if len(verificationErrs) == 0 {
|
||||
t.Fatalf(`Two files require linting but the verifyStarlark function provided no linting error`)
|
||||
}
|
||||
if len(verificationErrs) == 1 {
|
||||
t.Fatalf(`Two files require linting but the verifyStarlark function provided only one linting error: %v`, verificationErrs[0])
|
||||
}
|
||||
if len(verificationErrs) > 2 {
|
||||
t.Fatalf(`verifyStarlark returned more errors than expected: %v`, verificationErrs)
|
||||
}
|
||||
if !strings.Contains(verificationErrs[0].Error(), "has-lint.star:1: module-docstring: The file has no module docstring.") {
|
||||
t.Errorf(`"has-lint.star" is missing a module docstring but the verifyStarlark function linting error did not mention this, instead we got: %v`, verificationErrs[0])
|
||||
}
|
||||
if !strings.Contains(verificationErrs[1].Error(), "has-lint2.star:1: module-docstring: The file has no module docstring.") {
|
||||
t.Fatalf(`"has-lint2.star" is missing a module docstring but the verifyStarlark function linting error did not mention this, instead we got: %v`, verificationErrs[0])
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
package compilers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
const (
|
||||
ArmV6 = "/opt/rpi-tools/arm-bcm2708/arm-linux-gnueabihf/bin/arm-linux-gnueabihf-gcc"
|
||||
Armv7 = "arm-linux-gnueabihf-gcc"
|
||||
Armv7Musl = "/tmp/arm-linux-musleabihf-cross/bin/arm-linux-musleabihf-gcc"
|
||||
Arm64 = "aarch64-linux-gnu-gcc"
|
||||
Arm64Musl = "/tmp/aarch64-linux-musl-cross/bin/aarch64-linux-musl-gcc"
|
||||
Osx64 = "/tmp/osxcross/target/bin/o64-clang"
|
||||
Win64 = "x86_64-w64-mingw32-gcc"
|
||||
LinuxX64 = "/tmp/x86_64-centos6-linux-gnu/bin/x86_64-centos6-linux-gnu-gcc"
|
||||
LinuxX64Musl = "/tmp/x86_64-linux-musl-cross/bin/x86_64-linux-musl-gcc"
|
||||
)
|
||||
|
||||
func Install() error {
|
||||
// From the os.TempDir documentation:
|
||||
// On Unix systems, it returns $TMPDIR if non-empty,
|
||||
// else /tmp. On Windows, it uses GetTempPath,
|
||||
// returning the first non-empty value from %TMP%, %TEMP%, %USERPROFILE%,
|
||||
// or the Windows directory. On Plan 9, it returns /tmp.
|
||||
tmp := os.TempDir()
|
||||
|
||||
var (
|
||||
centosArchive = "x86_64-centos6-linux-gnu.tar.xz"
|
||||
osxArchive = "osxcross.tar.xz"
|
||||
)
|
||||
|
||||
for _, fname := range []string{centosArchive, osxArchive} {
|
||||
path := filepath.Join(tmp, fname)
|
||||
if _, err := os.Stat(path); err != nil {
|
||||
return fmt.Errorf("stat error: %w", err)
|
||||
}
|
||||
// Ignore gosec G204 as this function is only used in the build process.
|
||||
//nolint:gosec
|
||||
cmd := exec.Command("tar", "xfJ", fname)
|
||||
cmd.Dir = tmp
|
||||
if output, err := cmd.CombinedOutput(); err != nil {
|
||||
return fmt.Errorf("failed to unpack %q: %q, %w", fname, output, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana/pkg/build/executil"
|
||||
)
|
||||
|
||||
type Revision struct {
|
||||
Timestamp int64
|
||||
SHA256 string
|
||||
EnterpriseCommit string
|
||||
Branch string
|
||||
}
|
||||
|
||||
func GrafanaTimestamp(ctx context.Context, dir string) (int64, error) {
|
||||
out, err := executil.OutputAt(ctx, dir, "git", "show", "-s", "--format=%ct")
|
||||
if err != nil {
|
||||
return time.Now().Unix(), nil
|
||||
}
|
||||
|
||||
stamp, err := strconv.ParseInt(out, 10, 64)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to parse output from git show: %q", out)
|
||||
}
|
||||
|
||||
return stamp, nil
|
||||
}
|
||||
|
||||
// GrafanaRevision uses git commands to get information about the checked out Grafana code located at 'grafanaDir'.
|
||||
// This could maybe be a more generic "Describe" function in the "git" package.
|
||||
func GrafanaRevision(ctx context.Context, grafanaDir string) (Revision, error) {
|
||||
stamp, err := GrafanaTimestamp(ctx, grafanaDir)
|
||||
if err != nil {
|
||||
return Revision{}, err
|
||||
}
|
||||
|
||||
sha, err := executil.OutputAt(ctx, grafanaDir, "git", "rev-parse", "--short", "HEAD")
|
||||
if err != nil {
|
||||
return Revision{}, err
|
||||
}
|
||||
|
||||
enterpriseCommit, err := executil.OutputAt(ctx, grafanaDir, "git", "-C", "../grafana-enterprise", "rev-parse", "--short", "HEAD")
|
||||
if err != nil {
|
||||
enterpriseCommit, err = executil.OutputAt(ctx, grafanaDir, "git", "-C", "..", "rev-parse", "--short", "HEAD")
|
||||
if err != nil {
|
||||
enterpriseCommit, err = executil.OutputAt(ctx, grafanaDir, "git", "-C", "/tmp/grafana-enterprise", "rev-parse", "--short", "HEAD")
|
||||
if err != nil {
|
||||
log.Println("Could not get enterprise commit. Error:", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
branch, err := executil.OutputAt(ctx, grafanaDir, "git", "rev-parse", "--abbrev-ref", "HEAD")
|
||||
if err != nil {
|
||||
return Revision{}, err
|
||||
}
|
||||
|
||||
return Revision{
|
||||
SHA256: sha,
|
||||
EnterpriseCommit: enterpriseCommit,
|
||||
Branch: branch,
|
||||
Timestamp: stamp,
|
||||
}, nil
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
package cryptoutil
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
func MD5File(fpath string) error {
|
||||
// Ignore gosec G304 as this function is only used in the build process.
|
||||
//nolint:gosec
|
||||
fd, err := os.Open(fpath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
if err := fd.Close(); err != nil {
|
||||
log.Printf("error closing file at '%s': %s", fpath, err.Error())
|
||||
}
|
||||
}()
|
||||
|
||||
h := md5.New() // nolint:gosec
|
||||
if _, err = io.Copy(h, fd); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// nolint:gosec
|
||||
if err := os.WriteFile(fpath+".md5", []byte(fmt.Sprintf("%x\n", h.Sum(nil))), 0664); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,182 +0,0 @@
|
||||
package docker
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/grafana/grafana/pkg/build/config"
|
||||
)
|
||||
|
||||
// verifyArchive verifies the integrity of an archive file.
|
||||
func verifyArchive(archive string) error {
|
||||
log.Printf("Verifying checksum of %q", archive)
|
||||
|
||||
//nolint:gosec
|
||||
shaB, err := os.ReadFile(archive + ".sha256")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
exp := strings.TrimSpace(string(shaB))
|
||||
|
||||
//nolint:gosec
|
||||
f, err := os.Open(archive)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err := f.Close(); err != nil {
|
||||
log.Println("error closing file:", err)
|
||||
}
|
||||
}()
|
||||
|
||||
h := sha256.New()
|
||||
_, err = io.Copy(h, f)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
chksum := hex.EncodeToString(h.Sum(nil))
|
||||
if chksum != exp {
|
||||
return fmt.Errorf("archive checksum is different than expected: %q", archive)
|
||||
}
|
||||
|
||||
log.Printf("Archive %q has expected checksum: %s", archive, exp)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// BuildImage builds a Docker image.
|
||||
// The image tag is returned.
|
||||
func BuildImage(version string, arch config.Architecture, grafanaDir string, useUbuntu, shouldSave bool, edition config.Edition, mode config.VersionMode) ([]string, error) {
|
||||
var baseArch string
|
||||
|
||||
switch arch {
|
||||
case "amd64":
|
||||
case "armv7":
|
||||
baseArch = "arm32v7/"
|
||||
case "arm64":
|
||||
baseArch = "arm64v8/"
|
||||
default:
|
||||
return []string{}, fmt.Errorf("unrecognized architecture %q", arch)
|
||||
}
|
||||
|
||||
libc := "-musl"
|
||||
baseImage := fmt.Sprintf("%salpine:3.18.5", baseArch)
|
||||
tagSuffix := ""
|
||||
if useUbuntu {
|
||||
libc = ""
|
||||
baseImage = fmt.Sprintf("%subuntu:22.04", baseArch)
|
||||
tagSuffix = "-ubuntu"
|
||||
}
|
||||
|
||||
var editionStr string
|
||||
var dockerRepo string
|
||||
var additionalDockerRepo string
|
||||
var tags []string
|
||||
var imageFileBase string
|
||||
var dockerEnterprise2Repo string
|
||||
if repo, ok := os.LookupEnv("DOCKER_ENTERPRISE2_REPO"); ok {
|
||||
dockerEnterprise2Repo = repo
|
||||
}
|
||||
|
||||
switch edition {
|
||||
case config.EditionOSS:
|
||||
dockerRepo = "grafana/grafana-image-tags"
|
||||
additionalDockerRepo = "grafana/grafana-oss-image-tags"
|
||||
imageFileBase = "grafana-oss"
|
||||
case config.EditionEnterprise:
|
||||
dockerRepo = "grafana/grafana-enterprise-image-tags"
|
||||
imageFileBase = "grafana-enterprise"
|
||||
editionStr = "-enterprise"
|
||||
case config.EditionEnterprise2:
|
||||
dockerRepo = dockerEnterprise2Repo
|
||||
imageFileBase = "grafana-enterprise2"
|
||||
editionStr = "-enterprise2"
|
||||
default:
|
||||
return []string{}, fmt.Errorf("unrecognized edition %s", edition)
|
||||
}
|
||||
|
||||
buildDir := filepath.Join(grafanaDir, "packaging/docker")
|
||||
// For example: grafana-8.5.0-52819pre.linux-amd64-musl.tar.gz
|
||||
archive := fmt.Sprintf("grafana%s-%s.linux-%s%s.tar.gz", editionStr, version, arch, libc)
|
||||
if err := verifyArchive(filepath.Join(buildDir, archive)); err != nil {
|
||||
return []string{}, err
|
||||
}
|
||||
|
||||
tag := fmt.Sprintf("%s:%s%s-%s", dockerRepo, version, tagSuffix, arch)
|
||||
tags = append(tags, tag)
|
||||
|
||||
args := []string{
|
||||
"build",
|
||||
"-q",
|
||||
"--build-arg", fmt.Sprintf("BASE_IMAGE=%s", baseImage),
|
||||
"--build-arg", fmt.Sprintf("GRAFANA_TGZ=%s", archive),
|
||||
"--build-arg", "GO_SRC=tgz-builder",
|
||||
"--build-arg", "JS_SRC=tgz-builder",
|
||||
"--build-arg", "RUN_SH=./run.sh",
|
||||
"--tag", tag,
|
||||
"--no-cache",
|
||||
"--file", "../../Dockerfile",
|
||||
".",
|
||||
"--label", fmt.Sprintf("mode=%s", string(mode)),
|
||||
}
|
||||
|
||||
//nolint:gosec
|
||||
cmd := exec.Command("docker", args...)
|
||||
cmd.Dir = buildDir
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
cmd.Env = append(os.Environ(), "DOCKER_CLI_EXPERIMENTAL=enabled", "DOCKER_BUILDKIT=1")
|
||||
log.Printf("Running Docker: DOCKER_CLI_EXPERIMENTAL=enabled DOCKER_BUILDKIT=1 %s", cmd)
|
||||
if err := cmd.Run(); err != nil {
|
||||
return []string{}, fmt.Errorf("building Docker image failed: %w", err)
|
||||
}
|
||||
if shouldSave {
|
||||
imageFile := fmt.Sprintf("%s-%s%s-%s.img", imageFileBase, version, tagSuffix, arch)
|
||||
//nolint:gosec
|
||||
cmd = exec.Command("docker", "save", tag, "-o", imageFile)
|
||||
cmd.Dir = buildDir
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
log.Printf("Running Docker: %s", cmd)
|
||||
if err := cmd.Run(); err != nil {
|
||||
return []string{}, fmt.Errorf("saving Docker image failed: %w", err)
|
||||
}
|
||||
gcsURL := fmt.Sprintf("gs://grafana-prerelease/artifacts/docker/%s/%s", version, imageFile)
|
||||
//nolint:gosec
|
||||
cmd = exec.Command("gsutil", "-q", "cp", imageFile, gcsURL)
|
||||
cmd.Dir = buildDir
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
log.Printf("Running gsutil: %s", cmd)
|
||||
if err := cmd.Run(); err != nil {
|
||||
return []string{}, fmt.Errorf("storing Docker image failed: %w", err)
|
||||
}
|
||||
log.Printf("Docker image %s stored to grafana-prerelease GCS bucket", imageFile)
|
||||
}
|
||||
if additionalDockerRepo != "" {
|
||||
additionalTag := fmt.Sprintf("%s:%s%s-%s", additionalDockerRepo, version, tagSuffix, arch)
|
||||
|
||||
//nolint:gosec
|
||||
cmd = exec.Command("docker", "tag", tag, additionalTag)
|
||||
cmd.Dir = buildDir
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
log.Printf("Running Docker: %s", cmd)
|
||||
if err := cmd.Run(); err != nil {
|
||||
return []string{}, fmt.Errorf("tagging Docker image failed: %w", err)
|
||||
}
|
||||
tags = append(tags, additionalTag)
|
||||
}
|
||||
|
||||
return tags, nil
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
package docker
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
// AllArchs is a list of all supported Docker image architectures.
|
||||
var AllArchs = []string{"amd64", "arm64"}
|
||||
|
||||
// emulatorImage is the docker image used as the cross-platform emulator
|
||||
var emulatorImage = "tonistiigi/binfmt:qemu-v7.0.0"
|
||||
|
||||
// Init initializes the OS for Docker image building.
|
||||
func Init() error {
|
||||
// Necessary for cross-platform builds
|
||||
if err := os.Setenv("DOCKER_BUILDKIT", "1"); err != nil {
|
||||
log.Println("error setting DOCKER_BUILDKIT environment variable:", err)
|
||||
}
|
||||
|
||||
// Enable execution of Docker images for other architectures
|
||||
//nolint:gosec
|
||||
cmd := exec.Command("docker", "run", "--privileged", "--rm",
|
||||
emulatorImage, "--install", "all")
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to enable execution of cross-platform Docker images: %w\n%s", err, output)
|
||||
}
|
||||
log.Println("emulators have been installed successfully!")
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
package docker
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
tries = 3
|
||||
sleepTime = 30
|
||||
)
|
||||
|
||||
func PushImage(newImage string) error {
|
||||
var err error
|
||||
for i := 0; i < tries; i++ {
|
||||
log.Printf("push attempt #%d...", i+1)
|
||||
var out []byte
|
||||
cmd := exec.Command("docker", "push", newImage)
|
||||
cmd.Dir = "."
|
||||
out, err = cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
log.Printf("output: %s", out)
|
||||
log.Printf("sleep for %d, before retrying...", sleepTime)
|
||||
time.Sleep(sleepTime * time.Second)
|
||||
} else {
|
||||
log.Printf("Successfully pushed %s!", newImage)
|
||||
break
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("error pushing images to DockerHub: %q", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func PushManifest(manifest string) error {
|
||||
log.Printf("Pushing Docker manifest %s...", manifest)
|
||||
|
||||
var err error
|
||||
for i := 0; i < tries; i++ {
|
||||
log.Printf("push attempt #%d...", i+1)
|
||||
var out []byte
|
||||
cmd := exec.Command("docker", "manifest", "push", manifest)
|
||||
cmd.Env = append(os.Environ(), "DOCKER_CLI_EXPERIMENTAL=enabled")
|
||||
out, err = cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
log.Printf("output: %s", out)
|
||||
log.Printf("sleep for %d, before retrying...", sleepTime)
|
||||
time.Sleep(sleepTime * time.Second)
|
||||
} else {
|
||||
log.Printf("Successful manifest push! %s", string(out))
|
||||
break
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to push manifest, err: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
18
pkg/build/env/lookup.go
vendored
18
pkg/build/env/lookup.go
vendored
@@ -1,18 +0,0 @@
|
||||
package env
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Lookup is the equivalent of os.LookupEnv, only you are able to provide the list of environment variables.
|
||||
// To use this as os.LookupEnv would be used, simply call
|
||||
// `env.Lookup("ENVIRONMENT_VARIABLE", os.Environ())`
|
||||
func Lookup(name string, vars []string) (string, bool) {
|
||||
for _, v := range vars {
|
||||
if strings.HasPrefix(v, name) {
|
||||
return strings.TrimPrefix(v, name+"="), true
|
||||
}
|
||||
}
|
||||
|
||||
return "", false
|
||||
}
|
||||
43
pkg/build/env/lookup_test.go
vendored
43
pkg/build/env/lookup_test.go
vendored
@@ -1,43 +0,0 @@
|
||||
package env_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/grafana/grafana/pkg/build/env"
|
||||
)
|
||||
|
||||
func TestLookup(t *testing.T) {
|
||||
values := []string{"ENV_1=a", "ENV_2=b", "ENV_3=c", "ENV_4_TEST="}
|
||||
|
||||
{
|
||||
v, ok := env.Lookup("ENV_1", values)
|
||||
require.Equal(t, v, "a")
|
||||
require.True(t, ok)
|
||||
}
|
||||
|
||||
{
|
||||
v, ok := env.Lookup("ENV_2", values)
|
||||
require.Equal(t, v, "b")
|
||||
require.True(t, ok)
|
||||
}
|
||||
|
||||
{
|
||||
v, ok := env.Lookup("ENV_3", values)
|
||||
require.Equal(t, v, "c")
|
||||
require.True(t, ok)
|
||||
}
|
||||
|
||||
{
|
||||
v, ok := env.Lookup("ENV_4_TEST", values)
|
||||
require.Equal(t, v, "")
|
||||
require.True(t, ok)
|
||||
}
|
||||
|
||||
{
|
||||
v, ok := env.Lookup("NOT_THERE", values)
|
||||
require.Equal(t, v, "")
|
||||
require.False(t, ok)
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
package errutil
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type Group struct {
|
||||
cancel func()
|
||||
wg sync.WaitGroup
|
||||
errOnce sync.Once
|
||||
err error
|
||||
}
|
||||
|
||||
func GroupWithContext(ctx context.Context) (*Group, context.Context) {
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
return &Group{cancel: cancel}, ctx
|
||||
}
|
||||
|
||||
// Wait waits for any wrapped goroutines to finish and returns any error having occurred in one of them.
|
||||
func (g *Group) Wait() error {
|
||||
log.Println("Waiting on Group")
|
||||
g.wg.Wait()
|
||||
if g.cancel != nil {
|
||||
log.Println("Group canceling its context after waiting")
|
||||
g.cancel()
|
||||
}
|
||||
return g.err
|
||||
}
|
||||
|
||||
// Cancel cancels the associated context.
|
||||
func (g *Group) Cancel() {
|
||||
log.Println("Group's Cancel method being called")
|
||||
g.cancel()
|
||||
}
|
||||
|
||||
// Wrap wraps a function to be executed in a goroutine.
|
||||
func (g *Group) Wrap(f func() error) func() {
|
||||
g.wg.Add(1)
|
||||
return func() {
|
||||
defer g.wg.Done()
|
||||
|
||||
if err := f(); err != nil {
|
||||
g.errOnce.Do(func() {
|
||||
log.Printf("An error occurred in Group: %s", err)
|
||||
g.err = err
|
||||
if g.cancel != nil {
|
||||
log.Println("Group canceling its context due to error")
|
||||
g.cancel()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Go wraps the provided function and executes it in a goroutine.
|
||||
func (g *Group) Go(f func() error) {
|
||||
wrapped := g.Wrap(f)
|
||||
go wrapped()
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
package executil
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func RunAt(ctx context.Context, dir, cmd string, args ...string) error {
|
||||
// Ignore gosec G204 as this function is only used in the build process.
|
||||
//nolint:gosec
|
||||
c := exec.CommandContext(ctx, cmd, args...)
|
||||
c.Dir = dir
|
||||
|
||||
b, err := c.CombinedOutput()
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("%w. '%s %v': %s", err, cmd, args, string(b))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func Run(ctx context.Context, cmd string, args ...string) error {
|
||||
return RunAt(ctx, ".", cmd, args...)
|
||||
}
|
||||
|
||||
func OutputAt(ctx context.Context, dir, cmd string, args ...string) (string, error) {
|
||||
// Ignore gosec G204 as this function is only used in the build process.
|
||||
//nolint:gosec
|
||||
c := exec.CommandContext(ctx, cmd, args...)
|
||||
c.Dir = dir
|
||||
|
||||
b, err := c.CombinedOutput()
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return strings.TrimSpace(string(b)), nil
|
||||
}
|
||||
|
||||
func Output(ctx context.Context, cmd string, args ...string) (string, error) {
|
||||
return OutputAt(ctx, ".", cmd, args...)
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
package frontend
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/grafana/grafana/pkg/build/config"
|
||||
"github.com/grafana/grafana/pkg/build/errutil"
|
||||
"github.com/grafana/grafana/pkg/build/lerna"
|
||||
"github.com/grafana/grafana/pkg/build/syncutil"
|
||||
)
|
||||
|
||||
func BuildFrontendPackages(version string, edition config.Edition, grafanaDir string, p syncutil.WorkerPool, g *errutil.Group) error {
|
||||
p.Schedule(g.Wrap(func() error {
|
||||
if err := lerna.BuildFrontendPackages(version, edition, grafanaDir); err != nil {
|
||||
return fmt.Errorf("failed to build %s frontend packages: %v", edition, err)
|
||||
}
|
||||
|
||||
log.Printf("Finished building %s frontend packages", string(edition))
|
||||
return nil
|
||||
}))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Build builds the Grafana front-end
|
||||
func Build(edition config.Edition, grafanaDir string, p syncutil.WorkerPool, g *errutil.Group) error {
|
||||
log.Printf("Building %s frontend in %q", edition, grafanaDir)
|
||||
grafanaDir, err := filepath.Abs(grafanaDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, dpath := range []string{"tmp", "public_gen", "public/build"} {
|
||||
dpath = filepath.Join(grafanaDir, dpath)
|
||||
if err := os.RemoveAll(dpath); err != nil {
|
||||
return fmt.Errorf("failed to remove %q: %w", dpath, err)
|
||||
}
|
||||
}
|
||||
|
||||
p.Schedule(g.Wrap(func() error {
|
||||
cmd := exec.Command("yarn", "run", "build")
|
||||
cmd.Dir = grafanaDir
|
||||
if output, err := cmd.CombinedOutput(); err != nil {
|
||||
return fmt.Errorf("failed to build %s frontend with webpack: %s", edition, output)
|
||||
}
|
||||
|
||||
log.Printf("Finished building %s frontend", edition)
|
||||
return nil
|
||||
}))
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
package frontend
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/blang/semver/v4"
|
||||
"github.com/grafana/grafana/pkg/build/config"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
const GrafanaDir = "."
|
||||
|
||||
func GetConfig(c *cli.Context, metadata config.Metadata) (config.Config, config.Edition, error) {
|
||||
cfg := config.Config{
|
||||
NumWorkers: c.Int("jobs"),
|
||||
GitHubToken: c.String("github-token"),
|
||||
}
|
||||
|
||||
mode := config.Edition(c.String("edition"))
|
||||
|
||||
if metadata.ReleaseMode.Mode == config.TagMode && !metadata.ReleaseMode.IsTest {
|
||||
packageJSONVersion, err := config.GetPackageJSONVersion(GrafanaDir)
|
||||
if err != nil {
|
||||
return config.Config{}, "", err
|
||||
}
|
||||
semverGrafanaVersion, err := semver.Parse(metadata.GrafanaVersion)
|
||||
if err != nil {
|
||||
return config.Config{}, "", err
|
||||
}
|
||||
semverPackageJSONVersion, err := semver.Parse(packageJSONVersion)
|
||||
if err != nil {
|
||||
return config.Config{}, "", err
|
||||
}
|
||||
// Check if the semver digits of the tag are not equal
|
||||
if semverGrafanaVersion.FinalizeVersion() != semverPackageJSONVersion.FinalizeVersion() {
|
||||
return config.Config{}, "", cli.Exit(fmt.Errorf("package.json version and input tag version differ %s != %s.\nPlease update package.json", packageJSONVersion, metadata.GrafanaVersion), 1)
|
||||
}
|
||||
}
|
||||
|
||||
cfg.PackageVersion = metadata.GrafanaVersion
|
||||
return cfg, mode, nil
|
||||
}
|
||||
@@ -1,118 +0,0 @@
|
||||
package frontend
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/urfave/cli/v2"
|
||||
|
||||
"github.com/grafana/grafana/pkg/build/config"
|
||||
)
|
||||
|
||||
const (
|
||||
jobs = "jobs"
|
||||
githubToken = "github-token"
|
||||
buildID = "build-id"
|
||||
)
|
||||
|
||||
type packageJson struct {
|
||||
Version string `json:"version"`
|
||||
}
|
||||
|
||||
type flagObj struct {
|
||||
name string
|
||||
value string
|
||||
}
|
||||
|
||||
var app = cli.NewApp()
|
||||
|
||||
func TestGetConfig(t *testing.T) {
|
||||
tests := []struct {
|
||||
ctx *cli.Context
|
||||
name string
|
||||
packageJsonVersion string
|
||||
metadata config.Metadata
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
ctx: cli.NewContext(app, setFlags(t, flag.NewFlagSet("flagSet", flag.ContinueOnError), flagObj{name: jobs, value: "2"}, flagObj{name: githubToken, value: "token"}), nil),
|
||||
name: "package.json matches tag",
|
||||
packageJsonVersion: "10.0.0",
|
||||
metadata: config.Metadata{GrafanaVersion: "10.0.0", ReleaseMode: config.ReleaseMode{Mode: config.TagMode}},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
ctx: cli.NewContext(app, setFlags(t, flag.NewFlagSet("flagSet", flag.ContinueOnError), flagObj{name: jobs, value: "2"}, flagObj{name: githubToken, value: "token"}), nil),
|
||||
name: "custom tag, package.json doesn't match",
|
||||
packageJsonVersion: "10.0.0",
|
||||
metadata: config.Metadata{GrafanaVersion: "10.0.0-abcd123pre", ReleaseMode: config.ReleaseMode{Mode: config.TagMode}},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
ctx: cli.NewContext(app, setFlags(t, flag.NewFlagSet("flagSet", flag.ContinueOnError), flagObj{name: jobs, value: "2"}, flagObj{name: githubToken, value: "token"}), nil),
|
||||
name: "package.json doesn't match tag",
|
||||
packageJsonVersion: "10.1.0",
|
||||
metadata: config.Metadata{GrafanaVersion: "10.0.0", ReleaseMode: config.ReleaseMode{Mode: config.TagMode}},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
ctx: cli.NewContext(app, setFlags(t, flag.NewFlagSet("flagSet", flag.ContinueOnError), flagObj{name: jobs, value: "2"}, flagObj{name: githubToken, value: "token"}), nil),
|
||||
name: "test tag event, check should be skipped",
|
||||
packageJsonVersion: "10.1.0",
|
||||
metadata: config.Metadata{GrafanaVersion: "10.1.0-test", ReleaseMode: config.ReleaseMode{Mode: config.TagMode, IsTest: true}},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
ctx: cli.NewContext(app, setFlags(t, flag.NewFlagSet("flagSet", flag.ContinueOnError), flagObj{name: jobs, value: "2"}, flagObj{name: githubToken, value: "token"}, flagObj{name: buildID, value: "12345"}), nil),
|
||||
name: "non-tag event",
|
||||
packageJsonVersion: "10.1.0-pre",
|
||||
metadata: config.Metadata{GrafanaVersion: "10.1.0-12345pre", ReleaseMode: config.ReleaseMode{Mode: config.PullRequestMode}},
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := createTempPackageJson(t, tt.packageJsonVersion)
|
||||
require.NoError(t, err)
|
||||
|
||||
got, _, err := GetConfig(tt.ctx, tt.metadata)
|
||||
if !tt.wantErr {
|
||||
require.Equal(t, got.PackageVersion, tt.metadata.GrafanaVersion)
|
||||
}
|
||||
|
||||
if tt.wantErr {
|
||||
require.Equal(t, got.PackageVersion, "")
|
||||
require.Error(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func setFlags(t *testing.T, flagSet *flag.FlagSet, flags ...flagObj) *flag.FlagSet {
|
||||
t.Helper()
|
||||
for _, f := range flags {
|
||||
if f.name != "" {
|
||||
flagSet.StringVar(&f.name, f.name, f.value, "")
|
||||
}
|
||||
}
|
||||
return flagSet
|
||||
}
|
||||
|
||||
func createTempPackageJson(t *testing.T, version string) error {
|
||||
t.Helper()
|
||||
|
||||
data := packageJson{Version: version}
|
||||
file, _ := json.MarshalIndent(data, "", " ")
|
||||
|
||||
err := os.WriteFile("package.json", file, 0644)
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Cleanup(func() {
|
||||
err := os.RemoveAll("package.json")
|
||||
require.NoError(t, err)
|
||||
})
|
||||
return nil
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
package fsutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// CopyRecursive copies files and directories recursively.
|
||||
func CopyRecursive(src, dst string) error {
|
||||
sfi, err := os.Stat(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !sfi.IsDir() {
|
||||
return CopyFile(src, dst)
|
||||
}
|
||||
|
||||
if _, err := os.Stat(dst); os.IsNotExist(err) {
|
||||
if err := os.MkdirAll(dst, sfi.Mode()); err != nil {
|
||||
return fmt.Errorf("failed to create directory %q: %s", dst, err)
|
||||
}
|
||||
}
|
||||
|
||||
entries, err := os.ReadDir(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, entry := range entries {
|
||||
srcPath := filepath.Join(src, entry.Name())
|
||||
dstPath := filepath.Join(dst, entry.Name())
|
||||
|
||||
srcFi, err := os.Stat(srcPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch srcFi.Mode() & os.ModeType {
|
||||
case os.ModeDir:
|
||||
if err := CopyRecursive(srcPath, dstPath); err != nil {
|
||||
return err
|
||||
}
|
||||
case os.ModeSymlink:
|
||||
link, err := os.Readlink(srcPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.Symlink(link, dstPath); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
if err := CopyFile(srcPath, dstPath); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if srcFi.Mode()&os.ModeSymlink != 0 {
|
||||
if err := os.Chmod(dstPath, srcFi.Mode()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
package fsutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
// CreateTempFile generates a temp filepath, based on the provided suffix.
|
||||
// A typical generated path looks like /var/folders/abcd/abcdefg/A/1137975807.
|
||||
func CreateTempFile(sfx string) (string, error) {
|
||||
var suffix string
|
||||
if sfx != "" {
|
||||
suffix = fmt.Sprintf("*-%s", sfx)
|
||||
} else {
|
||||
suffix = sfx
|
||||
}
|
||||
f, err := os.CreateTemp("", suffix)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err := f.Close(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return f.Name(), nil
|
||||
}
|
||||
|
||||
// CreateTempDir generates a temp directory, based on the provided suffix.
|
||||
// A typical generated path looks like /var/folders/abcd/abcdefg/A/1137975807/.
|
||||
func CreateTempDir(sfx string) (string, error) {
|
||||
var suffix string
|
||||
if sfx != "" {
|
||||
suffix = fmt.Sprintf("*-%s", sfx)
|
||||
} else {
|
||||
suffix = sfx
|
||||
}
|
||||
dir, err := os.MkdirTemp("", suffix)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return dir, nil
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
package fsutil
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestCreateTempFile(t *testing.T) {
|
||||
t.Run("empty suffix, expects pattern like: /var/folders/abcd/abcdefg/A/1137975807", func(t *testing.T) {
|
||||
filePath, err := CreateTempFile("")
|
||||
require.NoError(t, err)
|
||||
|
||||
pathParts := strings.Split(filePath, "/")
|
||||
require.Greater(t, len(pathParts), 1)
|
||||
require.Len(t, strings.Split(pathParts[len(pathParts)-1], "-"), 1)
|
||||
})
|
||||
|
||||
t.Run("non-empty suffix, expects /var/folders/abcd/abcdefg/A/1137975807-foobar", func(t *testing.T) {
|
||||
filePath, err := CreateTempFile("foobar")
|
||||
require.NoError(t, err)
|
||||
|
||||
pathParts := strings.Split(filePath, "/")
|
||||
require.Greater(t, len(pathParts), 1)
|
||||
require.Len(t, strings.Split(pathParts[len(pathParts)-1], "-"), 2)
|
||||
})
|
||||
}
|
||||
|
||||
func TestCreateTempDir(t *testing.T) {
|
||||
t.Run("empty suffix, expects pattern like: /var/folders/abcd/abcdefg/A/1137975807/", func(t *testing.T) {
|
||||
filePath, err := CreateTempFile("")
|
||||
require.NoError(t, err)
|
||||
|
||||
pathParts := strings.Split(filePath, "/")
|
||||
require.Greater(t, len(pathParts), 1)
|
||||
require.Len(t, strings.Split(pathParts[len(pathParts)-1], "-"), 1)
|
||||
})
|
||||
|
||||
t.Run("non-empty suffix, expects /var/folders/abcd/abcdefg/A/1137975807-foobar/", func(t *testing.T) {
|
||||
filePath, err := CreateTempFile("foobar")
|
||||
require.NoError(t, err)
|
||||
|
||||
pathParts := strings.Split(filePath, "/")
|
||||
require.Greater(t, len(pathParts), 1)
|
||||
require.Len(t, strings.Split(pathParts[len(pathParts)-1], "-"), 2)
|
||||
})
|
||||
}
|
||||
72
pkg/build/gcom/url.go
Normal file
72
pkg/build/gcom/url.go
Normal file
@@ -0,0 +1,72 @@
|
||||
package gcom
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/grafana/grafana/pkg/build/versions"
|
||||
)
|
||||
|
||||
func PackageName(grafana, distro, arch, version, ext string, musl bool, raspberryPi bool) string {
|
||||
v := versions.ParseSemver(version)
|
||||
|
||||
if raspberryPi {
|
||||
grafana += "-rpi"
|
||||
}
|
||||
|
||||
versionString := strings.Join([]string{v.Major, v.Minor, v.Patch}, ".")
|
||||
fmt.Println("Version string:", versionString)
|
||||
if distro == "deb" {
|
||||
if v.BuildMetadata != "" {
|
||||
versionString += "+" + strings.ReplaceAll(v.BuildMetadata, "-", "~")
|
||||
}
|
||||
|
||||
if v.Prerelease != "" {
|
||||
versionString += "~" + v.Prerelease
|
||||
}
|
||||
|
||||
return strings.Join([]string{grafana, versionString, arch}, "_") + "." + ext
|
||||
}
|
||||
|
||||
if distro == "rhel" {
|
||||
if v.BuildMetadata != "" {
|
||||
versionString += "+" + strings.ReplaceAll(v.BuildMetadata, "-", "~")
|
||||
}
|
||||
|
||||
if v.Prerelease != "" {
|
||||
versionString += "~" + v.Prerelease
|
||||
}
|
||||
|
||||
versionString += "-1"
|
||||
|
||||
// Notable difference between our deb naming and our RPM naming: the file ends with `.arch.ext`, not
|
||||
// `_arch.ext`.
|
||||
return strings.Join([]string{grafana, versionString}, "-") + "." + arch + "." + ext
|
||||
}
|
||||
|
||||
if v.Prerelease != "" {
|
||||
versionString += "-" + v.Prerelease
|
||||
}
|
||||
|
||||
if v.BuildMetadata != "" {
|
||||
versionString += "+" + v.BuildMetadata
|
||||
}
|
||||
|
||||
if musl {
|
||||
arch += "-musl"
|
||||
}
|
||||
|
||||
// grafana-enterprise-1.2.3+example-01.linux-amd64.tar.gz
|
||||
return fmt.Sprintf("%s-%s.%s-%s.%s", grafana, versionString, distro, arch, ext)
|
||||
}
|
||||
|
||||
func GetURL(baseURL *url.URL, version, grafana, distro, arch, ext string, musl, raspberryPi bool) *url.URL {
|
||||
packageName := PackageName(grafana, distro, arch, version, ext, musl, raspberryPi)
|
||||
return &url.URL{
|
||||
Host: baseURL.Host,
|
||||
Scheme: baseURL.Scheme,
|
||||
Path: path.Join(baseURL.Path, packageName),
|
||||
}
|
||||
}
|
||||
367
pkg/build/gcom/url_test.go
Normal file
367
pkg/build/gcom/url_test.go
Normal file
@@ -0,0 +1,367 @@
|
||||
package gcom_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/grafana/grafana/pkg/build/gcom"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestPackageName(t *testing.T) {
|
||||
type args struct {
|
||||
Distro string
|
||||
Arch string
|
||||
Version string
|
||||
Ext string
|
||||
Musl bool
|
||||
RaspberryPi bool
|
||||
|
||||
Expect string
|
||||
}
|
||||
|
||||
cases := []args{
|
||||
{
|
||||
RaspberryPi: true,
|
||||
Distro: "deb",
|
||||
Arch: "armhf",
|
||||
Version: "1.2.3",
|
||||
Ext: "deb",
|
||||
Expect: "grafana-rpi_1.2.3_armhf.deb",
|
||||
},
|
||||
{
|
||||
Distro: "deb",
|
||||
Arch: "arm64",
|
||||
Version: "1.2.3",
|
||||
Ext: "deb",
|
||||
Expect: "grafana_1.2.3_arm64.deb",
|
||||
},
|
||||
{
|
||||
Distro: "rhel",
|
||||
Arch: "aarch64",
|
||||
Version: "1.2.3",
|
||||
Ext: "rpm",
|
||||
Expect: "grafana-1.2.3-1.aarch64.rpm",
|
||||
},
|
||||
{
|
||||
Distro: "rhel",
|
||||
Arch: "aarch64",
|
||||
Ext: "rpm.sha256",
|
||||
Version: "1.2.3",
|
||||
Expect: "grafana-1.2.3-1.aarch64.rpm.sha256",
|
||||
},
|
||||
{
|
||||
Distro: "rhel",
|
||||
Ext: "rpm",
|
||||
Version: "1.2.3",
|
||||
Arch: "x86_64",
|
||||
Expect: "grafana-1.2.3-1.x86_64.rpm",
|
||||
},
|
||||
{
|
||||
Distro: "rhel",
|
||||
Ext: "rpm.sha256",
|
||||
Version: "1.2.3",
|
||||
Arch: "x86_64",
|
||||
Expect: "grafana-1.2.3-1.x86_64.rpm.sha256",
|
||||
},
|
||||
{
|
||||
Distro: "darwin",
|
||||
Ext: "tar.gz",
|
||||
Version: "1.2.3",
|
||||
Arch: "amd64",
|
||||
Expect: "grafana-1.2.3.darwin-amd64.tar.gz",
|
||||
},
|
||||
{
|
||||
Distro: "darwin",
|
||||
Ext: "tar.gz.sha256",
|
||||
Version: "1.2.3",
|
||||
Arch: "amd64",
|
||||
Expect: "grafana-1.2.3.darwin-amd64.tar.gz.sha256",
|
||||
},
|
||||
{
|
||||
Distro: "darwin",
|
||||
Ext: "tar.gz",
|
||||
Version: "1.2.3",
|
||||
Arch: "arm64",
|
||||
Expect: "grafana-1.2.3.darwin-arm64-musl.tar.gz",
|
||||
Musl: true,
|
||||
},
|
||||
{
|
||||
Distro: "darwin",
|
||||
Ext: "tar.gz.sha256",
|
||||
Version: "1.2.3",
|
||||
Arch: "arm64",
|
||||
Expect: "grafana-1.2.3.darwin-arm64-musl.tar.gz.sha256",
|
||||
Musl: true,
|
||||
},
|
||||
{
|
||||
Distro: "darwin",
|
||||
Ext: "tar.gz",
|
||||
Version: "1.2.3",
|
||||
Arch: "arm64",
|
||||
Expect: "grafana-1.2.3.darwin-arm64.tar.gz",
|
||||
},
|
||||
{
|
||||
Distro: "darwin",
|
||||
Ext: "tar.gz.sha256",
|
||||
Version: "1.2.3",
|
||||
Arch: "arm64",
|
||||
Expect: "grafana-1.2.3.darwin-arm64.tar.gz.sha256",
|
||||
},
|
||||
{
|
||||
Distro: "linux",
|
||||
Ext: "tar.gz",
|
||||
Version: "1.2.3",
|
||||
Arch: "amd64",
|
||||
Expect: "grafana-1.2.3.linux-amd64-musl.tar.gz",
|
||||
Musl: true,
|
||||
},
|
||||
{
|
||||
Distro: "linux",
|
||||
Ext: "tar.gz.sha256",
|
||||
Version: "1.2.3",
|
||||
Arch: "amd64",
|
||||
Expect: "grafana-1.2.3.linux-amd64-musl.tar.gz.sha256",
|
||||
Musl: true,
|
||||
},
|
||||
{
|
||||
Distro: "linux",
|
||||
Ext: "tar.gz",
|
||||
Version: "1.2.3",
|
||||
Arch: "amd64",
|
||||
Expect: "grafana-1.2.3.linux-amd64.tar.gz",
|
||||
},
|
||||
{
|
||||
Distro: "linux",
|
||||
Ext: "tar.gz.sha256",
|
||||
Version: "1.2.3",
|
||||
Arch: "amd64",
|
||||
Expect: "grafana-1.2.3.linux-amd64.tar.gz.sha256",
|
||||
},
|
||||
{
|
||||
Distro: "linux",
|
||||
Ext: "tar.gz",
|
||||
Version: "1.2.3",
|
||||
Arch: "arm64",
|
||||
Expect: "grafana-1.2.3.linux-arm64-musl.tar.gz",
|
||||
Musl: true,
|
||||
},
|
||||
{
|
||||
Distro: "linux",
|
||||
Ext: "tar.gz.sha256",
|
||||
Version: "1.2.3",
|
||||
Arch: "arm64",
|
||||
Expect: "grafana-1.2.3.linux-arm64-musl.tar.gz.sha256",
|
||||
Musl: true,
|
||||
},
|
||||
{
|
||||
Distro: "linux",
|
||||
Ext: "tar.gz",
|
||||
Version: "1.2.3",
|
||||
Arch: "arm64",
|
||||
Expect: "grafana-1.2.3.linux-arm64.tar.gz",
|
||||
},
|
||||
{
|
||||
Ext: "tar.gz.sha256",
|
||||
Version: "1.2.3",
|
||||
Distro: "linux",
|
||||
Arch: "arm64",
|
||||
Expect: "grafana-1.2.3.linux-arm64.tar.gz.sha256",
|
||||
},
|
||||
{
|
||||
Ext: "tar.gz",
|
||||
Version: "1.2.3",
|
||||
Distro: "linux",
|
||||
Arch: "armv6",
|
||||
Expect: "grafana-1.2.3.linux-armv6.tar.gz",
|
||||
},
|
||||
{
|
||||
Ext: "tar.gz.sha256",
|
||||
Version: "1.2.3",
|
||||
Distro: "linux",
|
||||
Arch: "armv6",
|
||||
Expect: "grafana-1.2.3.linux-armv6.tar.gz.sha256",
|
||||
},
|
||||
{
|
||||
Ext: "tar.gz",
|
||||
Version: "1.2.3",
|
||||
Distro: "linux",
|
||||
Arch: "armv7",
|
||||
Expect: "grafana-1.2.3.linux-armv7-musl.tar.gz",
|
||||
Musl: true,
|
||||
},
|
||||
{
|
||||
Ext: "tar.gz.sha256",
|
||||
Version: "1.2.3",
|
||||
Distro: "linux",
|
||||
Arch: "armv7",
|
||||
Expect: "grafana-1.2.3.linux-armv7-musl.tar.gz.sha256",
|
||||
Musl: true,
|
||||
},
|
||||
{
|
||||
Ext: "tar.gz",
|
||||
Version: "1.2.3",
|
||||
Distro: "linux",
|
||||
Arch: "armv7",
|
||||
Expect: "grafana-1.2.3.linux-armv7.tar.gz",
|
||||
},
|
||||
{
|
||||
Ext: "tar.gz.sha256",
|
||||
Version: "1.2.3",
|
||||
Distro: "linux",
|
||||
Arch: "armv7",
|
||||
Expect: "grafana-1.2.3.linux-armv7.tar.gz.sha256",
|
||||
},
|
||||
{
|
||||
Version: "1.2.3",
|
||||
Arch: "amd64",
|
||||
Ext: "exe",
|
||||
Distro: "windows",
|
||||
Expect: "grafana-1.2.3.windows-amd64.exe",
|
||||
},
|
||||
{
|
||||
Version: "1.2.3",
|
||||
Arch: "amd64",
|
||||
Distro: "windows",
|
||||
Ext: "exe.sha256",
|
||||
Expect: "grafana-1.2.3.windows-amd64.exe.sha256",
|
||||
},
|
||||
{
|
||||
Version: "1.2.3",
|
||||
Arch: "amd64",
|
||||
Distro: "windows",
|
||||
Ext: "msi",
|
||||
Expect: "grafana-1.2.3.windows-amd64.msi",
|
||||
},
|
||||
{
|
||||
Version: "1.2.3",
|
||||
Arch: "amd64",
|
||||
Distro: "windows",
|
||||
Ext: "msi.sha256",
|
||||
Expect: "grafana-1.2.3.windows-amd64.msi.sha256",
|
||||
},
|
||||
{
|
||||
Ext: "tar.gz",
|
||||
Version: "1.2.3",
|
||||
Distro: "windows",
|
||||
Expect: "grafana-1.2.3.windows-amd64.tar.gz",
|
||||
Arch: "amd64",
|
||||
},
|
||||
{
|
||||
Version: "1.2.3",
|
||||
Distro: "windows",
|
||||
Arch: "amd64",
|
||||
Ext: "tar.gz.sha256",
|
||||
Expect: "grafana-1.2.3.windows-amd64.tar.gz.sha256",
|
||||
},
|
||||
{
|
||||
Version: "1.2.3",
|
||||
Distro: "windows",
|
||||
Expect: "grafana-1.2.3.windows-amd64.zip",
|
||||
Ext: "zip",
|
||||
Arch: "amd64",
|
||||
},
|
||||
{
|
||||
Version: "1.2.3",
|
||||
Distro: "windows",
|
||||
Expect: "grafana-1.2.3.windows-amd64.zip.sha256",
|
||||
Ext: "zip.sha256",
|
||||
Arch: "amd64",
|
||||
},
|
||||
{
|
||||
Ext: "tar.gz",
|
||||
Version: "1.2.3",
|
||||
Distro: "windows",
|
||||
Arch: "arm64",
|
||||
Expect: "grafana-1.2.3.windows-arm64-musl.tar.gz",
|
||||
Musl: true,
|
||||
},
|
||||
{
|
||||
Version: "1.2.3",
|
||||
Ext: "tar.gz.sha256",
|
||||
Distro: "windows",
|
||||
Arch: "arm64",
|
||||
Expect: "grafana-1.2.3.windows-arm64-musl.tar.gz.sha256",
|
||||
Musl: true,
|
||||
},
|
||||
{
|
||||
Ext: "tar.gz",
|
||||
Version: "1.2.3",
|
||||
Distro: "windows",
|
||||
Arch: "arm64",
|
||||
Expect: "grafana-1.2.3.windows-arm64.tar.gz",
|
||||
},
|
||||
{
|
||||
Version: "1.2.3",
|
||||
Ext: "tar.gz.sha256",
|
||||
Distro: "windows",
|
||||
Arch: "arm64",
|
||||
Expect: "grafana-1.2.3.windows-arm64.tar.gz.sha256",
|
||||
},
|
||||
{
|
||||
RaspberryPi: true,
|
||||
Version: "1.2.3",
|
||||
Ext: "deb",
|
||||
Arch: "armhf",
|
||||
Distro: "deb",
|
||||
Expect: "grafana-rpi_1.2.3_armhf.deb",
|
||||
},
|
||||
{
|
||||
RaspberryPi: true,
|
||||
Version: "1.2.3",
|
||||
Ext: "deb.sha256",
|
||||
Distro: "deb",
|
||||
Arch: "armhf",
|
||||
Expect: "grafana-rpi_1.2.3_armhf.deb.sha256",
|
||||
},
|
||||
{
|
||||
Version: "1.2.3",
|
||||
Ext: "deb",
|
||||
Distro: "deb",
|
||||
Expect: "grafana_1.2.3_amd64.deb",
|
||||
Arch: "amd64",
|
||||
},
|
||||
{
|
||||
Version: "1.2.3",
|
||||
Ext: "deb.sha256",
|
||||
Distro: "deb",
|
||||
Expect: "grafana_1.2.3_amd64.deb.sha256",
|
||||
Arch: "amd64",
|
||||
},
|
||||
{
|
||||
Version: "1.2.3",
|
||||
Ext: "deb",
|
||||
Arch: "arm64",
|
||||
Distro: "deb",
|
||||
Expect: "grafana_1.2.3_arm64.deb",
|
||||
},
|
||||
{
|
||||
Version: "1.2.3",
|
||||
Ext: "deb.sha256",
|
||||
Arch: "arm64",
|
||||
Distro: "deb",
|
||||
Expect: "grafana_1.2.3_arm64.deb.sha256",
|
||||
},
|
||||
{
|
||||
Version: "1.2.3",
|
||||
Ext: "deb",
|
||||
Distro: "deb",
|
||||
Arch: "armhf",
|
||||
Expect: "grafana_1.2.3_armhf.deb",
|
||||
},
|
||||
{
|
||||
Version: "1.2.3",
|
||||
Ext: "deb.sha256",
|
||||
Arch: "armhf",
|
||||
Distro: "deb",
|
||||
Expect: "grafana_1.2.3_armhf.deb.sha256",
|
||||
},
|
||||
}
|
||||
|
||||
for i, v := range cases {
|
||||
t.Run(fmt.Sprintf("[%d / %d] %s", i+1, len(cases), v.Expect), func(t *testing.T) {
|
||||
n := gcom.PackageName("grafana", v.Distro, v.Arch, v.Version, v.Ext, v.Musl, v.RaspberryPi)
|
||||
require.Equal(t, v.Expect, n)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -4,13 +4,9 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"regexp"
|
||||
|
||||
"github.com/google/go-github/v45/github"
|
||||
"golang.org/x/oauth2"
|
||||
|
||||
"github.com/grafana/grafana/pkg/build/stringutil"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -47,19 +43,6 @@ type StatusesService interface {
|
||||
CreateStatus(ctx context.Context, owner, repo, ref string, status *github.RepoStatus) (*github.RepoStatus, *github.Response, error)
|
||||
}
|
||||
|
||||
// NewGitHubClient creates a new Client using the provided GitHub token if not empty.
|
||||
func NewGitHubClient(ctx context.Context, token string) *github.Client {
|
||||
var tc *http.Client
|
||||
if token != "" {
|
||||
ts := oauth2.StaticTokenSource(&oauth2.Token{
|
||||
AccessToken: token,
|
||||
})
|
||||
tc = oauth2.NewClient(ctx, ts)
|
||||
}
|
||||
|
||||
return github.NewClient(tc)
|
||||
}
|
||||
|
||||
func PRCheckRegexp() *regexp.Regexp {
|
||||
reBranch, err := regexp.Compile(`^prc-([0-9]+)-([A-Za-z0-9]+)\/(.+)$`)
|
||||
if err != nil {
|
||||
@@ -68,76 +51,3 @@ func PRCheckRegexp() *regexp.Regexp {
|
||||
|
||||
return reBranch
|
||||
}
|
||||
|
||||
func AddLabelToPR(ctx context.Context, client LabelsService, prID int, newLabel string) error {
|
||||
// Check existing labels
|
||||
labels, _, err := client.ListLabelsByIssue(ctx, RepoOwner, OSSRepo, prID, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
duplicate := false
|
||||
for _, label := range labels {
|
||||
if *label.Name == newLabel {
|
||||
duplicate = true
|
||||
continue
|
||||
}
|
||||
|
||||
// Delete existing "enterprise-xx" labels
|
||||
if stringutil.Contains(EnterpriseCheckLabels, *label.Name) {
|
||||
_, err := client.RemoveLabelForIssue(ctx, RepoOwner, OSSRepo, prID, *label.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if duplicate {
|
||||
return nil
|
||||
}
|
||||
|
||||
_, _, err = client.AddLabelsToIssue(ctx, RepoOwner, OSSRepo, prID, []string{newLabel})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeleteEnterpriseBranch(ctx context.Context, client GitService, branchName string) error {
|
||||
ref := "heads/" + branchName
|
||||
if _, err := client.DeleteRef(ctx, RepoOwner, EnterpriseRepo, ref); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateEnterpriseStatus sets the status on a commit for the enterprise build check.
|
||||
func CreateEnterpriseStatus(ctx context.Context, client StatusesService, sha, link, status string) (*github.RepoStatus, error) {
|
||||
check, _, err := client.CreateStatus(ctx, RepoOwner, OSSRepo, sha, &github.RepoStatus{
|
||||
Context: github.String(EnterpriseCheckName),
|
||||
Description: github.String(EnterpriseCheckDescription),
|
||||
TargetURL: github.String(link),
|
||||
State: github.String(status),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return check, nil
|
||||
}
|
||||
|
||||
func CreateEnterpriseBuildFailedComment(ctx context.Context, client CommentService, link string, prID int) error {
|
||||
body := fmt.Sprintf("Drone build failed: %s", link)
|
||||
|
||||
_, _, err := client.CreateComment(ctx, RepoOwner, OSSRepo, prID, &github.IssueComment{
|
||||
Body: &body,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
package git_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-github/v45/github"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/grafana/grafana/pkg/build/git"
|
||||
)
|
||||
|
||||
type TestChecksService struct {
|
||||
CreateCheckRunError error
|
||||
}
|
||||
|
||||
func (s *TestChecksService) CreateStatus(ctx context.Context, owner, repo, ref string, status *github.RepoStatus) (*github.RepoStatus, *github.Response, error) {
|
||||
if s.CreateCheckRunError != nil {
|
||||
return nil, nil, s.CreateCheckRunError
|
||||
}
|
||||
|
||||
return &github.RepoStatus{
|
||||
ID: github.Int64(1),
|
||||
URL: status.URL,
|
||||
}, nil, nil
|
||||
}
|
||||
|
||||
func TestCreateEnterpriseRepoStatus(t *testing.T) {
|
||||
t.Run("It should create a repo status", func(t *testing.T) {
|
||||
var (
|
||||
ctx = context.Background()
|
||||
client = &TestChecksService{}
|
||||
link = "http://example.com"
|
||||
sha = "1234"
|
||||
)
|
||||
|
||||
_, err := git.CreateEnterpriseStatus(ctx, client, link, sha, "success")
|
||||
|
||||
require.NoError(t, err)
|
||||
})
|
||||
t.Run("It should return an error if GitHub fails to create the status", func(t *testing.T) {
|
||||
var (
|
||||
ctx = context.Background()
|
||||
createCheckError = errors.New("create check run error")
|
||||
client = &TestChecksService{
|
||||
CreateCheckRunError: createCheckError,
|
||||
}
|
||||
link = "http://example.com"
|
||||
sha = "1234"
|
||||
)
|
||||
|
||||
_, err := git.CreateEnterpriseStatus(ctx, client, link, sha, "success")
|
||||
require.ErrorIs(t, err, createCheckError)
|
||||
})
|
||||
}
|
||||
@@ -1,135 +0,0 @@
|
||||
package git_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-github/v45/github"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/grafana/grafana/pkg/build/git"
|
||||
)
|
||||
|
||||
type TestLabelsService struct {
|
||||
Labels []*github.Label
|
||||
ListLabelsError error
|
||||
RemoveLabelError error
|
||||
AddLabelsError error
|
||||
}
|
||||
|
||||
func (s *TestLabelsService) ListLabelsByIssue(ctx context.Context, owner string, repo string, number int, opts *github.ListOptions) ([]*github.Label, *github.Response, error) {
|
||||
if s.ListLabelsError != nil {
|
||||
return nil, nil, s.ListLabelsError
|
||||
}
|
||||
|
||||
labels := s.Labels
|
||||
if labels == nil {
|
||||
labels = []*github.Label{}
|
||||
}
|
||||
|
||||
return labels, nil, nil
|
||||
}
|
||||
|
||||
func (s *TestLabelsService) RemoveLabelForIssue(ctx context.Context, owner string, repo string, number int, label string) (*github.Response, error) {
|
||||
if s.RemoveLabelError != nil {
|
||||
return nil, s.RemoveLabelError
|
||||
}
|
||||
|
||||
return &github.Response{}, nil
|
||||
}
|
||||
|
||||
func (s *TestLabelsService) AddLabelsToIssue(ctx context.Context, owner string, repo string, number int, labels []string) ([]*github.Label, *github.Response, error) {
|
||||
if s.AddLabelsError != nil {
|
||||
return nil, nil, s.AddLabelsError
|
||||
}
|
||||
|
||||
l := make([]*github.Label, len(labels))
|
||||
for i, v := range labels {
|
||||
l[i] = &github.Label{
|
||||
Name: github.String(v),
|
||||
}
|
||||
}
|
||||
|
||||
return l, nil, nil
|
||||
}
|
||||
|
||||
func TestAddLabelToPR(t *testing.T) {
|
||||
t.Run("It should add a label to a pull request", func(t *testing.T) {
|
||||
var (
|
||||
ctx = context.Background()
|
||||
client = &TestLabelsService{}
|
||||
pr = 20
|
||||
label = "test-label"
|
||||
)
|
||||
|
||||
require.NoError(t, git.AddLabelToPR(ctx, client, pr, label))
|
||||
})
|
||||
t.Run("It should not return an error if the label already exists", func(t *testing.T) {
|
||||
var (
|
||||
ctx = context.Background()
|
||||
client = &TestLabelsService{
|
||||
Labels: []*github.Label{
|
||||
{
|
||||
Name: github.String("test-label"),
|
||||
},
|
||||
},
|
||||
}
|
||||
pr = 20
|
||||
label = "test-label"
|
||||
)
|
||||
|
||||
require.NoError(t, git.AddLabelToPR(ctx, client, pr, label))
|
||||
})
|
||||
|
||||
t.Run("It should return an error if GitHub returns an error when listing labels", func(t *testing.T) {
|
||||
var (
|
||||
ctx = context.Background()
|
||||
listLabelsError = errors.New("list labels error")
|
||||
client = &TestLabelsService{
|
||||
ListLabelsError: listLabelsError,
|
||||
Labels: []*github.Label{},
|
||||
}
|
||||
pr = 20
|
||||
label = "test-label"
|
||||
)
|
||||
|
||||
require.ErrorIs(t, git.AddLabelToPR(ctx, client, pr, label), listLabelsError)
|
||||
})
|
||||
|
||||
t.Run("It should not return an error if there are existing enterprise-check labels.", func(t *testing.T) {
|
||||
var (
|
||||
ctx = context.Background()
|
||||
client = &TestLabelsService{
|
||||
Labels: []*github.Label{
|
||||
{
|
||||
Name: github.String("enterprise-failed"),
|
||||
},
|
||||
},
|
||||
}
|
||||
pr = 20
|
||||
label = "test-label"
|
||||
)
|
||||
|
||||
require.NoError(t, git.AddLabelToPR(ctx, client, pr, label))
|
||||
})
|
||||
|
||||
t.Run("It should return an error if GitHub returns an error when removing existing enterprise-check labels", func(t *testing.T) {
|
||||
var (
|
||||
ctx = context.Background()
|
||||
removeLabelError = errors.New("remove label error")
|
||||
client = &TestLabelsService{
|
||||
RemoveLabelError: removeLabelError,
|
||||
Labels: []*github.Label{
|
||||
{
|
||||
Name: github.String("enterprise-failed"),
|
||||
},
|
||||
},
|
||||
}
|
||||
pr = 20
|
||||
label = "test-label"
|
||||
)
|
||||
|
||||
require.ErrorIs(t, git.AddLabelToPR(ctx, client, pr, label), removeLabelError)
|
||||
})
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
package git_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/grafana/grafana/pkg/build/git"
|
||||
)
|
||||
|
||||
func TestPRCheckRegexp(t *testing.T) {
|
||||
type match struct {
|
||||
String string
|
||||
Commit string
|
||||
Branch string
|
||||
PR string
|
||||
}
|
||||
|
||||
var (
|
||||
shouldMatch = []match{
|
||||
{
|
||||
String: "prc-1-a1b2c3d4/branch-name",
|
||||
Branch: "branch-name",
|
||||
Commit: "a1b2c3d4",
|
||||
PR: "1",
|
||||
},
|
||||
{
|
||||
String: "prc-111-a1b2c3d4/branch/name",
|
||||
Branch: "branch/name",
|
||||
Commit: "a1b2c3d4",
|
||||
PR: "111",
|
||||
},
|
||||
{
|
||||
String: "prc-102930122-a1b2c3d4/branch-name",
|
||||
Branch: "branch-name",
|
||||
Commit: "a1b2c3d4",
|
||||
PR: "102930122",
|
||||
},
|
||||
}
|
||||
|
||||
shouldNotMatch = []string{"prc-a/branch", "km/test", "test", "prc", "prc/test", "price"}
|
||||
)
|
||||
|
||||
regex := git.PRCheckRegexp()
|
||||
|
||||
for _, v := range shouldMatch {
|
||||
assert.Truef(t, regex.MatchString(v.String), "regex '%s' should match %s", regex.String(), v)
|
||||
m := regex.FindStringSubmatch(v.String)
|
||||
assert.Equal(t, m[1], v.PR)
|
||||
assert.Equal(t, m[2], v.Commit)
|
||||
assert.Equal(t, m[3], v.Branch)
|
||||
}
|
||||
|
||||
for _, v := range shouldNotMatch {
|
||||
assert.False(t, regex.MatchString(v), "regex '%s' should not match %s", regex.String(), v)
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
module github.com/grafana/grafana/pkg/build
|
||||
|
||||
go 1.22.4
|
||||
go 1.22.7
|
||||
|
||||
// Override docker/docker to avoid:
|
||||
// go: github.com/drone-runners/drone-runner-docker@v1.8.2 requires
|
||||
|
||||
@@ -1,124 +0,0 @@
|
||||
package golangutils
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"github.com/grafana/grafana/pkg/build/config"
|
||||
)
|
||||
|
||||
type BuildOpts struct {
|
||||
// Package refers to the path to the `main` package containing `func main`
|
||||
Package string
|
||||
|
||||
// Output is used as the -o argument in the go build command
|
||||
Output string
|
||||
|
||||
// Workdir should define some place in the module where the package path resolves.
|
||||
// Go commands need to be ran inside a the Go module directory.
|
||||
Workdir string
|
||||
|
||||
GoOS config.OS
|
||||
GoArch config.Architecture
|
||||
GoArm string
|
||||
Go386 string
|
||||
CC string
|
||||
LibC string
|
||||
|
||||
CGoEnabled bool
|
||||
CGoCFlags string
|
||||
|
||||
// LdFlags are joined by a space character and provided to the -ldflags argument.
|
||||
// A valid element here would be `-X 'main.version=1.0.0'`.
|
||||
LdFlags []string
|
||||
|
||||
Stdout io.ReadWriter
|
||||
Stderr io.ReadWriter
|
||||
Stdin io.ReadWriter
|
||||
|
||||
// ExtraEnv allows consumers to provide extra env args that are not defined above.
|
||||
// A single element should be formatted using like so: {NAME}={VALUE}. Example: GOOS=linux.
|
||||
ExtraEnv []string
|
||||
|
||||
// ExtraArgs allows consumers to provide extra arguments that are not defined above.
|
||||
// Flag names and values should be two separate elements.
|
||||
// These flags will be appended to the command arguments before the package path in "go build".
|
||||
ExtraArgs []string
|
||||
}
|
||||
|
||||
// Env constructs a list of key/value pairs for setting a build command's environment.
|
||||
// Should we consider using something to unmarshal the struct to env?
|
||||
func (opts BuildOpts) Env() []string {
|
||||
env := []string{}
|
||||
if opts.CGoEnabled {
|
||||
env = append(env, "CGO_ENABLED=1")
|
||||
}
|
||||
|
||||
if opts.GoOS != "" {
|
||||
env = append(env, fmt.Sprintf("GOOS=%s", opts.GoOS))
|
||||
}
|
||||
|
||||
if opts.GoArch != "" {
|
||||
env = append(env, fmt.Sprintf("GOARCH=%s", opts.GoArch))
|
||||
}
|
||||
|
||||
if opts.CC != "" {
|
||||
env = append(env, fmt.Sprintf("CC=%s", opts.CC))
|
||||
}
|
||||
|
||||
if opts.CGoCFlags != "" {
|
||||
env = append(env, fmt.Sprintf("CGO_CFLAGS=%s", opts.CGoCFlags))
|
||||
}
|
||||
|
||||
if opts.GoArm != "" {
|
||||
env = append(env, fmt.Sprintf("GOARM=%s", opts.GoArm))
|
||||
}
|
||||
|
||||
if opts.ExtraEnv != nil {
|
||||
return append(opts.ExtraEnv, env...)
|
||||
}
|
||||
|
||||
return env
|
||||
}
|
||||
|
||||
// Args constructs a list of flags and values for use with the exec.Command type when running "go build".
|
||||
func (opts BuildOpts) Args() []string {
|
||||
args := []string{}
|
||||
|
||||
if opts.LdFlags != nil {
|
||||
args = append(args, "-ldflags", strings.Join(opts.LdFlags, " "))
|
||||
}
|
||||
|
||||
if opts.Output != "" {
|
||||
args = append(args, "-o", opts.Output)
|
||||
}
|
||||
|
||||
if opts.ExtraArgs != nil {
|
||||
args = append(args, opts.ExtraArgs...)
|
||||
}
|
||||
|
||||
args = append(args, opts.Package)
|
||||
|
||||
return args
|
||||
}
|
||||
|
||||
// Build runs the go build process in the current shell given the opts.
|
||||
// This function will panic if no Stdout/Stderr/Stdin is provided in the opts.
|
||||
func RunBuild(ctx context.Context, opts BuildOpts) error {
|
||||
env := opts.Env()
|
||||
args := append([]string{"build"}, opts.Args()...)
|
||||
// Ignore gosec G304 as this function is only used in the build process.
|
||||
//nolint:gosec
|
||||
cmd := exec.CommandContext(ctx, "go", args...)
|
||||
cmd.Env = env
|
||||
|
||||
cmd.Stdout = opts.Stdout
|
||||
cmd.Stderr = opts.Stderr
|
||||
cmd.Stdin = opts.Stdin
|
||||
cmd.Dir = opts.Workdir
|
||||
|
||||
return cmd.Run()
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
// Package golangutils holds utility functions, wrappers, and types for building Go binaries for Grafana.
|
||||
package golangutils
|
||||
@@ -1,73 +0,0 @@
|
||||
package gpg
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/grafana/grafana/pkg/build/config"
|
||||
"github.com/grafana/grafana/pkg/build/fsutil"
|
||||
)
|
||||
|
||||
// LoadGPGKeys loads GPG key pair and password from the environment and writes them to corresponding files.
|
||||
//
|
||||
// The passed config's GPG fields also get updated. Make sure to call RemoveGPGFiles at application exit.
|
||||
func LoadGPGKeys(cfg *config.Config) error {
|
||||
var err error
|
||||
cfg.GPGPrivateKey, err = fsutil.CreateTempFile("priv.key")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cfg.GPGPublicKey, err = fsutil.CreateTempFile("pub.key")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cfg.GPGPassPath, err = fsutil.CreateTempFile("")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
gpgPrivKey := os.Getenv("GPG_PRIV_KEY")
|
||||
if gpgPrivKey == "" {
|
||||
return fmt.Errorf("$GPG_PRIV_KEY must be defined")
|
||||
}
|
||||
gpgPubKey := os.Getenv("GPG_PUB_KEY")
|
||||
if gpgPubKey == "" {
|
||||
return fmt.Errorf("$GPG_PUB_KEY must be defined")
|
||||
}
|
||||
gpgPass := os.Getenv("GPG_KEY_PASSWORD")
|
||||
if gpgPass == "" {
|
||||
return fmt.Errorf("$GPG_KEY_PASSWORD must be defined")
|
||||
}
|
||||
|
||||
gpgPrivKeyB, err := base64.StdEncoding.DecodeString(gpgPrivKey)
|
||||
if err != nil {
|
||||
return fmt.Errorf("couldn't decode $GPG_PRIV_KEY: %w", err)
|
||||
}
|
||||
gpgPubKeyB, err := base64.StdEncoding.DecodeString(gpgPubKey)
|
||||
if err != nil {
|
||||
return fmt.Errorf("couldn't decode $GPG_PUB_KEY: %w", err)
|
||||
}
|
||||
|
||||
if err := os.WriteFile(cfg.GPGPrivateKey, append(gpgPrivKeyB, '\n'), 0400); err != nil {
|
||||
return fmt.Errorf("failed to write GPG private key file: %w", err)
|
||||
}
|
||||
if err := os.WriteFile(cfg.GPGPublicKey, append(gpgPubKeyB, '\n'), 0400); err != nil {
|
||||
return fmt.Errorf("failed to write GPG public key file: %w", err)
|
||||
}
|
||||
if err := os.WriteFile(cfg.GPGPassPath, []byte(gpgPass+"\n"), 0400); err != nil {
|
||||
return fmt.Errorf("failed to write GPG password file: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoveGPGFiles removes configured GPG files.
|
||||
func RemoveGPGFiles(cfg config.Config) {
|
||||
for _, fpath := range []string{cfg.GPGPrivateKey, cfg.GPGPublicKey, cfg.GPGPassPath} {
|
||||
if err := os.Remove(fpath); err != nil {
|
||||
log.Printf("failed to remove %q", fpath)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
package gpg
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/grafana/grafana/pkg/build/config"
|
||||
"github.com/grafana/grafana/pkg/build/fsutil"
|
||||
)
|
||||
|
||||
// writeRpmMacros writes ~/.rpmmacros.
|
||||
func writeRpmMacros(homeDir, gpgPassPath string) error {
|
||||
fpath := filepath.Join(homeDir, ".rpmmacros")
|
||||
content := fmt.Sprintf(`%%_signature gpg
|
||||
%%_gpg_path %s/.gnupg
|
||||
%%_gpg_name Grafana
|
||||
%%_gpgbin /usr/bin/gpg
|
||||
%%__gpg_sign_cmd %%{__gpg} gpg --batch --yes --pinentry-mode loopback --no-armor --passphrase-file %s --no-secmem-warning -u "%%{_gpg_name}" -sbo %%{__signature_filename} %%{__plaintext_filename}
|
||||
`, homeDir, gpgPassPath)
|
||||
//nolint:gosec
|
||||
if err := os.WriteFile(fpath, []byte(content), 0600); err != nil {
|
||||
return fmt.Errorf("failed to write %q: %w", fpath, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Import imports the GPG package signing key.
|
||||
// ~/.rpmmacros also gets written.
|
||||
func Import(cfg config.Config) error {
|
||||
exists, err := fsutil.Exists(cfg.GPGPrivateKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !exists {
|
||||
return fmt.Errorf("GPG private key file doesn't exist: %q", cfg.GPGPrivateKey)
|
||||
}
|
||||
|
||||
log.Printf("Importing GPG key %q...", cfg.GPGPrivateKey)
|
||||
// nolint:gosec
|
||||
cmd := exec.Command("gpg", "--batch", "--yes", "--no-tty", "--allow-secret-key-import", "--import",
|
||||
cfg.GPGPrivateKey)
|
||||
if output, err := cmd.CombinedOutput(); err != nil {
|
||||
return fmt.Errorf("failed to import private key: %s", output)
|
||||
}
|
||||
|
||||
homeDir, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := writeRpmMacros(homeDir, cfg.GPGPassPath); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pubKeysPath := filepath.Join(homeDir, ".rpmdb", "pubkeys")
|
||||
if err := os.MkdirAll(pubKeysPath, 0700); err != nil {
|
||||
return fmt.Errorf("failed to make %s: %w", pubKeysPath, err)
|
||||
}
|
||||
gpgPub, err := os.ReadFile(cfg.GPGPublicKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
//nolint:gosec
|
||||
if err := os.WriteFile(filepath.Join(homeDir, ".rpmdb", "pubkeys", "grafana.key"), gpgPub, 0400); err != nil {
|
||||
return fmt.Errorf("failed to write pub key to ~/.rpmdb: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,129 +0,0 @@
|
||||
package grafana
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/grafana/grafana/pkg/build/config"
|
||||
"github.com/grafana/grafana/pkg/build/cryptoutil"
|
||||
"github.com/grafana/grafana/pkg/build/golangutils"
|
||||
)
|
||||
|
||||
var binaries = []string{"grafana", "grafana-server", "grafana-cli"}
|
||||
|
||||
const (
|
||||
SuffixEnterprise2 = "-enterprise2"
|
||||
)
|
||||
|
||||
const (
|
||||
ExtensionExe = ".exe"
|
||||
)
|
||||
|
||||
func GrafanaLDFlags(version string, r config.Revision) []string {
|
||||
cmd := []string{
|
||||
"-w",
|
||||
fmt.Sprintf("-X main.version=%s", version),
|
||||
fmt.Sprintf("-X main.commit=%s", r.SHA256),
|
||||
fmt.Sprintf("-X main.buildstamp=%d", r.Timestamp),
|
||||
fmt.Sprintf("-X main.buildBranch=%s", r.Branch),
|
||||
}
|
||||
|
||||
if r.EnterpriseCommit != "" {
|
||||
cmd = append(cmd, fmt.Sprintf("-X main.enterpriseCommit=%s", r.EnterpriseCommit))
|
||||
}
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
// BinaryFolder returns the path to where the Grafana binary is build given the provided arguments.
|
||||
func BinaryFolder(edition config.Edition, args BuildArgs) string {
|
||||
sfx := ""
|
||||
if edition == config.EditionEnterprise2 {
|
||||
sfx = SuffixEnterprise2
|
||||
}
|
||||
|
||||
arch := string(args.GoArch)
|
||||
if args.GoArch == config.ArchARM {
|
||||
arch = string(args.GoArch) + "v" + args.GoArm
|
||||
}
|
||||
|
||||
format := fmt.Sprintf("%s-%s", args.GoOS, arch)
|
||||
if args.LibC != "" {
|
||||
format += fmt.Sprintf("-%s", args.LibC)
|
||||
}
|
||||
format += sfx
|
||||
|
||||
if args.GoOS == config.OSWindows {
|
||||
format += ExtensionExe
|
||||
}
|
||||
|
||||
return format
|
||||
}
|
||||
|
||||
func GrafanaDescriptor(opts golangutils.BuildOpts) string {
|
||||
libcPart := ""
|
||||
if opts.LibC != "" {
|
||||
libcPart = fmt.Sprintf("/%s", opts.LibC)
|
||||
}
|
||||
arch := string(opts.GoArch)
|
||||
if opts.GoArch == config.ArchARM {
|
||||
arch = string(opts.GoArch) + "v" + opts.GoArm
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s/%s%s", opts.GoOS, arch, libcPart)
|
||||
}
|
||||
|
||||
// BuildGrafanaBinary builds a certain binary according to certain parameters.
|
||||
func BuildGrafanaBinary(ctx context.Context, name, version string, args BuildArgs, edition config.Edition) error {
|
||||
opts := args.BuildOpts
|
||||
opts.ExtraEnv = os.Environ()
|
||||
|
||||
revision, err := config.GrafanaRevision(ctx, opts.Workdir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
folder := BinaryFolder(edition, args)
|
||||
|
||||
if opts.GoOS == config.OSWindows {
|
||||
name += ExtensionExe
|
||||
}
|
||||
|
||||
binary := filepath.Join(opts.Workdir, "bin", folder, name)
|
||||
opts.Output = binary
|
||||
|
||||
if err := os.RemoveAll(binary); err != nil {
|
||||
return fmt.Errorf("failed to remove %q: %w", binary, err)
|
||||
}
|
||||
|
||||
if err := os.RemoveAll(binary + ".md5"); err != nil {
|
||||
return fmt.Errorf("failed to remove %q: %w", binary+".md5", err)
|
||||
}
|
||||
|
||||
descriptor := GrafanaDescriptor(opts)
|
||||
|
||||
log.Printf("Building %q for %s", binary, descriptor)
|
||||
|
||||
opts.LdFlags = append(args.LdFlags, GrafanaLDFlags(version, revision)...)
|
||||
|
||||
if edition == config.EditionEnterprise2 {
|
||||
opts.ExtraArgs = []string{"-tags=pro"}
|
||||
}
|
||||
|
||||
log.Printf("Running command 'go %s'", opts.Args())
|
||||
|
||||
if err := golangutils.RunBuild(ctx, opts); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create an MD5 checksum of the binary, to be included in the archive for
|
||||
// automatic upgrades.
|
||||
if err := cryptoutil.MD5File(binary); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,160 +1 @@
|
||||
package grafana
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/grafana/grafana/pkg/build/compilers"
|
||||
"github.com/grafana/grafana/pkg/build/config"
|
||||
"github.com/grafana/grafana/pkg/build/golangutils"
|
||||
)
|
||||
|
||||
// BuildArgs represent the build parameters that define the "go build" behavior of a single variant.
|
||||
// These arguments are applied as environment variables and arguments to the "go build" command.
|
||||
type BuildArgs struct {
|
||||
golangutils.BuildOpts
|
||||
DebArch config.Architecture
|
||||
RPMArch config.Architecture
|
||||
}
|
||||
|
||||
type BuildVariantOpts struct {
|
||||
Variant config.Variant
|
||||
Edition config.Edition
|
||||
|
||||
Version string
|
||||
GrafanaDir string
|
||||
}
|
||||
|
||||
// BuildVariant builds a certain variant of the grafana-server and grafana-cli binaries sequentially.
|
||||
func BuildVariant(ctx context.Context, opts BuildVariantOpts) error {
|
||||
grafanaDir, err := filepath.Abs(opts.GrafanaDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var (
|
||||
args = VariantBuildArgs(opts.Variant)
|
||||
)
|
||||
|
||||
for _, binary := range binaries {
|
||||
// Note that for Golang cmd paths we must use the relative path and the Linux file separators (/) even for Windows users.
|
||||
var (
|
||||
pkg = fmt.Sprintf("./pkg/cmd/%s", binary)
|
||||
stdout = bytes.NewBuffer(nil)
|
||||
stderr = bytes.NewBuffer(nil)
|
||||
)
|
||||
|
||||
args.Workdir = grafanaDir
|
||||
args.Stdout = stdout
|
||||
args.Stderr = stderr
|
||||
args.Package = pkg
|
||||
|
||||
if err := BuildGrafanaBinary(ctx, binary, opts.Version, args, opts.Edition); err != nil {
|
||||
return fmt.Errorf("failed to build %s for %s: %w\nstdout: %s\nstderr: %s", pkg, opts.Variant, err, stdout.String(), stderr.String())
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var ldFlagsStatic = []string{"-linkmode=external", "-extldflags=-static"}
|
||||
|
||||
var variantArgs = map[config.Variant]BuildArgs{
|
||||
config.VariantArmV6: {
|
||||
BuildOpts: golangutils.BuildOpts{
|
||||
GoOS: config.OSLinux,
|
||||
CGoEnabled: true,
|
||||
GoArch: config.ArchARM,
|
||||
GoArm: "6",
|
||||
CC: compilers.ArmV6,
|
||||
},
|
||||
DebArch: config.ArchARMHF,
|
||||
},
|
||||
config.VariantArmV7: {
|
||||
BuildOpts: golangutils.BuildOpts{
|
||||
GoOS: config.OSLinux,
|
||||
CGoEnabled: true,
|
||||
GoArch: config.ArchARM,
|
||||
GoArm: "7",
|
||||
CC: compilers.Armv7,
|
||||
},
|
||||
DebArch: config.ArchARMHF,
|
||||
RPMArch: config.ArchARMHFP,
|
||||
},
|
||||
config.VariantArmV7Musl: {
|
||||
BuildOpts: golangutils.BuildOpts{
|
||||
GoOS: config.OSLinux,
|
||||
CGoEnabled: true,
|
||||
GoArch: config.ArchARM,
|
||||
GoArm: "7",
|
||||
LibC: config.LibCMusl,
|
||||
CC: compilers.Armv7Musl,
|
||||
LdFlags: ldFlagsStatic,
|
||||
},
|
||||
},
|
||||
config.VariantArm64: {
|
||||
BuildOpts: golangutils.BuildOpts{
|
||||
GoOS: config.OSLinux,
|
||||
CGoEnabled: true,
|
||||
GoArch: config.ArchARM64,
|
||||
CC: compilers.Arm64,
|
||||
},
|
||||
DebArch: config.ArchARM64,
|
||||
RPMArch: "aarch64",
|
||||
},
|
||||
config.VariantArm64Musl: {
|
||||
BuildOpts: golangutils.BuildOpts{
|
||||
GoOS: config.OSLinux,
|
||||
GoArch: config.ArchARM64,
|
||||
CGoEnabled: true,
|
||||
CC: compilers.Arm64Musl,
|
||||
LibC: config.LibCMusl,
|
||||
LdFlags: ldFlagsStatic,
|
||||
},
|
||||
},
|
||||
config.VariantDarwinAmd64: {
|
||||
BuildOpts: golangutils.BuildOpts{
|
||||
GoOS: config.OSDarwin,
|
||||
CGoEnabled: true,
|
||||
GoArch: config.ArchAMD64,
|
||||
CC: compilers.Osx64,
|
||||
},
|
||||
},
|
||||
config.VariantWindowsAmd64: {
|
||||
BuildOpts: golangutils.BuildOpts{
|
||||
GoOS: config.OSWindows,
|
||||
GoArch: config.ArchAMD64,
|
||||
CC: compilers.Win64,
|
||||
CGoEnabled: true,
|
||||
CGoCFlags: "-D_WIN32_WINNT=0x0601",
|
||||
},
|
||||
},
|
||||
config.VariantLinuxAmd64: {
|
||||
BuildOpts: golangutils.BuildOpts{
|
||||
GoOS: config.OSLinux,
|
||||
GoArch: config.ArchAMD64,
|
||||
CC: compilers.LinuxX64,
|
||||
},
|
||||
DebArch: config.ArchAMD64,
|
||||
RPMArch: config.ArchAMD64,
|
||||
},
|
||||
config.VariantLinuxAmd64Musl: {
|
||||
BuildOpts: golangutils.BuildOpts{
|
||||
GoOS: config.OSLinux,
|
||||
GoArch: config.ArchAMD64,
|
||||
CC: compilers.LinuxX64Musl,
|
||||
LibC: config.LibCMusl,
|
||||
LdFlags: ldFlagsStatic,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func VariantBuildArgs(v config.Variant) BuildArgs {
|
||||
if val, ok := variantArgs[v]; ok {
|
||||
return val
|
||||
}
|
||||
|
||||
return BuildArgs{}
|
||||
}
|
||||
|
||||
@@ -2,63 +2,13 @@ package lerna
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/grafana/grafana/pkg/build/config"
|
||||
"github.com/grafana/grafana/pkg/build/fsutil"
|
||||
)
|
||||
|
||||
// BuildFrontendPackages will bump the version for the package to the latest canary build
|
||||
// and build the packages so they are ready for being published, used for generating docs etc.
|
||||
func BuildFrontendPackages(version string, mode config.Edition, grafanaDir string) error {
|
||||
err := bumpLernaVersion(version, grafanaDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cmd := exec.Command("yarn", "run", "packages:build")
|
||||
cmd.Dir = grafanaDir
|
||||
if output, err := cmd.CombinedOutput(); err != nil {
|
||||
return fmt.Errorf("failed to build %s frontend packages: %s", mode, output)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func bumpLernaVersion(version string, grafanaDir string) error {
|
||||
//nolint:gosec
|
||||
cmd := exec.Command("yarn", "run", "lerna", "version", version, "--exact", "--no-git-tag-version", "--no-push", "--force-publish", "-y")
|
||||
cmd.Dir = grafanaDir
|
||||
if output, err := cmd.CombinedOutput(); err != nil {
|
||||
return fmt.Errorf("failed to bump version for frontend packages: %s\n%s", err, output)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetLernaVersion(grafanaDir string) (string, error) {
|
||||
lernaJSONPath := filepath.Join(grafanaDir, "lerna.json")
|
||||
//nolint:gosec
|
||||
lernaJSONB, err := os.ReadFile(lernaJSONPath)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to read %q: %w", lernaJSONPath, err)
|
||||
}
|
||||
pkgObj := map[string]any{}
|
||||
if err := json.Unmarshal(lernaJSONB, &pkgObj); err != nil {
|
||||
return "", fmt.Errorf("failed decoding %q: %w", lernaJSONPath, err)
|
||||
}
|
||||
|
||||
version := pkgObj["version"].(string)
|
||||
if version == "" {
|
||||
return "", fmt.Errorf("failed to read version from %q", lernaJSONPath)
|
||||
}
|
||||
return strings.TrimSpace(version), nil
|
||||
}
|
||||
|
||||
func PackFrontendPackages(ctx context.Context, tag, grafanaDir, artifactsDir string) error {
|
||||
exists, err := fsutil.Exists(artifactsDir)
|
||||
if err != nil {
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
package packaging
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/grafana/grafana/pkg/build/config"
|
||||
)
|
||||
|
||||
@@ -12,11 +9,18 @@ const MainFolder = "main"
|
||||
const EnterpriseSfx = "-enterprise"
|
||||
const CacheSettings = "Cache-Control:public, max-age="
|
||||
|
||||
type buildArtifact struct {
|
||||
Os string
|
||||
Arch string
|
||||
urlPostfix string
|
||||
packagePostfix string
|
||||
type BuildArtifact struct {
|
||||
// Distro can be "windows", "darwin", "deb", "rhel", or "linux"
|
||||
Distro string
|
||||
Arch string
|
||||
// Ext is the file extension without the "."
|
||||
Ext string
|
||||
Musl bool
|
||||
RaspberryPi bool
|
||||
|
||||
// URL can be set optionally by another process
|
||||
// Note: check other repos before determining this to be dead code
|
||||
URL string
|
||||
}
|
||||
|
||||
type PublishConfig struct {
|
||||
@@ -32,110 +36,91 @@ type PublishConfig struct {
|
||||
SimulateRelease bool
|
||||
}
|
||||
|
||||
const rhelOS = "rhel"
|
||||
const debOS = "deb"
|
||||
|
||||
func (t buildArtifact) GetURL(baseArchiveURL string, cfg PublishConfig) string {
|
||||
rev := ""
|
||||
prefix := "-"
|
||||
if t.Os == debOS {
|
||||
prefix = "_"
|
||||
} else if t.Os == rhelOS {
|
||||
rev = "-1"
|
||||
}
|
||||
|
||||
version := cfg.Version
|
||||
verComponents := strings.Split(version, "-")
|
||||
if len(verComponents) > 2 {
|
||||
panic(fmt.Sprintf("Version string contains more than one hyphen: %q", version))
|
||||
}
|
||||
|
||||
switch t.Os {
|
||||
case debOS, rhelOS:
|
||||
if len(verComponents) > 1 {
|
||||
// With Debian and RPM packages, it's customary to prefix any pre-release component with a ~, since this
|
||||
// is considered of lower lexical value than the empty character, and this way pre-release versions are
|
||||
// considered to be of a lower version than the final version (which lacks this suffix).
|
||||
version = fmt.Sprintf("%s~%s", verComponents[0], verComponents[1])
|
||||
}
|
||||
}
|
||||
|
||||
// https://dl.grafana.com/oss/main/grafana_8.5.0~54094pre_armhf.deb: 404 Not Found
|
||||
url := fmt.Sprintf("%s%s%s%s%s%s", baseArchiveURL, t.packagePostfix, prefix, version, rev, t.urlPostfix)
|
||||
return url
|
||||
}
|
||||
|
||||
var ArtifactConfigs = []buildArtifact{
|
||||
var LinuxArtifacts = []BuildArtifact{
|
||||
{
|
||||
Os: debOS,
|
||||
Arch: "arm64",
|
||||
urlPostfix: "_arm64.deb",
|
||||
Distro: "linux",
|
||||
Arch: "arm64",
|
||||
Ext: "tar.gz",
|
||||
},
|
||||
{
|
||||
Os: rhelOS,
|
||||
Arch: "arm64",
|
||||
urlPostfix: ".aarch64.rpm",
|
||||
Distro: "deb",
|
||||
Arch: "amd64",
|
||||
Ext: "deb",
|
||||
},
|
||||
{
|
||||
Os: "linux",
|
||||
Arch: "arm64",
|
||||
urlPostfix: ".linux-arm64.tar.gz",
|
||||
},
|
||||
// https://github.com/golang/go/issues/58425 disabling arm builds until go issue is resolved
|
||||
// {
|
||||
// Os: debOS,
|
||||
// Arch: "armv7",
|
||||
// urlPostfix: "_armhf.deb",
|
||||
// },
|
||||
// {
|
||||
// Os: debOS,
|
||||
// Arch: "armv6",
|
||||
// packagePostfix: "-rpi",
|
||||
// urlPostfix: "_armhf.deb",
|
||||
// },
|
||||
// {
|
||||
// Os: rhelOS,
|
||||
// Arch: "armv7",
|
||||
// urlPostfix: ".armhfp.rpm",
|
||||
// },
|
||||
// {
|
||||
// Os: "linux",
|
||||
// Arch: "armv6",
|
||||
// urlPostfix: ".linux-armv6.tar.gz",
|
||||
// },
|
||||
// {
|
||||
// Os: "linux",
|
||||
// Arch: "armv7",
|
||||
// urlPostfix: ".linux-armv7.tar.gz",
|
||||
// },
|
||||
{
|
||||
Os: "darwin",
|
||||
Arch: "amd64",
|
||||
urlPostfix: ".darwin-amd64.tar.gz",
|
||||
Distro: "rhel",
|
||||
Arch: "x86_64",
|
||||
Ext: "rpm",
|
||||
},
|
||||
{
|
||||
Os: "deb",
|
||||
Arch: "amd64",
|
||||
urlPostfix: "_amd64.deb",
|
||||
},
|
||||
{
|
||||
Os: rhelOS,
|
||||
Arch: "amd64",
|
||||
urlPostfix: ".x86_64.rpm",
|
||||
},
|
||||
{
|
||||
Os: "linux",
|
||||
Arch: "amd64",
|
||||
urlPostfix: ".linux-amd64.tar.gz",
|
||||
},
|
||||
{
|
||||
Os: "win",
|
||||
Arch: "amd64",
|
||||
urlPostfix: ".windows-amd64.zip",
|
||||
},
|
||||
{
|
||||
Os: "win-installer",
|
||||
Arch: "amd64",
|
||||
urlPostfix: ".windows-amd64.msi",
|
||||
Distro: "linux",
|
||||
Arch: "amd64",
|
||||
Ext: "tar.gz",
|
||||
},
|
||||
}
|
||||
|
||||
var DarwinArtifacts = []BuildArtifact{
|
||||
{
|
||||
Distro: "darwin",
|
||||
Arch: "amd64",
|
||||
Ext: "tar.gz",
|
||||
},
|
||||
}
|
||||
|
||||
var WindowsArtifacts = []BuildArtifact{
|
||||
{
|
||||
Distro: "windows",
|
||||
Arch: "amd64",
|
||||
Ext: "zip",
|
||||
},
|
||||
{
|
||||
Distro: "windows",
|
||||
Arch: "amd64",
|
||||
Ext: "msi",
|
||||
},
|
||||
}
|
||||
|
||||
var ARMArtifacts = []BuildArtifact{
|
||||
{
|
||||
Distro: "deb",
|
||||
Arch: "arm64",
|
||||
Ext: "deb",
|
||||
},
|
||||
{
|
||||
Distro: "rhel",
|
||||
Arch: "aarch64",
|
||||
Ext: "rpm",
|
||||
},
|
||||
{
|
||||
Distro: "deb",
|
||||
Arch: "armhf",
|
||||
Ext: "deb",
|
||||
RaspberryPi: false,
|
||||
},
|
||||
{
|
||||
Distro: "deb",
|
||||
Arch: "armhf",
|
||||
RaspberryPi: true,
|
||||
Ext: "deb",
|
||||
},
|
||||
{
|
||||
Distro: "linux",
|
||||
Arch: "armv6",
|
||||
Ext: "tar.gz",
|
||||
},
|
||||
{
|
||||
Distro: "linux",
|
||||
Arch: "armv7",
|
||||
Ext: "tar.gz",
|
||||
},
|
||||
}
|
||||
|
||||
func join(a []BuildArtifact, b ...[]BuildArtifact) []BuildArtifact {
|
||||
for i := range b {
|
||||
a = append(a, b[i]...)
|
||||
}
|
||||
|
||||
return a
|
||||
}
|
||||
|
||||
var ArtifactConfigs = join(LinuxArtifacts, DarwinArtifacts, WindowsArtifacts, ARMArtifacts)
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
// Package packaging holds functions and types for creating the tar.gz, deb, and rpm packages of Grafana.
|
||||
package packaging
|
||||
@@ -1 +0,0 @@
|
||||
package packaging
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,23 +0,0 @@
|
||||
package packaging_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/grafana/grafana/pkg/build/config"
|
||||
"github.com/grafana/grafana/pkg/build/packaging"
|
||||
)
|
||||
|
||||
func TestPackageRegexp(t *testing.T) {
|
||||
t.Run("It should match enterprise2 packages", func(t *testing.T) {
|
||||
rgx := packaging.PackageRegexp(config.EditionEnterprise2)
|
||||
matches := []string{
|
||||
"grafana-enterprise2-1.2.3-4567pre.linux-amd64.tar.gz",
|
||||
"grafana-enterprise2-1.2.3-4567pre.linux-amd64.tar.gz.sha256",
|
||||
}
|
||||
for _, v := range matches {
|
||||
assert.Truef(t, rgx.MatchString(v), "'%s' should match regex '%s'", v, rgx.String())
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
package plugins
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/grafana/grafana/pkg/build/config"
|
||||
"github.com/grafana/grafana/pkg/build/errutil"
|
||||
"github.com/grafana/grafana/pkg/build/fsutil"
|
||||
"github.com/grafana/grafana/pkg/build/syncutil"
|
||||
)
|
||||
|
||||
type PluginSigningMode = int
|
||||
|
||||
// BuildPlugins builds internal plugins.
|
||||
// The built plugins are placed in plugins-bundled/dist/.
|
||||
func Build(ctx context.Context, grafanaDir string, p syncutil.WorkerPool, g *errutil.Group, verMode *config.BuildConfig) error {
|
||||
log.Printf("Building plugins in %q...", grafanaDir)
|
||||
|
||||
root := filepath.Join(grafanaDir, "plugins-bundled", "internal")
|
||||
fis, err := os.ReadDir(root)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := range fis {
|
||||
fi := fis[i]
|
||||
if !fi.IsDir() {
|
||||
continue
|
||||
}
|
||||
|
||||
dpath := filepath.Join(root, fi.Name())
|
||||
|
||||
p.Schedule(g.Wrap(func() error {
|
||||
log.Printf("Building plugin %q...", dpath)
|
||||
|
||||
cmd := exec.Command("yarn", "build")
|
||||
cmd.Dir = dpath
|
||||
if output, err := cmd.CombinedOutput(); err != nil {
|
||||
return fmt.Errorf("yarn build failed: %s", output)
|
||||
}
|
||||
|
||||
dstPath := filepath.Join("plugins-bundled", "dist", fi.Name())
|
||||
if err := fsutil.CopyRecursive(filepath.Join(dpath, "dist"), dstPath); err != nil {
|
||||
return err
|
||||
}
|
||||
if !verMode.PluginSignature.Sign {
|
||||
return nil
|
||||
}
|
||||
|
||||
return BuildManifest(ctx, dstPath, verMode.PluginSignature.AdminSign)
|
||||
}))
|
||||
}
|
||||
|
||||
if err := g.Wait(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Printf("Built all plug-ins successfully!")
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,118 +0,0 @@
|
||||
package plugins
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/grafana/grafana/pkg/build/errutil"
|
||||
"github.com/grafana/grafana/pkg/build/syncutil"
|
||||
)
|
||||
|
||||
// logCloseError executes the closeFunc; if it returns an error, it is logged by the log package.
|
||||
func logCloseError(closeFunc func() error) {
|
||||
if err := closeFunc(); err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
// logCloseError executes the closeFunc; if it returns an error, it is logged by the log package.
|
||||
func logError(err error) {
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
// pluginManifest has details of an external plugin package.
|
||||
type pluginManifest struct {
|
||||
Name string `json:"name"`
|
||||
Version string `json:"version"`
|
||||
Checksum string `json:"checksum"`
|
||||
}
|
||||
|
||||
// pluginsManifest represents a manifest of Grafana's external plugins.
|
||||
type pluginsManifest struct {
|
||||
Plugins []pluginManifest `json:"plugins"`
|
||||
}
|
||||
|
||||
// downloadPlugins downloads Grafana plugins that should be bundled into packages.
|
||||
//
|
||||
// The plugin archives are downloaded into <grafanaDir>/plugins-bundled.
|
||||
func Download(ctx context.Context, grafanaDir string, p syncutil.WorkerPool) error {
|
||||
g, _ := errutil.GroupWithContext(ctx)
|
||||
|
||||
log.Println("Downloading external plugins...")
|
||||
|
||||
var m pluginsManifest
|
||||
manifestPath := filepath.Join(grafanaDir, "plugins-bundled", "external.json")
|
||||
//nolint:gosec
|
||||
manifestB, err := os.ReadFile(manifestPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to open plugins manifest %q: %w", manifestPath, err)
|
||||
}
|
||||
if err := json.Unmarshal(manifestB, &m); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := range m.Plugins {
|
||||
pm := m.Plugins[i]
|
||||
p.Schedule(g.Wrap(func() error {
|
||||
tgt := filepath.Join(grafanaDir, "plugins-bundled", fmt.Sprintf("%s-%s.zip", pm.Name, pm.Version))
|
||||
//nolint:gosec
|
||||
out, err := os.Create(tgt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer logCloseError(out.Close)
|
||||
|
||||
u := fmt.Sprintf("http://storage.googleapis.com/plugins-ci/plugins/%s/%s-%s.zip", pm.Name, pm.Name,
|
||||
pm.Version)
|
||||
log.Printf("Downloading plugin %q to %q...", u, tgt)
|
||||
// nolint:gosec
|
||||
resp, err := http.Get(u)
|
||||
if err != nil {
|
||||
return fmt.Errorf("downloading %q failed: %w", u, err)
|
||||
}
|
||||
defer logError(resp.Body.Close())
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return fmt.Errorf("failed to download %q, status code %d", u, resp.StatusCode)
|
||||
}
|
||||
|
||||
if _, err := io.Copy(out, resp.Body); err != nil {
|
||||
return fmt.Errorf("downloading %q failed: %w", u, err)
|
||||
}
|
||||
if err := out.Close(); err != nil {
|
||||
return fmt.Errorf("downloading %q failed: %w", u, err)
|
||||
}
|
||||
|
||||
//nolint:gosec
|
||||
fd, err := os.Open(tgt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer logCloseError(fd.Close)
|
||||
|
||||
h := sha256.New()
|
||||
if _, err := io.Copy(h, fd); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
chksum := hex.EncodeToString(h.Sum(nil))
|
||||
if chksum != pm.Checksum {
|
||||
return fmt.Errorf("plugin %q has bad checksum: %s (expected %s)", u, chksum, pm.Checksum)
|
||||
}
|
||||
|
||||
return Unzip(tgt, filepath.Join(grafanaDir, "plugins-bundled"))
|
||||
}))
|
||||
}
|
||||
|
||||
return g.Wait()
|
||||
}
|
||||
@@ -1,204 +0,0 @@
|
||||
package plugins
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
type manifest struct {
|
||||
Plugin string `json:"plugin"`
|
||||
Version string `json:"version"`
|
||||
Files map[string]string `json:"files"`
|
||||
}
|
||||
|
||||
func getManifest(dpath string, chksums map[string]string) (manifest, error) {
|
||||
m := manifest{}
|
||||
|
||||
type pluginInfo struct {
|
||||
Version string `json:"version"`
|
||||
}
|
||||
|
||||
type plugin struct {
|
||||
ID string `json:"id"`
|
||||
Info pluginInfo `json:"info"`
|
||||
}
|
||||
|
||||
//nolint:gosec
|
||||
f, err := os.Open(filepath.Join(dpath, "plugin.json"))
|
||||
if err != nil {
|
||||
return m, err
|
||||
}
|
||||
decoder := json.NewDecoder(f)
|
||||
var p plugin
|
||||
if err := decoder.Decode(&p); err != nil {
|
||||
return m, err
|
||||
}
|
||||
|
||||
if p.ID == "" {
|
||||
return m, fmt.Errorf("plugin.json doesn't define id")
|
||||
}
|
||||
if p.Info.Version == "" {
|
||||
return m, fmt.Errorf("plugin.json doesn't define info.version")
|
||||
}
|
||||
|
||||
return manifest{
|
||||
Plugin: p.ID,
|
||||
Version: p.Info.Version,
|
||||
Files: chksums,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// BuildManifest requests a plugin's signed manifest file fromt he Grafana API.
|
||||
// If signingAdmin is true, the manifest signing admin endpoint (without plugin ID) will be used, and requires
|
||||
// an admin API key.
|
||||
func BuildManifest(ctx context.Context, dpath string, signingAdmin bool) error {
|
||||
log.Printf("Building manifest for plug-in at %q", dpath)
|
||||
|
||||
apiKey := os.Getenv("GRAFANA_API_KEY")
|
||||
if apiKey == "" {
|
||||
return fmt.Errorf("GRAFANA_API_KEY must be set")
|
||||
}
|
||||
|
||||
manifestPath := filepath.Join(dpath, "MANIFEST.txt")
|
||||
chksums, err := getChksums(dpath, manifestPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m, err := getManifest(dpath, chksums)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
b := bytes.NewBuffer(nil)
|
||||
encoder := json.NewEncoder(b)
|
||||
if err := encoder.Encode(&m); err != nil {
|
||||
return err
|
||||
}
|
||||
jsonB := b.Bytes()
|
||||
u := "https://grafana.com/api/plugins/ci/sign"
|
||||
if !signingAdmin {
|
||||
u = fmt.Sprintf("https://grafana.com/api/plugins/%s/ci/sign", m.Plugin)
|
||||
}
|
||||
log.Printf("Requesting signed manifest from Grafana API...")
|
||||
req, err := http.NewRequestWithContext(ctx, "POST", u, bytes.NewReader(jsonB))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", apiKey))
|
||||
req.Header.Add("Content-Type", "application/json")
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get signed manifest from Grafana API: %w", err)
|
||||
}
|
||||
defer func() {
|
||||
if err := resp.Body.Close(); err != nil {
|
||||
log.Println("failed to close response body, err: %w", err)
|
||||
}
|
||||
}()
|
||||
if resp.StatusCode != 200 {
|
||||
msg, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
log.Printf("Failed to read response body: %s", err)
|
||||
msg = []byte("")
|
||||
}
|
||||
return fmt.Errorf("request for signed manifest failed with status code %d: %s", resp.StatusCode, string(msg))
|
||||
}
|
||||
|
||||
log.Printf("Successfully signed manifest via Grafana API, writing to %q", manifestPath)
|
||||
//nolint:gosec
|
||||
f, err := os.Create(manifestPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create %s: %w", manifestPath, err)
|
||||
}
|
||||
defer func() {
|
||||
if err := f.Close(); err != nil {
|
||||
log.Println("failed to close file, err: %w", err)
|
||||
}
|
||||
}()
|
||||
if _, err := io.Copy(f, resp.Body); err != nil {
|
||||
return fmt.Errorf("failed to write %s: %w", manifestPath, err)
|
||||
}
|
||||
if err := f.Close(); err != nil {
|
||||
return fmt.Errorf("failed to write %s: %w", manifestPath, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getChksums(dpath, manifestPath string) (map[string]string, error) {
|
||||
manifestPath = filepath.Clean(manifestPath)
|
||||
|
||||
chksums := map[string]string{}
|
||||
if err := filepath.Walk(dpath, func(path string, fi os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if fi.IsDir() {
|
||||
return nil
|
||||
}
|
||||
|
||||
path = filepath.Clean(path)
|
||||
|
||||
// Handle symbolic links
|
||||
if fi.Mode()&os.ModeSymlink == os.ModeSymlink {
|
||||
finalPath, err := filepath.EvalSymlinks(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Printf("Handling symlink %q, pointing to %q", path, finalPath)
|
||||
|
||||
info, err := os.Stat(finalPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if info.IsDir() {
|
||||
return nil
|
||||
}
|
||||
|
||||
if _, err := filepath.Rel(dpath, finalPath); err != nil {
|
||||
return fmt.Errorf("symbolic link %q targets a file outside of the plugin directory: %q", path, finalPath)
|
||||
}
|
||||
|
||||
if finalPath == manifestPath {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
if path == manifestPath {
|
||||
return nil
|
||||
}
|
||||
|
||||
h := sha256.New()
|
||||
//nolint:gosec
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer logCloseError(f.Close)
|
||||
if _, err := io.Copy(h, f); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
relPath, err := filepath.Rel(dpath, path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
chksums[relPath] = fmt.Sprintf("%x", h.Sum(nil))
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return chksums, nil
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
package plugins
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// Unzip unzips a plugin.
|
||||
func Unzip(fpath, tgtDir string) error {
|
||||
log.Printf("Unzipping plugin %q into %q...", fpath, tgtDir)
|
||||
|
||||
r, err := zip.OpenReader(fpath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer logCloseError(r.Close)
|
||||
|
||||
// Closure to address file descriptors issue with all the deferred .Close() methods
|
||||
extractAndWriteFile := func(f *zip.File) error {
|
||||
log.Printf("Extracting zip member %q...", f.Name)
|
||||
|
||||
rc, err := f.Open()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer logCloseError(rc.Close)
|
||||
|
||||
//nolint:gosec
|
||||
dstPath := filepath.Join(tgtDir, f.Name)
|
||||
|
||||
if f.FileInfo().IsDir() {
|
||||
return os.MkdirAll(dstPath, f.Mode())
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(filepath.Dir(dstPath), f.Mode()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
//nolint:gosec
|
||||
fd, err := os.OpenFile(dstPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer logCloseError(fd.Close)
|
||||
|
||||
// nolint:gosec
|
||||
if _, err := io.Copy(fd, rc); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return fd.Close()
|
||||
}
|
||||
|
||||
for _, f := range r.File {
|
||||
if err := extractAndWriteFile(f); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
package stringutil
|
||||
|
||||
func Contains(arr []string, s string) bool {
|
||||
for _, e := range arr {
|
||||
if e == s {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
package syncutil
|
||||
|
||||
import (
|
||||
"log"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
func worker(jobs chan func()) {
|
||||
for j := range jobs {
|
||||
j()
|
||||
}
|
||||
}
|
||||
|
||||
// WorkerPool represents a concurrent worker pool.
|
||||
type WorkerPool struct {
|
||||
NumWorkers int
|
||||
jobs chan func()
|
||||
}
|
||||
|
||||
// NewWorkerPool constructs a new WorkerPool.
|
||||
func NewWorkerPool(numWorkers int) WorkerPool {
|
||||
if numWorkers <= 0 {
|
||||
numWorkers = runtime.NumCPU()
|
||||
}
|
||||
log.Printf("Creating worker pool with %d workers", numWorkers)
|
||||
jobs := make(chan func(), 100)
|
||||
for i := 0; i < numWorkers; i++ {
|
||||
go worker(jobs)
|
||||
}
|
||||
return WorkerPool{
|
||||
NumWorkers: numWorkers,
|
||||
jobs: jobs,
|
||||
}
|
||||
}
|
||||
|
||||
// Schedule schedules a job to be executed by a worker in the pool.
|
||||
func (p WorkerPool) Schedule(job func()) {
|
||||
p.jobs <- job
|
||||
}
|
||||
|
||||
func (p WorkerPool) Close() {
|
||||
close(p.jobs)
|
||||
}
|
||||
@@ -1,9 +1,5 @@
|
||||
package validation
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
type ArtifactType int
|
||||
|
||||
const (
|
||||
@@ -15,13 +11,3 @@ type Artifact struct {
|
||||
Type ArtifactType
|
||||
URL string
|
||||
}
|
||||
|
||||
// ReleaseArtifacts generates a list of release artifacts
|
||||
func ReleaseArtifacts(version string) ([]Artifact, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// VerifyRelease tests that a that, given the information, a release will completed wholly and successfully.
|
||||
func VerifyRelease(ctx context.Context, version string) (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
31
pkg/build/versions/parse.go
Normal file
31
pkg/build/versions/parse.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package versions
|
||||
|
||||
import "regexp"
|
||||
|
||||
var semverRegex = regexp.MustCompile(`^(?P<major>0|[1-9]\d*)\.(?P<minor>0|[1-9]\d*)\.(?P<patch>0|[1-9]\d*)(?:-(?P<prerelease>(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?P<buildmetadata>[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$`)
|
||||
|
||||
type Semver struct {
|
||||
Major string
|
||||
Minor string
|
||||
Patch string
|
||||
Prerelease string
|
||||
BuildMetadata string
|
||||
}
|
||||
|
||||
func ParseSemver(version string) Semver {
|
||||
matches := semverRegex.FindStringSubmatch(version)
|
||||
results := make(map[string]string)
|
||||
for i, name := range semverRegex.SubexpNames() {
|
||||
if i != 0 && name != "" {
|
||||
results[name] = matches[i]
|
||||
}
|
||||
}
|
||||
|
||||
return Semver{
|
||||
Major: results["major"],
|
||||
Minor: results["minor"],
|
||||
Patch: results["patch"],
|
||||
Prerelease: results["prerelease"],
|
||||
BuildMetadata: results["buildmetadata"],
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
module github.com/grafana/grafana/pkg/build/wire
|
||||
|
||||
go 1.22.4
|
||||
go 1.22.7
|
||||
|
||||
require (
|
||||
github.com/google/go-cmp v0.6.0
|
||||
|
||||
26
pkg/expr/sql/db.go
Normal file
26
pkg/expr/sql/db.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package sql
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/data"
|
||||
)
|
||||
|
||||
type DB struct {
|
||||
}
|
||||
|
||||
func (db *DB) TablesList(rawSQL string) ([]string, error) {
|
||||
return nil, errors.New("not implemented")
|
||||
}
|
||||
|
||||
func (db *DB) RunCommands(commands []string) (string, error) {
|
||||
return "", errors.New("not implemented")
|
||||
}
|
||||
|
||||
func (db *DB) QueryFramesInto(name string, query string, frames []*data.Frame, f *data.Frame) error {
|
||||
return errors.New("not implemented")
|
||||
}
|
||||
|
||||
func NewInMemoryDB() *DB {
|
||||
return &DB{}
|
||||
}
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/jeremywohl/flatten"
|
||||
"github.com/scottlepp/go-duck/duck"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -21,7 +20,7 @@ var logger = log.New("sql_expr")
|
||||
|
||||
// TablesList returns a list of tables for the sql statement
|
||||
func TablesList(rawSQL string) ([]string, error) {
|
||||
duckDB := duck.NewInMemoryDB()
|
||||
duckDB := NewInMemoryDB()
|
||||
rawSQL = strings.Replace(rawSQL, "'", "''", -1)
|
||||
cmd := fmt.Sprintf("SELECT json_serialize_sql('%s')", rawSQL)
|
||||
ret, err := duckDB.RunCommands([]string{cmd})
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/data"
|
||||
"github.com/scottlepp/go-duck/duck"
|
||||
|
||||
"github.com/grafana/grafana/pkg/apimachinery/errutil"
|
||||
"github.com/grafana/grafana/pkg/expr/mathexp"
|
||||
@@ -94,7 +93,7 @@ func (gr *SQLCommand) Execute(ctx context.Context, now time.Time, vars mathexp.V
|
||||
|
||||
rsp := mathexp.Results{}
|
||||
|
||||
duckDB := duck.NewInMemoryDB()
|
||||
duckDB := sql.NewInMemoryDB()
|
||||
var frame = &data.Frame{}
|
||||
|
||||
logger.Debug("Executing query", "query", gr.query, "frames", len(allFrames))
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module github.com/grafana/grafana/pkg/promlib
|
||||
|
||||
go 1.22.4
|
||||
go 1.22.7
|
||||
|
||||
require (
|
||||
github.com/grafana/grafana-plugin-sdk-go v0.241.0
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module github.com/grafana/grafana/pkg/semconv
|
||||
|
||||
go 1.22.4
|
||||
go 1.22.7
|
||||
|
||||
require go.opentelemetry.io/otel v1.28.0
|
||||
|
||||
|
||||
@@ -112,7 +112,7 @@ func (api *API) authorize(method, path string) web.Handler {
|
||||
case http.MethodGet + "/api/ruler/{DatasourceUID}/api/v1/rules":
|
||||
eval = ac.EvalPermission(ac.ActionAlertingRuleExternalRead, datasources.ScopeProvider.GetResourceScopeUID(ac.Parameter(":DatasourceUID")))
|
||||
case http.MethodPost + "/api/ruler/{DatasourceUID}/api/v1/rules/{Namespace}":
|
||||
eval = ac.EvalPermission(ac.ActionAlertingInstancesExternalWrite, datasources.ScopeProvider.GetResourceScopeUID(ac.Parameter(":DatasourceUID")))
|
||||
eval = ac.EvalPermission(ac.ActionAlertingRuleExternalWrite, datasources.ScopeProvider.GetResourceScopeUID(ac.Parameter(":DatasourceUID")))
|
||||
|
||||
// Lotex Prometheus-compatible Paths
|
||||
case http.MethodGet + "/api/prometheus/{DatasourceUID}/api/v1/rules":
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module github.com/grafana/grafana/pkg/storage/unified/resource
|
||||
|
||||
go 1.22.4
|
||||
go 1.22.7
|
||||
|
||||
require (
|
||||
github.com/fullstorydev/grpchan v1.1.1
|
||||
|
||||
@@ -16,7 +16,9 @@ type ParseFilterTestCase = {
|
||||
};
|
||||
|
||||
describe('DataTrailsHistory', () => {
|
||||
describe('parseTimeTooltip', () => {
|
||||
// Due to daylight saving changes the expected time differs depends on when we run the tests.
|
||||
// Until we find a better way to test, those will be skipped.
|
||||
describe.skip('parseTimeTooltip', () => {
|
||||
// global timezone is set to Pacific/Easter, see jest-config.js file
|
||||
test.each<ParseTimeTestCase>([
|
||||
{
|
||||
|
||||
@@ -112,22 +112,7 @@ def publish_artifacts_step():
|
||||
"PRERELEASE_BUCKET": from_secret("prerelease_bucket"),
|
||||
},
|
||||
"commands": [
|
||||
"./bin/build artifacts packages --tag $${DRONE_TAG} --src-bucket $${PRERELEASE_BUCKET}",
|
||||
],
|
||||
"depends_on": ["compile-build-cmd"],
|
||||
}
|
||||
|
||||
def publish_static_assets_step():
|
||||
return {
|
||||
"name": "publish-static-assets",
|
||||
"image": images["publish"],
|
||||
"environment": {
|
||||
"GCP_KEY": from_secret(gcp_grafanauploads_base64),
|
||||
"PRERELEASE_BUCKET": from_secret("prerelease_bucket"),
|
||||
"STATIC_ASSET_EDITIONS": from_secret("static_asset_editions"),
|
||||
},
|
||||
"commands": [
|
||||
"./bin/build artifacts static-assets --tag ${DRONE_TAG} --static-asset-editions=grafana-oss",
|
||||
"./bin/build artifacts packages --artifacts-editions=oss --tag $${DRONE_TAG} --src-bucket $${PRERELEASE_BUCKET}",
|
||||
],
|
||||
"depends_on": ["compile-build-cmd"],
|
||||
}
|
||||
@@ -163,9 +148,8 @@ def publish_artifacts_pipelines(mode):
|
||||
steps = [
|
||||
compile_build_cmd(),
|
||||
publish_artifacts_step(),
|
||||
publish_static_assets_step(),
|
||||
publish_storybook_step(),
|
||||
release_pr_step(depends_on = ["publish-artifacts", "publish-static-assets"]),
|
||||
release_pr_step(depends_on = ["publish-artifacts"]),
|
||||
]
|
||||
|
||||
return [
|
||||
|
||||
@@ -31,43 +31,44 @@ def publish_image_public_step():
|
||||
"""
|
||||
command = """
|
||||
bash -c '
|
||||
IMAGE_TAG=$(echo "$${TAG}" | sed -e "s/+/-/g")
|
||||
debug=
|
||||
if [[ -n $${DRY_RUN} ]]; then debug=echo; fi
|
||||
docker login -u $${DOCKER_USER} -p $${DOCKER_PASSWORD}
|
||||
|
||||
# Push the grafana-image-tags images
|
||||
$$debug docker push grafana/grafana-image-tags:$${TAG}-amd64
|
||||
$$debug docker push grafana/grafana-image-tags:$${TAG}-arm64
|
||||
$$debug docker push grafana/grafana-image-tags:$${TAG}-armv7
|
||||
$$debug docker push grafana/grafana-image-tags:$${TAG}-ubuntu-amd64
|
||||
$$debug docker push grafana/grafana-image-tags:$${TAG}-ubuntu-arm64
|
||||
$$debug docker push grafana/grafana-image-tags:$${TAG}-ubuntu-armv7
|
||||
$$debug docker push grafana/grafana-image-tags:$${IMAGE_TAG}-amd64
|
||||
$$debug docker push grafana/grafana-image-tags:$${IMAGE_TAG}-arm64
|
||||
$$debug docker push grafana/grafana-image-tags:$${IMAGE_TAG}-armv7
|
||||
$$debug docker push grafana/grafana-image-tags:$${IMAGE_TAG}-ubuntu-amd64
|
||||
$$debug docker push grafana/grafana-image-tags:$${IMAGE_TAG}-ubuntu-arm64
|
||||
$$debug docker push grafana/grafana-image-tags:$${IMAGE_TAG}-ubuntu-armv7
|
||||
|
||||
# Create the grafana manifests
|
||||
$$debug docker manifest create grafana/grafana:${TAG} \
|
||||
grafana/grafana-image-tags:$${TAG}-amd64 \
|
||||
grafana/grafana-image-tags:$${TAG}-arm64 \
|
||||
grafana/grafana-image-tags:$${TAG}-armv7
|
||||
grafana/grafana-image-tags:$${IMAGE_TAG}-amd64 \
|
||||
grafana/grafana-image-tags:$${IMAGE_TAG}-arm64 \
|
||||
grafana/grafana-image-tags:$${IMAGE_TAG}-armv7
|
||||
|
||||
$$debug docker manifest create grafana/grafana:${TAG}-ubuntu \
|
||||
grafana/grafana-image-tags:$${TAG}-ubuntu-amd64 \
|
||||
grafana/grafana-image-tags:$${TAG}-ubuntu-arm64 \
|
||||
grafana/grafana-image-tags:$${TAG}-ubuntu-armv7
|
||||
grafana/grafana-image-tags:$${IMAGE_TAG}-ubuntu-amd64 \
|
||||
grafana/grafana-image-tags:$${IMAGE_TAG}-ubuntu-arm64 \
|
||||
grafana/grafana-image-tags:$${IMAGE_TAG}-ubuntu-armv7
|
||||
|
||||
# Push the grafana manifests
|
||||
$$debug docker manifest push grafana/grafana:$${TAG}
|
||||
$$debug docker manifest push grafana/grafana:$${TAG}-ubuntu
|
||||
$$debug docker manifest push grafana/grafana:$${IMAGE_TAG}
|
||||
$$debug docker manifest push grafana/grafana:$${IMAGE_TAG}-ubuntu
|
||||
|
||||
# if LATEST is set, then also create & push latest
|
||||
if [[ -n $${LATEST} ]]; then
|
||||
$$debug docker manifest create grafana/grafana:latest \
|
||||
grafana/grafana-image-tags:$${TAG}-amd64 \
|
||||
grafana/grafana-image-tags:$${TAG}-arm64 \
|
||||
grafana/grafana-image-tags:$${TAG}-armv7
|
||||
grafana/grafana-image-tags:$${IMAGE_TAG}-amd64 \
|
||||
grafana/grafana-image-tags:$${IMAGE_TAG}-arm64 \
|
||||
grafana/grafana-image-tags:$${IMAGE_TAG}-armv7
|
||||
$$debug docker manifest create grafana/grafana:latest-ubuntu \
|
||||
grafana/grafana-image-tags:$${TAG}-ubuntu-amd64 \
|
||||
grafana/grafana-image-tags:$${TAG}-ubuntu-arm64 \
|
||||
grafana/grafana-image-tags:$${TAG}-ubuntu-armv7
|
||||
grafana/grafana-image-tags:$${IMAGE_TAG}-ubuntu-amd64 \
|
||||
grafana/grafana-image-tags:$${IMAGE_TAG}-ubuntu-arm64 \
|
||||
grafana/grafana-image-tags:$${IMAGE_TAG}-ubuntu-armv7
|
||||
|
||||
$$debug docker manifest push grafana/grafana:latest
|
||||
$$debug docker manifest push grafana/grafana:latest-ubuntu
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
This module returns a Drone step and pipeline for linting with shellcheck.
|
||||
"""
|
||||
|
||||
load("scripts/drone/steps/lib.star", "compile_build_cmd")
|
||||
load(
|
||||
"scripts/drone/utils/images.star",
|
||||
"images",
|
||||
@@ -39,7 +38,6 @@ def shellcheck_step():
|
||||
def shellcheck_pipeline():
|
||||
environment = {"EDITION": "oss"}
|
||||
steps = [
|
||||
compile_build_cmd(),
|
||||
shellcheck_step(),
|
||||
]
|
||||
return pipeline(
|
||||
|
||||
@@ -4,7 +4,6 @@ This module returns a Drone pipeline that verifies all Starlark files are linted
|
||||
|
||||
load(
|
||||
"scripts/drone/steps/lib.star",
|
||||
"compile_build_cmd",
|
||||
"identify_runner_step",
|
||||
"lint_starlark_step",
|
||||
)
|
||||
@@ -17,7 +16,6 @@ def verify_starlark(trigger, ver_mode):
|
||||
environment = {"EDITION": "oss"}
|
||||
steps = [
|
||||
identify_runner_step(),
|
||||
compile_build_cmd(),
|
||||
lint_starlark_step(),
|
||||
]
|
||||
return pipeline(
|
||||
|
||||
@@ -156,9 +156,7 @@ def lint_starlark_step():
|
||||
"go install github.com/bazelbuild/buildtools/buildifier@latest",
|
||||
"buildifier --lint=warn -mode=check -r .",
|
||||
],
|
||||
"depends_on": [
|
||||
"compile-build-cmd",
|
||||
],
|
||||
"depends_on": [],
|
||||
}
|
||||
|
||||
def enterprise_downstream_step(ver_mode):
|
||||
|
||||
@@ -16,7 +16,7 @@ images = {
|
||||
"node_deb": "node:{}-bookworm".format(nodejs_version[:2]),
|
||||
"cloudsdk": "google/cloud-sdk:431.0.0",
|
||||
"publish": "grafana/grafana-ci-deploy:1.3.3",
|
||||
"alpine": "alpine:3.19.1",
|
||||
"alpine": "alpine:3.20.3",
|
||||
"ubuntu": "ubuntu:22.04",
|
||||
"curl": "byrnedo/alpine-curl:0.1.8",
|
||||
"plugins_slack": "plugins/slack",
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
global variables
|
||||
"""
|
||||
|
||||
grabpl_version = "v3.0.50"
|
||||
golang_version = "1.22.4"
|
||||
grabpl_version = "v3.0.53"
|
||||
golang_version = "1.22.7"
|
||||
|
||||
# nodejs_version should match what's in ".nvmrc", but without the v prefix.
|
||||
nodejs_version = "20.9.0"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
module github.com/grafana/grafana/scripts/go-workspace
|
||||
|
||||
go 1.22.4
|
||||
go 1.22.7
|
||||
|
||||
require golang.org/x/mod v0.20.0
|
||||
|
||||
Reference in New Issue
Block a user