You've already forked woodpecker
							
							
				mirror of
				https://github.com/woodpecker-ci/woodpecker.git
				synced 2025-10-30 23:27:39 +02:00 
			
		
		
		
	removed yaml functions that were pushed down to the build layer
This commit is contained in:
		| @@ -1,74 +1,74 @@ | ||||
| package client | ||||
|  | ||||
| import ( | ||||
| 	"net" | ||||
| 	"net/http" | ||||
| 	"net/rpc" | ||||
| // import ( | ||||
| // 	"net" | ||||
| // 	"net/http" | ||||
| // 	"net/rpc" | ||||
|  | ||||
| 	common "github.com/drone/drone/pkg/types" | ||||
| ) | ||||
| // 	common "github.com/drone/drone/pkg/types" | ||||
| // ) | ||||
|  | ||||
| // Client communicates with a Remote plugin using the | ||||
| // net/rpc protocol. | ||||
| type Client struct { | ||||
| 	*rpc.Client | ||||
| } | ||||
| // // Client communicates with a Remote plugin using the | ||||
| // // net/rpc protocol. | ||||
| // type Client struct { | ||||
| // 	*rpc.Client | ||||
| // } | ||||
|  | ||||
| // New returns a new, remote datastore backend that connects | ||||
| // via tcp and exchanges data using Go's RPC mechanism. | ||||
| func New(conf *config.Config) (*Client, error) { | ||||
| 	// conn, err := net.Dial("tcp", conf.Server.Addr) | ||||
| 	// if err != nil { | ||||
| 	// 	return nil, err | ||||
| 	// } | ||||
| 	// client := &Client{ | ||||
| 	// 	rpc.NewClient(conn), | ||||
| 	// } | ||||
| 	// return client, nil | ||||
| 	return nil, nil | ||||
| } | ||||
| // // New returns a new, remote datastore backend that connects | ||||
| // // via tcp and exchanges data using Go's RPC mechanism. | ||||
| // func New(conf *config.Config) (*Client, error) { | ||||
| // 	// conn, err := net.Dial("tcp", conf.Server.Addr) | ||||
| // 	// if err != nil { | ||||
| // 	// 	return nil, err | ||||
| // 	// } | ||||
| // 	// client := &Client{ | ||||
| // 	// 	rpc.NewClient(conn), | ||||
| // 	// } | ||||
| // 	// return client, nil | ||||
| // 	return nil, nil | ||||
| // } | ||||
|  | ||||
| func (c *Client) Login(token, secret string) (*common.User, error) { | ||||
| 	return nil, nil | ||||
| } | ||||
| // func (c *Client) Login(token, secret string) (*common.User, error) { | ||||
| // 	return nil, nil | ||||
| // } | ||||
|  | ||||
| // Repo fetches the named repository from the remote system. | ||||
| func (c *Client) Repo(u *common.User, owner, repo string) (*common.Repo, error) { | ||||
| 	return nil, nil | ||||
| } | ||||
| // // Repo fetches the named repository from the remote system. | ||||
| // func (c *Client) Repo(u *common.User, owner, repo string) (*common.Repo, error) { | ||||
| // 	return nil, nil | ||||
| // } | ||||
|  | ||||
| func (c *Client) Perm(u *common.User, owner, repo string) (*common.Perm, error) { | ||||
| 	return nil, nil | ||||
| } | ||||
| // func (c *Client) Perm(u *common.User, owner, repo string) (*common.Perm, error) { | ||||
| // 	return nil, nil | ||||
| // } | ||||
|  | ||||
| func (c *Client) Script(u *common.User, r *common.Repo, b *common.Build) ([]byte, error) { | ||||
| 	return nil, nil | ||||
| } | ||||
| // func (c *Client) Script(u *common.User, r *common.Repo, b *common.Build) ([]byte, error) { | ||||
| // 	return nil, nil | ||||
| // } | ||||
|  | ||||
| func (c *Client) Status(u *common.User, r *common.Repo, b *common.Build, link string) error { | ||||
| 	return nil | ||||
| } | ||||
| // func (c *Client) Status(u *common.User, r *common.Repo, b *common.Build, link string) error { | ||||
| // 	return nil | ||||
| // } | ||||
|  | ||||
| func (c *Client) Activate(u *common.User, r *common.Repo, k *common.Keypair, link string) error { | ||||
| 	return nil | ||||
| } | ||||
| // func (c *Client) Activate(u *common.User, r *common.Repo, k *common.Keypair, link string) error { | ||||
| // 	return nil | ||||
| // } | ||||
|  | ||||
| func (c *Client) Deactivate(u *common.User, r *common.Repo, link string) error { | ||||
| 	return nil | ||||
| } | ||||
| // func (c *Client) Deactivate(u *common.User, r *common.Repo, link string) error { | ||||
| // 	return nil | ||||
| // } | ||||
|  | ||||
| func (c *Client) Hook(r *http.Request) (*common.Hook, error) { | ||||
| 	hook := new(common.Hook) | ||||
| 	header := make(http.Header) | ||||
| 	copyHeader(r.Header, header) | ||||
| // func (c *Client) Hook(r *http.Request) (*common.Hook, error) { | ||||
| // 	hook := new(common.Hook) | ||||
| // 	header := make(http.Header) | ||||
| // 	copyHeader(r.Header, header) | ||||
|  | ||||
| 	return hook, nil | ||||
| } | ||||
| // 	return hook, nil | ||||
| // } | ||||
|  | ||||
| func copyHeader(dst, src http.Header) { | ||||
| 	for k, vv := range src { | ||||
| 		for _, v := range vv { | ||||
| 			dst.Add(k, v) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| // func copyHeader(dst, src http.Header) { | ||||
| // 	for k, vv := range src { | ||||
| // 		for _, v := range vv { | ||||
| // 			dst.Add(k, v) | ||||
| // 		} | ||||
| // 	} | ||||
| // } | ||||
|   | ||||
| @@ -1,54 +0,0 @@ | ||||
| package inject | ||||
|  | ||||
| import ( | ||||
| 	"sort" | ||||
| 	"strings" | ||||
|  | ||||
| 	"github.com/drone/drone/Godeps/_workspace/src/gopkg.in/yaml.v2" | ||||
| 	"github.com/drone/drone/pkg/types" | ||||
| ) | ||||
|  | ||||
| // Inject injects a map of parameters into a raw string and returns | ||||
| // the resulting string. | ||||
| // | ||||
| // Parameters are represented in the string using $$ notation, similar | ||||
| // to how environment variables are defined in Makefiles. | ||||
| func Inject(raw string, params map[string]string) string { | ||||
| 	if params == nil { | ||||
| 		return raw | ||||
| 	} | ||||
| 	keys := []string{} | ||||
| 	for k := range params { | ||||
| 		keys = append(keys, k) | ||||
| 	} | ||||
| 	sort.Sort(sort.Reverse(sort.StringSlice(keys))) | ||||
| 	injected := raw | ||||
| 	for _, k := range keys { | ||||
| 		v := params[k] | ||||
| 		injected = strings.Replace(injected, "$$"+k, v, -1) | ||||
| 	} | ||||
| 	return injected | ||||
| } | ||||
|  | ||||
| // InjectSafe attempts to safely inject parameters without leaking | ||||
| // parameters in the Build or Compose section of the yaml file. | ||||
| // | ||||
| // The intended use case for this function are public pull requests. | ||||
| // We want to avoid a malicious pull request that allows someone | ||||
| // to inject and print private variables. | ||||
| func InjectSafe(raw string, params map[string]string) string { | ||||
| 	before, _ := parse(raw) | ||||
| 	after, _ := parse(Inject(raw, params)) | ||||
| 	before.Notify = after.Notify | ||||
| 	before.Publish = after.Publish | ||||
| 	before.Deploy = after.Deploy | ||||
| 	result, _ := yaml.Marshal(before) | ||||
| 	return string(result) | ||||
| } | ||||
|  | ||||
| // helper funtion to parse a yaml configuration file. | ||||
| func parse(raw string) (*types.Config, error) { | ||||
| 	cfg := types.Config{} | ||||
| 	err := yaml.Unmarshal([]byte(raw), &cfg) | ||||
| 	return &cfg, err | ||||
| } | ||||
| @@ -1,67 +0,0 @@ | ||||
| package inject | ||||
|  | ||||
| import ( | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/drone/drone/Godeps/_workspace/src/github.com/franela/goblin" | ||||
| ) | ||||
|  | ||||
| func Test_Inject(t *testing.T) { | ||||
|  | ||||
| 	g := goblin.Goblin(t) | ||||
| 	g.Describe("Inject params", func() { | ||||
|  | ||||
| 		g.It("Should replace vars with $$", func() { | ||||
| 			s := "echo $$FOO $BAR" | ||||
| 			m := map[string]string{} | ||||
| 			m["FOO"] = "BAZ" | ||||
| 			g.Assert("echo BAZ $BAR").Equal(Inject(s, m)) | ||||
| 		}) | ||||
|  | ||||
| 		g.It("Should not replace vars with single $", func() { | ||||
| 			s := "echo $FOO $BAR" | ||||
| 			m := map[string]string{} | ||||
| 			m["FOO"] = "BAZ" | ||||
| 			g.Assert(s).Equal(Inject(s, m)) | ||||
| 		}) | ||||
|  | ||||
| 		g.It("Should not replace vars in nil map", func() { | ||||
| 			s := "echo $$FOO $BAR" | ||||
| 			g.Assert(s).Equal(Inject(s, nil)) | ||||
| 		}) | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func Test_InjectSafe(t *testing.T) { | ||||
|  | ||||
| 	g := goblin.Goblin(t) | ||||
| 	g.Describe("Safely Inject params", func() { | ||||
|  | ||||
| 		m := map[string]string{} | ||||
| 		m["TOKEN"] = "FOO" | ||||
| 		m["SECRET"] = "BAR" | ||||
| 		c, _ := parse(InjectSafe(yml, m)) | ||||
|  | ||||
| 		g.It("Should replace vars in notify section", func() { | ||||
| 			g.Assert(c.Deploy["digital_ocean"].Config["token"]).Equal("FOO") | ||||
| 			g.Assert(c.Deploy["digital_ocean"].Config["secret"]).Equal("BAR") | ||||
| 		}) | ||||
|  | ||||
| 		g.It("Should not replace vars in script section", func() { | ||||
| 			g.Assert(c.Build.Config["commands"].([]interface{})[0]).Equal("echo $$TOKEN") | ||||
| 			g.Assert(c.Build.Config["commands"].([]interface{})[1]).Equal("echo $$SECRET") | ||||
| 		}) | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| var yml = ` | ||||
| build: | ||||
|   image: foo | ||||
|   commands: | ||||
|     - echo $$TOKEN | ||||
|     - echo $$SECRET | ||||
| deploy: | ||||
|   digital_ocean: | ||||
|     token: $$TOKEN | ||||
|     secret: $$SECRET | ||||
| ` | ||||
							
								
								
									
										142
									
								
								pkg/yaml/lint.go
									
									
									
									
									
								
							
							
						
						
									
										142
									
								
								pkg/yaml/lint.go
									
									
									
									
									
								
							| @@ -1,142 +0,0 @@ | ||||
| package parser | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"path/filepath" | ||||
| 	"strings" | ||||
|  | ||||
| 	common "github.com/drone/drone/pkg/types" | ||||
| ) | ||||
|  | ||||
| // lintRule defines a function that runs lint | ||||
| // checks against a Yaml Config file. If the rule | ||||
| // fails it should return an error message. | ||||
| type lintRule func(*common.Config) error | ||||
|  | ||||
| var lintRules = []lintRule{ | ||||
| 	expectBuild, | ||||
| 	expectImage, | ||||
| 	expectCommand, | ||||
| 	expectCloneInWorkspace, | ||||
| 	expectCacheInWorkspace, | ||||
| } | ||||
|  | ||||
| // Lint runs all lint rules against the Yaml Config. | ||||
| func Lint(c *common.Config) error { | ||||
| 	for _, rule := range lintRules { | ||||
| 		err := rule(c) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // lint rule that fails when no build is defined | ||||
| func expectBuild(c *common.Config) error { | ||||
| 	if c.Build == nil { | ||||
| 		return fmt.Errorf("Yaml must define a build section") | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // lint rule that fails when no build image is defined | ||||
| func expectImage(c *common.Config) error { | ||||
| 	if len(c.Build.Image) == 0 { | ||||
| 		return fmt.Errorf("Yaml must define a build image") | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // lint rule that fails when no build commands are defined | ||||
| func expectCommand(c *common.Config) error { | ||||
| 	if c.Setup.Config == nil || c.Setup.Config["commands"] == nil { | ||||
| 		return fmt.Errorf("Yaml must define build / setup commands") | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // lint rule that fails if the clone directory is not contained | ||||
| // in the root workspace. | ||||
| func expectCloneInWorkspace(c *common.Config) error { | ||||
| 	pathv, ok := c.Clone.Config["path"] | ||||
| 	var path string | ||||
|  | ||||
| 	if ok { | ||||
| 		path, _ = pathv.(string) | ||||
| 	} | ||||
| 	if len(path) == 0 { | ||||
| 		// This should only happen if the transformer was not run | ||||
| 		return fmt.Errorf("No workspace specified") | ||||
| 	} | ||||
|  | ||||
| 	relative, relOk := filepath.Rel("/drone/src", path) | ||||
| 	if relOk != nil { | ||||
| 		return fmt.Errorf("Path is not relative to root") | ||||
| 	} | ||||
|  | ||||
| 	cleaned := filepath.Clean(relative) | ||||
| 	if strings.Index(cleaned, "../") != -1 { | ||||
| 		return fmt.Errorf("Cannot clone above the root") | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // lint rule that fails if the cache directories are not contained | ||||
| // in the workspace. | ||||
| func expectCacheInWorkspace(c *common.Config) error { | ||||
| 	for _, step := range c.Build.Cache { | ||||
| 		if strings.Index(step, ":") != -1 { | ||||
| 			return fmt.Errorf("Cache cannot contain : in the path") | ||||
| 		} | ||||
|  | ||||
| 		cleaned := filepath.Clean(step) | ||||
|  | ||||
| 		if strings.Index(cleaned, "../") != -1 { | ||||
| 			return fmt.Errorf("Cache must point to a path in the workspace") | ||||
| 		} else if cleaned == "." { | ||||
| 			return fmt.Errorf("Cannot cache the workspace") | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func LintPlugins(c *common.Config, opts *Opts) error { | ||||
| 	if len(opts.Whitelist) == 0 { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	var images []string | ||||
| 	images = append(images, c.Setup.Image) | ||||
| 	images = append(images, c.Clone.Image) | ||||
| 	for _, step := range c.Publish { | ||||
| 		images = append(images, step.Image) | ||||
| 	} | ||||
| 	for _, step := range c.Deploy { | ||||
| 		images = append(images, step.Image) | ||||
| 	} | ||||
| 	for _, step := range c.Notify { | ||||
| 		images = append(images, step.Image) | ||||
| 	} | ||||
|  | ||||
| 	for _, image := range images { | ||||
| 		match := false | ||||
| 		for _, pattern := range opts.Whitelist { | ||||
| 			if pattern == image { | ||||
| 				match = true | ||||
| 				break | ||||
| 			} | ||||
| 			ok, err := filepath.Match(pattern, image) | ||||
| 			if ok && err == nil { | ||||
| 				match = true | ||||
| 				break | ||||
| 			} | ||||
| 		} | ||||
| 		if !match { | ||||
| 			return fmt.Errorf("Cannot use un-trusted image %s", image) | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| @@ -1,177 +0,0 @@ | ||||
| package parser | ||||
|  | ||||
| import ( | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/drone/drone/Godeps/_workspace/src/github.com/franela/goblin" | ||||
| 	common "github.com/drone/drone/pkg/types" | ||||
| ) | ||||
|  | ||||
| func Test_Linter(t *testing.T) { | ||||
|  | ||||
| 	g := goblin.Goblin(t) | ||||
| 	g.Describe("Linter", func() { | ||||
|  | ||||
| 		g.It("Should fail when nil build", func() { | ||||
| 			c := &common.Config{} | ||||
| 			g.Assert(expectBuild(c) != nil).IsTrue() | ||||
| 		}) | ||||
|  | ||||
| 		g.It("Should fail when no image", func() { | ||||
| 			c := &common.Config{ | ||||
| 				Build: &common.Step{}, | ||||
| 			} | ||||
| 			g.Assert(expectImage(c) != nil).IsTrue() | ||||
| 		}) | ||||
|  | ||||
| 		g.It("Should fail when no commands", func() { | ||||
| 			c := &common.Config{ | ||||
| 				Setup: &common.Step{}, | ||||
| 			} | ||||
| 			g.Assert(expectCommand(c) != nil).IsTrue() | ||||
| 		}) | ||||
|  | ||||
| 		g.It("Should pass when proper Build provided", func() { | ||||
| 			c := &common.Config{ | ||||
| 				Build: &common.Step{ | ||||
| 					Config: map[string]interface{}{ | ||||
| 						"commands": []string{"echo hi"}, | ||||
| 					}, | ||||
| 				}, | ||||
| 			} | ||||
| 			g.Assert(expectImage(c) != nil).IsTrue() | ||||
| 		}) | ||||
|  | ||||
| 		g.It("Should pass linter when build properly setup", func() { | ||||
| 			c := &common.Config{} | ||||
| 			c.Build = &common.Step{} | ||||
| 			c.Build.Image = "golang" | ||||
| 			c.Setup = &common.Step{} | ||||
| 			c.Setup.Config = map[string]interface{}{} | ||||
| 			c.Setup.Config["commands"] = []string{"go build", "go test"} | ||||
| 			c.Clone = &common.Step{} | ||||
| 			c.Clone.Config = map[string]interface{}{} | ||||
| 			c.Clone.Config["path"] = "/drone/src/foo/bar" | ||||
| 			c.Publish = map[string]*common.Step{} | ||||
| 			c.Publish["docker"] = &common.Step{Image: "docker"} | ||||
| 			c.Deploy = map[string]*common.Step{} | ||||
| 			c.Deploy["kubernetes"] = &common.Step{Image: "kubernetes"} | ||||
| 			c.Notify = map[string]*common.Step{} | ||||
| 			c.Notify["email"] = &common.Step{Image: "email"} | ||||
| 			g.Assert(Lint(c) == nil).IsTrue() | ||||
| 		}) | ||||
|  | ||||
| 		g.It("Should pass with clone path inside workspace", func() { | ||||
| 			c := &common.Config{ | ||||
| 				Clone: &common.Step{ | ||||
| 					Config: map[string]interface{}{ | ||||
| 						"path": "/drone/src/foo/bar", | ||||
| 					}, | ||||
| 				}, | ||||
| 			} | ||||
| 			g.Assert(expectCloneInWorkspace(c) == nil).IsTrue() | ||||
| 		}) | ||||
|  | ||||
| 		g.It("Should fail with clone path outside workspace", func() { | ||||
| 			c := &common.Config{ | ||||
| 				Clone: &common.Step{ | ||||
| 					Config: map[string]interface{}{ | ||||
| 						"path": "/foo/bar", | ||||
| 					}, | ||||
| 				}, | ||||
| 			} | ||||
| 			g.Assert(expectCloneInWorkspace(c) != nil).IsTrue() | ||||
| 		}) | ||||
|  | ||||
| 		g.It("Should pass with cache path inside workspace", func() { | ||||
| 			c := &common.Config{ | ||||
| 				Build: &common.Step{ | ||||
| 					Cache: []string{".git", "/.git", "/.git/../.git/../.git"}, | ||||
| 				}, | ||||
| 			} | ||||
| 			g.Assert(expectCacheInWorkspace(c) == nil).IsTrue() | ||||
| 		}) | ||||
|  | ||||
| 		g.It("Should fail with cache path outside workspace", func() { | ||||
| 			c := &common.Config{ | ||||
| 				Build: &common.Step{ | ||||
| 					Cache: []string{".git", "/.git", "../../.git"}, | ||||
| 				}, | ||||
| 			} | ||||
| 			g.Assert(expectCacheInWorkspace(c) != nil).IsTrue() | ||||
| 		}) | ||||
|  | ||||
| 		g.It("Should fail when caching workspace directory", func() { | ||||
| 			c := &common.Config{ | ||||
| 				Build: &common.Step{ | ||||
| 					Cache: []string{".git", ".git/../"}, | ||||
| 				}, | ||||
| 			} | ||||
| 			g.Assert(expectCacheInWorkspace(c) != nil).IsTrue() | ||||
| 		}) | ||||
|  | ||||
| 		g.It("Should fail when : is in the cache path", func() { | ||||
| 			c := &common.Config{ | ||||
| 				Build: &common.Step{ | ||||
| 					Cache: []string{".git", ".git:/../"}, | ||||
| 				}, | ||||
| 			} | ||||
| 			g.Assert(expectCacheInWorkspace(c) != nil).IsTrue() | ||||
| 		}) | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func Test_LintPlugins(t *testing.T) { | ||||
|  | ||||
| 	g := goblin.Goblin(t) | ||||
| 	g.Describe("Plugin Linter", func() { | ||||
|  | ||||
| 		g.It("Should fail un-trusted plugin", func() { | ||||
| 			c := &common.Config{ | ||||
| 				Setup:   &common.Step{Image: "foo/baz"}, | ||||
| 				Clone:   &common.Step{Image: "foo/bar"}, | ||||
| 				Notify:  map[string]*common.Step{}, | ||||
| 				Deploy:  map[string]*common.Step{}, | ||||
| 				Publish: map[string]*common.Step{}, | ||||
| 			} | ||||
| 			o := &Opts{Whitelist: []string{"plugins/*"}} | ||||
| 			g.Assert(LintPlugins(c, o) != nil).IsTrue() | ||||
| 		}) | ||||
|  | ||||
| 		g.It("Should pass when empty whitelist", func() { | ||||
| 			c := &common.Config{ | ||||
| 				Setup:   &common.Step{Image: "foo/baz"}, | ||||
| 				Clone:   &common.Step{Image: "foo/bar"}, | ||||
| 				Notify:  map[string]*common.Step{}, | ||||
| 				Deploy:  map[string]*common.Step{}, | ||||
| 				Publish: map[string]*common.Step{}, | ||||
| 			} | ||||
| 			o := &Opts{Whitelist: []string{}} | ||||
| 			g.Assert(LintPlugins(c, o) == nil).IsTrue() | ||||
| 		}) | ||||
|  | ||||
| 		g.It("Should pass wildcard", func() { | ||||
| 			c := &common.Config{ | ||||
| 				Setup:   &common.Step{Image: "plugins/drone-setup"}, | ||||
| 				Clone:   &common.Step{Image: "plugins/drone-build"}, | ||||
| 				Notify:  map[string]*common.Step{}, | ||||
| 				Deploy:  map[string]*common.Step{}, | ||||
| 				Publish: map[string]*common.Step{}, | ||||
| 			} | ||||
| 			o := &Opts{Whitelist: []string{"plugins/*"}} | ||||
| 			g.Assert(LintPlugins(c, o) == nil).IsTrue() | ||||
| 		}) | ||||
|  | ||||
| 		g.It("Should pass itemized", func() { | ||||
| 			c := &common.Config{ | ||||
| 				Setup:   &common.Step{Image: "plugins/drone-setup"}, | ||||
| 				Clone:   &common.Step{Image: "plugins/drone-build"}, | ||||
| 				Notify:  map[string]*common.Step{}, | ||||
| 				Deploy:  map[string]*common.Step{}, | ||||
| 				Publish: map[string]*common.Step{}, | ||||
| 			} | ||||
| 			o := &Opts{Whitelist: []string{"plugins/drone-setup", "plugins/drone-build"}} | ||||
| 			g.Assert(LintPlugins(c, o) == nil).IsTrue() | ||||
| 		}) | ||||
| 	}) | ||||
| } | ||||
| @@ -1,112 +1,14 @@ | ||||
| package parser | ||||
|  | ||||
| import ( | ||||
| 	common "github.com/drone/drone/pkg/types" | ||||
| 	"github.com/drone/drone/pkg/yaml/inject" | ||||
| 	"github.com/drone/drone/pkg/yaml/matrix" | ||||
| 	"github.com/drone/drone/pkg/yaml/transform" | ||||
| 	"github.com/drone/drone/pkg/types" | ||||
|  | ||||
| 	"github.com/drone/drone/Godeps/_workspace/src/gopkg.in/yaml.v2" | ||||
| ) | ||||
|  | ||||
| // Opts specifies parser options that will permit | ||||
| // or deny certain Yaml settings. | ||||
| type Opts struct { | ||||
| 	Volumes    bool | ||||
| 	Network    bool | ||||
| 	Privileged bool | ||||
| 	Caching    bool | ||||
| 	Whitelist  []string | ||||
| } | ||||
|  | ||||
| var DefaultOpts = &Opts{ | ||||
| 	Volumes:    false, | ||||
| 	Network:    false, | ||||
| 	Privileged: false, | ||||
| 	Caching:    true, | ||||
| 	Whitelist:  []string{"plugins/*"}, | ||||
| } | ||||
|  | ||||
| // Parse parses a build matrix and returns | ||||
| // a list of build configurations for each axis | ||||
| // using the default parsing options. | ||||
| func Parse(raw string, r *common.Repo) ([]*common.Config, error) { | ||||
| 	return ParseOpts(raw, DefaultOpts, r) | ||||
| } | ||||
|  | ||||
| // ParseOpts parses a build matrix and returns | ||||
| // a list of build configurations for each axis | ||||
| // using the provided parsing options. | ||||
| func ParseOpts(raw string, opts *Opts, r *common.Repo) ([]*common.Config, error) { | ||||
| 	axis, err := matrix.Parse(raw) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	confs := []*common.Config{} | ||||
|  | ||||
| 	// when no matrix values exist we should return | ||||
| 	// a single config value with an empty label. | ||||
| 	if len(axis) == 0 { | ||||
| 		conf, err := ParseSingle(raw, opts, r) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		confs = append(confs, conf) | ||||
| 	} | ||||
|  | ||||
| 	for _, ax := range axis { | ||||
| 		// inject the matrix values into the raw script | ||||
| 		injected := inject.Inject(raw, ax) | ||||
| 		conf, err := ParseSingle(injected, opts, r) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		conf.Axis = common.Axis(ax) | ||||
| 		confs = append(confs, conf) | ||||
| 	} | ||||
|  | ||||
| 	return confs, nil | ||||
| } | ||||
|  | ||||
| // helper funtion to parse a yaml configuration file. | ||||
| func ParseSingle(raw string, opts *Opts, r *common.Repo) (*common.Config, error) { | ||||
| 	conf := &common.Config{} | ||||
| 	err := yaml.Unmarshal([]byte(raw), conf) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	// apply rules / transforms | ||||
| 	transform.Defaults(conf) | ||||
| 	if !opts.Network { | ||||
| 		transform.RemoveNetwork(conf) | ||||
| 	} | ||||
| 	if !opts.Volumes { | ||||
| 		transform.RemoveVolumes(conf) | ||||
| 	} | ||||
| 	if !opts.Privileged { | ||||
| 		transform.RemovePrivileged(conf) | ||||
| 	} | ||||
| 	transform.Repo(conf, r) | ||||
| 	if !opts.Caching { | ||||
| 		transform.RemoveVolumes(conf) | ||||
| 	} | ||||
|  | ||||
| 	// lint the yaml file | ||||
| 	err = Lint(conf) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	err = LintPlugins(conf, opts) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return conf, err | ||||
| } | ||||
|  | ||||
| func ParseCondition(raw string) (*common.Condition, error) { | ||||
| func ParseCondition(raw string) (*types.Condition, error) { | ||||
| 	c := struct { | ||||
| 		Condition *common.Condition `yaml:"when"` | ||||
| 		Condition *types.Condition `yaml:"when"` | ||||
| 	}{} | ||||
| 	err := yaml.Unmarshal([]byte(raw), c) | ||||
| 	return c.Condition, err | ||||
|   | ||||
| @@ -1,314 +0,0 @@ | ||||
| package transform | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"net/url" | ||||
| 	"path/filepath" | ||||
| 	"strings" | ||||
|  | ||||
| 	common "github.com/drone/drone/pkg/types" | ||||
| ) | ||||
|  | ||||
| // buildRoot is the root build directory. | ||||
| // | ||||
| // If this changes then the matching value in lint.go needs | ||||
| // to be modified as well. | ||||
| const buildRoot = "/drone/src" | ||||
|  | ||||
| // transformRule applies a check or transformation rule | ||||
| // to the build configuration. | ||||
| type transformRule func(*common.Config) | ||||
|  | ||||
| var transformRules = []transformRule{ | ||||
| 	transformSetup, | ||||
| 	transformClone, | ||||
| 	transformBuild, | ||||
| 	transformImages, | ||||
| 	transformDockerPlugin, | ||||
| } | ||||
|  | ||||
| var rmPrivilegedRules = []transformRule{ | ||||
| 	rmPrivileged, | ||||
| 	rmVolumes, | ||||
| 	rmNetwork, | ||||
| } | ||||
|  | ||||
| // Default executes the default transformers that | ||||
| // ensure the minimal Yaml configuration is in place | ||||
| // and correctly configured. | ||||
| func Defaults(c *common.Config) { | ||||
| 	for _, rule := range transformRules { | ||||
| 		rule(c) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Safe executes all transformers that remove privileged | ||||
| // options from the Yaml. | ||||
| func Safe(c *common.Config) { | ||||
| 	for _, rule := range rmPrivilegedRules { | ||||
| 		rule(c) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // RemoveNetwork executes all transformers that remove | ||||
| // network options from the Yaml. | ||||
| func RemoveNetwork(c *common.Config) { | ||||
| 	rmNetwork(c) | ||||
| } | ||||
|  | ||||
| // TransformRemoveVolumes executes all transformers that | ||||
| // remove volume options from the Yaml. | ||||
| func RemoveVolumes(c *common.Config) { | ||||
| 	rmVolumes(c) | ||||
| } | ||||
|  | ||||
| // RemovePrivileged executes all transformers that remove | ||||
| // privileged options from the Yaml. | ||||
| func RemovePrivileged(c *common.Config) { | ||||
| 	rmPrivileged(c) | ||||
| } | ||||
|  | ||||
| // Repo executes all transformers that rely on repository | ||||
| // information. | ||||
| func Repo(c *common.Config, r *common.Repo) { | ||||
| 	transformWorkspace(c, r) | ||||
| 	transformCache(c, r) | ||||
| } | ||||
|  | ||||
| // transformSetup is a transformer that adds a default | ||||
| // setup step if none exists. | ||||
| func transformSetup(c *common.Config) { | ||||
| 	c.Setup = &common.Step{} | ||||
| 	c.Setup.Image = "plugins/drone-build" | ||||
|  | ||||
| 	// TODO move below code to separate transform | ||||
| 	if c.Build == nil { | ||||
| 		c.Build = &common.Step{} | ||||
| 	} | ||||
| 	if c.Build.Config == nil { | ||||
| 		c.Build.Config = map[string]interface{}{} | ||||
| 	} | ||||
| 	//// | ||||
|  | ||||
| 	c.Setup.Config = c.Build.Config | ||||
| } | ||||
|  | ||||
| // transformClone is a transformer that adds a default | ||||
| // clone step if none exists. | ||||
| func transformClone(c *common.Config) { | ||||
| 	if c.Clone == nil { | ||||
| 		c.Clone = &common.Step{} | ||||
| 	} | ||||
| 	if len(c.Clone.Image) == 0 { | ||||
| 		c.Clone.Image = "plugins/drone-git" | ||||
| 		c.Clone.Volumes = nil | ||||
| 		c.Clone.NetworkMode = "" | ||||
| 	} | ||||
| 	if c.Clone.Config == nil { | ||||
| 		c.Clone.Config = map[string]interface{}{} | ||||
| 		c.Clone.Config["depth"] = 50 | ||||
| 		c.Clone.Config["recursive"] = true | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // transformBuild is a transformer that removes the | ||||
| // build configuration vargs. They should have | ||||
| // already been transferred to the Setup step. | ||||
| func transformBuild(c *common.Config) { | ||||
| 	c.Build.Config = nil | ||||
| 	c.Build.Entrypoint = []string{"/bin/bash", "-e"} | ||||
| 	c.Build.Command = []string{"/drone/bin/build.sh"} | ||||
| } | ||||
|  | ||||
| // transformImages is a transformer that ensures every | ||||
| // step has an image and uses a fully-qualified | ||||
| // image name. | ||||
| func transformImages(c *common.Config) { | ||||
| 	c.Setup.Image = imageName(c.Setup.Image) | ||||
| 	c.Clone.Image = imageName(c.Clone.Image) | ||||
| 	for name, step := range c.Publish { | ||||
| 		step.Image = imageNameDefault(step.Image, name) | ||||
| 	} | ||||
| 	for name, step := range c.Deploy { | ||||
| 		step.Image = imageNameDefault(step.Image, name) | ||||
| 	} | ||||
| 	for name, step := range c.Notify { | ||||
| 		step.Image = imageNameDefault(step.Image, name) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // transformDockerPlugin is a transformer that ensures the | ||||
| // official Docker plugin can run in privileged mode. It | ||||
| // will disable volumes and network mode for added protection. | ||||
| func transformDockerPlugin(c *common.Config) { | ||||
| 	for _, step := range c.Publish { | ||||
| 		if step.Image == "plugins/drone-docker" { | ||||
| 			step.Privileged = true | ||||
| 			step.Volumes = nil | ||||
| 			step.NetworkMode = "" | ||||
| 			step.Entrypoint = []string{} | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // rmPrivileged is a transformer that ensures every | ||||
| // step is executed in non-privileged mode. | ||||
| func rmPrivileged(c *common.Config) { | ||||
| 	c.Setup.Privileged = false | ||||
| 	c.Clone.Privileged = false | ||||
| 	c.Build.Privileged = false | ||||
| 	for _, step := range c.Publish { | ||||
| 		if step.Image == "plugins/drone-docker" { | ||||
| 			continue // the official docker plugin is the only exception here | ||||
| 		} | ||||
| 		step.Privileged = false | ||||
| 	} | ||||
| 	for _, step := range c.Deploy { | ||||
| 		step.Privileged = false | ||||
| 	} | ||||
| 	for _, step := range c.Notify { | ||||
| 		step.Privileged = false | ||||
| 	} | ||||
| 	for _, step := range c.Compose { | ||||
| 		step.Privileged = false | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // rmVolumes is a transformer that ensures every | ||||
| // step is executed without volumes. | ||||
| func rmVolumes(c *common.Config) { | ||||
| 	c.Setup.Volumes = nil | ||||
| 	c.Clone.Volumes = nil | ||||
| 	c.Build.Volumes = nil | ||||
| 	for _, step := range c.Publish { | ||||
| 		step.Volumes = nil | ||||
| 	} | ||||
| 	for _, step := range c.Deploy { | ||||
| 		step.Volumes = nil | ||||
| 	} | ||||
| 	for _, step := range c.Notify { | ||||
| 		step.Volumes = nil | ||||
| 	} | ||||
| 	for _, step := range c.Compose { | ||||
| 		step.Volumes = nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // rmNetwork is a transformer that ensures every | ||||
| // step is executed with default bridge networking. | ||||
| func rmNetwork(c *common.Config) { | ||||
| 	c.Setup.NetworkMode = "" | ||||
| 	c.Clone.NetworkMode = "" | ||||
| 	c.Build.NetworkMode = "" | ||||
| 	for _, step := range c.Publish { | ||||
| 		step.NetworkMode = "" | ||||
| 	} | ||||
| 	for _, step := range c.Deploy { | ||||
| 		step.NetworkMode = "" | ||||
| 	} | ||||
| 	for _, step := range c.Notify { | ||||
| 		step.NetworkMode = "" | ||||
| 	} | ||||
| 	for _, step := range c.Compose { | ||||
| 		step.NetworkMode = "" | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // transformWorkspace is a transformer that adds the workspace | ||||
| // directory to the configuration based on the repository | ||||
| // information. | ||||
| func transformWorkspace(c *common.Config, r *common.Repo) { | ||||
| 	pathv, ok := c.Clone.Config["path"] | ||||
| 	var path string | ||||
|  | ||||
| 	if ok { | ||||
| 		path, _ = pathv.(string) | ||||
| 	} | ||||
| 	if len(path) == 0 { | ||||
| 		path = repoPath(r) | ||||
| 	} | ||||
|  | ||||
| 	c.Clone.Config["path"] = filepath.Join(buildRoot, path) | ||||
| } | ||||
|  | ||||
| // transformCache is a transformer that adds volumes | ||||
| // to the configuration based on the cache. | ||||
| func transformCache(c *common.Config, r *common.Repo) { | ||||
| 	cacheCount := len(c.Build.Cache) | ||||
|  | ||||
| 	if cacheCount == 0 { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	volumes := make([]string, cacheCount) | ||||
|  | ||||
| 	cache := cacheRoot(r) | ||||
| 	workspace := c.Clone.Config["path"].(string) | ||||
|  | ||||
| 	for i, dir := range c.Build.Cache { | ||||
| 		cacheDir := filepath.Join(cache, dir) | ||||
| 		workspaceDir := filepath.Join(workspace, dir) | ||||
|  | ||||
| 		volumes[i] = fmt.Sprintf("%s:%s", cacheDir, workspaceDir) | ||||
| 	} | ||||
|  | ||||
| 	c.Setup.Volumes = append(c.Setup.Volumes, volumes...) | ||||
| 	c.Clone.Volumes = append(c.Clone.Volumes, volumes...) | ||||
| 	c.Build.Volumes = append(c.Build.Volumes, volumes...) | ||||
|  | ||||
| 	for _, step := range c.Publish { | ||||
| 		step.Volumes = append(step.Volumes, volumes...) | ||||
| 	} | ||||
| 	for _, step := range c.Deploy { | ||||
| 		step.Volumes = append(step.Volumes, volumes...) | ||||
| 	} | ||||
| 	for _, step := range c.Notify { | ||||
| 		step.Volumes = append(step.Volumes, volumes...) | ||||
| 	} | ||||
| 	for _, step := range c.Compose { | ||||
| 		step.Volumes = append(step.Volumes, volumes...) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // imageName is a helper function that resolves the | ||||
| // image name. When using official drone plugins it | ||||
| // is possible to use an alias name. This converts to | ||||
| // the fully qualified name. | ||||
| func imageName(name string) string { | ||||
| 	if strings.Contains(name, "/") { | ||||
| 		return name | ||||
| 	} | ||||
| 	name = strings.Replace(name, "_", "-", -1) | ||||
| 	name = "plugins/drone-" + name | ||||
| 	return name | ||||
| } | ||||
|  | ||||
| // imageNameDefault is a helper function that resolves | ||||
| // the image name. If the image name is blank the | ||||
| // default name is used instead. | ||||
| func imageNameDefault(name, defaultName string) string { | ||||
| 	if len(name) == 0 { | ||||
| 		name = defaultName | ||||
| 	} | ||||
| 	return imageName(name) | ||||
| } | ||||
|  | ||||
| // workspaceRoot is a helper function that determines the | ||||
| // default workspace the build runs in. | ||||
| func workspaceRoot(r *common.Repo) string { | ||||
| 	return filepath.Join(buildRoot, repoPath(r)) | ||||
| } | ||||
|  | ||||
| // cacheRoot is a helper function that deteremines the | ||||
| // default caching root. | ||||
| func cacheRoot(r *common.Repo) string { | ||||
| 	return filepath.Join("/tmp/drone/cache", repoPath(r)) | ||||
| } | ||||
|  | ||||
| // repoPath is a helper function that creates a path based | ||||
| // on the host and repository name. | ||||
| func repoPath(r *common.Repo) string { | ||||
| 	parsed, _ := url.Parse(r.Link) | ||||
| 	return filepath.Join(parsed.Host, r.FullName) | ||||
| } | ||||
| @@ -1,220 +0,0 @@ | ||||
| package transform | ||||
|  | ||||
| import ( | ||||
| 	"path/filepath" | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/drone/drone/Godeps/_workspace/src/github.com/franela/goblin" | ||||
| 	common "github.com/drone/drone/pkg/types" | ||||
| ) | ||||
|  | ||||
| func Test_Transform(t *testing.T) { | ||||
|  | ||||
| 	g := goblin.Goblin(t) | ||||
| 	g.Describe("Transform", func() { | ||||
|  | ||||
| 		g.It("Should transform setup step", func() { | ||||
| 			c := &common.Config{} | ||||
| 			c.Build = &common.Step{} | ||||
| 			c.Build.Config = map[string]interface{}{} | ||||
| 			transformSetup(c) | ||||
| 			g.Assert(c.Setup != nil).IsTrue() | ||||
| 			g.Assert(c.Setup.Image).Equal("plugins/drone-build") | ||||
| 			g.Assert(c.Setup.Config).Equal(c.Build.Config) | ||||
| 		}) | ||||
|  | ||||
| 		g.It("Should transform clone step", func() { | ||||
| 			c := &common.Config{} | ||||
| 			transformClone(c) | ||||
| 			g.Assert(c.Clone != nil).IsTrue() | ||||
| 			g.Assert(c.Clone.Image).Equal("plugins/drone-git") | ||||
| 		}) | ||||
|  | ||||
| 		g.It("Should transform build", func() { | ||||
| 			c := &common.Config{} | ||||
| 			c.Build = &common.Step{} | ||||
| 			c.Build.Config = map[string]interface{}{} | ||||
| 			c.Build.Config["commands"] = []string{"echo hello"} | ||||
| 			transformBuild(c) | ||||
| 			g.Assert(len(c.Build.Config)).Equal(0) | ||||
| 			g.Assert(c.Build.Entrypoint[0]).Equal("/bin/bash") | ||||
| 			g.Assert(c.Build.Command[0]).Equal("/drone/bin/build.sh") | ||||
| 		}) | ||||
|  | ||||
| 		g.It("Should transform images", func() { | ||||
| 			c := &common.Config{} | ||||
| 			c.Setup = &common.Step{Image: "foo"} | ||||
| 			c.Clone = &common.Step{Image: "foo/bar"} | ||||
| 			c.Build = &common.Step{Image: "golang"} | ||||
| 			c.Publish = map[string]*common.Step{"google_compute": &common.Step{}} | ||||
| 			c.Deploy = map[string]*common.Step{"amazon": &common.Step{}} | ||||
| 			c.Notify = map[string]*common.Step{"slack": &common.Step{}} | ||||
| 			transformImages(c) | ||||
|  | ||||
| 			g.Assert(c.Setup.Image).Equal("plugins/drone-foo") | ||||
| 			g.Assert(c.Clone.Image).Equal("foo/bar") | ||||
| 			g.Assert(c.Build.Image).Equal("golang") | ||||
| 			g.Assert(c.Publish["google_compute"].Image).Equal("plugins/drone-google-compute") | ||||
| 			g.Assert(c.Deploy["amazon"].Image).Equal("plugins/drone-amazon") | ||||
| 			g.Assert(c.Notify["slack"].Image).Equal("plugins/drone-slack") | ||||
| 		}) | ||||
|  | ||||
| 		g.It("Should transform docker plugin", func() { | ||||
| 			c := &common.Config{} | ||||
| 			c.Publish = map[string]*common.Step{} | ||||
| 			c.Publish["docker"] = &common.Step{Image: "plugins/drone-docker"} | ||||
| 			transformDockerPlugin(c) | ||||
| 			g.Assert(c.Publish["docker"].Privileged).Equal(true) | ||||
| 		}) | ||||
|  | ||||
| 		g.It("Should remove privileged flag", func() { | ||||
| 			c := &common.Config{} | ||||
| 			c.Setup = &common.Step{Privileged: true} | ||||
| 			c.Clone = &common.Step{Privileged: true} | ||||
| 			c.Build = &common.Step{Privileged: true} | ||||
| 			c.Compose = map[string]*common.Step{"postgres": &common.Step{Privileged: true}} | ||||
| 			c.Publish = map[string]*common.Step{"google": &common.Step{Privileged: true}} | ||||
| 			c.Deploy = map[string]*common.Step{"amazon": &common.Step{Privileged: true}} | ||||
| 			c.Notify = map[string]*common.Step{"slack": &common.Step{Privileged: true}} | ||||
| 			rmPrivileged(c) | ||||
|  | ||||
| 			g.Assert(c.Setup.Privileged).Equal(false) | ||||
| 			g.Assert(c.Clone.Privileged).Equal(false) | ||||
| 			g.Assert(c.Build.Privileged).Equal(false) | ||||
| 			g.Assert(c.Compose["postgres"].Privileged).Equal(false) | ||||
| 			g.Assert(c.Publish["google"].Privileged).Equal(false) | ||||
| 			g.Assert(c.Deploy["amazon"].Privileged).Equal(false) | ||||
| 			g.Assert(c.Notify["slack"].Privileged).Equal(false) | ||||
| 		}) | ||||
|  | ||||
| 		g.It("Should not remove docker plugin privileged flag", func() { | ||||
| 			c := &common.Config{} | ||||
| 			c.Setup = &common.Step{} | ||||
| 			c.Clone = &common.Step{} | ||||
| 			c.Build = &common.Step{} | ||||
| 			c.Publish = map[string]*common.Step{} | ||||
| 			c.Publish["docker"] = &common.Step{Image: "plugins/drone-docker"} | ||||
| 			transformDockerPlugin(c) | ||||
| 			g.Assert(c.Publish["docker"].Privileged).Equal(true) | ||||
| 		}) | ||||
|  | ||||
| 		g.It("Should remove volumes", func() { | ||||
| 			c := &common.Config{} | ||||
| 			c.Setup = &common.Step{Volumes: []string{"/:/tmp"}} | ||||
| 			c.Clone = &common.Step{Volumes: []string{"/:/tmp"}} | ||||
| 			c.Build = &common.Step{Volumes: []string{"/:/tmp"}} | ||||
| 			c.Compose = map[string]*common.Step{"postgres": &common.Step{Volumes: []string{"/:/tmp"}}} | ||||
| 			c.Publish = map[string]*common.Step{"google": &common.Step{Volumes: []string{"/:/tmp"}}} | ||||
| 			c.Deploy = map[string]*common.Step{"amazon": &common.Step{Volumes: []string{"/:/tmp"}}} | ||||
| 			c.Notify = map[string]*common.Step{"slack": &common.Step{Volumes: []string{"/:/tmp"}}} | ||||
| 			rmVolumes(c) | ||||
|  | ||||
| 			g.Assert(len(c.Setup.Volumes)).Equal(0) | ||||
| 			g.Assert(len(c.Clone.Volumes)).Equal(0) | ||||
| 			g.Assert(len(c.Build.Volumes)).Equal(0) | ||||
| 			g.Assert(len(c.Compose["postgres"].Volumes)).Equal(0) | ||||
| 			g.Assert(len(c.Publish["google"].Volumes)).Equal(0) | ||||
| 			g.Assert(len(c.Deploy["amazon"].Volumes)).Equal(0) | ||||
| 			g.Assert(len(c.Notify["slack"].Volumes)).Equal(0) | ||||
| 		}) | ||||
|  | ||||
| 		g.It("Should remove network", func() { | ||||
| 			c := &common.Config{} | ||||
| 			c.Setup = &common.Step{NetworkMode: "host"} | ||||
| 			c.Clone = &common.Step{NetworkMode: "host"} | ||||
| 			c.Build = &common.Step{NetworkMode: "host"} | ||||
| 			c.Compose = map[string]*common.Step{"postgres": &common.Step{NetworkMode: "host"}} | ||||
| 			c.Publish = map[string]*common.Step{"google": &common.Step{NetworkMode: "host"}} | ||||
| 			c.Deploy = map[string]*common.Step{"amazon": &common.Step{NetworkMode: "host"}} | ||||
| 			c.Notify = map[string]*common.Step{"slack": &common.Step{NetworkMode: "host"}} | ||||
| 			rmNetwork(c) | ||||
|  | ||||
| 			g.Assert(c.Setup.NetworkMode).Equal("") | ||||
| 			g.Assert(c.Clone.NetworkMode).Equal("") | ||||
| 			g.Assert(c.Build.NetworkMode).Equal("") | ||||
| 			g.Assert(c.Compose["postgres"].NetworkMode).Equal("") | ||||
| 			g.Assert(c.Publish["google"].NetworkMode).Equal("") | ||||
| 			g.Assert(c.Deploy["amazon"].NetworkMode).Equal("") | ||||
| 			g.Assert(c.Notify["slack"].NetworkMode).Equal("") | ||||
| 		}) | ||||
|  | ||||
| 		g.It("Should return full qualified image name", func() { | ||||
| 			g.Assert(imageName("microsoft/azure")).Equal("microsoft/azure") | ||||
| 			g.Assert(imageName("azure")).Equal("plugins/drone-azure") | ||||
| 			g.Assert(imageName("azure_storage")).Equal("plugins/drone-azure-storage") | ||||
| 		}) | ||||
|  | ||||
| 		g.It("Should have cached volumes", func() { | ||||
| 			c := &common.Config{ | ||||
| 				Setup: &common.Step{}, | ||||
| 				Clone: &common.Step{ | ||||
| 					Config: map[string]interface{}{}, | ||||
| 				}, | ||||
| 				Build: &common.Step{ | ||||
| 					Cache: []string{".git", "foo", "bar"}, | ||||
| 				}, | ||||
| 				Notify:  map[string]*common.Step{}, | ||||
| 				Deploy:  map[string]*common.Step{}, | ||||
| 				Publish: map[string]*common.Step{}, | ||||
| 			} | ||||
| 			r := &common.Repo{ | ||||
| 				Link:     "https://github.com/drone/drone", | ||||
| 				FullName: "drone/drone", | ||||
| 			} | ||||
| 			transformWorkspace(c, r) | ||||
| 			transformCache(c, r) | ||||
|  | ||||
| 			cacheCount := len(c.Build.Cache) | ||||
|  | ||||
| 			test := func(s *common.Step) { | ||||
| 				g.Assert(len(s.Volumes)).Equal(cacheCount) | ||||
| 			} | ||||
|  | ||||
| 			testRange := func(s map[string]*common.Step) { | ||||
| 				for _, step := range s { | ||||
| 					test(step) | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			test(c.Setup) | ||||
| 			test(c.Clone) | ||||
| 			test(c.Build) | ||||
| 			testRange(c.Publish) | ||||
| 			testRange(c.Deploy) | ||||
| 			testRange(c.Notify) | ||||
| 			testRange(c.Compose) | ||||
| 		}) | ||||
|  | ||||
| 		g.It("Should have default workspace directory", func() { | ||||
| 			c := &common.Config{ | ||||
| 				Clone: &common.Step{ | ||||
| 					Config: map[string]interface{}{}, | ||||
| 				}, | ||||
| 			} | ||||
| 			r := &common.Repo{ | ||||
| 				Link:     "https://github.com/drone/drone", | ||||
| 				FullName: "drone/drone", | ||||
| 			} | ||||
| 			transformWorkspace(c, r) | ||||
|  | ||||
| 			g.Assert(c.Clone.Config["path"]).Equal(workspaceRoot(r)) | ||||
| 		}) | ||||
|  | ||||
| 		g.It("Should use path for working directory", func() { | ||||
| 			c := &common.Config{ | ||||
| 				Clone: &common.Step{ | ||||
| 					Config: map[string]interface{}{ | ||||
| 						"path": "foo/bar", | ||||
| 					}, | ||||
| 				}, | ||||
| 			} | ||||
| 			r := &common.Repo{ | ||||
| 				Link:     "https://github.com/drone/drone", | ||||
| 				FullName: "drone/drone", | ||||
| 			} | ||||
| 			transformWorkspace(c, r) | ||||
|  | ||||
| 			g.Assert(c.Clone.Config["path"]).Equal(filepath.Join(buildRoot, "foo/bar")) | ||||
| 		}) | ||||
| 	}) | ||||
| } | ||||
		Reference in New Issue
	
	Block a user