From 9c188c998c1b2c4622f2d3f6352ddfdaf2be400a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Barroso?= Date: Thu, 17 Mar 2022 16:17:54 +0100 Subject: [PATCH 1/3] feat: Include gitSha on apps creation --- cmd/meroxa/root/apps/deploy.go | 69 +++++---------------------- cmd/meroxa/root/apps/deploy_test.go | 5 +- cmd/meroxa/turbine_cli/utils.go | 73 +++++++++++++++++++++++++++++ 3 files changed, 87 insertions(+), 60 deletions(-) diff --git a/cmd/meroxa/root/apps/deploy.go b/cmd/meroxa/root/apps/deploy.go index f66d97e46..410201256 100644 --- a/cmd/meroxa/root/apps/deploy.go +++ b/cmd/meroxa/root/apps/deploy.go @@ -21,18 +21,13 @@ import ( "errors" "fmt" "os" - "os/exec" - "regexp" - "strings" - - turbineGo "github.com/meroxa/cli/cmd/meroxa/turbine_cli/golang" - - turbineJS "github.com/meroxa/cli/cmd/meroxa/turbine_cli/javascript" "github.com/volatiletech/null/v8" "github.com/meroxa/cli/cmd/meroxa/builder" turbineCLI "github.com/meroxa/cli/cmd/meroxa/turbine_cli" + turbineGo "github.com/meroxa/cli/cmd/meroxa/turbine_cli/golang" + turbineJS "github.com/meroxa/cli/cmd/meroxa/turbine_cli/javascript" "github.com/meroxa/cli/config" "github.com/meroxa/cli/log" "github.com/meroxa/meroxa-go/pkg/meroxa" @@ -170,7 +165,7 @@ func (d *Deploy) Logger(logger log.Logger) { } // TODO: Move this to each turbine library. -func (d *Deploy) createApplication(ctx context.Context, pipelineUUID string) error { +func (d *Deploy) createApplication(ctx context.Context, pipelineUUID, gitSha string) error { appName, err := turbineCLI.GetAppNameFromAppJSON(d.path) if err != nil { return err @@ -179,7 +174,7 @@ func (d *Deploy) createApplication(ctx context.Context, pipelineUUID string) err input := meroxa.CreateApplicationInput{ Name: appName, Language: d.lang, - GitSha: "hardcoded", + GitSha: gitSha, Pipeline: meroxa.EntityIdentifier{UUID: null.StringFrom(pipelineUUID)}, } d.logger.Infof(ctx, "Creating application %q with language %q...", input.Name, d.lang) @@ -194,52 +189,6 @@ func (d *Deploy) createApplication(ctx context.Context, pipelineUUID string) err return nil } -// gitChecks prints warnings about uncommitted tracked and untracked files. -func (d *Deploy) gitChecks(ctx context.Context) error { - // temporarily switching to the app's directory - pwd, err := os.Getwd() - if err != nil { - return err - } - err = os.Chdir(d.path) - if err != nil { - return err - } - - cmd := exec.Command("git", "status", "--porcelain=v2") - output, err := cmd.Output() - if err != nil { - return err - } - all := string(output) - lines := strings.Split(strings.TrimSpace(all), "\n") - if len(lines) > 0 && lines[0] != "" { - cmd = exec.Command("git", "status") - output, err = cmd.Output() - if err != nil { - return err - } - d.logger.Error(ctx, string(output)) - err = os.Chdir(pwd) - if err != nil { - return err - } - return fmt.Errorf("unable to proceed with deployment because of uncommitted changes") - } - - return os.Chdir(pwd) -} - -// getPipelineUUID parses the deploy output when it was successful to determine the pipeline UUID to create. -func getPipelineUUID(output string) string { - // Example output: - // 2022/03/16 13:21:36 pipeline created: "turbine-pipeline-simple" ("049760a8-a3d2-44d9-b326-0614c09a3f3e"). - re := regexp.MustCompile(`pipeline created:."[a-zA-Z]+-[a-zA-Z]+-[a-zA-Z]+".(\([^)]*\))`) - res := re.FindStringSubmatch(output)[1] - res = strings.Trim(res, "()\"") - return res -} - func (d *Deploy) Execute(ctx context.Context) error { var deployOuput string // validateLocalDeploymentConfig will look for DockerHub credentials to determine whether it's a local deployment or not. @@ -254,7 +203,7 @@ func (d *Deploy) Execute(ctx context.Context) error { return err } - err = d.gitChecks(ctx) + err = turbineCLI.GitChecks(ctx, d.logger, d.path) if err != nil { return err } @@ -275,7 +224,11 @@ func (d *Deploy) Execute(ctx context.Context) error { return err } - pipelineUUID := getPipelineUUID(deployOuput) + pipelineUUID := turbineCLI.GetPipelineUUID(deployOuput) + gitSha, err := turbineCLI.GetGitSha(d.path) + if err != nil { + return err + } - return d.createApplication(ctx, pipelineUUID) + return d.createApplication(ctx, pipelineUUID, gitSha) } diff --git a/cmd/meroxa/root/apps/deploy_test.go b/cmd/meroxa/root/apps/deploy_test.go index 2d9f444f6..c61208c08 100644 --- a/cmd/meroxa/root/apps/deploy_test.go +++ b/cmd/meroxa/root/apps/deploy_test.go @@ -231,6 +231,7 @@ func TestCreateApplication(t *testing.T) { name := "my-application" lang := GoLang pipelineUUID := "5d0c9667-1626-4ffd-9a94-fab4092eec5a" + gitSha := "626de930-67ee-4f2b-9af3-12e7165c86b3" // Create application locally path, err := initLocalApp(name) @@ -244,7 +245,7 @@ func TestCreateApplication(t *testing.T) { ai := &meroxa.CreateApplicationInput{ Name: name, Language: lang, - GitSha: "hardcoded", + GitSha: gitSha, Pipeline: meroxa.EntityIdentifier{UUID: null.StringFrom(pipelineUUID)}, } @@ -269,7 +270,7 @@ func TestCreateApplication(t *testing.T) { lang: lang, } - err = d.createApplication(ctx, pipelineUUID) + err = d.createApplication(ctx, pipelineUUID, gitSha) if err != nil { t.Fatalf("not expected error, got \"%s\"", err.Error()) diff --git a/cmd/meroxa/turbine_cli/utils.go b/cmd/meroxa/turbine_cli/utils.go index 492db66b0..7e4f2e3f8 100644 --- a/cmd/meroxa/turbine_cli/utils.go +++ b/cmd/meroxa/turbine_cli/utils.go @@ -1,10 +1,16 @@ package turbinecli import ( + "context" "encoding/json" "fmt" "os" + "os/exec" "path" + "regexp" + "strings" + + "github.com/meroxa/cli/log" ) type AppConfig struct { @@ -74,3 +80,70 @@ func readConfigFile(appPath string) (AppConfig, error) { return appConfig, nil } + +// GitChecks prints warnings about uncommitted tracked and untracked files. +func GitChecks(ctx context.Context, l log.Logger, path string) error { + // temporarily switching to the app's directory + pwd, err := switchToAppDirectory(path) + + cmd := exec.Command("git", "status", "--porcelain=v2") + output, err := cmd.Output() + if err != nil { + return err + } + all := string(output) + lines := strings.Split(strings.TrimSpace(all), "\n") + if len(lines) > 0 && lines[0] != "" { + cmd = exec.Command("git", "status") + output, err = cmd.Output() + if err != nil { + return err + } + l.Error(ctx, string(output)) + err = os.Chdir(pwd) + if err != nil { + return err + } + return fmt.Errorf("unable to proceed with deployment because of uncommitted changes") + } + return os.Chdir(pwd) +} + +// GetPipelineUUID parses the deploy output when it was successful to determine the pipeline UUID to create. +func GetPipelineUUID(output string) string { + // Example output: + // 2022/03/16 13:21:36 pipeline created: "turbine-pipeline-simple" ("049760a8-a3d2-44d9-b326-0614c09a3f3e"). + re := regexp.MustCompile(`pipeline created:."[a-zA-Z]+-[a-zA-Z]+-[a-zA-Z]+".(\([^)]*\))`) + res := re.FindStringSubmatch(output)[1] + res = strings.Trim(res, "()\"") + return res +} + +// GetGitSha will return the latest gitSha that will be used to create an application +func GetGitSha(path string) (string, error) { + // temporarily switching to the app's directory + pwd, err := switchToAppDirectory(path) + + // Gets latest git sha + cmd := exec.Command("git", "rev-parse", "HEAD") + output, err := cmd.Output() + if err != nil { + return "", err + } + + err = os.Chdir(pwd) + if err != nil { + return "", err + } + + return string(output), nil +} + +// switchToAppDirectory switches temporarily to the application's directory +func switchToAppDirectory(path string) (string, error) { + pwd, err := os.Getwd() + if err != nil { + return pwd, err + } + return pwd, os.Chdir(path) +} From 1b920f16a923c1bfe01d806ec8fef107424c7bb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Barroso?= Date: Thu, 17 Mar 2022 18:19:46 +0100 Subject: [PATCH 2/3] feat: Add branch validation Co-authored-by: janelletavares --- cmd/meroxa/root/apps/deploy.go | 5 +++++ cmd/meroxa/turbine_cli/utils.go | 28 ++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/cmd/meroxa/root/apps/deploy.go b/cmd/meroxa/root/apps/deploy.go index 410201256..008bf7ed3 100644 --- a/cmd/meroxa/root/apps/deploy.go +++ b/cmd/meroxa/root/apps/deploy.go @@ -208,6 +208,11 @@ func (d *Deploy) Execute(ctx context.Context) error { return err } + err = turbineCLI.ValidateBranch(d.path) + if err != nil { + return err + } + switch d.lang { case GoLang: // The only reason Deploy is scoped this other way is, so we can have the Docker Credentials diff --git a/cmd/meroxa/turbine_cli/utils.go b/cmd/meroxa/turbine_cli/utils.go index 7e4f2e3f8..690fe3e50 100644 --- a/cmd/meroxa/turbine_cli/utils.go +++ b/cmd/meroxa/turbine_cli/utils.go @@ -119,10 +119,38 @@ func GetPipelineUUID(output string) string { return res } +// ValidateBranch validates the deployment is being performed from one of the allowed branches +func ValidateBranch(path string) error { + // temporarily switching to the app's directory + pwd, err := switchToAppDirectory(path) + if err != nil { + return err + } + + cmd := exec.Command("git", "branch", "--show-current") + output, err := cmd.Output() + if err != nil { + return err + } + branchName := strings.TrimSpace(string(output)) + if branchName != "main" && branchName != "master" { + return fmt.Errorf("deployment allowed only from 'main' or 'master' branch, not %s", branchName) + } + + err = os.Chdir(pwd) + if err != nil { + return err + } + return nil +} + // GetGitSha will return the latest gitSha that will be used to create an application func GetGitSha(path string) (string, error) { // temporarily switching to the app's directory pwd, err := switchToAppDirectory(path) + if err != nil { + return "", err + } // Gets latest git sha cmd := exec.Command("git", "rev-parse", "HEAD") From e40ff0e9da0cd15551e580c1bfdae3e87b7b3255 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Barroso?= Date: Thu, 17 Mar 2022 18:24:28 +0100 Subject: [PATCH 3/3] fix: lint errors --- cmd/meroxa/turbine_cli/utils.go | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/cmd/meroxa/turbine_cli/utils.go b/cmd/meroxa/turbine_cli/utils.go index 690fe3e50..bf63f08d0 100644 --- a/cmd/meroxa/turbine_cli/utils.go +++ b/cmd/meroxa/turbine_cli/utils.go @@ -82,9 +82,12 @@ func readConfigFile(appPath string) (AppConfig, error) { } // GitChecks prints warnings about uncommitted tracked and untracked files. -func GitChecks(ctx context.Context, l log.Logger, path string) error { +func GitChecks(ctx context.Context, l log.Logger, appPath string) error { // temporarily switching to the app's directory - pwd, err := switchToAppDirectory(path) + pwd, err := switchToAppDirectory(appPath) + if err != nil { + return err + } cmd := exec.Command("git", "status", "--porcelain=v2") output, err := cmd.Output() @@ -119,10 +122,10 @@ func GetPipelineUUID(output string) string { return res } -// ValidateBranch validates the deployment is being performed from one of the allowed branches -func ValidateBranch(path string) error { +// ValidateBranch validates the deployment is being performed from one of the allowed branches. +func ValidateBranch(appPath string) error { // temporarily switching to the app's directory - pwd, err := switchToAppDirectory(path) + pwd, err := switchToAppDirectory(appPath) if err != nil { return err } @@ -144,10 +147,10 @@ func ValidateBranch(path string) error { return nil } -// GetGitSha will return the latest gitSha that will be used to create an application -func GetGitSha(path string) (string, error) { +// GetGitSha will return the latest gitSha that will be used to create an application. +func GetGitSha(appPath string) (string, error) { // temporarily switching to the app's directory - pwd, err := switchToAppDirectory(path) + pwd, err := switchToAppDirectory(appPath) if err != nil { return "", err } @@ -167,11 +170,11 @@ func GetGitSha(path string) (string, error) { return string(output), nil } -// switchToAppDirectory switches temporarily to the application's directory -func switchToAppDirectory(path string) (string, error) { +// switchToAppDirectory switches temporarily to the application's directory. +func switchToAppDirectory(appPath string) (string, error) { pwd, err := os.Getwd() if err != nil { return pwd, err } - return pwd, os.Chdir(path) + return pwd, os.Chdir(appPath) }