From a9f2affd5cb231ed16d5b633e752a728a72a9f42 Mon Sep 17 00:00:00 2001 From: Brad Rydzewski Date: Sun, 7 Sep 2014 23:08:35 -0700 Subject: [PATCH] updated all deployments to include conditional logic --- plugin/condition/condition.go | 14 +++- plugin/condition/condition_test.go | 113 +++++++++++++++++++++++++++++ plugin/deploy/bash.go | 7 ++ plugin/deploy/cloudfoundry.go | 7 ++ plugin/deploy/deployment.go | 47 ++++++------ plugin/deploy/git.go | 7 ++ plugin/deploy/heroku.go | 7 ++ plugin/deploy/modulus.go | 7 ++ plugin/deploy/nodejitsu.go | 7 ++ plugin/deploy/ssh.go | 7 ++ plugin/deploy/tsuru.go | 13 +++- shared/build/script/script.go | 2 +- 12 files changed, 212 insertions(+), 26 deletions(-) create mode 100644 plugin/condition/condition_test.go diff --git a/plugin/condition/condition.go b/plugin/condition/condition.go index 1eaed11b3..9a6bc2a70 100644 --- a/plugin/condition/condition.go +++ b/plugin/condition/condition.go @@ -1,5 +1,9 @@ package condition +import ( + "strings" +) + type Condition struct { Owner string // Indicates the step should run only for this repo (useful for forks) Branch string // Indicates the step should run only for this branch @@ -49,5 +53,13 @@ func (c *Condition) MatchOwner(owner string) bool { if len(c.Owner) == 0 { return true } - return c.Owner == owner + parts := strings.Split(owner, "/") + switch len(parts) { + case 2: + return c.Owner == parts[0] + case 3: + return c.Owner == parts[1] + default: + return c.Owner == owner + } } diff --git a/plugin/condition/condition_test.go b/plugin/condition/condition_test.go new file mode 100644 index 000000000..8a007e154 --- /dev/null +++ b/plugin/condition/condition_test.go @@ -0,0 +1,113 @@ +package condition + +import ( + "testing" +) + +type Bool bool + +func Test_MatchPullRequest(t *testing.T) { + + var c = Condition{} + var got, want = c.MatchPullRequest(""), true + if got != want { + t.Errorf("Non-pull requests are always enabled, expected %v, got %v", want, got) + } + + got, want = c.MatchPullRequest("65"), false + if got != want { + t.Errorf("Pull requests should be disabled by default, expected %v, got %v", want, got) + } + + c.PullRequest = new(bool) + *c.PullRequest = false + got, want = c.MatchPullRequest("65"), false + if got != want { + t.Errorf("Pull requests can be explicity disabled, expected %v, got %v", want, got) + } + + c.PullRequest = new(bool) + *c.PullRequest = true + got, want = c.MatchPullRequest("65"), true + if got != want { + t.Errorf("Pull requests can be explicitly enabled, expected %v, got %v", want, got) + } +} + +func Test_MatchBranch(t *testing.T) { + + var c = Condition{} + var got, want = c.MatchBranch("master"), true + if got != want { + t.Errorf("All branches should be enabled by default, expected %v, got %v", want, got) + } + + c.Branch = "" + got, want = c.MatchBranch("master"), true + if got != want { + t.Errorf("Empty branch should match, expected %v, got %v", want, got) + } + + c.Branch = "master" + got, want = c.MatchBranch("master"), true + if got != want { + t.Errorf("Branch should match, expected %v, got %v", want, got) + } + + c.Branch = "master" + got, want = c.MatchBranch("dev"), false + if got != want { + t.Errorf("Branch should not match, expected %v, got %v", want, got) + } +} + +func Test_MatchOwner(t *testing.T) { + + var c = Condition{} + var got, want = c.MatchOwner("drone"), true + if got != want { + t.Errorf("All owners should be enabled by default, expected %v, got %v", want, got) + } + + c.Owner = "" + got, want = c.MatchOwner("drone"), true + if got != want { + t.Errorf("Empty owner should match, expected %v, got %v", want, got) + } + + c.Owner = "drone" + got, want = c.MatchOwner("drone"), true + if got != want { + t.Errorf("Owner should match, expected %v, got %v", want, got) + } + + c.Owner = "drone" + got, want = c.MatchOwner("drone/config"), true + if got != want { + t.Errorf("Owner/Repo should match, expected %v, got %v", want, got) + } + + c.Owner = "drone" + got, want = c.MatchOwner("github.com/drone/config"), true + if got != want { + t.Errorf("Host/Owner/Repo should match, expected %v, got %v", want, got) + } + + c.Owner = "bradrydzewski" + got, want = c.MatchOwner("drone"), false + if got != want { + t.Errorf("Owner should not match, expected %v, got %v", want, got) + } + + c.Owner = "drone" + got, want = c.MatchOwner("bradrydzewski/drone"), false + if got != want { + t.Errorf("Owner/Repo should not match, expected %v, got %v", want, got) + } + + c.Owner = "drone" + got, want = c.MatchOwner("github.com/bradrydzewski/drone"), false + if got != want { + t.Errorf("Host/Owner/Repo should not match, expected %v, got %v", want, got) + } +} diff --git a/plugin/deploy/bash.go b/plugin/deploy/bash.go index 715639b5a..983cba663 100644 --- a/plugin/deploy/bash.go +++ b/plugin/deploy/bash.go @@ -1,12 +1,15 @@ package deploy import ( + "github.com/drone/drone/plugin/condition" "github.com/drone/drone/shared/build/buildfile" ) type Bash struct { Script []string `yaml:"script,omitempty"` Command string `yaml:"command,omitempty"` + + Condition *condition.Condition `yaml:"when,omitempty"` } func (g *Bash) Write(f *buildfile.Buildfile) { @@ -16,3 +19,7 @@ func (g *Bash) Write(f *buildfile.Buildfile) { f.WriteCmd(cmd) } } + +func (g *Bash) GetCondition() *condition.Condition { + return g.Condition +} diff --git a/plugin/deploy/cloudfoundry.go b/plugin/deploy/cloudfoundry.go index d90782c4a..872b69b49 100644 --- a/plugin/deploy/cloudfoundry.go +++ b/plugin/deploy/cloudfoundry.go @@ -2,6 +2,7 @@ package deploy import ( "fmt" + "github.com/drone/drone/plugin/condition" "github.com/drone/drone/shared/build/buildfile" ) @@ -13,6 +14,8 @@ type CloudFoundry struct { Space string `yaml:"space,omitempty"` App string `yaml:"app,omitempty"` + + Condition *condition.Condition `yaml:"when,omitempty"` } func (cf *CloudFoundry) Write(f *buildfile.Buildfile) { @@ -42,3 +45,7 @@ func (cf *CloudFoundry) Write(f *buildfile.Buildfile) { pushCmd := "cf push %s" f.WriteCmd(fmt.Sprintf(pushCmd, cf.App)) } + +func (cf *CloudFoundry) GetCondition() *condition.Condition { + return cf.Condition +} diff --git a/plugin/deploy/deployment.go b/plugin/deploy/deployment.go index 9619238d6..1f28cf69b 100644 --- a/plugin/deploy/deployment.go +++ b/plugin/deploy/deployment.go @@ -1,7 +1,9 @@ package deploy import ( + "github.com/drone/drone/plugin/condition" "github.com/drone/drone/shared/build/buildfile" + "github.com/drone/drone/shared/build/repo" ) // Deploy stores the configuration details @@ -22,41 +24,44 @@ type Deploy struct { Bash *Bash `yaml:"bash,omitempty"` } -func (d *Deploy) Write(f *buildfile.Buildfile) { - if d.AppFog != nil { - d.AppFog.Write(f) - } - if d.CloudControl != nil { - d.CloudControl.Write(f) - } - if d.CloudFoundry != nil { +func (d *Deploy) Write(f *buildfile.Buildfile, r *repo.Repo) { + + if d.CloudFoundry != nil && match(d.CloudFoundry.GetCondition(), r) { d.CloudFoundry.Write(f) } - if d.EngineYard != nil { - d.EngineYard.Write(f) - } - if d.Git != nil { + if d.Git != nil && match(d.Git.GetCondition(), r) { d.Git.Write(f) } - if d.Heroku != nil { + if d.Heroku != nil && match(d.Heroku.GetCondition(), r) { d.Heroku.Write(f) } - if d.Modulus != nil { + if d.Modulus != nil && match(d.Modulus.GetCondition(), r) { d.Modulus.Write(f) } - if d.Nodejitsu != nil { + if d.Nodejitsu != nil && match(d.Nodejitsu.GetCondition(), r) { d.Nodejitsu.Write(f) } - if d.Openshift != nil { - d.Openshift.Write(f) - } - if d.SSH != nil { + if d.SSH != nil && match(d.SSH.GetCondition(), r) { d.SSH.Write(f) } - if d.Tsuru != nil { + if d.Tsuru != nil && match(d.Tsuru.GetCondition(), r) { d.Tsuru.Write(f) } - if d.Bash != nil { + if d.Bash != nil && match(d.Bash.GetCondition(), r) { d.Bash.Write(f) } } + +func match(c *condition.Condition, r *repo.Repo) bool { + switch { + case c == nil: + return true + case !c.MatchBranch(r.Branch): + return false + case !c.MatchOwner(r.Name): + return false + case !c.MatchPullRequest(r.PR): + return false + } + return true +} diff --git a/plugin/deploy/git.go b/plugin/deploy/git.go index 37a48a136..d26d89cfb 100644 --- a/plugin/deploy/git.go +++ b/plugin/deploy/git.go @@ -2,6 +2,7 @@ package deploy import ( "fmt" + "github.com/drone/drone/plugin/condition" "github.com/drone/drone/shared/build/buildfile" ) @@ -9,6 +10,8 @@ type Git struct { Target string `yaml:"target,omitempty"` Force bool `yaml:"force,omitempty"` Branch string `yaml:"branch,omitempty"` + + Condition *condition.Condition `yaml:"when,omitempty"` } func (g *Git) Write(f *buildfile.Buildfile) { @@ -41,3 +44,7 @@ func (g *Git) Write(f *buildfile.Buildfile) { f.WriteCmd(fmt.Sprintf("git push deploy $COMMIT:%s", destinationBranch)) } } + +func (g *Git) GetCondition() *condition.Condition { + return g.Condition +} diff --git a/plugin/deploy/heroku.go b/plugin/deploy/heroku.go index 6742ef5fd..8379e0fc3 100644 --- a/plugin/deploy/heroku.go +++ b/plugin/deploy/heroku.go @@ -2,6 +2,7 @@ package deploy import ( "fmt" + "github.com/drone/drone/plugin/condition" "github.com/drone/drone/shared/build/buildfile" ) @@ -9,6 +10,8 @@ type Heroku struct { App string `yaml:"app,omitempty"` Force bool `yaml:"force,omitempty"` Branch string `yaml:"branch,omitempty"` + + Condition *condition.Condition `yaml:"when,omitempty"` } func (h *Heroku) Write(f *buildfile.Buildfile) { @@ -36,3 +39,7 @@ func (h *Heroku) Write(f *buildfile.Buildfile) { f.WriteCmd(fmt.Sprintf("git push heroku $COMMIT:master")) } } + +func (h *Heroku) GetCondition() *condition.Condition { + return h.Condition +} diff --git a/plugin/deploy/modulus.go b/plugin/deploy/modulus.go index b88cb2e32..be2b6f165 100644 --- a/plugin/deploy/modulus.go +++ b/plugin/deploy/modulus.go @@ -2,12 +2,15 @@ package deploy import ( "fmt" + "github.com/drone/drone/plugin/condition" "github.com/drone/drone/shared/build/buildfile" ) type Modulus struct { Project string `yaml:"project,omitempty"` Token string `yaml:"token,omitempty"` + + Condition *condition.Condition `yaml:"when,omitempty"` } func (m *Modulus) Write(f *buildfile.Buildfile) { @@ -19,3 +22,7 @@ func (m *Modulus) Write(f *buildfile.Buildfile) { f.WriteCmdSilent("[ -f /usr/bin/sudo ] && sudo npm install -g modulus") f.WriteCmd(fmt.Sprintf("modulus deploy -p '%s'", m.Project)) } + +func (m *Modulus) GetCondition() *condition.Condition { + return m.Condition +} diff --git a/plugin/deploy/nodejitsu.go b/plugin/deploy/nodejitsu.go index e6fbf437b..cf8f5b405 100644 --- a/plugin/deploy/nodejitsu.go +++ b/plugin/deploy/nodejitsu.go @@ -1,6 +1,7 @@ package deploy import ( + "github.com/drone/drone/plugin/condition" "github.com/drone/drone/shared/build/buildfile" ) @@ -8,6 +9,8 @@ type Nodejitsu struct { App string `yaml:"app,omitempty"` User string `yaml:"user,omitempty"` Token string `yaml:"token,omitempty"` + + Condition *condition.Condition `yaml:"when,omitempty"` } func (n *Nodejitsu) Write(f *buildfile.Buildfile) { @@ -20,3 +23,7 @@ func (n *Nodejitsu) Write(f *buildfile.Buildfile) { f.WriteCmdSilent("[ -f /usr/bin/sudo ] && sudo npm install -g jitsu") f.WriteCmd("jitsu deploy") } + +func (n *Nodejitsu) GetCondition() *condition.Condition { + return n.Condition +} diff --git a/plugin/deploy/ssh.go b/plugin/deploy/ssh.go index badf60056..0799dd88f 100644 --- a/plugin/deploy/ssh.go +++ b/plugin/deploy/ssh.go @@ -5,6 +5,7 @@ import ( "strconv" "strings" + "github.com/drone/drone/plugin/condition" "github.com/drone/drone/shared/build/buildfile" ) @@ -41,6 +42,8 @@ type SSH struct { // Cmd is a single command executed at target host after the artifacts // is deployed. Cmd string `yaml:"cmd,omitempty"` + + Condition *condition.Condition `yaml:"when,omitempty"` } // Write down the buildfile @@ -96,3 +99,7 @@ func compress(f *buildfile.Buildfile, files []string) bool { f.WriteCmdSilent(fmt.Sprintf(cmd, strings.Join(files, " "))) return true } + +func (s *SSH) GetCondition() *condition.Condition { + return s.Condition +} diff --git a/plugin/deploy/tsuru.go b/plugin/deploy/tsuru.go index 2feee0d22..a54954fa9 100644 --- a/plugin/deploy/tsuru.go +++ b/plugin/deploy/tsuru.go @@ -2,6 +2,7 @@ package deploy import ( "fmt" + "github.com/drone/drone/plugin/condition" "github.com/drone/drone/shared/build/buildfile" ) @@ -9,9 +10,11 @@ type Tsuru struct { Force bool `yaml:"force,omitempty"` Branch string `yaml:"branch,omitempty"` Remote string `yaml:"remote,omitempty"` + + Condition *condition.Condition `yaml:"when,omitempty"` } -func (h *Tsuru) Write(f *buildfile.Buildfile) { +func (t *Tsuru) Write(f *buildfile.Buildfile) { // get the current commit hash f.WriteCmdSilent("COMMIT=$(git rev-parse HEAD)") @@ -21,9 +24,9 @@ func (h *Tsuru) Write(f *buildfile.Buildfile) { f.WriteCmdSilent("git config --global user.email $(git --no-pager log -1 --pretty=format:'%ae')") // add tsuru as a git remote - f.WriteCmd(fmt.Sprintf("git remote add tsuru %s", h.Remote)) + f.WriteCmd(fmt.Sprintf("git remote add tsuru %s", t.Remote)) - switch h.Force { + switch t.Force { case true: // this is useful when the there are artifacts generated // by the build script, such as less files converted to css, @@ -36,3 +39,7 @@ func (h *Tsuru) Write(f *buildfile.Buildfile) { f.WriteCmd(fmt.Sprintf("git push tsuru $COMMIT:master")) } } + +func (t *Tsuru) GetCondition() *condition.Condition { + return t.Condition +} diff --git a/shared/build/script/script.go b/shared/build/script/script.go index 9f7d2d6ed..0819af92f 100644 --- a/shared/build/script/script.go +++ b/shared/build/script/script.go @@ -96,7 +96,7 @@ func (b *Build) Write(f *buildfile.Buildfile, r *repo.Repo) { // write deployment commands if b.Deploy != nil { - b.Deploy.Write(f) + b.Deploy.Write(f, r) } // write exit value