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