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/runner-go v1.12.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/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa // 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-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/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/go.mod h1:FObaZJEDSTa/WGCzZ2Z3eoCDXWJKMenWWTrd8jrta28=
|
||||
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.84.0 h1:NMB9J4cCxs9xEm+1Z9QiO3eFvn7EnQj3Eo3hN6ugVlg=
|
||||
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.3.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"
|
||||
|
||||
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 {
|
||||
if ctx.NArg() > max {
|
||||
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",
|
||||
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",
|
||||
Usage: "Build one or more variants of back-end binaries",
|
||||
ArgsUsage: "[version]",
|
||||
Action: ArgCountWrapper(1, BuildBackend),
|
||||
Action: MaxArgCountWrapper(1, BuildBackend),
|
||||
Flags: []cli.Flag{
|
||||
&jobsFlag,
|
||||
&variantsFlag,
|
||||
@ -67,7 +67,7 @@ func main() {
|
||||
Name: "build-frontend",
|
||||
Usage: "Build front-end artifacts",
|
||||
ArgsUsage: "[version]",
|
||||
Action: ArgCountWrapper(1, BuildFrontend),
|
||||
Action: MaxArgCountWrapper(1, BuildFrontend),
|
||||
Flags: []cli.Flag{
|
||||
&jobsFlag,
|
||||
&editionFlag,
|
||||
@ -77,7 +77,7 @@ func main() {
|
||||
{
|
||||
Name: "build-docker",
|
||||
Usage: "Build Grafana Docker images",
|
||||
Action: ArgCountWrapper(1, BuildDocker),
|
||||
Action: MaxArgCountWrapper(1, BuildDocker),
|
||||
Flags: []cli.Flag{
|
||||
&jobsFlag,
|
||||
&editionFlag,
|
||||
@ -112,7 +112,7 @@ func main() {
|
||||
{
|
||||
Name: "build-plugins",
|
||||
Usage: "Build internal plug-ins",
|
||||
Action: ArgCountWrapper(1, BuildInternalPlugins),
|
||||
Action: MaxArgCountWrapper(1, BuildInternalPlugins),
|
||||
Flags: []cli.Flag{
|
||||
&jobsFlag,
|
||||
&editionFlag,
|
||||
@ -125,7 +125,7 @@ func main() {
|
||||
Name: "publish-metrics",
|
||||
Usage: "Publish a set of metrics from stdin",
|
||||
ArgsUsage: "<api-key>",
|
||||
Action: ArgCountWrapper(1, PublishMetrics),
|
||||
Action: MaxArgCountWrapper(1, PublishMetrics),
|
||||
},
|
||||
{
|
||||
Name: "verify-drone",
|
||||
@ -141,7 +141,7 @@ func main() {
|
||||
Name: "package",
|
||||
Usage: "Package one or more Grafana variants",
|
||||
ArgsUsage: "[version]",
|
||||
Action: ArgCountWrapper(1, Package),
|
||||
Action: MaxArgCountWrapper(1, Package),
|
||||
Flags: []cli.Flag{
|
||||
&jobsFlag,
|
||||
&variantsFlag,
|
||||
@ -182,7 +182,7 @@ func main() {
|
||||
Name: "fetch",
|
||||
Usage: "Fetch Grafana Docker images",
|
||||
ArgsUsage: "[version]",
|
||||
Action: ArgCountWrapper(1, FetchImages),
|
||||
Action: MaxArgCountWrapper(1, FetchImages),
|
||||
Flags: []cli.Flag{
|
||||
&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 {
|
||||
|
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