From 637c47341f3d9cad166d26605232f65e289594b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Fr=C3=B6ssman?= Date: Mon, 9 Nov 2015 05:38:31 +0100 Subject: [PATCH 01/21] Add /etc/nsswitch.conf to docker container Fixes #1269 --- Dockerfile | 3 ++- contrib/docker/etc/nsswitch.conf | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 contrib/docker/etc/nsswitch.conf diff --git a/Dockerfile b/Dockerfile index 5cc355e3..80cc6966 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,10 +14,11 @@ FROM centurylink/ca-certs EXPOSE 8000 +ADD contrib/docker/etc/nsswitch.conf /etc/ ENV DATABASE_DRIVER=sqlite3 ENV DATABASE_CONFIG=/var/lib/drone/drone.sqlite ADD drone_static /drone_static -ENTRYPOINT ["/drone_static"] \ No newline at end of file +ENTRYPOINT ["/drone_static"] diff --git a/contrib/docker/etc/nsswitch.conf b/contrib/docker/etc/nsswitch.conf new file mode 100644 index 00000000..cb918b77 --- /dev/null +++ b/contrib/docker/etc/nsswitch.conf @@ -0,0 +1,19 @@ +# /etc/nsswitch.conf +# +# Example configuration of GNU Name Service Switch functionality. +# If you have the `glibc-doc-reference' and `info' packages installed, try: +# `info libc "Name Service Switch"' for information about this file. + +passwd: compat +group: compat +shadow: compat + +hosts: files dns +networks: files + +protocols: files +services: files +ethers: files +rpc: files + +netgroup: nis From d9f9d6f76225caf246ffe8cb94b27e5aee374d39 Mon Sep 17 00:00:00 2001 From: Kirilll Zaycev Date: Sat, 12 Dec 2015 15:20:01 +0300 Subject: [PATCH 02/21] Move gitlab client inside drone --- remote/gitlab/client/drone.go | 27 ++++++ remote/gitlab/client/gitlab.go | 92 ++++++++++++++++++++ remote/gitlab/client/hook.go | 5 ++ remote/gitlab/client/project.go | 116 +++++++++++++++++++++++++ remote/gitlab/client/types.go | 145 ++++++++++++++++++++++++++++++++ remote/gitlab/client/user.go | 21 +++++ remote/gitlab/client/util.go | 33 ++++++++ remote/gitlab/gitlab.go | 8 +- remote/gitlab/helper.go | 21 +++-- 9 files changed, 453 insertions(+), 15 deletions(-) create mode 100644 remote/gitlab/client/drone.go create mode 100644 remote/gitlab/client/gitlab.go create mode 100644 remote/gitlab/client/hook.go create mode 100644 remote/gitlab/client/project.go create mode 100644 remote/gitlab/client/types.go create mode 100644 remote/gitlab/client/user.go create mode 100644 remote/gitlab/client/util.go diff --git a/remote/gitlab/client/drone.go b/remote/gitlab/client/drone.go new file mode 100644 index 00000000..8915e845 --- /dev/null +++ b/remote/gitlab/client/drone.go @@ -0,0 +1,27 @@ +package client + +const ( + droneServiceUrl = "/projects/:id/services/drone-ci" +) + +func (c *Client) AddDroneService(id string, params QMap) error { + url, opaque := c.ResourceUrl( + droneServiceUrl, + QMap{":id": id}, + params, + ) + + _, err := c.Do("PUT", url, opaque, nil) + return err +} + +func (c *Client) DeleteDroneService(id string) error { + url, opaque := c.ResourceUrl( + droneServiceUrl, + QMap{":id": id}, + nil, + ) + + _, err := c.Do("DELETE", url, opaque, nil) + return err +} diff --git a/remote/gitlab/client/gitlab.go b/remote/gitlab/client/gitlab.go new file mode 100644 index 00000000..a44946ae --- /dev/null +++ b/remote/gitlab/client/gitlab.go @@ -0,0 +1,92 @@ +package client + +import ( + "bytes" + "crypto/tls" + "fmt" + "io/ioutil" + "net/http" + "net/url" + "strings" +) + +type Client struct { + BaseUrl string + ApiPath string + Token string + Client *http.Client +} + +func New(baseUrl, apiPath, token string, skipVerify bool) *Client { + config := &tls.Config{InsecureSkipVerify: skipVerify} + tr := &http.Transport{ + Proxy: http.ProxyFromEnvironment, + TLSClientConfig: config, + } + client := &http.Client{Transport: tr} + + return &Client{ + BaseUrl: baseUrl, + ApiPath: apiPath, + Token: token, + Client: client, + } +} + +func (c *Client) ResourceUrl(u string, params, query QMap) (string, string) { + if params != nil { + for key, val := range params { + u = strings.Replace(u, key, encodeParameter(val), -1) + } + } + + query_params := url.Values{} + + if query != nil { + for key, val := range query { + query_params.Set(key, val) + } + } + + u = c.BaseUrl + c.ApiPath + u + "?" + query_params.Encode() + p, err := url.Parse(u) + if err != nil { + return u, "" + } + + opaque := "//" + p.Host + p.Path + return u, opaque +} + +func (c *Client) Do(method, url, opaque string, body []byte) ([]byte, error) { + var req *http.Request + var err error + + if body != nil { + reader := bytes.NewReader(body) + req, err = http.NewRequest(method, url, reader) + } else { + req, err = http.NewRequest(method, url, nil) + } + if err != nil { + return nil, fmt.Errorf("Error while building gitlab request") + } + + req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", c.Token)) + + resp, err := c.Client.Do(req) + if err != nil { + return nil, fmt.Errorf("Client.Do error: %q", err) + } + defer resp.Body.Close() + contents, err := ioutil.ReadAll(resp.Body) + if err != nil { + fmt.Printf("%s", err) + } + + if resp.StatusCode >= 400 { + err = fmt.Errorf("*Gitlab.buildAndExecRequest failed: <%d> %s", resp.StatusCode, req.URL) + } + + return contents, err +} diff --git a/remote/gitlab/client/hook.go b/remote/gitlab/client/hook.go new file mode 100644 index 00000000..0263e100 --- /dev/null +++ b/remote/gitlab/client/hook.go @@ -0,0 +1,5 @@ +package client + +func ParseHook(payload []byte) (*HookPayload, error) { + return nil, nil +} diff --git a/remote/gitlab/client/project.go b/remote/gitlab/client/project.go new file mode 100644 index 00000000..49d58f10 --- /dev/null +++ b/remote/gitlab/client/project.go @@ -0,0 +1,116 @@ +package client + +import ( + "encoding/json" + "strconv" + "strings" +) + +const ( + searchUrl = "/projects/search/:query" + projectsUrl = "/projects" + projectUrl = "/projects/:id" + repoUrlRawFile = "/projects/:id/repository/blobs/:sha" +) + +// Get a list of all projects owned by the authenticated user. +func (g *Client) AllProjects() ([]*Project, error) { + var per_page = 100 + var projects []*Project + + for i := 1; true; i++ { + contents, err := g.Projects(i, per_page) + if err != nil { + return projects, err + } + + for _, value := range contents { + projects = append(projects, value) + } + + if len(projects) == 0 { + break + } + + if len(projects)/i < per_page { + break + } + } + + return projects, nil +} + +// Get a list of projects owned by the authenticated user. +func (c *Client) Projects(page int, per_page int) ([]*Project, error) { + + url, opaque := c.ResourceUrl(projectsUrl, nil, QMap{ + "page": strconv.Itoa(page), + "per_page": strconv.Itoa(per_page), + }) + + var projects []*Project + + contents, err := c.Do("GET", url, opaque, nil) + if err == nil { + err = json.Unmarshal(contents, &projects) + } + + return projects, err +} + +// Get a project by id +func (c *Client) Project(id string) (*Project, error) { + url, opaque := c.ResourceUrl(projectUrl, QMap{":id": id}, nil) + + var project *Project + + contents, err := c.Do("GET", url, opaque, nil) + if err == nil { + err = json.Unmarshal(contents, &project) + } + + return project, err +} + +// Get Raw file content +func (c *Client) RepoRawFile(id, sha, filepath string) ([]byte, error) { + url, opaque := c.ResourceUrl( + repoUrlRawFile, + QMap{ + ":id": id, + ":sha": sha, + }, + QMap{ + "filepath": filepath, + }, + ) + + contents, err := c.Do("GET", url, opaque, nil) + + return contents, err +} + +// Get a list of projects by query owned by the authenticated user. +func (c *Client) SearchProjectId(namespace string, name string) (id int, err error) { + + url, opaque := c.ResourceUrl(searchUrl, nil, QMap{ + ":query": strings.ToLower(name), + }) + + var projects []*Project + + contents, err := c.Do("GET", url, opaque, nil) + if err == nil { + err = json.Unmarshal(contents, &projects) + } else { + return id, err + } + + for _, project := range projects { + if project.Namespace.Name == namespace && strings.ToLower(project.Name) == strings.ToLower(name) { + id = project.Id + } + } + + return id, err +} diff --git a/remote/gitlab/client/types.go b/remote/gitlab/client/types.go new file mode 100644 index 00000000..04cb99d2 --- /dev/null +++ b/remote/gitlab/client/types.go @@ -0,0 +1,145 @@ +package client + +type QMap map[string]string + +type User struct { + Id int `json:"id,omitempty"` + Username string `json:"username,omitempty"` + Email string `json:"email,omitempty"` + AvatarUrl string `json:"avatar_url,omitempty"` + Name string `json:"name,omitempty"` + State string `json:"state,omitempty"` + CreatedAt string `json:"created_at,omitempty"` + Bio string `json:"bio,omitempty"` + Skype string `json:"skype,omitempty"` + LinkedIn string `json:"linkedin,omitempty"` + Twitter string `json:"twitter,omitempty"` + ExternUid string `json:"extern_uid,omitempty"` + Provider string `json:"provider,omitempty"` + ThemeId int `json:"theme_id,omitempty"` + ColorSchemeId int `json:"color_scheme_id,color_scheme_id"` +} + +type Member struct { + Id int + Username string + Email string + Name string + State string + CreatedAt string `json:"created_at,omitempty"` + // AccessLevel int +} + +type ProjectAccess struct { + AccessLevel int `json:"access_level,omitempty"` + NotificationLevel int `json:"notification_level,omitempty"` +} + +type GroupAccess struct { + AccessLevel int `json:"access_level,omitempty"` + NotificationLevel int `json:"notification_level,omitempty"` +} + +type Permissions struct { + ProjectAccess *ProjectAccess `json:"project_access,omitempty"` + GroupAccess *GroupAccess `json:"group_access,omitempty"` +} + +type Project struct { + Id int `json:"id,omitempty"` + Name string `json:"name,omitempty"` + Description string `json:"description,omitempty"` + DefaultBranch string `json:"default_branch,omitempty"` + Owner *Member `json:"owner,omitempty"` + Public bool `json:"public,omitempty"` + Path string `json:"path,omitempty"` + PathWithNamespace string `json:"path_with_namespace,omitempty"` + IssuesEnabled bool `json:"issues_enabled,omitempty"` + MergeRequestsEnabled bool `json:"merge_requests_enabled,omitempty"` + WallEnabled bool `json:"wall_enabled,omitempty"` + WikiEnabled bool `json:"wiki_enabled,omitempty"` + CreatedAtRaw string `json:"created_at,omitempty"` + Namespace *Namespace `json:"namespace,omitempty"` + SshRepoUrl string `json:"ssh_url_to_repo"` + HttpRepoUrl string `json:"http_url_to_repo"` + Url string `json:"web_url"` + Permissions *Permissions `json:"permissions,omitempty"` +} + +type Namespace struct { + Id int `json:"id,omitempty"` + Name string `json:"name,omitempty"` +} + +type Person struct { + Name string `json:"name"` + Email string `json:"email"` +} + +type hProject struct { + Name string `json:"name"` + SshUrl string `json:"ssh_url"` + HttpUrl string `json:"http_url"` + VisibilityLevel int `json:"visibility_level"` + WebUrl string `json:"web_url"` + Namespace string `json:"namespace"` +} + +type hRepository struct { + Name string `json:"name,omitempty"` + URL string `json:"url,omitempty"` + Description string `json:"description,omitempty"` + Homepage string `json:"homepage,omitempty"` + GitHttpUrl string `json:"git_http_url,omitempty"` + GitSshUrl string `json:"git_ssh_url,omitempty"` + VisibilityLevel int `json:"visibility_level,omitempty"` +} + +type hCommit struct { + Id string `json:"id,omitempty"` + Message string `json:"message,omitempty"` + Timestamp string `json:"timestamp,omitempty"` + URL string `json:"url,omitempty"` + Author *Person `json:"author,omitempty"` +} + +type HookObjAttr struct { + Id int `json:"id,omitempty"` + Title string `json:"title,omitempty"` + AssigneeId int `json:"assignee_id,omitempty"` + AuthorId int `json:"author_id,omitempty"` + ProjectId int `json:"project_id,omitempty"` + CreatedAt string `json:"created_at,omitempty"` + UpdatedAt string `json:"updated_at,omitempty"` + Position int `json:"position,omitempty"` + BranchName string `json:"branch_name,omitempty"` + Description string `json:"description,omitempty"` + MilestoneId int `json:"milestone_id,omitempty"` + State string `json:"state,omitempty"` + IId int `json:"iid,omitempty"` + TargetBranch string `json:"target_branch,omitempty"` + SourceBranch string `json:"source_branch,omitempty"` + SourceProjectId int `json:"source_project_id,omitempty"` + StCommits string `json:"st_commits,omitempty"` + StDiffs string `json:"st_diffs,omitempty"` + MergeStatus string `json:"merge_status,omitempty"` + TargetProjectId int `json:"target_project_id,omitempty"` + Url string `json:"url,omiyempty"` + Source *hProject `json:"source,omitempty"` + Target *hProject `json:"target,omitempty"` + LastCommit *hCommit `json:"last_commit,omitempty"` +} + +type HookPayload struct { + Before string `json:"before,omitempty"` + After string `json:"after,omitempty"` + Ref string `json:"ref,omitempty"` + UserId int `json:"user_id,omitempty"` + UserName string `json:"user_name,omitempty"` + ProjectId int `json:"project_id,omitempty"` + Repository *hRepository `json:"repository,omitempty"` + Commits []hCommit `json:"commits,omitempty"` + TotalCommitsCount int `json:"total_commits_count,omitempty"` + ObjectKind string `json:"object_kind,omitempty"` + ObjectAttributes *HookObjAttr `json:"object_attributes,omitempty"` +} diff --git a/remote/gitlab/client/user.go b/remote/gitlab/client/user.go new file mode 100644 index 00000000..bafc7c47 --- /dev/null +++ b/remote/gitlab/client/user.go @@ -0,0 +1,21 @@ +package client + +import ( + "encoding/json" +) + +const ( + currentUserUrl = "/user" +) + +func (c *Client) CurrentUser() (User, error) { + url, opaque := c.ResourceUrl(currentUserUrl, nil, nil) + var user User + + contents, err := c.Do("GET", url, opaque, nil) + if err == nil { + err = json.Unmarshal(contents, &user) + } + + return user, err +} diff --git a/remote/gitlab/client/util.go b/remote/gitlab/client/util.go new file mode 100644 index 00000000..7cc5c37f --- /dev/null +++ b/remote/gitlab/client/util.go @@ -0,0 +1,33 @@ +package client + +import ( + "net/url" + "strings" +) + +func encodeParameter(value string) string { + return strings.Replace(url.QueryEscape(value), "/", "%2F", 0) +} + +// Tag returns current tag for push event hook payload +// This function returns empty string for any other events +func (h *HookPayload) Tag() string { + return strings.TrimPrefix(h.Ref, "refs/tags/") +} + +// Branch returns current branch for push event hook payload +// This function returns empty string for any other events +func (h *HookPayload) Branch() string { + return strings.TrimPrefix(h.Ref, "refs/heads/") +} + +// Head returns the latest changeset for push event hook payload +func (h *HookPayload) Head() hCommit { + c := hCommit{} + for _, cm := range h.Commits { + if h.After == cm.Id { + return cm + } + } + return c +} diff --git a/remote/gitlab/gitlab.go b/remote/gitlab/gitlab.go index 1ae99007..e24a2532 100644 --- a/remote/gitlab/gitlab.go +++ b/remote/gitlab/gitlab.go @@ -15,7 +15,7 @@ import ( "github.com/drone/drone/shared/oauth2" "github.com/drone/drone/shared/token" - "github.com/Bugagazavr/go-gitlab-client" + "github.com/drone/drone/remote/gitlab/client" ) const ( @@ -296,7 +296,7 @@ func (g *Gitlab) Deactivate(user *model.User, repo *model.Repo, link string) err func (g *Gitlab) Hook(req *http.Request) (*model.Repo, *model.Build, error) { defer req.Body.Close() var payload, _ = ioutil.ReadAll(req.Body) - var parsed, err = gogitlab.ParseHook(payload) + var parsed, err = client.ParseHook(payload) if err != nil { return nil, nil, err } @@ -311,7 +311,7 @@ func (g *Gitlab) Hook(req *http.Request) (*model.Repo, *model.Build, error) { } } -func mergeRequest(parsed *gogitlab.HookPayload, req *http.Request) (*model.Repo, *model.Build, error) { +func mergeRequest(parsed *client.HookPayload, req *http.Request) (*model.Repo, *model.Build, error) { repo := &model.Repo{} repo.Owner = req.FormValue("owner") @@ -344,7 +344,7 @@ func mergeRequest(parsed *gogitlab.HookPayload, req *http.Request) (*model.Repo, return repo, build, nil } -func push(parsed *gogitlab.HookPayload, req *http.Request) (*model.Repo, *model.Build, error) { +func push(parsed *client.HookPayload, req *http.Request) (*model.Repo, *model.Build, error) { var cloneUrl = parsed.Repository.GitHttpUrl repo := &model.Repo{} diff --git a/remote/gitlab/helper.go b/remote/gitlab/helper.go index 25b7f1d5..62edc019 100644 --- a/remote/gitlab/helper.go +++ b/remote/gitlab/helper.go @@ -5,20 +5,19 @@ import ( "net/url" "strconv" - "github.com/Bugagazavr/go-gitlab-client" + "github.com/drone/drone/remote/gitlab/client" ) // NewClient is a helper function that returns a new GitHub // client using the provided OAuth token. -func NewClient(url, accessToken string, skipVerify bool) *gogitlab.Gitlab { - client := gogitlab.NewGitlabCert(url, "/api/v3", accessToken, skipVerify) - client.Bearer = true +func NewClient(url, accessToken string, skipVerify bool) *client.Client { + client := client.New(url, "/api/v3", accessToken, skipVerify) return client } // IsRead is a helper function that returns true if the // user has Read-only access to the repository. -func IsRead(proj *gogitlab.Project) bool { +func IsRead(proj *client.Project) bool { var user = proj.Permissions.ProjectAccess var group = proj.Permissions.GroupAccess @@ -36,7 +35,7 @@ func IsRead(proj *gogitlab.Project) bool { // IsWrite is a helper function that returns true if the // user has Read-Write access to the repository. -func IsWrite(proj *gogitlab.Project) bool { +func IsWrite(proj *client.Project) bool { var user = proj.Permissions.ProjectAccess var group = proj.Permissions.GroupAccess @@ -52,7 +51,7 @@ func IsWrite(proj *gogitlab.Project) bool { // IsAdmin is a helper function that returns true if the // user has Admin access to the repository. -func IsAdmin(proj *gogitlab.Project) bool { +func IsAdmin(proj *client.Project) bool { var user = proj.Permissions.ProjectAccess var group = proj.Permissions.GroupAccess @@ -80,13 +79,13 @@ func ns(owner, name string) string { return fmt.Sprintf("%s%%2F%s", owner, name) } -func GetUserEmail(client *gogitlab.Gitlab, defaultURL string) (*gogitlab.Gitlab, error) { - return client, nil +func GetUserEmail(c *client.Client, defaultURL string) (*client.Client, error) { + return c, nil } -func GetProjectId(r *Gitlab, client *gogitlab.Gitlab, owner, name string) (projectId string, err error) { +func GetProjectId(r *Gitlab, c *client.Client, owner, name string) (projectId string, err error) { if r.Search { - _projectId, err := client.SearchProjectId(owner, name) + _projectId, err := c.SearchProjectId(owner, name) if err != nil || _projectId == 0 { return "", err } From 044e2ea07a86fa9a61f1c4e2a05093486c2b697f Mon Sep 17 00:00:00 2001 From: Kirilll Zaycev Date: Sat, 12 Dec 2015 16:18:27 +0300 Subject: [PATCH 03/21] Added hook parser and opaque in request --- remote/gitlab/client/gitlab.go | 4 ++++ remote/gitlab/client/hook.go | 38 +++++++++++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/remote/gitlab/client/gitlab.go b/remote/gitlab/client/gitlab.go index a44946ae..1b4bad74 100644 --- a/remote/gitlab/client/gitlab.go +++ b/remote/gitlab/client/gitlab.go @@ -74,6 +74,10 @@ func (c *Client) Do(method, url, opaque string, body []byte) ([]byte, error) { req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", c.Token)) + if len(opaque) > 0 { + req.URL.Opaque = opaque + } + resp, err := c.Client.Do(req) if err != nil { return nil, fmt.Errorf("Client.Do error: %q", err) diff --git a/remote/gitlab/client/hook.go b/remote/gitlab/client/hook.go index 0263e100..8ea89689 100644 --- a/remote/gitlab/client/hook.go +++ b/remote/gitlab/client/hook.go @@ -1,5 +1,41 @@ package client +import ( + "encoding/json" + "fmt" +) + +// ParseHook parses hook payload from GitLab func ParseHook(payload []byte) (*HookPayload, error) { - return nil, nil + hp := HookPayload{} + if err := json.Unmarshal(payload, &hp); err != nil { + return nil, err + } + + // Basic sanity check + switch { + case len(hp.ObjectKind) == 0: + // Assume this is a post-receive within repository + if len(hp.After) == 0 { + return nil, fmt.Errorf("Invalid hook received, commit hash not found.") + } + case hp.ObjectKind == "push": + if hp.Repository == nil { + return nil, fmt.Errorf("Invalid push hook received, attributes not found") + } + case hp.ObjectKind == "tag_push": + if hp.Repository == nil { + return nil, fmt.Errorf("Invalid tag push hook received, attributes not found") + } + case hp.ObjectKind == "issue": + fallthrough + case hp.ObjectKind == "merge_request": + if hp.ObjectAttributes == nil { + return nil, fmt.Errorf("Invalid hook received, attributes not found.") + } + default: + return nil, fmt.Errorf("Invalid hook received, payload format not recognized.") + } + + return &hp, nil } From b5e50ff76668ffd4d4aa3c5f7df8e0250d896958 Mon Sep 17 00:00:00 2001 From: Kirilll Zaycev Date: Sat, 12 Dec 2015 20:09:59 +0300 Subject: [PATCH 04/21] Gitlab commit statuses --- remote/gitlab/client/project.go | 31 +++++++++++++-- remote/gitlab/gitlab.go | 70 +++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+), 4 deletions(-) diff --git a/remote/gitlab/client/project.go b/remote/gitlab/client/project.go index 49d58f10..97b661ee 100644 --- a/remote/gitlab/client/project.go +++ b/remote/gitlab/client/project.go @@ -7,10 +7,11 @@ import ( ) const ( - searchUrl = "/projects/search/:query" - projectsUrl = "/projects" - projectUrl = "/projects/:id" - repoUrlRawFile = "/projects/:id/repository/blobs/:sha" + searchUrl = "/projects/search/:query" + projectsUrl = "/projects" + projectUrl = "/projects/:id" + repoUrlRawFile = "/projects/:id/repository/blobs/:sha" + commitStatusUrl = "/projects/:id/statuses/:sha" ) // Get a list of all projects owned by the authenticated user. @@ -90,6 +91,28 @@ func (c *Client) RepoRawFile(id, sha, filepath string) ([]byte, error) { return contents, err } +// +func (c *Client) SetStatus(id, sha, state, desc, ref, link string) error { + url, opaque := c.ResourceUrl( + commitStatusUrl, + QMap{ + ":id": id, + ":sha": sha, + }, + QMap{ + "state": state, + "ref": ref, + "target_url": link, + "description": desc, + "context": "ci/drone", + }, + ) + + println(url, opaque) + _, err := c.Do("POST", url, opaque, nil) + return err +} + // Get a list of projects by query owned by the authenticated user. func (c *Client) SearchProjectId(namespace string, name string) (id int, err error) { diff --git a/remote/gitlab/gitlab.go b/remote/gitlab/gitlab.go index e24a2532..4b5e8a72 100644 --- a/remote/gitlab/gitlab.go +++ b/remote/gitlab/gitlab.go @@ -229,6 +229,22 @@ func (g *Gitlab) Script(user *model.User, repo *model.Repo, build *model.Build) // also if we want get MR status in gitlab we need implement a special plugin for gitlab, // gitlab uses API to fetch build status on client side. But for now we skip this. func (g *Gitlab) Status(u *model.User, repo *model.Repo, b *model.Build, link string) error { + client := NewClient(g.URL, u.Token, g.SkipVerify) + + status := getStatus(b.Status) + desc := getDesc(b.Status) + + client.SetStatus( + ns(repo.Owner, repo.Name), + b.Commit, + status, + desc, + strings.Replace(b.Ref, "refs/heads/", "", -1), + link, + ) + + // Gitlab statuses it's a new feature, just ignore error + // if gitlab version not support this return nil } @@ -431,3 +447,57 @@ func (g *Gitlab) Scope() string { func (g *Gitlab) String() string { return "gitlab" } + +const ( + StatusPending = "pending" + StatusRunning = "running" + StatusSuccess = "success" + StatusFailure = "failed" + StatusCanceled = "canceled" +) + +const ( + DescPending = "this build is pending" + DescRunning = "this buils is running" + DescSuccess = "the build was successful" + DescFailure = "the build failed" + DescCanceled = "the build canceled" +) + +// getStatus is a helper functin that converts a Drone +// status to a GitHub status. +func getStatus(status string) string { + switch status { + case model.StatusPending: + return StatusPending + case model.StatusRunning: + return StatusRunning + case model.StatusSuccess: + return StatusSuccess + case model.StatusFailure, model.StatusError: + return StatusFailure + case model.StatusKilled: + return StatusCanceled + default: + return StatusFailure + } +} + +// getDesc is a helper function that generates a description +// message for the build based on the status. +func getDesc(status string) string { + switch status { + case model.StatusPending: + return DescPending + case model.StatusRunning: + return DescRunning + case model.StatusSuccess: + return DescSuccess + case model.StatusFailure, model.StatusError: + return DescFailure + case model.StatusKilled: + return DescCanceled + default: + return DescFailure + } +} From 5ca67d304cfd56f666ecc7305c958f147eac9468 Mon Sep 17 00:00:00 2001 From: alex Date: Fri, 18 Dec 2015 10:57:38 +0000 Subject: [PATCH 05/21] Do not ignore refs/heads/gh-pages --- remote/github/github.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/remote/github/github.go b/remote/github/github.go index a27bbe27..4d44b43c 100644 --- a/remote/github/github.go +++ b/remote/github/github.go @@ -356,10 +356,6 @@ func (g *Github) push(r *http.Request) (*model.Repo, *model.Build, error) { // default gravatar? } - // we should ignore github pages - if build.Ref == "refs/heads/gh-pages" { - return nil, nil, nil - } if strings.HasPrefix(build.Ref, "refs/tags/") { // just kidding, this is actually a tag event build.Event = model.EventTag From 9eb4161750d5df127a904c1bcee3d0644612cc75 Mon Sep 17 00:00:00 2001 From: Fabio Rapposelli Date: Tue, 22 Dec 2015 14:10:39 +0100 Subject: [PATCH 06/21] Make GitHub status API context congruous Signed-off-by: Fabio Rapposelli --- remote/github/github.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/remote/github/github.go b/remote/github/github.go index 4d44b43c..d7c793b7 100644 --- a/remote/github/github.go +++ b/remote/github/github.go @@ -230,7 +230,7 @@ func (g *Github) Status(u *model.User, r *model.Repo, b *model.Build, link strin status := getStatus(b.Status) desc := getDesc(b.Status) data := github.RepoStatus{ - Context: github.String("Drone"), + Context: github.String("continuous-integration/drone"), State: github.String(status), Description: github.String(desc), TargetURL: github.String(link), From 2b3d6b45b60457e582b3702cbb9d82e3389bdc43 Mon Sep 17 00:00:00 2001 From: Nils Werner Date: Tue, 22 Dec 2015 15:33:27 +0100 Subject: [PATCH 07/21] Append reponame to ssh keys --- template/amber/repo_config.amber | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/template/amber/repo_config.amber b/template/amber/repo_config.amber index c26a82cd..be0f3516 100644 --- a/template/amber/repo_config.amber +++ b/template/amber/repo_config.amber @@ -68,7 +68,7 @@ block content div.row div.col-md-3 Public Key div.col-md-9 - pre #{Key.Public} + pre #{Key.Public} #{Repo.Owner}-#{Repo.Name}@drone div.row div.col-md-12 div.alert.alert-danger From 32cdf41ce72980530df6419f59316a1d477224cd Mon Sep 17 00:00:00 2001 From: Brad Rydzewski Date: Thu, 24 Dec 2015 10:09:18 -0500 Subject: [PATCH 08/21] Strip port from gogs netrc file --- remote/gogs/gogs.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/remote/gogs/gogs.go b/remote/gogs/gogs.go index 16755a08..c420a8e0 100644 --- a/remote/gogs/gogs.go +++ b/remote/gogs/gogs.go @@ -2,6 +2,7 @@ package gogs import ( "fmt" + "net" "net/http" "net/url" "strconv" @@ -179,6 +180,10 @@ func (g *Gogs) Netrc(u *model.User, r *model.Repo) (*model.Netrc, error) { if err != nil { return nil, err } + host, _, err := net.SplitHostPort(url_.Host) + if err == nil { + url_.Host=host + } return &model.Netrc{ Login: u.Token, Password: "x-oauth-basic", From 64403c353eeb6314f17877e75de15e86c2039fed Mon Sep 17 00:00:00 2001 From: Jesse Donat Date: Mon, 4 Jan 2016 15:26:30 -0600 Subject: [PATCH 09/21] Corrects CC Menu url CC Menu URL was an empty placeholder. This completes it with a URL --- controller/badge.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/controller/badge.go b/controller/badge.go index 6ddf402b..b8cb8942 100644 --- a/controller/badge.go +++ b/controller/badge.go @@ -1,9 +1,12 @@ package controller import ( + "fmt" + "github.com/gin-gonic/gin" "github.com/drone/drone/model" + "github.com/drone/drone/shared/httputil" "github.com/drone/drone/store" ) @@ -73,6 +76,7 @@ func GetCC(c *gin.Context) { return } - cc := model.NewCC(repo, builds[0], "") + url := fmt.Sprintf("%s/%s/%d", httputil.GetURL(c.Request), repo.FullName, builds[0].Number) + cc := model.NewCC(repo, builds[0], url) c.XML(200, cc) } From 73dd59d1ca0b21d90fea4cc08064c50d68a0df40 Mon Sep 17 00:00:00 2001 From: Kirilll Zaycev Date: Tue, 5 Jan 2016 01:07:36 +0300 Subject: [PATCH 10/21] Remove unused data from structs --- remote/gitlab/client/types.go | 60 ++++++++++------------------------- 1 file changed, 17 insertions(+), 43 deletions(-) diff --git a/remote/gitlab/client/types.go b/remote/gitlab/client/types.go index 04cb99d2..7a5668a6 100644 --- a/remote/gitlab/client/types.go +++ b/remote/gitlab/client/types.go @@ -3,31 +3,11 @@ package client type QMap map[string]string type User struct { - Id int `json:"id,omitempty"` - Username string `json:"username,omitempty"` - Email string `json:"email,omitempty"` - AvatarUrl string `json:"avatar_url,omitempty"` - Name string `json:"name,omitempty"` - State string `json:"state,omitempty"` - CreatedAt string `json:"created_at,omitempty"` - Bio string `json:"bio,omitempty"` - Skype string `json:"skype,omitempty"` - LinkedIn string `json:"linkedin,omitempty"` - Twitter string `json:"twitter,omitempty"` - ExternUid string `json:"extern_uid,omitempty"` - Provider string `json:"provider,omitempty"` - ThemeId int `json:"theme_id,omitempty"` - ColorSchemeId int `json:"color_scheme_id,color_scheme_id"` -} - -type Member struct { - Id int - Username string - Email string - Name string - State string - CreatedAt string `json:"created_at,omitempty"` - // AccessLevel int + Id int `json:"id,omitempty"` + Username string `json:"username,omitempty"` + Email string `json:"email,omitempty"` + AvatarUrl string `json:"avatar_url,omitempty"` + Name string `json:"name,omitempty"` } type ProjectAccess struct { @@ -46,24 +26,18 @@ type Permissions struct { } type Project struct { - Id int `json:"id,omitempty"` - Name string `json:"name,omitempty"` - Description string `json:"description,omitempty"` - DefaultBranch string `json:"default_branch,omitempty"` - Owner *Member `json:"owner,omitempty"` - Public bool `json:"public,omitempty"` - Path string `json:"path,omitempty"` - PathWithNamespace string `json:"path_with_namespace,omitempty"` - IssuesEnabled bool `json:"issues_enabled,omitempty"` - MergeRequestsEnabled bool `json:"merge_requests_enabled,omitempty"` - WallEnabled bool `json:"wall_enabled,omitempty"` - WikiEnabled bool `json:"wiki_enabled,omitempty"` - CreatedAtRaw string `json:"created_at,omitempty"` - Namespace *Namespace `json:"namespace,omitempty"` - SshRepoUrl string `json:"ssh_url_to_repo"` - HttpRepoUrl string `json:"http_url_to_repo"` - Url string `json:"web_url"` - Permissions *Permissions `json:"permissions,omitempty"` + Id int `json:"id,omitempty"` + Name string `json:"name,omitempty"` + Description string `json:"description,omitempty"` + DefaultBranch string `json:"default_branch,omitempty"` + Public bool `json:"public,omitempty"` + Path string `json:"path,omitempty"` + PathWithNamespace string `json:"path_with_namespace,omitempty"` + Namespace *Namespace `json:"namespace,omitempty"` + SshRepoUrl string `json:"ssh_url_to_repo"` + HttpRepoUrl string `json:"http_url_to_repo"` + Url string `json:"web_url"` + Permissions *Permissions `json:"permissions,omitempty"` } type Namespace struct { From c69343ecc620b777c9a4558ad249e956f967a91b Mon Sep 17 00:00:00 2001 From: Kirilll Zaycev Date: Tue, 5 Jan 2016 01:16:50 +0300 Subject: [PATCH 11/21] Remove println --- remote/gitlab/client/project.go | 1 - 1 file changed, 1 deletion(-) diff --git a/remote/gitlab/client/project.go b/remote/gitlab/client/project.go index 97b661ee..f6f22765 100644 --- a/remote/gitlab/client/project.go +++ b/remote/gitlab/client/project.go @@ -108,7 +108,6 @@ func (c *Client) SetStatus(id, sha, state, desc, ref, link string) error { }, ) - println(url, opaque) _, err := c.Do("POST", url, opaque, nil) return err } From bd616344fd8431ae8c4c9021cb30a0e85f3f26d4 Mon Sep 17 00:00:00 2001 From: Georges Chaudy Date: Thu, 7 Jan 2016 14:35:53 +0000 Subject: [PATCH 12/21] fix: gitlab owner has admin privileges --- remote/gitlab/gitlab.go | 7 +++++++ remote/gitlab/gitlab_test.go | 9 +++++++-- remote/gitlab/testdata/projects.go | 18 ++++++++---------- remote/gitlab/testdata/testdata.go | 9 ++++----- 4 files changed, 26 insertions(+), 17 deletions(-) diff --git a/remote/gitlab/gitlab.go b/remote/gitlab/gitlab.go index 1ae99007..ebf5ae61 100644 --- a/remote/gitlab/gitlab.go +++ b/remote/gitlab/gitlab.go @@ -198,6 +198,13 @@ func (g *Gitlab) Perm(u *model.User, owner, name string) (*model.Perm, error) { if err != nil { return nil, err } + + // repo owner are granted full access + if u.Login == repo.Owner.Username { + return &model.Perm{true, true, true}, nil + } + + // check permission for users m := &model.Perm{} m.Admin = IsAdmin(repo) m.Pull = IsRead(repo) diff --git a/remote/gitlab/gitlab_test.go b/remote/gitlab/gitlab_test.go index 7d8183a6..2e876d88 100644 --- a/remote/gitlab/gitlab_test.go +++ b/remote/gitlab/gitlab_test.go @@ -54,13 +54,18 @@ func Test_Gitlab(t *testing.T) { g.Describe("Perm", func() { g.It("Should return repo permissions", func() { perm, err := gitlab.Perm(&user, "diaspora", "diaspora-client") - g.Assert(err == nil).IsTrue() g.Assert(perm.Admin).Equal(true) g.Assert(perm.Pull).Equal(true) g.Assert(perm.Push).Equal(true) }) - + g.It("Should return repo permissions when user is admin", func() { + perm, err := gitlab.Perm(&user, "brightbox", "puppet") + g.Assert(err == nil).IsTrue() + g.Assert(perm.Admin).Equal(true) + g.Assert(perm.Pull).Equal(true) + g.Assert(perm.Push).Equal(true) + }) g.It("Should return error, when repo is not exist", func() { _, err := gitlab.Perm(&user, "not-existed", "not-existed") diff --git a/remote/gitlab/testdata/projects.go b/remote/gitlab/testdata/projects.go index 09bec736..ebe9bd39 100644 --- a/remote/gitlab/testdata/projects.go +++ b/remote/gitlab/testdata/projects.go @@ -15,6 +15,7 @@ var projectsPayload = []byte(` "owner": { "id": 3, "name": "Diaspora", + "username": "some_user", "created_at": "2013-09-30T13: 46: 02Z" }, "name": "Diaspora Client", @@ -48,8 +49,9 @@ var projectsPayload = []byte(` "http_url_to_repo": "http://example.com/brightbox/puppet.git", "web_url": "http://example.com/brightbox/puppet", "owner": { - "id": 4, + "id": 1, "name": "Brightbox", + "username": "test_user", "created_at": "2013-09-30T13:46:02Z" }, "name": "Puppet", @@ -89,6 +91,7 @@ var project4Paylod = []byte(` "owner": { "id": 3, "name": "Diaspora", + "username": "some_user", "created_at": "2013-09-30T13: 46: 02Z" }, "name": "Diaspora Client", @@ -135,8 +138,9 @@ var project6Paylod = []byte(` "http_url_to_repo": "http://example.com/brightbox/puppet.git", "web_url": "http://example.com/brightbox/puppet", "owner": { - "id": 4, + "id": 1, "name": "Brightbox", + "username": "test_user", "created_at": "2013-09-30T13:46:02Z" }, "name": "Puppet", @@ -160,14 +164,8 @@ var project6Paylod = []byte(` }, "archived": false, "permissions": { - "project_access": { - "access_level": 10, - "notification_level": 3 - }, - "group_access": { - "access_level": 50, - "notification_level": 3 - } + "project_access": null, + "group_access": null } } `) diff --git a/remote/gitlab/testdata/testdata.go b/remote/gitlab/testdata/testdata.go index de36846e..3702c13d 100644 --- a/remote/gitlab/testdata/testdata.go +++ b/remote/gitlab/testdata/testdata.go @@ -21,6 +21,9 @@ func NewServer() *httptest.Server { case "/api/v3/projects/diaspora/diaspora-client": w.Write(project4Paylod) return + case "/api/v3/projects/brightbox/puppet": + w.Write(project6Paylod) + return case "/api/v3/projects/diaspora/diaspora-client/services/drone-ci": switch r.Method { case "PUT": @@ -38,11 +41,7 @@ func NewServer() *httptest.Server { w.Write(accessTokenPayload) return case "/api/v3/user": - if r.Header.Get("Authorization") == "Bearer valid_token" { - w.Write(currentUserPayload) - } else { - w.WriteHeader(401) - } + w.Write(currentUserPayload) return } From 8464511286cda786d81ebecec5382dd215a00bca Mon Sep 17 00:00:00 2001 From: Greg Taylor Date: Sat, 9 Jan 2016 23:00:24 -0800 Subject: [PATCH 13/21] Spelling fix on controller/login.go --- controller/login.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/controller/login.go b/controller/login.go index 78cd274b..9a914e24 100644 --- a/controller/login.go +++ b/controller/login.go @@ -20,7 +20,7 @@ func GetLogin(c *gin.Context) { // when dealing with redirects we may need // to adjust the content type. I cannot, however, - // rememver why, so need to revisit this line. + // remember why, so need to revisit this line. c.Writer.Header().Del("Content-Type") tmpuser, open, err := remote.Login(c.Writer, c.Request) From d78edefb0a1416c962e7d98dd677f4bce6328683 Mon Sep 17 00:00:00 2001 From: jackspirou Date: Mon, 11 Jan 2016 12:42:31 -0600 Subject: [PATCH 14/21] allowing for protocol-relative access to external js and css in UI templates --- template/amber/base.amber | 22 +++++++++++----------- template/amber/docs.amber | 4 ++-- template/amber/login.amber | 13 ++++++------- template/amber/login_form.amber | 8 ++++---- template/amber/swagger.amber | 6 +++--- 5 files changed, 26 insertions(+), 27 deletions(-) diff --git a/template/amber/base.amber b/template/amber/base.amber index 6bb2e295..491bf3cf 100644 --- a/template/amber/base.amber +++ b/template/amber/base.amber @@ -7,11 +7,11 @@ html meta[http-equiv="x-ua-compatible"][content="ie=edge"] link[rel="icon"][type="image/x-icon"][href="/static/images/favicon.ico"] - link[rel="stylesheet"][href="https://fonts.googleapis.com/icon?family=Material+Icons"] - link[rel="stylesheet"][href="https://fonts.googleapis.com/css?family=Roboto+Mono"] - link[rel="stylesheet"][href="https://fonts.googleapis.com/css?family=Roboto"] - link[rel="stylesheet"][href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha/css/bootstrap.min.css"] - link[rel="stylesheet"][href="https://cdnjs.cloudflare.com/ajax/libs/octicons/3.1.0/octicons.min.css"] + link[rel="stylesheet"][href="//fonts.googleapis.com/icon?family=Material+Icons"] + link[rel="stylesheet"][href="//fonts.googleapis.com/css?family=Roboto+Mono"] + link[rel="stylesheet"][href="//fonts.googleapis.com/css?family=Roboto"] + link[rel="stylesheet"][href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha/css/bootstrap.min.css"] + link[rel="stylesheet"][href="//cdnjs.cloudflare.com/ajax/libs/octicons/3.1.0/octicons.min.css"] link[rel="stylesheet"][href="/static/styles_gen/style.css"] if Csrf @@ -48,10 +48,10 @@ html block content block scripts - script[type="text/javascript"][src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"] - script[type="text/javascript"][src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.10.6/moment.min.js"] - script[type="text/javascript"][src="https://cdnjs.cloudflare.com/ajax/libs/jquery-searcher/0.2.0/jquery.searcher.min.js"] - script[type="text/javascript"][src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha/js/bootstrap.min.js"] - script[type="text/javascript"][src="https://cdnjs.cloudflare.com/ajax/libs/typeahead.js/0.11.1/typeahead.bundle.min.js"] - script[text="text/javascript"][src="https://cdnjs.cloudflare.com/ajax/libs/stickyfill/1.1.2/stickyfill.js"] + script[type="text/javascript"][src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"] + script[type="text/javascript"][src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.10.6/moment.min.js"] + script[type="text/javascript"][src="//cdnjs.cloudflare.com/ajax/libs/jquery-searcher/0.2.0/jquery.searcher.min.js"] + script[type="text/javascript"][src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha/js/bootstrap.min.js"] + script[type="text/javascript"][src="//cdnjs.cloudflare.com/ajax/libs/typeahead.js/0.11.1/typeahead.bundle.min.js"] + script[text="text/javascript"][src="//cdnjs.cloudflare.com/ajax/libs/stickyfill/1.1.2/stickyfill.js"] script[type="text/javascript"][src="/static/scripts_gen/drone.min.js"] diff --git a/template/amber/docs.amber b/template/amber/docs.amber index a981c904..f0555e13 100644 --- a/template/amber/docs.amber +++ b/template/amber/docs.amber @@ -36,5 +36,5 @@ block content #{Page.HTML} block scripts - script[type="text/javascript"][src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"] - script[type="text/javascript"][src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha/js/bootstrap.min.js"] + script[type="text/javascript"][src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"] + script[type="text/javascript"][src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha/js/bootstrap.min.js"] diff --git a/template/amber/login.amber b/template/amber/login.amber index 716ac88f..7686d2a2 100644 --- a/template/amber/login.amber +++ b/template/amber/login.amber @@ -7,10 +7,10 @@ html meta[http-equiv="x-ua-compatible"][content="ie=edge"] link[rel="icon"][type="image/x-icon"][href="/static/images/favicon.ico"] - link[rel="stylesheet"][href="https://fonts.googleapis.com/icon?family=Material+Icons"] - link[rel="stylesheet"][href="https://fonts.googleapis.com/css?family=Roboto+Mono"] - link[rel="stylesheet"][href="https://fonts.googleapis.com/css?family=Roboto"] - link[rel="stylesheet"][href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha/css/bootstrap.min.css"] + link[rel="stylesheet"][href="//fonts.googleapis.com/icon?family=Material+Icons"] + link[rel="stylesheet"][href="//fonts.googleapis.com/css?family=Roboto+Mono"] + link[rel="stylesheet"][href="//fonts.googleapis.com/css?family=Roboto"] + link[rel="stylesheet"][href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha/css/bootstrap.min.css"] link[rel="stylesheet"][href="/static/styles_gen/style.css"] style html { height: 100%; overflow: hidden; } @@ -22,7 +22,7 @@ html if Error == "oauth_error" div.alert.alert-danger - | We failed to authorize your account. Please contact your + | We failed to authorize your account. Please contact your | system administrator to check the logs and see what went wrong. else if Error == "access_denied" @@ -31,6 +31,5 @@ html else if Error == "internal_error" div.alert.alert-danger - | We encountered an unexpected error. Please contact your + | We encountered an unexpected error. Please contact your | system administrator to check the logs and see what went wrong. - diff --git a/template/amber/login_form.amber b/template/amber/login_form.amber index c74eacf6..62631dfd 100644 --- a/template/amber/login_form.amber +++ b/template/amber/login_form.amber @@ -7,10 +7,10 @@ html meta[http-equiv="x-ua-compatible"][content="ie=edge"] link[rel="icon"][type="image/x-icon"][href="/static/images/favicon.ico"] - link[rel="stylesheet"][href="https://fonts.googleapis.com/icon?family=Material+Icons"] - link[rel="stylesheet"][href="https://fonts.googleapis.com/css?family=Roboto+Mono"] - link[rel="stylesheet"][href="https://fonts.googleapis.com/css?family=Roboto"] - link[rel="stylesheet"][href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha/css/bootstrap.min.css"] + link[rel="stylesheet"][href="//fonts.googleapis.com/icon?family=Material+Icons"] + link[rel="stylesheet"][href="//fonts.googleapis.com/css?family=Roboto+Mono"] + link[rel="stylesheet"][href="//fonts.googleapis.com/css?family=Roboto"] + link[rel="stylesheet"][href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha/css/bootstrap.min.css"] link[rel="stylesheet"][href="/static/styles_gen/style.css"] style html { height: 100%; overflow: hidden; } diff --git a/template/amber/swagger.amber b/template/amber/swagger.amber index fc7f1561..0f7cedf5 100644 --- a/template/amber/swagger.amber +++ b/template/amber/swagger.amber @@ -24,7 +24,7 @@ block content div.row ul.toc each $tag in Swagger.Tags - li + li h2 #{$tag.Name} ul each $op in $tag.Ops @@ -72,5 +72,5 @@ block content pre #{$res.Example} block scripts - script[type="text/javascript"][src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"] - script[type="text/javascript"][src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha/js/bootstrap.min.js"] + script[type="text/javascript"][src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"] + script[type="text/javascript"][src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha/js/bootstrap.min.js"] From 39ee59a01b7e6740d99e6c83ee4fb74f8ffe0132 Mon Sep 17 00:00:00 2001 From: Georges Chaudy Date: Tue, 12 Jan 2016 15:40:13 +0000 Subject: [PATCH 15/21] fix: gitlab owner permission --- remote/gitlab/gitlab.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/remote/gitlab/gitlab.go b/remote/gitlab/gitlab.go index ebf5ae61..f20ebf2d 100644 --- a/remote/gitlab/gitlab.go +++ b/remote/gitlab/gitlab.go @@ -199,12 +199,12 @@ func (g *Gitlab) Perm(u *model.User, owner, name string) (*model.Perm, error) { return nil, err } - // repo owner are granted full access - if u.Login == repo.Owner.Username { + // repo owner is granted full access + if repo.Owner != nil && repo.Owner.Username == u.Login { return &model.Perm{true, true, true}, nil } - // check permission for users + // check permission for current user m := &model.Perm{} m.Admin = IsAdmin(repo) m.Pull = IsRead(repo) From d5767b7d571edd89403626b0b2cb6ea21e29caa3 Mon Sep 17 00:00:00 2001 From: John Engelman Date: Sun, 10 Jan 2016 17:19:48 -0600 Subject: [PATCH 16/21] Add support for configuring escalated plugins via envvar. --- controller/build.go | 7 ++++--- controller/hook.go | 12 +++++++----- docs/setup/plugins.md | 10 ++++++++++ model/sys.go | 9 +++++---- 4 files changed, 26 insertions(+), 12 deletions(-) diff --git a/controller/build.go b/controller/build.go index 67a4a7cc..7680fe10 100644 --- a/controller/build.go +++ b/controller/build.go @@ -264,9 +264,10 @@ func PostBuild(c *gin.Context) { Config: string(raw), Secret: string(sec), System: &model.System{ - Link: httputil.GetURL(c.Request), - Plugins: strings.Split(os.Getenv("PLUGIN_FILTER"), " "), - Globals: strings.Split(os.Getenv("PLUGIN_PARAMS"), " "), + Link: httputil.GetURL(c.Request), + Plugins: strings.Split(os.Getenv("PLUGIN_FILTER"), " "), + Globals: strings.Split(os.Getenv("PLUGIN_PARAMS"), " "), + Escalates: strings.Split(os.Getenv("ESCALATE_FILTER"), " "), }, }) diff --git a/controller/hook.go b/controller/hook.go index f435c326..58bc83fd 100644 --- a/controller/hook.go +++ b/controller/hook.go @@ -2,11 +2,12 @@ package controller import ( "fmt" - "github.com/gin-gonic/gin" "os" "path/filepath" - "strings" "regexp" + "strings" + + "github.com/gin-gonic/gin" log "github.com/Sirupsen/logrus" "github.com/drone/drone/engine" @@ -214,9 +215,10 @@ func PostHook(c *gin.Context) { Config: string(raw), Secret: string(sec), System: &model.System{ - Link: httputil.GetURL(c.Request), - Plugins: strings.Split(os.Getenv("PLUGIN_FILTER"), " "), - Globals: strings.Split(os.Getenv("PLUGIN_PARAMS"), " "), + Link: httputil.GetURL(c.Request), + Plugins: strings.Split(os.Getenv("PLUGIN_FILTER"), " "), + Globals: strings.Split(os.Getenv("PLUGIN_PARAMS"), " "), + Escalates: strings.Split(os.Getenv("ESCALATE_FILTER"), " "), }, }) diff --git a/docs/setup/plugins.md b/docs/setup/plugins.md index 0a8d9e49..971f97bc 100644 --- a/docs/setup/plugins.md +++ b/docs/setup/plugins.md @@ -19,3 +19,13 @@ Whitelist official Drone plugins and registry user `octocat` ``` PLUGIN_FILTER=plugins/* octocat/* ``` + +Additionally, some plugins may require to be execute as a "privileged" container. +This mode is most common for plugins that are attempting to run docker in docker type behaviors (for example the plugins/docker requires this mode). +Drone will ship will a default pattern that will allow selected official Drone plugins to run in an privileged mode. +This whitelist can be customized by setting the `ESCALATE_FILTER` environment variable. +This is a space-separated list and includes glob matching capabilities. + +``` +ESCALATE_FILTER=plugins/drone-docker plugins/drone-ecr plugins/drone-gcr +``` diff --git a/model/sys.go b/model/sys.go index ce515f1c..d66cc6ed 100644 --- a/model/sys.go +++ b/model/sys.go @@ -1,8 +1,9 @@ package model type System struct { - Version string `json:"version"` - Link string `json:"link_url"` - Plugins []string `json:"plugins"` - Globals []string `json:"globals"` + Version string `json:"version"` + Link string `json:"link_url"` + Plugins []string `json:"plugins"` + Globals []string `json:"globals"` + Escalates []string `json:"privileged_plugins"` } From 007a3462cadf18da4173449d891db54a8243725d Mon Sep 17 00:00:00 2001 From: Jonathan Duck Date: Wed, 13 Jan 2016 04:31:16 -0800 Subject: [PATCH 17/21] Allow Gogs server on a subdirectory --- docs/setup/gogs.md | 3 ++- remote/gogs/gogs.go | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/setup/gogs.md b/docs/setup/gogs.md index 736cabc8..c33aa6a3 100644 --- a/docs/setup/gogs.md +++ b/docs/setup/gogs.md @@ -12,7 +12,7 @@ REMOTE_CONFIG=https://gogs.hooli.com?open=false The following is the standard URI connection scheme: ``` -scheme://host[:port][?options] +scheme://host[:port][/path][?options] ``` The components of this string are: @@ -20,6 +20,7 @@ The components of this string are: * `scheme` server protocol `http` or `https`. * `host` server address to connect to. The default value is github.com if not specified. * `:port` optional. The default value is :80 if not specified. +* `/path` optional. The default value is the root directory if not specified. * `?options` connection specific options. ## Gogs options diff --git a/remote/gogs/gogs.go b/remote/gogs/gogs.go index c420a8e0..d8e33824 100644 --- a/remote/gogs/gogs.go +++ b/remote/gogs/gogs.go @@ -30,7 +30,6 @@ func Load(env envconfig.Env) *Gogs { log.Fatalln("unable to parse remote dsn. %s", err) } params := url_.Query() - url_.Path = "" url_.RawQuery = "" // create the Githbub remote using parameters from From 32e2371ba6626a9f352baeb69177f5d3fef19ec8 Mon Sep 17 00:00:00 2001 From: Kirilll Zaycev Date: Thu, 14 Jan 2016 02:05:46 +0300 Subject: [PATCH 18/21] Add member struct to project --- remote/gitlab/client/types.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/remote/gitlab/client/types.go b/remote/gitlab/client/types.go index 7a5668a6..d89311a2 100644 --- a/remote/gitlab/client/types.go +++ b/remote/gitlab/client/types.go @@ -25,8 +25,19 @@ type Permissions struct { GroupAccess *GroupAccess `json:"group_access,omitempty"` } +type Member struct { + Id int + Username string + Email string + Name string + State string + CreatedAt string `json:"created_at,omitempty"` + // AccessLevel int +} + type Project struct { Id int `json:"id,omitempty"` + Owner *Member `json:"owner,omitempty"` Name string `json:"name,omitempty"` Description string `json:"description,omitempty"` DefaultBranch string `json:"default_branch,omitempty"` From 5a4b928dbe507058f592c32f6b1cc89f6714e807 Mon Sep 17 00:00:00 2001 From: Michael Gibson Date: Thu, 21 Jan 2016 09:41:34 -0700 Subject: [PATCH 19/21] updating go-gogs-client vendor codebase --- .../gogits/go-gogs-client/admin_orgs.go | 30 ++++++++ .../gogits/go-gogs-client/admin_repos.go | 22 ++++++ .../gogits/go-gogs-client/admin_users.go | 70 +++++++++++++++++++ .../github.com/gogits/go-gogs-client/gogs.go | 9 ++- .../gogits/go-gogs-client/miscellaneous.go | 11 +++ .../github.com/gogits/go-gogs-client/org.go | 54 ++++++++++++++ .../github.com/gogits/go-gogs-client/repo.go | 37 +++++++++- .../gogits/go-gogs-client/repo_hooks.go | 2 + .../gogits/go-gogs-client/repo_keys.go | 52 ++++++++++++++ .../gogits/go-gogs-client/user_app.go | 2 +- .../gogits/go-gogs-client/user_email.go | 46 ++++++++++++ .../gogits/go-gogs-client/user_follow.go | 47 +++++++++++++ .../gogits/go-gogs-client/user_keys.go | 51 ++++++++++++++ .../github.com/gogits/go-gogs-client/utils.go | 9 +++ 14 files changed, 436 insertions(+), 6 deletions(-) create mode 100644 vendor/github.com/gogits/go-gogs-client/admin_orgs.go create mode 100644 vendor/github.com/gogits/go-gogs-client/admin_repos.go create mode 100644 vendor/github.com/gogits/go-gogs-client/admin_users.go create mode 100644 vendor/github.com/gogits/go-gogs-client/miscellaneous.go create mode 100644 vendor/github.com/gogits/go-gogs-client/org.go create mode 100644 vendor/github.com/gogits/go-gogs-client/repo_keys.go create mode 100644 vendor/github.com/gogits/go-gogs-client/user_email.go create mode 100644 vendor/github.com/gogits/go-gogs-client/user_follow.go create mode 100644 vendor/github.com/gogits/go-gogs-client/user_keys.go create mode 100644 vendor/github.com/gogits/go-gogs-client/utils.go diff --git a/vendor/github.com/gogits/go-gogs-client/admin_orgs.go b/vendor/github.com/gogits/go-gogs-client/admin_orgs.go new file mode 100644 index 00000000..ee29464d --- /dev/null +++ b/vendor/github.com/gogits/go-gogs-client/admin_orgs.go @@ -0,0 +1,30 @@ +// Copyright 2015 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package gogs + +import ( + "bytes" + "encoding/json" + "fmt" + "net/http" +) + +type CreateOrgOption struct { + UserName string `json:"username" binding:"Required"` + FullName string `json:"full_name"` + Description string `json:"description"` + Website string `json:"website"` + Location string `json:"location"` +} + +func (c *Client) AdminCreateOrg(user string, opt CreateOrgOption) (*Organization, error) { + body, err := json.Marshal(&opt) + if err != nil { + return nil, err + } + org := new(Organization) + return org, c.getParsedResponse("POST", fmt.Sprintf("/admin/users/%s/orgs", user), + http.Header{"content-type": []string{"application/json"}}, bytes.NewReader(body), org) +} diff --git a/vendor/github.com/gogits/go-gogs-client/admin_repos.go b/vendor/github.com/gogits/go-gogs-client/admin_repos.go new file mode 100644 index 00000000..8a213cb1 --- /dev/null +++ b/vendor/github.com/gogits/go-gogs-client/admin_repos.go @@ -0,0 +1,22 @@ +// Copyright 2015 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package gogs + +import ( + "bytes" + "encoding/json" + "fmt" + "net/http" +) + +func (c *Client) AdminCreateRepo(user string, opt CreateRepoOption) (*Repository, error) { + body, err := json.Marshal(&opt) + if err != nil { + return nil, err + } + repo := new(Repository) + return repo, c.getParsedResponse("POST", fmt.Sprintf("/admin/users/%s/repos", user), + http.Header{"content-type": []string{"application/json"}}, bytes.NewReader(body), repo) +} diff --git a/vendor/github.com/gogits/go-gogs-client/admin_users.go b/vendor/github.com/gogits/go-gogs-client/admin_users.go new file mode 100644 index 00000000..f8e26d95 --- /dev/null +++ b/vendor/github.com/gogits/go-gogs-client/admin_users.go @@ -0,0 +1,70 @@ +// Copyright 2015 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package gogs + +import ( + "bytes" + "encoding/json" + "fmt" + "net/http" +) + +type CreateUserOption struct { + SourceID int64 `json:"source_id"` + LoginName string `json:"login_name"` + Username string `json:"username" binding:"Required;AlphaDashDot;MaxSize(35)"` + Email string `json:"email" binding:"Required;Email;MaxSize(254)"` + Password string `json:"password" binding:"MaxSize(255)"` + SendNotify bool `json:"send_notify"` +} + +func (c *Client) AdminCreateUser(opt CreateUserOption) (*User, error) { + body, err := json.Marshal(&opt) + if err != nil { + return nil, err + } + user := new(User) + return user, c.getParsedResponse("POST", "/admin/users", + http.Header{"content-type": []string{"application/json"}}, bytes.NewReader(body), user) +} + +type EditUserOption struct { + SourceID int64 `json:"source_id"` + LoginName string `json:"login_name"` + FullName string `json:"full_name" binding:"MaxSize(100)"` + Email string `json:"email" binding:"Required;Email;MaxSize(254)"` + Password string `json:"password" binding:"MaxSize(255)"` + Website string `json:"website" binding:"MaxSize(50)"` + Location string `json:"location" binding:"MaxSize(50)"` + Active *bool `json:"active"` + Admin *bool `json:"admin"` + AllowGitHook *bool `json:"allow_git_hook"` + AllowImportLocal *bool `json:"allow_import_local"` +} + +func (c *Client) AdminEditUser(user string, opt EditUserOption) error { + body, err := json.Marshal(&opt) + if err != nil { + return err + } + _, err = c.getResponse("PATCH", fmt.Sprintf("/admin/users/%s", user), + http.Header{"content-type": []string{"application/json"}}, bytes.NewReader(body)) + return err +} + +func (c *Client) AdminDeleteUser(user string) error { + _, err := c.getResponse("DELETE", fmt.Sprintf("/admin/users/%s", user), nil, nil) + return err +} + +func (c *Client) AdminCreateUserPublicKey(user string, opt CreateKeyOption) (*PublicKey, error) { + body, err := json.Marshal(&opt) + if err != nil { + return nil, err + } + key := new(PublicKey) + return key, c.getParsedResponse("POST", fmt.Sprintf("/admin/users/%s/keys", user), + http.Header{"content-type": []string{"application/json"}}, bytes.NewReader(body), key) +} diff --git a/vendor/github.com/gogits/go-gogs-client/gogs.go b/vendor/github.com/gogits/go-gogs-client/gogs.go index f921090f..dba1328d 100644 --- a/vendor/github.com/gogits/go-gogs-client/gogs.go +++ b/vendor/github.com/gogits/go-gogs-client/gogs.go @@ -14,7 +14,7 @@ import ( ) func Version() string { - return "0.0.2" + return "0.7.2" } // Client represents a Gogs API client. @@ -33,6 +33,11 @@ func NewClient(url, token string) *Client { } } +// SetHTTPClient replaces default http.Client with user given one. +func (c *Client) SetHTTPClient(client *http.Client) { + c.client = client +} + func (c *Client) getResponse(method, path string, header http.Header, body io.Reader) ([]byte, error) { req, err := http.NewRequest(method, c.url+"/api/v1"+path, body) if err != nil { @@ -61,7 +66,7 @@ func (c *Client) getResponse(method, path string, header http.Header, body io.Re return nil, errors.New("404 Not Found") } - if resp.StatusCode != 200 && resp.StatusCode != 201 { + if resp.StatusCode/100 != 2 { errMap := make(map[string]interface{}) if err = json.Unmarshal(data, &errMap); err != nil { return nil, err diff --git a/vendor/github.com/gogits/go-gogs-client/miscellaneous.go b/vendor/github.com/gogits/go-gogs-client/miscellaneous.go new file mode 100644 index 00000000..fcf362ce --- /dev/null +++ b/vendor/github.com/gogits/go-gogs-client/miscellaneous.go @@ -0,0 +1,11 @@ +// Copyright 2015 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package gogs + +type MarkdownOption struct { + Text string + Mode string + Context string +} diff --git a/vendor/github.com/gogits/go-gogs-client/org.go b/vendor/github.com/gogits/go-gogs-client/org.go new file mode 100644 index 00000000..4d31461e --- /dev/null +++ b/vendor/github.com/gogits/go-gogs-client/org.go @@ -0,0 +1,54 @@ +// Copyright 2015 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package gogs + +import ( + "bytes" + "encoding/json" + "fmt" + "net/http" +) + +type Organization struct { + ID int64 `json:"id"` + UserName string `json:"username"` + FullName string `json:"full_name"` + AvatarUrl string `json:"avatar_url"` + Description string `json:"description"` + Website string `json:"website"` + Location string `json:"location"` +} + +func (c *Client) ListMyOrgs() ([]*Organization, error) { + orgs := make([]*Organization, 0, 5) + return orgs, c.getParsedResponse("GET", "/user/orgs", nil, nil, &orgs) +} + +func (c *Client) ListUserOrgs(user string) ([]*Organization, error) { + orgs := make([]*Organization, 0, 5) + return orgs, c.getParsedResponse("GET", fmt.Sprintf("/users/%s/orgs", user), nil, nil, &orgs) +} + +func (c *Client) GetOrg(orgname string) (*Organization, error) { + org := new(Organization) + return org, c.getParsedResponse("GET", fmt.Sprintf("/orgs/%s", orgname), nil, nil, org) +} + +type EditOrgOption struct { + FullName string `json:"full_name"` + Description string `json:"description"` + Website string `json:"website"` + Location string `json:"location"` +} + +func (c *Client) EditOrg(orgname string, opt EditOrgOption) error { + body, err := json.Marshal(&opt) + if err != nil { + return err + } + _, err = c.getResponse("PATCH", fmt.Sprintf("/orgs/%s", orgname), + http.Header{"content-type": []string{"application/json"}}, bytes.NewReader(body)) + return err +} diff --git a/vendor/github.com/gogits/go-gogs-client/repo.go b/vendor/github.com/gogits/go-gogs-client/repo.go index 5f519448..7f703cba 100644 --- a/vendor/github.com/gogits/go-gogs-client/repo.go +++ b/vendor/github.com/gogits/go-gogs-client/repo.go @@ -34,12 +34,11 @@ type Repository struct { // ListMyRepos lists all repositories for the authenticated user that has access to. func (c *Client) ListMyRepos() ([]*Repository, error) { repos := make([]*Repository, 0, 10) - err := c.getParsedResponse("GET", "/user/repos", nil, nil, &repos) - return repos, err + return repos, c.getParsedResponse("GET", "/user/repos", nil, nil, &repos) } type CreateRepoOption struct { - Name string `json:"name" binding:"Required"` + Name string `json:"name" binding:"Required;AlphaDashDot;MaxSize(100)"` Description string `json:"description" binding:"MaxSize(255)"` Private bool `json:"private"` AutoInit bool `json:"auto_init"` @@ -70,8 +69,40 @@ func (c *Client) CreateOrgRepo(org string, opt CreateRepoOption) (*Repository, e http.Header{"content-type": []string{"application/json"}}, bytes.NewReader(body), repo) } +// GetRepo returns information of a repository of given owner. +func (c *Client) GetRepo(owner, reponame string) (*Repository, error) { + repo := new(Repository) + return repo, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s", owner, reponame), nil, nil, repo) +} + // DeleteRepo deletes a repository of user or organization. func (c *Client) DeleteRepo(owner, repo string) error { _, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s", owner, repo), nil, nil) return err } + +type MigrateRepoOption struct { + CloneAddr string `json:"clone_addr" binding:"Required"` + AuthUsername string `json:"auth_username"` + AuthPassword string `json:"auth_password"` + UID int `json:"uid" binding:"Required"` + RepoName string `json:"repo_name" binding:"Required"` + Mirror bool `json:"mirror"` + Private bool `json:"private"` + Description string `json:"description"` +} + +// MigrateRepo migrates a repository from other Git hosting sources for the +// authenticated user. +// +// To migrate a repository for a organization, the authenticated user must be a +// owner of the specified organization. +func (c *Client) MigrateRepo(opt MigrateRepoOption) (*Repository, error) { + body, err := json.Marshal(&opt) + if err != nil { + return nil, err + } + repo := new(Repository) + return repo, c.getParsedResponse("POST", "/repos/migrate", + http.Header{"content-type": []string{"application/json"}}, bytes.NewReader(body), repo) +} diff --git a/vendor/github.com/gogits/go-gogs-client/repo_hooks.go b/vendor/github.com/gogits/go-gogs-client/repo_hooks.go index 89d5ef9a..fa3a1e68 100644 --- a/vendor/github.com/gogits/go-gogs-client/repo_hooks.go +++ b/vendor/github.com/gogits/go-gogs-client/repo_hooks.go @@ -95,6 +95,8 @@ type PayloadRepo struct { ID int64 `json:"id"` Name string `json:"name"` URL string `json:"url"` + SSHURL string `json:"ssh_url"` + CloneURL string `json:"clone_url"` Description string `json:"description"` Website string `json:"website"` Watchers int `json:"watchers"` diff --git a/vendor/github.com/gogits/go-gogs-client/repo_keys.go b/vendor/github.com/gogits/go-gogs-client/repo_keys.go new file mode 100644 index 00000000..dfd15c9e --- /dev/null +++ b/vendor/github.com/gogits/go-gogs-client/repo_keys.go @@ -0,0 +1,52 @@ +// Copyright 2015 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package gogs + +import ( + "bytes" + "encoding/json" + "fmt" + "net/http" + "time" +) + +type DeployKey struct { + ID int64 `json:"id"` + Key string `json:"key"` + URL string `json:"url"` + Title string `json:"title"` + Created time.Time `json:"created_at"` + ReadOnly bool `json:"read_only"` +} + +func (c *Client) ListDeployKeys(user, repo string) ([]*DeployKey, error) { + keys := make([]*DeployKey, 0, 10) + return keys, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/keys", user, repo), nil, nil, &keys) +} + +func (c *Client) GetDeployKey(user, repo string, keyID int64) (*DeployKey, error) { + key := new(DeployKey) + return key, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/keys/%d", user, repo, keyID), nil, nil, &key) +} + +type CreateKeyOption struct { + Title string `json:"title" binding:"Required"` + Key string `json:"key" binding:"Required"` +} + +func (c *Client) CreateDeployKey(user, repo string, opt CreateKeyOption) (*DeployKey, error) { + body, err := json.Marshal(&opt) + if err != nil { + return nil, err + } + key := new(DeployKey) + return key, c.getParsedResponse("POST", fmt.Sprintf("/repos/%s/%s/keys", user, repo), + http.Header{"content-type": []string{"application/json"}}, bytes.NewReader(body), key) +} + +func (c *Client) DeleteDeployKey(owner, repo string, keyID int64) error { + _, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/keys/%d", owner, repo, keyID), nil, nil) + return err +} diff --git a/vendor/github.com/gogits/go-gogs-client/user_app.go b/vendor/github.com/gogits/go-gogs-client/user_app.go index 152492bf..965ed6eb 100644 --- a/vendor/github.com/gogits/go-gogs-client/user_app.go +++ b/vendor/github.com/gogits/go-gogs-client/user_app.go @@ -29,7 +29,7 @@ func (c *Client) ListAccessTokens(user, pass string) ([]*AccessToken, error) { } type CreateAccessTokenOption struct { - Name string `json:"name"` + Name string `json:"name" binding:"Required"` } func (c *Client) CreateAccessToken(user, pass string, opt CreateAccessTokenOption) (*AccessToken, error) { diff --git a/vendor/github.com/gogits/go-gogs-client/user_email.go b/vendor/github.com/gogits/go-gogs-client/user_email.go new file mode 100644 index 00000000..b3465992 --- /dev/null +++ b/vendor/github.com/gogits/go-gogs-client/user_email.go @@ -0,0 +1,46 @@ +// Copyright 2015 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package gogs + +import ( + "bytes" + "encoding/json" + "net/http" +) + +type Email struct { + Email string `json:"email"` + Verified bool `json:"verified"` + Primary bool `json:"primary"` +} + +func (c *Client) ListEmails() ([]*Email, error) { + emails := make([]*Email, 0, 3) + return emails, c.getParsedResponse("GET", "/user/emails", nil, nil, &emails) +} + +type CreateEmailOption struct { + Emails []string `json:"emails"` +} + +func (c *Client) AddEmail(opt CreateEmailOption) ([]*Email, error) { + body, err := json.Marshal(&opt) + if err != nil { + return nil, err + } + emails := make([]*Email, 0, 3) + return emails, c.getParsedResponse("POST", "/user/emails", + http.Header{"content-type": []string{"application/json"}}, bytes.NewReader(body), emails) +} + +func (c *Client) DeleteEmail(opt CreateEmailOption) error { + body, err := json.Marshal(&opt) + if err != nil { + return err + } + _, err = c.getResponse("DELETE", "/user/emails", + http.Header{"content-type": []string{"application/json"}}, bytes.NewReader(body)) + return err +} diff --git a/vendor/github.com/gogits/go-gogs-client/user_follow.go b/vendor/github.com/gogits/go-gogs-client/user_follow.go new file mode 100644 index 00000000..36cc65d4 --- /dev/null +++ b/vendor/github.com/gogits/go-gogs-client/user_follow.go @@ -0,0 +1,47 @@ +// Copyright 2015 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package gogs + +import "fmt" + +func (c *Client) ListMyFollowers(page int) ([]*User, error) { + users := make([]*User, 0, 10) + return users, c.getParsedResponse("GET", fmt.Sprintf("/user/followers?page=%d", page), nil, nil, &users) +} + +func (c *Client) ListFollowers(user string, page int) ([]*User, error) { + users := make([]*User, 0, 10) + return users, c.getParsedResponse("GET", fmt.Sprintf("/users/%s/followers?page=%d", user, page), nil, nil, &users) +} + +func (c *Client) ListMyFollowing(page int) ([]*User, error) { + users := make([]*User, 0, 10) + return users, c.getParsedResponse("GET", fmt.Sprintf("/user/following?page=%d", page), nil, nil, &users) +} + +func (c *Client) ListFollowing(user string, page int) ([]*User, error) { + users := make([]*User, 0, 10) + return users, c.getParsedResponse("GET", fmt.Sprintf("/users/%s/following?page=%d", user, page), nil, nil, &users) +} + +func (c *Client) IsFollowing(target string) bool { + _, err := c.getResponse("GET", fmt.Sprintf("/user/following/%s", target), nil, nil) + return err == nil +} + +func (c *Client) IsUserFollowing(user, target string) bool { + _, err := c.getResponse("GET", fmt.Sprintf("/users/%s/following/%s", user, target), nil, nil) + return err == nil +} + +func (c *Client) Follow(target string) error { + _, err := c.getResponse("PUT", fmt.Sprintf("/user/following/%s", target), nil, nil) + return err +} + +func (c *Client) Unfollow(target string) error { + _, err := c.getResponse("DELETE", fmt.Sprintf("/user/following/%s", target), nil, nil) + return err +} diff --git a/vendor/github.com/gogits/go-gogs-client/user_keys.go b/vendor/github.com/gogits/go-gogs-client/user_keys.go new file mode 100644 index 00000000..cb217572 --- /dev/null +++ b/vendor/github.com/gogits/go-gogs-client/user_keys.go @@ -0,0 +1,51 @@ +// Copyright 2015 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package gogs + +import ( + "bytes" + "encoding/json" + "fmt" + "net/http" + "time" +) + +type PublicKey struct { + ID int64 `json:"id"` + Key string `json:"key"` + URL string `json:"url,omitempty"` + Title string `json:"title,omitempty"` + Created time.Time `json:"created_at,omitempty"` +} + +func (c *Client) ListPublicKeys(user string) ([]*PublicKey, error) { + keys := make([]*PublicKey, 0, 10) + return keys, c.getParsedResponse("GET", fmt.Sprintf("/users/%s/keys", user), nil, nil, &keys) +} + +func (c *Client) ListMyPublicKeys(user string) ([]*PublicKey, error) { + keys := make([]*PublicKey, 0, 10) + return keys, c.getParsedResponse("GET", fmt.Sprintf("/user/keys", user), nil, nil, &keys) +} + +func (c *Client) GetPublicKey(keyID int64) (*PublicKey, error) { + key := new(PublicKey) + return key, c.getParsedResponse("GET", fmt.Sprintf("/user/keys/%d", keyID), nil, nil, &key) +} + +func (c *Client) CreatePublicKey(opt CreateKeyOption) (*PublicKey, error) { + body, err := json.Marshal(&opt) + if err != nil { + return nil, err + } + key := new(PublicKey) + return key, c.getParsedResponse("POST", "/user/keys", + http.Header{"content-type": []string{"application/json"}}, bytes.NewReader(body), key) +} + +func (c *Client) DeletePublicKey(keyID int64) error { + _, err := c.getResponse("DELETE", fmt.Sprintf("/user/keys/%d", keyID), nil, nil) + return err +} diff --git a/vendor/github.com/gogits/go-gogs-client/utils.go b/vendor/github.com/gogits/go-gogs-client/utils.go new file mode 100644 index 00000000..134fd8e5 --- /dev/null +++ b/vendor/github.com/gogits/go-gogs-client/utils.go @@ -0,0 +1,9 @@ +// Copyright 2015 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package gogs + +func Bool(v bool) *bool { + return &v +} From 2de9f29c6bdebc3cc8eecdd84fc35366393aa2fd Mon Sep 17 00:00:00 2001 From: Michael Gibson Date: Thu, 21 Jan 2016 09:50:15 -0700 Subject: [PATCH 20/21] enabling skip_verify functionality in gogs client --- remote/gogs/gogs.go | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/remote/gogs/gogs.go b/remote/gogs/gogs.go index d8e33824..96f85879 100644 --- a/remote/gogs/gogs.go +++ b/remote/gogs/gogs.go @@ -1,6 +1,7 @@ package gogs import ( + "crypto/tls" "fmt" "net" "net/http" @@ -58,7 +59,7 @@ func (g *Gogs) Login(res http.ResponseWriter, req *http.Request) (*model.User, b return nil, false, nil } - client := gogs.NewClient(g.URL, "") + client := NewGogsClient(g.URL, "", g.SkipVerify) // try to fetch drone token if it exists var accessToken string @@ -82,7 +83,7 @@ func (g *Gogs) Login(res http.ResponseWriter, req *http.Request) (*model.User, b accessToken = token.Sha1 } - client = gogs.NewClient(g.URL, accessToken) + client = NewGogsClient(g.URL, accessToken, g.SkipVerify) userInfo, err := client.GetUserInfo(username) if err != nil { return nil, false, err @@ -104,7 +105,7 @@ func (g *Gogs) Auth(token, secret string) (string, error) { // Repo fetches the named repository from the remote system. func (g *Gogs) Repo(u *model.User, owner, name string) (*model.Repo, error) { - client := gogs.NewClient(g.URL, u.Token) + client := NewGogsClient(g.URL, u.Token, g.SkipVerify) repos_, err := client.ListMyRepos() if err != nil { return nil, err @@ -124,7 +125,7 @@ func (g *Gogs) Repo(u *model.User, owner, name string) (*model.Repo, error) { func (g *Gogs) Repos(u *model.User) ([]*model.RepoLite, error) { repos := []*model.RepoLite{} - client := gogs.NewClient(g.URL, u.Token) + client := NewGogsClient(g.URL, u.Token, g.SkipVerify) repos_, err := client.ListMyRepos() if err != nil { return repos, err @@ -140,7 +141,7 @@ func (g *Gogs) Repos(u *model.User) ([]*model.RepoLite, error) { // Perm fetches the named repository permissions from // the remote system for the specified user. func (g *Gogs) Perm(u *model.User, owner, name string) (*model.Perm, error) { - client := gogs.NewClient(g.URL, u.Token) + client := NewGogsClient(g.URL, u.Token, g.SkipVerify) repos_, err := client.ListMyRepos() if err != nil { return nil, err @@ -160,7 +161,7 @@ func (g *Gogs) Perm(u *model.User, owner, name string) (*model.Perm, error) { // Script fetches the build script (.drone.yml) from the remote // repository and returns in string format. func (g *Gogs) Script(u *model.User, r *model.Repo, b *model.Build) ([]byte, []byte, error) { - client := gogs.NewClient(g.URL, u.Token) + client := NewGogsClient(g.URL, u.Token, g.SkipVerify) cfg, err := client.GetFile(r.Owner, r.Name, b.Commit, ".drone.yml") sec, _ := client.GetFile(r.Owner, r.Name, b.Commit, ".drone.sec") return cfg, sec, err @@ -204,7 +205,7 @@ func (g *Gogs) Activate(u *model.User, r *model.Repo, k *model.Key, link string) Active: true, } - client := gogs.NewClient(g.URL, u.Token) + client := NewGogsClient(g.URL, u.Token, g.SkipVerify) _, err := client.CreateRepoHook(r.Owner, r.Name, hook) return err } @@ -236,6 +237,20 @@ func (g *Gogs) Hook(r *http.Request) (*model.Repo, *model.Build, error) { return repo, build, err } +// NewClient initializes and returns a API client. +func NewGogsClient(url, token string, skipVerify bool) *gogs.Client { + sslClient := &http.Client{} + c := gogs.NewClient(url, token) + + if skipVerify { + sslClient.Transport = &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + } + c.SetHTTPClient(sslClient) + } + return c +} + func (g *Gogs) String() string { return "gogs" } From 20c1ca6e33a3de260b3ab5f84391fa4c07e278e7 Mon Sep 17 00:00:00 2001 From: Brad Rydzewski Date: Thu, 21 Jan 2016 13:23:19 -0800 Subject: [PATCH 21/21] Update cache.go set the cache to 30m instead of 24h until we have a way to flush from the UI --- cache/cache.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cache/cache.go b/cache/cache.go index f29c219c..80e631a8 100644 --- a/cache/cache.go +++ b/cache/cache.go @@ -21,9 +21,9 @@ func Set(c context.Context, key string, value interface{}) error { } // Default creates an in-memory cache with the default -// 24 hour expiration period. +// 30 minute expiration period. func Default() Cache { - return cache.NewMemoryWithTTL(time.Hour * 24) + return cache.NewMemoryWithTTL(time.Minute * 30) } // NewTTL returns an in-memory cache with the specified