diff --git a/agent/agent.go b/agent/agent.go index e441608be..afe0e14df 100644 --- a/agent/agent.go +++ b/agent/agent.go @@ -167,7 +167,7 @@ func (a *Agent) prep(w *queue.Work) (*yaml.Config, error) { transform.ImageVolume(conf, []string{a.Local + ":" + conf.Workspace.Path}) } - transform.Pod(conf) + transform.Pod(conf, a.Platform) return conf, nil } diff --git a/client/client_impl.go b/client/client_impl.go index 89f78f7c0..ca661a88e 100644 --- a/client/client_impl.go +++ b/client/client_impl.go @@ -222,8 +222,8 @@ func (c *client) BuildQueue() ([]*model.Feed, error) { func (c *client) BuildStart(owner, name string, num int, params map[string]string) (*model.Build, error) { out := new(model.Build) val := parseToQueryParams(params) - uri := fmt.Sprintf(pathBuild+"?"+val.Encode(), c.base, owner, name, num) - err := c.post(uri, nil, out) + uri := fmt.Sprintf(pathBuild, c.base, owner, name, num) + err := c.post(uri+"?"+val.Encode(), nil, out) return out, err } @@ -240,8 +240,8 @@ func (c *client) BuildFork(owner, name string, num int, params map[string]string out := new(model.Build) val := parseToQueryParams(params) val.Set("fork", "true") - uri := fmt.Sprintf(pathBuild+"?"+val.Encode(), c.base, owner, name, num) - err := c.post(uri, nil, out) + uri := fmt.Sprintf(pathBuild, c.base, owner, name, num) + err := c.post(uri+"?"+val.Encode(), nil, out) return out, err } @@ -259,8 +259,8 @@ func (c *client) Deploy(owner, name string, num int, env string, params map[stri 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) + uri := fmt.Sprintf(pathBuild, c.base, owner, name, num) + err := c.post(uri+"?"+val.Encode(), nil, out) return out, err } diff --git a/drone/org_secret_add.go b/drone/org_secret_add.go index 52ac250dc..c9145fb28 100644 --- a/drone/org_secret_add.go +++ b/drone/org_secret_add.go @@ -42,7 +42,7 @@ var orgSecretAddCmd = cli.Command{ } func orgSecretAdd(c *cli.Context) error { - if len(c.Args().Tail()) != 3 { + if len(c.Args()) != 3 { cli.ShowSubcommandHelp(c) return nil } diff --git a/drone/org_secret_list.go b/drone/org_secret_list.go index ea0144b9b..550224d0b 100644 --- a/drone/org_secret_list.go +++ b/drone/org_secret_list.go @@ -35,7 +35,7 @@ var orgSecretListCmd = cli.Command{ } func orgSecretList(c *cli.Context) error { - if len(c.Args().Tail()) != 1 { + if len(c.Args()) != 1 { cli.ShowSubcommandHelp(c) return nil } diff --git a/drone/org_secret_rm.go b/drone/org_secret_rm.go index c0b4170d0..fc46d7b60 100644 --- a/drone/org_secret_rm.go +++ b/drone/org_secret_rm.go @@ -17,7 +17,7 @@ var orgSecretRemoveCmd = cli.Command{ } func orgSecretRemove(c *cli.Context) error { - if len(c.Args().Tail()) != 2 { + if len(c.Args()) != 2 { cli.ShowSubcommandHelp(c) return nil } diff --git a/remote/bitbucketserver/bitbucketserver.go b/remote/bitbucketserver/bitbucketserver.go index 8b70edf82..cb4e415f1 100644 --- a/remote/bitbucketserver/bitbucketserver.go +++ b/remote/bitbucketserver/bitbucketserver.go @@ -149,8 +149,18 @@ func (c *Config) File(u *model.User, r *model.Repo, b *model.Build, f string) ([ } // Status is not supported by the bitbucketserver driver. -func (*Config) Status(*model.User, *model.Repo, *model.Build, string) error { - return nil +func (c *Config) Status(u *model.User,r *model.Repo,b *model.Build,link string) error { + status := internal.BuildStatus{ + State: convertStatus(b.Status), + Desc: convertDesc(b.Status), + Name: fmt.Sprintf("Drone #%d - %s", b.Number, b.Branch), + Key: "Drone", + Url: link, + } + + client := internal.NewClientWithToken(c.URL, c.Consumer, u.Token) + + return client.CreateStatus(b.Commit, &status) } func (c *Config) Netrc(user *model.User, r *model.Repo) (*model.Netrc, error) { diff --git a/remote/bitbucketserver/convert.go b/remote/bitbucketserver/convert.go index 65fe8e3cb..20f7069fb 100644 --- a/remote/bitbucketserver/convert.go +++ b/remote/bitbucketserver/convert.go @@ -13,6 +13,48 @@ import ( "time" ) + +const ( + statusPending = "INPROGRESS" + statusSuccess = "SUCCESSFUL" + statusFailure = "FAILED" +) + +const ( + descPending = "this build is pending" + descSuccess = "the build was successful" + descFailure = "the build failed" + descError = "oops, something went wrong" +) + +// convertStatus is a helper function used to convert a Drone status to a +// Bitbucket commit status. +func convertStatus(status string) string { + switch status { + case model.StatusPending, model.StatusRunning: + return statusPending + case model.StatusSuccess: + return statusSuccess + default: + return statusFailure + } +} + +// convertDesc is a helper function used to convert a Drone status to a +// Bitbucket status description. +func convertDesc(status string) string { + switch status { + case model.StatusPending, model.StatusRunning: + return descPending + case model.StatusSuccess: + return descSuccess + case model.StatusFailure: + return descFailure + default: + return descError + } +} + // convertRepo is a helper function used to convert a Bitbucket server repository // structure to the common Drone repository structure. func convertRepo(from *internal.Repo) *model.Repo { diff --git a/remote/bitbucketserver/internal/client.go b/remote/bitbucketserver/internal/client.go index 058538481..11bf904fe 100644 --- a/remote/bitbucketserver/internal/client.go +++ b/remote/bitbucketserver/internal/client.go @@ -9,6 +9,7 @@ import ( "github.com/mrjones/oauth" "io/ioutil" "net/http" + "io" ) const ( @@ -20,6 +21,7 @@ const ( pathSource = "%s/projects/%s/repos/%s/browse/%s?at=%s&raw" hookName = "com.atlassian.stash.plugin.stash-web-post-receive-hooks-plugin:postReceiveHook" pathHookEnabled = "%s/rest/api/1.0/projects/%s/repos/%s/settings/hooks/%s/enabled" + pathStatus = "%s/rest/build-status/1.0/commits/%s" ) type Client struct { @@ -151,11 +153,18 @@ func (c *Client) CreateHook(owner string, name string, callBackLink string) erro return c.doPut(fmt.Sprintf(pathHookEnabled, c.base, owner, name, hookName), hookBytes) } +func (c *Client) CreateStatus(revision string, status *BuildStatus) error { + uri := fmt.Sprintf(pathStatus, c.base, revision) + return c.doPost(uri, status) +} + func (c *Client) DeleteHook(owner string, name string, link string) error { //TODO: eventially should only delete the link callback return c.doDelete(fmt.Sprintf(pathHookEnabled, c.base, owner, name, hookName)) } +//TODO: make these as as general do with the action + //Helper function to help create the hook func (c *Client) doPut(url string, body []byte) error { request, err := http.NewRequest("PUT", url, bytes.NewBuffer(body)) @@ -166,9 +175,34 @@ func (c *Client) doPut(url string, body []byte) error { } defer response.Body.Close() return nil - } + +//Helper function to help create the hook +func (c *Client) doPost(url string, status *BuildStatus) error { + // write it to the body of the request. + var buf io.ReadWriter + if status != nil { + buf = new(bytes.Buffer) + err := json.NewEncoder(buf).Encode(status) + if err != nil { + return err + } + } + request, err := http.NewRequest("POST", url, buf) + request.Header.Add("Content-Type", "application/json") + response, err := c.client.Do(request) + if err != nil { + return err + } + defer response.Body.Close() + return nil +} + + + + + //Helper function to do delete on the hook func (c *Client) doDelete(url string) error { request, err := http.NewRequest("DELETE", url, nil) diff --git a/remote/bitbucketserver/internal/types.go b/remote/bitbucketserver/internal/types.go index 0e879e272..9b50c3a09 100644 --- a/remote/bitbucketserver/internal/types.go +++ b/remote/bitbucketserver/internal/types.go @@ -24,6 +24,14 @@ type SelfRefLink struct { Href string `json:"href"` } +type BuildStatus struct { + State string `json:"state"` + Key string `json:"key"` + Name string `json:"name,omitempty"` + Url string `json:"url"` + Desc string `json:"description,omitempty"` +} + type Repo struct { Forkable bool `json:"forkable"` ID int `json:"id"` diff --git a/remote/github/github.go b/remote/github/github.go index 026380cdf..abd05dc19 100644 --- a/remote/github/github.go +++ b/remote/github/github.go @@ -67,6 +67,9 @@ func New(opts Opts) (remote.Remote, error) { remote.URL = strings.TrimSuffix(opts.URL, "/") remote.API = remote.URL + "/api/v3/" } + + // Hack to enable oauth2 access in older GHE + oauth2.RegisterBrokenAuthHeaderProvider(remote.URL) return remote, nil } diff --git a/yaml/transform/command.go b/yaml/transform/command.go index cf4892f01..a90e8c2a1 100644 --- a/yaml/transform/command.go +++ b/yaml/transform/command.go @@ -40,7 +40,7 @@ func toScript(commands []string) string { var buf bytes.Buffer for _, command := range commands { escaped := fmt.Sprintf("%q", command) - escaped = strings.Replace(command, "$", `$\`, -1) + escaped = strings.Replace(escaped, "$", `\$`, -1) buf.WriteString(fmt.Sprintf( traceScript, escaped, diff --git a/yaml/transform/pod.go b/yaml/transform/pod.go index ae734cd6a..dd92acbb8 100644 --- a/yaml/transform/pod.go +++ b/yaml/transform/pod.go @@ -9,21 +9,54 @@ import ( "github.com/gorilla/securecookie" ) +type ambassador struct { + image string + entrypoint []string + command []string +} + +// default linux amd64 ambassador +var defaultAmbassador = ambassador{ + image: "busybox:latest", + entrypoint: []string{"/bin/sleep"}, + command: []string{"86400"}, +} + +// lookup ambassador configuration by architecture and os +var lookupAmbassador = map[string]ambassador{ + "linux/amd64": { + image: "busybox:latest", + entrypoint: []string{"/bin/sleep"}, + command: []string{"86400"}, + }, + "linux/arm": { + image: "armhf/alpine:latest", + entrypoint: []string{"/bin/sleep"}, + command: []string{"86400"}, + }, +} + // Pod transforms the containers in the Yaml to use Pod networking, where every // container shares the localhost connection. -func Pod(c *yaml.Config) error { +func Pod(c *yaml.Config, platform string) error { rand := base64.RawURLEncoding.EncodeToString( securecookie.GenerateRandomKey(8), ) + // choose the ambassador configuration based on os and architecture + conf, ok := lookupAmbassador[platform] + if !ok { + conf = defaultAmbassador + } + ambassador := &yaml.Container{ ID: fmt.Sprintf("drone_ambassador_%s", rand), Name: "ambassador", - Image: "busybox:latest", + Image: conf.image, Detached: true, - Entrypoint: []string{"/bin/sleep"}, - Command: []string{"86400"}, + Entrypoint: conf.entrypoint, + Command: conf.command, Volumes: []string{c.Workspace.Path, c.Workspace.Base}, Environment: map[string]string{}, }