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