func (a *Agent) prep(w *queue.Work) (*yaml.Config, error) { envs := toEnv(w) w.Yaml = expander.ExpandString(w.Yaml, envs) // inject the netrc file into the clone plugin if the repository is // private and requires authentication. var secrets []*model.Secret if w.Verified { secrets = append(secrets, w.Secrets...) } if w.Repo.IsPrivate { secrets = append(secrets, &model.Secret{ Name: "DRONE_NETRC_USERNAME", Value: w.Netrc.Login, Images: []string{"*"}, Events: []string{"*"}, }) secrets = append(secrets, &model.Secret{ Name: "DRONE_NETRC_PASSWORD", Value: w.Netrc.Password, Images: []string{"*"}, Events: []string{"*"}, }) secrets = append(secrets, &model.Secret{ Name: "DRONE_NETRC_MACHINE", Value: w.Netrc.Machine, Images: []string{"*"}, Events: []string{"*"}, }) } conf, err := yaml.ParseString(w.Yaml) if err != nil { return nil, err } src := "src" if url, _ := url.Parse(w.Repo.Link); url != nil { host, _, err := net.SplitHostPort(url.Host) if err == nil { url.Host = host } src = filepath.Join(src, url.Host, url.Path) } transform.Clone(conf, w.Repo.Kind) transform.Environ(conf, envs) transform.DefaultFilter(conf) if w.BuildLast != nil { transform.ChangeFilter(conf, w.BuildLast.Status) } transform.ImageSecrets(conf, secrets, w.Build.Event) transform.Identifier(conf) transform.WorkspaceTransform(conf, "/drone", src) if err := transform.Check(conf, w.Repo.IsTrusted); err != nil { return nil, err } transform.CommandTransform(conf) transform.ImagePull(conf, a.Pull) transform.ImageTag(conf) transform.ImageName(conf) transform.ImageNamespace(conf, a.Namespace) if err := transform.ImageEscalate(conf, a.Escalate); err != nil { return nil, err } transform.PluginParams(conf) if a.Local != "" { transform.PluginDisable(conf, a.Disable) transform.ImageVolume(conf, []string{a.Local + ":" + conf.Workspace.Path}) } transform.Pod(conf) return conf, nil }
func (r *pipeline) run() error { w, err := r.drone.Pull("linux", "amd64") if err != nil { return err } logrus.Infof("Starting build %s/%s#%d.%d", w.Repo.Owner, w.Repo.Name, w.Build.Number, w.Job.Number) w.Job.Status = model.StatusRunning w.Job.Started = time.Now().Unix() prefix := fmt.Sprintf("drone_%s", uniuri.New()) envs := toEnv(w) w.Yaml = expander.ExpandString(w.Yaml, envs) // inject the netrc file into the clone plugin if the repositroy is // private and requires authentication. var secrets []*model.Secret if w.Verified { secrets = append(secrets, w.Secrets...) } if w.Repo.IsPrivate { secrets = append(secrets, &model.Secret{ Name: "DRONE_NETRC_USERNAME", Value: w.Netrc.Login, Images: []string{"*"}, Events: []string{"*"}, }) secrets = append(secrets, &model.Secret{ Name: "DRONE_NETRC_PASSWORD", Value: w.Netrc.Password, Images: []string{"*"}, Events: []string{"*"}, }) secrets = append(secrets, &model.Secret{ Name: "DRONE_NETRC_MACHINE", Value: w.Netrc.Machine, Images: []string{"*"}, Events: []string{"*"}, }) } var lastStatus string if w.BuildLast != nil { lastStatus = w.BuildLast.Status } trans := []compiler.Transform{ builtin.NewCloneOp("git", true), builtin.NewCacheOp( "plugins/cache:latest", "/var/lib/drone/cache/"+w.Repo.FullName, false, ), builtin.NewSecretOp(w.Build.Event, secrets), builtin.NewNormalizeOp(r.config.namespace), builtin.NewWorkspaceOp("/drone", "/drone/src/github.com/"+w.Repo.FullName), builtin.NewValidateOp( w.Repo.IsTrusted, r.config.whitelist, ), builtin.NewEnvOp(envs), builtin.NewShellOp(builtin.Linux_adm64), builtin.NewArgsOp(), builtin.NewEscalateOp(r.config.privileged), builtin.NewPodOp(prefix), builtin.NewAliasOp(prefix), builtin.NewPullOp(r.config.pull), builtin.NewFilterOp( lastStatus, w.Build.Branch, w.Build.Event, w.Build.Deploy, w.Job.Environment, ), } compile := compiler.New() compile.Transforms(trans) spec, err := compile.CompileString(w.Yaml) if err != nil { w.Job.Error = err.Error() w.Job.ExitCode = 255 w.Job.Finished = w.Job.Started w.Job.Status = model.StatusError pushRetry(r.drone, w) return nil } pushRetry(r.drone, w) conf := runner.Config{ Engine: docker.New(r.docker), } c := context.TODO() c, timout := context.WithTimeout(c, time.Minute*time.Duration(w.Repo.Timeout)) c, cancel := context.WithCancel(c) defer cancel() defer timout() run := conf.Runner(c, spec) run.Run() wait := r.drone.Wait(w.Job.ID) defer wait.Cancel() go func() { if _, err := wait.Done(); err == nil { logrus.Infof("Cancel build %s/%s#%d.%d", w.Repo.Owner, w.Repo.Name, w.Build.Number, w.Job.Number) cancel() } }() rc, wc := io.Pipe() go func() { // TODO(bradrydzewski) figure out how to resume upload on failure err := r.drone.Stream(w.Job.ID, rc) if err != nil && err != io.ErrClosedPipe { logrus.Errorf("Error streaming build logs. %s", err) } }() pipe := run.Pipe() for { line := pipe.Next() if line == nil { break } linejson, _ := json.Marshal(line) wc.Write(linejson) wc.Write([]byte{'\n'}) } err = run.Wait() pipe.Close() wc.Close() rc.Close() // catch the build result if err != nil { w.Job.ExitCode = 255 } if exitErr, ok := err.(*runner.ExitError); ok { w.Job.ExitCode = exitErr.Code } w.Job.Finished = time.Now().Unix() switch w.Job.ExitCode { case 128, 130, 137: w.Job.Status = model.StatusKilled case 0: w.Job.Status = model.StatusSuccess default: w.Job.Status = model.StatusFailure } pushRetry(r.drone, w) logrus.Infof("Finished build %s/%s#%d.%d", w.Repo.Owner, w.Repo.Name, w.Build.Number, w.Job.Number) return nil }