Skip to content

Commit

Permalink
fix: character on failed deployments (and add colors) (#307)
Browse files Browse the repository at this point in the history
* chore: Make functions consistent

* fix: character on failed deployments

- Adds color 🎨

* feat: Update output errors
  • Loading branch information
raulb authored Apr 8, 2022
1 parent 4640356 commit dbd9087
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 40 deletions.
56 changes: 28 additions & 28 deletions cmd/meroxa/root/apps/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,24 +203,25 @@ func (d *Deploy) createApplication(ctx context.Context, pipelineUUID, gitSha str
var app *meroxa.Application
app, err = d.client.GetApplication(ctx, appName)
if err != nil {
d.logger.StopSpinner("\t")
d.logger.StopSpinnerWithStatus("\t", log.Failed)
return err
}
if app.Pipeline.UUID.String != pipelineUUID {
d.logger.StopSpinner(fmt.Sprintf("\t 𐄂 unable to finish creating the %s Application because its entities are in an"+
" unrecoverable state; try deleting and re-deploying", appName))
d.logger.StopSpinnerWithStatus(fmt.Sprintf("unable to finish creating the %s Application because its entities are in an"+
" unrecoverable state; try deleting and re-deploying", appName), log.Failed)

d.logger.StopSpinner("\t")
d.logger.StopSpinnerWithStatus("\t", log.Failed)
// TODO: Rollback here?
return fmt.Errorf("unable to finish creating application")
}
}
d.logger.StopSpinner("\t")
d.logger.StopSpinnerWithStatus("\t", log.Failed)
return err
}

dashboardURL := fmt.Sprintf("https://dashboard.meroxa.io/v2/apps/%s/detail", res.UUID)
output := fmt.Sprintf("\t✔ Application %q successfully created!\n\n ✨ To visualize your application visit %s", res.Name, dashboardURL)
output := fmt.Sprintf("\t%s Application %q successfully created!\n\n ✨ To visualize your application visit %s",
d.logger.SuccessfulCheck(), res.Name, dashboardURL)
d.logger.StopSpinner(output)
d.logger.JSON(ctx, res)
return nil
Expand Down Expand Up @@ -289,7 +290,7 @@ func (d *Deploy) uploadFile(ctx context.Context, filePath, url string) error {

fh, err := os.Open(filePath)
if err != nil {
d.logger.StopSpinner("\t")
d.logger.StopSpinnerWithStatus("\t", log.Failed)
return err
}
defer func(fh *os.File) {
Expand All @@ -298,13 +299,13 @@ func (d *Deploy) uploadFile(ctx context.Context, filePath, url string) error {

req, err := http.NewRequestWithContext(ctx, "PUT", url, fh)
if err != nil {
d.logger.StopSpinner("\t")
d.logger.StopSpinnerWithStatus("\t", log.Failed)
return err
}

fi, err := fh.Stat()
if err != nil {
d.logger.StopSpinner("\t")
d.logger.StopSpinnerWithStatus("\t", log.Failed)
return err
}

Expand All @@ -318,7 +319,7 @@ func (d *Deploy) uploadFile(ctx context.Context, filePath, url string) error {
client := &http.Client{}
res, err := client.Do(req) //nolint:bodyclose
if err != nil {
d.logger.StopSpinner("\t")
d.logger.StopSpinnerWithStatus("\t", log.Failed)
return err
}
defer func(Body io.ReadCloser) {
Expand All @@ -328,7 +329,7 @@ func (d *Deploy) uploadFile(ctx context.Context, filePath, url string) error {
}
}(res.Body)

d.logger.StopSpinner("\tSource uploaded!")
d.logger.StopSpinnerWithStatus("Source uploaded!", log.Successful)
return nil
}

Expand All @@ -338,10 +339,10 @@ func (d *Deploy) getPlatformImage(ctx context.Context, appPath string) (string,
s, err := d.client.CreateSource(ctx)
if err != nil {
d.logger.Errorf(ctx, "\t 𐄂 Unable to fetch source")
d.logger.StopSpinner("\t")
d.logger.StopSpinnerWithStatus("\t", log.Failed)
return "", err
}
d.logger.StopSpinner("\tPlatform source fetched!")
d.logger.StopSpinnerWithStatus("Platform source fetched!", log.Successful)

err = d.uploadSource(ctx, appPath, s.PutUrl)
if err != nil {
Expand All @@ -355,23 +356,24 @@ func (d *Deploy) getPlatformImage(ctx context.Context, appPath string) (string,

build, err := d.client.CreateBuild(ctx, buildInput)
if err != nil {
d.logger.StopSpinner("\t")
d.logger.StopSpinnerWithStatus("\t", log.Failed)
return "", err
}

for {
b, err := d.client.GetBuild(ctx, build.Uuid)
if err != nil {
d.logger.StopSpinner("\t")
d.logger.StopSpinnerWithStatus("\t", log.Failed)
return "", err
}

switch b.Status.State {
case "error":
d.logger.StopSpinner(fmt.Sprintf("\t 𐄂 build with uuid %q errored\nRun `meroxa build logs %s` for more information", b.Uuid, b.Uuid))
msg := fmt.Sprintf("build with uuid %q errored\nRun `meroxa build logs %s` for more information", b.Uuid, b.Uuid)
d.logger.StopSpinnerWithStatus(msg, log.Failed)
return "", fmt.Errorf("build with uuid %q errored", b.Uuid)
case "complete":
d.logger.StopSpinner("\tProcess image built!")
d.logger.StopSpinnerWithStatus("Process image built!", log.Successful)
return build.Image, nil
}
time.Sleep(pollDuration)
Expand All @@ -385,21 +387,19 @@ func (d *Deploy) deployApp(ctx context.Context, imageName string) (string, error
d.logger.StartSpinner("\t", fmt.Sprintf(" Deploying application %q...", d.appName))
switch d.lang {
case GoLang:
output, err = turbineGo.RunDeployApp(ctx, d.logger, d.path, d.appName, imageName)
output, err = turbineGo.RunDeployApp(ctx, d.logger, d.path, imageName, d.appName)
case JavaScript:
// TODO: @james
// TODO: Do less here!!!
output, err = turbineJS.Deploy(ctx, d.path, imageName, d.logger)
output, err = turbineJS.RunDeployApp(ctx, d.logger, d.path, imageName)
case Python:
// TODO: @eric
}

if err != nil {
d.logger.StopSpinner("\t𐄂 Deployment failed\n\n")
d.logger.StopSpinnerWithStatus("Deployment failed\n\n", log.Failed)
return "", err
}

d.logger.StopSpinner("\tDeploy complete!")
d.logger.StopSpinnerWithStatus("Deploy complete!", log.Successful)
return output, nil
}

Expand All @@ -421,10 +421,10 @@ func (d *Deploy) buildApp(ctx context.Context) error {
// Dockerfile will already exist
}
if err != nil {
d.logger.StopSpinner("\t")
d.logger.StopSpinnerWithStatus("\t", log.Failed)
return err
}
d.logger.StopSpinner("\tApplication built!")
d.logger.StopSpinnerWithStatus("Application built!", log.Successful)
return nil
}

Expand All @@ -445,17 +445,17 @@ func (d *Deploy) getAppImage(ctx context.Context) (string, error) {
// TODO: @eric
}
if err != nil {
d.logger.StopSpinner("\t")
d.logger.StopSpinnerWithStatus("\t", log.Failed)
return "", err
}

// If no need to build, return empty imageName which won't be utilized by the deploy process anyways
if !needsToBuild {
d.logger.StopSpinner("\tNo need to create process image...")
d.logger.StopSpinnerWithStatus("No need to create process image...", log.Successful)
return "", nil
}

d.logger.StopSpinner("\tApplication processes found. Creating application image...")
d.logger.StopSpinnerWithStatus("Application processes found. Creating application image...", log.Successful)

d.localDeploy.TempPath = d.tempPath
d.localDeploy.Lang = d.lang
Expand Down
2 changes: 1 addition & 1 deletion cmd/meroxa/turbine_cli/golang/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
)

// RunDeployApp runs the binary previously built with the `--deploy` flag which should create all necessary resources.
func RunDeployApp(ctx context.Context, l log.Logger, appPath, appName, imageName string) (string, error) {
func RunDeployApp(ctx context.Context, l log.Logger, appPath, imageName, appName string) (string, error) {
var cmd *exec.Cmd

if imageName != "" {
Expand Down
2 changes: 1 addition & 1 deletion cmd/meroxa/turbine_cli/javascript/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ func BuildApp(path string) (string, error) {
return strings.TrimSpace(string(output)), err
}

func Deploy(ctx context.Context, path, imageName string, l log.Logger) (string, error) {
func RunDeployApp(ctx context.Context, l log.Logger, path, imageName string) (string, error) {
cmd := exec.Command("npx", "turbine", "clideploy", imageName, path)

accessToken, _, err := global.GetUserToken()
Expand Down
16 changes: 8 additions & 8 deletions cmd/meroxa/turbine_cli/local_deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,19 +54,19 @@ func (ld *LocalDeploy) GetDockerImageName(ctx context.Context, l log.Logger, app
// this will go away when using the new service.
err = ld.pushImage(l, fqImageName)
if err != nil {
l.Errorf(ctx, "\t 𐄂 Unable to push image %q", fqImageName)
l.Errorf(ctx, "\t %s Unable to push image %q", l.FailedMark(), fqImageName)
return "", err
}

l.Infof(ctx, "\t Image built!")
l.Infof(ctx, "\t%s Image built!", l.SuccessfulCheck())
return fqImageName, nil
}

func (ld *LocalDeploy) buildImage(ctx context.Context, l log.Logger, pwd, imageName string) error {
l.Infof(ctx, "\t Building image %q located at %q", imageName, pwd)
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
if err != nil {
l.Errorf(ctx, "\t 𐄂 Unable to init docker client")
l.Errorf(ctx, "\t %s Unable to init docker client", l.FailedMark())
return err
}

Expand All @@ -87,7 +87,7 @@ func (ld *LocalDeploy) buildImage(ctx context.Context, l log.Logger, pwd, imageN
ExcludePatterns: []string{".git", "fixtures"},
})
if err != nil {
l.Errorf(ctx, "\t 𐄂 Unable to create tar")
l.Errorf(ctx, "\t %s Unable to create tar", l.FailedMark())
return err
}

Expand All @@ -103,20 +103,20 @@ func (ld *LocalDeploy) buildImage(ctx context.Context, l log.Logger, pwd, imageN
buildOptions,
)
if err != nil {
l.Errorf(ctx, "\t 𐄂 Unable to build docker image")
l.Errorf(ctx, "\t %s Unable to build docker image", l.FailedMark())
return err
}
defer func(Body io.ReadCloser) {
err = Body.Close()
if err != nil {
l.Errorf(ctx, "\t 𐄂 Unable to close docker build response body; %s", err)
l.Errorf(ctx, "\t %s Unable to close docker build response body; %s", l.FailedMark(), err)
}
}(resp.Body)

buf := new(strings.Builder)
_, err = io.Copy(buf, resp.Body)
if err != nil {
l.Errorf(ctx, "\t 𐄂 Unable to read image build response")
l.Errorf(ctx, "\t %s Unable to read image build response", l.FailedMark())
return err
}
dockerBuildOutput := buf.String()
Expand All @@ -133,7 +133,7 @@ func (ld *LocalDeploy) buildImage(ctx context.Context, l log.Logger, pwd, imageN
errMsg += "\n" + str[1]
}
err = fmt.Errorf("%s", errMsg)
l.Errorf(ctx, "\t 𐄂 Unable to build docker image")
l.Errorf(ctx, "\t %s Unable to build docker image", l.FailedMark())
return err
}
l.Info(ctx, dockerBuildOutput)
Expand Down
4 changes: 2 additions & 2 deletions cmd/meroxa/turbine_cli/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ func GitChecks(ctx context.Context, l log.Logger, appPath string) error {
}
return fmt.Errorf("unable to proceed with deployment because of uncommitted changes")
}
l.Info(ctx, "\t No uncommitted changes!")
l.Infof(ctx, "\t%s No uncommitted changes!", l.SuccessfulCheck())
return os.Chdir(pwd)
}

Expand Down Expand Up @@ -208,7 +208,7 @@ func ValidateBranch(ctx context.Context, l log.Logger, appPath string) error {
if branchName != "main" && branchName != "master" {
return fmt.Errorf("deployment allowed only from 'main' or 'master' branch, not %s", branchName)
}
l.Infof(ctx, "\t Deployment allowed from %s branch!", branchName)
l.Infof(ctx, "\t%s Deployment allowed from %s branch!", l.SuccessfulCheck(), branchName)
err = os.Chdir(pwd)
if err != nil {
return err
Expand Down
29 changes: 29 additions & 0 deletions log/spinner.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,27 @@
package log

import (
"fmt"
"io"
"log"
"time"

"github.com/fatih/color"

"github.com/briandowns/spinner"
)

const (
Successful = "successful"
Failed = "failed"
)

type SpinnerLogger interface {
StartSpinner(prefix, suffix string)
StopSpinner(msg string)
StopSpinnerWithStatus(msg, status string)
SuccessfulCheck() string
FailedMark() string
}

func NewSpinnerLogger(out io.Writer) SpinnerLogger {
Expand All @@ -33,3 +44,21 @@ func (l *spinnerLogger) StopSpinner(msg string) {
l.s.Stop()
l.l.Printf(msg)
}

func (l *spinnerLogger) StopSpinnerWithStatus(msg, status string) {
if status == Failed {
msg = fmt.Sprintf("\t%s %s", l.FailedMark(), msg)
} else if status == Successful {
msg = fmt.Sprintf("\t%s %s", l.SuccessfulCheck(), msg)
}
l.s.Stop()
l.l.Printf(msg)
}

func (l *spinnerLogger) SuccessfulCheck() string {
return color.New(color.FgGreen).Sprintf("✔")
}

func (l *spinnerLogger) FailedMark() string {
return color.New(color.FgRed).Sprintf("x")
}

0 comments on commit dbd9087

Please sign in to comment.