2019-07-14 14:55:34 -08:00
|
|
|
package cicd
|
|
|
|
|
|
|
|
import (
|
2019-08-06 12:01:43 -08:00
|
|
|
"bufio"
|
|
|
|
"crypto/md5"
|
2019-07-14 14:55:34 -08:00
|
|
|
"encoding/base64"
|
2019-08-06 12:01:43 -08:00
|
|
|
"fmt"
|
|
|
|
"io/ioutil"
|
2019-07-14 14:55:34 -08:00
|
|
|
"log"
|
2019-08-06 12:01:43 -08:00
|
|
|
"os"
|
2019-07-14 14:55:34 -08:00
|
|
|
"path/filepath"
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
"geeks-accelerator/oss/saas-starter-kit/internal/platform/tests"
|
|
|
|
"github.com/aws/aws-sdk-go/aws"
|
|
|
|
"github.com/aws/aws-sdk-go/aws/awserr"
|
|
|
|
"github.com/aws/aws-sdk-go/service/ecr"
|
2019-08-08 01:12:04 -08:00
|
|
|
"github.com/aws/aws-sdk-go/service/s3/s3manager"
|
|
|
|
"github.com/pborman/uuid"
|
2019-07-14 14:55:34 -08:00
|
|
|
"github.com/pkg/errors"
|
|
|
|
"gopkg.in/go-playground/validator.v9"
|
|
|
|
)
|
|
|
|
|
|
|
|
// ServiceBuildFlags defines the flags used for executing a service build.
|
|
|
|
type ServiceBuildFlags struct {
|
|
|
|
// Required flags.
|
|
|
|
ServiceName string `validate:"required" example:"web-api"`
|
|
|
|
Env string `validate:"oneof=dev stage prod" example:"dev"`
|
|
|
|
|
|
|
|
// Optional flags.
|
2019-08-08 01:12:04 -08:00
|
|
|
ProjectRoot string `validate:"omitempty" example:"."`
|
|
|
|
ProjectName string ` validate:"omitempty" example:"example-project"`
|
|
|
|
DockerFile string `validate:"omitempty" example:"./cmd/web-api/Dockerfile"`
|
|
|
|
CommitRef string `validate:"omitempty" example:"master@1ecfd275"`
|
|
|
|
S3BucketPrivateName string `validate:"omitempty" example:"saas-example-project-private"`
|
|
|
|
BuildDir string `validate:"omitempty" example:"."`
|
|
|
|
NoCache bool `validate:"omitempty" example:"false"`
|
|
|
|
NoPush bool `validate:"omitempty" example:"false"`
|
|
|
|
IsLambda bool `validate:"omitempty" example:"false"`
|
2019-07-14 14:55:34 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// serviceBuildRequest defines the details needed to execute a service build.
|
|
|
|
type serviceBuildRequest struct {
|
|
|
|
*serviceRequest
|
|
|
|
|
|
|
|
EcrRepositoryName string `validate:"required"`
|
|
|
|
EcrRepository *ecr.CreateRepositoryInput
|
|
|
|
EcrRepositoryMaxImages int `validate:"omitempty"`
|
|
|
|
|
2019-08-08 01:12:04 -08:00
|
|
|
BuildDir string `validate:"omitempty" example:""`
|
|
|
|
CommitRef string `validate:"omitempty"`
|
|
|
|
S3BucketPrivateName string `validate:"omitempty"`
|
|
|
|
NoCache bool `validate:"omitempty"`
|
|
|
|
NoPush bool `validate:"omitempty"`
|
|
|
|
IsLambda bool `validate:"omitempty"`
|
2019-07-14 14:55:34 -08:00
|
|
|
|
|
|
|
flags ServiceBuildFlags
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewServiceBuildRequest generates a new request for executing build of a single service for a given set of CLI flags.
|
|
|
|
func NewServiceBuildRequest(log *log.Logger, flags ServiceBuildFlags) (*serviceBuildRequest, error) {
|
|
|
|
|
|
|
|
// Validates specified CLI flags map to struct successfully.
|
|
|
|
log.Println("Validate flags.")
|
|
|
|
{
|
|
|
|
errs := validator.New().Struct(flags)
|
|
|
|
if errs != nil {
|
|
|
|
return nil, errs
|
|
|
|
}
|
|
|
|
log.Printf("\t%s\tFlags ok.", tests.Success)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Generate a deploy request using CLI flags and AWS credentials.
|
|
|
|
log.Println("Generate deploy request.")
|
|
|
|
var req serviceBuildRequest
|
|
|
|
{
|
2019-07-14 15:33:23 -08:00
|
|
|
// Define new service request.
|
|
|
|
sr := &serviceRequest{
|
|
|
|
ServiceName: flags.ServiceName,
|
|
|
|
Env: flags.Env,
|
|
|
|
ProjectRoot: flags.ProjectRoot,
|
|
|
|
ProjectName: flags.ProjectName,
|
|
|
|
DockerFile: flags.DockerFile,
|
|
|
|
}
|
|
|
|
if err := sr.init(log); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2019-07-14 14:55:34 -08:00
|
|
|
req = serviceBuildRequest{
|
|
|
|
serviceRequest: sr,
|
|
|
|
|
2019-08-08 01:12:04 -08:00
|
|
|
CommitRef: flags.CommitRef,
|
|
|
|
S3BucketPrivateName: flags.S3BucketPrivateName,
|
|
|
|
BuildDir: flags.BuildDir,
|
|
|
|
NoCache: flags.NoCache,
|
|
|
|
NoPush: flags.NoPush,
|
|
|
|
IsLambda: flags.IsLambda,
|
2019-07-14 14:55:34 -08:00
|
|
|
|
|
|
|
flags: flags,
|
|
|
|
}
|
|
|
|
|
2019-08-08 01:12:04 -08:00
|
|
|
if req.BuildDir == "" {
|
|
|
|
req.BuildDir = req.ProjectRoot
|
|
|
|
}
|
|
|
|
|
2019-07-14 14:55:34 -08:00
|
|
|
// Set default AWS ECR Repository Name.
|
|
|
|
req.EcrRepositoryName = ecrRepositoryName(req.ProjectName)
|
|
|
|
req.EcrRepository = &ecr.CreateRepositoryInput{
|
|
|
|
RepositoryName: aws.String(req.EcrRepositoryName),
|
|
|
|
Tags: []*ecr.Tag{
|
|
|
|
&ecr.Tag{Key: aws.String(awsTagNameProject), Value: aws.String(req.ProjectName)},
|
|
|
|
&ecr.Tag{Key: aws.String(awsTagNameEnv), Value: aws.String(req.Env)},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
log.Printf("\t\t\tSet ECR Repository Name to '%s'.", req.EcrRepositoryName)
|
|
|
|
|
|
|
|
// Set default AWS ECR Regsistry Max Images.
|
|
|
|
req.EcrRepositoryMaxImages = defaultAwsRegistryMaxImages
|
|
|
|
log.Printf("\t\t\tSet ECR Regsistry Max Images to '%d'.", req.EcrRepositoryMaxImages)
|
|
|
|
|
2019-08-07 17:49:21 -08:00
|
|
|
// Get the default commit ref.
|
|
|
|
if req.CommitRef == "" {
|
|
|
|
if ev := os.Getenv("CI_COMMIT_TAG"); ev != "" {
|
|
|
|
req.CommitRef = "tag-" + ev
|
|
|
|
} else if ev := os.Getenv("CI_COMMIT_REF_NAME"); ev != "" {
|
|
|
|
req.CommitRef = "branch-" + ev
|
|
|
|
}
|
|
|
|
|
|
|
|
if ev := os.Getenv("CI_COMMIT_SHORT_SHA"); ev != "" {
|
|
|
|
req.CommitRef = req.CommitRef + "@" + ev
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-14 14:55:34 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
return &req, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Run is the main entrypoint for building a service for a given target environment.
|
|
|
|
func ServiceBuild(log *log.Logger, req *serviceBuildRequest) error {
|
|
|
|
|
|
|
|
// Load the AWS ECR repository. Try to find by name else create new one.
|
|
|
|
var dockerLoginCmd []string
|
|
|
|
{
|
|
|
|
log.Println("ECR - Get or create repository.")
|
|
|
|
|
|
|
|
svc := ecr.New(req.awsSession())
|
|
|
|
|
|
|
|
// First try to find ECR repository by name.
|
|
|
|
var awsRepo *ecr.Repository
|
|
|
|
descRes, err := svc.DescribeRepositories(&ecr.DescribeRepositoriesInput{
|
|
|
|
RepositoryNames: []*string{aws.String(req.EcrRepositoryName)},
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
if aerr, ok := err.(awserr.Error); !ok || aerr.Code() != ecr.ErrCodeRepositoryNotFoundException {
|
|
|
|
return errors.Wrapf(err, "failed to describe repository '%s'", req.EcrRepositoryName)
|
|
|
|
}
|
|
|
|
} else if len(descRes.Repositories) > 0 {
|
|
|
|
awsRepo = descRes.Repositories[0]
|
|
|
|
}
|
|
|
|
|
|
|
|
if awsRepo == nil {
|
|
|
|
// If no repository was found, create one.
|
|
|
|
createRes, err := svc.CreateRepository(req.EcrRepository)
|
|
|
|
if err != nil {
|
|
|
|
return errors.Wrapf(err, "failed to create repository '%s'", req.EcrRepositoryName)
|
|
|
|
}
|
|
|
|
awsRepo = createRes.Repository
|
|
|
|
log.Printf("\t\tCreated: %s.", *awsRepo.RepositoryArn)
|
|
|
|
} else {
|
|
|
|
log.Printf("\t\tFound: %s.", *awsRepo.RepositoryArn)
|
|
|
|
|
|
|
|
log.Println("\t\tChecking old ECR images.")
|
|
|
|
delIds, err := EcrPurgeImages(req)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Since ECR has max number of repository images, need to delete old ones so can stay under limit.
|
|
|
|
// If there are image IDs to delete, delete them.
|
|
|
|
if len(delIds) > 0 {
|
|
|
|
log.Printf("\t\tDeleted %d images that exceeded limit of %d", len(delIds), req.EcrRepositoryMaxImages)
|
|
|
|
for _, imgId := range delIds {
|
|
|
|
log.Printf("\t\t\t%s", *imgId.ImageTag)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
req.ReleaseImage = releaseImage(req.Env, req.ServiceName, *awsRepo.RepositoryUri)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
log.Printf("\t\trelease image: %s", req.ReleaseImage)
|
|
|
|
log.Printf("\t%s\tRelease image valid.", tests.Success)
|
|
|
|
|
|
|
|
log.Println("ECR - Retrieve authorization token used for docker login.")
|
|
|
|
|
|
|
|
// Get the credentials necessary for logging into the AWS Elastic Container Registry
|
|
|
|
// made available with the AWS access key and AWS secret access keys.
|
|
|
|
res, err := svc.GetAuthorizationToken(&ecr.GetAuthorizationTokenInput{})
|
|
|
|
if err != nil {
|
|
|
|
return errors.Wrap(err, "failed to get ecr authorization token")
|
|
|
|
}
|
|
|
|
|
|
|
|
authToken, err := base64.StdEncoding.DecodeString(*res.AuthorizationData[0].AuthorizationToken)
|
|
|
|
if err != nil {
|
|
|
|
return errors.Wrap(err, "failed to base64 decode ecr authorization token")
|
|
|
|
}
|
|
|
|
pts := strings.Split(string(authToken), ":")
|
|
|
|
user := pts[0]
|
|
|
|
pass := pts[1]
|
|
|
|
|
|
|
|
dockerLoginCmd = []string{
|
|
|
|
"docker",
|
|
|
|
"login",
|
|
|
|
"-u", user,
|
|
|
|
"-p", pass,
|
|
|
|
*res.AuthorizationData[0].ProxyEndpoint,
|
|
|
|
}
|
|
|
|
|
|
|
|
log.Printf("\t%s\tdocker login ok.", tests.Success)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Once we can access the repository in ECR, do the docker build.
|
|
|
|
{
|
2019-08-06 12:01:43 -08:00
|
|
|
log.Printf("Starting docker build %s\n", req.ReleaseImage)
|
2019-08-08 01:12:04 -08:00
|
|
|
|
|
|
|
var dockerFile string
|
|
|
|
dockerPath := filepath.Join(req.BuildDir, req.DockerFile)
|
|
|
|
if _, err := os.Stat(dockerPath); err == nil {
|
|
|
|
dockerFile = req.DockerFile
|
|
|
|
} else {
|
|
|
|
dockerPath = req.DockerFile
|
|
|
|
|
|
|
|
dockerFile, err = filepath.Rel(req.BuildDir, dockerPath)
|
|
|
|
if err != nil {
|
|
|
|
return errors.Wrapf(err, "Failed parse relative path for %s from %s", dockerPath, req.BuildDir)
|
|
|
|
}
|
2019-07-14 14:55:34 -08:00
|
|
|
}
|
|
|
|
|
2019-08-06 12:29:00 -08:00
|
|
|
// Name of the first build stage declared in the docckerFile.
|
|
|
|
var buildStageName string
|
|
|
|
|
2019-08-06 12:01:43 -08:00
|
|
|
// When the dockerFile is multistage, caching can be applied. Scan the dockerFile for the first stage.
|
|
|
|
// FROM golang:1.12.6-alpine3.9 AS build_base
|
|
|
|
var buildBaseImageTag string
|
|
|
|
{
|
2019-08-08 01:12:04 -08:00
|
|
|
file, err := os.Open(dockerPath)
|
2019-08-06 12:01:43 -08:00
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
defer file.Close()
|
|
|
|
|
|
|
|
// List of lines in the dockerfile for the first stage. This will be used to tag the image to help ensure
|
|
|
|
// any changes to the lines associated with the first stage force cache to be reset.
|
|
|
|
var stageLines []string
|
|
|
|
|
|
|
|
// Loop through all the lines in the Dockerfile searching for the lines associated with the first build stage.
|
|
|
|
scanner := bufio.NewScanner(file)
|
|
|
|
for scanner.Scan() {
|
|
|
|
line := scanner.Text()
|
|
|
|
|
|
|
|
lineLower := strings.ToLower(line)
|
|
|
|
|
|
|
|
if strings.HasPrefix(lineLower, "from ") {
|
|
|
|
if buildStageName != "" {
|
|
|
|
// Only need to scan all the lines for the first build stage. Break when reach next FROM.
|
|
|
|
break
|
|
|
|
} else if !strings.Contains(lineLower, " as ") {
|
|
|
|
// Caching is only supported if the first FROM has a name.
|
|
|
|
log.Printf("\t\t\tSkipping stage cache, build stage not detected.\n")
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
buildStageName = strings.TrimSpace(strings.Split(lineLower, " as ")[1])
|
2019-08-06 17:04:37 -08:00
|
|
|
stageLines = append(stageLines, line)
|
2019-08-06 12:01:43 -08:00
|
|
|
} else if buildStageName != "" {
|
2019-08-06 17:04:37 -08:00
|
|
|
stageLines = append(stageLines, line)
|
2019-08-06 12:01:43 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := scanner.Err(); err != nil {
|
|
|
|
return errors.WithStack(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we have detected a build stage, then generate the appropriate tag.
|
|
|
|
if buildStageName != "" {
|
|
|
|
log.Printf("\t\tFound build stage %s for caching.\n", buildStageName)
|
|
|
|
|
|
|
|
// Generate a checksum for the lines associated with the build stage.
|
2019-08-06 12:19:18 -08:00
|
|
|
buildBaseHashPts := []string{
|
|
|
|
fmt.Sprintf("%x", md5.Sum([]byte(strings.Join(stageLines, "\n")))),
|
|
|
|
}
|
2019-08-06 12:01:43 -08:00
|
|
|
|
2019-08-06 12:19:18 -08:00
|
|
|
switch buildStageName {
|
|
|
|
case "build_base_golang":
|
|
|
|
// Compute the checksum for the go.mod file.
|
|
|
|
goSumPath := filepath.Join(req.ProjectRoot, "go.sum")
|
|
|
|
goSumDat, err := ioutil.ReadFile(goSumPath)
|
|
|
|
if err != nil {
|
|
|
|
return errors.Wrapf(err, "Failed parse relative path for %s from %s", req.DockerFile, req.ProjectRoot)
|
|
|
|
}
|
|
|
|
buildBaseHashPts = append(buildBaseHashPts, fmt.Sprintf("%x", md5.Sum(goSumDat)))
|
2019-08-06 12:01:43 -08:00
|
|
|
}
|
|
|
|
|
2019-08-06 12:19:18 -08:00
|
|
|
// Combine all the checksums to be used to tag the target build stage.
|
|
|
|
buildBaseHash := fmt.Sprintf("%x", md5.Sum([]byte(strings.Join(buildBaseHashPts, "|"))))
|
2019-08-06 12:01:43 -08:00
|
|
|
|
2019-08-06 12:19:18 -08:00
|
|
|
// New stage image tag.
|
2019-08-06 12:01:43 -08:00
|
|
|
buildBaseImageTag = buildStageName + "-" + buildBaseHash[0:8]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
var cmds [][]string
|
|
|
|
|
|
|
|
// Enabling caching of the first build stage defined in the dockerFile.
|
|
|
|
var buildBaseImage string
|
|
|
|
if !req.NoCache && buildBaseImageTag != "" {
|
|
|
|
var pushTargetImg bool
|
|
|
|
if ciReg := os.Getenv("CI_REGISTRY"); ciReg != "" {
|
2019-08-06 12:10:47 -08:00
|
|
|
cmds = append(cmds, []string{
|
|
|
|
"docker", "login",
|
|
|
|
"-u", os.Getenv("CI_REGISTRY_USER"),
|
|
|
|
"-p", os.Getenv("CI_REGISTRY_PASSWORD"),
|
|
|
|
ciReg})
|
2019-08-06 12:01:43 -08:00
|
|
|
|
2019-08-06 12:19:18 -08:00
|
|
|
buildBaseImage = os.Getenv("CI_REGISTRY_IMAGE") + ":" + buildBaseImageTag
|
2019-08-06 12:01:43 -08:00
|
|
|
pushTargetImg = true
|
|
|
|
} else {
|
2019-08-06 17:04:37 -08:00
|
|
|
buildBaseImage = req.ProjectName + ":" + req.Env + "-" + req.ServiceName + "-" + buildBaseImageTag
|
2019-08-06 12:01:43 -08:00
|
|
|
}
|
|
|
|
|
2019-08-06 19:40:11 -08:00
|
|
|
cmds = append(cmds, []string{"docker", "pull", buildBaseImage})
|
2019-08-06 12:01:43 -08:00
|
|
|
|
|
|
|
cmds = append(cmds, []string{
|
|
|
|
"docker", "build",
|
|
|
|
"--file=" + dockerFile,
|
2019-08-06 18:38:45 -08:00
|
|
|
"--cache-from", buildBaseImage,
|
2019-08-06 12:01:43 -08:00
|
|
|
"--build-arg", "service=" + req.ServiceName,
|
|
|
|
"--build-arg", "env=" + req.Env,
|
2019-08-06 12:37:19 -08:00
|
|
|
"-t", buildBaseImage,
|
2019-08-06 12:29:00 -08:00
|
|
|
"--target", buildStageName,
|
2019-08-06 12:01:43 -08:00
|
|
|
".",
|
|
|
|
})
|
|
|
|
|
|
|
|
if pushTargetImg {
|
2019-08-06 12:37:19 -08:00
|
|
|
cmds = append(cmds, []string{"docker", "push", buildBaseImage})
|
2019-08-06 12:01:43 -08:00
|
|
|
}
|
|
|
|
}
|
2019-08-06 12:10:47 -08:00
|
|
|
|
2019-07-14 14:55:34 -08:00
|
|
|
// The initial build command slice.
|
|
|
|
buildCmd := []string{
|
|
|
|
"docker", "build",
|
|
|
|
"--file=" + dockerFile,
|
|
|
|
"--build-arg", "service=" + req.ServiceName,
|
|
|
|
"--build-arg", "env=" + req.Env,
|
2019-08-07 17:49:21 -08:00
|
|
|
"--build-arg", "commit_ref=" + req.CommitRef,
|
2019-08-07 20:19:09 -08:00
|
|
|
"--build-arg", "swagInit=1",
|
2019-07-14 14:55:34 -08:00
|
|
|
"-t", req.ReleaseImage,
|
|
|
|
}
|
|
|
|
|
|
|
|
// Append additional build flags.
|
|
|
|
if req.NoCache {
|
|
|
|
buildCmd = append(buildCmd, "--no-cache")
|
2019-08-06 12:01:43 -08:00
|
|
|
} else if buildBaseImage != "" {
|
|
|
|
buildCmd = append(buildCmd, "--cache-from", buildBaseImage)
|
2019-07-14 14:55:34 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Finally append the build context as the current directory since os.Exec will use the project root as
|
|
|
|
// the working directory.
|
|
|
|
buildCmd = append(buildCmd, ".")
|
|
|
|
|
2019-08-06 12:01:43 -08:00
|
|
|
cmds = append(cmds, buildCmd)
|
2019-07-14 14:55:34 -08:00
|
|
|
|
2019-08-08 01:12:04 -08:00
|
|
|
s3Files := make(map[string]*s3manager.UploadInput)
|
2019-07-14 14:55:34 -08:00
|
|
|
if req.NoPush == false {
|
2019-08-08 01:12:04 -08:00
|
|
|
if req.IsLambda {
|
|
|
|
|
|
|
|
lambdaS3Key := LambdaS3KeyFromReleaseImage(req.ReleaseImage)
|
|
|
|
|
|
|
|
tmpDir := os.TempDir()
|
|
|
|
lambdaZip := filepath.Join(tmpDir, filepath.Base(lambdaS3Key))
|
|
|
|
|
|
|
|
containerName := uuid.NewRandom().String()
|
|
|
|
|
|
|
|
cmds = append(cmds, []string{"docker", "create", "-ti", "--name", containerName, req.ReleaseImage, "bash"})
|
|
|
|
cmds = append(cmds, []string{"docker", "cp", containerName + ":/var/task", tmpDir})
|
|
|
|
cmds = append(cmds, []string{"docker", "rm", containerName})
|
|
|
|
cmds = append(cmds, []string{"cd", tmpDir + "/task"})
|
|
|
|
cmds = append(cmds, []string{"zip", "-r", lambdaZip, "."})
|
|
|
|
|
|
|
|
s3Files[lambdaZip] = &s3manager.UploadInput{
|
|
|
|
Bucket: &req.S3BucketPrivateName,
|
|
|
|
Key: &lambdaS3Key,
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
cmds = append(cmds, dockerLoginCmd)
|
|
|
|
cmds = append(cmds, []string{"docker", "push", req.ReleaseImage})
|
|
|
|
}
|
2019-08-06 12:01:43 -08:00
|
|
|
}
|
2019-07-14 14:55:34 -08:00
|
|
|
|
2019-08-06 12:01:43 -08:00
|
|
|
for _, cmd := range cmds {
|
2019-08-06 19:40:11 -08:00
|
|
|
var logCmd string
|
|
|
|
if len(cmd) >= 2 && cmd[1] == "login" {
|
|
|
|
logCmd = strings.Join(cmd[0:2], " ")
|
|
|
|
} else {
|
|
|
|
logCmd = strings.Join(cmd, " ")
|
|
|
|
}
|
|
|
|
|
|
|
|
log.Printf("\t\t%s\n", logCmd)
|
2019-07-14 14:55:34 -08:00
|
|
|
|
2019-08-08 01:12:04 -08:00
|
|
|
err := execCmds(log, req.BuildDir, cmd)
|
2019-07-14 14:55:34 -08:00
|
|
|
if err != nil {
|
2019-08-06 12:01:43 -08:00
|
|
|
if len(cmd) > 2 && cmd[1] == "pull" {
|
2019-08-06 17:04:37 -08:00
|
|
|
log.Printf("\t\t\tSkipping pull - %s\n", err.Error())
|
2019-08-06 12:01:43 -08:00
|
|
|
} else {
|
|
|
|
return errors.Wrapf(err, "Failed to exec %s", strings.Join(cmd, " "))
|
|
|
|
}
|
2019-07-14 14:55:34 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-08 01:12:04 -08:00
|
|
|
if s3Files != nil && len(s3Files) > 0 {
|
|
|
|
// Create an uploader with the session and default options
|
|
|
|
uploader := s3manager.NewUploader(req.awsSession())
|
|
|
|
|
|
|
|
// Perform an upload.
|
|
|
|
for lf, upParams := range s3Files {
|
|
|
|
f, err := os.Open(lf)
|
|
|
|
if err != nil {
|
|
|
|
return errors.Wrapf(err, "Failed open file to %s", lf)
|
|
|
|
}
|
|
|
|
upParams.Body = f
|
|
|
|
|
|
|
|
_, err = uploader.Upload(upParams)
|
|
|
|
if err != nil {
|
|
|
|
return errors.Wrapf(err, "Failed upload file to %s", *upParams.Key)
|
|
|
|
}
|
|
|
|
|
|
|
|
log.Printf("\t\tUploaded %s to s3://%s/%s\n", lf, *upParams.Bucket, *upParams.Key)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-14 14:55:34 -08:00
|
|
|
log.Printf("\t%s\tbuild complete.\n", tests.Success)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|