mirror of
https://github.com/grafana/grafana.git
synced 2025-02-11 08:05:43 -06:00
241 lines
6.7 KiB
Go
241 lines
6.7 KiB
Go
package npm
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/grafana/grafana/pkg/build/gcloud/storage"
|
|
"github.com/grafana/grafana/pkg/build/lerna"
|
|
"github.com/grafana/grafana/pkg/build/versions"
|
|
)
|
|
|
|
const GrafanaDir = "."
|
|
const NpmArtifactDir = "./npm-artifacts"
|
|
|
|
// TODO: could this be replaced by `yarn lerna list -p` ?
|
|
var packages = []string{
|
|
"@grafana/ui",
|
|
"@grafana/data",
|
|
"@grafana/toolkit",
|
|
"@grafana/runtime",
|
|
"@grafana/e2e",
|
|
"@grafana/e2e-selectors",
|
|
"@grafana/schema",
|
|
}
|
|
|
|
// PublishNpmPackages will publish local NPM packages to NPM registry.
|
|
func PublishNpmPackages(ctx context.Context, tag string) error {
|
|
version, err := versions.GetVersion(tag)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
log.Printf("Grafana version: %s", version.Version)
|
|
|
|
if err := setNpmCredentials(); err != nil {
|
|
return err
|
|
}
|
|
|
|
npmArtifacts, err := storage.ListLocalFiles(NpmArtifactDir)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for _, packedFile := range npmArtifacts {
|
|
// nolint:gosec
|
|
cmd := exec.CommandContext(ctx, "npm", "publish", packedFile.FullPath, "--tag", version.Channel)
|
|
cmd.Dir = GrafanaDir
|
|
if out, err := cmd.CombinedOutput(); err != nil {
|
|
return fmt.Errorf("command '%s' failed to run, output: %s, err: %q", cmd.String(), out, err)
|
|
}
|
|
}
|
|
|
|
return updateTag(ctx, version, tag)
|
|
}
|
|
|
|
// StoreNpmPackages will store local NPM packages in GCS bucket `bucketName`.
|
|
func StoreNpmPackages(ctx context.Context, tag, bucketName string) error {
|
|
err := lerna.PackFrontendPackages(ctx, tag, GrafanaDir, NpmArtifactDir)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
gcs, err := storage.New()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
bucket := gcs.Bucket(bucketName)
|
|
bucketPath := fmt.Sprintf("artifacts/npm/%s/", tag)
|
|
if err = gcs.CopyLocalDir(ctx, NpmArtifactDir, bucket, bucketPath, true); err != nil {
|
|
return err
|
|
}
|
|
|
|
log.Print("Successfully stored npm packages!")
|
|
return nil
|
|
}
|
|
|
|
// FetchNpmPackages will store NPM packages stored in GCS bucket `bucketName` on local disk in `frontend.NpmArtifactDir`.
|
|
func FetchNpmPackages(ctx context.Context, tag, bucketName string) error {
|
|
gcs, err := storage.New()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
bucketPath := fmt.Sprintf("artifacts/npm/%s/", tag)
|
|
bucket := gcs.Bucket(bucketName)
|
|
err = gcs.DownloadDirectory(ctx, bucket, NpmArtifactDir, storage.FilesFilter{
|
|
Prefix: bucketPath,
|
|
FileExts: []string{".tgz"},
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// updateTag will move next or latest npm dist-tags, if needed.
|
|
//
|
|
// Note: This function makes the assumption that npm dist-tags has already
|
|
// been updated and hence why move of dist-tags not always happens:
|
|
//
|
|
// If stable the dist-tag latest was used.
|
|
// If beta the dist-tag next was used.
|
|
//
|
|
// Scenarios:
|
|
//
|
|
// 1. Releasing a newer stable than the current stable
|
|
// Latest and next is 9.1.5.
|
|
// 9.1.6 is released, latest and next should point to 9.1.6.
|
|
// The next dist-tag is moved to point to 9.1.6.
|
|
//
|
|
// 2. Releasing during an active beta period:
|
|
// Latest and next is 9.1.6.
|
|
// 9.2.0-beta1 is released, the latest should stay on 9.1.6, next should point to 9.2.0-beta1
|
|
// No move of dist-tags
|
|
// 9.1.7 is relased, the latest should point to 9.1.7, next should stay to 9.2.0-beta1
|
|
// No move of dist-tags
|
|
// Next week 9.2.0-beta2 is released, the latest should point to 9.1.7, next should point to 9.2.0-beta2
|
|
// No move of dist-tags
|
|
// In two weeks 9.2.0 stable is relased, the latest and next should point to 9.2.0.
|
|
// The next dist-tag is moved to point to 9.2.0.
|
|
//
|
|
// 3. Releasing an older stable than the current stable
|
|
// Latest and next is 9.2.0.
|
|
// Next 9.1.8 is released, latest should point to 9.2.0, next should point to 9.2.0
|
|
// The latest dist-tag is moved to point to 9.2.0.
|
|
func updateTag(ctx context.Context, version *versions.Version, releaseVersion string) error {
|
|
if version.Channel != versions.Latest {
|
|
return nil
|
|
}
|
|
|
|
latestStableVersion, err := getLatestStableVersion()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
betaVersion, err := getLatestBetaVersion()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
isLatest, err := versions.IsGreaterThanOrEqual(releaseVersion, latestStableVersion)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
isNewerThanLatestBeta, err := versions.IsGreaterThanOrEqual(releaseVersion, betaVersion)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, pkg := range packages {
|
|
if !isLatest {
|
|
err = runMoveLatestNPMTagCommand(ctx, pkg, latestStableVersion)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
if isLatest && isNewerThanLatestBeta {
|
|
err = runMoveNextNPMTagCommand(ctx, pkg, version.Version)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func getLatestStableVersion() (string, error) {
|
|
return versions.GetLatestVersion(versions.LatestStableVersionURL)
|
|
}
|
|
|
|
func getLatestBetaVersion() (string, error) {
|
|
return versions.GetLatestVersion(versions.LatestBetaVersionURL)
|
|
}
|
|
|
|
func runMoveNextNPMTagCommand(ctx context.Context, pkg string, packageVersion string) error {
|
|
// nolint:gosec
|
|
cmd := exec.CommandContext(ctx, "npm", "dist-tag", "add", fmt.Sprintf("%s@%s", pkg, packageVersion), "next")
|
|
if out, err := cmd.CombinedOutput(); err != nil {
|
|
return fmt.Errorf("command '%s' failed to run, output: %s, err: %q", cmd.String(), out, err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func runMoveLatestNPMTagCommand(ctx context.Context, pkg string, latestStableVersion string) error {
|
|
// nolint:gosec
|
|
cmd := exec.CommandContext(ctx, "npm", "dist-tag", "add", fmt.Sprintf("%s@%s", pkg, latestStableVersion), "latest")
|
|
if out, err := cmd.CombinedOutput(); err != nil {
|
|
return fmt.Errorf("command '%s' failed to run, output: %s, err: %q", cmd.String(), out, err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// setNpmCredentials Creates a .npmrc file in the users home folder and writes the
|
|
// necessary credentials to it for publishing packages to the NPM registry.
|
|
func setNpmCredentials() error {
|
|
npmToken := strings.TrimSpace(os.Getenv("NPM_TOKEN"))
|
|
if npmToken == "" {
|
|
return fmt.Errorf("npm token is not set")
|
|
}
|
|
|
|
homeDir, err := os.UserHomeDir()
|
|
if err != nil {
|
|
return fmt.Errorf("failed to obtain home directory, err: %q", err)
|
|
}
|
|
|
|
npmPath := filepath.Join(homeDir, ".npmrc")
|
|
registry := []byte(fmt.Sprintf("//registry.npmjs.org/:_authToken=%s", npmToken))
|
|
if _, err = os.Stat(npmPath); os.IsNotExist(err) {
|
|
// nolint:gosec
|
|
f, err := os.Create(npmPath)
|
|
if err != nil {
|
|
return fmt.Errorf("couldn't create npmrc file, err: %q", err)
|
|
}
|
|
_, err = f.Write(registry)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to write to file, err: %q", err)
|
|
}
|
|
defer func() {
|
|
if err := f.Close(); err != nil {
|
|
log.Printf("Failed to close file: %s", err.Error())
|
|
}
|
|
}()
|
|
} else {
|
|
err = os.WriteFile(npmPath, registry, 0644)
|
|
if err != nil {
|
|
return fmt.Errorf("error writing to file, err: %q", err)
|
|
}
|
|
}
|
|
return nil
|
|
}
|