Пример #1
0
func execCmd(c *cli.Context) error {

	cert, _ := ioutil.ReadFile(filepath.Join(
		c.String("docker-cert-path"),
		"cert.pem",
	))

	key, _ := ioutil.ReadFile(filepath.Join(
		c.String("docker-cert-path"),
		"key.pem",
	))

	ca, _ := ioutil.ReadFile(filepath.Join(
		c.String("docker-cert-path"),
		"ca.pem",
	))
	if len(cert) == 0 || len(key) == 0 || len(ca) == 0 {
		println("")
	}

	yml, err := ioutil.ReadFile(".drone.yml")
	if err != nil {
		return err
	}

	axes, err := matrix.Parse(string(yml))
	if err != nil {
		return err
	}
	if len(axes) == 0 {
		axes = append(axes, matrix.Axis{})
	}

	cli, err := newDockerClient(c.String("docker-host"), cert, key, ca)
	if err != nil {
		return err
	}

	pwd, err := os.Getwd()
	if err != nil {
		return err
	}

	proj := resolvePath(pwd)

	var exits []int

	for i, axis := range axes {
		color.Magenta("[DRONE] starting job #%d", i+1)
		if len(axis) != 0 {
			color.Magenta("[DRONE] export %s", axis)
		}

		payload := struct {
			System    drone.System    `json:"system"`
			Workspace drone.Workspace `json:"workspace"`
			Repo      drone.Repo      `json:"repo"`
			Build     drone.Build     `json:"build"`
			Job       drone.Job       `json:"job"`
			Config    string          `json:"config"`
		}{
			Job: drone.Job{
				Status:      drone.StatusRunning,
				Environment: axis,
			},
			Config: string(yml),
			Build: drone.Build{
				Status: drone.StatusRunning,
				Commit: "0000000000", // hack
			},
		}
		if len(proj) != 0 {
			payload.Repo.Link = fmt.Sprintf("https://%s", proj)
		}
		out, _ := json.Marshal(payload)

		exit, err := run(cli, pwd, string(out))
		if err != nil {
			return err
		}
		exits = append(exits, exit)

		color.Magenta("[DRONE] finished job #%d", i+1)
		color.Magenta("[DRONE] exit code %d", exit)
	}

	var passed = true
	for i, _ := range axes {
		exit := exits[i]
		if exit == 0 {
			color.Green("[DRONE] job #%d passed", i+1)
		} else {
			color.Red("[DRONE] job #%d failed", i+1)
			passed = false
		}
	}
	if passed {
		color.Green("[DRONE] build passed")
	} else {
		color.Red("[DRONE] build failed")
		os.Exit(1)
	}

	return nil
}
Пример #2
0
func execCmd(c *cli.Context) error {
	info := git.Info()

	cert, _ := ioutil.ReadFile(filepath.Join(
		c.String("docker-cert-path"),
		"cert.pem",
	))

	key, _ := ioutil.ReadFile(filepath.Join(
		c.String("docker-cert-path"),
		"key.pem",
	))

	ca, _ := ioutil.ReadFile(filepath.Join(
		c.String("docker-cert-path"),
		"ca.pem",
	))
	if len(cert) == 0 || len(key) == 0 || len(ca) == 0 {
		println("")
	}

	yml, err := ioutil.ReadFile(".drone.yml")
	if err != nil {
		return err
	}

	axes, err := matrix.Parse(string(yml))
	if err != nil {
		return err
	}
	if len(axes) == 0 {
		axes = append(axes, matrix.Axis{})
	}

	cli, err := newDockerClient(c.String("docker-host"), cert, key, ca)
	if err != nil {
		return err
	}

	pwd, err := os.Getwd()
	if err != nil {
		return err
	}

	execArgs := []string{"--build", "--debug", "--mount", pwd}
	for _, arg := range []string{"cache", "deploy", "notify", "pull"} {
		if c.Bool(arg) {
			execArgs = append(execArgs, "--"+arg)
		}
	}

	proj := resolvePath(pwd)

	var exits []int

	for i, axis := range axes {
		color.Magenta("[DRONE] starting job #%d", i+1)
		if len(axis) != 0 {
			color.Magenta("[DRONE] export %s", axis)
		}

		payload := struct {
			System    drone.System    `json:"system"`
			Workspace drone.Workspace `json:"workspace"`
			Repo      drone.Repo      `json:"repo"`
			Build     drone.Build     `json:"build"`
			Job       drone.Job       `json:"job"`
			Netrc     drone.Netrc     `json:"netrc"`
			Keys      drone.Key       `json:"keys"`
			Config    string          `json:"config"`
		}{
			Repo: drone.Repo{
				IsTrusted: c.Bool("trusted"),
				IsPrivate: true,
			},
			Job: drone.Job{
				Status:      drone.StatusRunning,
				Environment: axis,
			},
			Config: string(yml),
			Build: drone.Build{
				Status:  drone.StatusRunning,
				Branch:  info.Branch,
				Commit:  info.Head.Id,
				Author:  info.Head.AuthorName,
				Email:   info.Head.AuthorEmail,
				Message: info.Head.Message,
				Event:   c.String("event"),
			},
			System: drone.System{
				Link:    c.GlobalString("server"),
				Globals: c.StringSlice("e"),
				Plugins: []string{"plugins/*", "*/*"},
			},
		}

		// gets the ssh key if provided
		if len(c.String("i")) != 0 {
			key, err = ioutil.ReadFile(c.String("i"))
			if err != nil {
				return err
			}
			payload.Keys = drone.Key{
				Private: string(key),
			}
			payload.Netrc = drone.Netrc{}
		}

		if len(proj) != 0 {
			payload.Repo.Link = fmt.Sprintf("https://%s", proj)
		}
		out, _ := json.Marshal(payload)

		exit, err := run(cli, execArgs, string(out))
		if err != nil {
			return err
		}
		exits = append(exits, exit)

		color.Magenta("[DRONE] finished job #%d", i+1)
		color.Magenta("[DRONE] exit code %d", exit)
	}

	var passed = true
	for i, _ := range axes {
		exit := exits[i]
		if exit == 0 {
			color.Green("[DRONE] job #%d passed", i+1)
		} else {
			color.Red("[DRONE] job #%d failed", i+1)
			passed = false
		}
	}
	if passed {
		color.Green("[DRONE] build passed")
	} else {
		color.Red("[DRONE] build failed")
		os.Exit(1)
	}

	return nil
}
Пример #3
0
func PostHook(c *gin.Context) {
	remote_ := remote.FromContext(c)

	tmprepo, build, err := remote_.Hook(c.Request)
	if err != nil {
		log.Errorf("failure to parse hook. %s", err)
		c.AbortWithError(400, err)
		return
	}
	if build == nil {
		c.Writer.WriteHeader(200)
		return
	}
	if tmprepo == nil {
		log.Errorf("failure to ascertain repo from hook.")
		c.Writer.WriteHeader(400)
		return
	}

	// skip the build if any case-insensitive combination of the words "skip" and "ci"
	// wrapped in square brackets appear in the commit message
	skipMatch := skipRe.FindString(build.Message)
	if len(skipMatch) > 0 {
		log.Infof("ignoring hook. %s found in %s", skipMatch, build.Commit)
		c.Writer.WriteHeader(204)
		return
	}

	repo, err := store.GetRepoOwnerName(c, tmprepo.Owner, tmprepo.Name)
	if err != nil {
		log.Errorf("failure to find repo %s/%s from hook. %s", tmprepo.Owner, tmprepo.Name, err)
		c.AbortWithError(404, err)
		return
	}

	// get the token and verify the hook is authorized
	parsed, err := token.ParseRequest(c.Request, func(t *token.Token) (string, error) {
		return repo.Hash, nil
	})
	if err != nil {
		log.Errorf("failure to parse token from hook for %s. %s", repo.FullName, err)
		c.AbortWithError(400, err)
		return
	}
	if parsed.Text != repo.FullName {
		log.Errorf("failure to verify token from hook. Expected %s, got %s", repo.FullName, parsed.Text)
		c.AbortWithStatus(403)
		return
	}

	if repo.UserID == 0 {
		log.Warnf("ignoring hook. repo %s has no owner.", repo.FullName)
		c.Writer.WriteHeader(204)
		return
	}
	var skipped = true
	if (build.Event == model.EventPush && repo.AllowPush) ||
		(build.Event == model.EventPull && repo.AllowPull) ||
		(build.Event == model.EventDeploy && repo.AllowDeploy) ||
		(build.Event == model.EventTag && repo.AllowTag) {
		skipped = false
	}

	if skipped {
		log.Infof("ignoring hook. repo %s is disabled for %s events.", repo.FullName, build.Event)
		c.Writer.WriteHeader(204)
		return
	}

	user, err := store.GetUser(c, repo.UserID)
	if err != nil {
		log.Errorf("failure to find repo owner %s. %s", repo.FullName, err)
		c.AbortWithError(500, err)
		return
	}

	// if there is no email address associated with the pull request,
	// we lookup the email address based on the authors github login.
	//
	// my initial hesitation with this code is that it has the ability
	// to expose your email address. At the same time, your email address
	// is already exposed in the public .git log. So while some people will
	// a small number of people will probably be upset by this, I'm not sure
	// it is actually that big of a deal.
	if len(build.Email) == 0 {
		author, err := store.GetUserLogin(c, build.Author)
		if err == nil {
			build.Email = author.Email
		}
	}

	// if the remote has a refresh token, the current access token
	// may be stale. Therefore, we should refresh prior to dispatching
	// the job.
	if refresher, ok := remote_.(remote.Refresher); ok {
		ok, _ := refresher.Refresh(user)
		if ok {
			store.UpdateUser(c, user)
		}
	}

	// fetch the .drone.yml file from the database
	raw, sec, err := remote_.Script(user, repo, build)
	if err != nil {
		log.Errorf("failure to get .drone.yml for %s. %s", repo.FullName, err)
		c.AbortWithError(404, err)
		return
	}

	axes, err := matrix.Parse(string(raw))
	if err != nil {
		log.Errorf("failure to calculate matrix for %s. %s", repo.FullName, err)
		c.AbortWithError(400, err)
		return
	}
	if len(axes) == 0 {
		axes = append(axes, matrix.Axis{})
	}

	netrc, err := remote_.Netrc(user, repo)
	if err != nil {
		log.Errorf("failure to generate netrc for %s. %s", repo.FullName, err)
		c.AbortWithError(500, err)
		return
	}

	key, _ := store.GetKey(c, repo)

	// verify the branches can be built vs skipped
	yconfig, _ := yaml.Parse(string(raw))
	var match = false
	for _, branch := range yconfig.Branches {
		if branch == build.Branch {
			match = true
			break
		}
		match, _ = filepath.Match(branch, build.Branch)
		if match {
			break
		}
	}
	if !match && len(yconfig.Branches) != 0 {
		log.Infof("ignoring hook. yaml file excludes repo and branch %s %s", repo.FullName, build.Branch)
		c.AbortWithStatus(200)
		return
	}

	// update some build fields
	build.Status = model.StatusPending
	build.RepoID = repo.ID

	// and use a transaction
	var jobs []*model.Job
	for num, axis := range axes {
		jobs = append(jobs, &model.Job{
			BuildID:     build.ID,
			Number:      num + 1,
			Status:      model.StatusPending,
			Environment: axis,
		})
	}
	err = store.CreateBuild(c, build, jobs...)
	if err != nil {
		log.Errorf("failure to save commit for %s. %s", repo.FullName, err)
		c.AbortWithError(500, err)
		return
	}

	c.JSON(200, build)

	url := fmt.Sprintf("%s/%s/%d", httputil.GetURL(c.Request), repo.FullName, build.Number)
	err = remote_.Status(user, repo, build, url)
	if err != nil {
		log.Errorf("error setting commit status for %s/%d", repo.FullName, build.Number)
	}

	// get the previous build so taht we can send
	// on status change notifications
	last, _ := store.GetBuildLastBefore(c, repo, build.Branch, build.ID)

	engine_ := context.Engine(c)
	go engine_.Schedule(c.Copy(), &engine.Task{
		User:      user,
		Repo:      repo,
		Build:     build,
		BuildPrev: last,
		Jobs:      jobs,
		Keys:      key,
		Netrc:     netrc,
		Config:    string(raw),
		Secret:    string(sec),
		System: &model.System{
			Link:    httputil.GetURL(c.Request),
			Plugins: strings.Split(os.Getenv("PLUGIN_FILTER"), " "),
			Globals: strings.Split(os.Getenv("PLUGIN_PARAMS"), " "),
		},
	})

}
Пример #4
0
func execCmd(c *cli.Context) error {
	info := git.Info()

	cert, _ := ioutil.ReadFile(filepath.Join(
		c.String("docker-cert-path"),
		"cert.pem",
	))

	key, _ := ioutil.ReadFile(filepath.Join(
		c.String("docker-cert-path"),
		"key.pem",
	))

	ca, _ := ioutil.ReadFile(filepath.Join(
		c.String("docker-cert-path"),
		"ca.pem",
	))
	if len(cert) == 0 || len(key) == 0 || len(ca) == 0 {
		println("")
	}

	yml, err := ioutil.ReadFile(".drone.yml")
	if err != nil {
		return err
	}

	// initially populate globals from the '-e' slice
	globals := c.StringSlice("e")
	if c.IsSet("E") {
		// read the .drone.sec.yml file (plain text)
		plaintext, err := readInput(c.String("E"))
		if err != nil {
			return err
		}

		// parse the plaintext secrets file
		sec := new(secure.Secure)
		err = yaml.Unmarshal(plaintext, sec)
		if err != nil {
			return err
		}

		// prepend values into globals (allow '-e' to override the secrets file)
		for k, v := range sec.Environment.Map() {
			tmp := strings.Join([]string{k, v}, "=")
			globals = append([]string{tmp}, globals...)
		}
	}

	axes, err := matrix.Parse(string(yml))
	if err != nil {
		return err
	}
	if len(axes) == 0 {
		axes = append(axes, matrix.Axis{})
	}

	cli, err := newDockerClient(c.String("docker-host"), cert, key, ca)
	if err != nil {
		return err
	}

	pwd, err := os.Getwd()
	if err != nil {
		return err
	}

	execArgs := []string{"--build", "--debug", "--mount", pwd}
	for _, arg := range []string{"cache", "deploy", "notify", "pull"} {
		if c.Bool(arg) {
			execArgs = append(execArgs, "--"+arg)
		}
	}
	if c.Bool("pull") {
		image := "drone/drone-exec:latest"
		color.Magenta("[DRONE] pulling %s", image)
		err := cli.PullImage(image, nil)
		if err != nil {
			color.Red("[DRONE] failed to pull %s", image)
			os.Exit(1)
		}
	}

	proj := resolvePath(pwd)

	var exits []int

	for i, axis := range axes {
		color.Magenta("[DRONE] starting job #%d", i+1)
		if len(axis) != 0 {
			color.Magenta("[DRONE] export %s", axis)
		}

		payload := drone.Payload{
			Repo: &drone.Repo{
				IsTrusted: c.Bool("trusted"),
				IsPrivate: true,
			},
			Job: &drone.Job{
				Status:      drone.StatusRunning,
				Environment: axis,
			},
			Yaml: string(yml),
			Build: &drone.Build{
				Status:  drone.StatusRunning,
				Branch:  info.Branch,
				Commit:  info.Head.ID,
				Author:  info.Head.AuthorName,
				Email:   info.Head.AuthorEmail,
				Message: info.Head.Message,
				Event:   c.String("event"),
			},
			System: &drone.System{
				Link:    c.GlobalString("server"),
				Globals: globals,
				Plugins: []string{"plugins/*", "*/*"},
			},
		}

		// gets the ssh key if provided
		if len(c.String("i")) != 0 {
			key, err = ioutil.ReadFile(c.String("i"))
			if err != nil {
				return err
			}
			payload.Keys = &drone.Key{
				Private: string(key),
			}
			payload.Netrc = &drone.Netrc{}
		}

		if len(proj) != 0 {
			payload.Repo.Link = fmt.Sprintf("https://%s", proj)
		}
		out, _ := json.Marshal(payload)

		exit, err := run(cli, execArgs, string(out))
		if err != nil {
			return err
		}
		exits = append(exits, exit)

		color.Magenta("[DRONE] finished job #%d", i+1)
		color.Magenta("[DRONE] exit code %d", exit)
	}

	var passed = true
	for i, _ := range axes {
		exit := exits[i]
		if exit == 0 {
			color.Green("[DRONE] job #%d passed", i+1)
		} else {
			color.Red("[DRONE] job #%d failed", i+1)
			passed = false
		}
	}
	if passed {
		color.Green("[DRONE] build passed")
	} else {
		color.Red("[DRONE] build failed")
		os.Exit(1)
	}

	return nil
}