1
0
mirror of https://github.com/goreleaser/goreleaser.git synced 2025-01-10 03:47:03 +02:00
goreleaser/internal/pipe/release/release.go
Carlos Alexandro Becker 8706fd2e89
feat: allow goreleaser to run in gerrit, soft-serve and others (#4271)
Currently, GoReleaser will assume you're running against github, gitea
or gitlab.

You could set `release.disable: true`, but it would still set and try to
use some defaults that could break things up.

Now, if you disable the release, goreleaser will not set these defaults.
It'll also hard error in some cases in which it would happily produce
invalid resources before, namely, if `release.disable` is set, and, for
example, `brews.url_template` is empty (in which case it would try to
use the one from the release, usually github).

closes #4208
2023-09-04 11:23:38 -03:00

212 lines
5.3 KiB
Go

package release
import (
"errors"
"fmt"
"io/fs"
"os"
"time"
"github.com/caarlos0/log"
"github.com/goreleaser/goreleaser/internal/artifact"
"github.com/goreleaser/goreleaser/internal/client"
"github.com/goreleaser/goreleaser/internal/extrafiles"
"github.com/goreleaser/goreleaser/internal/git"
"github.com/goreleaser/goreleaser/internal/pipe"
"github.com/goreleaser/goreleaser/internal/semerrgroup"
"github.com/goreleaser/goreleaser/internal/tmpl"
"github.com/goreleaser/goreleaser/pkg/config"
"github.com/goreleaser/goreleaser/pkg/context"
)
// ErrMultipleReleases indicates that multiple releases are defined. ATM only one of them is allowed.
// See https://github.com/goreleaser/goreleaser/pull/809
var ErrMultipleReleases = errors.New("multiple releases are defined. Only one is allowed")
// Pipe for github release.
type Pipe struct{}
func (Pipe) String() string { return "scm releases" }
func (Pipe) Skip(ctx *context.Context) (bool, error) {
return tmpl.New(ctx).Bool(ctx.Config.Release.Disable)
}
// Default sets the pipe defaults.
func (p Pipe) Default(ctx *context.Context) error {
if b, _ := p.Skip(ctx); b {
return pipe.Skip("release is disabled")
}
numOfReleases := 0
if ctx.Config.Release.GitHub.String() != "" {
numOfReleases++
}
if ctx.Config.Release.GitLab.String() != "" {
numOfReleases++
}
if ctx.Config.Release.Gitea.String() != "" {
numOfReleases++
}
if numOfReleases > 1 {
return ErrMultipleReleases
}
if ctx.Config.Release.NameTemplate == "" {
ctx.Config.Release.NameTemplate = "{{.Tag}}"
}
switch ctx.TokenType {
case context.TokenTypeGitLab:
if err := setupGitLab(ctx); err != nil {
return err
}
case context.TokenTypeGitea:
if err := setupGitea(ctx); err != nil {
return err
}
default:
// We keep github as default for now
if err := setupGitHub(ctx); err != nil {
return err
}
}
// Check if we have to check the git tag for an indicator to mark as pre release
switch ctx.Config.Release.Prerelease {
case "auto":
if ctx.Semver.Prerelease != "" {
ctx.PreRelease = true
}
log.Debugf("pre-release was detected for tag %s: %v", ctx.Git.CurrentTag, ctx.PreRelease)
case "true":
ctx.PreRelease = true
}
log.Debugf("pre-release for tag %s set to %v", ctx.Git.CurrentTag, ctx.PreRelease)
return nil
}
func getRepository(ctx *context.Context) (config.Repo, error) {
repo, err := git.ExtractRepoFromConfig(ctx)
if err != nil {
return config.Repo{}, err
}
if err := repo.CheckSCM(); err != nil {
return config.Repo{}, err
}
return repo, nil
}
// Publish the release.
func (Pipe) Publish(ctx *context.Context) error {
c, err := client.New(ctx)
if err != nil {
return err
}
if err := doPublish(ctx, c); err != nil {
return err
}
log.WithField("url", ctx.ReleaseURL).Info("published")
return nil
}
func doPublish(ctx *context.Context, client client.Client) error {
log.WithField("tag", ctx.Git.CurrentTag).
WithField("repo", ctx.Config.Release.GitHub.String()).
Info("creating or updating release")
body, err := describeBody(ctx)
if err != nil {
return err
}
releaseID, err := client.CreateRelease(ctx, body.String())
if err != nil {
return err
}
skipUpload, err := tmpl.New(ctx).Bool(ctx.Config.Release.SkipUpload)
if err != nil {
return err
}
if skipUpload {
return pipe.Skip("release.skip_upload is set")
}
extraFiles, err := extrafiles.Find(ctx, ctx.Config.Release.ExtraFiles)
if err != nil {
return err
}
for name, path := range extraFiles {
if _, err := os.Stat(path); errors.Is(err, fs.ErrNotExist) {
return fmt.Errorf("failed to upload %s: %w", name, err)
}
ctx.Artifacts.Add(&artifact.Artifact{
Name: name,
Path: path,
Type: artifact.UploadableFile,
})
}
filters := artifact.Or(
artifact.ByType(artifact.UploadableArchive),
artifact.ByType(artifact.UploadableBinary),
artifact.ByType(artifact.UploadableSourceArchive),
artifact.ByType(artifact.Checksum),
artifact.ByType(artifact.Signature),
artifact.ByType(artifact.Certificate),
artifact.ByType(artifact.LinuxPackage),
artifact.ByType(artifact.SBOM),
)
if len(ctx.Config.Release.IDs) > 0 {
filters = artifact.And(filters, artifact.ByIDs(ctx.Config.Release.IDs...))
}
filters = artifact.Or(filters, artifact.ByType(artifact.UploadableFile))
g := semerrgroup.New(ctx.Parallelism)
for _, artifact := range ctx.Artifacts.Filter(filters).List() {
artifact := artifact
g.Go(func() error {
return upload(ctx, client, releaseID, artifact)
})
}
return g.Wait()
}
func upload(ctx *context.Context, cli client.Client, releaseID string, artifact *artifact.Artifact) error {
var try int
tryUpload := func() error {
try++
file, err := os.Open(artifact.Path)
if err != nil {
return err
}
defer file.Close()
log.WithField("file", file.Name()).WithField("name", artifact.Name).Info("uploading to release")
if err := cli.Upload(ctx, releaseID, artifact, file); err != nil {
log.WithField("try", try).
WithField("artifact", artifact.Name).
WithError(err).
Warnf("failed to upload artifact, will retry")
return err
}
return nil
}
var err error
for try < 10 {
err = tryUpload()
if err == nil {
return nil
}
if errors.As(err, &client.RetriableError{}) {
time.Sleep(time.Duration(try*50) * time.Millisecond)
continue
}
break
}
return fmt.Errorf("failed to upload %s after %d tries: %w", artifact.Name, try, err)
}