github.com/ahmet2mir/goreleaser@v0.180.3-0.20210927151101-8e5ee5a9b8c5/internal/client/gitea.go (about) 1 package client 2 3 import ( 4 "crypto/tls" 5 "encoding/base64" 6 "fmt" 7 "net/http" 8 "net/url" 9 "os" 10 "strconv" 11 12 "code.gitea.io/sdk/gitea" 13 "github.com/apex/log" 14 "github.com/goreleaser/goreleaser/internal/artifact" 15 "github.com/goreleaser/goreleaser/internal/tmpl" 16 "github.com/goreleaser/goreleaser/pkg/config" 17 "github.com/goreleaser/goreleaser/pkg/context" 18 ) 19 20 type giteaClient struct { 21 client *gitea.Client 22 } 23 24 func getInstanceURL(ctx *context.Context) (string, error) { 25 apiURL, err := tmpl.New(ctx).Apply(ctx.Config.GiteaURLs.API) 26 if err != nil { 27 return "", fmt.Errorf("templating Gitea API URL: %w", err) 28 } 29 30 u, err := url.Parse(apiURL) 31 if err != nil { 32 return "", err 33 } 34 u.Path = "" 35 rawurl := u.String() 36 if rawurl == "" { 37 return "", fmt.Errorf("invalid URL: %v", apiURL) 38 } 39 return rawurl, nil 40 } 41 42 // NewGitea returns a gitea client implementation. 43 func NewGitea(ctx *context.Context, token string) (Client, error) { 44 instanceURL, err := getInstanceURL(ctx) 45 if err != nil { 46 return nil, err 47 } 48 transport := &http.Transport{ 49 Proxy: http.ProxyFromEnvironment, 50 TLSClientConfig: &tls.Config{ 51 // nolint: gosec 52 InsecureSkipVerify: ctx.Config.GiteaURLs.SkipTLSVerify, 53 }, 54 } 55 httpClient := &http.Client{Transport: transport} 56 client, err := gitea.NewClient(instanceURL, 57 gitea.SetToken(token), 58 gitea.SetHTTPClient(httpClient), 59 ) 60 if err != nil { 61 return nil, err 62 } 63 if ctx != nil { 64 gitea.SetContext(ctx)(client) 65 } 66 return &giteaClient{client: client}, nil 67 } 68 69 // CloseMilestone closes a given milestone. 70 func (c *giteaClient) CloseMilestone(ctx *context.Context, repo Repo, title string) error { 71 closedState := gitea.StateClosed 72 opts := gitea.EditMilestoneOption{ 73 State: &closedState, 74 Title: title, 75 } 76 77 _, resp, err := c.client.EditMilestoneByName(repo.Owner, repo.Name, title, opts) 78 if resp != nil && resp.StatusCode == http.StatusNotFound { 79 return ErrNoMilestoneFound{Title: title} 80 } 81 return err 82 } 83 84 // CreateFile creates a file in the repository at a given path 85 // or updates the file if it exists. 86 func (c *giteaClient) CreateFile( 87 ctx *context.Context, 88 commitAuthor config.CommitAuthor, 89 repo Repo, 90 content []byte, 91 path, 92 message string, 93 ) error { 94 // use default branch 95 branchName := "" 96 97 fileOptions := gitea.FileOptions{ 98 Message: message, 99 BranchName: branchName, 100 Author: gitea.Identity{ 101 Name: commitAuthor.Name, 102 Email: commitAuthor.Email, 103 }, 104 Committer: gitea.Identity{ 105 Name: commitAuthor.Name, 106 Email: commitAuthor.Email, 107 }, 108 } 109 110 currentFile, resp, err := c.client.GetContents(repo.Owner, repo.Name, branchName, path) 111 // file not exist, create it 112 if err != nil { 113 if resp == nil || resp.StatusCode != http.StatusNotFound { 114 return err 115 } 116 _, _, err = c.client.CreateFile(repo.Owner, repo.Name, path, gitea.CreateFileOptions{ 117 FileOptions: fileOptions, 118 Content: base64.StdEncoding.EncodeToString(content), 119 }) 120 return err 121 } 122 123 // update file 124 _, _, err = c.client.UpdateFile(repo.Owner, repo.Name, path, gitea.UpdateFileOptions{ 125 FileOptions: fileOptions, 126 SHA: currentFile.SHA, 127 Content: base64.StdEncoding.EncodeToString(content), 128 }) 129 return err 130 } 131 132 func (c *giteaClient) createRelease(ctx *context.Context, title, body string) (*gitea.Release, error) { 133 releaseConfig := ctx.Config.Release 134 owner := releaseConfig.Gitea.Owner 135 repoName := releaseConfig.Gitea.Name 136 tag := ctx.Git.CurrentTag 137 138 opts := gitea.CreateReleaseOption{ 139 TagName: tag, 140 Target: ctx.Git.Commit, 141 Title: title, 142 Note: body, 143 IsDraft: releaseConfig.Draft, 144 IsPrerelease: ctx.PreRelease, 145 } 146 release, _, err := c.client.CreateRelease(owner, repoName, opts) 147 if err != nil { 148 log.WithFields(log.Fields{ 149 "err": err.Error(), 150 }).Debug("error creating Gitea release") 151 return nil, err 152 } 153 log.WithField("id", release.ID).Info("Gitea release created") 154 return release, nil 155 } 156 157 func (c *giteaClient) getExistingRelease(owner, repoName, tagName string) (*gitea.Release, error) { 158 releases, _, err := c.client.ListReleases(owner, repoName, gitea.ListReleasesOptions{}) 159 if err != nil { 160 return nil, err 161 } 162 163 for _, release := range releases { 164 if release.TagName == tagName { 165 return release, nil 166 } 167 } 168 169 return nil, nil 170 } 171 172 func (c *giteaClient) updateRelease(ctx *context.Context, title, body string, id int64) (*gitea.Release, error) { 173 releaseConfig := ctx.Config.Release 174 owner := releaseConfig.Gitea.Owner 175 repoName := releaseConfig.Gitea.Name 176 tag := ctx.Git.CurrentTag 177 178 opts := gitea.EditReleaseOption{ 179 TagName: tag, 180 Target: ctx.Git.Commit, 181 Title: title, 182 Note: body, 183 IsDraft: &releaseConfig.Draft, 184 IsPrerelease: &ctx.PreRelease, 185 } 186 187 release, _, err := c.client.EditRelease(owner, repoName, id, opts) 188 if err != nil { 189 log.WithFields(log.Fields{ 190 "err": err.Error(), 191 }).Debug("error updating Gitea release") 192 return nil, err 193 } 194 log.WithField("id", release.ID).Info("Gitea release updated") 195 return release, nil 196 } 197 198 // CreateRelease creates a new release or updates it by keeping 199 // the release notes if it exists. 200 func (c *giteaClient) CreateRelease(ctx *context.Context, body string) (string, error) { 201 var release *gitea.Release 202 var err error 203 204 releaseConfig := ctx.Config.Release 205 206 title, err := tmpl.New(ctx).Apply(releaseConfig.NameTemplate) 207 if err != nil { 208 return "", err 209 } 210 211 release, err = c.getExistingRelease( 212 releaseConfig.Gitea.Owner, 213 releaseConfig.Gitea.Name, 214 ctx.Git.CurrentTag, 215 ) 216 if err != nil { 217 return "", err 218 } 219 220 if release != nil { 221 if release.Note != "" { 222 body = release.Note 223 } 224 release, err = c.updateRelease(ctx, title, body, release.ID) 225 if err != nil { 226 return "", err 227 } 228 } else { 229 release, err = c.createRelease(ctx, title, body) 230 if err != nil { 231 return "", err 232 } 233 } 234 235 return strconv.FormatInt(release.ID, 10), nil 236 } 237 238 func (c *giteaClient) ReleaseURLTemplate(ctx *context.Context) (string, error) { 239 downloadURL, err := tmpl.New(ctx).Apply(ctx.Config.GiteaURLs.Download) 240 if err != nil { 241 return "", fmt.Errorf("templating Gitea download URL: %w", err) 242 } 243 244 return fmt.Sprintf( 245 "%s/%s/%s/releases/download/{{ .Tag }}/{{ .ArtifactName }}", 246 downloadURL, 247 ctx.Config.Release.Gitea.Owner, 248 ctx.Config.Release.Gitea.Name, 249 ), nil 250 } 251 252 // Upload uploads a file into a release repository. 253 func (c *giteaClient) Upload( 254 ctx *context.Context, 255 releaseID string, 256 artifact *artifact.Artifact, 257 file *os.File, 258 ) error { 259 giteaReleaseID, err := strconv.ParseInt(releaseID, 10, 64) 260 if err != nil { 261 return err 262 } 263 releaseConfig := ctx.Config.Release 264 owner := releaseConfig.Gitea.Owner 265 repoName := releaseConfig.Gitea.Name 266 267 _, _, err = c.client.CreateReleaseAttachment(owner, repoName, giteaReleaseID, file, artifact.Name) 268 if err != nil { 269 return RetriableError{err} 270 } 271 return nil 272 }