mirror of
https://github.com/goreleaser/goreleaser.git
synced 2025-01-08 03:31:59 +02:00
fe7e2123bd
* feat: replacing logs Signed-off-by: Carlos A Becker <caarlos0@users.noreply.github.com> * fix: tests et al Signed-off-by: Carlos A Becker <caarlos0@users.noreply.github.com> * feat: update termenv/lipgloss Signed-off-by: Carlos A Becker <caarlos0@users.noreply.github.com> * wip: output Signed-off-by: Carlos A Becker <caarlos0@users.noreply.github.com> * fix: pin dep Signed-off-by: Carlos A Becker <caarlos0@users.noreply.github.com> * fix: update Signed-off-by: Carlos A Becker <caarlos0@users.noreply.github.com> * fix: tests Signed-off-by: Carlos A Becker <caarlos0@users.noreply.github.com> * fix: tests Signed-off-by: Carlos A Becker <caarlos0@users.noreply.github.com> * fix: deps Signed-off-by: Carlos A Becker <caarlos0@users.noreply.github.com> * fix: dep Signed-off-by: Carlos A Becker <caarlos0@users.noreply.github.com>
307 lines
7.7 KiB
Go
307 lines
7.7 KiB
Go
package client
|
|
|
|
import (
|
|
"crypto/tls"
|
|
"encoding/base64"
|
|
"fmt"
|
|
"net/http"
|
|
"net/url"
|
|
"os"
|
|
"strconv"
|
|
|
|
"code.gitea.io/sdk/gitea"
|
|
"github.com/caarlos0/log"
|
|
"github.com/goreleaser/goreleaser/internal/artifact"
|
|
"github.com/goreleaser/goreleaser/internal/tmpl"
|
|
"github.com/goreleaser/goreleaser/pkg/config"
|
|
"github.com/goreleaser/goreleaser/pkg/context"
|
|
)
|
|
|
|
type giteaClient struct {
|
|
client *gitea.Client
|
|
}
|
|
|
|
func getInstanceURL(ctx *context.Context) (string, error) {
|
|
apiURL, err := tmpl.New(ctx).Apply(ctx.Config.GiteaURLs.API)
|
|
if err != nil {
|
|
return "", fmt.Errorf("templating Gitea API URL: %w", err)
|
|
}
|
|
|
|
u, err := url.Parse(apiURL)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
u.Path = ""
|
|
rawurl := u.String()
|
|
if rawurl == "" {
|
|
return "", fmt.Errorf("invalid URL: %v", apiURL)
|
|
}
|
|
return rawurl, nil
|
|
}
|
|
|
|
// NewGitea returns a gitea client implementation.
|
|
func NewGitea(ctx *context.Context, token string) (Client, error) {
|
|
instanceURL, err := getInstanceURL(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
transport := &http.Transport{
|
|
Proxy: http.ProxyFromEnvironment,
|
|
TLSClientConfig: &tls.Config{
|
|
// nolint: gosec
|
|
InsecureSkipVerify: ctx.Config.GiteaURLs.SkipTLSVerify,
|
|
},
|
|
}
|
|
httpClient := &http.Client{Transport: transport}
|
|
client, err := gitea.NewClient(instanceURL,
|
|
gitea.SetToken(token),
|
|
gitea.SetHTTPClient(httpClient),
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if ctx != nil {
|
|
if err := gitea.SetContext(ctx)(client); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
return &giteaClient{client: client}, nil
|
|
}
|
|
|
|
func (c *giteaClient) Changelog(ctx *context.Context, repo Repo, prev, current string) (string, error) {
|
|
return "", ErrNotImplemented
|
|
}
|
|
|
|
// CloseMilestone closes a given milestone.
|
|
func (c *giteaClient) CloseMilestone(ctx *context.Context, repo Repo, title string) error {
|
|
closedState := gitea.StateClosed
|
|
opts := gitea.EditMilestoneOption{
|
|
State: &closedState,
|
|
Title: title,
|
|
}
|
|
|
|
_, resp, err := c.client.EditMilestoneByName(repo.Owner, repo.Name, title, opts)
|
|
if resp != nil && resp.StatusCode == http.StatusNotFound {
|
|
return ErrNoMilestoneFound{Title: title}
|
|
}
|
|
return err
|
|
}
|
|
|
|
func (c *giteaClient) GetDefaultBranch(ctx *context.Context, repo Repo) (string, error) {
|
|
projectID := repo.String()
|
|
p, res, err := c.client.GetRepo(repo.Owner, repo.Name)
|
|
if err != nil {
|
|
log.WithFields(log.Fields{
|
|
"projectID": projectID,
|
|
"statusCode": res.StatusCode,
|
|
"err": err.Error(),
|
|
}).Warn("error checking for default branch")
|
|
return "", err
|
|
}
|
|
return p.DefaultBranch, nil
|
|
}
|
|
|
|
// CreateFile creates a file in the repository at a given path
|
|
// or updates the file if it exists.
|
|
func (c *giteaClient) CreateFile(
|
|
ctx *context.Context,
|
|
commitAuthor config.CommitAuthor,
|
|
repo Repo,
|
|
content []byte,
|
|
path,
|
|
message string,
|
|
) error {
|
|
// use default branch
|
|
var branch string
|
|
var err error
|
|
if repo.Branch != "" {
|
|
branch = repo.Branch
|
|
} else {
|
|
branch, err = c.GetDefaultBranch(ctx, repo)
|
|
if err != nil {
|
|
// Fall back to 'master' 😭
|
|
log.WithFields(log.Fields{
|
|
"fileName": path,
|
|
"projectID": repo.String(),
|
|
"requestedBranch": branch,
|
|
"err": err.Error(),
|
|
}).Warn("error checking for default branch, using master")
|
|
}
|
|
|
|
}
|
|
|
|
fileOptions := gitea.FileOptions{
|
|
Message: message,
|
|
BranchName: branch,
|
|
Author: gitea.Identity{
|
|
Name: commitAuthor.Name,
|
|
Email: commitAuthor.Email,
|
|
},
|
|
Committer: gitea.Identity{
|
|
Name: commitAuthor.Name,
|
|
Email: commitAuthor.Email,
|
|
},
|
|
}
|
|
|
|
currentFile, resp, err := c.client.GetContents(repo.Owner, repo.Name, branch, path)
|
|
// file not exist, create it
|
|
if err != nil {
|
|
if resp == nil || resp.StatusCode != http.StatusNotFound {
|
|
return err
|
|
}
|
|
_, _, err = c.client.CreateFile(repo.Owner, repo.Name, path, gitea.CreateFileOptions{
|
|
FileOptions: fileOptions,
|
|
Content: base64.StdEncoding.EncodeToString(content),
|
|
})
|
|
return err
|
|
}
|
|
|
|
// update file
|
|
_, _, err = c.client.UpdateFile(repo.Owner, repo.Name, path, gitea.UpdateFileOptions{
|
|
FileOptions: fileOptions,
|
|
SHA: currentFile.SHA,
|
|
Content: base64.StdEncoding.EncodeToString(content),
|
|
})
|
|
return err
|
|
}
|
|
|
|
func (c *giteaClient) createRelease(ctx *context.Context, title, body string) (*gitea.Release, error) {
|
|
releaseConfig := ctx.Config.Release
|
|
owner := releaseConfig.Gitea.Owner
|
|
repoName := releaseConfig.Gitea.Name
|
|
tag := ctx.Git.CurrentTag
|
|
|
|
opts := gitea.CreateReleaseOption{
|
|
TagName: tag,
|
|
Target: ctx.Git.Commit,
|
|
Title: title,
|
|
Note: body,
|
|
IsDraft: releaseConfig.Draft,
|
|
IsPrerelease: ctx.PreRelease,
|
|
}
|
|
release, _, err := c.client.CreateRelease(owner, repoName, opts)
|
|
if err != nil {
|
|
log.WithFields(log.Fields{
|
|
"err": err.Error(),
|
|
}).Debug("error creating Gitea release")
|
|
return nil, err
|
|
}
|
|
log.WithField("id", release.ID).Info("Gitea release created")
|
|
return release, nil
|
|
}
|
|
|
|
func (c *giteaClient) getExistingRelease(owner, repoName, tagName string) (*gitea.Release, error) {
|
|
releases, _, err := c.client.ListReleases(owner, repoName, gitea.ListReleasesOptions{})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for _, release := range releases {
|
|
if release.TagName == tagName {
|
|
return release, nil
|
|
}
|
|
}
|
|
|
|
return nil, nil
|
|
}
|
|
|
|
func (c *giteaClient) updateRelease(ctx *context.Context, title, body string, id int64) (*gitea.Release, error) {
|
|
releaseConfig := ctx.Config.Release
|
|
owner := releaseConfig.Gitea.Owner
|
|
repoName := releaseConfig.Gitea.Name
|
|
tag := ctx.Git.CurrentTag
|
|
|
|
opts := gitea.EditReleaseOption{
|
|
TagName: tag,
|
|
Target: ctx.Git.Commit,
|
|
Title: title,
|
|
Note: body,
|
|
IsDraft: &releaseConfig.Draft,
|
|
IsPrerelease: &ctx.PreRelease,
|
|
}
|
|
|
|
release, _, err := c.client.EditRelease(owner, repoName, id, opts)
|
|
if err != nil {
|
|
log.WithFields(log.Fields{
|
|
"err": err.Error(),
|
|
}).Debug("error updating Gitea release")
|
|
return nil, err
|
|
}
|
|
log.WithField("id", release.ID).Info("Gitea release updated")
|
|
return release, nil
|
|
}
|
|
|
|
// CreateRelease creates a new release or updates it by keeping
|
|
// the release notes if it exists.
|
|
func (c *giteaClient) CreateRelease(ctx *context.Context, body string) (string, error) {
|
|
var release *gitea.Release
|
|
var err error
|
|
|
|
releaseConfig := ctx.Config.Release
|
|
|
|
title, err := tmpl.New(ctx).Apply(releaseConfig.NameTemplate)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
release, err = c.getExistingRelease(
|
|
releaseConfig.Gitea.Owner,
|
|
releaseConfig.Gitea.Name,
|
|
ctx.Git.CurrentTag,
|
|
)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
if release != nil {
|
|
body = getReleaseNotes(release.Note, body, ctx.Config.Release.ReleaseNotesMode)
|
|
release, err = c.updateRelease(ctx, title, body, release.ID)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
} else {
|
|
release, err = c.createRelease(ctx, title, body)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
}
|
|
|
|
return strconv.FormatInt(release.ID, 10), nil
|
|
}
|
|
|
|
func (c *giteaClient) ReleaseURLTemplate(ctx *context.Context) (string, error) {
|
|
downloadURL, err := tmpl.New(ctx).Apply(ctx.Config.GiteaURLs.Download)
|
|
if err != nil {
|
|
return "", fmt.Errorf("templating Gitea download URL: %w", err)
|
|
}
|
|
|
|
return fmt.Sprintf(
|
|
"%s/%s/%s/releases/download/{{ .Tag }}/{{ .ArtifactName }}",
|
|
downloadURL,
|
|
ctx.Config.Release.Gitea.Owner,
|
|
ctx.Config.Release.Gitea.Name,
|
|
), nil
|
|
}
|
|
|
|
// Upload uploads a file into a release repository.
|
|
func (c *giteaClient) Upload(
|
|
ctx *context.Context,
|
|
releaseID string,
|
|
artifact *artifact.Artifact,
|
|
file *os.File,
|
|
) error {
|
|
giteaReleaseID, err := strconv.ParseInt(releaseID, 10, 64)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
releaseConfig := ctx.Config.Release
|
|
owner := releaseConfig.Gitea.Owner
|
|
repoName := releaseConfig.Gitea.Name
|
|
|
|
_, _, err = c.client.CreateReleaseAttachment(owner, repoName, giteaReleaseID, file, artifact.Name)
|
|
if err != nil {
|
|
return RetriableError{err}
|
|
}
|
|
return nil
|
|
}
|