Add custom build parameters support to build re-start and deploy

This commit is contained in:
Vaidas Jablonskis 2016-07-27 22:11:54 +01:00
parent ae418bf063
commit 7170cd6758
7 changed files with 80 additions and 12 deletions

View file

@ -76,21 +76,21 @@ type Client interface {
BuildQueue() ([]*model.Feed, error)
// BuildStart re-starts a stopped build.
BuildStart(string, string, int) (*model.Build, error)
BuildStart(string, string, int, map[string]string) (*model.Build, error)
// BuildStop stops the specified running job for given build.
BuildStop(string, string, int, int) error
// BuildFork re-starts a stopped build with a new build number, preserving
// the prior history.
BuildFork(string, string, int) (*model.Build, error)
BuildFork(string, string, int, map[string]string) (*model.Build, error)
// BuildLogs returns the build logs for the specified job.
BuildLogs(string, string, int, int) (io.ReadCloser, error)
// Deploy triggers a deployment for an existing build using the specified
// target environment.
Deploy(string, string, int, string) (*model.Build, error)
Deploy(string, string, int, string, map[string]string) (*model.Build, error)
// AgentList returns a list of build agents.
AgentList() ([]*model.Agent, error)

View file

@ -217,9 +217,10 @@ func (c *client) BuildQueue() ([]*model.Feed, error) {
}
// BuildStart re-starts a stopped build.
func (c *client) BuildStart(owner, name string, num int) (*model.Build, error) {
func (c *client) BuildStart(owner, name string, num int, params map[string]string) (*model.Build, error) {
out := new(model.Build)
uri := fmt.Sprintf(pathBuild, c.base, owner, name, num)
val := parseToQueryParams(params)
uri := fmt.Sprintf(pathBuild+"?"+val.Encode(), c.base, owner, name, num)
err := c.post(uri, nil, out)
return out, err
}
@ -233,9 +234,11 @@ func (c *client) BuildStop(owner, name string, num, job int) error {
// BuildFork re-starts a stopped build with a new build number,
// preserving the prior history.
func (c *client) BuildFork(owner, name string, num int) (*model.Build, error) {
func (c *client) BuildFork(owner, name string, num int, params map[string]string) (*model.Build, error) {
out := new(model.Build)
uri := fmt.Sprintf(pathBuild+"?fork=true", c.base, owner, name, num)
val := parseToQueryParams(params)
val.Set("fork", "true")
uri := fmt.Sprintf(pathBuild+"?"+val.Encode(), c.base, owner, name, num)
err := c.post(uri, nil, out)
return out, err
}
@ -248,9 +251,9 @@ func (c *client) BuildLogs(owner, name string, num, job int) (io.ReadCloser, err
// Deploy triggers a deployment for an existing build using the
// specified target environment.
func (c *client) Deploy(owner, name string, num int, env string) (*model.Build, error) {
func (c *client) Deploy(owner, name string, num int, env string, params map[string]string) (*model.Build, error) {
out := new(model.Build)
val := url.Values{}
val := parseToQueryParams(params)
val.Set("fork", "true")
val.Set("event", "deployment")
val.Set("deploy_to", env)
@ -523,3 +526,12 @@ func (c *client) createRequest(rawurl, method string, in interface{}) (*http.Req
}
return req, nil
}
// parseToQueryParams parses a map of strings and returns url.Values
func parseToQueryParams(p map[string]string) url.Values {
values := url.Values{}
for k, v := range p {
values.Add(k, v)
}
return values
}

View file

@ -22,6 +22,10 @@ var buildStartCmd = cli.Command{
Name: "fork",
Usage: "fork the build",
},
cli.StringSliceFlag{
Name: "param, p",
Usage: "custom parameters to be injected into the job environment. Format: KEY=value",
},
},
}
@ -41,11 +45,13 @@ func buildStart(c *cli.Context) (err error) {
return err
}
params := parseKVPairs(c.StringSlice("param"))
var build *model.Build
if c.Bool("fork") {
build, err = client.BuildFork(owner, name, number)
build, err = client.BuildFork(owner, name, number, params)
} else {
build, err = client.BuildStart(owner, name, number)
build, err = client.BuildStart(owner, name, number, params)
}
if err != nil {
return err

View file

@ -25,6 +25,10 @@ var deployCmd = cli.Command{
Usage: "format output",
Value: tmplDeployInfo,
},
cli.StringSliceFlag{
Name: "param, p",
Usage: "custom parameters to be injected into the job environment. Format: KEY=value",
},
},
}
@ -56,7 +60,9 @@ func deploy(c *cli.Context) error {
return fmt.Errorf("Please specify the target environment (ie production)")
}
deploy, err := client.Deploy(owner, name, number, env)
params := parseKVPairs(c.StringSlice("param"))
deploy, err := client.Deploy(owner, name, number, env, params)
if err != nil {
return err
}

View file

@ -61,3 +61,15 @@ func stringInSlice(a string, list []string) bool {
return false
}
func parseKVPairs(p []string) map[string]string {
params := map[string]string{}
for _, i := range p {
parts := strings.Split(i, "=")
if len(parts) != 2 {
continue
}
params[parts[0]] = parts[1]
}
return params
}

17
drone/util_test.go Normal file
View file

@ -0,0 +1,17 @@
package main
import "testing"
func Test_parseKVPairs(t *testing.T) {
s := []string{"FOO=bar", "BAR=", "INVALID"}
p := parseKVPairs(s)
if p["FOO"] != "bar" {
t.Errorf("Wanted %q, got %q.", "bar", p["FOO"])
}
if _, exists := p["BAR"]; !exists {
t.Error("Missing a key with no value. Keys with empty values are also valid.")
}
if _, exists := p["INVALID"]; exists {
t.Error("Keys without an equal sign suffix are invalid.")
}
}

View file

@ -248,6 +248,18 @@ func PostBuild(c *gin.Context) {
build.Deploy = c.DefaultQuery("deploy_to", build.Deploy)
}
// Read query string parameters into buildParams, exclude reserved params
var buildParams = map[string]string{}
for key, val := range c.Request.URL.Query() {
switch key {
case "fork", "event", "deply_to":
default:
// We only accept string literals, because build parameters will be
// injected as environment variables
buildParams[key] = val[0]
}
}
// todo move this to database tier
// and wrap inside a transaction
build.Status = model.StatusPending
@ -255,6 +267,9 @@ func PostBuild(c *gin.Context) {
build.Finished = 0
build.Enqueued = time.Now().UTC().Unix()
for _, job := range jobs {
for k, v := range buildParams {
job.Environment[k] = v
}
job.Error = ""
job.Status = model.StatusPending
job.Started = 0