mirror of
https://github.com/raseels-repos/golang-saas-starter-kit.git
synced 2025-06-08 23:56:37 +02:00
214 lines
6.2 KiB
Go
214 lines
6.2 KiB
Go
package devops
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"geeks-accelerator/oss/saas-starter-kit/example-project/internal/platform/tests"
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
// requiredCmdsBuild proves a list of required executables for completing build.
|
|
var requiredCmdsBuild = [][]string{
|
|
[]string{"docker", "version", "-f", "{{.Client.Version}}"},
|
|
}
|
|
|
|
// Run is the main entrypoint for building a service for a given target env.
|
|
func ServiceBuild(log *log.Logger, projectRoot, targetService, targetEnv, releaseImage string, noPush, noCache bool) error {
|
|
|
|
log.SetPrefix(log.Prefix() + " build : ")
|
|
|
|
//
|
|
log.Println("Verify required commands are installed.")
|
|
for _, cmdVals := range requiredCmdsBuild {
|
|
cmd := exec.Command(cmdVals[0], cmdVals[1:]...)
|
|
cmd.Env = os.Environ()
|
|
|
|
out, err := cmd.CombinedOutput()
|
|
if err != nil {
|
|
return errors.WithMessagef(err, "failed to execute %s - %s\n%s", strings.Join(cmdVals, " "), string(out))
|
|
}
|
|
|
|
log.Printf("\t%s\t%s - %s", tests.Success, cmdVals[0], string(out))
|
|
}
|
|
|
|
// When project root directory is empty or set to current working path, then search for the project root by locating
|
|
// the go.mod file.
|
|
var goModFile string
|
|
if projectRoot == "" || projectRoot == "." {
|
|
log.Println("Attempting to location project root directory from current working directory.")
|
|
|
|
var err error
|
|
goModFile, err = findProjectGoModFile()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
projectRoot = filepath.Dir(goModFile)
|
|
} else {
|
|
log.Println("Using supplied project root directory.")
|
|
goModFile = filepath.Join(projectRoot, "go.mod")
|
|
}
|
|
|
|
log.Printf("\t\tproject root: %s", projectRoot)
|
|
log.Printf("\t\tgo.mod: %s", goModFile)
|
|
log.Printf("\t%s\tFound project root directory.", tests.Success)
|
|
|
|
log.Println("Extracting go module name from go.mod.")
|
|
modName, err := loadGoModName(goModFile)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
log.Printf("\t\tmodule name: %s", modName)
|
|
log.Printf("\t%s\tgo module name.", tests.Success)
|
|
|
|
log.Println("Determining the project name.")
|
|
projectName := getTargetEnv(targetEnv, "PROJECT_NAME")
|
|
if projectName != "" {
|
|
log.Printf("\t\tproject name: %s", projectName)
|
|
log.Printf("\t%s\tFound env variable.", tests.Success)
|
|
} else {
|
|
projectName = filepath.Base(modName)
|
|
log.Printf("\t\tproject name: %s", projectName)
|
|
log.Printf("\t%s\tSet from go module.", tests.Success)
|
|
}
|
|
|
|
log.Println("Attempting to locate service directory from project root directory.")
|
|
dockerFile, err := findServiceDockerFile(projectRoot, targetService)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
serviceDir := filepath.Dir(dockerFile)
|
|
|
|
log.Printf("\t\tservice directory: %s", serviceDir)
|
|
log.Printf("\t\tdockerfile: %s", dockerFile)
|
|
log.Printf("\t%s\tFound service directory.", tests.Success)
|
|
|
|
|
|
log.Println("Verify release image.")
|
|
if releaseImage == "" {
|
|
if v := os.Getenv("CI_REGISTRY_IMAGE"); v != "" {
|
|
releaseImage = fmt.Sprintf("%s:%s-%s", v, targetService, targetEnv)
|
|
} else {
|
|
releaseImage = fmt.Sprintf("%s/%s:latest", targetService, targetEnv)
|
|
noPush = true
|
|
}
|
|
}
|
|
log.Printf("\t\trelease image: %s", releaseImage)
|
|
log.Printf("\t%s\tRelease image valid.", tests.Success)
|
|
|
|
// Load the AWS
|
|
log.Println("Verify AWS credentials.")
|
|
awsCreds, err := GetAwsCredentials(targetEnv)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
log.Printf("\t\tAccessKeyID: %s", awsCreds.AccessKeyID)
|
|
log.Printf("\t\tRegion: %s", awsCreds.Region)
|
|
|
|
// Set default AWS Registry Name if needed.
|
|
if awsCreds.RepositoryName == "" {
|
|
awsCreds.RepositoryName = projectName
|
|
log.Printf("\t\tSetting Repository Name to Project Name.")
|
|
}
|
|
log.Printf("\t\tRepository Name: %s", awsCreds.RepositoryName)
|
|
log.Printf("\t%s\tAWS credentials valid.", tests.Success)
|
|
|
|
// Pull the current env variables to be passed in for command execution.
|
|
envVars := EnvVars(os.Environ())
|
|
|
|
// Do the docker build.
|
|
{
|
|
cmdVals := []string{
|
|
"docker",
|
|
"build",
|
|
"--file=" + dockerFile,
|
|
"--build-arg", "service=" + targetService,
|
|
"--build-arg", "env=" + targetEnv,
|
|
"-t", releaseImage,
|
|
}
|
|
|
|
if noCache {
|
|
cmdVals = append(cmdVals, "--no-cache")
|
|
}
|
|
cmdVals = append(cmdVals, ".")
|
|
|
|
log.Printf("starting docker build: \n\t%s\n", strings.Join(cmdVals, " "))
|
|
out, err := execCmds(projectRoot, &envVars, cmdVals)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
log.Printf("build complete\n\t%s\n", string(out[0]))
|
|
}
|
|
|
|
// Push the newly built docker container to the registry.
|
|
if !noPush {
|
|
log.Println("Push release image.")
|
|
_, err = execCmds(projectRoot, &envVars, []string{"docker", "push", releaseImage})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
|
|
if awsCreds.RepositoryName != "" {
|
|
awsRepo, err := EcrGetOrCreateRepository(awsCreds, projectName, targetEnv)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
maxImages := defaultAwsRegistryMaxImages
|
|
if v := getTargetEnv(targetEnv, "AWS_REPOSITORY_MAX_IMAGES"); v != "" {
|
|
maxImages, err = strconv.Atoi(v)
|
|
if err != nil {
|
|
return errors.WithMessagef(err, "Failed to parse max ECR images")
|
|
}
|
|
}
|
|
|
|
log.Println("Purging old ECR images.")
|
|
err = EcrPurgeImages(log, awsCreds, maxImages)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
log.Println("Retrieve ECR authorization token used for docker login.")
|
|
dockerLogin, err := GetEcrLogin(awsCreds)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
awsRegistryImage := *awsRepo.RepositoryUri
|
|
|
|
// Login to AWS docker registry and pull release image locally.
|
|
log.Println("Push release image to ECR.")
|
|
log.Printf("\t\t%s", awsRegistryImage)
|
|
_, err = execCmds(projectRoot, &envVars, dockerLogin, []string{"docker", "tag", releaseImage, awsRegistryImage}, []string{"docker", "push", awsRegistryImage})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
tag1 := targetEnv+"-"+targetService
|
|
log.Printf("\t\ttagging as %s", tag1)
|
|
_, err = execCmds(projectRoot, &envVars, []string{"docker", "tag", releaseImage, awsRegistryImage+":"+tag1}, []string{"docker", "push", awsRegistryImage+":"+tag1})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if v := os.Getenv("CI_COMMIT_REF_NAME"); v != "" {
|
|
tag2 := tag1 + "-" + v
|
|
log.Printf("\t\ttagging as %s", tag2)
|
|
_, err = execCmds(projectRoot, &envVars, []string{"docker", "tag", releaseImage, awsRegistryImage+ ":" + tag2}, []string{"docker", "push", awsRegistryImage + ":" + tag2})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|