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 }