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