github.com/orangenpresse/up@v0.6.0/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() error {
    93  	defer p.events.Time("platform.build", nil)()
    94  
    95  	if err := p.RunHooks("prebuild", "build"); err != nil {
    96  		return err
    97  	}
    98  
    99  	if err := p.Platform.Build(); err != nil {
   100  		return errors.Wrap(err, "building")
   101  	}
   102  
   103  	if err := p.RunHooks("postbuild"); err != nil {
   104  		return err
   105  	}
   106  
   107  	return nil
   108  }
   109  
   110  // Deploy the project.
   111  func (p *Project) Deploy(d Deploy) error {
   112  	defer p.events.Time("deploy", event.Fields{
   113  		"commit": d.Commit,
   114  		"stage":  d.Stage,
   115  	})()
   116  
   117  	if err := p.Build(); err != nil {
   118  		return errors.Wrap(err, "building")
   119  	}
   120  
   121  	if err := p.deploy(d); err != nil {
   122  		return errors.Wrap(err, "deploying")
   123  	}
   124  
   125  	if err := p.RunHook("clean"); err != nil {
   126  		return errors.Wrap(err, "clean hook")
   127  	}
   128  
   129  	return nil
   130  }
   131  
   132  // deploy stage.
   133  func (p *Project) deploy(d Deploy) error {
   134  	if err := p.RunHooks("predeploy", "deploy"); err != nil {
   135  		return err
   136  	}
   137  
   138  	if err := p.Platform.Deploy(d); err != nil {
   139  		return err
   140  	}
   141  
   142  	if err := p.RunHooks("postdeploy"); err != nil {
   143  		return err
   144  	}
   145  
   146  	return nil
   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  }