diff --git a/drone/main.go b/drone/main.go index f50e7188..738382f0 100644 --- a/drone/main.go +++ b/drone/main.go @@ -42,6 +42,7 @@ func main() { signCmd, repoCmd, userCmd, + orgCmd, } app.Run(os.Args) diff --git a/drone/org.go b/drone/org.go new file mode 100644 index 00000000..d9ffaefe --- /dev/null +++ b/drone/org.go @@ -0,0 +1,11 @@ +package main + +import "github.com/codegangsta/cli" + +var orgCmd = cli.Command{ + Name: "org", + Usage: "manage organizations", + Subcommands: []cli.Command{ + orgSecretCmd, + }, +} diff --git a/drone/org_secret.go b/drone/org_secret.go new file mode 100644 index 00000000..1bf4e812 --- /dev/null +++ b/drone/org_secret.go @@ -0,0 +1,13 @@ +package main + +import "github.com/codegangsta/cli" + +var orgSecretCmd = cli.Command{ + Name: "secret", + Usage: "manage secrets", + Subcommands: []cli.Command{ + orgSecretAddCmd, + orgSecretRemoveCmd, + orgSecretListCmd, + }, +} diff --git a/drone/org_secret_add.go b/drone/org_secret_add.go new file mode 100644 index 00000000..52ac250d --- /dev/null +++ b/drone/org_secret_add.go @@ -0,0 +1,83 @@ +package main + +import ( + "fmt" + "io/ioutil" + "log" + "strings" + + "github.com/codegangsta/cli" + "github.com/drone/drone/model" +) + +var orgSecretAddCmd = cli.Command{ + Name: "add", + Usage: "adds a secret", + ArgsUsage: "[org] [key] [value]", + Action: func(c *cli.Context) { + if err := orgSecretAdd(c); err != nil { + log.Fatalln(err) + } + }, + Flags: []cli.Flag{ + cli.StringSliceFlag{ + Name: "event", + Usage: "inject the secret for these event types", + Value: &cli.StringSlice{ + model.EventPush, + model.EventTag, + model.EventDeploy, + }, + }, + cli.StringSliceFlag{ + Name: "image", + Usage: "inject the secret for these image types", + Value: &cli.StringSlice{}, + }, + cli.StringFlag{ + Name: "input", + Usage: "input secret value from a file", + }, + }, +} + +func orgSecretAdd(c *cli.Context) error { + if len(c.Args().Tail()) != 3 { + cli.ShowSubcommandHelp(c) + return nil + } + + team := c.Args().First() + name := c.Args().Get(1) + value := c.Args().Get(2) + + secret := &model.Secret{} + secret.Name = name + secret.Value = value + secret.Images = c.StringSlice("image") + secret.Events = c.StringSlice("event") + + if len(secret.Images) == 0 { + return fmt.Errorf("Please specify the --image parameter") + } + + // TODO(bradrydzewski) below we use an @ sybmol to denote that the secret + // value should be loaded from a file (inspired by curl). I'd prefer to use + // a --input flag to explicitly specify a filepath instead. + + if strings.HasPrefix(secret.Value, "@") { + path := secret.Value[1:] + out, ferr := ioutil.ReadFile(path) + if ferr != nil { + return ferr + } + secret.Value = string(out) + } + + client, err := newClient(c) + if err != nil { + return err + } + + return client.TeamSecretPost(team, secret) +} diff --git a/drone/org_secret_info.go b/drone/org_secret_info.go new file mode 100644 index 00000000..06ab7d0f --- /dev/null +++ b/drone/org_secret_info.go @@ -0,0 +1 @@ +package main diff --git a/drone/org_secret_list.go b/drone/org_secret_list.go new file mode 100644 index 00000000..ea0144b9 --- /dev/null +++ b/drone/org_secret_list.go @@ -0,0 +1,87 @@ +package main + +import ( + "log" + "os" + "strings" + "text/template" + + "github.com/codegangsta/cli" +) + +var orgSecretListCmd = cli.Command{ + Name: "ls", + Usage: "list all secrets", + Action: func(c *cli.Context) { + if err := orgSecretList(c); err != nil { + log.Fatalln(err) + } + }, + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "format", + Usage: "format output", + Value: tmplOrgSecretList, + }, + cli.StringFlag{ + Name: "image", + Usage: "filter by image", + }, + cli.StringFlag{ + Name: "event", + Usage: "filter by event", + }, + }, +} + +func orgSecretList(c *cli.Context) error { + if len(c.Args().Tail()) != 1 { + cli.ShowSubcommandHelp(c) + return nil + } + + team := c.Args().First() + + client, err := newClient(c) + if err != nil { + return err + } + + secrets, err := client.TeamSecretList(team) + + if err != nil || len(secrets) == 0 { + return err + } + + tmpl, err := template.New("_").Funcs(orgSecretFuncMap).Parse(c.String("format") + "\n") + + if err != nil { + return err + } + + for _, secret := range secrets { + if c.String("image") != "" && !stringInSlice(c.String("image"), secret.Images) { + continue + } + + if c.String("event") != "" && !stringInSlice(c.String("event"), secret.Events) { + continue + } + + tmpl.Execute(os.Stdout, secret) + } + + return nil +} + +// template for secret list items +var tmplOrgSecretList = "\x1b[33m{{ .Name }} \x1b[0m" + ` +Images: {{ list .Images }} +Events: {{ list .Events }} +` + +var orgSecretFuncMap = template.FuncMap{ + "list": func(s []string) string { + return strings.Join(s, ", ") + }, +} diff --git a/drone/org_secret_rm.go b/drone/org_secret_rm.go new file mode 100644 index 00000000..c0b4170d --- /dev/null +++ b/drone/org_secret_rm.go @@ -0,0 +1,34 @@ +package main + +import ( + "log" + + "github.com/codegangsta/cli" +) + +var orgSecretRemoveCmd = cli.Command{ + Name: "rm", + Usage: "remove a secret", + Action: func(c *cli.Context) { + if err := orgSecretRemove(c); err != nil { + log.Fatalln(err) + } + }, +} + +func orgSecretRemove(c *cli.Context) error { + if len(c.Args().Tail()) != 2 { + cli.ShowSubcommandHelp(c) + return nil + } + + team := c.Args().First() + secret := c.Args().Get(1) + + client, err := newClient(c) + if err != nil { + return err + } + + return client.TeamSecretDel(team, secret) +}