2015-05-13 01:32:46 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/base64"
|
|
|
|
"fmt"
|
2015-05-13 03:30:36 +00:00
|
|
|
"path/filepath"
|
2015-05-13 01:32:46 +00:00
|
|
|
|
2015-05-17 20:51:42 +00:00
|
|
|
common "github.com/drone/drone/pkg/types"
|
2015-05-17 18:48:02 +00:00
|
|
|
"github.com/drone/drone/pkg/yaml"
|
|
|
|
"github.com/drone/drone/pkg/yaml/inject"
|
2015-05-13 01:32:46 +00:00
|
|
|
"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
|
2015-05-16 02:41:22 +00:00
|
|
|
var opts = parser.DefaultOpts
|
|
|
|
|
|
|
|
// if repository is trusted the build may specify
|
|
|
|
// custom volumes, networking and run in trusted mode.
|
|
|
|
if c.Repo.Trusted {
|
2015-05-17 00:46:29 +00:00
|
|
|
opts = &parser.Opts{Network: true, Privileged: true, Volumes: true}
|
2015-05-16 02:41:22 +00:00
|
|
|
}
|
2015-05-13 01:32:46 +00:00
|
|
|
|
|
|
|
// inject the matrix parameters into the yaml
|
|
|
|
injected := inject.Inject(string(c.Yaml), c.Build.Environment)
|
2015-05-17 00:46:29 +00:00
|
|
|
c.Conf, err = parser.ParseSingle(injected, opts)
|
2015-05-13 01:32:46 +00:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2015-05-13 03:30:36 +00:00
|
|
|
// 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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-13 01:32:46 +00:00
|
|
|
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
|
2015-05-15 21:55:26 +00:00
|
|
|
if step.Condition != nil {
|
|
|
|
if !step.Condition.MatchOwner(c.Repo.Owner) ||
|
|
|
|
!step.Condition.MatchBranch(c.Clone.Branch) ||
|
|
|
|
!step.Condition.MatchMatrix(c.Build.Environment) {
|
|
|
|
continue
|
|
|
|
}
|
2015-05-13 01:32:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
}
|