package main import ( "encoding/base64" "fmt" "path/filepath" common "github.com/drone/drone/pkg/types" "github.com/drone/drone/pkg/yaml" "github.com/drone/drone/pkg/yaml/inject" "github.com/samalba/dockerclient" ) type Context struct { // Links *common.Link Clone *common.Clone `json:"clone"` Repo *common.Repo `json:"repo"` Commit *common.Commit `json:"commit"` Build *common.Build `json:"build"` Keys *common.Keypair `json:"keys"` Netrc *common.Netrc `json:"netrc"` Yaml []byte `json:"yaml"` Conf *common.Config `json:"-"` infos []*dockerclient.ContainerInfo client dockerclient.Client } func setup(c *Context) error { var err error var opts = parser.DefaultOpts // if repository is trusted the build may specify // custom volumes, networking and run in trusted mode. if c.Repo.Trusted { opts = &parser.Opts{Network: true, Privileged: true, Volumes: true} } // inject the matrix parameters into the yaml injected := inject.Inject(string(c.Yaml), c.Build.Environment) c.Conf, err = parser.ParseSingle(injected, opts) if err != nil { return err } // and append the matrix parameters as environment // variables for the build for k, v := range c.Build.Environment { env := k + "=" + v c.Conf.Build.Environment = append(c.Conf.Build.Environment, env) } // and append drone, jenkins, travis and other // environment variables that may be of use. for k, v := range toEnv(c) { env := k + "=" + v c.Conf.Build.Environment = append(c.Conf.Build.Environment, env) } // attempt to extract the clone path. i'm not a huge fan of // this, by the way, but for now we'll keep it. // TODO consider moving this to a transform? pathv, ok := c.Conf.Clone.Config["path"] if ok { path, ok := pathv.(string) if ok { c.Clone.Dir = filepath.Join("/drone/src", path) } } return nil } type execFunc func(c *Context) (int, error) func execClone(c *Context) (int, error) { conf := toContainerConfig(c.Conf.Clone) conf.Cmd = toCommand(c, c.Conf.Clone) info, err := run(c.client, conf, c.Conf.Clone.Pull) if err != nil { return 255, err } return info.State.ExitCode, nil } func execBuild(c *Context) (int, error) { conf := toContainerConfig(c.Conf.Build) conf.Entrypoint = []string{"/bin/bash", "-e"} conf.Cmd = []string{"/drone/bin/build.sh"} info, err := run(c.client, conf, c.Conf.Build.Pull) if err != nil { return 255, err } return info.State.ExitCode, nil } func execSetup(c *Context) (int, error) { conf := toContainerConfig(c.Conf.Setup) conf.Cmd = toCommand(c, c.Conf.Setup) info, err := run(c.client, conf, c.Conf.Setup.Pull) if err != nil { return 255, err } return info.State.ExitCode, nil } func execDeploy(c *Context) (int, error) { return runSteps(c, c.Conf.Deploy) } func execPublish(c *Context) (int, error) { return runSteps(c, c.Conf.Publish) } func execNotify(c *Context) (int, error) { return runSteps(c, c.Conf.Notify) } func execCompose(c *Context) (int, error) { for _, step := range c.Conf.Compose { conf := toContainerConfig(step) _, err := daemon(c.client, conf, step.Pull) if err != nil { return 0, err } } return 0, nil } func trace(s string) string { cmd := fmt.Sprintf("$ %s\n", s) encoded := base64.StdEncoding.EncodeToString([]byte(cmd)) return fmt.Sprintf("echo %s | base64 --decode\n", encoded) } func newline(s string) string { return fmt.Sprintf("%s\n", s) } func runSteps(c *Context, steps map[string]*common.Step) (int, error) { for _, step := range steps { // verify the step matches the branch // and other specifications if step.Condition != nil { if !step.Condition.MatchOwner(c.Repo.Owner) || !step.Condition.MatchBranch(c.Clone.Branch) || !step.Condition.MatchMatrix(c.Build.Environment) { continue } } conf := toContainerConfig(step) conf.Cmd = toCommand(c, step) info, err := run(c.client, conf, step.Pull) if err != nil { return 255, err } else if info.State.ExitCode != 0 { return info.State.ExitCode, nil } } return 0, nil }