github.com/ahmet2mir/goreleaser@v0.180.3-0.20210927151101-8e5ee5a9b8c5/internal/pipe/release/release.go (about)

     1  package release
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"os"
     7  	"time"
     8  
     9  	"github.com/apex/log"
    10  	"github.com/goreleaser/goreleaser/internal/artifact"
    11  	"github.com/goreleaser/goreleaser/internal/client"
    12  	"github.com/goreleaser/goreleaser/internal/extrafiles"
    13  	"github.com/goreleaser/goreleaser/internal/git"
    14  	"github.com/goreleaser/goreleaser/internal/semerrgroup"
    15  	"github.com/goreleaser/goreleaser/pkg/context"
    16  )
    17  
    18  // ErrMultipleReleases indicates that multiple releases are defined. ATM only one of them is allowed.
    19  // See https://github.com/goreleaser/goreleaser/pull/809
    20  var ErrMultipleReleases = errors.New("multiple releases are defined. Only one is allowed")
    21  
    22  // Pipe for github release.
    23  type Pipe struct{}
    24  
    25  func (Pipe) String() string                 { return "github/gitlab/gitea releases" }
    26  func (Pipe) Skip(ctx *context.Context) bool { return ctx.Config.Release.Disable }
    27  
    28  // Default sets the pipe defaults.
    29  func (Pipe) Default(ctx *context.Context) error {
    30  	numOfReleases := 0
    31  	if ctx.Config.Release.GitHub.String() != "" {
    32  		numOfReleases++
    33  	}
    34  	if ctx.Config.Release.GitLab.String() != "" {
    35  		numOfReleases++
    36  	}
    37  	if ctx.Config.Release.Gitea.String() != "" {
    38  		numOfReleases++
    39  	}
    40  	if numOfReleases > 1 {
    41  		return ErrMultipleReleases
    42  	}
    43  
    44  	if ctx.Config.Release.NameTemplate == "" {
    45  		ctx.Config.Release.NameTemplate = "{{.Tag}}"
    46  	}
    47  
    48  	// nolint: exhaustive
    49  	switch ctx.TokenType {
    50  	case context.TokenTypeGitLab:
    51  		{
    52  			if ctx.Config.Release.GitLab.Name == "" {
    53  				repo, err := git.ExtractRepoFromConfig()
    54  				if err != nil {
    55  					return err
    56  				}
    57  				ctx.Config.Release.GitLab = repo
    58  			}
    59  
    60  			return nil
    61  		}
    62  	case context.TokenTypeGitea:
    63  		{
    64  			if ctx.Config.Release.Gitea.Name == "" {
    65  				repo, err := git.ExtractRepoFromConfig()
    66  				if err != nil {
    67  					return err
    68  				}
    69  				ctx.Config.Release.Gitea = repo
    70  			}
    71  
    72  			return nil
    73  		}
    74  	}
    75  
    76  	// We keep github as default for now
    77  	if ctx.Config.Release.GitHub.Name == "" {
    78  		repo, err := git.ExtractRepoFromConfig()
    79  		if err != nil && !ctx.Snapshot {
    80  			return err
    81  		}
    82  		ctx.Config.Release.GitHub = repo
    83  	}
    84  
    85  	// Check if we have to check the git tag for an indicator to mark as pre release
    86  	switch ctx.Config.Release.Prerelease {
    87  	case "auto":
    88  		if ctx.Semver.Prerelease != "" {
    89  			ctx.PreRelease = true
    90  		}
    91  		log.Debugf("pre-release was detected for tag %s: %v", ctx.Git.CurrentTag, ctx.PreRelease)
    92  	case "true":
    93  		ctx.PreRelease = true
    94  	}
    95  	log.Debugf("pre-release for tag %s set to %v", ctx.Git.CurrentTag, ctx.PreRelease)
    96  
    97  	return nil
    98  }
    99  
   100  // Publish the release.
   101  func (Pipe) Publish(ctx *context.Context) error {
   102  	c, err := client.New(ctx)
   103  	if err != nil {
   104  		return err
   105  	}
   106  	return doPublish(ctx, c)
   107  }
   108  
   109  func doPublish(ctx *context.Context, client client.Client) error {
   110  	log.WithField("tag", ctx.Git.CurrentTag).
   111  		WithField("repo", ctx.Config.Release.GitHub.String()).
   112  		Info("creating or updating release")
   113  	body, err := describeBody(ctx)
   114  	if err != nil {
   115  		return err
   116  	}
   117  	releaseID, err := client.CreateRelease(ctx, body.String())
   118  	if err != nil {
   119  		return err
   120  	}
   121  
   122  	extraFiles, err := extrafiles.Find(ctx.Config.Release.ExtraFiles)
   123  	if err != nil {
   124  		return err
   125  	}
   126  
   127  	for name, path := range extraFiles {
   128  		if _, err := os.Stat(path); os.IsNotExist(err) {
   129  			return fmt.Errorf("failed to upload %s: %w", name, err)
   130  		}
   131  		ctx.Artifacts.Add(&artifact.Artifact{
   132  			Name: name,
   133  			Path: path,
   134  			Type: artifact.UploadableFile,
   135  		})
   136  	}
   137  
   138  	filters := artifact.Or(
   139  		artifact.ByType(artifact.UploadableArchive),
   140  		artifact.ByType(artifact.UploadableBinary),
   141  		artifact.ByType(artifact.UploadableSourceArchive),
   142  		artifact.ByType(artifact.Checksum),
   143  		artifact.ByType(artifact.Signature),
   144  		artifact.ByType(artifact.LinuxPackage),
   145  	)
   146  
   147  	if len(ctx.Config.Release.IDs) > 0 {
   148  		filters = artifact.And(filters, artifact.ByIDs(ctx.Config.Release.IDs...))
   149  	}
   150  
   151  	filters = artifact.Or(filters, artifact.ByType(artifact.UploadableFile))
   152  
   153  	g := semerrgroup.New(ctx.Parallelism)
   154  	for _, artifact := range ctx.Artifacts.Filter(filters).List() {
   155  		artifact := artifact
   156  		g.Go(func() error {
   157  			return upload(ctx, client, releaseID, artifact)
   158  		})
   159  	}
   160  	return g.Wait()
   161  }
   162  
   163  func upload(ctx *context.Context, cli client.Client, releaseID string, artifact *artifact.Artifact) error {
   164  	var try int
   165  	tryUpload := func() error {
   166  		try++
   167  		file, err := os.Open(artifact.Path)
   168  		if err != nil {
   169  			return err
   170  		}
   171  		defer file.Close()
   172  		log.WithField("file", file.Name()).WithField("name", artifact.Name).Info("uploading to release")
   173  		if err := cli.Upload(ctx, releaseID, artifact, file); err != nil {
   174  			log.WithField("try", try).
   175  				WithField("artifact", artifact.Name).
   176  				WithError(err).
   177  				Warnf("failed to upload artifact, will retry")
   178  			return err
   179  		}
   180  		return nil
   181  	}
   182  
   183  	var err error
   184  	for try < 10 {
   185  		err = tryUpload()
   186  		if err == nil {
   187  			return nil
   188  		}
   189  		if errors.As(err, &client.RetriableError{}) {
   190  			time.Sleep(time.Duration(try*50) * time.Millisecond)
   191  			continue
   192  		}
   193  		break
   194  	}
   195  
   196  	return fmt.Errorf("failed to upload %s after %d tries: %w", artifact.Name, try, err)
   197  }