1
0
mirror of https://github.com/goreleaser/goreleaser.git synced 2025-01-24 04:16:27 +02:00
Carlos Alexandro Becker 8706fd2e89
feat: allow goreleaser to run in gerrit, soft-serve and others (#4271)
Currently, GoReleaser will assume you're running against github, gitea
or gitlab.

You could set `release.disable: true`, but it would still set and try to
use some defaults that could break things up.

Now, if you disable the release, goreleaser will not set these defaults.
It'll also hard error in some cases in which it would happily produce
invalid resources before, namely, if `release.disable` is set, and, for
example, `brews.url_template` is empty (in which case it would try to
use the one from the release, usually github).

closes #4208
2023-09-04 11:23:38 -03:00

172 lines
4.8 KiB
Go

// Package client contains the client implementations for several providers.
package client
import (
"fmt"
"os"
"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"
)
const (
// maxReleaseBodyLength defines the max characters size of the body
maxReleaseBodyLength = 125000
// ellipsis to be used when release notes body is too long
ellipsis = "..."
)
// ErrNotImplemented is returned when a client does not implement certain feature.
var ErrNotImplemented = fmt.Errorf("not implemented")
// ErrReleaseDisabled happens when a configuration tries to use the default
// url_template even though the release is disabled.
var ErrReleaseDisabled = fmt.Errorf("release is disabled, cannot use default url_template")
// Info of the repository.
type Info struct {
Description string
Homepage string
URL string
}
type Repo struct {
Owner string
Name string
Branch string
GitURL string
GitSSHCommand string
PrivateKey string
}
func (r Repo) String() string {
if r.Owner == "" && r.Name == "" {
return ""
}
return r.Owner + "/" + r.Name
}
// Client interface.
type Client interface {
CloseMilestone(ctx *context.Context, repo Repo, title string) (err error)
CreateRelease(ctx *context.Context, body string) (releaseID string, err error)
Upload(ctx *context.Context, releaseID string, artifact *artifact.Artifact, file *os.File) (err error)
Changelog(ctx *context.Context, repo Repo, prev, current string) (string, error)
ReleaseURLTemplater
FileCreator
}
// ReleaseURLTemplater provides the release URL as a template, containing the
// artifact name as well.
type ReleaseURLTemplater interface {
ReleaseURLTemplate(ctx *context.Context) (string, error)
}
// RepoFile is a file to be created.
type RepoFile struct {
Content []byte
Path string
Identifier string // for the use of the caller.
}
// FileCreator can create the given file to some code repository.
type FileCreator interface {
CreateFile(ctx *context.Context, commitAuthor config.CommitAuthor, repo Repo, content []byte, path, message string) (err error)
}
// FilesCreator can create the multiple files in some repository and in a single commit.
type FilesCreator interface {
FileCreator
CreateFiles(ctx *context.Context, commitAuthor config.CommitAuthor, repo Repo, message string, files []RepoFile) (err error)
}
// ReleaseNotesGenerator can generate release notes.
type ReleaseNotesGenerator interface {
GenerateReleaseNotes(ctx *context.Context, repo Repo, prev, current string) (string, error)
}
// PullRequestOpener can open pull requests.
type PullRequestOpener interface {
OpenPullRequest(ctx *context.Context, base, head Repo, title string, draft bool) error
}
// New creates a new client depending on the token type.
func New(ctx *context.Context) (Client, error) {
return newWithToken(ctx, ctx.Token)
}
// NewReleaseClient returns a ReleaserURLTemplater, handling the possibility of
// the release being disabled.
func NewReleaseClient(ctx *context.Context) (ReleaseURLTemplater, error) {
disable, err := tmpl.New(ctx).Bool(ctx.Config.Release.Disable)
if err != nil {
return nil, err
}
if disable {
return errURLTemplater{}, nil
}
return New(ctx)
}
var _ ReleaseURLTemplater = errURLTemplater{}
type errURLTemplater struct{}
func (errURLTemplater) ReleaseURLTemplate(_ *context.Context) (string, error) {
return "", ErrReleaseDisabled
}
func newWithToken(ctx *context.Context, token string) (Client, error) {
log.WithField("type", ctx.TokenType).Debug("token type")
switch ctx.TokenType {
case context.TokenTypeGitHub:
return newGitHub(ctx, token)
case context.TokenTypeGitLab:
return newGitLab(ctx, token)
case context.TokenTypeGitea:
return newGitea(ctx, token)
default:
return nil, fmt.Errorf("invalid client token type: %q", ctx.TokenType)
}
}
func NewIfToken(ctx *context.Context, cli Client, token string) (Client, error) {
if token == "" {
return cli, nil
}
token, err := tmpl.New(ctx).ApplySingleEnvOnly(token)
if err != nil {
return nil, err
}
log.Debug("using custom token")
return newWithToken(ctx, token)
}
func truncateReleaseBody(body string) string {
if len(body) > maxReleaseBodyLength {
body = body[1:(maxReleaseBodyLength-len(ellipsis))] + ellipsis
}
return body
}
// ErrNoMilestoneFound is an error when no milestone is found.
type ErrNoMilestoneFound struct {
Title string
}
func (e ErrNoMilestoneFound) Error() string {
return fmt.Sprintf("no milestone found: %s", e.Title)
}
// RetriableError is an error that will cause the action to be retried.
type RetriableError struct {
Err error
}
func (e RetriableError) Error() string {
return e.Err.Error()
}