mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
CI: Make the downstream enterprise test a check instead of comments (#59071)
This commit is contained in:
parent
76372a240c
commit
45c759eb59
1
go.mod
1
go.mod
@ -284,6 +284,7 @@ require (
|
|||||||
github.com/drone/envsubst v1.0.3 // indirect
|
github.com/drone/envsubst v1.0.3 // indirect
|
||||||
github.com/drone/runner-go v1.12.0 // indirect
|
github.com/drone/runner-go v1.12.0 // indirect
|
||||||
github.com/go-ozzo/ozzo-validation/v4 v4.3.0 // indirect
|
github.com/go-ozzo/ozzo-validation/v4 v4.3.0 // indirect
|
||||||
|
github.com/google/go-github/v31 v31.0.0 // indirect
|
||||||
github.com/google/go-querystring v1.1.0 // indirect
|
github.com/google/go-querystring v1.1.0 // indirect
|
||||||
github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa // indirect
|
github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa // indirect
|
||||||
github.com/googleapis/go-type-adapters v1.0.0 // indirect
|
github.com/googleapis/go-type-adapters v1.0.0 // indirect
|
||||||
|
3
go.sum
3
go.sum
@ -1240,6 +1240,8 @@ github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
|||||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY=
|
github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY=
|
||||||
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
|
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
|
||||||
|
github.com/google/go-github/v31 v31.0.0 h1:JJUxlP9lFK+ziXKimTCprajMApV1ecWD4NB6CCb0plo=
|
||||||
|
github.com/google/go-github/v31 v31.0.0/go.mod h1:NQPZol8/1sMoWYGN2yaALIBytu17gAWfhbweiEed3pM=
|
||||||
github.com/google/go-github/v45 v45.2.0 h1:5oRLszbrkvxDDqBCNj2hjDZMKmvexaZ1xw/FCD+K3FI=
|
github.com/google/go-github/v45 v45.2.0 h1:5oRLszbrkvxDDqBCNj2hjDZMKmvexaZ1xw/FCD+K3FI=
|
||||||
github.com/google/go-github/v45 v45.2.0/go.mod h1:FObaZJEDSTa/WGCzZ2Z3eoCDXWJKMenWWTrd8jrta28=
|
github.com/google/go-github/v45 v45.2.0/go.mod h1:FObaZJEDSTa/WGCzZ2Z3eoCDXWJKMenWWTrd8jrta28=
|
||||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||||
@ -3303,6 +3305,7 @@ google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6r
|
|||||||
google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg=
|
google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg=
|
||||||
google.golang.org/api v0.84.0 h1:NMB9J4cCxs9xEm+1Z9QiO3eFvn7EnQj3Eo3hN6ugVlg=
|
google.golang.org/api v0.84.0 h1:NMB9J4cCxs9xEm+1Z9QiO3eFvn7EnQj3Eo3hN6ugVlg=
|
||||||
google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o=
|
google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o=
|
||||||
|
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||||
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
|
@ -2,7 +2,22 @@ package main
|
|||||||
|
|
||||||
import "github.com/urfave/cli/v2"
|
import "github.com/urfave/cli/v2"
|
||||||
|
|
||||||
func ArgCountWrapper(max int, action cli.ActionFunc) cli.ActionFunc {
|
// 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 {
|
return func(ctx *cli.Context) error {
|
||||||
if ctx.NArg() > max {
|
if ctx.NArg() > max {
|
||||||
if err := cli.ShowSubcommandHelp(ctx); err != nil {
|
if err := cli.ShowSubcommandHelp(ctx); err != nil {
|
||||||
|
121
pkg/build/cmd/enterprisecheck.go
Normal file
121
pkg/build/cmd/enterprisecheck.go
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/build/env"
|
||||||
|
"github.com/grafana/grafana/pkg/build/git"
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
sha, ok := env.Lookup("SOURCE_COMMIT", args)
|
||||||
|
if !ok {
|
||||||
|
return nil, cli.Exit(`missing environment variable "SOURCE_COMMIT"`, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
url, ok := env.Lookup("DRONE_BUILD_LINK", args)
|
||||||
|
if !ok {
|
||||||
|
return nil, cli.Exit(`missing environment variable "DRONE_BUILD_LINK"`, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
branch, ok := env.Lookup("DRONE_SOURCE_BRANCH", args)
|
||||||
|
if !ok {
|
||||||
|
return nil, cli.Exit("Unable to retrieve build source branch", 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
prStr, ok := env.Lookup("OSS_PULL_REQUEST", args)
|
||||||
|
if !ok {
|
||||||
|
matches := git.PRCheckRegexp().FindStringSubmatch(branch)
|
||||||
|
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
|
||||||
|
if git.PRCheckRegexp().MatchString(opts.Branch) {
|
||||||
|
if err := git.DeleteEnterpriseBranch(ctx, client.Git, opts.Branch); err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
label := "enterprise-failed"
|
||||||
|
if success {
|
||||||
|
label = "enterprise-ok"
|
||||||
|
}
|
||||||
|
|
||||||
|
return git.AddLabelToPR(ctx, client.Issues, opts.PR, label)
|
||||||
|
}
|
69
pkg/build/cmd/enterprisecheck_test.go
Normal file
69
pkg/build/cmd/enterprisecheck_test.go
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
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)
|
||||||
|
})
|
||||||
|
}
|
@ -46,4 +46,10 @@ var (
|
|||||||
Usage: "Google Cloud Platform key file",
|
Usage: "Google Cloud Platform key file",
|
||||||
Required: true,
|
Required: true,
|
||||||
}
|
}
|
||||||
|
gitHubTokenFlag = cli.StringFlag{
|
||||||
|
Name: "github-token",
|
||||||
|
Value: "",
|
||||||
|
EnvVars: []string{"GITHUB_TOKEN"},
|
||||||
|
Usage: "GitHub token",
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
@ -16,7 +16,7 @@ func main() {
|
|||||||
Name: "build-backend",
|
Name: "build-backend",
|
||||||
Usage: "Build one or more variants of back-end binaries",
|
Usage: "Build one or more variants of back-end binaries",
|
||||||
ArgsUsage: "[version]",
|
ArgsUsage: "[version]",
|
||||||
Action: ArgCountWrapper(1, BuildBackend),
|
Action: MaxArgCountWrapper(1, BuildBackend),
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&jobsFlag,
|
&jobsFlag,
|
||||||
&variantsFlag,
|
&variantsFlag,
|
||||||
@ -67,7 +67,7 @@ func main() {
|
|||||||
Name: "build-frontend",
|
Name: "build-frontend",
|
||||||
Usage: "Build front-end artifacts",
|
Usage: "Build front-end artifacts",
|
||||||
ArgsUsage: "[version]",
|
ArgsUsage: "[version]",
|
||||||
Action: ArgCountWrapper(1, BuildFrontend),
|
Action: MaxArgCountWrapper(1, BuildFrontend),
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&jobsFlag,
|
&jobsFlag,
|
||||||
&editionFlag,
|
&editionFlag,
|
||||||
@ -77,7 +77,7 @@ func main() {
|
|||||||
{
|
{
|
||||||
Name: "build-docker",
|
Name: "build-docker",
|
||||||
Usage: "Build Grafana Docker images",
|
Usage: "Build Grafana Docker images",
|
||||||
Action: ArgCountWrapper(1, BuildDocker),
|
Action: MaxArgCountWrapper(1, BuildDocker),
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&jobsFlag,
|
&jobsFlag,
|
||||||
&editionFlag,
|
&editionFlag,
|
||||||
@ -112,7 +112,7 @@ func main() {
|
|||||||
{
|
{
|
||||||
Name: "build-plugins",
|
Name: "build-plugins",
|
||||||
Usage: "Build internal plug-ins",
|
Usage: "Build internal plug-ins",
|
||||||
Action: ArgCountWrapper(1, BuildInternalPlugins),
|
Action: MaxArgCountWrapper(1, BuildInternalPlugins),
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&jobsFlag,
|
&jobsFlag,
|
||||||
&editionFlag,
|
&editionFlag,
|
||||||
@ -125,7 +125,7 @@ func main() {
|
|||||||
Name: "publish-metrics",
|
Name: "publish-metrics",
|
||||||
Usage: "Publish a set of metrics from stdin",
|
Usage: "Publish a set of metrics from stdin",
|
||||||
ArgsUsage: "<api-key>",
|
ArgsUsage: "<api-key>",
|
||||||
Action: ArgCountWrapper(1, PublishMetrics),
|
Action: MaxArgCountWrapper(1, PublishMetrics),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "verify-drone",
|
Name: "verify-drone",
|
||||||
@ -141,7 +141,7 @@ func main() {
|
|||||||
Name: "package",
|
Name: "package",
|
||||||
Usage: "Package one or more Grafana variants",
|
Usage: "Package one or more Grafana variants",
|
||||||
ArgsUsage: "[version]",
|
ArgsUsage: "[version]",
|
||||||
Action: ArgCountWrapper(1, Package),
|
Action: MaxArgCountWrapper(1, Package),
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&jobsFlag,
|
&jobsFlag,
|
||||||
&variantsFlag,
|
&variantsFlag,
|
||||||
@ -182,7 +182,7 @@ func main() {
|
|||||||
Name: "fetch",
|
Name: "fetch",
|
||||||
Usage: "Fetch Grafana Docker images",
|
Usage: "Fetch Grafana Docker images",
|
||||||
ArgsUsage: "[version]",
|
ArgsUsage: "[version]",
|
||||||
Action: ArgCountWrapper(1, FetchImages),
|
Action: MaxArgCountWrapper(1, FetchImages),
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&editionFlag,
|
&editionFlag,
|
||||||
},
|
},
|
||||||
@ -277,6 +277,36 @@ 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,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := app.Run(os.Args); err != nil {
|
if err := app.Run(os.Args); err != nil {
|
||||||
|
18
pkg/build/env/lookup.go
vendored
Normal file
18
pkg/build/env/lookup.go
vendored
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
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
Normal file
43
pkg/build/env/lookup_test.go
vendored
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
package env_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/build/env"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
143
pkg/build/git/git.go
Normal file
143
pkg/build/git/git.go
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
package git
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"regexp"
|
||||||
|
|
||||||
|
"github.com/google/go-github/v45/github"
|
||||||
|
"github.com/grafana/grafana/pkg/build/stringutil"
|
||||||
|
"golang.org/x/oauth2"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
MainBranch = "main"
|
||||||
|
HomeDir = "."
|
||||||
|
RepoOwner = "grafana"
|
||||||
|
OSSRepo = "grafana"
|
||||||
|
EnterpriseRepo = "grafana-enterprise"
|
||||||
|
EnterpriseCheckName = "Grafana Enterprise"
|
||||||
|
EnterpriseCheckDescription = "Downstream tests to ensure that your changes are compatible with Grafana Enterprise"
|
||||||
|
)
|
||||||
|
|
||||||
|
var EnterpriseCheckLabels = []string{"enterprise-ok", "enterprise-failed", "enterprise-override"}
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrorNoDroneBuildLink = errors.New("no drone build link")
|
||||||
|
)
|
||||||
|
|
||||||
|
type GitService interface {
|
||||||
|
DeleteRef(ctx context.Context, owner string, repo string, ref string) (*github.Response, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type LabelsService interface {
|
||||||
|
ListLabelsByIssue(ctx context.Context, owner string, repo string, number int, opts *github.ListOptions) ([]*github.Label, *github.Response, error)
|
||||||
|
RemoveLabelForIssue(ctx context.Context, owner string, repo string, number int, label string) (*github.Response, error)
|
||||||
|
AddLabelsToIssue(ctx context.Context, owner string, repo string, number int, labels []string) ([]*github.Label, *github.Response, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type CommentService interface {
|
||||||
|
CreateComment(ctx context.Context, owner string, repo string, number int, comment *github.IssueComment) (*github.IssueComment, *github.Response, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
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(`^pr-check-([0-9]+)\/(.+)$`)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Sprintf("Failed to compile regexp: %s", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
_, err := client.DeleteRef(ctx, RepoOwner, EnterpriseRepo, ref)
|
||||||
|
if 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
|
||||||
|
}
|
55
pkg/build/git/git_checks_test.go
Normal file
55
pkg/build/git/git_checks_test.go
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
package git_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/google/go-github/v45/github"
|
||||||
|
"github.com/grafana/grafana/pkg/build/git"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
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)
|
||||||
|
})
|
||||||
|
}
|
134
pkg/build/git/git_issues_test.go
Normal file
134
pkg/build/git/git_issues_test.go
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
package git_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/google/go-github/v45/github"
|
||||||
|
"github.com/grafana/grafana/pkg/build/git"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
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)
|
||||||
|
})
|
||||||
|
}
|
25
pkg/build/git/git_test.go
Normal file
25
pkg/build/git/git_test.go
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package git_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/build/git"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPRCheckRegexp(t *testing.T) {
|
||||||
|
var (
|
||||||
|
shouldMatch = []string{"pr-check-1/branch-name", "pr-check-111/branch/name", "pr-check-102930122/branch-name"}
|
||||||
|
shouldNotMatch = []string{"pr-check-a/branch", "km/test", "test", "pr-check", "pr-check/test", "price"}
|
||||||
|
)
|
||||||
|
|
||||||
|
regex := git.PRCheckRegexp()
|
||||||
|
|
||||||
|
for _, v := range shouldMatch {
|
||||||
|
assert.Truef(t, regex.MatchString(v), "regex should match %s", v)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range shouldNotMatch {
|
||||||
|
assert.False(t, regex.MatchString(v), "regex should not match %s", v)
|
||||||
|
}
|
||||||
|
}
|
10
pkg/build/stringutil/contains.go
Normal file
10
pkg/build/stringutil/contains.go
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
package stringutil
|
||||||
|
|
||||||
|
func Contains(arr []string, s string) bool {
|
||||||
|
for _, e := range arr {
|
||||||
|
if e == s {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user