mirror of
https://github.com/goreleaser/goreleaser.git
synced 2025-02-07 13:31:37 +02:00
feat: Use GitLab Direct Asset Links (#2219)
* feat: Use GitLab Direct Asset Links Implement the use of Direct Asset Links when uploading artifacts to a GitLab release * fix: Remove ArtifactUploadHash As GitLab support for direct asset linking exists, remove ArtifactUploadHash due to it no longer being required * test: fix unit tests for gitlab urls * fix: Use artifact name during GitLab upload file.Name() included the path to the file, which isn't needed and breaks other areas such as homebrew releases * docs: Require GitLab version v12.9+ Due to newly introduced dependency on direct asset linking
This commit is contained in:
parent
513503644e
commit
bf4359017b
@ -2,11 +2,9 @@ package client
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/apex/log"
|
||||
"github.com/goreleaser/goreleaser/internal/artifact"
|
||||
@ -18,9 +16,6 @@ import (
|
||||
|
||||
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")
|
||||
|
||||
type gitlabClient struct {
|
||||
client *gitlab.Client
|
||||
}
|
||||
@ -264,7 +259,7 @@ func (c *gitlabClient) CreateRelease(ctx *context.Context, body string) (release
|
||||
|
||||
func (c *gitlabClient) ReleaseURLTemplate(ctx *context.Context) (string, error) {
|
||||
return fmt.Sprintf(
|
||||
"%s/%s/%s/uploads/{{ .ArtifactUploadHash }}/{{ .ArtifactName }}",
|
||||
"%s/%s/%s/-/releases/{{ .Tag }}/downloads/{{ .ArtifactName }}",
|
||||
ctx.Config.GitLabURLs.Download,
|
||||
ctx.Config.Release.GitLab.Owner,
|
||||
ctx.Config.Release.GitLab.Name,
|
||||
@ -299,12 +294,14 @@ func (c *gitlabClient) Upload(
|
||||
// projectFile.URL from upload: /uploads/<hash>/filename.txt
|
||||
linkURL := gitlabBaseURL + "/" + projectID + projectFile.URL
|
||||
name := artifact.Name
|
||||
filename := "/" + name
|
||||
releaseLink, _, err := c.client.ReleaseLinks.CreateReleaseLink(
|
||||
projectID,
|
||||
releaseID,
|
||||
&gitlab.CreateReleaseLinkOptions{
|
||||
Name: &name,
|
||||
URL: &linkURL,
|
||||
Name: &name,
|
||||
URL: &linkURL,
|
||||
FilePath: &filename,
|
||||
})
|
||||
if err != nil {
|
||||
return RetriableError{err}
|
||||
@ -312,43 +309,17 @@ func (c *gitlabClient) Upload(
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
"id": releaseLink.ID,
|
||||
"url": releaseLink.URL,
|
||||
"url": releaseLink.DirectAssetURL,
|
||||
}).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 nil
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// getMilestoneByTitle returns a milestone by title.
|
||||
func (c *gitlabClient) getMilestoneByTitle(repo Repo, title string) (*gitlab.Milestone, error) {
|
||||
opts := &gitlab.ListMilestonesOptions{
|
||||
|
@ -1,7 +1,6 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/goreleaser/goreleaser/pkg/config"
|
||||
@ -9,31 +8,6 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
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)
|
||||
}
|
||||
require.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")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGitLabReleaseURLTemplate(t *testing.T) {
|
||||
ctx := context.New(config.Project{
|
||||
GitLabURLs: config.GitLabURLs{
|
||||
@ -53,6 +27,6 @@ func TestGitLabReleaseURLTemplate(t *testing.T) {
|
||||
urlTpl, err := client.ReleaseURLTemplate(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
expectedUrl := "https://gitlab.com/owner/name/uploads/{{ .ArtifactUploadHash }}/{{ .ArtifactName }}"
|
||||
expectedUrl := "https://gitlab.com/owner/name/-/releases/{{ .Tag }}/downloads/{{ .ArtifactName }}"
|
||||
require.Equal(t, expectedUrl, urlTpl)
|
||||
}
|
||||
|
@ -223,9 +223,8 @@ func TestRunPipe(t *testing.T) {
|
||||
Goarch: "amd64",
|
||||
Type: artifact.UploadableArchive,
|
||||
Extra: map[string]interface{}{
|
||||
"ID": "bar",
|
||||
"Format": "tar.gz",
|
||||
"ArtifactUploadHash": "820ead5d9d2266c728dce6d4d55b6460",
|
||||
"ID": "bar",
|
||||
"Format": "tar.gz",
|
||||
},
|
||||
})
|
||||
path := filepath.Join(folder, "bin.tar.gz")
|
||||
@ -236,9 +235,8 @@ func TestRunPipe(t *testing.T) {
|
||||
Goarch: "amd64",
|
||||
Type: artifact.UploadableArchive,
|
||||
Extra: map[string]interface{}{
|
||||
"ID": "foo",
|
||||
"Format": "tar.gz",
|
||||
"ArtifactUploadHash": "820ead5d9d2266c728dce6d4d55b6460",
|
||||
"ID": "foo",
|
||||
"Format": "tar.gz",
|
||||
},
|
||||
})
|
||||
|
||||
@ -301,9 +299,8 @@ func TestRunPipeNameTemplate(t *testing.T) {
|
||||
Goarch: "amd64",
|
||||
Type: artifact.UploadableArchive,
|
||||
Extra: map[string]interface{}{
|
||||
"ID": "foo",
|
||||
"Format": "tar.gz",
|
||||
"ArtifactUploadHash": "820ead5d9d2266c728dce6d4d55b6460",
|
||||
"ID": "foo",
|
||||
"Format": "tar.gz",
|
||||
},
|
||||
})
|
||||
|
||||
@ -386,9 +383,8 @@ func TestRunPipeMultipleBrewsWithSkip(t *testing.T) {
|
||||
Goarch: "amd64",
|
||||
Type: artifact.UploadableArchive,
|
||||
Extra: map[string]interface{}{
|
||||
"ID": "foo",
|
||||
"Format": "tar.gz",
|
||||
"ArtifactUploadHash": "820ead5d9d2266c728dce6d4d55b6460",
|
||||
"ID": "foo",
|
||||
"Format": "tar.gz",
|
||||
},
|
||||
})
|
||||
|
||||
|
@ -274,18 +274,12 @@ func Test_doRun(t *testing.T) {
|
||||
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,
|
||||
@ -334,18 +328,12 @@ func Test_doRun(t *testing.T) {
|
||||
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,
|
||||
@ -904,7 +892,7 @@ func Test_buildManifest(t *testing.T) {
|
||||
},
|
||||
Description: "A run pipe test formula",
|
||||
Homepage: "https://gitlab.com/goreleaser",
|
||||
URLTemplate: "http://gitlab.mycompany.com/foo/bar/uploads/{{ .ArtifactUploadHash }}/{{ .ArtifactName }}",
|
||||
URLTemplate: "http://gitlab.mycompany.com/foo/bar/-/releases/{{ .Tag }}/downloads/{{ .ArtifactName }}",
|
||||
CommitMessageTemplate: "chore(scoop): update {{ .ProjectName }} version {{ .Tag }}",
|
||||
Persist: []string{"data.cfg", "etc"},
|
||||
},
|
||||
@ -929,7 +917,6 @@ func Test_buildManifest(t *testing.T) {
|
||||
Goarch: "amd64",
|
||||
Path: file,
|
||||
Extra: map[string]interface{}{
|
||||
"ArtifactUploadHash": "820ead5d9d2266c728dce6d4d55b6460",
|
||||
"Builds": []*artifact.Artifact{
|
||||
{
|
||||
Name: "foo.exe",
|
||||
@ -946,7 +933,6 @@ func Test_buildManifest(t *testing.T) {
|
||||
Goarch: "arm",
|
||||
Path: file,
|
||||
Extra: map[string]interface{}{
|
||||
"ArtifactUploadHash": "820ead5d9d2266c728dce6d4d55b6460",
|
||||
"Builds": []*artifact.Artifact{
|
||||
{
|
||||
Name: "foo.exe",
|
||||
@ -963,7 +949,6 @@ func Test_buildManifest(t *testing.T) {
|
||||
Goarch: "386",
|
||||
Path: file,
|
||||
Extra: map[string]interface{}{
|
||||
"ArtifactUploadHash": "820ead5d9d2266c728dce6d4d55b6460",
|
||||
"Builds": []*artifact.Artifact{
|
||||
{
|
||||
Name: "foo.exe",
|
||||
@ -1026,7 +1011,7 @@ func TestWrapInDirectory(t *testing.T) {
|
||||
},
|
||||
Description: "A run pipe test formula",
|
||||
Homepage: "https://gitlab.com/goreleaser",
|
||||
URLTemplate: "http://gitlab.mycompany.com/foo/bar/uploads/{{ .ArtifactUploadHash }}/{{ .ArtifactName }}",
|
||||
URLTemplate: "http://gitlab.mycompany.com/foo/bar/-/releases/{{ .Tag }}/downloads/{{ .ArtifactName }}",
|
||||
CommitMessageTemplate: "chore(scoop): update {{ .ProjectName }} version {{ .Tag }}",
|
||||
Persist: []string{"data.cfg", "etc"},
|
||||
},
|
||||
@ -1042,8 +1027,7 @@ func TestWrapInDirectory(t *testing.T) {
|
||||
Goarch: "amd64",
|
||||
Path: file,
|
||||
Extra: map[string]interface{}{
|
||||
"ArtifactUploadHash": "820ead5d9d2266c728dce6d4d55b6460",
|
||||
"WrappedIn": "foo_1.0.1_windows_amd64",
|
||||
"WrappedIn": "foo_1.0.1_windows_amd64",
|
||||
"Builds": []*artifact.Artifact{
|
||||
{
|
||||
Name: "foo.exe",
|
||||
|
@ -2,7 +2,7 @@
|
||||
"version": "1.0.1",
|
||||
"architecture": {
|
||||
"32bit": {
|
||||
"url": "http://gitlab.mycompany.com/foo/bar/uploads/820ead5d9d2266c728dce6d4d55b6460/foo_1.0.1_windows_386.tar.gz",
|
||||
"url": "http://gitlab.mycompany.com/foo/bar/-/releases/v1.0.1/downloads/foo_1.0.1_windows_386.tar.gz",
|
||||
"bin": [
|
||||
"foo.exe",
|
||||
"bar.exe"
|
||||
@ -10,7 +10,7 @@
|
||||
"hash": "5e2bf57d3f40c4b6df69daf1936cb766f832374b4fc0259a7cbff06e2f70f269"
|
||||
},
|
||||
"64bit": {
|
||||
"url": "http://gitlab.mycompany.com/foo/bar/uploads/820ead5d9d2266c728dce6d4d55b6460/foo_1.0.1_windows_amd64.tar.gz",
|
||||
"url": "http://gitlab.mycompany.com/foo/bar/-/releases/v1.0.1/downloads/foo_1.0.1_windows_amd64.tar.gz",
|
||||
"bin": [
|
||||
"foo.exe",
|
||||
"bar.exe"
|
||||
|
@ -2,7 +2,7 @@
|
||||
"version": "1.0.1",
|
||||
"architecture": {
|
||||
"64bit": {
|
||||
"url": "http://gitlab.mycompany.com/foo/bar/uploads/820ead5d9d2266c728dce6d4d55b6460/foo_1.0.1_windows_amd64.tar.gz",
|
||||
"url": "http://gitlab.mycompany.com/foo/bar/-/releases/v1.0.1/downloads/foo_1.0.1_windows_amd64.tar.gz",
|
||||
"bin": [
|
||||
"foo_1.0.1_windows_amd64/foo.exe",
|
||||
"foo_1.0.1_windows_amd64/bar.exe"
|
||||
|
@ -55,9 +55,6 @@ const (
|
||||
artifactName = "ArtifactName"
|
||||
artifactPath = "ArtifactPath"
|
||||
|
||||
// gitlab only.
|
||||
artifactUploadHash = "ArtifactUploadHash"
|
||||
|
||||
// build keys.
|
||||
name = "Name"
|
||||
ext = "Ext"
|
||||
@ -135,11 +132,6 @@ func (t *Template) WithArtifact(a *artifact.Artifact, replacements map[string]st
|
||||
t.fields[binary] = bin.(string)
|
||||
t.fields[artifactName] = a.Name
|
||||
t.fields[artifactPath] = a.Path
|
||||
if val, ok := a.Extra["ArtifactUploadHash"]; ok {
|
||||
t.fields[artifactUploadHash] = val
|
||||
} else {
|
||||
t.fields[artifactUploadHash] = ""
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
|
@ -47,7 +47,6 @@ func TestWithArtifact(t *testing.T) {
|
||||
"shortcommit": "{{.ShortCommit}}",
|
||||
"binary": "{{.Binary}}",
|
||||
"proj": "{{.ProjectName}}",
|
||||
"": "{{.ArtifactUploadHash}}",
|
||||
"github.com/goreleaser/goreleaser": "{{ .ModulePath }}",
|
||||
} {
|
||||
tmpl := tmpl
|
||||
@ -72,24 +71,6 @@ func TestWithArtifact(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
t.Run("artifact with gitlab ArtifactUploadHash", func(t *testing.T) {
|
||||
t.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 }}")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, uploadHash, result)
|
||||
})
|
||||
|
||||
t.Run("artifact without binary name", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
result, err := New(ctx).WithArtifact(
|
||||
|
@ -49,7 +49,7 @@ brews:
|
||||
|
||||
# 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 }}"
|
||||
# Default for gitlab is "https://gitlab.com/<repo_owner>/<repo_name>/-/releases/{{ .Tag }}/downloads/{{ .ArtifactName }}"
|
||||
# Default for gitea is "https://gitea.com/<repo_owner>/<repo_name>/releases/download/{{ .Tag }}/{{ .ArtifactName }}"
|
||||
url_template: "http://github.mycompany.com/foo/bar/releases/{{ .Tag }}/{{ .ArtifactName }}"
|
||||
|
||||
@ -132,7 +132,7 @@ brews:
|
||||
install: |
|
||||
bin.install "program"
|
||||
...
|
||||
|
||||
|
||||
# Custom post_install script for brew.
|
||||
# Could be used to do any additional work after the "install" script
|
||||
# Default is empty.
|
||||
@ -178,7 +178,7 @@ class Program < Formula
|
||||
def install
|
||||
bin.install "program"
|
||||
end
|
||||
|
||||
|
||||
def post_install
|
||||
etc.install "app-config.conf"
|
||||
end
|
||||
|
@ -95,7 +95,7 @@ release:
|
||||
If you use GitLab subgroups, you need to specify it in the `owner` field, e.g. `mygroup/mysubgroup`.
|
||||
|
||||
!!! warning
|
||||
Only GitLab `v11.7+` are supported for releases.
|
||||
Only GitLab `v12.9+` are supported for releases.
|
||||
|
||||
You can also configure the `release` section to upload to a [Gitea](https://gitea.io) instance:
|
||||
|
||||
|
@ -13,7 +13,7 @@ the commented example below:
|
||||
scoop:
|
||||
# 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 }}"
|
||||
# Default for gitlab is "https://gitlab.com/<repo_owner>/<repo_name>/-/releases/{{ .Tag }}/downloads/{{ .ArtifactName }}"
|
||||
# Default for gitea is "https://gitea.com/<repo_owner>/<repo_name>/releases/download/{{ .Tag }}/{{ .ArtifactName }}"
|
||||
url_template: "http://github.mycompany.com/foo/bar/releases/{{ .Tag }}/{{ .ArtifactName }}"
|
||||
|
||||
|
@ -104,9 +104,9 @@ Or, if you released to GitLab, check it out too!
|
||||
</a>
|
||||
|
||||
!!! note
|
||||
Releasing to a private-hosted GitLab CE will only work for version `v11.7+`,
|
||||
because the release feature was introduced in this
|
||||
[version](https://docs.gitlab.com/ee/user/project/releases/index.html).
|
||||
Releasing to a private-hosted GitLab CE will only work for version `v12.9+`, due to dependencies
|
||||
on [release](https://docs.gitlab.com/ee/user/project/releases/index.html) functionality
|
||||
and [direct asset linking](https://docs.gitlab.com/ee/user/project/releases/index.html#permanent-links-to-release-assets).
|
||||
|
||||
## Dry run
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user