github.com/apex/up@v1.7.1/up.go (about) 1 package up 2 3 import ( 4 "io" 5 "os" 6 "os/exec" 7 "time" 8 9 "github.com/apex/log" 10 "github.com/pkg/errors" 11 12 "github.com/apex/up/config" 13 "github.com/apex/up/internal/util" 14 "github.com/apex/up/platform/event" 15 ) 16 17 // Config for a project. 18 type Config = config.Config 19 20 // ReadConfig reads the configuration from `path`. 21 var ReadConfig = config.ReadConfig 22 23 // ParseConfigString returns config from JSON string. 24 var ParseConfigString = config.ParseConfigString 25 26 // MustParseConfigString returns config from JSON string. 27 var MustParseConfigString = config.MustParseConfigString 28 29 // Project manager. 30 type Project struct { 31 Platform 32 config *Config 33 events event.Events 34 } 35 36 // New project. 37 func New(c *Config, events event.Events) *Project { 38 return &Project{ 39 config: c, 40 events: events, 41 } 42 } 43 44 // WithPlatform to `platform`. 45 func (p *Project) WithPlatform(platform Platform) *Project { 46 p.Platform = platform 47 return p 48 } 49 50 // RunHook runs a hook by name. 51 func (p *Project) RunHook(name string) error { 52 hook := p.config.Hooks.Get(name) 53 54 if hook.IsEmpty() { 55 log.Debugf("hook %s is not defined", name) 56 return nil 57 } 58 59 defer p.events.Time("hook", event.Fields{ 60 "name": name, 61 "hook": hook, 62 })() 63 64 for _, command := range hook { 65 log.Debugf("hook %q command %q", name, command) 66 67 cmd := exec.Command("sh", "-c", command) 68 cmd.Env = os.Environ() 69 cmd.Env = append(cmd.Env, util.Env(p.config.Environment)...) 70 cmd.Env = append(cmd.Env, "PATH=node_modules/.bin:"+os.Getenv("PATH")) 71 72 b, err := cmd.CombinedOutput() 73 if err != nil { 74 return errors.Errorf("%q: %s", command, b) 75 } 76 } 77 78 return nil 79 } 80 81 // RunHooks runs hooks by name. 82 func (p *Project) RunHooks(names ...string) error { 83 for _, n := range names { 84 if err := p.RunHook(n); err != nil { 85 return errors.Wrapf(err, "%q hook", n) 86 } 87 } 88 return nil 89 } 90 91 // Build the project. 92 func (p *Project) Build(hooks bool) error { 93 defer p.events.Time("platform.build", nil)() 94 95 if hooks { 96 if err := p.RunHooks("prebuild", "build"); err != nil { 97 return err 98 } 99 } 100 101 if err := p.Platform.Build(); err != nil { 102 return errors.Wrap(err, "building") 103 } 104 105 if hooks { 106 return p.RunHooks("postbuild") 107 } 108 109 return nil 110 } 111 112 // Deploy the project. 113 func (p *Project) Deploy(d Deploy) error { 114 defer p.events.Time("deploy", event.Fields{ 115 "commit": d.Commit, 116 "stage": d.Stage, 117 })() 118 119 if err := p.Build(d.Build); err != nil { 120 return errors.Wrap(err, "building") 121 } 122 123 if err := p.deploy(d); err != nil { 124 return errors.Wrap(err, "deploying") 125 } 126 127 if d.Build { 128 if err := p.RunHook("clean"); err != nil { 129 return errors.Wrap(err, "clean hook") 130 } 131 } 132 133 return nil 134 } 135 136 // deploy stage. 137 func (p *Project) deploy(d Deploy) error { 138 if err := p.RunHooks("predeploy", "deploy"); err != nil { 139 return err 140 } 141 142 if err := p.Platform.Deploy(d); err != nil { 143 return err 144 } 145 146 return p.RunHooks("postdeploy") 147 } 148 149 // Zip returns the zip if supported by the platform. 150 func (p *Project) Zip() (io.Reader, error) { 151 z, ok := p.Platform.(Zipper) 152 if !ok { 153 return nil, errors.Errorf("platform does not support zips") 154 } 155 156 return z.Zip(), nil 157 } 158 159 // Init initializes the runtime such as remote environment variables. 160 func (p *Project) Init(stage string) error { 161 r, ok := p.Platform.(Runtime) 162 if !ok { 163 return nil 164 } 165 166 return r.Init(stage) 167 } 168 169 // CreateStack implementation. 170 func (p *Project) CreateStack(region, version string) error { 171 defer p.events.Time("stack.create", event.Fields{ 172 "region": region, 173 "version": version, 174 })() 175 176 return p.Platform.CreateStack(region, version) 177 } 178 179 // DeleteStack implementation. 180 func (p *Project) DeleteStack(region string, wait bool) error { 181 defer p.events.Time("stack.delete", event.Fields{ 182 "region": region, 183 })() 184 185 return p.Platform.DeleteStack(region, wait) 186 } 187 188 // ShowStack implementation. 189 func (p *Project) ShowStack(region string) error { 190 defer p.events.Time("stack.show", event.Fields{ 191 "region": region, 192 })() 193 194 return p.Platform.ShowStack(region) 195 } 196 197 // ShowMetrics implementation. 198 func (p *Project) ShowMetrics(region, stage string, start time.Time) error { 199 defer p.events.Time("metrics", event.Fields{ 200 "region": region, 201 "stage": stage, 202 "start": start, 203 })() 204 205 return p.Platform.ShowMetrics(region, stage, start) 206 } 207 208 // PlanStack implementation. 209 func (p *Project) PlanStack(region string) error { 210 defer p.events.Time("stack.plan", event.Fields{ 211 "region": region, 212 })() 213 214 return p.Platform.PlanStack(region) 215 } 216 217 // ApplyStack implementation. 218 func (p *Project) ApplyStack(region string) error { 219 defer p.events.Time("stack.apply", event.Fields{ 220 "region": region, 221 })() 222 223 return p.Platform.ApplyStack(region) 224 } 225 226 // Prune implementation. 227 func (p *Project) Prune(region, stage string, versions int) error { 228 pruner, ok := p.Platform.(Pruner) 229 if !ok { 230 return errors.Errorf("platform does not support pruning") 231 } 232 233 return pruner.Prune(region, stage, versions) 234 }