mirror of
https://github.com/goreleaser/goreleaser.git
synced 2025-02-07 13:31:37 +02:00
feat: remove deprecated s3 pipe (#1291)
* feat: remove deprecated s3 pipe Signed-off-by: Carlos Alexandro Becker <caarlos0@gmail.com> * fix: go mod tidy Signed-off-by: Carlos Alexandro Becker <caarlos0@gmail.com>
This commit is contained in:
parent
f1fc2c03bd
commit
5f2cf501e8
2
go.mod
2
go.mod
@ -6,7 +6,7 @@ require (
|
||||
code.gitea.io/sdk/gitea v0.0.0-20191013013401-e41e9ea72caa
|
||||
github.com/Masterminds/semver/v3 v3.0.3
|
||||
github.com/apex/log v1.1.1
|
||||
github.com/aws/aws-sdk-go v1.25.11
|
||||
github.com/aws/aws-sdk-go v1.25.11 // indirect
|
||||
github.com/caarlos0/ctrlc v1.0.0
|
||||
github.com/campoy/unique v0.0.0-20180121183637-88950e537e7e
|
||||
github.com/fatih/color v1.9.0
|
||||
|
@ -11,7 +11,6 @@ import (
|
||||
"github.com/goreleaser/goreleaser/internal/pipe/brew"
|
||||
"github.com/goreleaser/goreleaser/internal/pipe/docker"
|
||||
"github.com/goreleaser/goreleaser/internal/pipe/release"
|
||||
"github.com/goreleaser/goreleaser/internal/pipe/s3"
|
||||
"github.com/goreleaser/goreleaser/internal/pipe/scoop"
|
||||
"github.com/goreleaser/goreleaser/internal/pipe/snapcraft"
|
||||
"github.com/goreleaser/goreleaser/internal/pipe/upload"
|
||||
@ -36,7 +35,6 @@ type Publisher interface {
|
||||
|
||||
// nolint: gochecknoglobals
|
||||
var publishers = []Publisher{
|
||||
s3.Pipe{},
|
||||
blob.Pipe{},
|
||||
upload.Pipe{},
|
||||
artifactory.Pipe{},
|
||||
|
@ -1,86 +0,0 @@
|
||||
package s3
|
||||
|
||||
import (
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials/stscreds"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
)
|
||||
|
||||
type SessionBuilder interface {
|
||||
Config(*aws.Config) SessionBuilder
|
||||
Profile(string) SessionBuilder
|
||||
Options(*session.Options) SessionBuilder
|
||||
Endpoint(string) SessionBuilder
|
||||
S3ForcePathStyle(bool) SessionBuilder
|
||||
Build() *session.Session
|
||||
}
|
||||
|
||||
type sessionBuilder struct {
|
||||
awsConfig *aws.Config
|
||||
profile string
|
||||
options *session.Options
|
||||
endpoint *string
|
||||
forcePathStyle *bool
|
||||
}
|
||||
|
||||
func (sb *sessionBuilder) Config(c *aws.Config) SessionBuilder {
|
||||
sb.awsConfig = c
|
||||
return sb
|
||||
}
|
||||
|
||||
func (sb *sessionBuilder) Profile(p string) SessionBuilder {
|
||||
sb.profile = p
|
||||
return sb
|
||||
}
|
||||
|
||||
func (sb *sessionBuilder) Endpoint(e string) SessionBuilder {
|
||||
sb.endpoint = aws.String(e)
|
||||
return sb
|
||||
}
|
||||
|
||||
func (sb *sessionBuilder) S3ForcePathStyle(b bool) SessionBuilder {
|
||||
sb.forcePathStyle = aws.Bool(b)
|
||||
return sb
|
||||
}
|
||||
|
||||
func (sb *sessionBuilder) Options(o *session.Options) SessionBuilder {
|
||||
sb.options = o
|
||||
return sb
|
||||
}
|
||||
|
||||
func (sb *sessionBuilder) Build() *session.Session {
|
||||
if sb.awsConfig == nil {
|
||||
sb.awsConfig = aws.NewConfig()
|
||||
}
|
||||
|
||||
if sb.endpoint != nil {
|
||||
sb.awsConfig.Endpoint = sb.endpoint
|
||||
sb.awsConfig.S3ForcePathStyle = sb.forcePathStyle
|
||||
}
|
||||
|
||||
sb.awsConfig.Credentials = credentials.NewChainCredentials([]credentials.Provider{
|
||||
&credentials.EnvProvider{},
|
||||
&credentials.SharedCredentialsProvider{
|
||||
Profile: sb.profile,
|
||||
},
|
||||
})
|
||||
|
||||
_, err := sb.awsConfig.Credentials.Get()
|
||||
if err == nil {
|
||||
return session.Must(session.NewSession(sb.awsConfig))
|
||||
}
|
||||
if sb.options == nil {
|
||||
sb.options = &session.Options{
|
||||
AssumeRoleTokenProvider: stscreds.StdinTokenProvider,
|
||||
SharedConfigState: session.SharedConfigEnable,
|
||||
Profile: sb.profile,
|
||||
}
|
||||
}
|
||||
|
||||
return session.Must(session.NewSessionWithOptions(*sb.options))
|
||||
}
|
||||
|
||||
func newSessionBuilder() SessionBuilder {
|
||||
return &sessionBuilder{}
|
||||
}
|
@ -1,202 +0,0 @@
|
||||
package s3
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func setEnv() {
|
||||
os.Setenv("AWS_ACCESS_KEY_ID", "accessKey")
|
||||
os.Setenv("AWS_SECRET_ACCESS_KEY", "secret")
|
||||
}
|
||||
|
||||
func clearnEnv() {
|
||||
os.Unsetenv("AWS_ACCESS_KEY_ID")
|
||||
os.Unsetenv("AWS_SECRET_ACCESS_KEY")
|
||||
os.Unsetenv("AWS_SHARED_CREDENTIALS_FILE")
|
||||
os.Unsetenv("AWS_CONFIG_FILE")
|
||||
}
|
||||
|
||||
func Test_awsSession(t *testing.T) {
|
||||
type args struct {
|
||||
profile string
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want *session.Session
|
||||
before func()
|
||||
expectToken string
|
||||
endpoint string
|
||||
S3ForcePathStyle bool
|
||||
}{
|
||||
{
|
||||
name: "test endpoint",
|
||||
before: setEnv,
|
||||
endpoint: "test",
|
||||
},
|
||||
{
|
||||
name: "test S3ForcePathStyle",
|
||||
before: setEnv,
|
||||
S3ForcePathStyle: true,
|
||||
},
|
||||
{
|
||||
name: "test env provider",
|
||||
args: args{
|
||||
profile: "test1",
|
||||
},
|
||||
before: setEnv,
|
||||
},
|
||||
{
|
||||
name: "test default shared credentials provider",
|
||||
before: func() {
|
||||
clearnEnv()
|
||||
os.Setenv("AWS_SHARED_CREDENTIALS_FILE", filepath.Join("testdata", "credentials.ini"))
|
||||
},
|
||||
expectToken: "token",
|
||||
},
|
||||
{
|
||||
name: "test default shared credentials provider",
|
||||
before: func() {
|
||||
clearnEnv()
|
||||
os.Setenv("AWS_SHARED_CREDENTIALS_FILE", filepath.Join("testdata", "credentials.ini"))
|
||||
},
|
||||
expectToken: "token",
|
||||
},
|
||||
{
|
||||
name: "test profile with shared credentials provider",
|
||||
before: func() {
|
||||
clearnEnv()
|
||||
os.Setenv("AWS_SHARED_CREDENTIALS_FILE", filepath.Join("testdata", "credentials.ini"))
|
||||
},
|
||||
args: args{
|
||||
profile: "no_token",
|
||||
},
|
||||
expectToken: "",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
clearnEnv()
|
||||
defer clearnEnv()
|
||||
if tt.before != nil {
|
||||
tt.before()
|
||||
}
|
||||
|
||||
builder := newSessionBuilder()
|
||||
builder.Profile(tt.args.profile)
|
||||
builder.Endpoint(tt.endpoint)
|
||||
builder.S3ForcePathStyle(tt.S3ForcePathStyle)
|
||||
sess := builder.Build()
|
||||
assert.NotNil(t, sess)
|
||||
|
||||
creds, err := sess.Config.Credentials.Get()
|
||||
assert.Nil(t, err)
|
||||
|
||||
assert.Equal(t, "accessKey", creds.AccessKeyID, "Expect access key ID to match")
|
||||
assert.Equal(t, "secret", creds.SecretAccessKey, "Expect secret access key to match")
|
||||
assert.Equal(t, tt.expectToken, creds.SessionToken, "Expect token to match")
|
||||
|
||||
assert.Equal(t, aws.String(tt.endpoint), sess.Config.Endpoint, "Expect endpoint to match")
|
||||
assert.Equal(t, aws.Bool(tt.S3ForcePathStyle), sess.Config.S3ForcePathStyle, "Expect S3ForcePathStyle to match")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const assumeRoleRespMsg = `
|
||||
<AssumeRoleResponse xmlns="https://sts.amazonaws.com/doc/2011-06-15/">
|
||||
<AssumeRoleResult>
|
||||
<AssumedRoleUser>
|
||||
<Arn>arn:aws:sts::account_id:assumed-role/role/session_name</Arn>
|
||||
<AssumedRoleId>AKID:session_name</AssumedRoleId>
|
||||
</AssumedRoleUser>
|
||||
<Credentials>
|
||||
<AccessKeyId>AKID</AccessKeyId>
|
||||
<SecretAccessKey>SECRET</SecretAccessKey>
|
||||
<SessionToken>SESSION_TOKEN</SessionToken>
|
||||
<Expiration>%s</Expiration>
|
||||
</Credentials>
|
||||
</AssumeRoleResult>
|
||||
<ResponseMetadata>
|
||||
<RequestId>request-id</RequestId>
|
||||
</ResponseMetadata>
|
||||
</AssumeRoleResponse>
|
||||
`
|
||||
|
||||
func Test_awsSession_mfa(t *testing.T) {
|
||||
clearnEnv()
|
||||
defer clearnEnv()
|
||||
os.Setenv("AWS_SHARED_CREDENTIALS_FILE", filepath.Join("testdata", "credentials.ini"))
|
||||
os.Setenv("AWS_CONFIG_FILE", filepath.Join("testdata", "config.ini"))
|
||||
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, r.FormValue("SerialNumber"), "arn:aws:iam::1111111111:mfa/test")
|
||||
assert.Equal(t, r.FormValue("TokenCode"), "tokencode")
|
||||
|
||||
_, err := w.Write([]byte(fmt.Sprintf(assumeRoleRespMsg, time.Now().Add(15*time.Minute).Format("2006-01-02T15:04:05Z"))))
|
||||
assert.NoError(t, err)
|
||||
}))
|
||||
|
||||
customProviderCalled := false
|
||||
|
||||
options := &session.Options{
|
||||
Profile: "cloudformation@flowlab-dev",
|
||||
Config: aws.Config{
|
||||
Region: aws.String("eu-west-1"),
|
||||
Endpoint: aws.String(server.URL),
|
||||
DisableSSL: aws.Bool(true),
|
||||
},
|
||||
SharedConfigState: session.SharedConfigEnable,
|
||||
AssumeRoleTokenProvider: func() (string, error) {
|
||||
customProviderCalled = true
|
||||
return "tokencode", nil
|
||||
},
|
||||
}
|
||||
|
||||
builder := newSessionBuilder()
|
||||
builder.Profile("cloudformation@flowlab-dev")
|
||||
builder.Options(options)
|
||||
sess := builder.Build()
|
||||
|
||||
creds, err := sess.Config.Credentials.Get()
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, customProviderCalled)
|
||||
assert.Contains(t, creds.ProviderName, "AssumeRoleProvider")
|
||||
}
|
||||
|
||||
func Test_awsSession_fail(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
}{
|
||||
{
|
||||
name: "should fail with no credentials",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
clearnEnv()
|
||||
defer clearnEnv()
|
||||
os.Setenv("AWS_SHARED_CREDENTIALS_FILE", "/nope")
|
||||
|
||||
builder := newSessionBuilder()
|
||||
sess := builder.Build()
|
||||
assert.NotNil(t, sess)
|
||||
|
||||
_, err := sess.Config.Credentials.Get()
|
||||
assert.NotNil(t, err)
|
||||
})
|
||||
}
|
||||
}
|
@ -1,126 +0,0 @@
|
||||
// Package s3 provides a Pipe that push artifacts to s3/minio
|
||||
package s3
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/apex/log"
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/s3"
|
||||
"github.com/goreleaser/goreleaser/internal/artifact"
|
||||
"github.com/goreleaser/goreleaser/internal/deprecate"
|
||||
"github.com/goreleaser/goreleaser/internal/pipe"
|
||||
"github.com/goreleaser/goreleaser/internal/semerrgroup"
|
||||
"github.com/goreleaser/goreleaser/internal/tmpl"
|
||||
"github.com/goreleaser/goreleaser/pkg/config"
|
||||
"github.com/goreleaser/goreleaser/pkg/context"
|
||||
)
|
||||
|
||||
// Pipe for Artifactory
|
||||
type Pipe struct{}
|
||||
|
||||
// String returns the description of the pipe
|
||||
func (Pipe) String() string {
|
||||
return "S3"
|
||||
}
|
||||
|
||||
// Default sets the pipe defaults
|
||||
func (Pipe) Default(ctx *context.Context) error {
|
||||
for i := range ctx.Config.S3 {
|
||||
s3 := &ctx.Config.S3[i]
|
||||
if s3.Bucket == "" {
|
||||
continue
|
||||
}
|
||||
deprecate.Notice("s3")
|
||||
if s3.Folder == "" {
|
||||
s3.Folder = "{{ .ProjectName }}/{{ .Tag }}"
|
||||
}
|
||||
if s3.Region == "" {
|
||||
s3.Region = "us-east-1"
|
||||
}
|
||||
if s3.ACL == "" {
|
||||
s3.ACL = "private"
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Publish to S3
|
||||
func (Pipe) Publish(ctx *context.Context) error {
|
||||
if len(ctx.Config.S3) == 0 {
|
||||
return pipe.Skip("s3 section is not configured")
|
||||
}
|
||||
var g = semerrgroup.New(ctx.Parallelism)
|
||||
for _, conf := range ctx.Config.S3 {
|
||||
conf := conf
|
||||
g.Go(func() error {
|
||||
return upload(ctx, conf)
|
||||
})
|
||||
}
|
||||
return g.Wait()
|
||||
}
|
||||
|
||||
func newS3Svc(conf config.S3) *s3.S3 {
|
||||
builder := newSessionBuilder()
|
||||
builder.Profile(conf.Profile)
|
||||
if conf.Endpoint != "" {
|
||||
builder.Endpoint(conf.Endpoint)
|
||||
builder.S3ForcePathStyle(true)
|
||||
}
|
||||
sess := builder.Build()
|
||||
|
||||
return s3.New(sess, &aws.Config{
|
||||
Region: aws.String(conf.Region),
|
||||
})
|
||||
}
|
||||
|
||||
func upload(ctx *context.Context, conf config.S3) error {
|
||||
var svc = newS3Svc(conf)
|
||||
|
||||
template := tmpl.New(ctx)
|
||||
bucket, err := template.Apply(conf.Bucket)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
folder, err := template.Apply(conf.Folder)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var filter = artifact.Or(
|
||||
artifact.ByType(artifact.UploadableArchive),
|
||||
artifact.ByType(artifact.UploadableBinary),
|
||||
artifact.ByType(artifact.Checksum),
|
||||
artifact.ByType(artifact.Signature),
|
||||
artifact.ByType(artifact.LinuxPackage),
|
||||
)
|
||||
if len(conf.IDs) > 0 {
|
||||
filter = artifact.And(filter, artifact.ByIDs(conf.IDs...))
|
||||
}
|
||||
|
||||
var g = semerrgroup.New(ctx.Parallelism)
|
||||
for _, artifact := range ctx.Artifacts.Filter(filter).List() {
|
||||
artifact := artifact
|
||||
g.Go(func() error {
|
||||
f, err := os.Open(artifact.Path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.WithFields(log.Fields{
|
||||
"bucket": bucket,
|
||||
"folder": folder,
|
||||
"artifact": artifact.Name,
|
||||
}).Info("uploading")
|
||||
_, err = svc.PutObjectWithContext(ctx, &s3.PutObjectInput{
|
||||
Bucket: aws.String(bucket),
|
||||
Key: aws.String(filepath.Join(folder, artifact.Name)),
|
||||
Body: f,
|
||||
ACL: aws.String(conf.ACL),
|
||||
})
|
||||
return err
|
||||
})
|
||||
}
|
||||
return g.Wait()
|
||||
}
|
@ -1,236 +0,0 @@
|
||||
package s3
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/s3"
|
||||
"github.com/goreleaser/goreleaser/internal/artifact"
|
||||
"github.com/goreleaser/goreleaser/internal/testlib"
|
||||
"github.com/goreleaser/goreleaser/pkg/config"
|
||||
"github.com/goreleaser/goreleaser/pkg/context"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestDescription(t *testing.T) {
|
||||
assert.NotEmpty(t, Pipe{}.String())
|
||||
}
|
||||
|
||||
func TestNoS3(t *testing.T) {
|
||||
testlib.AssertSkipped(t, Pipe{}.Publish(context.New(config.Project{})))
|
||||
}
|
||||
|
||||
func TestDefaultsNoS3(t *testing.T) {
|
||||
var assert = assert.New(t)
|
||||
var ctx = context.New(config.Project{
|
||||
S3: []config.S3{
|
||||
{},
|
||||
},
|
||||
})
|
||||
assert.NoError(Pipe{}.Default(ctx))
|
||||
assert.Equal([]config.S3{{}}, ctx.Config.S3)
|
||||
}
|
||||
|
||||
func TestDefaults(t *testing.T) {
|
||||
var assert = assert.New(t)
|
||||
var ctx = context.New(config.Project{
|
||||
S3: []config.S3{
|
||||
{
|
||||
Bucket: "foo",
|
||||
},
|
||||
},
|
||||
})
|
||||
assert.NoError(Pipe{}.Default(ctx))
|
||||
assert.Equal([]config.S3{{
|
||||
Bucket: "foo",
|
||||
Region: "us-east-1",
|
||||
Folder: "{{ .ProjectName }}/{{ .Tag }}",
|
||||
ACL: "private",
|
||||
}}, ctx.Config.S3)
|
||||
}
|
||||
|
||||
func TestUpload(t *testing.T) {
|
||||
var listen = randomListen(t)
|
||||
folder, err := ioutil.TempDir("", "goreleasertest")
|
||||
assert.NoError(t, err)
|
||||
tgzpath := filepath.Join(folder, "bin.tar.gz")
|
||||
debpath := filepath.Join(folder, "bin.deb")
|
||||
assert.NoError(t, ioutil.WriteFile(tgzpath, []byte("fake\ntargz"), 0744))
|
||||
assert.NoError(t, ioutil.WriteFile(debpath, []byte("fake\ndeb"), 0744))
|
||||
var ctx = context.New(config.Project{
|
||||
Dist: folder,
|
||||
ProjectName: "testupload",
|
||||
S3: []config.S3{
|
||||
{
|
||||
Bucket: "test",
|
||||
Endpoint: "http://" + listen,
|
||||
IDs: []string{"foo", "bar"},
|
||||
},
|
||||
},
|
||||
})
|
||||
ctx.Git = context.GitInfo{CurrentTag: "v1.0.0"}
|
||||
ctx.Artifacts.Add(&artifact.Artifact{
|
||||
Type: artifact.UploadableArchive,
|
||||
Name: "bin.tar.gz",
|
||||
Path: tgzpath,
|
||||
Extra: map[string]interface{}{
|
||||
"ID": "foo",
|
||||
},
|
||||
})
|
||||
ctx.Artifacts.Add(&artifact.Artifact{
|
||||
Type: artifact.LinuxPackage,
|
||||
Name: "bin.deb",
|
||||
Path: debpath,
|
||||
Extra: map[string]interface{}{
|
||||
"ID": "bar",
|
||||
},
|
||||
})
|
||||
var name = "test_upload"
|
||||
defer stop(t, name)
|
||||
start(t, name, listen)
|
||||
prepareEnv(t, listen)
|
||||
assert.NoError(t, Pipe{}.Default(ctx))
|
||||
assert.NoError(t, Pipe{}.Publish(ctx))
|
||||
}
|
||||
|
||||
func TestUploadCustomBucketID(t *testing.T) {
|
||||
var listen = randomListen(t)
|
||||
folder, err := ioutil.TempDir("", "goreleasertest")
|
||||
assert.NoError(t, err)
|
||||
tgzpath := filepath.Join(folder, "bin.tar.gz")
|
||||
debpath := filepath.Join(folder, "bin.deb")
|
||||
assert.NoError(t, ioutil.WriteFile(tgzpath, []byte("fake\ntargz"), 0744))
|
||||
assert.NoError(t, ioutil.WriteFile(debpath, []byte("fake\ndeb"), 0744))
|
||||
// Set custom BUCKET_ID env variable.
|
||||
err = os.Setenv("BUCKET_ID", "test")
|
||||
assert.NoError(t, err)
|
||||
var ctx = context.New(config.Project{
|
||||
Dist: folder,
|
||||
ProjectName: "testupload",
|
||||
S3: []config.S3{
|
||||
{
|
||||
Bucket: "{{.Env.BUCKET_ID}}",
|
||||
Endpoint: "http://" + listen,
|
||||
},
|
||||
},
|
||||
})
|
||||
ctx.Git = context.GitInfo{CurrentTag: "v1.0.0"}
|
||||
ctx.Artifacts.Add(&artifact.Artifact{
|
||||
Type: artifact.UploadableArchive,
|
||||
Name: "bin.tar.gz",
|
||||
Path: tgzpath,
|
||||
})
|
||||
ctx.Artifacts.Add(&artifact.Artifact{
|
||||
Type: artifact.LinuxPackage,
|
||||
Name: "bin.deb",
|
||||
Path: debpath,
|
||||
})
|
||||
var name = "custom_bucket_id"
|
||||
defer stop(t, name)
|
||||
start(t, name, listen)
|
||||
prepareEnv(t, listen)
|
||||
assert.NoError(t, Pipe{}.Default(ctx))
|
||||
assert.NoError(t, Pipe{}.Publish(ctx))
|
||||
}
|
||||
|
||||
func TestUploadInvalidCustomBucketID(t *testing.T) {
|
||||
var listen = randomListen(t)
|
||||
folder, err := ioutil.TempDir("", "goreleasertest")
|
||||
assert.NoError(t, err)
|
||||
tgzpath := filepath.Join(folder, "bin.tar.gz")
|
||||
debpath := filepath.Join(folder, "bin.deb")
|
||||
assert.NoError(t, ioutil.WriteFile(tgzpath, []byte("fake\ntargz"), 0744))
|
||||
assert.NoError(t, ioutil.WriteFile(debpath, []byte("fake\ndeb"), 0744))
|
||||
// Set custom BUCKET_ID env variable.
|
||||
assert.NoError(t, err)
|
||||
var ctx = context.New(config.Project{
|
||||
Dist: folder,
|
||||
ProjectName: "testupload",
|
||||
S3: []config.S3{
|
||||
{
|
||||
Bucket: "{{.Bad}}",
|
||||
Endpoint: "http://" + listen,
|
||||
},
|
||||
},
|
||||
})
|
||||
ctx.Git = context.GitInfo{CurrentTag: "v1.0.0"}
|
||||
ctx.Artifacts.Add(&artifact.Artifact{
|
||||
Type: artifact.UploadableArchive,
|
||||
Name: "bin.tar.gz",
|
||||
Path: tgzpath,
|
||||
})
|
||||
ctx.Artifacts.Add(&artifact.Artifact{
|
||||
Type: artifact.LinuxPackage,
|
||||
Name: "bin.deb",
|
||||
Path: debpath,
|
||||
})
|
||||
var name = "invalid_bucket_id"
|
||||
defer stop(t, name)
|
||||
start(t, name, listen)
|
||||
prepareEnv(t, listen)
|
||||
assert.NoError(t, Pipe{}.Default(ctx))
|
||||
assert.Error(t, Pipe{}.Publish(ctx))
|
||||
}
|
||||
|
||||
func randomListen(t *testing.T) string {
|
||||
listener, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
require.NoError(t, err)
|
||||
listener.Close()
|
||||
return listener.Addr().String()
|
||||
}
|
||||
|
||||
func prepareEnv(t *testing.T, listen string) {
|
||||
os.Setenv("AWS_ACCESS_KEY_ID", "minio")
|
||||
os.Setenv("AWS_SECRET_ACCESS_KEY", "miniostorage")
|
||||
os.Setenv("AWS_REGION", "us-east-1")
|
||||
|
||||
t.Log("creating test bucket")
|
||||
_, err := newS3Svc(config.S3{
|
||||
Endpoint: "http://" + listen,
|
||||
Region: "us-east-1",
|
||||
}).CreateBucket(&s3.CreateBucketInput{
|
||||
Bucket: aws.String("test"),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func start(t *testing.T, name, listen string) {
|
||||
if out, err := exec.Command(
|
||||
"docker", "run", "-d", "--rm",
|
||||
"--name", name,
|
||||
"-p", listen+":9000",
|
||||
"-e", "MINIO_ACCESS_KEY=minio",
|
||||
"-e", "MINIO_SECRET_KEY=miniostorage",
|
||||
"--health-interval", "1s",
|
||||
"minio/minio:RELEASE.2019-05-14T23-57-45Z",
|
||||
"server", "/data",
|
||||
).CombinedOutput(); err != nil {
|
||||
t.Fatalf("failed to start minio: %s", string(out))
|
||||
}
|
||||
|
||||
for range time.Tick(time.Second) {
|
||||
out, err := exec.Command("docker", "inspect", "--format='{{json .State.Health}}'", name).CombinedOutput()
|
||||
if err != nil {
|
||||
t.Fatalf("failed to check minio status: %s", string(out))
|
||||
}
|
||||
if strings.Contains(string(out), `"Status":"healthy"`) {
|
||||
t.Log("minio is healthy")
|
||||
break
|
||||
}
|
||||
t.Log("waiting for minio to be healthy")
|
||||
}
|
||||
}
|
||||
|
||||
func stop(t *testing.T, name string) {
|
||||
if out, err := exec.Command("docker", "stop", name).CombinedOutput(); err != nil {
|
||||
t.Fatalf("failed to stop minio: %s", string(out))
|
||||
}
|
||||
}
|
4
internal/pipe/s3/testdata/config.ini
vendored
4
internal/pipe/s3/testdata/config.ini
vendored
@ -1,4 +0,0 @@
|
||||
[profile cloudformation@flowlab-dev]
|
||||
role_arn = arn:aws:iam::1111111111:role/CloudFormation
|
||||
source_profile = user
|
||||
mfa_serial = arn:aws:iam::1111111111:mfa/test
|
12
internal/pipe/s3/testdata/credentials.ini
vendored
12
internal/pipe/s3/testdata/credentials.ini
vendored
@ -1,12 +0,0 @@
|
||||
[default]
|
||||
aws_access_key_id = accessKey
|
||||
aws_secret_access_key = secret
|
||||
aws_session_token = token
|
||||
|
||||
[no_token]
|
||||
aws_access_key_id = accessKey
|
||||
aws_secret_access_key = secret
|
||||
|
||||
[user]
|
||||
aws_access_key_id = accesKey
|
||||
aws_secret_access_key = secret
|
@ -313,17 +313,6 @@ type Before struct {
|
||||
Hooks []string `yaml:",omitempty"`
|
||||
}
|
||||
|
||||
// S3 contains s3 config
|
||||
type S3 struct {
|
||||
Region string `yaml:",omitempty"`
|
||||
Bucket string `yaml:",omitempty"`
|
||||
Folder string `yaml:",omitempty"`
|
||||
Profile string `yaml:",omitempty"`
|
||||
Endpoint string `yaml:",omitempty"` // used for minio for example
|
||||
ACL string `yaml:",omitempty"`
|
||||
IDs []string `yaml:"ids,omitempty"`
|
||||
}
|
||||
|
||||
// Blob contains config for GO CDK blob
|
||||
type Blob struct {
|
||||
Bucket string `yaml:",omitempty"`
|
||||
@ -368,7 +357,6 @@ type Project struct {
|
||||
Artifactories []Upload `yaml:",omitempty"`
|
||||
Uploads []Upload `yaml:",omitempty"`
|
||||
Puts []Upload `yaml:",omitempty"` // TODO: remove this
|
||||
S3 []S3 `yaml:"s3,omitempty"`
|
||||
Blob []Blob `yaml:"blob,omitempty"` // TODO: remove this
|
||||
Blobs []Blob `yaml:"blobs,omitempty"`
|
||||
Changelog Changelog `yaml:",omitempty"`
|
||||
|
@ -16,7 +16,6 @@ import (
|
||||
"github.com/goreleaser/goreleaser/internal/pipe/nfpm"
|
||||
"github.com/goreleaser/goreleaser/internal/pipe/project"
|
||||
"github.com/goreleaser/goreleaser/internal/pipe/release"
|
||||
"github.com/goreleaser/goreleaser/internal/pipe/s3"
|
||||
"github.com/goreleaser/goreleaser/internal/pipe/scoop"
|
||||
"github.com/goreleaser/goreleaser/internal/pipe/sign"
|
||||
"github.com/goreleaser/goreleaser/internal/pipe/snapcraft"
|
||||
@ -48,7 +47,6 @@ var Defaulters = []Defaulter{
|
||||
sign.Pipe{},
|
||||
docker.Pipe{},
|
||||
artifactory.Pipe{},
|
||||
s3.Pipe{},
|
||||
blob.Pipe{},
|
||||
brew.Pipe{},
|
||||
scoop.Pipe{},
|
||||
|
@ -84,3 +84,13 @@ GCS provider uses [Application Default Credentials](https://cloud.google.com/doc
|
||||
- Environment Variable (GOOGLE_APPLICATION_CREDENTIALS)
|
||||
- Default Service Account from the compute instance(Compute Engine, Kubernetes Engine, Cloud function etc).
|
||||
|
||||
### ACLs
|
||||
|
||||
There is no common way to set ACLs across all bucket providers, so, [go-cloud][]
|
||||
[does not support it yet][issue1108].
|
||||
|
||||
You are expected to set the ACLs on the bucket/folder/etc, depending on your
|
||||
provider.
|
||||
|
||||
[go-cloud]: https://gocloud.dev/howto/blob/
|
||||
[issue1108]: https://github.com/google/go-cloud/issues/1108
|
||||
|
@ -151,9 +151,13 @@ brews:
|
||||
# etc
|
||||
```
|
||||
|
||||
## Expired deprecation notices
|
||||
|
||||
The following options were deprecated for ~6 months and are now fully removed.
|
||||
|
||||
### s3
|
||||
|
||||
> since 2019-06-09
|
||||
> since 2019-06-09, removed 2020-01-07
|
||||
|
||||
S3 was deprecated in favor of the new `blob`, which supports S3, Azure Blob and
|
||||
GCS.
|
||||
@ -175,9 +179,7 @@ blobs:
|
||||
# etc
|
||||
```
|
||||
|
||||
## Expired deprecation notices
|
||||
|
||||
The following options were deprecated for ~6 months and are now fully removed.
|
||||
ACLs should be set on the bucket, the `acl` option does not exist anymore.
|
||||
|
||||
### archive
|
||||
|
||||
|
@ -1,87 +0,0 @@
|
||||
---
|
||||
title: S3
|
||||
series: customization
|
||||
hideFromIndex: true
|
||||
weight: 115
|
||||
---
|
||||
|
||||
Since [v0.74.0](https://github.com/goreleaser/goreleaser/releases/tag/v0.74.0),
|
||||
GoReleaser supports pushing artifacts to Amazon S3 and other API-compatible
|
||||
object storages ([minio][] for example).
|
||||
|
||||
[minio]: https://www.minio.io
|
||||
|
||||
Right now, the implementation is quite simple and probably won't cover all
|
||||
use cases. If you need one of such use cases, please open an issue/pull request.
|
||||
|
||||
Here is what you can customize:
|
||||
|
||||
## Customization
|
||||
|
||||
```yaml
|
||||
# .goreleaser.yml
|
||||
s3:
|
||||
# You can have multiple s3 configs
|
||||
-
|
||||
# Template for the bucket name(without the s3:// prefix)
|
||||
# Default is empty.
|
||||
bucket: my-bucket
|
||||
|
||||
# IDs of the artifacts you want to upload.
|
||||
ids:
|
||||
- foo
|
||||
- bar
|
||||
|
||||
# AWS Region to use.
|
||||
# Defaults is us-east-1
|
||||
region: us-east-1
|
||||
|
||||
# Template for the path/name inside the bucket.
|
||||
# Default is `{{ .ProjectName }}/{{ .Tag }}`
|
||||
folder: "foo/bar/{{.Version}}"
|
||||
|
||||
# Set a custom profile to use for this s3 config. If you have multiple
|
||||
# profiles setup in you ~/.aws config, this shall help defining which
|
||||
# profile to use in which s3 bucket.
|
||||
# Default is empty.
|
||||
profile: my-profile
|
||||
|
||||
# Endpoint allows you to set a custom endpoint, which is useful if you
|
||||
# want to push your artifacts to a minio server for example.
|
||||
# Default is AWS S3 URL.
|
||||
endpoint: "http://minio.foo.com"
|
||||
|
||||
# Sets the ACL of the object using the specified canned ACL.
|
||||
# Default is private.
|
||||
acl: public-read
|
||||
```
|
||||
|
||||
> Learn more about the [name template engine](/templates).
|
||||
> Learn more about the [acl](https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectPUTacl.html).
|
||||
|
||||
## Authentication
|
||||
|
||||
GoReleaser will authenticate using the [same methods defined by aws-cli][auth].
|
||||
You can read the [docs][auth] to find out more about it.
|
||||
|
||||
Currently it supports authentication with:
|
||||
|
||||
- An [EnvProvider][EnvProvider] which retrieves credentials from the environment
|
||||
variables of the running process. Environment credentials never expire.
|
||||
Environment variables used:
|
||||
- Access Key ID: `AWS_ACCESS_KEY_ID` or `AWS_ACCESS_KEY`
|
||||
- Secret Access Key: `AWS_SECRET_ACCESS_KEY` or `AWS_SECRET_KEY`
|
||||
- A [SharedCredentialsProvider][SharedCredentialsProvider] which retrieves
|
||||
credentials from the current user's home directory, and keeps track if those
|
||||
credentials are expired. Profile ini file example: `$HOME/.aws/credentials`
|
||||
- A AssumeRoleTokenProvider with enabled SharedConfigState which uses MFA
|
||||
prompting for token code on stdin. Go to [session doc][session] for more
|
||||
details.
|
||||
|
||||
You can also set different profile names for each S3 config, so you may be able
|
||||
to push to buckets in different accounts, for example.
|
||||
|
||||
[auth]: https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html
|
||||
[envProvider]: https://docs.aws.amazon.com/sdk-for-go/api/aws/credentials/#EnvProvider
|
||||
[sharedCredentialsProvider]: https://docs.aws.amazon.com/sdk-for-go/api/aws/credentials/#SharedCredentialsProvider
|
||||
[session]: https://docs.aws.amazon.com/sdk-for-go/api/aws/session/
|
Loading…
x
Reference in New Issue
Block a user