1
0
mirror of https://github.com/goreleaser/goreleaser.git synced 2025-10-30 23:58:09 +02:00

feat: full gitlab support for brew and scoop (#1084)

* makes context tokentype a public var

* passes artifacts object into client upload function. extracts gitlab upload hash from url

* adds gitlab url to brew config

* build brew formula depending on token type

* fixes client for release tests

* fixes exiting brew tests

* fixes scoop test with dummy client adaption

* uses new artifact upload hash

* fixes brew usage

* updates gitlab createFile for brew

* fixes logging for non-existing file in gitlab logging

* fix: gitlab createFile

* fix: removes encoding from gitlab create and update file opts

* fix: gitlab upload and artifact set upload hash

* fix: linter

* changed artifact item to a pointer in ctx

* docs: updates homebrew

* feat: enables scoop for gitlab release

* fix: scoop panic for pointer access

* chore: rename formula build func for brew

* chore: brew removes comments

* fix: brew tests

* test: updates brew tests

* docs: updates homebrew

* test: for token type not implemented for brew

* tests: for multiple linux builds

* fix: build artifacts are pointer in scoop

* test: for scoop and gitlab

* test: for artifacts set upload hash

* adds missing files after adaption

* chore: removes and clarifies comments

* fix: moves artifact upload hash to extra map

* adds comment why we initialize the extra map
This commit is contained in:
Manuel Vogel
2019-08-13 20:28:03 +02:00
committed by Carlos Alexandro Becker
parent 23e275e946
commit e92bbe32ce
20 changed files with 787 additions and 168 deletions

View File

@@ -4,6 +4,7 @@ package client
import ( import (
"os" "os"
"github.com/goreleaser/goreleaser/internal/artifact"
"github.com/goreleaser/goreleaser/pkg/config" "github.com/goreleaser/goreleaser/pkg/config"
"github.com/goreleaser/goreleaser/pkg/context" "github.com/goreleaser/goreleaser/pkg/context"
) )
@@ -19,7 +20,7 @@ type Info struct {
type Client interface { type Client interface {
CreateRelease(ctx *context.Context, body string) (releaseID string, err error) CreateRelease(ctx *context.Context, body string) (releaseID string, err error)
CreateFile(ctx *context.Context, commitAuthor config.CommitAuthor, repo config.Repo, content []byte, path, message string) (err error) CreateFile(ctx *context.Context, commitAuthor config.CommitAuthor, repo config.Repo, content []byte, path, message string) (err error)
Upload(ctx *context.Context, releaseID string, name string, file *os.File) (err error) Upload(ctx *context.Context, releaseID string, artifact *artifact.Artifact, file *os.File) (err error)
} }
// New creates a new client depending on the token type // New creates a new client depending on the token type

View File

@@ -10,6 +10,7 @@ import (
"github.com/apex/log" "github.com/apex/log"
"github.com/google/go-github/v25/github" "github.com/google/go-github/v25/github"
"github.com/goreleaser/goreleaser/internal/artifact"
"github.com/goreleaser/goreleaser/internal/tmpl" "github.com/goreleaser/goreleaser/internal/tmpl"
"github.com/goreleaser/goreleaser/pkg/config" "github.com/goreleaser/goreleaser/pkg/config"
"github.com/goreleaser/goreleaser/pkg/context" "github.com/goreleaser/goreleaser/pkg/context"
@@ -150,7 +151,7 @@ func (c *githubClient) CreateRelease(ctx *context.Context, body string) (string,
func (c *githubClient) Upload( func (c *githubClient) Upload(
ctx *context.Context, ctx *context.Context,
releaseID string, releaseID string,
name string, artifact *artifact.Artifact,
file *os.File, file *os.File,
) error { ) error {
githubReleaseID, err := strconv.ParseInt(releaseID, 10, 64) githubReleaseID, err := strconv.ParseInt(releaseID, 10, 64)
@@ -163,7 +164,7 @@ func (c *githubClient) Upload(
ctx.Config.Release.GitHub.Name, ctx.Config.Release.GitHub.Name,
githubReleaseID, githubReleaseID,
&github.UploadOptions{ &github.UploadOptions{
Name: name, Name: artifact.Name,
}, },
file, file,
) )

View File

@@ -2,16 +2,22 @@ package client
import ( import (
"crypto/tls" "crypto/tls"
"errors"
"net/http" "net/http"
"os" "os"
"strings"
"github.com/apex/log" "github.com/apex/log"
"github.com/goreleaser/goreleaser/internal/artifact"
"github.com/goreleaser/goreleaser/internal/tmpl" "github.com/goreleaser/goreleaser/internal/tmpl"
"github.com/goreleaser/goreleaser/pkg/config" "github.com/goreleaser/goreleaser/pkg/config"
"github.com/goreleaser/goreleaser/pkg/context" "github.com/goreleaser/goreleaser/pkg/context"
"github.com/xanzy/go-gitlab" "github.com/xanzy/go-gitlab"
) )
// 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")
type gitlabClient struct { type gitlabClient struct {
client *gitlab.Client client *gitlab.Client
} }
@@ -36,18 +42,113 @@ func NewGitLab(ctx *context.Context) (Client, error) {
return &gitlabClient{client: client}, nil return &gitlabClient{client: client}, nil
} }
// CreateFile creates a file in the repository at a given path // CreateFile gets a file in the repository at a given path
// or updates the file if it exists // and updates if it exists or creates it for later pipes in the pipeline
func (c *gitlabClient) CreateFile( func (c *gitlabClient) CreateFile(
ctx *context.Context, ctx *context.Context,
commitAuthor config.CommitAuthor, commitAuthor config.CommitAuthor,
repo config.Repo, repo config.Repo,
content []byte, content []byte, // the content of the formula.rb
path, path, // the path to the formula.rb
message string, message string, // the commit msg
) error { ) error {
// Used by brew and scoop, hence those two pipes are fileName := path
// only supported for github atm. So we disable it for now. // we assume having the formula in the master branch only
ref := "master"
branch := "master"
opts := &gitlab.GetFileOptions{Ref: &ref}
castedContent := string(content)
projectID := repo.Owner + "/" + repo.Name
log.WithFields(log.Fields{
"owner": repo.Owner,
"name": repo.Name,
}).Debug("projectID at brew")
_, res, err := c.client.RepositoryFiles.GetFile(projectID, fileName, opts)
if err != nil && (res == nil || res.StatusCode != 404) {
log.WithFields(log.Fields{
"fileName": fileName,
"ref": ref,
"projectID": projectID,
"statusCode": res.StatusCode,
"err": err.Error(),
}).Error("error getting file for brew formula")
return err
}
log.WithFields(log.Fields{
"fileName": fileName,
"branch": branch,
"projectID": projectID,
}).Debug("found already existing brew formula file")
if res.StatusCode == 404 {
log.WithFields(log.Fields{
"fileName": fileName,
"ref": ref,
"projectID": projectID,
}).Debug("creating brew formula")
createOpts := &gitlab.CreateFileOptions{
AuthorName: &commitAuthor.Name,
AuthorEmail: &commitAuthor.Email,
Content: &castedContent,
Branch: &branch,
CommitMessage: &message,
}
fileInfo, res, err := c.client.RepositoryFiles.CreateFile(projectID, fileName, createOpts)
if err != nil {
log.WithFields(log.Fields{
"fileName": fileName,
"branch": branch,
"projectID": projectID,
"statusCode": res.StatusCode,
"err": err.Error(),
}).Error("error creating brew formula file")
return err
}
log.WithFields(log.Fields{
"fileName": fileName,
"branch": branch,
"projectID": projectID,
"filePath": fileInfo.FilePath,
}).Debug("created brew formula file")
return nil
}
log.WithFields(log.Fields{
"fileName": fileName,
"ref": ref,
"projectID": projectID,
}).Debug("updating brew formula")
updateOpts := &gitlab.UpdateFileOptions{
AuthorName: &commitAuthor.Name,
AuthorEmail: &commitAuthor.Email,
Content: &castedContent,
Branch: &branch,
CommitMessage: &message,
}
updateFileInfo, res, err := c.client.RepositoryFiles.UpdateFile(projectID, fileName, updateOpts)
if err != nil {
log.WithFields(log.Fields{
"fileName": fileName,
"branch": branch,
"projectID": projectID,
"statusCode": res.StatusCode,
"err": err.Error(),
}).Error("error updating brew formula file")
return err
}
log.WithFields(log.Fields{
"fileName": fileName,
"branch": branch,
"projectID": projectID,
"filePath": updateFileInfo.FilePath,
"statusCode": res.StatusCode,
}).Debug("updated brew formula file")
return nil return nil
} }
@@ -128,7 +229,7 @@ func (c *gitlabClient) CreateRelease(ctx *context.Context, body string) (release
func (c *gitlabClient) Upload( func (c *gitlabClient) Upload(
ctx *context.Context, ctx *context.Context,
releaseID string, releaseID string,
name string, artifact *artifact.Artifact,
file *os.File, file *os.File,
) error { ) error {
projectID := ctx.Config.Release.GitLab.Owner + "/" + ctx.Config.Release.GitLab.Name projectID := ctx.Config.Release.GitLab.Owner + "/" + ctx.Config.Release.GitLab.Name
@@ -150,9 +251,9 @@ func (c *gitlabClient) Upload(
}).Debug("uploaded file") }).Debug("uploaded file")
gitlabBaseURL := ctx.Config.GitLabURLs.Download gitlabBaseURL := ctx.Config.GitLabURLs.Download
// projectFile from upload: /uploads/<sha>/filename.txt // projectFile.URL from upload: /uploads/<hash>/filename.txt
relativeUploadURL := projectFile.URL linkURL := gitlabBaseURL + "/" + projectID + projectFile.URL
linkURL := gitlabBaseURL + "/" + projectID + relativeUploadURL name := artifact.Name
releaseLink, _, err := c.client.ReleaseLinks.CreateReleaseLink( releaseLink, _, err := c.client.ReleaseLinks.CreateReleaseLink(
projectID, projectID,
releaseID, releaseID,
@@ -170,5 +271,36 @@ func (c *gitlabClient) Upload(
"url": releaseLink.URL, "url": releaseLink.URL,
}).Debug("created release link") }).Debug("created release link")
fileUploadHash, err := extractProjectFileHashFrom(projectFile.URL)
if err != nil {
return err
}
// for checksums.txt the field is nil, so we initialize it
if artifact.Extra == nil {
artifact.Extra = make(map[string]interface{})
}
// we set this hash to be able to download the file
// in following publish pipes like brew, scoop
artifact.Extra["ArtifactUploadHash"] = fileUploadHash
return err return err
} }
// extractProjectFileHashFrom extracts the hash from the
// relative project file url of the format '/uploads/<hash>/filename.ext'
func extractProjectFileHashFrom(projectFileURL string) (string, error) {
log.WithField("projectFileURL", projectFileURL).Debug("extract file hash from")
splittedProjectFileURL := strings.Split(projectFileURL, "/")
if len(splittedProjectFileURL) != 4 {
log.WithField("projectFileURL", projectFileURL).Debug("could not extract file hash")
return "", ErrExtractHashFromFileUploadURL
}
fileHash := splittedProjectFileURL[2]
log.WithFields(log.Fields{
"projectFileURL": projectFileURL,
"fileHash": fileHash,
}).Debug("extracted file hash")
return fileHash, nil
}

View File

@@ -0,0 +1,33 @@
package client
import (
"fmt"
"testing"
"github.com/stretchr/testify/assert"
)
func TestExtractHashFromProjectFileURL(t *testing.T) {
givenHash := "22e8b1508b0f28433b94754a5ea2f4aa"
projectFileURL := fmt.Sprintf("/uploads/%s/release-testing_0.3.7_Darwin_x86_64.tar.gz", givenHash)
extractedHash, err := extractProjectFileHashFrom(projectFileURL)
if err != nil {
t.Errorf("expexted no error but got: %v", err)
}
assert.Equal(t, givenHash, extractedHash)
}
func TestFailToExtractHashFromProjectFileURL(t *testing.T) {
givenHash := "22e8b1508b0f28433b94754a5ea2f4aa"
projectFileURL := fmt.Sprintf("/uploads/%s/new-path/file.ext", givenHash)
_, err := extractProjectFileHashFrom(projectFileURL)
if err == nil {
t.Errorf("expected an error but got none for new-path in url")
}
projectFileURL = fmt.Sprintf("/%s/file.ext", givenHash)
_, err = extractProjectFileHashFrom(projectFileURL)
if err == nil {
t.Errorf("expected an error but got none for path-too-small in url")
}
}

View File

@@ -30,6 +30,9 @@ var ErrNoArchivesFound = errors.New("brew tap: no archives found matching criter
// TODO: improve this confusing error message // TODO: improve this confusing error message
var ErrMultipleArchivesSameOS = errors.New("brew tap: one tap can handle only 1 linux and 1 macos archive") var ErrMultipleArchivesSameOS = errors.New("brew tap: one tap can handle only 1 linux and 1 macos archive")
// ErrTokenTypeNotImplementedForBrew indicates that a new token type was not implemented for this pipe
var ErrTokenTypeNotImplementedForBrew = errors.New("token type not implemented for brew pipe")
// Pipe for brew deployment // Pipe for brew deployment
type Pipe struct{} type Pipe struct{}
@@ -39,7 +42,7 @@ func (Pipe) String() string {
// Publish brew formula // Publish brew formula
func (Pipe) Publish(ctx *context.Context) error { func (Pipe) Publish(ctx *context.Context) error {
client, err := client.NewGitHub(ctx) client, err := client.New(ctx)
if err != nil { if err != nil {
return err return err
} }
@@ -112,15 +115,14 @@ func contains(ss []string, s string) bool {
} }
func doRun(ctx *context.Context, brew config.Homebrew, client client.Client) error { func doRun(ctx *context.Context, brew config.Homebrew, client client.Client) error {
if brew.GitHub.Name == "" { if brew.GitHub.Name == "" && brew.GitLab.Name == "" {
return pipe.Skip("brew section is not configured") return pipe.Skip("brew section is not configured")
} }
// If we'd use 'ctx.TokenType != context.TokenTypeGitHub' we'd have to adapt all the tests
// For simplicity we use this check because the functionality will be implemented later for // TODO mavogel: in another PR
// all types of releases. See https://github.com/goreleaser/goreleaser/pull/1038#issuecomment-498891464 // check if release pipe is not configured!
if ctx.TokenType == context.TokenTypeGitLab { // if ctx.Config.Release.Disable {
return pipe.Skip("brew pipe is only configured for github releases") // }
}
var filters = []artifact.Filter{ var filters = []artifact.Filter{
artifact.Or( artifact.Or(
@@ -140,7 +142,7 @@ func doRun(ctx *context.Context, brew config.Homebrew, client client.Client) err
return ErrNoArchivesFound return ErrNoArchivesFound
} }
content, err := buildFormula(ctx, brew, archives) content, err := buildFormula(ctx, brew, ctx.TokenType, archives)
if err != nil { if err != nil {
return err return err
} }
@@ -165,21 +167,31 @@ func doRun(ctx *context.Context, brew config.Homebrew, client client.Client) err
return pipe.Skip("prerelease detected with 'auto' upload, skipping homebrew publish") return pipe.Skip("prerelease detected with 'auto' upload, skipping homebrew publish")
} }
var gpath = ghFormulaPath(brew.Folder, filename) var repo config.Repo
switch ctx.TokenType {
case context.TokenTypeGitHub:
repo = brew.GitHub
case context.TokenTypeGitLab:
repo = brew.GitLab
default:
return ErrTokenTypeNotImplementedForBrew
}
var gpath = buildFormulaPath(brew.Folder, filename)
log.WithField("formula", gpath). log.WithField("formula", gpath).
WithField("repo", brew.GitHub.String()). WithField("repo", repo.String()).
Info("pushing") Info("pushing")
var msg = fmt.Sprintf("Brew formula update for %s version %s", ctx.Config.ProjectName, ctx.Git.CurrentTag) var msg = fmt.Sprintf("Brew formula update for %s version %s", ctx.Config.ProjectName, ctx.Git.CurrentTag)
return client.CreateFile(ctx, brew.CommitAuthor, brew.GitHub, []byte(content), gpath, msg) return client.CreateFile(ctx, brew.CommitAuthor, repo, []byte(content), gpath, msg)
} }
func ghFormulaPath(folder, filename string) string { func buildFormulaPath(folder, filename string) string {
return path.Join(folder, filename) return path.Join(folder, filename)
} }
func buildFormula(ctx *context.Context, brew config.Homebrew, artifacts []*artifact.Artifact) (string, error) { func buildFormula(ctx *context.Context, brew config.Homebrew, tokenType context.TokenType, artifacts []*artifact.Artifact) (string, error) {
data, err := dataFor(ctx, brew, artifacts) data, err := dataFor(ctx, brew, tokenType, artifacts)
if err != nil { if err != nil {
return "", err return "", err
} }
@@ -198,7 +210,7 @@ func doBuildFormula(ctx *context.Context, data templateData) (string, error) {
return tmpl.New(ctx).Apply(out.String()) return tmpl.New(ctx).Apply(out.String())
} }
func dataFor(ctx *context.Context, cfg config.Homebrew, artifacts []*artifact.Artifact) (templateData, error) { func dataFor(ctx *context.Context, cfg config.Homebrew, tokenType context.TokenType, artifacts []*artifact.Artifact) (templateData, error) {
var result = templateData{ var result = templateData{
Name: formulaNameFor(cfg.Name), Name: formulaNameFor(cfg.Name),
Desc: cfg.Description, Desc: cfg.Description,
@@ -222,12 +234,24 @@ func dataFor(ctx *context.Context, cfg config.Homebrew, artifacts []*artifact.Ar
} }
if cfg.URLTemplate == "" { if cfg.URLTemplate == "" {
cfg.URLTemplate = fmt.Sprintf( switch tokenType {
"%s/%s/%s/releases/download/{{ .Tag }}/{{ .ArtifactName }}", case context.TokenTypeGitHub:
ctx.Config.GitHubURLs.Download, cfg.URLTemplate = fmt.Sprintf(
ctx.Config.Release.GitHub.Owner, "%s/%s/%s/releases/download/{{ .Tag }}/{{ .ArtifactName }}",
ctx.Config.Release.GitHub.Name, 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
}
} }
url, err := tmpl.New(ctx).WithArtifact(artifact, map[string]string{}).Apply(cfg.URLTemplate) url, err := tmpl.New(ctx).WithArtifact(artifact, map[string]string{}).Apply(cfg.URLTemplate)
if err != nil { if err != nil {

View File

@@ -109,20 +109,80 @@ func TestSplit(t *testing.T) {
func TestRunPipe(t *testing.T) { func TestRunPipe(t *testing.T) {
for name, fn := range map[string]func(ctx *context.Context){ for name, fn := range map[string]func(ctx *context.Context){
"default": func(ctx *context.Context) {}, "default": func(ctx *context.Context) {
ctx.TokenType = context.TokenTypeGitHub
ctx.Config.GitHubURLs.Download = "https://github.com"
ctx.Config.Release.GitHub.Owner = "test"
ctx.Config.Release.GitHub.Name = "test"
ctx.Config.Brews[0].GitHub.Owner = "test"
ctx.Config.Brews[0].GitHub.Name = "test"
ctx.Config.Brews[0].Homepage = "https://github.com/goreleaser"
},
"github_enterprise_url": func(ctx *context.Context) { "github_enterprise_url": func(ctx *context.Context) {
ctx.TokenType = context.TokenTypeGitHub
ctx.Config.GitHubURLs.Download = "https://github.com"
ctx.Config.Release.GitHub.Owner = "test"
ctx.Config.Release.GitHub.Name = "test"
ctx.Config.Brews[0].GitHub.Owner = "test"
ctx.Config.Brews[0].GitHub.Name = "test"
ctx.Config.Brews[0].Homepage = "https://github.com/goreleaser"
ctx.Config.GitHubURLs.Download = "http://github.example.org" ctx.Config.GitHubURLs.Download = "http://github.example.org"
}, },
"custom_download_strategy": func(ctx *context.Context) { "custom_download_strategy": func(ctx *context.Context) {
ctx.TokenType = context.TokenTypeGitHub
ctx.Config.GitHubURLs.Download = "https://github.com"
ctx.Config.Release.GitHub.Owner = "test"
ctx.Config.Release.GitHub.Name = "test"
ctx.Config.Brews[0].GitHub.Owner = "test"
ctx.Config.Brews[0].GitHub.Name = "test"
ctx.Config.Brews[0].Homepage = "https://github.com/goreleaser"
ctx.Config.Brews[0].DownloadStrategy = "GitHubPrivateRepositoryReleaseDownloadStrategy" ctx.Config.Brews[0].DownloadStrategy = "GitHubPrivateRepositoryReleaseDownloadStrategy"
}, },
"custom_require": func(ctx *context.Context) { "custom_require": func(ctx *context.Context) {
ctx.TokenType = context.TokenTypeGitHub
ctx.Config.GitHubURLs.Download = "https://github.com"
ctx.Config.Release.GitHub.Owner = "test"
ctx.Config.Release.GitHub.Name = "test"
ctx.Config.Brews[0].GitHub.Owner = "test"
ctx.Config.Brews[0].GitHub.Name = "test"
ctx.Config.Brews[0].Homepage = "https://github.com/goreleaser"
ctx.Config.Brews[0].DownloadStrategy = "CustomDownloadStrategy" ctx.Config.Brews[0].DownloadStrategy = "CustomDownloadStrategy"
ctx.Config.Brews[0].CustomRequire = "custom_download_strategy" ctx.Config.Brews[0].CustomRequire = "custom_download_strategy"
}, },
"custom_block": func(ctx *context.Context) { "custom_block": func(ctx *context.Context) {
ctx.TokenType = context.TokenTypeGitHub
ctx.Config.GitHubURLs.Download = "https://github.com"
ctx.Config.Release.GitHub.Owner = "test"
ctx.Config.Release.GitHub.Name = "test"
ctx.Config.Brews[0].GitHub.Owner = "test"
ctx.Config.Brews[0].GitHub.Name = "test"
ctx.Config.Brews[0].Homepage = "https://github.com/goreleaser"
ctx.Config.Brews[0].CustomBlock = `head "https://github.com/caarlos0/test.git"` ctx.Config.Brews[0].CustomBlock = `head "https://github.com/caarlos0/test.git"`
}, },
"default_gitlab": func(ctx *context.Context) {
ctx.TokenType = context.TokenTypeGitLab
ctx.Config.GitLabURLs.Download = "https://gitlab.com"
ctx.Config.Release.GitLab.Owner = "test"
ctx.Config.Release.GitLab.Name = "test"
ctx.Config.Brews[0].GitLab.Owner = "test"
ctx.Config.Brews[0].GitLab.Name = "test"
ctx.Config.Brews[0].Homepage = "https://gitlab.com/goreleaser"
},
"gitlab_enterprise_url": func(ctx *context.Context) {
ctx.TokenType = context.TokenTypeGitLab
ctx.Config.GitLabURLs.Download = "https://gitlab.com"
ctx.Config.Release.GitLab.Owner = "test"
ctx.Config.Release.GitLab.Name = "test"
ctx.Config.Brews[0].GitLab.Owner = "test"
ctx.Config.Brews[0].GitLab.Name = "test"
ctx.Config.Brews[0].Homepage = "https://gitlab.com/goreleaser"
ctx.Config.GitLabURLs.Download = "https://gitlab.my-company.org"
},
} { } {
t.Run(name, func(t *testing.T) { t.Run(name, func(t *testing.T) {
folder, err := ioutil.TempDir("", "goreleasertest") folder, err := ioutil.TempDir("", "goreleasertest")
@@ -139,27 +199,13 @@ func TestRunPipe(t *testing.T) {
Config: config.Project{ Config: config.Project{
Dist: folder, Dist: folder,
ProjectName: name, ProjectName: name,
GitHubURLs: config.GitHubURLs{
Download: "https://github.com",
},
Release: config.Release{
GitHub: config.Repo{
Owner: "test",
Name: "test",
},
},
Brews: []config.Homebrew{ Brews: []config.Homebrew{
{ {
Name: name, Name: name,
GitHub: config.Repo{
Owner: "test",
Name: "test",
},
IDs: []string{ IDs: []string{
"foo", "foo",
}, },
Description: "A run pipe test formula and FOO={{ .Env.FOO }}", Description: "A run pipe test formula and FOO={{ .Env.FOO }}",
Homepage: "https://github.com/goreleaser",
Caveats: "don't do this {{ .ProjectName }}", Caveats: "don't do this {{ .ProjectName }}",
Test: "system \"true\"\nsystem \"#{bin}/foo -h\"", Test: "system \"true\"\nsystem \"#{bin}/foo -h\"",
Plist: `<xml>whatever</xml>`, Plist: `<xml>whatever</xml>`,
@@ -178,8 +224,9 @@ func TestRunPipe(t *testing.T) {
Goarch: "amd64", Goarch: "amd64",
Type: artifact.UploadableArchive, Type: artifact.UploadableArchive,
Extra: map[string]interface{}{ Extra: map[string]interface{}{
"ID": "bar", "ID": "bar",
"Format": "tar.gz", "Format": "tar.gz",
"ArtifactUploadHash": "820ead5d9d2266c728dce6d4d55b6460",
}, },
}) })
var path = filepath.Join(folder, "bin.tar.gz") var path = filepath.Join(folder, "bin.tar.gz")
@@ -190,8 +237,9 @@ func TestRunPipe(t *testing.T) {
Goarch: "amd64", Goarch: "amd64",
Type: artifact.UploadableArchive, Type: artifact.UploadableArchive,
Extra: map[string]interface{}{ Extra: map[string]interface{}{
"ID": "foo", "ID": "foo",
"Format": "tar.gz", "Format": "tar.gz",
"ArtifactUploadHash": "820ead5d9d2266c728dce6d4d55b6460",
}, },
}) })
@@ -219,6 +267,7 @@ func TestRunPipe(t *testing.T) {
func TestRunPipeNoDarwin64Build(t *testing.T) { func TestRunPipeNoDarwin64Build(t *testing.T) {
var ctx = &context.Context{ var ctx = &context.Context{
TokenType: context.TokenTypeGitHub,
Config: config.Project{ Config: config.Project{
Brews: []config.Homebrew{ Brews: []config.Homebrew{
{ {
@@ -235,7 +284,7 @@ func TestRunPipeNoDarwin64Build(t *testing.T) {
assert.False(t, client.CreatedFile) assert.False(t, client.CreatedFile)
} }
func TestRunPipeMultipleDarwin64Build(t *testing.T) { func TestRunPipeMultipleArchivesSameOsBuild(t *testing.T) {
var ctx = context.New( var ctx = context.New(
config.Project{ config.Project{
Brews: []config.Homebrew{ Brews: []config.Homebrew{
@@ -249,34 +298,50 @@ func TestRunPipeMultipleDarwin64Build(t *testing.T) {
}, },
) )
ctx.TokenType = context.TokenTypeGitHub
f, err := ioutil.TempFile("", "") f, err := ioutil.TempFile("", "")
assert.NoError(t, err) assert.NoError(t, err)
defer f.Close() defer f.Close()
ctx.Artifacts.Add(&artifact.Artifact{
Name: "bin1", osarchs := []struct {
Path: f.Name(), goos string
Goos: "darwin", goarch string
Goarch: "amd64", }{
Type: artifact.UploadableArchive, {goos: "darwin", goarch: "amd64"},
Extra: map[string]interface{}{ {goos: "linux", goarch: "amd64"},
"ID": "foo", }
"Format": "tar.gz",
}, for idx, ttt := range osarchs {
}) t.Run(ttt.goos, func(tt *testing.T) {
ctx.Artifacts.Add(&artifact.Artifact{ ctx.Artifacts.Add(&artifact.Artifact{
Name: "bin2", Name: fmt.Sprintf("bin%d", idx),
Path: f.Name(), Path: f.Name(),
Goos: "darwin", Goos: ttt.goos,
Goarch: "amd64", Goarch: ttt.goarch,
Type: artifact.UploadableArchive, Type: artifact.UploadableArchive,
Extra: map[string]interface{}{ Extra: map[string]interface{}{
"ID": "bar", "ID": "foo",
"Format": "tar.gz", "Format": "tar.gz",
}, },
}) })
client := &DummyClient{} ctx.Artifacts.Add(&artifact.Artifact{
assert.Equal(t, ErrMultipleArchivesSameOS, doRun(ctx, ctx.Config.Brews[0], client)) Name: fmt.Sprintf("bin%d", idx),
assert.False(t, client.CreatedFile) Path: f.Name(),
Goos: ttt.goos,
Goarch: ttt.goarch,
Type: artifact.UploadableArchive,
Extra: map[string]interface{}{
"ID": "bar",
"Format": "tar.gz",
},
})
client := &DummyClient{}
assert.Equal(t, ErrMultipleArchivesSameOS, doRun(ctx, ctx.Config.Brews[0], client))
assert.False(t, client.CreatedFile)
// clean the artifacts for the next run
ctx.Artifacts = artifact.New()
})
}
} }
func TestRunPipeBrewNotSetup(t *testing.T) { func TestRunPipeBrewNotSetup(t *testing.T) {
@@ -329,6 +394,7 @@ func TestRunPipeNoUpload(t *testing.T) {
}, },
}, },
}) })
ctx.TokenType = context.TokenTypeGitHub
ctx.Git = context.GitInfo{CurrentTag: "v1.0.1"} ctx.Git = context.GitInfo{CurrentTag: "v1.0.1"}
var path = filepath.Join(folder, "whatever.tar.gz") var path = filepath.Join(folder, "whatever.tar.gz")
_, err = os.Create(path) _, err = os.Create(path)
@@ -380,13 +446,41 @@ func TestRunPipeNoUpload(t *testing.T) {
} }
assertNoPublish(tt) assertNoPublish(tt)
}) })
t.Run("skip publish because not a github release", func(tt *testing.T) { }
ctx.Config.Release.Draft = false
ctx.Config.Brew.SkipUpload = "false" func TestRunTokenTypeNotImplementedForBrew(t *testing.T) {
ctx.SkipPublish = false folder, err := ioutil.TempDir("", "goreleasertest")
ctx.TokenType = context.TokenTypeGitLab assert.NoError(t, err)
assertNoPublish(tt) var ctx = context.New(config.Project{
Dist: folder,
ProjectName: "foo",
Release: config.Release{},
Brews: []config.Homebrew{
{
GitHub: config.Repo{
Owner: "test",
Name: "test",
},
},
},
}) })
ctx.Git = context.GitInfo{CurrentTag: "v1.0.1"}
var path = filepath.Join(folder, "whatever.tar.gz")
_, err = os.Create(path)
assert.NoError(t, err)
ctx.Artifacts.Add(&artifact.Artifact{
Name: "bin",
Path: path,
Goos: "darwin",
Goarch: "amd64",
Type: artifact.UploadableArchive,
Extra: map[string]interface{}{
"ID": "foo",
"Format": "tar.gz",
},
})
client := &DummyClient{}
assert.Equal(t, ErrTokenTypeNotImplementedForBrew, doRun(ctx, ctx.Config.Brews[0], client))
} }
func TestDefault(t *testing.T) { func TestDefault(t *testing.T) {
@@ -394,6 +488,7 @@ func TestDefault(t *testing.T) {
defer back() defer back()
var ctx = &context.Context{ var ctx = &context.Context{
TokenType: context.TokenTypeGitHub,
Config: config.Project{ Config: config.Project{
ProjectName: "myproject", ProjectName: "myproject",
Brews: []config.Homebrew{}, Brews: []config.Homebrew{},
@@ -427,8 +522,8 @@ func TestDefault(t *testing.T) {
} }
func TestGHFolder(t *testing.T) { func TestGHFolder(t *testing.T) {
assert.Equal(t, "bar.rb", ghFormulaPath("", "bar.rb")) assert.Equal(t, "bar.rb", buildFormulaPath("", "bar.rb"))
assert.Equal(t, "fooo/bar.rb", ghFormulaPath("fooo", "bar.rb")) assert.Equal(t, "fooo/bar.rb", buildFormulaPath("fooo", "bar.rb"))
} }
type DummyClient struct { type DummyClient struct {
@@ -446,6 +541,6 @@ func (client *DummyClient) CreateFile(ctx *context.Context, commitAuthor config.
return return
} }
func (client *DummyClient) Upload(ctx *context.Context, releaseID string, name string, file *os.File) (err error) { func (client *DummyClient) Upload(ctx *context.Context, releaseID string, artifact *artifact.Artifact, file *os.File) (err error) {
return return
} }

View File

@@ -0,0 +1,40 @@
# This file was generated by GoReleaser. DO NOT EDIT.
class DefaultGitlab < Formula
desc "A run pipe test formula and FOO=foo_is_bar"
homepage "https://gitlab.com/goreleaser"
version "1.0.1"
bottle :unneeded
if OS.mac?
url "https://gitlab.com/test/test/uploads/820ead5d9d2266c728dce6d4d55b6460/bin.tar.gz"
sha256 "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
elsif OS.linux?
end
depends_on "zsh"
depends_on "bash"
conflicts_with "gtk+"
conflicts_with "qt"
def install
bin.install "default_gitlab"
end
def caveats; <<~EOS
don't do this default_gitlab
EOS
end
plist_options :startup => false
def plist; <<~EOS
<xml>whatever</xml>
EOS
end
test do
system "true"
system "#{bin}/foo -h"
end
end

View File

@@ -0,0 +1,40 @@
# This file was generated by GoReleaser. DO NOT EDIT.
class GitlabEnterpriseUrl < Formula
desc "A run pipe test formula and FOO=foo_is_bar"
homepage "https://gitlab.com/goreleaser"
version "1.0.1"
bottle :unneeded
if OS.mac?
url "https://gitlab.my-company.org/test/test/uploads/820ead5d9d2266c728dce6d4d55b6460/bin.tar.gz"
sha256 "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
elsif OS.linux?
end
depends_on "zsh"
depends_on "bash"
conflicts_with "gtk+"
conflicts_with "qt"
def install
bin.install "gitlab_enterprise_url"
end
def caveats; <<~EOS
don't do this gitlab_enterprise_url
EOS
end
plist_options :startup => false
def plist; <<~EOS
<xml>whatever</xml>
EOS
end
test do
system "true"
system "#{bin}/foo -h"
end
end

View File

@@ -21,7 +21,8 @@ func TestFillBasicData(t *testing.T) {
testlib.GitRemoteAdd(t, "git@github.com:goreleaser/goreleaser.git") testlib.GitRemoteAdd(t, "git@github.com:goreleaser/goreleaser.git")
var ctx = &context.Context{ var ctx = &context.Context{
Config: config.Project{}, TokenType: context.TokenTypeGitHub,
Config: config.Project{},
} }
assert.NoError(t, Pipe{}.Run(ctx)) assert.NoError(t, Pipe{}.Run(ctx))

View File

@@ -142,5 +142,5 @@ func upload(ctx *context.Context, client client.Client, releaseID string, artifa
} }
defer file.Close() // nolint: errcheck defer file.Close() // nolint: errcheck
log.WithField("file", file.Name()).WithField("name", artifact.Name).Info("uploading to release") log.WithField("file", file.Name()).WithField("name", artifact.Name).Info("uploading to release")
return client.Upload(ctx, releaseID, artifact.Name, file) return client.Upload(ctx, releaseID, artifact, file)
} }

View File

@@ -374,7 +374,7 @@ func (client *DummyClient) CreateFile(ctx *context.Context, commitAuthor config.
return return
} }
func (client *DummyClient) Upload(ctx *context.Context, releaseID string, name string, file *os.File) error { func (client *DummyClient) Upload(ctx *context.Context, releaseID string, artifact *artifact.Artifact, file *os.File) error {
client.Lock.Lock() client.Lock.Lock()
defer client.Lock.Unlock() defer client.Lock.Unlock()
// ensure file is read to better mimic real behavior // ensure file is read to better mimic real behavior
@@ -390,6 +390,6 @@ func (client *DummyClient) Upload(ctx *context.Context, releaseID string, name s
return errors.New("upload failed, should retry") return errors.New("upload failed, should retry")
} }
client.UploadedFile = true client.UploadedFile = true
client.UploadedFileNames = append(client.UploadedFileNames, name) client.UploadedFileNames = append(client.UploadedFileNames, artifact.Name)
return nil return nil
} }

View File

@@ -17,6 +17,9 @@ import (
// ErrNoWindows when there is no build for windows (goos doesn't contain windows) // ErrNoWindows when there is no build for windows (goos doesn't contain windows)
var ErrNoWindows = errors.New("scoop requires a windows build") var ErrNoWindows = errors.New("scoop requires a windows build")
// ErrTokenTypeNotImplementedForScoop indicates that a new token type was not implemented for this pipe
var ErrTokenTypeNotImplementedForScoop = errors.New("token type not implemented for scoop pipe")
// Pipe for build // Pipe for build
type Pipe struct{} type Pipe struct{}
@@ -44,14 +47,7 @@ func (Pipe) Default(ctx *context.Context) error {
if ctx.Config.Scoop.CommitAuthor.Email == "" { if ctx.Config.Scoop.CommitAuthor.Email == "" {
ctx.Config.Scoop.CommitAuthor.Email = "goreleaser@carlosbecker.com" ctx.Config.Scoop.CommitAuthor.Email = "goreleaser@carlosbecker.com"
} }
if ctx.Config.Scoop.URLTemplate == "" {
ctx.Config.Scoop.URLTemplate = fmt.Sprintf(
"%s/%s/%s/releases/download/{{ .Tag }}/{{ .ArtifactName }}",
ctx.Config.GitHubURLs.Download,
ctx.Config.Release.GitHub.Owner,
ctx.Config.Release.GitHub.Name,
)
}
return nil return nil
} }
@@ -59,12 +55,12 @@ func doRun(ctx *context.Context, client client.Client) error {
if ctx.Config.Scoop.Bucket.Name == "" { if ctx.Config.Scoop.Bucket.Name == "" {
return pipe.Skip("scoop section is not configured") return pipe.Skip("scoop section is not configured")
} }
// If we'd use 'ctx.TokenType != context.TokenTypeGitHub' we'd have to adapt all the tests
// For simplicity we use this check because the functionality will be implemented later for // TODO mavogel: in another PR
// all types of releases. See https://github.com/goreleaser/goreleaser/pull/1038#issuecomment-498891464 // check if release pipe is not configured!
if ctx.TokenType == context.TokenTypeGitLab { // if ctx.Config.Release.Disable {
return pipe.Skip("scoop pipe is only configured for github releases") // }
}
if ctx.Config.Archive.Format == "binary" { if ctx.Config.Archive.Format == "binary" {
return pipe.Skip("archive format is binary") return pipe.Skip("archive format is binary")
} }
@@ -131,6 +127,27 @@ func buildManifest(ctx *context.Context, artifacts []*artifact.Artifact) (bytes.
Persist: ctx.Config.Scoop.Persist, Persist: ctx.Config.Scoop.Persist,
} }
if ctx.Config.Scoop.URLTemplate == "" {
switch ctx.TokenType {
case context.TokenTypeGitHub:
ctx.Config.Scoop.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:
ctx.Config.Scoop.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, ErrTokenTypeNotImplementedForScoop
}
}
for _, artifact := range artifacts { for _, artifact := range artifacts {
var arch = "64bit" var arch = "64bit"
if artifact.Goarch == "386" { if artifact.Goarch == "386" {

View File

@@ -28,6 +28,7 @@ func TestDefault(t *testing.T) {
defer back() defer back()
var ctx = &context.Context{ var ctx = &context.Context{
TokenType: context.TokenTypeGitHub,
Config: config.Project{ Config: config.Project{
ProjectName: "barr", ProjectName: "barr",
Builds: []config.Build{ Builds: []config.Build{
@@ -85,9 +86,10 @@ func Test_doRun(t *testing.T) {
assertError errChecker assertError errChecker
}{ }{
{ {
"valid", "valid public github",
args{ args{
&context.Context{ &context.Context{
TokenType: context.TokenTypeGitHub,
Git: context.GitInfo{ Git: context.GitInfo{
CurrentTag: "v1.0.1", CurrentTag: "v1.0.1",
}, },
@@ -127,9 +129,10 @@ func Test_doRun(t *testing.T) {
shouldNotErr, shouldNotErr,
}, },
{ {
"valid", "valid enterprise github",
args{ args{
&context.Context{ &context.Context{
TokenType: context.TokenTypeGitHub,
Git: context.GitInfo{ Git: context.GitInfo{
CurrentTag: "v1.0.1", CurrentTag: "v1.0.1",
}, },
@@ -169,10 +172,172 @@ func Test_doRun(t *testing.T) {
}, },
shouldNotErr, shouldNotErr,
}, },
{
"valid public gitlab",
args{
&context.Context{
TokenType: context.TokenTypeGitLab,
Git: context.GitInfo{
CurrentTag: "v1.0.1",
},
Version: "1.0.1",
Artifacts: artifact.New(),
Config: config.Project{
Builds: []config.Build{
{Binary: "test", Goarch: []string{"amd64"}, Goos: []string{"windows"}},
},
Dist: ".",
ProjectName: "run-pipe",
Archive: config.Archive{
Format: "tar.gz",
},
Release: config.Release{
GitLab: config.Repo{
Owner: "test",
Name: "test",
},
},
Scoop: config.Scoop{
Bucket: config.Repo{
Owner: "test",
Name: "test",
},
Description: "A run pipe test formula",
Homepage: "https://gitlab.com/goreleaser",
},
},
},
&DummyClient{},
},
[]*artifact.Artifact{
{
Name: "foo_1.0.1_windows_amd64.tar.gz",
Goos: "windows",
Goarch: "amd64",
Path: file,
Extra: map[string]interface{}{
"ArtifactUploadHash": "820ead5d9d2266c728dce6d4d55b6460",
},
},
{
Name: "foo_1.0.1_windows_386.tar.gz",
Goos: "windows",
Goarch: "386",
Path: file,
Extra: map[string]interface{}{
"ArtifactUploadHash": "820ead5d9d2266c728dce6d4d55b6460",
},
},
},
shouldNotErr,
},
{
"valid enterprise gitlab",
args{
&context.Context{
TokenType: context.TokenTypeGitLab,
Git: context.GitInfo{
CurrentTag: "v1.0.1",
},
Version: "1.0.1",
Artifacts: artifact.New(),
Config: config.Project{
GitHubURLs: config.GitHubURLs{Download: "https://api.custom.gitlab.enterprise.com"},
Builds: []config.Build{
{Binary: "test", Goarch: []string{"amd64"}, Goos: []string{"windows"}},
},
Dist: ".",
ProjectName: "run-pipe",
Archive: config.Archive{
Format: "tar.gz",
},
Release: config.Release{
GitHub: config.Repo{
Owner: "test",
Name: "test",
},
},
Scoop: config.Scoop{
Bucket: config.Repo{
Owner: "test",
Name: "test",
},
Description: "A run pipe test formula",
Homepage: "https://gitlab.com/goreleaser",
},
},
},
&DummyClient{},
},
[]*artifact.Artifact{
{
Name: "foo_1.0.1_windows_amd64.tar.gz",
Goos: "windows",
Goarch: "amd64",
Path: file,
Extra: map[string]interface{}{
"ArtifactUploadHash": "820ead5d9d2266c728dce6d4d55b6460",
},
},
{
Name: "foo_1.0.1_windows_386.tar.gz",
Goos: "windows",
Goarch: "386",
Path: file,
Extra: map[string]interface{}{
"ArtifactUploadHash": "820ead5d9d2266c728dce6d4d55b6460",
},
},
},
shouldNotErr,
},
{
"token type not implemented for pipe",
args{
&context.Context{
Git: context.GitInfo{
CurrentTag: "v1.0.1",
},
Version: "1.0.1",
Artifacts: artifact.New(),
Config: config.Project{
Builds: []config.Build{
{Binary: "test", Goarch: []string{"amd64"}, Goos: []string{"windows"}},
},
Dist: ".",
ProjectName: "run-pipe",
Archive: config.Archive{
Format: "tar.gz",
},
Release: config.Release{
GitHub: config.Repo{
Owner: "test",
Name: "test",
},
},
Scoop: config.Scoop{
Bucket: config.Repo{
Owner: "test",
Name: "test",
},
Description: "A run pipe test formula",
Homepage: "https://github.com/goreleaser",
},
},
},
&DummyClient{},
},
[]*artifact.Artifact{
{Name: "foo_1.0.1_windows_amd64.tar.gz", Goos: "windows", Goarch: "amd64", Path: file},
{Name: "foo_1.0.1_windows_386.tar.gz", Goos: "windows", Goarch: "386", Path: file},
},
shouldErr(ErrTokenTypeNotImplementedForScoop.Error()),
},
{ {
"no windows build", "no windows build",
args{ args{
&context.Context{ &context.Context{
TokenType: context.TokenTypeGitHub,
Git: context.GitInfo{ Git: context.GitInfo{
CurrentTag: "v1.0.1", CurrentTag: "v1.0.1",
}, },
@@ -215,6 +380,7 @@ func Test_doRun(t *testing.T) {
"no scoop", "no scoop",
args{ args{
&context.Context{ &context.Context{
TokenType: context.TokenTypeGitHub,
Git: context.GitInfo{ Git: context.GitInfo{
CurrentTag: "v1.0.1", CurrentTag: "v1.0.1",
}, },
@@ -249,6 +415,7 @@ func Test_doRun(t *testing.T) {
"no publish", "no publish",
args{ args{
&context.Context{ &context.Context{
TokenType: context.TokenTypeGitHub,
Git: context.GitInfo{ Git: context.GitInfo{
CurrentTag: "v1.0.1", CurrentTag: "v1.0.1",
}, },
@@ -292,6 +459,7 @@ func Test_doRun(t *testing.T) {
"is draft", "is draft",
args{ args{
&context.Context{ &context.Context{
TokenType: context.TokenTypeGitHub,
Git: context.GitInfo{ Git: context.GitInfo{
CurrentTag: "v1.0.1", CurrentTag: "v1.0.1",
}, },
@@ -331,6 +499,7 @@ func Test_doRun(t *testing.T) {
"no archive", "no archive",
args{ args{
&context.Context{ &context.Context{
TokenType: context.TokenTypeGitHub,
Git: context.GitInfo{ Git: context.GitInfo{
CurrentTag: "v1.0.1", CurrentTag: "v1.0.1",
}, },
@@ -360,54 +529,11 @@ func Test_doRun(t *testing.T) {
}, },
&DummyClient{}, &DummyClient{},
}, },
[]*artifact.Artifact{
{Name: "foo_1.0.1_windows_amd64.tar.gz", Goos: "windows", Goarch: "amd64"},
{Name: "foo_1.0.1_windows_386.tar.gz", Goos: "windows", Goarch: "386"},
},
shouldErr("archive format is binary"),
},
{
"valid but non github release",
args{
&context.Context{
TokenType: context.TokenTypeGitLab,
Git: context.GitInfo{
CurrentTag: "v1.0.1",
},
Version: "1.0.1",
Artifacts: artifact.New(),
Config: config.Project{
Builds: []config.Build{
{Binary: "test", Goarch: []string{"amd64"}, Goos: []string{"windows"}},
},
Dist: ".",
ProjectName: "run-pipe",
Archive: config.Archive{
Format: "tar.gz",
},
Release: config.Release{
GitLab: config.Repo{
Owner: "test",
Name: "test",
},
},
Scoop: config.Scoop{
Bucket: config.Repo{
Owner: "test",
Name: "test",
},
Description: "A run pipe test formula",
Homepage: "https://github.com/goreleaser",
},
},
},
&DummyClient{},
},
[]*artifact.Artifact{ []*artifact.Artifact{
{Name: "foo_1.0.1_windows_amd64.tar.gz", Goos: "windows", Goarch: "amd64", Path: file}, {Name: "foo_1.0.1_windows_amd64.tar.gz", Goos: "windows", Goarch: "amd64", Path: file},
{Name: "foo_1.0.1_windows_386.tar.gz", Goos: "windows", Goarch: "386", Path: file}, {Name: "foo_1.0.1_windows_386.tar.gz", Goos: "windows", Goarch: "386", Path: file},
}, },
shouldErr("scoop pipe is only configured for github releases"), shouldErr("archive format is binary"),
}, },
} }
for _, tt := range tests { for _, tt := range tests {
@@ -435,6 +561,7 @@ func Test_buildManifest(t *testing.T) {
{ {
"testdata/test_buildmanifest.json.golden", "testdata/test_buildmanifest.json.golden",
&context.Context{ &context.Context{
TokenType: context.TokenTypeGitHub,
Git: context.GitInfo{ Git: context.GitInfo{
CurrentTag: "v1.0.1", CurrentTag: "v1.0.1",
}, },
@@ -470,6 +597,7 @@ func Test_buildManifest(t *testing.T) {
{ {
"testdata/test_buildmanifest_url_template.json.golden", "testdata/test_buildmanifest_url_template.json.golden",
&context.Context{ &context.Context{
TokenType: context.TokenTypeGitHub,
Git: context.GitInfo{ Git: context.GitInfo{
CurrentTag: "v1.0.1", CurrentTag: "v1.0.1",
}, },
@@ -506,6 +634,46 @@ func Test_buildManifest(t *testing.T) {
}, },
}, },
}, },
{
"testdata/test_buildmanifest_gitlab_url_template.json.golden",
&context.Context{
TokenType: context.TokenTypeGitLab,
Git: context.GitInfo{
CurrentTag: "v1.0.1",
},
Version: "1.0.1",
Artifacts: artifact.New(),
Config: config.Project{
GitLabURLs: config.GitLabURLs{
Download: "https://gitlab.com",
},
Builds: []config.Build{
{Binary: "test"},
},
Dist: ".",
ProjectName: "run-pipe",
Archive: config.Archive{
Format: "tar.gz",
},
Release: config.Release{
GitHub: config.Repo{
Owner: "test",
Name: "test",
},
},
Scoop: config.Scoop{
Bucket: config.Repo{
Owner: "test",
Name: "test",
},
Description: "A run pipe test formula",
Homepage: "https://gitlab.com/goreleaser",
URLTemplate: "http://gitlab.mycompany.com/foo/bar/uploads/{{ .ArtifactUploadHash }}/{{ .ArtifactName }}",
Persist: []string{"data.cfg", "etc"},
},
},
},
},
} }
for _, tt := range tests { for _, tt := range tests {
@@ -520,6 +688,7 @@ func Test_buildManifest(t *testing.T) {
Goarch: "amd64", Goarch: "amd64",
Path: file, Path: file,
Extra: map[string]interface{}{ Extra: map[string]interface{}{
"ArtifactUploadHash": "820ead5d9d2266c728dce6d4d55b6460",
"Builds": []*artifact.Artifact{ "Builds": []*artifact.Artifact{
{ {
Extra: map[string]interface{}{ Extra: map[string]interface{}{
@@ -540,6 +709,7 @@ func Test_buildManifest(t *testing.T) {
Goarch: "386", Goarch: "386",
Path: file, Path: file,
Extra: map[string]interface{}{ Extra: map[string]interface{}{
"ArtifactUploadHash": "820ead5d9d2266c728dce6d4d55b6460",
"Builds": []*artifact.Artifact{ "Builds": []*artifact.Artifact{
{ {
Extra: map[string]interface{}{ Extra: map[string]interface{}{
@@ -583,6 +753,6 @@ func (client *DummyClient) CreateFile(ctx *context.Context, commitAuthor config.
return return
} }
func (client *DummyClient) Upload(ctx *context.Context, releaseID string, name string, file *os.File) (err error) { func (client *DummyClient) Upload(ctx *context.Context, releaseID string, artifact *artifact.Artifact, file *os.File) (err error) {
return return
} }

View File

@@ -0,0 +1,27 @@
{
"version": "1.0.1",
"architecture": {
"32bit": {
"url": "http://gitlab.mycompany.com/foo/bar/uploads/820ead5d9d2266c728dce6d4d55b6460/foo_1.0.1_windows_386.tar.gz",
"bin": [
"foo.exe",
"bar.exe"
],
"hash": "5e2bf57d3f40c4b6df69daf1936cb766f832374b4fc0259a7cbff06e2f70f269"
},
"64bit": {
"url": "http://gitlab.mycompany.com/foo/bar/uploads/820ead5d9d2266c728dce6d4d55b6460/foo_1.0.1_windows_amd64.tar.gz",
"bin": [
"foo.exe",
"bar.exe"
],
"hash": "5e2bf57d3f40c4b6df69daf1936cb766f832374b4fc0259a7cbff06e2f70f269"
}
},
"homepage": "https://gitlab.com/goreleaser",
"description": "A run pipe test formula",
"persist": [
"data.cfg",
"etc"
]
}

View File

@@ -40,6 +40,8 @@ const (
arm = "Arm" arm = "Arm"
binary = "Binary" binary = "Binary"
artifactName = "ArtifactName" artifactName = "ArtifactName"
// gitlab only
artifactUploadHash = "ArtifactUploadHash"
) )
// New Template // New Template
@@ -92,6 +94,11 @@ func (t *Template) WithArtifact(a *artifact.Artifact, replacements map[string]st
t.fields[arm] = replace(replacements, a.Goarm) t.fields[arm] = replace(replacements, a.Goarm)
t.fields[binary] = bin.(string) t.fields[binary] = bin.(string)
t.fields[artifactName] = a.Name t.fields[artifactName] = a.Name
if val, ok := a.Extra["ArtifactUploadHash"]; ok {
t.fields[artifactUploadHash] = val
} else {
t.fields[artifactUploadHash] = ""
}
return t return t
} }

View File

@@ -39,6 +39,7 @@ func TestWithArtifact(t *testing.T) {
"shortcommit": "{{.ShortCommit}}", "shortcommit": "{{.ShortCommit}}",
"binary": "{{.Binary}}", "binary": "{{.Binary}}",
"proj": "{{.ProjectName}}", "proj": "{{.ProjectName}}",
"": "{{.ArtifactUploadHash}}",
} { } {
tmpl := tmpl tmpl := tmpl
expect := expect expect := expect
@@ -61,6 +62,24 @@ func TestWithArtifact(t *testing.T) {
}) })
} }
t.Run("artifact with gitlab ArtifactUploadHash", func(tt *testing.T) {
tt.Parallel()
uploadHash := "820ead5d9d2266c728dce6d4d55b6460"
result, err := New(ctx).WithArtifact(
&artifact.Artifact{
Name: "another-binary",
Goarch: "amd64",
Goos: "linux",
Goarm: "6",
Extra: map[string]interface{}{
"ArtifactUploadHash": uploadHash,
},
}, map[string]string{},
).Apply("{{ .ArtifactUploadHash }}")
assert.NoError(tt, err)
assert.Equal(tt, uploadHash, result)
})
t.Run("artifact without binary name", func(tt *testing.T) { t.Run("artifact without binary name", func(tt *testing.T) {
tt.Parallel() tt.Parallel()
result, err := New(ctx).WithArtifact( result, err := New(ctx).WithArtifact(

View File

@@ -45,6 +45,7 @@ func (r Repo) String() string {
type Homebrew struct { type Homebrew struct {
Name string `yaml:",omitempty"` Name string `yaml:",omitempty"`
GitHub Repo `yaml:",omitempty"` GitHub Repo `yaml:",omitempty"`
GitLab Repo `yaml:",omitempty"`
CommitAuthor CommitAuthor `yaml:"commit_author,omitempty"` CommitAuthor CommitAuthor `yaml:"commit_author,omitempty"`
Folder string `yaml:",omitempty"` Folder string `yaml:",omitempty"`
Caveats string `yaml:",omitempty"` Caveats string `yaml:",omitempty"`

View File

@@ -38,14 +38,14 @@ func (e Env) Strings() []string {
return result return result
} }
// tokenType is either github or gitlab // TokenType is either github or gitlab
type tokenType string type TokenType string
const ( const (
// TokenTypeGitHub defines github as type of the token // TokenTypeGitHub defines github as type of the token
TokenTypeGitHub tokenType = "github" TokenTypeGitHub TokenType = "github"
// TokenTypeGitLab defines gitlab as type of the token // TokenTypeGitLab defines gitlab as type of the token
TokenTypeGitLab tokenType = "gitlab" TokenTypeGitLab TokenType = "gitlab"
) )
// Context carries along some data through the pipes // Context carries along some data through the pipes
@@ -54,7 +54,7 @@ type Context struct {
Config config.Project Config config.Project
Env Env Env Env
Token string Token string
TokenType tokenType TokenType TokenType
Git GitInfo Git GitInfo
Artifacts artifact.Artifacts Artifacts artifact.Artifacts
ReleaseNotes string ReleaseNotes string

View File

@@ -5,7 +5,7 @@ hideFromIndex: true
weight: 90 weight: 90
--- ---
After releasing to GitHub (GitLab is not supported yet), GoReleaser can generate and publish a _homebrew-tap_ After releasing to GitHub or GitLab, GoReleaser can generate and publish a _homebrew-tap_
recipe into a repository that you have access to. recipe into a repository that you have access to.
The `brew` section specifies how the formula should be created. The `brew` section specifies how the formula should be created.
@@ -29,13 +29,23 @@ brews:
- foo - foo
- bar - bar
# Repository to push the tap to.
# NOTE: make sure the url_template, the token and given repo (github or gitlab) owner and name are from the
# same kind. We will probably unify this in the next major version like it is done with scoop.
# Github repository to push the tap to.
github: github:
owner: user owner: github-user
name: homebrew-tap name: homebrew-tap
# Template for the url. # OR Gitlab
# Default is "https://github.com/<repo_owner>/<repo_name>/releases/download/{{ .Tag }}/{{ .ArtifactName }}" # gitlab:
# owner: gitlab-user
# name: homebrew-tap
# Template for the url which is determined by the given Token (github or gitlab)
# Default for github is "https://github.com/<repo_owner>/<repo_name>/releases/download/{{ .Tag }}/{{ .ArtifactName }}"
# Default for gitlab is "https://gitlab.com/<repo_owner>/<repo_name>/uploads/{{ .ArtifactUploadHash }}/{{ .ArtifactName }}"
url_template: "http://github.mycompany.com/foo/bar/releases/{{ .Tag }}/{{ .ArtifactName }}" url_template: "http://github.mycompany.com/foo/bar/releases/{{ .Tag }}/{{ .ArtifactName }}"
# Allows you to set a custom download strategy. # Allows you to set a custom download strategy.

View File

@@ -5,7 +5,7 @@ hideFromIndex: true
weight: 100 weight: 100
--- ---
After releasing to GitHub (GitLab is not supported yet), GoReleaser can generate and publish a After releasing to GitHub or GitLab, GoReleaser can generate and publish a
_Scoop App Manifest_ into a repository that you have access to. _Scoop App Manifest_ into a repository that you have access to.
The `scoop` section specifies how the manifest should be created. See The `scoop` section specifies how the manifest should be created. See
@@ -14,8 +14,9 @@ the commented example bellow:
```yml ```yml
# .goreleaser.yml # .goreleaser.yml
scoop: scoop:
# Template for the url. # Template for the url which is determined by the given Token (github or gitlab)
# Default is "https://github.com/<repo_owner>/<repo_name>/releases/download/{{ .Tag }}/{{ .ArtifactName }}" # Default for github is "https://github.com/<repo_owner>/<repo_name>/releases/download/{{ .Tag }}/{{ .ArtifactName }}"
# Default for gitlab is "https://gitlab.com/<repo_owner>/<repo_name>/uploads/{{ .ArtifactUploadHash }}/{{ .ArtifactName }}"
url_template: "http://github.mycompany.com/foo/bar/releases/{{ .Tag }}/{{ .ArtifactName }}" url_template: "http://github.mycompany.com/foo/bar/releases/{{ .Tag }}/{{ .ArtifactName }}"
# Repository to push the app manifest to. # Repository to push the app manifest to.