diff --git a/client/command/build.go b/client/command/build.go new file mode 100644 index 000000000..8f70454d9 --- /dev/null +++ b/client/command/build.go @@ -0,0 +1,23 @@ +package main + +import ( + "github.com/codegangsta/cli" +) + +// NewBuildCommand returns the CLI command for "build". +func NewBuildCommand() cli.Command { + return cli.Command{ + Name: "build", + Usage: "run a local build", + Flags: []cli.Flag{}, + Action: func(c *cli.Context) { + buildCommandFunc(c) + }, + } +} + +// buildCommandFunc executes the "build" command. +func buildCommandFunc(c *cli.Context) error { + + return nil +} diff --git a/client/command/client.go b/client/command/client.go new file mode 100644 index 000000000..690cc8a1c --- /dev/null +++ b/client/command/client.go @@ -0,0 +1,104 @@ +package main + +import ( + "bytes" + "encoding/json" + "errors" + "io/ioutil" + "net/http" + "net/url" + "strconv" +) + +var ( + ErrNotFound = errors.New("Not Found") + ErrForbidden = errors.New("Forbidden") + ErrBadRequest = errors.New("Bad Request") + ErrNotAuthorized = errors.New("Unauthorized") + ErrInternalServer = errors.New("Internal Server Error") +) + +type Client struct { + Token string + URL string +} + +// Do submits an http.Request and parses the JSON-encoded http.Response, +// storing the result in the value pointed to by v. +func (c *Client) Do(method, path string, in, out interface{}) error { + + // create the URI + uri, err := url.Parse(c.URL + path) + if err != nil { + return err + } + + if len(uri.Scheme) == 0 { + uri.Scheme = "http" + } + + if len(c.Token) > 0 { + params := uri.Query() + params.Add("access_token", c.Token) + uri.RawQuery = params.Encode() + } + + // create the request + req := &http.Request{ + URL: uri, + Method: method, + ProtoMajor: 1, + ProtoMinor: 1, + Close: true, + ContentLength: 0, + } + + // if data input is provided, serialize to JSON + if in != nil { + inJson, err := json.Marshal(in) + if err != nil { + return err + } + + buf := bytes.NewBuffer(inJson) + req.Body = ioutil.NopCloser(buf) + + req.ContentLength = int64(len(inJson)) + req.Header.Set("Content-Length", strconv.Itoa(len(inJson))) + req.Header.Set("Content-Type", "application/json") + } + + // make the request using the default http client + resp, err := http.DefaultClient.Do(req) + if err != nil { + return err + } + + // Read the bytes from the body (make sure we defer close the body) + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return err + } + + // Check for an http error status (ie not 200 StatusOK) + switch resp.StatusCode { + case 404: + return ErrNotFound + case 403: + return ErrForbidden + case 401: + return ErrNotAuthorized + case 400: + return ErrBadRequest + case 500: + return ErrInternalServer + } + + // Unmarshall the JSON response + if out != nil { + return json.Unmarshal(body, out) + } + + return nil +} diff --git a/client/command/command b/client/command/command new file mode 100755 index 000000000..676797512 Binary files /dev/null and b/client/command/command differ diff --git a/client/command/disable.go b/client/command/disable.go new file mode 100644 index 000000000..5cdc4aae5 --- /dev/null +++ b/client/command/disable.go @@ -0,0 +1,34 @@ +package main + +import ( + "github.com/codegangsta/cli" +) + +// NewDisableCommand returns the CLI command for "disable". +func NewDisableCommand() cli.Command { + return cli.Command{ + Name: "disable", + Usage: "disable a repository", + Flags: []cli.Flag{}, + Action: func(c *cli.Context) { + handle(c, disableCommandFunc) + }, + } +} + +// disableCommandFunc executes the "disable" command. +func disableCommandFunc(c *cli.Context, client *Client) error { + var repo string + var arg = c.Args() + + if len(arg) != 0 { + repo = arg[0] + } + + err := client.Do("DELETE", "/v1/repos/"+repo, nil, nil) + if err != nil { + return err + } + + return nil +} diff --git a/client/command/enable.go b/client/command/enable.go new file mode 100644 index 000000000..5332a39dd --- /dev/null +++ b/client/command/enable.go @@ -0,0 +1,34 @@ +package main + +import ( + "github.com/codegangsta/cli" +) + +// NewEnableCommand returns the CLI command for "enable". +func NewEnableCommand() cli.Command { + return cli.Command{ + Name: "enable", + Usage: "enable a repository", + Flags: []cli.Flag{}, + Action: func(c *cli.Context) { + handle(c, enableCommandFunc) + }, + } +} + +// enableCommandFunc executes the "enable" command. +func enableCommandFunc(c *cli.Context, client *Client) error { + var repo string + var arg = c.Args() + + if len(arg) != 0 { + repo = arg[0] + } + + err := client.Do("POST", "/v1/repos/"+repo, nil, nil) + if err != nil { + return err + } + + return nil +} diff --git a/client/command/handle.go b/client/command/handle.go new file mode 100644 index 000000000..3634fd4f5 --- /dev/null +++ b/client/command/handle.go @@ -0,0 +1,29 @@ +package main + +import ( + "os" + + "github.com/codegangsta/cli" +) + +type handlerFunc func(*cli.Context, *Client) error + +// handle wraps the command function handlers and +// sets up the environment. +func handle(c *cli.Context, fn handlerFunc) { + client := Client{} + client.Token = os.Getenv("DRONE_TOKEN") + client.URL = os.Getenv("DRONE_HOST") + + // if no url is provided we can default + // to the hosted Drone service. + if len(client.URL) == 0 { + client.URL = "http://test.drone.io" + } + + // handle the function + if err := fn(c, &client); err != nil { + println(err.Error()) + os.Exit(1) + } +} diff --git a/client/command/main.go b/client/command/main.go new file mode 100644 index 000000000..31889ccee --- /dev/null +++ b/client/command/main.go @@ -0,0 +1,23 @@ +package main + +import ( + "github.com/codegangsta/cli" + "os" +) + +func main() { + app := cli.NewApp() + app.Name = "drone" + app.Version = "1.0" + app.Usage = "command line utility" + app.EnableBashCompletion = true + + app.Commands = []cli.Command{ + NewEnableCommand(), + NewDisableCommand(), + NewRestartCommand(), + NewWhoamiCommand(), + } + + app.Run(os.Args) +} diff --git a/client/command/restart.go b/client/command/restart.go new file mode 100644 index 000000000..df607dfff --- /dev/null +++ b/client/command/restart.go @@ -0,0 +1,40 @@ +package main + +import ( + "fmt" + + "github.com/codegangsta/cli" +) + +// NewRestartCommand returns the CLI command for "restart". +func NewRestartCommand() cli.Command { + return cli.Command{ + Name: "restart", + Usage: "restarts a build", + Flags: []cli.Flag{}, + Action: func(c *cli.Context) { + handle(c, restartCommandFunc) + }, + } +} + +// restartCommandFunc executes the "restart" command. +func restartCommandFunc(c *cli.Context, client *Client) error { + var branch string = "master" + var commit string + var repo string + var arg = c.Args() + + switch len(arg) { + case 2: + repo = arg[0] + commit = arg[1] + case 3: + repo = arg[0] + branch = arg[1] + commit = arg[2] + } + + path := fmt.Sprintf("/v1/repos/%s/branches/%s/commits/%s?action=rebuild", repo, branch, commit) + return client.Do("POST", path, nil, nil) +} diff --git a/client/command/whoami.go b/client/command/whoami.go new file mode 100644 index 000000000..0c3716fab --- /dev/null +++ b/client/command/whoami.go @@ -0,0 +1,32 @@ +package main + +import ( + "fmt" + + "github.com/codegangsta/cli" + "github.com/drone/drone/shared/model" +) + +// NewWhoamiCommand returns the CLI command for "whoami". +func NewWhoamiCommand() cli.Command { + return cli.Command{ + Name: "whoami", + Usage: "outputs the current user", + Flags: []cli.Flag{}, + Action: func(c *cli.Context) { + handle(c, whoamiCommandFunc) + }, + } +} + +// whoamiCommandFunc executes the "logout" command. +func whoamiCommandFunc(c *cli.Context, client *Client) error { + user := model.User{} + err := client.Do("GET", "/v1/user", nil, &user) + if err != nil { + return err + } + + fmt.Println(user.Login) + return nil +}