github.com/goreleaser/goreleaser@v1.25.1/internal/client/client.go (about) 1 // Package client contains the client implementations for several providers. 2 package client 3 4 import ( 5 "fmt" 6 "os" 7 8 "github.com/caarlos0/log" 9 "github.com/goreleaser/goreleaser/internal/artifact" 10 "github.com/goreleaser/goreleaser/internal/tmpl" 11 "github.com/goreleaser/goreleaser/pkg/config" 12 "github.com/goreleaser/goreleaser/pkg/context" 13 ) 14 15 const ( 16 // maxReleaseBodyLength defines the max characters size of the body 17 maxReleaseBodyLength = 125000 18 // ellipsis to be used when release notes body is too long 19 ellipsis = "..." 20 ) 21 22 // ErrNotImplemented is returned when a client does not implement certain feature. 23 var ErrNotImplemented = fmt.Errorf("not implemented") 24 25 // ErrReleaseDisabled happens when a configuration tries to use the default 26 // url_template even though the release is disabled. 27 var ErrReleaseDisabled = fmt.Errorf("release is disabled, cannot use default url_template") 28 29 // Info of the repository. 30 type Info struct { 31 Description string 32 Homepage string 33 URL string 34 } 35 36 type Repo struct { 37 Owner string 38 Name string 39 Branch string 40 GitURL string 41 GitSSHCommand string 42 PrivateKey string 43 } 44 45 func (r Repo) String() string { 46 if r.Owner == "" && r.Name == "" { 47 return "" 48 } 49 return r.Owner + "/" + r.Name 50 } 51 52 // Client interface. 53 type Client interface { 54 CloseMilestone(ctx *context.Context, repo Repo, title string) (err error) 55 // Creates a release. It's marked as draft if possible (should call PublishRelease to finish publishing). 56 CreateRelease(ctx *context.Context, body string) (releaseID string, err error) 57 PublishRelease(ctx *context.Context, releaseID string) (err error) 58 Upload(ctx *context.Context, releaseID string, artifact *artifact.Artifact, file *os.File) (err error) 59 Changelog(ctx *context.Context, repo Repo, prev, current string) (string, error) 60 ReleaseURLTemplater 61 FileCreator 62 } 63 64 // ReleaseURLTemplater provides the release URL as a template, containing the 65 // artifact name as well. 66 type ReleaseURLTemplater interface { 67 ReleaseURLTemplate(ctx *context.Context) (string, error) 68 } 69 70 // RepoFile is a file to be created. 71 type RepoFile struct { 72 Content []byte 73 Path string 74 Identifier string // for the use of the caller. 75 } 76 77 // FileCreator can create the given file to some code repository. 78 type FileCreator interface { 79 CreateFile(ctx *context.Context, commitAuthor config.CommitAuthor, repo Repo, content []byte, path, message string) (err error) 80 } 81 82 // FilesCreator can create the multiple files in some repository and in a single commit. 83 type FilesCreator interface { 84 FileCreator 85 CreateFiles(ctx *context.Context, commitAuthor config.CommitAuthor, repo Repo, message string, files []RepoFile) (err error) 86 } 87 88 // ReleaseNotesGenerator can generate release notes. 89 type ReleaseNotesGenerator interface { 90 GenerateReleaseNotes(ctx *context.Context, repo Repo, prev, current string) (string, error) 91 } 92 93 // ForkSyncer can sync forks. 94 type ForkSyncer interface { 95 SyncFork(ctx *context.Context, head, base Repo) error 96 } 97 98 // PullRequestOpener can open pull requests. 99 type PullRequestOpener interface { 100 OpenPullRequest(ctx *context.Context, base, head Repo, title string, draft bool) error 101 } 102 103 // New creates a new client depending on the token type. 104 func New(ctx *context.Context) (Client, error) { 105 return newWithToken(ctx, ctx.Token) 106 } 107 108 // NewReleaseClient returns a ReleaserURLTemplater, handling the possibility of 109 // the release being disabled. 110 func NewReleaseClient(ctx *context.Context) (ReleaseURLTemplater, error) { 111 disable, err := tmpl.New(ctx).Bool(ctx.Config.Release.Disable) 112 if err != nil { 113 return nil, err 114 } 115 if disable { 116 return errURLTemplater{}, nil 117 } 118 return New(ctx) 119 } 120 121 var _ ReleaseURLTemplater = errURLTemplater{} 122 123 type errURLTemplater struct{} 124 125 func (errURLTemplater) ReleaseURLTemplate(_ *context.Context) (string, error) { 126 return "", ErrReleaseDisabled 127 } 128 129 func newWithToken(ctx *context.Context, token string) (Client, error) { 130 log.WithField("type", ctx.TokenType).Debug("token type") 131 switch ctx.TokenType { 132 case context.TokenTypeGitHub: 133 return newGitHub(ctx, token) 134 case context.TokenTypeGitLab: 135 return newGitLab(ctx, token) 136 case context.TokenTypeGitea: 137 return newGitea(ctx, token) 138 default: 139 return nil, fmt.Errorf("invalid client token type: %q", ctx.TokenType) 140 } 141 } 142 143 func NewIfToken(ctx *context.Context, cli Client, token string) (Client, error) { 144 if token == "" { 145 return cli, nil 146 } 147 token, err := tmpl.New(ctx).ApplySingleEnvOnly(token) 148 if err != nil { 149 return nil, err 150 } 151 log.Debug("using custom token") 152 return newWithToken(ctx, token) 153 } 154 155 func truncateReleaseBody(body string) string { 156 if len(body) > maxReleaseBodyLength { 157 body = body[1:(maxReleaseBodyLength-len(ellipsis))] + ellipsis 158 } 159 return body 160 } 161 162 // ErrNoMilestoneFound is an error when no milestone is found. 163 type ErrNoMilestoneFound struct { 164 Title string 165 } 166 167 func (e ErrNoMilestoneFound) Error() string { 168 return fmt.Sprintf("no milestone found: %s", e.Title) 169 } 170 171 // RetriableError is an error that will cause the action to be retried. 172 type RetriableError struct { 173 Err error 174 } 175 176 func (e RetriableError) Error() string { 177 return e.Err.Error() 178 }