diff --git a/containers/gcom_publish.go b/containers/gcom_publish.go index 38205866..6f64cfd0 100644 --- a/containers/gcom_publish.go +++ b/containers/gcom_publish.go @@ -9,32 +9,49 @@ import ( ) type GCOMVersionPayload struct { - Version string `json:"version"` // "10.0.3" - ReleaseDate string `json:"releaseDate"` // "2023-07-26T08:20:16.628278891Z" - Stable bool `json:"stable"` // true - Beta bool `json:"beta"` // false - Nightly bool `json:"nightly"` // false - WhatsNewURL string `json:"whatsNewUrl"` // "https://grafana.com/docs/grafana/next/whatsnew/whats-new-in-v10-0/" - ReleaseNotesURL string `json:"releaseNotesUrl"` // "https://grafana.com/docs/grafana/next/release-notes/" + Version string `json:"version"` + ReleaseDate string `json:"releaseDate"` + Stable bool `json:"stable"` + Beta bool `json:"beta"` + Nightly bool `json:"nightly"` + WhatsNewURL string `json:"whatsNewUrl"` + ReleaseNotesURL string `json:"releaseNotesUrl"` } type GCOMPackagePayload struct { - OS string `json:"os"` // "deb" - URL string `json:"url"` // "https://dl.grafana.com/oss/release/grafana_10.0.3_arm64.deb" - Sha256 string `json:"sha256"` // "78a718816dd556198cfa3007dd594aaf1d80886decae8c4bd0f615bd3f118279\n" - Arch string `json:"arch"` // "arm64" + OS string `json:"os"` + URL string `json:"url"` + Sha256 string `json:"sha256"` + Arch string `json:"arch"` } -// PublishGCOM publishes a package to grafana.com. -func PublishGCOM(ctx context.Context, d *dagger.Client, versionPayload *GCOMVersionPayload, packagePayload *GCOMPackagePayload, opts *GCOMOpts) error { - versionApiUrl := fmt.Sprintf("%s/api/grafana/versions", opts.URL) - packagesApiUrl := fmt.Sprintf("%s/api/grafana/versions/%s/packages", opts.URL, versionPayload.Version) +// PublishGCOMVersion publishes a version to grafana.com. +func PublishGCOMVersion(ctx context.Context, d *dagger.Client, versionPayload *GCOMVersionPayload, opts *GCOMOpts) error { + versionApiUrl := opts.URL.JoinPath("/api/grafana/versions") jsonVersionPayload, err := json.Marshal(versionPayload) if err != nil { return err } + apiKeySecret := d.SetSecret("gcom-api-key", opts.ApiKey) + + _, err = d.Container().From("alpine/curl"). + WithSecretVariable("GCOM_API_KEY", apiKeySecret). + WithExec([]string{"/bin/sh", "-c", fmt.Sprintf(`curl -H "Content-Type: application/json" -H "Authorization: Bearer $GCOM_API_KEY" -d '%s' %s`, string(jsonVersionPayload), versionApiUrl.String())}). + Sync(ctx) + + if err != nil { + return err + } + + return nil +} + +// PublishGCOMPackage publishes a package to grafana.com. +func PublishGCOMPackage(ctx context.Context, d *dagger.Client, packagePayload *GCOMPackagePayload, opts *GCOMOpts, version string) error { + packagesApiUrl := opts.URL.JoinPath("/api/grafana/versions/", version, "/packages") + jsonPackagePayload, err := json.Marshal(packagePayload) if err != nil { return err @@ -44,8 +61,7 @@ func PublishGCOM(ctx context.Context, d *dagger.Client, versionPayload *GCOMVers _, err = d.Container().From("alpine/curl"). WithSecretVariable("GCOM_API_KEY", apiKeySecret). - WithExec([]string{"/bin/sh", "-c", fmt.Sprintf(`curl -H "Content-Type: application/json" -H "Authorization: Bearer $GCOM_API_KEY" -d '%s' %s`, string(jsonVersionPayload), versionApiUrl)}). - WithExec([]string{"/bin/sh", "-c", fmt.Sprintf(`curl -H "Content-Type: application/json" -H "Authorization: Bearer $GCOM_API_KEY" -d '%s' %s`, string(jsonPackagePayload), packagesApiUrl)}). + WithExec([]string{"/bin/sh", "-c", fmt.Sprintf(`curl -H "Content-Type: application/json" -H "Authorization: Bearer $GCOM_API_KEY" -d '%s' %s`, string(jsonPackagePayload), packagesApiUrl.String())}). Sync(ctx) if err != nil { diff --git a/containers/opts_gcom.go b/containers/opts_gcom.go index 9536685d..a4586993 100644 --- a/containers/opts_gcom.go +++ b/containers/opts_gcom.go @@ -1,18 +1,30 @@ package containers -import "github.com/grafana/grafana-build/cliutil" +import ( + "net/url" + + "github.com/grafana/grafana-build/cliutil" +) // GCOMOpts are options used when making requests to grafana.com. type GCOMOpts struct { - URL string + URL *url.URL + DownloadURL *url.URL ApiKey string - DownloadURL string } -func GCOMOptsFromFlags(c cliutil.CLIContext) *GCOMOpts { +func GCOMOptsFromFlags(c cliutil.CLIContext) (*GCOMOpts, error) { + apiUrl, err := url.Parse(c.String("url")) + if err != nil { + return nil, err + } + downloadUrl, err := url.Parse(c.String("download-url")) + if err != nil { + return nil, err + } return &GCOMOpts{ - URL: c.String("url"), + URL: apiUrl, + DownloadURL: downloadUrl, ApiKey: c.String("api-key"), - DownloadURL: c.String("download-url"), - } + }, nil } diff --git a/pipelines/gcom_publish.go b/pipelines/gcom_publish.go index 2c1e9fd0..a2ee4c1f 100644 --- a/pipelines/gcom_publish.go +++ b/pipelines/gcom_publish.go @@ -71,7 +71,7 @@ func PackagePayloadFromFile(ctx context.Context, d *dagger.Client, name string, return &containers.GCOMPackagePayload{ OS: os, - URL: fmt.Sprintf("%s/%s", opts.DownloadURL, name), + URL: opts.DownloadURL.JoinPath(name).String(), Sha256: sha256, Arch: arch, }, nil @@ -89,16 +89,37 @@ func PublishGCOM(ctx context.Context, d *dagger.Client, args PipelineArgs) error return err } - // Extract the package(s) + // Extract the package versions + versionPayloads := make(map[string]*containers.GCOMVersionPayload) + for _, name := range args.PackageInputOpts.Packages { + tarOpts := TarOptsFromFileName(name) + if _, ok := versionPayloads[tarOpts.Version]; !ok { + log.Printf("[%s] Building version payload", tarOpts.Version) + versionPayloads[tarOpts.Version] = VersionPayloadFromFileName(name) + } + } + + // Publish each version only once + for _, p := range versionPayloads { + log.Printf("[%s] Attempting to publish version", p.Version) + err := containers.PublishGCOMVersion(ctx, d, p, opts) + if err != nil { + return err + } + log.Printf("[%s] Done publishing version", p.Version) + } + + // Publish the package(s) for i, name := range args.PackageInputOpts.Packages { - wg.Go(PublishGCOMFunc(ctx, sm, d, opts, name, packages[i])) + wg.Go(PublishGCOMPackageFunc(ctx, sm, d, opts, name, packages[i])) } return wg.Wait() } -func PublishGCOMFunc(ctx context.Context, sm *semaphore.Weighted, d *dagger.Client, opts *containers.GCOMOpts, path string, file *dagger.File) func() error { +func PublishGCOMPackageFunc(ctx context.Context, sm *semaphore.Weighted, d *dagger.Client, opts *containers.GCOMOpts, path string, file *dagger.File) func() error { return func() error { name := filepath.Base(path) + tarOpts := TarOptsFromFileName(name) log.Printf("[%s] Attempting to publish package", name) log.Printf("[%s] Acquiring semaphore", name) if err := sm.Acquire(ctx, 1); err != nil { @@ -107,9 +128,6 @@ func PublishGCOMFunc(ctx context.Context, sm *semaphore.Weighted, d *dagger.Clie defer sm.Release(1) log.Printf("[%s] Acquired semaphore", name) - log.Printf("[%s] Building version payload", name) - versionPayload := VersionPayloadFromFileName(name) - log.Printf("[%s] Building package payload", name) packagePayload, err := PackagePayloadFromFile(ctx, d, name, file, opts) if err != nil { @@ -117,7 +135,7 @@ func PublishGCOMFunc(ctx context.Context, sm *semaphore.Weighted, d *dagger.Clie } log.Printf("[%s] Publishing package", name) - err = containers.PublishGCOM(ctx, d, versionPayload, packagePayload, opts) + err = containers.PublishGCOMPackage(ctx, d, packagePayload, opts, tarOpts.Version) if err != nil { return fmt.Errorf("[%s] error: %w", name, err) } diff --git a/pipelines/pipeline_args.go b/pipelines/pipeline_args.go index f8f82ade..164a325a 100644 --- a/pipelines/pipeline_args.go +++ b/pipelines/pipeline_args.go @@ -77,6 +77,10 @@ func PipelineArgsFromContext(ctx context.Context, c cliutil.CLIContext) (Pipelin if err != nil { return PipelineArgs{}, err } + gcomOpts, err := containers.GCOMOptsFromFlags(c) + if err != nil { + return PipelineArgs{}, err + } return PipelineArgs{ Context: c, @@ -92,7 +96,7 @@ func PipelineArgsFromContext(ctx context.Context, c cliutil.CLIContext) (Pipelin ConcurrencyOpts: ConcurrencyOptsFromFlags(c), ProImageOpts: containers.ProImageOptsFromFlags(c), NPMOpts: containers.NPMOptsFromFlags(c), - GCOMOpts: containers.GCOMOptsFromFlags(c), + GCOMOpts: gcomOpts, }, nil }