From 41af9c0720706a3db8265261f5d8a1c050b0cdb8 Mon Sep 17 00:00:00 2001 From: Thomas Boerger Date: Mon, 27 Jun 2016 23:06:02 +0200 Subject: [PATCH] Integrated initial command to list secrets Since we are not able to list the already set secrets I have added the required API andpoint and the required sub command to list them. --- client/client.go | 3 ++ client/client_impl.go | 8 ++++ drone/secret.go | 1 + drone/secret_list.go | 86 +++++++++++++++++++++++++++++++++++++++++++ drone/util.go | 10 +++++ model/secret.go | 9 +++++ router/router.go | 1 + server/secret.go | 32 +++++++++++++--- 8 files changed, 144 insertions(+), 6 deletions(-) diff --git a/client/client.go b/client/client.go index 783f1fc5..bf1ea155 100644 --- a/client/client.go +++ b/client/client.go @@ -49,6 +49,9 @@ type Client interface { // Sign returns a cryptographic signature for the input string. Sign(string, string, []byte) ([]byte, error) + // SecretList returns a list of all repository secrets. + SecretList(string, string) ([]*model.Secret, error) + // SecretPost create or updates a repository secret. SecretPost(string, string, *model.Secret) error diff --git a/client/client_impl.go b/client/client_impl.go index 780ffc81..7fa3099c 100644 --- a/client/client_impl.go +++ b/client/client_impl.go @@ -247,6 +247,14 @@ func (c *client) Deploy(owner, name string, num int, env string) (*model.Build, return out, err } +// SecretList returns a list of a repository secrets. +func (c *client) SecretList(owner, name string) ([]*model.Secret, error) { + var out []*model.Secret + uri := fmt.Sprintf(pathSecrets, c.base, owner, name) + err := c.get(uri, &out) + return out, err +} + // SecretPost create or updates a repository secret. func (c *client) SecretPost(owner, name string, secret *model.Secret) error { uri := fmt.Sprintf(pathSecrets, c.base, owner, name) diff --git a/drone/secret.go b/drone/secret.go index 97c35117..d39e5b86 100644 --- a/drone/secret.go +++ b/drone/secret.go @@ -8,5 +8,6 @@ var secretCmd = cli.Command{ Subcommands: []cli.Command{ secretAddCmd, secretRemoveCmd, + secretListCmd, }, } diff --git a/drone/secret_list.go b/drone/secret_list.go index 06ab7d0f..e875e556 100644 --- a/drone/secret_list.go +++ b/drone/secret_list.go @@ -1 +1,87 @@ package main + +import ( + "log" + "os" + "strings" + "text/template" + + "github.com/codegangsta/cli" +) + +var secretListCmd = cli.Command{ + Name: "ls", + Usage: "list all secrets", + Action: func(c *cli.Context) { + if err := secretList(c); err != nil { + log.Fatalln(err) + } + }, + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "format", + Usage: "format output", + Value: tmplSecretList, + }, + cli.StringFlag{ + Name: "image", + Usage: "filter by image", + }, + cli.StringFlag{ + Name: "event", + Usage: "filter by event", + }, + }, +} + +func secretList(c *cli.Context) error { + owner, name, err := parseRepo(c.Args().First()) + + if err != nil { + return err + } + + client, err := newClient(c) + + if err != nil { + return err + } + + secrets, err := client.SecretList(owner, name) + + if err != nil || len(secrets) == 0 { + return err + } + + tmpl, err := template.New("_").Funcs(secretFuncMap).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 tmplSecretList = "\x1b[33m{{ .Name }} \x1b[0m" + ` +Images: {{ list .Images }} +Events: {{ list .Events }} +` + +var secretFuncMap = template.FuncMap{ + "list": func(s []string) string { + return strings.Join(s, ", ") + }, +} diff --git a/drone/util.go b/drone/util.go index f52cff63..69fbc3a3 100644 --- a/drone/util.go +++ b/drone/util.go @@ -51,3 +51,13 @@ func readInput(in string) ([]byte, error) { } return ioutil.ReadFile(in) } + +func stringInSlice(a string, list []string) bool { + for _, b := range list { + if b == a { + return true + } + } + + return false +} diff --git a/model/secret.go b/model/secret.go index 767299a5..9f1c2f79 100644 --- a/model/secret.go +++ b/model/secret.go @@ -55,3 +55,12 @@ func (s *Secret) MatchEvent(event string) bool { func (s *Secret) Validate() error { return nil } + +func (s *Secret) Clone() *Secret { + return &Secret{ + ID: s.ID, + Name: s.Name, + Images: s.Images, + Events: s.Events, + } +} diff --git a/router/router.go b/router/router.go index 43b7cd4e..a6f89f2b 100644 --- a/router/router.go +++ b/router/router.go @@ -97,6 +97,7 @@ func Load(middleware ...gin.HandlerFunc) http.Handler { repo.GET("/logs/:number/:job", server.GetBuildLogs) repo.POST("/sign", session.MustPush, server.Sign) + repo.GET("/secrets", session.MustPush, server.GetSecrets) repo.POST("/secrets", session.MustPush, server.PostSecret) repo.DELETE("/secrets/:secret", session.MustPush, server.DeleteSecret) diff --git a/server/secret.go b/server/secret.go index f39d9768..bc241dca 100644 --- a/server/secret.go +++ b/server/secret.go @@ -1,6 +1,8 @@ package server import ( + "net/http" + "github.com/drone/drone/model" "github.com/drone/drone/router/middleware/session" "github.com/drone/drone/store" @@ -8,13 +10,31 @@ import ( "github.com/gin-gonic/gin" ) +func GetSecrets(c *gin.Context) { + repo := session.Repo(c) + secrets, err := store.GetSecretList(c, repo) + + if err != nil { + c.AbortWithStatus(http.StatusInternalServerError) + return + } + + var list []*model.Secret + + for _, s := range secrets { + list = append(list, s.Clone()) + } + + c.JSON(http.StatusOK, list) +} + func PostSecret(c *gin.Context) { repo := session.Repo(c) in := &model.Secret{} err := c.Bind(in) if err != nil { - c.String(400, "Invalid JSON input. %s", err.Error()) + c.String(http.StatusBadRequest, "Invalid JSON input. %s", err.Error()) return } in.ID = 0 @@ -22,11 +42,11 @@ func PostSecret(c *gin.Context) { err = store.SetSecret(c, in) if err != nil { - c.String(500, "Unable to persist secret. %s", err.Error()) + c.String(http.StatusInternalServerError, "Unable to persist secret. %s", err.Error()) return } - c.String(200, "") + c.String(http.StatusOK, "") } func DeleteSecret(c *gin.Context) { @@ -35,14 +55,14 @@ func DeleteSecret(c *gin.Context) { secret, err := store.GetSecret(c, repo, name) if err != nil { - c.String(404, "Cannot find secret %s.", name) + c.String(http.StatusNotFound, "Cannot find secret %s.", name) return } err = store.DeleteSecret(c, secret) if err != nil { - c.String(500, "Unable to delete secret. %s", err.Error()) + c.String(http.StatusInternalServerError, "Unable to delete secret. %s", err.Error()) return } - c.String(200, "") + c.String(http.StatusOK, "") }