Skip to content

Commit

Permalink
refactoring: align Homebrew repo handling with Scoop
Browse files Browse the repository at this point in the history
  • Loading branch information
radeksimko committed Jul 6, 2020
1 parent 345b917 commit 93f0b65
Show file tree
Hide file tree
Showing 26 changed files with 309 additions and 262 deletions.
15 changes: 15 additions & 0 deletions internal/client/client.go
Expand Up @@ -2,6 +2,7 @@
package client

import (
"fmt"
"os"

"github.com/apex/log"
Expand All @@ -20,6 +21,7 @@ type Info struct {
// Client interface.
type Client interface {
CreateRelease(ctx *context.Context, body string) (releaseID string, err error)
ReleaseURLTemplate(ctx *context.Context) (string, error)
CreateFile(ctx *context.Context, commitAuthor config.CommitAuthor, repo config.Repo, content []byte, path, message string) (err error)
Upload(ctx *context.Context, releaseID string, artifact *artifact.Artifact, file *os.File) (err error)
}
Expand Down Expand Up @@ -47,3 +49,16 @@ type RetriableError struct {
func (e RetriableError) Error() string {
return e.Err.Error()
}

type NotImplementedError struct {
TokenType context.TokenType
}

func (e NotImplementedError) Error() string {
return fmt.Sprintf("not implemented for %s", e.TokenType)
}

func IsNotImplementedErr(err error) bool {
_, ok := err.(NotImplementedError)
return ok
}
4 changes: 4 additions & 0 deletions internal/client/gitea.go
Expand Up @@ -168,6 +168,10 @@ func (c *giteaClient) CreateRelease(ctx *context.Context, body string) (string,
return strconv.FormatInt(release.ID, 10), nil
}

func (c *giteaClient) ReleaseURLTemplate(ctx *context.Context) (string, error) {
return "", NotImplementedError{TokenType: context.TokenTypeGitea}
}

// Upload uploads a file into a release repository.
func (c *giteaClient) Upload(
ctx *context.Context,
Expand Down
12 changes: 12 additions & 0 deletions internal/client/github.go
Expand Up @@ -2,6 +2,7 @@ package client

import (
"crypto/tls"
"fmt"
"net/http"
"net/url"
"os"
Expand All @@ -17,6 +18,8 @@ import (
"golang.org/x/oauth2"
)

const DefaultGitHubDownloadURL = "https://github.com"

type githubClient struct {
client *github.Client
}
Expand Down Expand Up @@ -147,6 +150,15 @@ func (c *githubClient) CreateRelease(ctx *context.Context, body string) (string,
return githubReleaseID, err
}

func (c *githubClient) ReleaseURLTemplate(ctx *context.Context) (string, error) {
return fmt.Sprintf(
"%s/%s/%s/releases/download/{{ .Tag }}/{{ .ArtifactName }}",
ctx.Config.GitHubURLs.Download,
ctx.Config.Release.GitHub.Owner,
ctx.Config.Release.GitHub.Name,
), nil
}

func (c *githubClient) Upload(
ctx *context.Context,
releaseID string,
Expand Down
23 changes: 23 additions & 0 deletions internal/client/github_test.go
Expand Up @@ -56,6 +56,29 @@ func TestGitHubUploadReleaseIDNotInt(t *testing.T) {
)
}

func TestGitHubReleaseURLTemplate(t *testing.T) {
var ctx = context.New(config.Project{
GitHubURLs: config.GitHubURLs{
// default URL would otherwise be set via pipe/defaults
Download: DefaultGitHubDownloadURL,
},
Release: config.Release{
GitHub: config.Repo{
Owner: "owner",
Name: "name",
},
},
})
client, err := NewGitHub(ctx)
require.NoError(t, err)

urlTpl, err := client.ReleaseURLTemplate(ctx)
require.NoError(t, err)

expectedUrl := "https://github.com/owner/name/releases/download/{{ .Tag }}/{{ .ArtifactName }}"
require.Equal(t, expectedUrl, urlTpl)
}

func TestGitHubCreateReleaseWrongNameTemplate(t *testing.T) {
var ctx = context.New(config.Project{
Release: config.Release{
Expand Down
12 changes: 12 additions & 0 deletions internal/client/gitlab.go
Expand Up @@ -3,6 +3,7 @@ package client
import (
"crypto/tls"
"errors"
"fmt"
"net/http"
"os"
"strings"
Expand All @@ -15,6 +16,8 @@ import (
"github.com/xanzy/go-gitlab"
)

const DefaultGitLabDownloadURL = "https://gitlab.com"

// ErrExtractHashFromFileUploadURL indicates the file upload hash could not ne extracted from the url.
var ErrExtractHashFromFileUploadURL = errors.New("could not extract hash from gitlab file upload url")

Expand Down Expand Up @@ -229,6 +232,15 @@ func (c *gitlabClient) CreateRelease(ctx *context.Context, body string) (release
return tagName, err // gitlab references a tag in a repo by its name
}

func (c *gitlabClient) ReleaseURLTemplate(ctx *context.Context) (string, error) {
return fmt.Sprintf(
"%s/%s/%s/uploads/{{ .ArtifactUploadHash }}/{{ .ArtifactName }}",
ctx.Config.GitLabURLs.Download,
ctx.Config.Release.GitLab.Owner,
ctx.Config.Release.GitLab.Name,
), nil
}

// Upload uploads a file into a release repository.
func (c *gitlabClient) Upload(
ctx *context.Context,
Expand Down
25 changes: 25 additions & 0 deletions internal/client/gitlab_test.go
Expand Up @@ -4,6 +4,8 @@ import (
"fmt"
"testing"

"github.com/goreleaser/goreleaser/pkg/config"
"github.com/goreleaser/goreleaser/pkg/context"
"github.com/stretchr/testify/assert"
)

Expand Down Expand Up @@ -31,3 +33,26 @@ func TestFailToExtractHashFromProjectFileURL(t *testing.T) {
t.Errorf("expected an error but got none for path-too-small in url")
}
}

func TestGitLabReleaseURLTemplate(t *testing.T) {
var ctx = context.New(config.Project{
GitLabURLs: config.GitLabURLs{
// default URL would otherwise be set via pipe/defaults
Download: DefaultGitLabDownloadURL,
},
Release: config.Release{
GitLab: config.Repo{
Owner: "owner",
Name: "name",
},
},
})
client, err := NewGitLab(ctx)
assert.NoError(t, err)

urlTpl, err := client.ReleaseURLTemplate(ctx)
assert.NoError(t, err)

expectedUrl := "https://gitlab.com/owner/name/uploads/{{ .ArtifactUploadHash }}/{{ .ArtifactName }}"
assert.Equal(t, expectedUrl, urlTpl)
}
4 changes: 2 additions & 2 deletions internal/deprecate/deprecate.go
Expand Up @@ -22,8 +22,8 @@ func Notice(ctx *context.Context, property string) {
}()
// replaces . and _ with -
url := baseURL + strings.NewReplacer(
".", "-",
"_", "-",
".", "",
"_", "",
).Replace(property)
log.Warn(color.New(color.Bold, color.FgHiYellow).Sprintf(
"DEPRECATED: `%s` should not be used anymore, check %s for more info.",
Expand Down
66 changes: 28 additions & 38 deletions internal/pipe/brew/brew.go
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/apex/log"
"github.com/goreleaser/goreleaser/internal/artifact"
"github.com/goreleaser/goreleaser/internal/client"
"github.com/goreleaser/goreleaser/internal/deprecate"
"github.com/goreleaser/goreleaser/internal/pipe"
"github.com/goreleaser/goreleaser/internal/tmpl"
"github.com/goreleaser/goreleaser/pkg/config"
Expand All @@ -26,9 +27,6 @@ var ErrNoArchivesFound = errors.New("no linux/macos archives found")
// for linux or windows.
var ErrMultipleArchivesSameOS = errors.New("one tap can handle only archive of an OS/Arch combination. Consider using ids in the brew section")

// ErrEmptyTokenType indicates unknown token type.
var ErrEmptyTokenType = errors.New("no token type found")

// ErrTokenTypeNotImplementedForBrew indicates that a new token type was not implemented for this pipe.
type ErrTokenTypeNotImplementedForBrew struct {
TokenType context.TokenType
Expand All @@ -50,6 +48,11 @@ func (Pipe) String() string {

// Publish brew formula.
func (Pipe) Publish(ctx *context.Context) error {
// we keep GitHub as default for now, in line with releases
if string(ctx.TokenType) == "" {
ctx.TokenType = context.TokenTypeGitHub
}

client, err := client.New(ctx)
if err != nil {
return err
Expand All @@ -66,6 +69,7 @@ func (Pipe) Publish(ctx *context.Context) error {
func (Pipe) Default(ctx *context.Context) error {
for i := range ctx.Config.Brews {
var brew = &ctx.Config.Brews[i]

if brew.Install == "" {
// TODO: maybe replace this with a simplear also optimistic
// approach of just doing `bin.install "project_name"`?
Expand All @@ -82,6 +86,14 @@ func (Pipe) Default(ctx *context.Context) error {
brew.Install = strings.Join(installs, "\n")
log.Warnf("optimistically guessing `brew[%d].installs`, double check", i)
}
if brew.GitHub.String() != "" {
deprecate.Notice(ctx, "brews.github")
brew.Tap = brew.GitHub
}
if brew.GitLab.String() != "" {
deprecate.Notice(ctx, "brews.gitlab")
brew.Tap = brew.GitLab
}
if brew.CommitAuthor.Name == "" {
brew.CommitAuthor.Name = "goreleaserbot"
}
Expand Down Expand Up @@ -118,7 +130,7 @@ func contains(ss []string, s string) bool {
}

func doRun(ctx *context.Context, brew config.Homebrew, client client.Client) error {
if brew.GitHub.Name == "" && brew.GitLab.Name == "" {
if brew.Tap.Name == "" {
return pipe.Skip("brew section is not configured")
}

Expand Down Expand Up @@ -148,7 +160,7 @@ func doRun(ctx *context.Context, brew config.Homebrew, client client.Client) err
return ErrNoArchivesFound
}

content, err := buildFormula(ctx, brew, ctx.TokenType, archives)
content, err := buildFormula(ctx, brew, client, archives)
if err != nil {
return err
}
Expand All @@ -170,18 +182,7 @@ func doRun(ctx *context.Context, brew config.Homebrew, client client.Client) err
return pipe.Skip("prerelease detected with 'auto' upload, skipping homebrew publish")
}

var repo config.Repo
switch ctx.TokenType {
case context.TokenTypeGitHub:
repo = brew.GitHub
case context.TokenTypeGitLab:
repo = brew.GitLab
default:
if string(ctx.TokenType) == "" {
return ErrEmptyTokenType
}
return ErrTokenTypeNotImplementedForBrew{ctx.TokenType}
}
repo := brew.Tap

var gpath = buildFormulaPath(brew.Folder, filename)
log.WithField("formula", gpath).
Expand All @@ -196,8 +197,8 @@ func buildFormulaPath(folder, filename string) string {
return path.Join(folder, filename)
}

func buildFormula(ctx *context.Context, brew config.Homebrew, tokenType context.TokenType, artifacts []*artifact.Artifact) (string, error) {
data, err := dataFor(ctx, brew, tokenType, artifacts)
func buildFormula(ctx *context.Context, brew config.Homebrew, client client.Client, artifacts []*artifact.Artifact) (string, error) {
data, err := dataFor(ctx, brew, client, artifacts)
if err != nil {
return "", err
}
Expand All @@ -216,7 +217,7 @@ func doBuildFormula(ctx *context.Context, data templateData) (string, error) {
return tmpl.New(ctx).Apply(out.String())
}

func dataFor(ctx *context.Context, cfg config.Homebrew, tokenType context.TokenType, artifacts []*artifact.Artifact) (templateData, error) {
func dataFor(ctx *context.Context, cfg config.Homebrew, cl client.Client, artifacts []*artifact.Artifact) (templateData, error) {
var result = templateData{
Name: formulaNameFor(cfg.Name),
Desc: cfg.Description,
Expand All @@ -240,25 +241,14 @@ func dataFor(ctx *context.Context, cfg config.Homebrew, tokenType context.TokenT
}

if cfg.URLTemplate == "" {
switch tokenType {
// we keep GitHub as default for now, in line with releases
case context.TokenTypeGitHub, "":
cfg.URLTemplate = fmt.Sprintf(
"%s/%s/%s/releases/download/{{ .Tag }}/{{ .ArtifactName }}",
ctx.Config.GitHubURLs.Download,
ctx.Config.Release.GitHub.Owner,
ctx.Config.Release.GitHub.Name,
)
case context.TokenTypeGitLab:
cfg.URLTemplate = fmt.Sprintf(
"%s/%s/%s/uploads/{{ .ArtifactUploadHash }}/{{ .ArtifactName }}",
ctx.Config.GitLabURLs.Download,
ctx.Config.Release.GitLab.Owner,
ctx.Config.Release.GitLab.Name,
)
default:
return result, ErrTokenTypeNotImplementedForBrew{tokenType}
url, err := cl.ReleaseURLTemplate(ctx)
if err != nil {
if client.IsNotImplementedErr(err) {
return result, ErrTokenTypeNotImplementedForBrew{ctx.TokenType}
}
return result, err
}
cfg.URLTemplate = url
}
url, err := tmpl.New(ctx).WithArtifact(artifact, map[string]string{}).Apply(cfg.URLTemplate)
if err != nil {
Expand Down

0 comments on commit 93f0b65

Please sign in to comment.