github.com/webonyx/up@v0.7.4-0.20180808230834-91b94e551323/internal/cli/deploy/deploy.go (about)

     1  package deploy
     2  
     3  import (
     4  	"os"
     5  	"time"
     6  
     7  	"github.com/pkg/errors"
     8  	"github.com/tj/go/git"
     9  	"github.com/tj/go/term"
    10  	"github.com/tj/kingpin"
    11  
    12  	"github.com/apex/up"
    13  	"github.com/apex/up/internal/cli/root"
    14  	"github.com/apex/up/internal/setup"
    15  	"github.com/apex/up/internal/stats"
    16  	"github.com/apex/up/internal/util"
    17  	"github.com/apex/up/internal/validate"
    18  )
    19  
    20  func init() {
    21  	cmd := root.Command("deploy", "Deploy the project.").Default()
    22  	stage := cmd.Arg("stage", "Target stage name.").Default("staging").String()
    23  	cmd.Example(`up deploy`, "Deploy the project the staging environment.")
    24  	cmd.Example(`up deploy production`, "Deploy the project to the production environment.")
    25  
    26  	cmd.Action(func(_ *kingpin.ParseContext) error {
    27  		return deploy(*stage)
    28  	})
    29  }
    30  
    31  func deploy(stage string) error {
    32  retry:
    33  	c, p, err := root.Init()
    34  
    35  	// missing up.json non-interactive
    36  	if isMissingConfig(err) && !term.IsTerminal(os.Stdin.Fd()) {
    37  		return errors.New("Cannot find ./up.json configuration file.")
    38  	}
    39  
    40  	// missing up.json interactive
    41  	if isMissingConfig(err) {
    42  		err := setup.Create()
    43  
    44  		if err == setup.ErrNoCredentials {
    45  			return errors.New("Cannot find credentials, visit https://up.docs.apex.sh/#aws_credentials for help.")
    46  		}
    47  
    48  		if err != nil {
    49  			return errors.Wrap(err, "setup")
    50  		}
    51  
    52  		util.Log("Deploying the project and creating resources.")
    53  		goto retry
    54  	}
    55  
    56  	// unrelated error
    57  	if err != nil {
    58  		return errors.Wrap(err, "initializing")
    59  	}
    60  
    61  	// validate stage name
    62  	if err := validate.List(stage, c.Stages.RemoteNames()); err != nil {
    63  		return err
    64  	}
    65  
    66  	// stage overrides
    67  	if err := c.Override(stage); err != nil {
    68  		return errors.Wrap(err, "overriding")
    69  	}
    70  
    71  	// git information
    72  	commit, err := getCommit()
    73  	if err != nil {
    74  		return errors.Wrap(err, "fetching git commit")
    75  	}
    76  
    77  	defer util.Pad()()
    78  	start := time.Now()
    79  
    80  	if err := p.Init(stage); err != nil {
    81  		return errors.Wrap(err, "initializing")
    82  	}
    83  
    84  	if err := p.Deploy(up.Deploy{
    85  		Stage:  stage,
    86  		Commit: util.StripLerna(commit.Describe()),
    87  		Author: commit.Author.Name,
    88  	}); err != nil {
    89  		return err
    90  	}
    91  
    92  	stats.Track("Deploy", map[string]interface{}{
    93  		"duration":             util.MillisecondsSince(start),
    94  		"type":                 c.Type,
    95  		"regions":              c.Regions,
    96  		"stage":                stage,
    97  		"proxy_timeout":        c.Proxy.Timeout,
    98  		"header_rules_count":   len(c.Headers),
    99  		"redirect_rules_count": len(c.Redirects),
   100  		"inject_rules_count":   len(c.Inject),
   101  		"environment_count":    len(c.Environment),
   102  		"dns_zone_count":       len(c.DNS.Zones),
   103  		"stage_count":          len(c.Stages.List()),
   104  		"stage_domain_count":   len(c.Stages.Domains()),
   105  		"lambda_accelerate":    c.Lambda.Accelerate,
   106  		"lambda_memory":        c.Lambda.Memory,
   107  		"has_cors":             c.CORS != nil,
   108  		"has_logs":             !c.Logs.Disable,
   109  		"has_profile":          c.Profile != "",
   110  		"has_error_pages":      !c.ErrorPages.Disable,
   111  		"app_name_hash":        util.Md5(c.Name),
   112  		"is_git":               commit.Author.Name != "",
   113  		"alerts_count":         len(c.Alerts),
   114  		"actions_count":        len(c.Actions),
   115  	})
   116  
   117  	stats.Flush()
   118  	return nil
   119  }
   120  
   121  // isMissingConfig returns true if the error represents a missing up.json.
   122  func isMissingConfig(err error) bool {
   123  	err = errors.Cause(err)
   124  	e, ok := err.(*os.PathError)
   125  	return ok && e.Path == "up.json"
   126  }
   127  
   128  // getCommit returns the git information when available.
   129  func getCommit() (git.Commit, error) {
   130  	c, err := git.GetCommit(".", "HEAD")
   131  	if err != nil && !isIgnorable(err) {
   132  		return git.Commit{}, err
   133  	}
   134  
   135  	if c == nil {
   136  		return git.Commit{}, nil
   137  	}
   138  
   139  	return *c, nil
   140  }
   141  
   142  // isIgnorable returns true if the GIT error is ignorable.
   143  func isIgnorable(err error) bool {
   144  	switch err {
   145  	case git.ErrLookup, git.ErrNoRepo, git.ErrDirty:
   146  		return true
   147  	default:
   148  		return false
   149  	}
   150  }