github.com/szyn/goreleaser@v0.76.1-0.20180517112710-333da09a1297/pipeline/s3/s3.go (about)

     1  // Package s3 provides a Pipe that push artifacts to s3/minio
     2  package s3
     3  
     4  import (
     5  	"os"
     6  	"path/filepath"
     7  
     8  	"github.com/apex/log"
     9  	"github.com/aws/aws-sdk-go/aws"
    10  	"github.com/aws/aws-sdk-go/aws/credentials"
    11  	"github.com/aws/aws-sdk-go/aws/session"
    12  	"github.com/aws/aws-sdk-go/service/s3"
    13  	"github.com/goreleaser/goreleaser/config"
    14  	"github.com/goreleaser/goreleaser/context"
    15  	"github.com/goreleaser/goreleaser/internal/artifact"
    16  	"github.com/goreleaser/goreleaser/internal/nametemplate"
    17  	"golang.org/x/sync/errgroup"
    18  )
    19  
    20  // Pipe for Artifactory
    21  type Pipe struct{}
    22  
    23  // String returns the description of the pipe
    24  func (Pipe) String() string {
    25  	return "releasing to s3"
    26  }
    27  
    28  // Default sets the pipe defaults
    29  func (Pipe) Default(ctx *context.Context) error {
    30  	for i := range ctx.Config.S3 {
    31  		s3 := &ctx.Config.S3[i]
    32  		if s3.Bucket == "" {
    33  			continue
    34  		}
    35  		if s3.Folder == "" {
    36  			s3.Folder = "{{ .ProjectName }}/{{ .Tag }}"
    37  		}
    38  		if s3.Region == "" {
    39  			s3.Region = "us-east-1"
    40  		}
    41  	}
    42  	return nil
    43  }
    44  
    45  // Run the pipe
    46  func (Pipe) Run(ctx *context.Context) error {
    47  	var g errgroup.Group
    48  	sem := make(chan bool, ctx.Parallelism)
    49  	for _, conf := range ctx.Config.S3 {
    50  		conf := conf
    51  		sem <- true
    52  		g.Go(func() error {
    53  			defer func() {
    54  				<-sem
    55  			}()
    56  			return upload(ctx, conf)
    57  		})
    58  	}
    59  	return g.Wait()
    60  }
    61  
    62  func upload(ctx *context.Context, conf config.S3) error {
    63  	var awsConfig = aws.NewConfig()
    64  	// TODO: add a test for this
    65  	if conf.Endpoint != "" {
    66  		awsConfig.Endpoint = aws.String(conf.Endpoint)
    67  		awsConfig.S3ForcePathStyle = aws.Bool(true)
    68  	}
    69  	// TODO: add a test for this
    70  	if conf.Profile != "" {
    71  		awsConfig.Credentials = credentials.NewSharedCredentials("", conf.Profile)
    72  	}
    73  	sess := session.Must(session.NewSession(awsConfig))
    74  	svc := s3.New(sess, &aws.Config{
    75  		Region: aws.String(conf.Region),
    76  	})
    77  	folder, err := nametemplate.Apply(ctx, conf.Folder)
    78  	if err != nil {
    79  		return err
    80  	}
    81  
    82  	var g errgroup.Group
    83  	sem := make(chan bool, ctx.Parallelism)
    84  	for _, artifact := range ctx.Artifacts.Filter(
    85  		artifact.Or(
    86  			artifact.ByType(artifact.UploadableArchive),
    87  			artifact.ByType(artifact.UploadableBinary),
    88  			artifact.ByType(artifact.Checksum),
    89  			artifact.ByType(artifact.Signature),
    90  			artifact.ByType(artifact.LinuxPackage),
    91  		),
    92  	).List() {
    93  		sem <- true
    94  		artifact := artifact
    95  		g.Go(func() error {
    96  			defer func() {
    97  				<-sem
    98  			}()
    99  			f, err := os.Open(artifact.Path)
   100  			if err != nil {
   101  				return err
   102  			}
   103  			log.WithFields(log.Fields{
   104  				"bucket":   conf.Bucket,
   105  				"folder":   folder,
   106  				"artifact": artifact.Name,
   107  			}).Info("uploading")
   108  			_, err = svc.PutObjectWithContext(ctx, &s3.PutObjectInput{
   109  				Bucket: aws.String(conf.Bucket),
   110  				Key:    aws.String(filepath.Join(folder, artifact.Name)),
   111  				Body:   f,
   112  			})
   113  			return err
   114  		})
   115  	}
   116  	return g.Wait()
   117  }