Merge pull request #1825 from donny-dont/feature/global_secrets
Implementing global secrets
This commit is contained in:
commit
58f84ced84
17 changed files with 423 additions and 216 deletions
|
@ -69,6 +69,15 @@ type Client interface {
|
|||
// TeamSecretDel deletes a named team secret.
|
||||
TeamSecretDel(string, string) error
|
||||
|
||||
// GlobalSecretList returns a list of global secrets.
|
||||
GlobalSecretList() ([]*model.Secret, error)
|
||||
|
||||
// GlobalSecretPost create or updates a global secret.
|
||||
GlobalSecretPost(secret *model.Secret) error
|
||||
|
||||
// GlobalSecretDel deletes a named global secret.
|
||||
GlobalSecretDel(secret string) error
|
||||
|
||||
// Build returns a repository build by number.
|
||||
Build(string, string, int) (*model.Build, error)
|
||||
|
||||
|
|
|
@ -24,28 +24,30 @@ const (
|
|||
pathLogs = "%s/api/queue/logs/%d"
|
||||
pathLogsAuth = "%s/api/queue/logs/%d?access_token=%s"
|
||||
|
||||
pathSelf = "%s/api/user"
|
||||
pathFeed = "%s/api/user/feed"
|
||||
pathRepos = "%s/api/user/repos"
|
||||
pathRepo = "%s/api/repos/%s/%s"
|
||||
pathChown = "%s/api/repos/%s/%s/chown"
|
||||
pathEncrypt = "%s/api/repos/%s/%s/encrypt"
|
||||
pathBuilds = "%s/api/repos/%s/%s/builds"
|
||||
pathBuild = "%s/api/repos/%s/%s/builds/%v"
|
||||
pathJob = "%s/api/repos/%s/%s/builds/%d/%d"
|
||||
pathLog = "%s/api/repos/%s/%s/logs/%d/%d"
|
||||
pathKey = "%s/api/repos/%s/%s/key"
|
||||
pathSign = "%s/api/repos/%s/%s/sign"
|
||||
pathRepoSecrets = "%s/api/repos/%s/%s/secrets"
|
||||
pathRepoSecret = "%s/api/repos/%s/%s/secrets/%s"
|
||||
pathTeamSecrets = "%s/api/teams/%s/secrets"
|
||||
pathTeamSecret = "%s/api/teams/%s/secrets/%s"
|
||||
pathNodes = "%s/api/nodes"
|
||||
pathNode = "%s/api/nodes/%d"
|
||||
pathUsers = "%s/api/users"
|
||||
pathUser = "%s/api/users/%s"
|
||||
pathBuildQueue = "%s/api/builds"
|
||||
pathAgent = "%s/api/agents"
|
||||
pathSelf = "%s/api/user"
|
||||
pathFeed = "%s/api/user/feed"
|
||||
pathRepos = "%s/api/user/repos"
|
||||
pathRepo = "%s/api/repos/%s/%s"
|
||||
pathChown = "%s/api/repos/%s/%s/chown"
|
||||
pathEncrypt = "%s/api/repos/%s/%s/encrypt"
|
||||
pathBuilds = "%s/api/repos/%s/%s/builds"
|
||||
pathBuild = "%s/api/repos/%s/%s/builds/%v"
|
||||
pathJob = "%s/api/repos/%s/%s/builds/%d/%d"
|
||||
pathLog = "%s/api/repos/%s/%s/logs/%d/%d"
|
||||
pathKey = "%s/api/repos/%s/%s/key"
|
||||
pathSign = "%s/api/repos/%s/%s/sign"
|
||||
pathRepoSecrets = "%s/api/repos/%s/%s/secrets"
|
||||
pathRepoSecret = "%s/api/repos/%s/%s/secrets/%s"
|
||||
pathTeamSecrets = "%s/api/teams/%s/secrets"
|
||||
pathTeamSecret = "%s/api/teams/%s/secrets/%s"
|
||||
pathGlobalSecrets = "%s/api/global/secrets"
|
||||
pathGlobalSecret = "%s/api/global/secrets/%s"
|
||||
pathNodes = "%s/api/nodes"
|
||||
pathNode = "%s/api/nodes/%d"
|
||||
pathUsers = "%s/api/users"
|
||||
pathUser = "%s/api/users/%s"
|
||||
pathBuildQueue = "%s/api/builds"
|
||||
pathAgent = "%s/api/agents"
|
||||
)
|
||||
|
||||
type client struct {
|
||||
|
@ -280,7 +282,7 @@ func (c *client) SecretDel(owner, name, secret string) error {
|
|||
return c.delete(uri)
|
||||
}
|
||||
|
||||
// TeamSecretList returns a list of a repository secrets.
|
||||
// TeamSecretList returns a list of organizational secrets.
|
||||
func (c *client) TeamSecretList(team string) ([]*model.Secret, error) {
|
||||
var out []*model.Secret
|
||||
uri := fmt.Sprintf(pathTeamSecrets, c.base, team)
|
||||
|
@ -288,18 +290,38 @@ func (c *client) TeamSecretList(team string) ([]*model.Secret, error) {
|
|||
return out, err
|
||||
}
|
||||
|
||||
// TeamSecretPost create or updates a repository secret.
|
||||
// TeamSecretPost create or updates a organizational secret.
|
||||
func (c *client) TeamSecretPost(team string, secret *model.Secret) error {
|
||||
uri := fmt.Sprintf(pathTeamSecrets, c.base, team)
|
||||
return c.post(uri, secret, nil)
|
||||
}
|
||||
|
||||
// TeamSecretDel deletes a named repository secret.
|
||||
// TeamSecretDel deletes a named orgainization secret.
|
||||
func (c *client) TeamSecretDel(team, secret string) error {
|
||||
uri := fmt.Sprintf(pathTeamSecret, c.base, team, secret)
|
||||
return c.delete(uri)
|
||||
}
|
||||
|
||||
// GlobalSecretList returns a list of global secrets.
|
||||
func (c *client) GlobalSecretList() ([]*model.Secret, error) {
|
||||
var out []*model.Secret
|
||||
uri := fmt.Sprintf(pathGlobalSecrets, c.base)
|
||||
err := c.get(uri, &out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// GlobalSecretPost create or updates a global secret.
|
||||
func (c *client) GlobalSecretPost(secret *model.Secret) error {
|
||||
uri := fmt.Sprintf(pathGlobalSecrets, c.base)
|
||||
return c.post(uri, secret, nil)
|
||||
}
|
||||
|
||||
// GlobalSecretDel deletes a named global secret.
|
||||
func (c *client) GlobalSecretDel(secret string) error {
|
||||
uri := fmt.Sprintf(pathGlobalSecret, c.base, secret)
|
||||
return c.delete(uri)
|
||||
}
|
||||
|
||||
// Sign returns a cryptographic signature for the input string.
|
||||
func (c *client) Sign(owner, name string, in []byte) ([]byte, error) {
|
||||
uri := fmt.Sprintf(pathSign, c.base, owner, name)
|
||||
|
|
11
drone/global.go
Normal file
11
drone/global.go
Normal file
|
@ -0,0 +1,11 @@
|
|||
package main
|
||||
|
||||
import "github.com/codegangsta/cli"
|
||||
|
||||
var globalCmd = cli.Command{
|
||||
Name: "global",
|
||||
Usage: "manage global state",
|
||||
Subcommands: []cli.Command{
|
||||
globalSecretCmd,
|
||||
},
|
||||
}
|
13
drone/global_secret.go
Normal file
13
drone/global_secret.go
Normal file
|
@ -0,0 +1,13 @@
|
|||
package main
|
||||
|
||||
import "github.com/codegangsta/cli"
|
||||
|
||||
var globalSecretCmd = cli.Command{
|
||||
Name: "secret",
|
||||
Usage: "manage secrets",
|
||||
Subcommands: []cli.Command{
|
||||
globalSecretAddCmd,
|
||||
globalSecretRemoveCmd,
|
||||
globalSecretListCmd,
|
||||
},
|
||||
}
|
41
drone/global_secret_add.go
Normal file
41
drone/global_secret_add.go
Normal file
|
@ -0,0 +1,41 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/codegangsta/cli"
|
||||
)
|
||||
|
||||
var globalSecretAddCmd = cli.Command{
|
||||
Name: "add",
|
||||
Usage: "adds a secret",
|
||||
ArgsUsage: "[key] [value]",
|
||||
Action: func(c *cli.Context) {
|
||||
if err := globalSecretAdd(c); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
},
|
||||
Flags: secretAddFlags(),
|
||||
}
|
||||
|
||||
func globalSecretAdd(c *cli.Context) error {
|
||||
if len(c.Args()) != 2 {
|
||||
cli.ShowSubcommandHelp(c)
|
||||
return nil
|
||||
}
|
||||
|
||||
name := c.Args().First()
|
||||
value := c.Args().Get(1)
|
||||
|
||||
secret, err := secretParseCmd(name, value, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
client, err := newClient(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return client.GlobalSecretPost(secret)
|
||||
}
|
1
drone/global_secret_info.go
Normal file
1
drone/global_secret_info.go
Normal file
|
@ -0,0 +1 @@
|
|||
package main
|
33
drone/global_secret_list.go
Normal file
33
drone/global_secret_list.go
Normal file
|
@ -0,0 +1,33 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/codegangsta/cli"
|
||||
)
|
||||
|
||||
var globalSecretListCmd = cli.Command{
|
||||
Name: "ls",
|
||||
Usage: "list all secrets",
|
||||
Action: func(c *cli.Context) {
|
||||
if err := globalSecretList(c); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
},
|
||||
Flags: secretListFlags(),
|
||||
}
|
||||
|
||||
func globalSecretList(c *cli.Context) error {
|
||||
client, err := newClient(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
secrets, err := client.GlobalSecretList()
|
||||
|
||||
if err != nil || len(secrets) == 0 {
|
||||
return err
|
||||
}
|
||||
|
||||
return secretDisplayList(secrets, c)
|
||||
}
|
33
drone/global_secret_rm.go
Normal file
33
drone/global_secret_rm.go
Normal file
|
@ -0,0 +1,33 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/codegangsta/cli"
|
||||
)
|
||||
|
||||
var globalSecretRemoveCmd = cli.Command{
|
||||
Name: "rm",
|
||||
Usage: "remove a secret",
|
||||
Action: func(c *cli.Context) {
|
||||
if err := globalSecretRemove(c); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func globalSecretRemove(c *cli.Context) error {
|
||||
if len(c.Args()) != 1 {
|
||||
cli.ShowSubcommandHelp(c)
|
||||
return nil
|
||||
}
|
||||
|
||||
secret := c.Args().First()
|
||||
|
||||
client, err := newClient(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return client.GlobalSecretDel(secret)
|
||||
}
|
|
@ -43,6 +43,7 @@ func main() {
|
|||
repoCmd,
|
||||
userCmd,
|
||||
orgCmd,
|
||||
globalCmd,
|
||||
}
|
||||
|
||||
app.Run(os.Args)
|
||||
|
|
|
@ -1,13 +1,9 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"github.com/codegangsta/cli"
|
||||
"github.com/drone/drone/model"
|
||||
)
|
||||
|
||||
var orgSecretAddCmd = cli.Command{
|
||||
|
@ -19,26 +15,7 @@ var orgSecretAddCmd = cli.Command{
|
|||
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",
|
||||
},
|
||||
},
|
||||
Flags: secretAddFlags(),
|
||||
}
|
||||
|
||||
func orgSecretAdd(c *cli.Context) error {
|
||||
|
@ -51,27 +28,9 @@ func orgSecretAdd(c *cli.Context) error {
|
|||
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)
|
||||
secret, err := secretParseCmd(name, value, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
client, err := newClient(c)
|
||||
|
|
|
@ -2,9 +2,6 @@ package main
|
|||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"github.com/codegangsta/cli"
|
||||
)
|
||||
|
@ -17,21 +14,7 @@ var orgSecretListCmd = cli.Command{
|
|||
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",
|
||||
},
|
||||
},
|
||||
Flags: secretListFlags(),
|
||||
}
|
||||
|
||||
func orgSecretList(c *cli.Context) error {
|
||||
|
@ -53,35 +36,5 @@ func orgSecretList(c *cli.Context) error {
|
|||
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, ", ")
|
||||
},
|
||||
return secretDisplayList(secrets, c)
|
||||
}
|
||||
|
|
120
drone/secret.go
120
drone/secret.go
|
@ -1,6 +1,15 @@
|
|||
package main
|
||||
|
||||
import "github.com/codegangsta/cli"
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"github.com/codegangsta/cli"
|
||||
"github.com/drone/drone/model"
|
||||
)
|
||||
|
||||
var secretCmd = cli.Command{
|
||||
Name: "secret",
|
||||
|
@ -11,3 +20,112 @@ var secretCmd = cli.Command{
|
|||
secretListCmd,
|
||||
},
|
||||
}
|
||||
|
||||
func secretAddFlags() []cli.Flag {
|
||||
return []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",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "skip-verify",
|
||||
Usage: "skip verification for the secret",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func secretListFlags() []cli.Flag {
|
||||
return []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 secretParseCmd(name string, value string, c *cli.Context) (*model.Secret, error) {
|
||||
secret := &model.Secret{}
|
||||
secret.Name = name
|
||||
secret.Value = value
|
||||
secret.Images = c.StringSlice("image")
|
||||
secret.Events = c.StringSlice("event")
|
||||
secret.SkipVerify = c.Bool("skip-verify")
|
||||
|
||||
if len(secret.Images) == 0 {
|
||||
return nil, 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 nil, ferr
|
||||
}
|
||||
secret.Value = string(out)
|
||||
}
|
||||
|
||||
return secret, nil
|
||||
}
|
||||
|
||||
func secretDisplayList(secrets []*model.Secret, c *cli.Context) error {
|
||||
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 }}
|
||||
SkipVerify: {{ .SkipVerify }}
|
||||
`
|
||||
|
||||
var secretFuncMap = template.FuncMap{
|
||||
"list": func(s []string) string {
|
||||
return strings.Join(s, ", ")
|
||||
},
|
||||
}
|
||||
|
|
|
@ -1,13 +1,9 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"github.com/codegangsta/cli"
|
||||
"github.com/drone/drone/model"
|
||||
)
|
||||
|
||||
var secretAddCmd = cli.Command{
|
||||
|
@ -19,26 +15,7 @@ var secretAddCmd = cli.Command{
|
|||
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",
|
||||
},
|
||||
},
|
||||
Flags: secretAddFlags(),
|
||||
}
|
||||
|
||||
func secretAdd(c *cli.Context) error {
|
||||
|
@ -54,27 +31,9 @@ func secretAdd(c *cli.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
secret := &model.Secret{}
|
||||
secret.Name = tail[0]
|
||||
secret.Value = tail[1]
|
||||
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)
|
||||
secret, err := secretParseCmd(tail[0], tail[1], c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
client, err := newClient(c)
|
||||
|
|
|
@ -2,9 +2,6 @@ package main
|
|||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"github.com/codegangsta/cli"
|
||||
)
|
||||
|
@ -17,21 +14,7 @@ var secretListCmd = cli.Command{
|
|||
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",
|
||||
},
|
||||
},
|
||||
Flags: secretListFlags(),
|
||||
}
|
||||
|
||||
func secretList(c *cli.Context) error {
|
||||
|
@ -53,35 +36,5 @@ func secretList(c *cli.Context) error {
|
|||
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, ", ")
|
||||
},
|
||||
return secretDisplayList(secrets, c)
|
||||
}
|
||||
|
|
|
@ -74,6 +74,15 @@ func Load(middleware ...gin.HandlerFunc) http.Handler {
|
|||
}
|
||||
}
|
||||
|
||||
global := e.Group("/api/global")
|
||||
{
|
||||
global.Use(session.MustAdmin())
|
||||
|
||||
global.GET("/secrets", server.GetGlobalSecrets)
|
||||
global.POST("/secrets", server.PostGlobalSecret)
|
||||
global.DELETE("/secrets/:secret", server.DeleteGlobalSecret)
|
||||
}
|
||||
|
||||
repos := e.Group("/api/repos/:owner/:name")
|
||||
{
|
||||
repos.POST("", server.PostRepo)
|
||||
|
|
62
server/global_secret.go
Normal file
62
server/global_secret.go
Normal file
|
@ -0,0 +1,62 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/drone/drone/model"
|
||||
"github.com/drone/drone/store"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func GetGlobalSecrets(c *gin.Context) {
|
||||
secrets, err := store.GetGlobalSecretList(c)
|
||||
|
||||
if err != nil {
|
||||
c.AbortWithStatus(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
var list []*model.TeamSecret
|
||||
|
||||
for _, s := range secrets {
|
||||
list = append(list, s.Clone())
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, list)
|
||||
}
|
||||
|
||||
func PostGlobalSecret(c *gin.Context) {
|
||||
in := &model.TeamSecret{}
|
||||
err := c.Bind(in)
|
||||
if err != nil {
|
||||
c.String(http.StatusBadRequest, "Invalid JSON input. %s", err.Error())
|
||||
return
|
||||
}
|
||||
in.ID = 0
|
||||
|
||||
err = store.SetGlobalSecret(c, in)
|
||||
if err != nil {
|
||||
c.String(http.StatusInternalServerError, "Unable to persist global secret. %s", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
c.String(http.StatusOK, "")
|
||||
}
|
||||
|
||||
func DeleteGlobalSecret(c *gin.Context) {
|
||||
name := c.Param("secret")
|
||||
|
||||
secret, err := store.GetGlobalSecret(c, name)
|
||||
if err != nil {
|
||||
c.String(http.StatusNotFound, "Cannot find secret %s.", name)
|
||||
return
|
||||
}
|
||||
err = store.DeleteGlobalSecret(c, secret)
|
||||
if err != nil {
|
||||
c.String(http.StatusInternalServerError, "Unable to delete global secret. %s", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
c.String(http.StatusOK, "")
|
||||
}
|
|
@ -146,6 +146,8 @@ type Store interface {
|
|||
DeleteAgent(*model.Agent) error
|
||||
}
|
||||
|
||||
const globalTeamName = "__global__"
|
||||
|
||||
// GetUser gets a user by unique ID.
|
||||
func GetUser(c context.Context, id int64) (*model.User, error) {
|
||||
return FromContext(c).GetUser(id)
|
||||
|
@ -246,12 +248,30 @@ func DeleteTeamSecret(c context.Context, s *model.TeamSecret) error {
|
|||
return FromContext(c).DeleteTeamSecret(s)
|
||||
}
|
||||
|
||||
func GetGlobalSecretList(c context.Context) ([]*model.TeamSecret, error) {
|
||||
return GetTeamSecretList(c, globalTeamName)
|
||||
}
|
||||
|
||||
func GetGlobalSecret(c context.Context, name string) (*model.TeamSecret, error) {
|
||||
return GetTeamSecret(c, globalTeamName, name)
|
||||
}
|
||||
|
||||
func SetGlobalSecret(c context.Context, s *model.TeamSecret) error {
|
||||
s.Key = globalTeamName
|
||||
return SetTeamSecret(c, s)
|
||||
}
|
||||
|
||||
func DeleteGlobalSecret(c context.Context, s *model.TeamSecret) error {
|
||||
s.Key = globalTeamName
|
||||
return DeleteTeamSecret(c, s)
|
||||
}
|
||||
|
||||
func GetMergedSecretList(c context.Context, r *model.Repo) ([]*model.Secret, error) {
|
||||
var (
|
||||
secrets []*model.Secret
|
||||
)
|
||||
|
||||
repoSecs, err := FromContext(c).GetSecretList(r)
|
||||
repoSecs, err := GetSecretList(c, r)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -261,7 +281,7 @@ func GetMergedSecretList(c context.Context, r *model.Repo) ([]*model.Secret, err
|
|||
secrets = append(secrets, secret.Secret())
|
||||
}
|
||||
|
||||
teamSecs, err := FromContext(c).GetTeamSecretList(r.Owner)
|
||||
teamSecs, err := GetTeamSecretList(c, r.Owner)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -271,6 +291,16 @@ func GetMergedSecretList(c context.Context, r *model.Repo) ([]*model.Secret, err
|
|||
secrets = append(secrets, secret.Secret())
|
||||
}
|
||||
|
||||
globalSecs, err := GetGlobalSecretList(c)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, secret := range globalSecs {
|
||||
secrets = append(secrets, secret.Secret())
|
||||
}
|
||||
|
||||
return secrets, nil
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue