mirror of https://github.com/grafana/grafana.git
				
				
				
			
		
			
				
	
	
		
			192 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			192 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			Go
		
	
	
	
package main
 | 
						|
 | 
						|
import (
 | 
						|
	"context"
 | 
						|
	"errors"
 | 
						|
	"fmt"
 | 
						|
	"os"
 | 
						|
	"path"
 | 
						|
	"strings"
 | 
						|
 | 
						|
	"github.com/google/go-github/github"
 | 
						|
	"github.com/urfave/cli/v2"
 | 
						|
	"golang.org/x/oauth2"
 | 
						|
 | 
						|
	"github.com/grafana/grafana/pkg/build/config"
 | 
						|
)
 | 
						|
 | 
						|
type githubRepositoryService interface {
 | 
						|
	GetReleaseByTag(ctx context.Context, owner string, repo string, tag string) (*github.RepositoryRelease, *github.Response, error)
 | 
						|
	CreateRelease(ctx context.Context, owner string, repo string, release *github.RepositoryRelease) (*github.RepositoryRelease, *github.Response, error)
 | 
						|
	UploadReleaseAsset(ctx context.Context, owner string, repo string, id int64, opt *github.UploadOptions, file *os.File) (*github.ReleaseAsset, *github.Response, error)
 | 
						|
	DeleteReleaseAsset(ctx context.Context, owner string, repo string, id int64) (*github.Response, error)
 | 
						|
	ListReleaseAssets(ctx context.Context, owner string, repo string, id int64, opt *github.ListOptions) ([]*github.ReleaseAsset, *github.Response, error)
 | 
						|
}
 | 
						|
 | 
						|
type githubRepo struct {
 | 
						|
	owner string
 | 
						|
	name  string
 | 
						|
}
 | 
						|
 | 
						|
type publishGithubFlags struct {
 | 
						|
	create       bool
 | 
						|
	dryRun       bool
 | 
						|
	tag          string
 | 
						|
	repo         *githubRepo
 | 
						|
	artifactPath string
 | 
						|
}
 | 
						|
 | 
						|
var (
 | 
						|
	newGithubClient    = githubRepositoryClient
 | 
						|
	errTokenIsEmpty    = errors.New("the environment variable GH_TOKEN must be set")
 | 
						|
	errTagIsEmpty      = errors.New(`failed to retrieve release tag from metadata, use "--tag" to set it manually`)
 | 
						|
	errReleaseNotFound = errors.New(`release not found, use "--create" to create the release`)
 | 
						|
)
 | 
						|
 | 
						|
func PublishGithub(c *cli.Context) error {
 | 
						|
	ctx := c.Context
 | 
						|
	token := os.Getenv("GH_TOKEN")
 | 
						|
	f, err := getPublishGithubFlags(c)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	if f.tag == "" {
 | 
						|
		return errTagIsEmpty
 | 
						|
	}
 | 
						|
 | 
						|
	if token == "" {
 | 
						|
		return errTokenIsEmpty
 | 
						|
	}
 | 
						|
 | 
						|
	if f.dryRun {
 | 
						|
		return runPublishGithubDryRun(f, token, c)
 | 
						|
	}
 | 
						|
 | 
						|
	client := newGithubClient(ctx, token)
 | 
						|
	release, res, err := client.GetReleaseByTag(ctx, f.repo.owner, f.repo.name, f.tag)
 | 
						|
	if err != nil && res.StatusCode != 404 {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	if release == nil {
 | 
						|
		if f.create {
 | 
						|
			release, _, err = client.CreateRelease(ctx, f.repo.owner, f.repo.name, &github.RepositoryRelease{TagName: &f.tag})
 | 
						|
			if err != nil {
 | 
						|
				return err
 | 
						|
			}
 | 
						|
		} else {
 | 
						|
			return errReleaseNotFound
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	artifactName := path.Base(f.artifactPath)
 | 
						|
	file, err := os.Open(f.artifactPath)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	assetsPage := 1
 | 
						|
	foundAsset := false
 | 
						|
	for {
 | 
						|
		assets, resp, err := client.ListReleaseAssets(ctx, f.repo.owner, f.repo.name, *release.ID, &github.ListOptions{
 | 
						|
			Page: assetsPage,
 | 
						|
		})
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
		for _, asset := range assets {
 | 
						|
			if asset.GetName() == artifactName {
 | 
						|
				fmt.Printf("Found existing artifact with the name '%s'. Deleting that now.\n", artifactName)
 | 
						|
				if _, err := client.DeleteReleaseAsset(ctx, f.repo.owner, f.repo.name, asset.GetID()); err != nil {
 | 
						|
					return fmt.Errorf("failed to delete already existing asset: %w", err)
 | 
						|
				}
 | 
						|
				foundAsset = true
 | 
						|
				break
 | 
						|
			}
 | 
						|
		}
 | 
						|
		if resp.NextPage <= assetsPage || foundAsset {
 | 
						|
			break
 | 
						|
		}
 | 
						|
		assetsPage = resp.NextPage
 | 
						|
	}
 | 
						|
 | 
						|
	asset, _, err := client.UploadReleaseAsset(ctx, f.repo.owner, f.repo.name, *release.ID, &github.UploadOptions{Name: artifactName}, file)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	fmt.Printf("Asset '%s' uploaded to release '%s' on repository '%s/%s'\nDownload: %s\n", *asset.Name, f.tag, f.repo.owner, f.repo.name, *asset.BrowserDownloadURL)
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func githubRepositoryClient(ctx context.Context, token string) githubRepositoryService {
 | 
						|
	ts := oauth2.StaticTokenSource(
 | 
						|
		&oauth2.Token{AccessToken: token},
 | 
						|
	)
 | 
						|
	tc := oauth2.NewClient(ctx, ts)
 | 
						|
 | 
						|
	client := github.NewClient(tc)
 | 
						|
	return client.Repositories
 | 
						|
}
 | 
						|
 | 
						|
func getPublishGithubFlags(c *cli.Context) (*publishGithubFlags, error) {
 | 
						|
	metadata, err := config.GenerateMetadata(c)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	tag := c.Value("tag").(string)
 | 
						|
	if tag == "" && metadata.GrafanaVersion != "" {
 | 
						|
		tag = fmt.Sprintf("v%s", metadata.GrafanaVersion)
 | 
						|
	}
 | 
						|
	fullRepo := c.Value("repo").(string)
 | 
						|
	dryRun := c.Value("dry-run").(bool)
 | 
						|
	owner := strings.Split(fullRepo, "/")[0]
 | 
						|
	name := strings.Split(fullRepo, "/")[1]
 | 
						|
	create := c.Value("create").(bool)
 | 
						|
	artifactPath := c.Value("path").(string)
 | 
						|
	if artifactPath == "" {
 | 
						|
		artifactPath = fmt.Sprintf("grafana-enterprise2-%s-amd64.img", metadata.GrafanaVersion)
 | 
						|
		fmt.Printf("path argument is not provided, resolving to default %s...\n", artifactPath)
 | 
						|
	}
 | 
						|
	return &publishGithubFlags{
 | 
						|
		artifactPath: artifactPath,
 | 
						|
		create:       create,
 | 
						|
		dryRun:       dryRun,
 | 
						|
		tag:          tag,
 | 
						|
		repo: &githubRepo{
 | 
						|
			owner: owner,
 | 
						|
			name:  name,
 | 
						|
		},
 | 
						|
	}, nil
 | 
						|
}
 | 
						|
 | 
						|
func runPublishGithubDryRun(f *publishGithubFlags, token string, c *cli.Context) error {
 | 
						|
	client := newGithubClient(c.Context, token)
 | 
						|
	fmt.Println("Dry-Run: Retrieving release on repository by tag")
 | 
						|
	release, res, err := client.GetReleaseByTag(c.Context, f.repo.owner, f.repo.name, f.tag)
 | 
						|
	if err != nil && res.StatusCode != 404 {
 | 
						|
		fmt.Println("Dry-Run: Github communication error:\n", err)
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
 | 
						|
	if release == nil {
 | 
						|
		if f.create {
 | 
						|
			fmt.Println("Dry-Run: Release doesn't exist and --create is enabled, so it would try to create the release")
 | 
						|
		} else {
 | 
						|
			fmt.Println("Dry-Run: Release doesn't exist and --create is disabled, so it would fail with error")
 | 
						|
			return nil
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	artifactName := path.Base(f.artifactPath)
 | 
						|
	fmt.Printf("Dry-Run: Opening file for release: %s\n", f.artifactPath)
 | 
						|
	_, err = os.Open(f.artifactPath)
 | 
						|
	if err != nil {
 | 
						|
		fmt.Println("Dry-Run: Error opening file\n", err)
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
 | 
						|
	fmt.Printf("Dry-Run: Would upload asset '%s' to release '%s' on repo '%s/%s' and return download URL if successful\n", artifactName, f.tag, f.repo.owner, f.repo.name)
 | 
						|
	return nil
 | 
						|
}
 |