migrate almost all CLI commands to core

This commit is contained in:
Brad Rydzewski 2016-05-06 10:59:36 -07:00
parent eaf2d30335
commit c07e8f1520
34 changed files with 1224 additions and 212 deletions

View file

@ -21,4 +21,4 @@ ADD drone/drone /drone
#RUN echo 'hosts: files mdns4_minimal [NOTFOUND=return] dns mdns4' >> /etc/nsswitch.conf #RUN echo 'hosts: files mdns4_minimal [NOTFOUND=return] dns mdns4' >> /etc/nsswitch.conf
ENTRYPOINT ["/drone"] ENTRYPOINT ["/drone"]
CMD ["daemon"] CMD ["server"]

View file

@ -9,6 +9,43 @@ import (
// Client is used to communicate with a Drone server. // Client is used to communicate with a Drone server.
type Client interface { type Client interface {
// Self returns the currently authenticated user.
Self() (*model.User, error)
// User returns a user by login.
User(string) (*model.User, error)
// UserList returns a list of all registered users.
UserList() ([]*model.User, error)
// UserPost creates a new user account.
UserPost(*model.User) (*model.User, error)
// UserPatch updates a user account.
UserPatch(*model.User) (*model.User, error)
// UserDel deletes a user account.
UserDel(string) error
// // UserFeed returns the user's activity feed.
// UserFeed() ([]*Activity, error)
// Repo returns a repository by name.
Repo(string, string) (*model.Repo, error)
// RepoList returns a list of all repositories to which
// the user has explicit access in the host system.
RepoList() ([]*model.Repo, error)
// RepoPost activates a repository.
RepoPost(string, string) (*model.Repo, error)
// RepoPatch updates a repository.
RepoPatch(*model.Repo) (*model.Repo, error)
// RepoDel deletes a repository.
RepoDel(string, string) error
// Sign returns a cryptographic signature for the input string. // Sign returns a cryptographic signature for the input string.
Sign(string, string, []byte) ([]byte, error) Sign(string, string, []byte) ([]byte, error)
@ -18,6 +55,38 @@ type Client interface {
// SecretDel deletes a named repository secret. // SecretDel deletes a named repository secret.
SecretDel(string, string, string) error SecretDel(string, string, string) error
// Build returns a repository build by number.
Build(string, string, int) (*model.Build, error)
// BuildLast returns the latest repository build by branch.
// An empty branch will result in the default branch.
BuildLast(string, string, string) (*model.Build, error)
// BuildList returns a list of recent builds for the
// the specified repository.
BuildList(string, string) ([]*model.Build, error)
// BuildStart re-starts a stopped build.
BuildStart(string, string, int) (*model.Build, error)
// BuildStop stops the specified running job for given build.
BuildStop(string, string, int, int) error
// BuildFork re-starts a stopped build with a new build number,
// preserving the prior history.
BuildFork(string, string, int) (*model.Build, error)
// BuildLogs returns the build logs for the specified job.
BuildLogs(string, string, int, int) (io.ReadCloser, error)
// Deploy triggers a deployment for an existing build using the
// specified target environment.
Deploy(string, string, int, string) (*model.Build, error)
//
// queue functions
//
// Pull pulls work from the server queue. // Pull pulls work from the server queue.
Pull(os, arch string) (*queue.Work, error) Pull(os, arch string) (*queue.Work, error)

View file

@ -74,6 +74,164 @@ func NewClientTokenTLS(uri, token string, c *tls.Config) Client {
return &client{auther, uri} return &client{auther, uri}
} }
// Self returns the currently authenticated user.
func (c *client) Self() (*model.User, error) {
out := new(model.User)
uri := fmt.Sprintf(pathSelf, c.base)
err := c.get(uri, out)
return out, err
}
// User returns a user by login.
func (c *client) User(login string) (*model.User, error) {
out := new(model.User)
uri := fmt.Sprintf(pathUser, c.base, login)
err := c.get(uri, out)
return out, err
}
// UserList returns a list of all registered users.
func (c *client) UserList() ([]*model.User, error) {
var out []*model.User
uri := fmt.Sprintf(pathUsers, c.base)
err := c.get(uri, &out)
return out, err
}
// UserPost creates a new user account.
func (c *client) UserPost(in *model.User) (*model.User, error) {
out := new(model.User)
uri := fmt.Sprintf(pathUsers, c.base)
err := c.post(uri, in, out)
return out, err
}
// UserPatch updates a user account.
func (c *client) UserPatch(in *model.User) (*model.User, error) {
out := new(model.User)
uri := fmt.Sprintf(pathUser, c.base, in.Login)
err := c.patch(uri, in, out)
return out, err
}
// UserDel deletes a user account.
func (c *client) UserDel(login string) error {
uri := fmt.Sprintf(pathUser, c.base, login)
err := c.delete(uri)
return err
}
// Repo returns a repository by name.
func (c *client) Repo(owner string, name string) (*model.Repo, error) {
out := new(model.Repo)
uri := fmt.Sprintf(pathRepo, c.base, owner, name)
err := c.get(uri, out)
return out, err
}
// RepoList returns a list of all repositories to which
// the user has explicit access in the host system.
func (c *client) RepoList() ([]*model.Repo, error) {
var out []*model.Repo
uri := fmt.Sprintf(pathRepos, c.base)
err := c.get(uri, &out)
return out, err
}
// RepoPost activates a repository.
func (c *client) RepoPost(owner string, name string) (*model.Repo, error) {
out := new(model.Repo)
uri := fmt.Sprintf(pathRepo, c.base, owner, name)
err := c.post(uri, nil, out)
return out, err
}
// RepoPatch updates a repository.
func (c *client) RepoPatch(in *model.Repo) (*model.Repo, error) {
out := new(model.Repo)
uri := fmt.Sprintf(pathRepo, c.base, in.Owner, in.Name)
err := c.patch(uri, in, out)
return out, err
}
// RepoDel deletes a repository.
func (c *client) RepoDel(owner, name string) error {
uri := fmt.Sprintf(pathRepo, c.base, owner, name)
err := c.delete(uri)
return err
}
// Build returns a repository build by number.
func (c *client) Build(owner, name string, num int) (*model.Build, error) {
out := new(model.Build)
uri := fmt.Sprintf(pathBuild, c.base, owner, name, num)
err := c.get(uri, out)
return out, err
}
// Build returns the latest repository build by branch.
func (c *client) BuildLast(owner, name, branch string) (*model.Build, error) {
out := new(model.Build)
uri := fmt.Sprintf(pathBuild, c.base, owner, name, "latest")
if len(branch) != 0 {
uri += "?branch=" + branch
}
err := c.get(uri, out)
return out, err
}
// BuildList returns a list of recent builds for the
// the specified repository.
func (c *client) BuildList(owner, name string) ([]*model.Build, error) {
var out []*model.Build
uri := fmt.Sprintf(pathBuilds, c.base, owner, name)
err := c.get(uri, &out)
return out, err
}
// BuildStart re-starts a stopped build.
func (c *client) BuildStart(owner, name string, num int) (*model.Build, error) {
out := new(model.Build)
uri := fmt.Sprintf(pathBuild, c.base, owner, name, num)
err := c.post(uri, nil, out)
return out, err
}
// BuildStop cancels the running job.
func (c *client) BuildStop(owner, name string, num, job int) error {
uri := fmt.Sprintf(pathJob, c.base, owner, name, num, job)
err := c.delete(uri)
return err
}
// BuildFork re-starts a stopped build with a new build number,
// preserving the prior history.
func (c *client) BuildFork(owner, name string, num int) (*model.Build, error) {
out := new(model.Build)
uri := fmt.Sprintf(pathBuild+"?fork=true", c.base, owner, name, num)
err := c.post(uri, nil, out)
return out, err
}
// BuildLogs returns the build logs for the specified job.
func (c *client) BuildLogs(owner, name string, num, job int) (io.ReadCloser, error) {
uri := fmt.Sprintf(pathLog, c.base, owner, name, num, job)
return stream(c.client, uri, "GET", nil, nil)
}
// Deploy triggers a deployment for an existing build using the
// specified target environment.
func (c *client) Deploy(owner, name string, num int, env string) (*model.Build, error) {
out := new(model.Build)
val := url.Values{}
val.Set("fork", "true")
val.Set("event", "deployment")
val.Set("deploy_to", env)
uri := fmt.Sprintf(pathBuild+"?"+val.Encode(), c.base, owner, name, num)
err := c.post(uri, nil, out)
return out, err
}
// SecretPost create or updates a repository secret. // SecretPost create or updates a repository secret.
func (c *client) SecretPost(owner, name string, secret *model.Secret) error { func (c *client) SecretPost(owner, name string, secret *model.Secret) error {
uri := fmt.Sprintf(pathSecrets, c.base, owner, name) uri := fmt.Sprintf(pathSecrets, c.base, owner, name)

View file

@ -90,12 +90,7 @@ func (r *pipeline) run() error {
} }
trans := []compiler.Transform{ trans := []compiler.Transform{
builtin.NewCloneOp("git", true), builtin.NewCloneOp(w.Repo.Kind, true),
builtin.NewCacheOp(
"plugins/cache:latest",
"/var/lib/drone/cache/"+w.Repo.FullName,
false,
),
builtin.NewSecretOp(w.Build.Event, secrets), builtin.NewSecretOp(w.Build.Event, secrets),
builtin.NewNormalizeOp(r.config.namespace), builtin.NewNormalizeOp(r.config.namespace),
builtin.NewWorkspaceOp("/drone", "/drone/src/github.com/"+w.Repo.FullName), builtin.NewWorkspaceOp("/drone", "/drone/src/github.com/"+w.Repo.FullName),

15
drone/build.go Normal file
View file

@ -0,0 +1,15 @@
package main
import "github.com/codegangsta/cli"
var buildCmd = cli.Command{
Name: "build",
Usage: "manage builds",
Subcommands: []cli.Command{
buildListCmd,
buildLastCmd,
buildInfoCmd,
buildStopCmd,
buildStartCmd,
},
}

66
drone/build_info.go Normal file
View file

@ -0,0 +1,66 @@
package main
import (
"log"
"os"
"strconv"
"text/template"
"github.com/codegangsta/cli"
)
var buildInfoCmd = cli.Command{
Name: "info",
Usage: "show build details",
Action: func(c *cli.Context) {
if err := buildInfo(c); err != nil {
log.Fatalln(err)
}
},
Flags: []cli.Flag{
cli.StringFlag{
Name: "format",
Usage: "format output",
Value: tmplBuildInfo,
},
},
}
func buildInfo(c *cli.Context) error {
repo := c.Args().First()
owner, name, err := parseRepo(repo)
if err != nil {
return err
}
number, err := strconv.Atoi(c.Args().Get(1))
if err != nil {
return err
}
client, err := newClient(c)
if err != nil {
return err
}
build, err := client.Build(owner, name, number)
if err != nil {
return err
}
tmpl, err := template.New("_").Parse(c.String("format"))
if err != nil {
return err
}
return tmpl.Execute(os.Stdout, build)
}
// template for build information
var tmplBuildInfo = `Number: {{ .Number }}
Status: {{ .Status }}
Event: {{ .Event }}
Commit: {{ .Commit }}
Branch: {{ .Branch }}
Ref: {{ .Ref }}
Message: {{ .Message }}
Author: {{ .Author }}
`

55
drone/build_last.go Normal file
View file

@ -0,0 +1,55 @@
package main
import (
"log"
"os"
"text/template"
"github.com/codegangsta/cli"
)
var buildLastCmd = cli.Command{
Name: "last",
Usage: "show latest build details",
Action: func(c *cli.Context) {
if err := buildLast(c); err != nil {
log.Fatalln(err)
}
},
Flags: []cli.Flag{
cli.StringFlag{
Name: "format",
Usage: "format output",
Value: tmplBuildInfo,
},
cli.StringFlag{
Name: "branch",
Usage: "branch name",
Value: "master",
},
},
}
func buildLast(c *cli.Context) error {
repo := c.Args().First()
owner, name, err := parseRepo(repo)
if err != nil {
return err
}
client, err := newClient(c)
if err != nil {
return err
}
build, err := client.BuildLast(owner, name, c.String("branch"))
if err != nil {
return err
}
tmpl, err := template.New("_").Parse(c.String("format"))
if err != nil {
return err
}
return tmpl.Execute(os.Stdout, build)
}

101
drone/build_list.go Normal file
View file

@ -0,0 +1,101 @@
package main
import (
"log"
"os"
"text/template"
"github.com/codegangsta/cli"
)
var buildListCmd = cli.Command{
Name: "list",
Usage: "show build history",
Action: func(c *cli.Context) {
if err := buildList(c); err != nil {
log.Fatalln(err)
}
},
Flags: []cli.Flag{
cli.StringFlag{
Name: "format",
Usage: "format output",
Value: tmplBuildList,
},
cli.StringFlag{
Name: "branch",
Usage: "branch filter",
},
cli.StringFlag{
Name: "event",
Usage: "event filter",
},
cli.StringFlag{
Name: "status",
Usage: "status filter",
},
cli.IntFlag{
Name: "limit",
Usage: "limit the list size",
Value: 25,
},
},
}
func buildList(c *cli.Context) error {
repo := c.Args().First()
owner, name, err := parseRepo(repo)
if err != nil {
return err
}
client, err := newClient(c)
if err != nil {
return err
}
builds, err := client.BuildList(owner, name)
if err != nil {
return err
}
tmpl, err := template.New("_").Parse(c.String("format") + "\n")
if err != nil {
return err
}
branch := c.String("branch")
event := c.String("event")
status := c.String("status")
limit := c.Int("limit")
var count int
for _, build := range builds {
if count >= limit {
break
}
if branch != "" && build.Branch != branch {
continue
}
if event != "" && build.Event != event {
continue
}
if status != "" && build.Status != status {
continue
}
tmpl.Execute(os.Stdout, build)
count++
}
return nil
}
// template for build list information
var tmplBuildList = "\x1b[33mBuild #{{ .Number }} \x1b[0m" + `
Status: {{ .Status }}
Event: {{ .Event }}
Commit: {{ .Commit }}
Branch: {{ .Branch }}
Ref: {{ .Ref }}
Author: {{ .Author }} {{ if .Email }}<{{.Email}}>{{ end }}
Message: {{ .Message }}
`

56
drone/build_start.go Normal file
View file

@ -0,0 +1,56 @@
package main
import (
"fmt"
"log"
"strconv"
"github.com/codegangsta/cli"
"github.com/drone/drone/model"
)
var buildStartCmd = cli.Command{
Name: "start",
Usage: "start a build",
Action: func(c *cli.Context) {
if err := buildStart(c); err != nil {
log.Fatalln(err)
}
},
Flags: []cli.Flag{
cli.BoolFlag{
Name: "fork",
Usage: "fork the build",
},
},
}
func buildStart(c *cli.Context) (err error) {
repo := c.Args().First()
owner, name, err := parseRepo(repo)
if err != nil {
return err
}
number, err := strconv.Atoi(c.Args().Get(1))
if err != nil {
return err
}
client, err := newClient(c)
if err != nil {
return err
}
var build *model.Build
if c.Bool("fork") {
build, err = client.BuildStart(owner, name, number)
} else {
build, err = client.BuildFork(owner, name, number)
}
if err != nil {
return err
}
fmt.Printf("Starting build %s/%s#%d\n", owner, name, build.Number)
return nil
}

48
drone/build_stop.go Normal file
View file

@ -0,0 +1,48 @@
package main
import (
"fmt"
"log"
"strconv"
"github.com/codegangsta/cli"
)
var buildStopCmd = cli.Command{
Name: "stop",
Usage: "stop a build",
Action: func(c *cli.Context) {
if err := buildStop(c); err != nil {
log.Fatalln(err)
}
},
}
func buildStop(c *cli.Context) (err error) {
repo := c.Args().First()
owner, name, err := parseRepo(repo)
if err != nil {
return err
}
number, err := strconv.Atoi(c.Args().Get(1))
if err != nil {
return err
}
job, _ := strconv.Atoi(c.Args().Get(2))
if job == 0 {
job = 1
}
client, err := newClient(c)
if err != nil {
return err
}
err = client.BuildStop(owner, name, number, job)
if err != nil {
return err
}
fmt.Printf("Stopping build %s/%s#%d.%d\n", owner, name, number, job)
return nil
}

1
drone/compile.go Normal file
View file

@ -0,0 +1 @@
package main

80
drone/deploy.go Normal file
View file

@ -0,0 +1,80 @@
package main
import (
"fmt"
"html/template"
"log"
"os"
"strconv"
"github.com/codegangsta/cli"
"github.com/drone/drone-go/drone"
)
var deployCmd = cli.Command{
Name: "deploy",
Usage: "deploy code",
Action: func(c *cli.Context) {
if err := deploy(c); err != nil {
log.Fatalln(err)
}
},
Flags: []cli.Flag{
cli.StringFlag{
Name: "format",
Usage: "format output",
Value: tmplDeployInfo,
},
},
}
func deploy(c *cli.Context) error {
repo := c.Args().First()
owner, name, err := parseRepo(repo)
if err != nil {
return err
}
number, err := strconv.Atoi(c.Args().Get(1))
if err != nil {
return err
}
client, err := newClient(c)
if err != nil {
return err
}
build, err := client.Build(owner, name, number)
if err != nil {
return err
}
if build.Event == drone.EventPull {
return fmt.Errorf("Cannot deploy a pull request")
}
env := c.Args().Get(2)
if env == "" {
return fmt.Errorf("Please specify the target environment (ie production)")
}
deploy, err := client.Deploy(owner, name, number, env)
if err != nil {
return err
}
tmpl, err := template.New("_").Parse(c.String("format"))
if err != nil {
return err
}
return tmpl.Execute(os.Stdout, deploy)
}
// template for deployment information
var tmplDeployInfo = `Number: {{ .Number }}
Status: {{ .Status }}
Commit: {{ .Commit }}
Branch: {{ .Branch }}
Ref: {{ .Ref }}
Message: {{ .Message }}
Author: {{ .Author }}
Target: {{ .Deploy }}
`

1
drone/exec.go Normal file
View file

@ -0,0 +1 @@
package main

49
drone/info.go Normal file
View file

@ -0,0 +1,49 @@
package main
import (
"log"
"os"
"text/template"
"github.com/codegangsta/cli"
)
var infoCmd = cli.Command{
Name: "info",
Usage: "should information about the current user",
Action: func(c *cli.Context) {
if err := info(c); err != nil {
log.Fatalln(err)
}
},
Flags: []cli.Flag{
cli.StringFlag{
Name: "format",
Usage: "format output",
Value: tmplUserInfo,
},
},
}
func info(c *cli.Context) error {
client, err := newClient(c)
if err != nil {
return err
}
user, err := client.Self()
if err != nil {
return err
}
tmpl, err := template.New("_").Parse(c.String("format") + "\n")
if err != nil {
return err
}
return tmpl.Execute(os.Stdout, user)
}
// template for user information
var tmplInfo = `User: {{ .Login }}
Email: {{ .Email }}`

View file

@ -21,22 +21,25 @@ func main() {
app.Flags = []cli.Flag{ app.Flags = []cli.Flag{
cli.StringFlag{ cli.StringFlag{
Name: "t, token", Name: "t, token",
Value: "",
Usage: "server auth token", Usage: "server auth token",
EnvVar: "DRONE_TOKEN", EnvVar: "DRONE_TOKEN",
}, },
cli.StringFlag{ cli.StringFlag{
Name: "s, server", Name: "s, server",
Value: "",
Usage: "server location", Usage: "server location",
EnvVar: "DRONE_SERVER", EnvVar: "DRONE_SERVER",
}, },
} }
app.Commands = []cli.Command{ app.Commands = []cli.Command{
agent.AgentCmd, agent.AgentCmd,
DaemonCmd, buildCmd,
SignCmd, deployCmd,
SecretCmd, infoCmd,
secretCmd,
serverCmd,
signCmd,
repoCmd,
userCmd,
} }
app.Run(os.Args) app.Run(os.Args)

14
drone/repo.go Normal file
View file

@ -0,0 +1,14 @@
package main
import "github.com/codegangsta/cli"
var repoCmd = cli.Command{
Name: "repo",
Usage: "manage repositories",
Subcommands: []cli.Command{
repoListCmd,
repoInfoCmd,
repoAddCmd,
repoRemoveCmd,
},
}

37
drone/repo_add.go Normal file
View file

@ -0,0 +1,37 @@
package main
import (
"fmt"
"log"
"github.com/codegangsta/cli"
)
var repoAddCmd = cli.Command{
Name: "add",
Usage: "add a repository",
Action: func(c *cli.Context) {
if err := repoRemove(c); err != nil {
log.Fatalln(err)
}
},
}
func repoAdd(c *cli.Context) error {
repo := c.Args().First()
owner, name, err := parseRepo(repo)
if err != nil {
return err
}
client, err := newClient(c)
if err != nil {
return err
}
if _, err := client.RepoPost(owner, name); err != nil {
return err
}
fmt.Printf("Successfully activated repository %s/%s\n", owner, name)
return nil
}

58
drone/repo_info.go Normal file
View file

@ -0,0 +1,58 @@
package main
import (
"log"
"os"
"text/template"
"github.com/codegangsta/cli"
)
var repoInfoCmd = cli.Command{
Name: "info",
Usage: "show repository details",
Action: func(c *cli.Context) {
if err := repoInfo(c); err != nil {
log.Fatalln(err)
}
},
Flags: []cli.Flag{
cli.StringFlag{
Name: "format",
Usage: "format output",
Value: tmplRepoInfo,
},
},
}
func repoInfo(c *cli.Context) error {
arg := c.Args().First()
owner, name, err := parseRepo(arg)
if err != nil {
return err
}
client, err := newClient(c)
if err != nil {
return err
}
repo, err := client.Repo(owner, name)
if err != nil {
return err
}
tmpl, err := template.New("_").Parse(c.String("format"))
if err != nil {
return err
}
return tmpl.Execute(os.Stdout, repo)
}
// template for repo information
var tmplRepoInfo = `Owner: {{ .Owner }}
Repo: {{ .Name }}
Type: {{ .Kind }}
Private: {{ .IsPrivate }}
Remote: {{ .Clone }}
`

59
drone/repo_list.go Normal file
View file

@ -0,0 +1,59 @@
package main
import (
"log"
"os"
"text/template"
"github.com/codegangsta/cli"
)
var repoListCmd = cli.Command{
Name: "ls",
Usage: "list all repos",
Action: func(c *cli.Context) {
if err := repoList(c); err != nil {
log.Fatalln(err)
}
},
Flags: []cli.Flag{
cli.StringFlag{
Name: "format",
Usage: "format output",
Value: tmplRepoList,
},
cli.StringFlag{
Name: "org",
Usage: "filter by organization",
},
},
}
func repoList(c *cli.Context) error {
client, err := newClient(c)
if err != nil {
return err
}
repos, err := client.RepoList()
if err != nil || len(repos) == 0 {
return err
}
tmpl, err := template.New("_").Parse(c.String("format") + "\n")
if err != nil {
return err
}
org := c.String("org")
for _, repo := range repos {
if org != "" && org != repo.Owner {
continue
}
tmpl.Execute(os.Stdout, repo)
}
return nil
}
// template for repository list items
var tmplRepoList = `{{ .FullName }}`

37
drone/repo_rm.go Normal file
View file

@ -0,0 +1,37 @@
package main
import (
"fmt"
"log"
"github.com/codegangsta/cli"
)
var repoRemoveCmd = cli.Command{
Name: "rm",
Usage: "remove a repository",
Action: func(c *cli.Context) {
if err := repoRemove(c); err != nil {
log.Fatalln(err)
}
},
}
func repoRemove(c *cli.Context) error {
repo := c.Args().First()
owner, name, err := parseRepo(repo)
if err != nil {
return err
}
client, err := newClient(c)
if err != nil {
return err
}
if err := client.RepoDel(owner, name); err != nil {
return err
}
fmt.Printf("Successfully removed repository %s/%s\n", owner, name)
return nil
}

80
drone/secert_add.go Normal file
View file

@ -0,0 +1,80 @@
package main
import (
"fmt"
"io/ioutil"
"log"
"strings"
"github.com/codegangsta/cli"
"github.com/drone/drone/model"
)
var secretAddCmd = cli.Command{
Name: "add",
Usage: "adds a secret",
ArgsUsage: "[repo] [key] [value]",
Action: func(c *cli.Context) {
if err := secretAdd(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{},
},
},
}
func secretAdd(c *cli.Context) error {
repo := c.Args().First()
owner, name, err := parseRepo(repo)
if err != nil {
return err
}
tail := c.Args().Tail()
if len(tail) != 2 {
cli.ShowSubcommandHelp(c)
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")
}
// allow secret value to come from a file when prefixed with the @ symbol,
// similar to curl conventions.
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.SecretPost(owner, name, secret)
}

View file

@ -1,103 +1,12 @@
package main package main
import ( import "github.com/codegangsta/cli"
"fmt"
"log"
"github.com/drone/drone/model" var secretCmd = cli.Command{
"github.com/codegangsta/cli"
)
// SecretCmd is the exported command for managing secrets.
var SecretCmd = cli.Command{
Name: "secret", Name: "secret",
Usage: "manage secrets", Usage: "manage secrets",
Subcommands: []cli.Command{ Subcommands: []cli.Command{
// Secret Add secretAddCmd,
{ secretRemoveCmd,
Name: "add",
Usage: "add a secret",
ArgsUsage: "[repo] [key] [value]",
Action: func(c *cli.Context) {
if err := secretAdd(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{},
},
},
},
// Secret Delete
{
Name: "rm",
Usage: "remove a secret",
Action: func(c *cli.Context) {
if err := secretDel(c); err != nil {
log.Fatalln(err)
}
},
},
}, },
} }
func secretAdd(c *cli.Context) error {
repo := c.Args().First()
owner, name, err := parseRepo(repo)
if err != nil {
return err
}
tail := c.Args().Tail()
if len(tail) != 2 {
cli.ShowSubcommandHelp(c)
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")
}
client, err := newClient(c)
if err != nil {
return err
}
return client.SecretPost(owner, name, secret)
}
func secretDel(c *cli.Context) error {
repo := c.Args().First()
owner, name, err := parseRepo(repo)
if err != nil {
return err
}
secret := c.Args().Get(1)
client, err := newClient(c)
if err != nil {
return err
}
return client.SecretDel(owner, name, secret)
}

1
drone/secret_info.go Normal file
View file

@ -0,0 +1 @@
package main

1
drone/secret_list.go Normal file
View file

@ -0,0 +1 @@
package main

33
drone/secret_rm.go Normal file
View file

@ -0,0 +1,33 @@
package main
import (
"log"
"github.com/codegangsta/cli"
)
var secretRemoveCmd = cli.Command{
Name: "rm",
Usage: "remove a secret",
Action: func(c *cli.Context) {
if err := secretRemove(c); err != nil {
log.Fatalln(err)
}
},
}
func secretRemove(c *cli.Context) error {
repo := c.Args().First()
owner, name, err := parseRepo(repo)
if err != nil {
return err
}
secret := c.Args().Get(1)
client, err := newClient(c)
if err != nil {
return err
}
return client.SecretDel(owner, name, secret)
}

View file

@ -14,12 +14,11 @@ import (
"github.com/codegangsta/cli" "github.com/codegangsta/cli"
) )
// DaemonCmd is the exported command for starting the drone server daemon. var serverCmd = cli.Command{
var DaemonCmd = cli.Command{ Name: "server",
Name: "daemon",
Usage: "starts the drone server daemon", Usage: "starts the drone server daemon",
Action: func(c *cli.Context) { Action: func(c *cli.Context) {
if err := start(c); err != nil { if err := server(c); err != nil {
logrus.Fatal(err) logrus.Fatal(err)
} }
}, },
@ -275,7 +274,7 @@ var DaemonCmd = cli.Command{
}, },
} }
func start(c *cli.Context) error { func server(c *cli.Context) error {
if c.Bool("agreement.ack") == false || c.Bool("agreement.fix") == false { if c.Bool("agreement.ack") == false || c.Bool("agreement.fix") == false {
fmt.Println(agreement) fmt.Println(agreement)

View file

@ -7,8 +7,7 @@ import (
"github.com/codegangsta/cli" "github.com/codegangsta/cli"
) )
// SignCmd is the exported command for signing the yaml. var signCmd = cli.Command{
var SignCmd = cli.Command{
Name: "sign", Name: "sign",
Usage: "creates a secure yaml file", Usage: "creates a secure yaml file",
Action: func(c *cli.Context) { Action: func(c *cli.Context) {

14
drone/user.go Normal file
View file

@ -0,0 +1,14 @@
package main
import "github.com/codegangsta/cli"
var userCmd = cli.Command{
Name: "user",
Usage: "manage users",
Subcommands: []cli.Command{
userListCmd,
userInfoCmd,
userAddCmd,
userRemoveCmd,
},
}

35
drone/user_add.go Normal file
View file

@ -0,0 +1,35 @@
package main
import (
"fmt"
"log"
"github.com/codegangsta/cli"
"github.com/drone/drone/model"
)
var userAddCmd = cli.Command{
Name: "add",
Usage: "adds a user",
Action: func(c *cli.Context) {
if err := userAdd(c); err != nil {
log.Fatalln(err)
}
},
}
func userAdd(c *cli.Context) error {
login := c.Args().First()
client, err := newClient(c)
if err != nil {
return err
}
user, err := client.UserPost(&model.User{Login: login})
if err != nil {
return err
}
fmt.Printf("Successfully added user %s\n", user.Login)
return nil
}

54
drone/user_info.go Normal file
View file

@ -0,0 +1,54 @@
package main
import (
"fmt"
"log"
"os"
"text/template"
"github.com/codegangsta/cli"
)
var userInfoCmd = cli.Command{
Name: "info",
Usage: "show user details",
Action: func(c *cli.Context) {
if err := userInfo(c); err != nil {
log.Fatalln(err)
}
},
Flags: []cli.Flag{
cli.StringFlag{
Name: "format",
Usage: "format output",
Value: tmplUserInfo,
},
},
}
func userInfo(c *cli.Context) error {
client, err := newClient(c)
if err != nil {
return err
}
login := c.Args().First()
if len(login) == 0 {
return fmt.Errorf("Missing or invalid user login")
}
user, err := client.User(login)
if err != nil {
return err
}
tmpl, err := template.New("_").Parse(c.String("format") + "\n")
if err != nil {
return err
}
return tmpl.Execute(os.Stdout, user)
}
// template for user information
var tmplUserInfo = `User: {{ .Login }}
Email: {{ .Email }}`

50
drone/user_list.go Normal file
View file

@ -0,0 +1,50 @@
package main
import (
"log"
"os"
"text/template"
"github.com/codegangsta/cli"
)
var userListCmd = cli.Command{
Name: "ls",
Usage: "list all users",
Action: func(c *cli.Context) {
if err := userList(c); err != nil {
log.Fatalln(err)
}
},
Flags: []cli.Flag{
cli.StringFlag{
Name: "format",
Usage: "format output",
Value: tmplUserList,
},
},
}
func userList(c *cli.Context) error {
client, err := newClient(c)
if err != nil {
return err
}
users, err := client.UserList()
if err != nil || len(users) == 0 {
return err
}
tmpl, err := template.New("_").Parse(c.String("format") + "\n")
if err != nil {
return err
}
for _, user := range users {
tmpl.Execute(os.Stdout, user)
}
return nil
}
// template for user list items
var tmplUserList = `{{ .Login }}`

33
drone/user_rm.go Normal file
View file

@ -0,0 +1,33 @@
package main
import (
"fmt"
"log"
"github.com/codegangsta/cli"
)
var userRemoveCmd = cli.Command{
Name: "rm",
Usage: "remove a user",
Action: func(c *cli.Context) {
if err := userRemove(c); err != nil {
log.Fatalln(err)
}
},
}
func userRemove(c *cli.Context) error {
login := c.Args().First()
client, err := newClient(c)
if err != nil {
return err
}
if err := client.UserDel(login); err != nil {
return err
}
fmt.Printf("Successfully removed user %s\n", login)
return nil
}

View file

@ -1,61 +0,0 @@
package builtin
import (
"github.com/drone/drone/engine/runner"
"github.com/drone/drone/engine/compiler/parse"
)
type cacheOp struct {
visitor
enable bool
plugin string
mount string
}
// NewCacheOp returns a transformer that configures the default cache plugin.
func NewCacheOp(plugin, mount string, enable bool) Visitor {
return &cacheOp{
mount: mount,
enable: enable,
plugin: plugin,
}
}
func (v *cacheOp) VisitContainer(node *parse.ContainerNode) error {
if node.Type() != parse.NodeCache {
return nil
}
if len(node.Vargs) == 0 || v.enable == false {
node.Disabled = true
return nil
}
if node.Container.Name == "" {
node.Container.Name = "cache"
}
if node.Container.Image == "" {
node.Container.Image = v.plugin
}
// discard any other cache properties except the image name.
// everything else is discard for security reasons.
node.Container = runner.Container{
Name: node.Container.Name,
Alias: node.Container.Alias,
Image: node.Container.Image,
Volumes: []string{
v.mount + ":/cache",
},
}
// this is a hack until I can come up with a better solution.
// this copies the clone name, and appends at the end of the
// build. When it is executed a second time the build should
// have a completed status, so it knows to cache instead
// of restore.
cache := node.Root().NewCacheNode()
cache.Vargs = node.Vargs
cache.Container = node.Container
node.Root().Script = append(node.Root().Script, cache)
return nil
}

View file

@ -1,37 +0,0 @@
package builtin
// import (
// "testing"
// "github.com/libcd/libcd"
// "github.com/libcd/libyaml/parse"
// "github.com/franela/goblin"
// )
// func Test_cache(t *testing.T) {
// root := parse.NewRootNode()
// g := goblin.Goblin(t)
// g.Describe("cache", func() {
// g.It("should use default when nil", func() {
// op := NewCacheOp("plugins/cache:latest", "/tmp/cache")
// op.VisitRoot(root)
// g.Assert(root.Cache.(*parse.ContainerNode).Container.Image).Equal("plugins/cache:latest")
// g.Assert(root.Cache.(*parse.ContainerNode).Container.Volumes[0]).Equal("/tmp/cache:/cache")
// })
// g.It("should use user-defined cache plugin", func() {
// op := NewCacheOp("plugins/cache:latest", "/tmp/cache")
// cache := root.NewCacheNode()
// cache.Container = libcd.Container{}
// cache.Container.Image = "custom/cacher:latest"
// root.Cache = cache
// op.VisitRoot(root)
// g.Assert(cache.Container.Image).Equal("custom/cacher:latest")
// })
// })
// }