From deb2c79c2fec33a8eb4be7d7b7a8012d1ae76906 Mon Sep 17 00:00:00 2001 From: Nurahmadie Date: Thu, 27 Mar 2014 18:19:36 +0700 Subject: [PATCH 01/12] Stub for gitlab integration --- Makefile | 1 + cmd/droned/drone.go | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/Makefile b/Makefile index a7882d6c..deb64cd6 100644 --- a/Makefile +++ b/Makefile @@ -42,6 +42,7 @@ deps: #go get github.com/dotcloud/docker/pkg/term go get github.com/drone/go-github/github go get github.com/drone/go-bitbucket/bitbucket + go get github.com/plouc/go-gitlab-client go get github.com/GeertJohan/go.rice go get github.com/GeertJohan/go.rice/rice go get github.com/go-sql-driver/mysql diff --git a/cmd/droned/drone.go b/cmd/droned/drone.go index 93dfa9c6..4c8d552f 100644 --- a/cmd/droned/drone.go +++ b/cmd/droned/drone.go @@ -16,6 +16,7 @@ import ( "github.com/drone/drone/pkg/channel" "github.com/drone/drone/pkg/database" "github.com/drone/drone/pkg/handler" + "github.com/drone/drone/pkg/handler/gitlab" "github.com/drone/drone/pkg/queue" ) @@ -135,6 +136,10 @@ func setupHandlers() { m.Post("/new/github.com", handler.UserHandler(handler.RepoCreateGithub)) m.Get("/new/github.com", handler.UserHandler(handler.RepoAdd)) + // handlers for setting up your GitLab repository + m.Post("/new/gitlab", handler.UserHandler(gitlab.RepoCreate)) + m.Get("/new/gitlab", handler.UserHandler(gitlab.RepoAdd)) + // handlers for linking your GitHub account m.Get("/auth/login/github", handler.UserHandler(handler.LinkGithub)) @@ -178,6 +183,9 @@ func setupHandlers() { // handlers for GitHub post-commit hooks m.Post("/hook/github.com", handler.ErrorHandler(hookHandler.Hook)) + // handlers for GitLab post-commit hooks + m.Post("/hook/gitlab", handler.ErrorHandler(gitlab.Hook)) + // handlers for first-time installation m.Get("/install", handler.ErrorHandler(handler.Install)) m.Post("/install", handler.ErrorHandler(handler.InstallPost)) From 43c0a5471819b3c3159408157a651909ac8dd0f0 Mon Sep 17 00:00:00 2001 From: Nurahmadie Date: Sat, 29 Mar 2014 06:37:50 +0000 Subject: [PATCH 02/12] Initial Gitlab Support --- cmd/droned/drone.go | 15 +- .../20140328201430_add_gitlab_columns.go | 34 ++ pkg/database/migrate/all.go | 1 + pkg/database/settings.go | 4 +- pkg/database/testing/testing.go | 39 ++- pkg/handler/gitlab.go | 129 +++++++ pkg/handler/testing/gitlab_test.go | 330 ++++++++++++++++++ pkg/model/settings.go | 4 + pkg/model/user.go | 2 + pkg/plugin/publish/publish.go | 2 +- pkg/template/pages/github_add.html | 3 +- pkg/template/pages/github_link.html | 3 +- pkg/template/pages/gitlab_add.html | 102 ++++++ pkg/template/pages/gitlab_link.html | 45 +++ pkg/template/template.go | 2 + 15 files changed, 686 insertions(+), 29 deletions(-) create mode 100644 pkg/database/migrate/20140328201430_add_gitlab_columns.go create mode 100644 pkg/handler/gitlab.go create mode 100644 pkg/handler/testing/gitlab_test.go create mode 100644 pkg/template/pages/gitlab_add.html create mode 100644 pkg/template/pages/gitlab_link.html diff --git a/cmd/droned/drone.go b/cmd/droned/drone.go index 4c8d552f..56bcd454 100644 --- a/cmd/droned/drone.go +++ b/cmd/droned/drone.go @@ -16,7 +16,6 @@ import ( "github.com/drone/drone/pkg/channel" "github.com/drone/drone/pkg/database" "github.com/drone/drone/pkg/handler" - "github.com/drone/drone/pkg/handler/gitlab" "github.com/drone/drone/pkg/queue" ) @@ -117,6 +116,7 @@ func setupHandlers() { queue := queue.Start(workers, queueRunner) hookHandler := handler.NewHookHandler(queue) + gitlab := handler.NewGitlabHandler(queue) m := pat.New() m.Get("/login", handler.ErrorHandler(handler.Login)) @@ -136,13 +136,16 @@ func setupHandlers() { m.Post("/new/github.com", handler.UserHandler(handler.RepoCreateGithub)) m.Get("/new/github.com", handler.UserHandler(handler.RepoAdd)) - // handlers for setting up your GitLab repository - m.Post("/new/gitlab", handler.UserHandler(gitlab.RepoCreate)) - m.Get("/new/gitlab", handler.UserHandler(gitlab.RepoAdd)) - // handlers for linking your GitHub account m.Get("/auth/login/github", handler.UserHandler(handler.LinkGithub)) + // handlers for setting up your GitLab repository + m.Post("/new/gitlab", handler.UserHandler(gitlab.Create)) + m.Get("/new/gitlab", handler.UserHandler(gitlab.Add)) + + // handler for linking GitLab account + m.Post("/link/gitlab", handler.UserHandler(gitlab.Link)) + // handlers for dashboard pages m.Get("/dashboard/team/:team", handler.UserHandler(handler.TeamShow)) m.Get("/dashboard", handler.UserHandler(handler.UserShow)) @@ -184,7 +187,7 @@ func setupHandlers() { m.Post("/hook/github.com", handler.ErrorHandler(hookHandler.Hook)) // handlers for GitLab post-commit hooks - m.Post("/hook/gitlab", handler.ErrorHandler(gitlab.Hook)) + //m.Post("/hook/gitlab", handler.ErrorHandler(gitlab.Hook)) // handlers for first-time installation m.Get("/install", handler.ErrorHandler(handler.Install)) diff --git a/pkg/database/migrate/20140328201430_add_gitlab_columns.go b/pkg/database/migrate/20140328201430_add_gitlab_columns.go new file mode 100644 index 00000000..f0d6ee5c --- /dev/null +++ b/pkg/database/migrate/20140328201430_add_gitlab_columns.go @@ -0,0 +1,34 @@ +package migrate + +type rev20140328201430 struct{} + +var AddGitlabColumns = &rev20140328201430{} + +func (r *rev20140328201430) Revision() int64 { + return 20140328201430 +} + +func (r *rev20140328201430) Up(mg *MigrationDriver) error { + // Migration steps here + if _, err := mg.AddColumn("settings", mg.T.String("gitlab_domain")); err != nil { + return err + } + if _, err := mg.AddColumn("settings", mg.T.String("gitlab_apiurl")); err != nil { + return err + } + + if _, err := mg.Tx.Exec(`update settings set gitlab_domain='gitlab.com', gitlab_apiurl='https://gitlab.com'`); err != nil { + return err + } + _, err := mg.AddColumn("users", mg.T.String("gitlab_token")) + return err +} + +func (r *rev20140328201430) Down(mg *MigrationDriver) error { + // Revert migration steps here + if _, err := mg.DropColumns("users", "gitlab_token"); err != nil { + return err + } + _, err:= mg.DropColumns("settings", "gitlab_domain", "gitlab_apiurl") + return err +} diff --git a/pkg/database/migrate/all.go b/pkg/database/migrate/all.go index 1748f18f..c745a4ed 100644 --- a/pkg/database/migrate/all.go +++ b/pkg/database/migrate/all.go @@ -12,6 +12,7 @@ func (m *Migration) All() *Migration { m.Add(RenamePrivelegedToPrivileged) m.Add(GitHubEnterpriseSupport) m.Add(AddOpenInvitationColumn) + m.Add(AddGitlabColumns) // m.Add(...) // ... diff --git a/pkg/database/settings.go b/pkg/database/settings.go index 883b87d3..fb22d226 100644 --- a/pkg/database/settings.go +++ b/pkg/database/settings.go @@ -11,8 +11,8 @@ const settingsTable = "settings" // SQL Queries to retrieve the system settings const settingsStmt = ` SELECT id, github_key, github_secret, github_domain, github_apiurl, bitbucket_key, bitbucket_secret, -smtp_server, smtp_port, smtp_address, smtp_username, smtp_password, hostname, scheme, open_invitations -FROM settings WHERE id = 1 +gitlab_domain, gitlab_apiurl, smtp_server, smtp_port, smtp_address, smtp_username, smtp_password, +hostname, scheme, open_invitations FROM settings WHERE id = 1 ` //var ( diff --git a/pkg/database/testing/testing.go b/pkg/database/testing/testing.go index d906f717..c252204c 100644 --- a/pkg/database/testing/testing.go +++ b/pkg/database/testing/testing.go @@ -32,26 +32,29 @@ func Setup() { // create dummy user data user1 := User{ - Password: "$2a$10$b8d63QsTL38vx7lj0HEHfOdbu1PCAg6Gfca74UavkXooIBx9YxopS", - Name: "Brad Rydzewski", - Email: "brad.rydzewski@gmail.com", - Gravatar: "8c58a0be77ee441bb8f8595b7f1b4e87", - Token: "123", - Admin: true} + Password: "$2a$10$b8d63QsTL38vx7lj0HEHfOdbu1PCAg6Gfca74UavkXooIBx9YxopS", + Name: "Brad Rydzewski", + Email: "brad.rydzewski@gmail.com", + Gravatar: "8c58a0be77ee441bb8f8595b7f1b4e87", + Token: "123", + GitlabToken: "123", + Admin: true} user2 := User{ - Password: "$2a$10$b8d63QsTL38vx7lj0HEHfOdbu1PCAg6Gfca74UavkXooIBx9YxopS", - Name: "Thomas Burke", - Email: "cavepig@gmail.com", - Gravatar: "c62f7126273f7fa786274274a5dec8ce", - Token: "456", - Admin: false} + Password: "$2a$10$b8d63QsTL38vx7lj0HEHfOdbu1PCAg6Gfca74UavkXooIBx9YxopS", + Name: "Thomas Burke", + Email: "cavepig@gmail.com", + Gravatar: "c62f7126273f7fa786274274a5dec8ce", + Token: "456", + GitlabToken: "456", + Admin: false} user3 := User{ - Password: "$2a$10$b8d63QsTL38vx7lj0HEHfOdbu1PCAg6Gfca74UavkXooIBx9YxopS", - Name: "Carlos Morales", - Email: "ytsejammer@gmail.com", - Gravatar: "c2180a539620d90d68eaeb848364f1c2", - Token: "789", - Admin: false} + Password: "$2a$10$b8d63QsTL38vx7lj0HEHfOdbu1PCAg6Gfca74UavkXooIBx9YxopS", + Name: "Carlos Morales", + Email: "ytsejammer@gmail.com", + Gravatar: "c2180a539620d90d68eaeb848364f1c2", + Token: "789", + GitlabToken: "789", + Admin: false} database.SaveUser(&user1) database.SaveUser(&user2) diff --git a/pkg/handler/gitlab.go b/pkg/handler/gitlab.go new file mode 100644 index 00000000..d38f6ca7 --- /dev/null +++ b/pkg/handler/gitlab.go @@ -0,0 +1,129 @@ +package handler + +import ( + "fmt" + "net/http" + + "github.com/drone/drone/pkg/database" + . "github.com/drone/drone/pkg/model" + "github.com/drone/drone/pkg/queue" + "github.com/plouc/go-gitlab-client" +) + +type GitlabHandler struct { + queue *queue.Queue + apiPath string +} + +func NewGitlabHandler(queue *queue.Queue) *GitlabHandler { + return &GitlabHandler{ + queue: queue, + apiPath: "/api/v3", + } +} + +func (g *GitlabHandler) Add(w http.ResponseWriter, r *http.Request, u *User) error { + settings := database.SettingsMust() + teams, err := database.ListTeams(u.ID) + if err != nil { + return err + } + data := struct { + User *User + Teams []*Team + Settings *Settings + }{u, teams, settings} + // if the user hasn't linked their GitLab account + // render a different template + if len(u.GitlabToken) == 0 { + return RenderTemplate(w, "gitlab_link.html", &data) + } + // otherwise display the template for adding + // a new GitLab repository. + return RenderTemplate(w, "gitlab_add.html", &data) +} + +func (g *GitlabHandler) Link(w http.ResponseWriter, r *http.Request, u *User) error { + var err error + return err +} + +func (g *GitlabHandler) Create(w http.ResponseWriter, r *http.Request, u *User) error { + teamName := r.FormValue("team") + owner := r.FormValue("owner") + name := r.FormValue("name") + + repo, err := g.newGitlabRepo(u, owner, name) + if err != nil { + return err + } + + if len(teamName) > 0 { + team, err := database.GetTeamSlug(teamName) + if err != nil { + return fmt.Errorf("Unable to find Team %s.", teamName) + } + + // user must be an admin member of the team + if ok, _ := database.IsMemberAdmin(u.ID, team.ID); !ok { + return fmt.Errorf("Invalid permission to access Team %s.", teamName) + } + repo.TeamID = team.ID + } + + // Save to the database + if err := database.SaveRepo(repo); err != nil { + return fmt.Errorf("Error saving repository to the database. %s", err) + } + + return RenderText(w, http.StatusText(http.StatusOK), http.StatusOK) +} + +func (g *GitlabHandler) newGitlabRepo(u *User, owner, name string) (*Repo, error) { + settings := database.SettingsMust() + gl := gogitlab.NewGitlab(settings.GitlabApiUrl, g.apiPath, u.GitlabToken) + + project, err := gl.Project(ns(owner, name)) + if err != nil { + return nil, err + } + + var cloneUrl string + if project.Public { + cloneUrl = project.HttpRepoUrl + } else { + cloneUrl = project.SshRepoUrl + } + + repo, err := NewRepo(settings.GitlabDomain, owner, name, ScmGit, cloneUrl) + if err != nil { + return nil, err + } + + repo.UserID = u.ID + repo.Private = !project.Public + if repo.Private { + // name the key + keyName := fmt.Sprintf("%s@%s", repo.Owner, settings.Domain) + + // TODO: (fudanchii) check if we already opted to use UserKey + + // create the github key, or update if one already exists + if err := gl.AddProjectDeployKey(ns(owner, name), keyName, repo.PublicKey); err != nil { + return nil, fmt.Errorf("Unable to add Public Key to your GitLab repository.") + } + } + + link := fmt.Sprintf("%s://%s/hook/gitlab?id=%s", settings.Scheme, settings.Domain, repo.Slug) + if err := gl.AddProjectHook(ns(owner, name), link, true, false, true); err != nil { + return nil, fmt.Errorf("Unable to add Hook to your GitLab repository.") + } + + return repo, err +} + +// ns namespaces user and repo. +// Returns user%2Frepo +func ns(user, repo string) string { + return fmt.Sprintf("%s%%252F%s", user, repo) +} diff --git a/pkg/handler/testing/gitlab_test.go b/pkg/handler/testing/gitlab_test.go new file mode 100644 index 00000000..aa4c623d --- /dev/null +++ b/pkg/handler/testing/gitlab_test.go @@ -0,0 +1,330 @@ +package testing + +import ( + "database/sql" + "fmt" + "net/http" + "net/http/httptest" + "net/url" + "testing" + + "github.com/drone/drone/pkg/database" + "github.com/drone/drone/pkg/handler" + "github.com/drone/drone/pkg/queue" + "github.com/drone/drone/pkg/model" + + dbtest "github.com/drone/drone/pkg/database/testing" + . "github.com/smartystreets/goconvey/convey" +) + +// Tests the ability to create GitHub repositories. +func Test_GitLabCreate(t *testing.T) { + // seed the database with values + SetupGitlabFixtures() + defer TeardownGitlabFixtures() + + q := &queue.Queue{} + gl := handler.NewGitlabHandler(q) + + // mock request + req := http.Request{} + req.Form = url.Values{} + + // get user that will add repositories + user, _ := database.GetUser(1) + settings := database.SettingsMust() + + Convey("Given request to setup gitlab repo", t, func() { + + Convey("When repository is public", func() { + req.Form.Set("owner", "example") + req.Form.Set("name", "public") + req.Form.Set("team", "") + res := httptest.NewRecorder() + err := gl.Create(res, &req, user) + repo, _ := database.GetRepoSlug(settings.GitlabDomain + "/example/public") + + Convey("The repository is created", func() { + So(err, ShouldBeNil) + So(repo, ShouldNotBeNil) + So(repo.ID, ShouldNotEqual, 0) + So(repo.Owner, ShouldEqual, "example") + So(repo.Name, ShouldEqual, "public") + So(repo.Host, ShouldEqual, settings.GitlabDomain) + So(repo.TeamID, ShouldEqual, 0) + So(repo.UserID, ShouldEqual, user.ID) + So(repo.Private, ShouldEqual, false) + So(repo.SCM, ShouldEqual, "git") + }) + Convey("The repository is public", func() { + So(repo.Private, ShouldEqual, false) + }) + }) + + Convey("When repository is private", func() { + req.Form.Set("owner", "example") + req.Form.Set("name", "private") + req.Form.Set("team", "") + res := httptest.NewRecorder() + err := gl.Create(res, &req, user) + repo, _ := database.GetRepoSlug(settings.GitlabDomain + "/example/private") + + Convey("The repository is created", func() { + So(err, ShouldBeNil) + So(repo, ShouldNotBeNil) + So(repo.ID, ShouldNotEqual, 0) + }) + Convey("The repository is private", func() { + So(repo.Private, ShouldEqual, true) + }) + }) + + Convey("When repository is not found", func() { + req.Form.Set("owner", "example") + req.Form.Set("name", "notfound") + req.Form.Set("team", "") + res := httptest.NewRecorder() + err := gl.Create(res, &req, user) + + Convey("The result is an error", func() { + So(err, ShouldNotBeNil) + So(err.Error(), ShouldEqual, "*Gitlab.buildAndExecRequest failed: 404 Not Found") + }) + + Convey("The repository is not created", func() { + _, err := database.GetRepoSlug("example/notfound") + So(err, ShouldNotBeNil) + So(err, ShouldEqual, sql.ErrNoRows) + }) + }) + + Convey("When repository hook is not writable", func() { + req.Form.Set("owner", "example") + req.Form.Set("name", "hookerr") + req.Form.Set("team", "") + res := httptest.NewRecorder() + err := gl.Create(res, &req, user) + + Convey("The result is an error", func() { + So(err, ShouldNotBeNil) + So(err.Error(), ShouldEqual, "Unable to add Hook to your GitLab repository.") + }) + + Convey("The repository is not created", func() { + _, err := database.GetRepoSlug("example/hookerr") + So(err, ShouldNotBeNil) + So(err, ShouldEqual, sql.ErrNoRows) + }) + }) + + Convey("When repository ssh key is not writable", func() { + req.Form.Set("owner", "example") + req.Form.Set("name", "keyerr") + req.Form.Set("team", "") + res := httptest.NewRecorder() + err := gl.Create(res, &req, user) + + Convey("The result is an error", func() { + So(err, ShouldNotBeNil) + So(err.Error(), ShouldEqual, "Unable to add Public Key to your GitLab repository.") + }) + + Convey("The repository is not created", func() { + _, err := database.GetRepoSlug("example/keyerr") + So(err, ShouldNotBeNil) + So(err, ShouldEqual, sql.ErrNoRows) + }) + }) + + Convey("When a team is provided", func() { + req.Form.Set("owner", "example") + req.Form.Set("name", "team") + req.Form.Set("team", "drone") + res := httptest.NewRecorder() + + // invoke handler + err := gl.Create(res, &req, user) + team, _ := database.GetTeamSlug("drone") + repo, _ := database.GetRepoSlug(settings.GitlabDomain + "/example/team") + + Convey("The repository is created", func() { + So(err, ShouldBeNil) + So(repo, ShouldNotBeNil) + So(repo.ID, ShouldNotEqual, 0) + }) + + Convey("The team should be set", func() { + So(repo.TeamID, ShouldEqual, team.ID) + }) + }) + + Convey("When a team is not found", func() { + req.Form.Set("owner", "example") + req.Form.Set("name", "public") + req.Form.Set("team", "faketeam") + res := httptest.NewRecorder() + err := gl.Create(res, &req, user) + + Convey("The result is an error", func() { + So(err, ShouldNotBeNil) + So(err.Error(), ShouldEqual, "Unable to find Team faketeam.") + }) + }) + + Convey("When a team is forbidden", func() { + req.Form.Set("owner", "example") + req.Form.Set("name", "public") + req.Form.Set("team", "golang") + res := httptest.NewRecorder() + err := gl.Create(res, &req, user) + + Convey("The result is an error", func() { + So(err, ShouldNotBeNil) + So(err.Error(), ShouldEqual, "Invalid permission to access Team golang.") + }) + }) + }) +} + +// this code should be refactored and centralized, but for now +// it is just proof-of-concepting a testing strategy, so we'll +// revisit later. + + +// server is a test HTTP server used to provide mock API responses. +var glServer *httptest.Server + + +func SetupGitlabFixtures() { + dbtest.Setup() + + // test server + mux := http.NewServeMux() + glServer = httptest.NewServer(mux) + url, _ := url.Parse(glServer.URL) + + // set database to use a localhost url for GitHub + settings := model.Settings{} + settings.GitlabApiUrl = url.String() // normall would be "https://api.github.com" + settings.GitlabDomain = url.Host // normally would be "github.com" + settings.Scheme = url.Scheme + settings.Domain = "localhost" + database.SaveSettings(&settings) + + // ----------------------------------------------------------------------------------- + // fixture to return a public repository and successfully + // create a commit hook. + + mux.HandleFunc("/api/v3/projects/example%2Fpublic", func(w http.ResponseWriter, r *http.Request) { + fmt.Fprint(w, `{ + "name": "public", + "path_with_namespace": "example/public", + "public": true + }`) + }) + + mux.HandleFunc("/api/v3/projects/example%2Fpublic/hooks", func(w http.ResponseWriter, r *http.Request) { + fmt.Fprintf(w, `{ + "url": "https://example.com/example/public/hooks/1", + "id": 1 + }`) + }) + + // ----------------------------------------------------------------------------------- + // fixture to return a private repository and successfully + // create a commit hook and ssh deploy key + + mux.HandleFunc("/api/v3/projects/example%2Fprivate", func(w http.ResponseWriter, r *http.Request) { + fmt.Fprint(w, `{ + "name": "private", + "path_with_namespace": "example/private", + "public": false + }`) + }) + + mux.HandleFunc("/api/v3/projects/example%2Fprivate/hooks", func(w http.ResponseWriter, r *http.Request) { + fmt.Fprintf(w, `{ + "url": "https://example.com/example/private/hooks/1", + "id": 1 + }`) + }) + + mux.HandleFunc("/api/v3/projects/example%2Fprivate/keys", func(w http.ResponseWriter, r *http.Request) { + fmt.Fprintf(w, `{ + "id": 1, + "key": "ssh-rsa AAA...", + "url": "https://api.github.com/user/keys/1", + "title": "octocat@octomac" + }`) + }) + + // ----------------------------------------------------------------------------------- + // fixture to return a not found when accessing a github repository. + + mux.HandleFunc("/api/v3/projects/example%2Fnotfound", func(w http.ResponseWriter, r *http.Request) { + http.NotFound(w, r) + }) + + // ----------------------------------------------------------------------------------- + // fixture to return a public repository and successfully + // create a commit hook. + + mux.HandleFunc("/api/v3/projects/example%2Fhookerr", func(w http.ResponseWriter, r *http.Request) { + fmt.Fprint(w, `{ + "name": "hookerr", + "path_with_namespace": "example/hookerr", + "public": true + }`) + }) + + mux.HandleFunc("/api/v3/projects/example%2Fhookerr/hooks", func(w http.ResponseWriter, r *http.Request) { + http.Error(w, "Forbidden", http.StatusForbidden) + }) + + // ----------------------------------------------------------------------------------- + // fixture to return a private repository and successfully + // create a commit hook and ssh deploy key + + mux.HandleFunc("/api/v3/projects/example%2Fkeyerr", func(w http.ResponseWriter, r *http.Request) { + fmt.Fprint(w, `{ + "name": "keyerr", + "path_with_namespace": "example/keyerr", + "public": false + }`) + }) + + mux.HandleFunc("/api/v3/projects/example%2Fkeyerr/hooks", func(w http.ResponseWriter, r *http.Request) { + fmt.Fprintf(w, `{ + "url": "https://api.github.com/api/v3/projects/example/keyerr/hooks/1", + "id": 1 + }`) + }) + + mux.HandleFunc("/api/v3/projects/example%2Fkeyerr/keys", func(w http.ResponseWriter, r *http.Request) { + http.Error(w, "Forbidden", http.StatusForbidden) + }) + + // ----------------------------------------------------------------------------------- + // fixture to return a public repository and successfully to + // test adding a team. + + mux.HandleFunc("/api/v3/projects/example%2Fteam", func(w http.ResponseWriter, r *http.Request) { + fmt.Fprint(w, `{ + "name": "team", + "path_with_namespace": "example/team", + "public": true + }`) + }) + + mux.HandleFunc("/api/v3/projects/example%2Fteam/hooks", func(w http.ResponseWriter, r *http.Request) { + fmt.Fprintf(w, `{ + "url": "https://api.github.com/api/v3/projects/example/team/hooks/1", + "id": 1 + }`) + }) +} + +func TeardownGitlabFixtures() { + dbtest.Teardown() + glServer.Close() +} diff --git a/pkg/model/settings.go b/pkg/model/settings.go index 978b289f..8bab931e 100644 --- a/pkg/model/settings.go +++ b/pkg/model/settings.go @@ -32,6 +32,10 @@ type Settings struct { BitbucketKey string `meddler:"bitbucket_key"` BitbucketSecret string `meddler:"bitbucket_secret"` + // GitLab Domain + GitlabDomain string `meddler:"gitlab_domain"` + GitlabApiUrl string `meddler:"gitlab_apiurl"` + // Domain of the server, eg drone.io Domain string `meddler:"hostname"` diff --git a/pkg/model/user.go b/pkg/model/user.go index 55bddb51..41a76d8c 100644 --- a/pkg/model/user.go +++ b/pkg/model/user.go @@ -41,6 +41,8 @@ type User struct { BitbucketLogin string `meddler:"bitbucket_login" json:"-"` BitbucketToken string `meddler:"bitbucket_token" json:"-"` BitbucketSecret string `meddler:"bitbucket_secret" json:"-"` + + GitlabToken string `meddler:"gitlab_token" json:"-"` } // Creates a new User from the given Name and Email. diff --git a/pkg/plugin/publish/publish.go b/pkg/plugin/publish/publish.go index 33a4dc43..9fd33603 100644 --- a/pkg/plugin/publish/publish.go +++ b/pkg/plugin/publish/publish.go @@ -8,7 +8,7 @@ import ( // for publishing build artifacts when // a Build has succeeded type Publish struct { - S3 *S3 `yaml:"s3,omitempty"` + S3 *S3 `yaml:"s3,omitempty"` Swift *Swift `yaml:"swift,omitempty"` } diff --git a/pkg/template/pages/github_add.html b/pkg/template/pages/github_add.html index f1c5c233..52326679 100644 --- a/pkg/template/pages/github_add.html +++ b/pkg/template/pages/github_add.html @@ -15,6 +15,7 @@ @@ -98,4 +99,4 @@ return false; } -{{ end }} \ No newline at end of file +{{ end }} diff --git a/pkg/template/pages/github_link.html b/pkg/template/pages/github_link.html index a59d0294..ebf04be6 100644 --- a/pkg/template/pages/github_link.html +++ b/pkg/template/pages/github_link.html @@ -15,6 +15,7 @@ @@ -28,4 +29,4 @@ {{ end }} -{{ define "script" }}{{ end }} \ No newline at end of file +{{ define "script" }}{{ end }} diff --git a/pkg/template/pages/gitlab_add.html b/pkg/template/pages/gitlab_add.html new file mode 100644 index 00000000..9c11953f --- /dev/null +++ b/pkg/template/pages/gitlab_add.html @@ -0,0 +1,102 @@ +{{ define "title" }}GitHub · Add Repository{{ end }} + +{{ define "content" }} +
+
+

+ Repository Setup + GitHub +

+
+
+ +
+
+ + +
+
+ Enter your repository details + Re-Link Account +
+
+ +
+
+ +
+ +
+
+
+
/
+
+
+ +
+ +
+
+
+
+
Select your Drone account
+
    +
  • + + + Me +
  • + {{ range .Teams }} +
  • + + + {{ .Name }} +
  • + {{ end }} +
+
+
+
+ + Cancel +
+
+
+
+
+{{ end }} + +{{ define "script" }} + +{{ end }} diff --git a/pkg/template/pages/gitlab_link.html b/pkg/template/pages/gitlab_link.html new file mode 100644 index 00000000..7eda96fc --- /dev/null +++ b/pkg/template/pages/gitlab_link.html @@ -0,0 +1,45 @@ +{{ define "title" }}GitLab · Add Repository{{ end }} + +{{ define "content" }} +
+
+

+ Repository Setup + GitLab +

+
+
+ +
+
+ + +
+
Link Your GitLab Account
+
+
+
+
+
+
+
+
+
+ + Cancel +
+
+ +
+
+
+ +{{ end }} + +{{ define "script" }}{{ end }} diff --git a/pkg/template/template.go b/pkg/template/template.go index 95fe3e85..634302b3 100644 --- a/pkg/template/template.go +++ b/pkg/template/template.go @@ -82,6 +82,8 @@ func init() { "admin_settings.html", "github_add.html", "github_link.html", + "gitlab_add.html", + "gitlab_link.html", } // extract the base template as a string From 15770e6237cb30bdae0a46e122b9cfaf1c29fd4e Mon Sep 17 00:00:00 2001 From: Nurahmadie Date: Sat, 29 Mar 2014 11:51:02 +0000 Subject: [PATCH 03/12] Add gitlab options add admin page. --- .../20140328201430_add_gitlab_columns.go | 9 +++++++-- pkg/database/users.go | 9 ++++++--- pkg/handler/admin.go | 11 ++++++++++ pkg/handler/auth.go | 4 ++-- pkg/handler/gitlab.go | 20 ++++++++++++++++--- pkg/handler/hooks.go | 2 +- pkg/handler/repos.go | 2 +- pkg/handler/testing/gitlab_test.go | 4 +--- pkg/template/pages/admin_settings.html | 7 +++++++ pkg/template/pages/bitbucket_add.html | 3 ++- pkg/template/pages/bitbucket_link.html | 3 ++- pkg/template/pages/github_add.html | 2 +- pkg/template/pages/github_link.html | 2 +- pkg/template/pages/gitlab_add.html | 12 +++++------ pkg/template/pages/gitlab_link.html | 4 +--- 15 files changed, 66 insertions(+), 28 deletions(-) diff --git a/pkg/database/migrate/20140328201430_add_gitlab_columns.go b/pkg/database/migrate/20140328201430_add_gitlab_columns.go index f0d6ee5c..f4701390 100644 --- a/pkg/database/migrate/20140328201430_add_gitlab_columns.go +++ b/pkg/database/migrate/20140328201430_add_gitlab_columns.go @@ -17,9 +17,14 @@ func (r *rev20140328201430) Up(mg *MigrationDriver) error { return err } - if _, err := mg.Tx.Exec(`update settings set gitlab_domain='gitlab.com', gitlab_apiurl='https://gitlab.com'`); err != nil { + if _, err := mg.Tx.Exec(`update settings set gitlab_domain=?`, "gitlab.com"); err != nil { return err } + + if _, err := mg.Tx.Exec(`update settings set gitlab_apiurl=?`, "https://gitlab.com"); err != nil { + return err + } + _, err := mg.AddColumn("users", mg.T.String("gitlab_token")) return err } @@ -29,6 +34,6 @@ func (r *rev20140328201430) Down(mg *MigrationDriver) error { if _, err := mg.DropColumns("users", "gitlab_token"); err != nil { return err } - _, err:= mg.DropColumns("settings", "gitlab_domain", "gitlab_apiurl") + _, err := mg.DropColumns("settings", "gitlab_domain", "gitlab_apiurl") return err } diff --git a/pkg/database/users.go b/pkg/database/users.go index 3bea9745..5e229e5b 100644 --- a/pkg/database/users.go +++ b/pkg/database/users.go @@ -13,21 +13,24 @@ const userTable = "users" // SQL Queries to retrieve a user by their unique database key const userFindIdStmt = ` SELECT id, email, password, token, name, gravatar, created, updated, admin, -github_login, github_token, bitbucket_login, bitbucket_token, bitbucket_secret +github_login, github_token, bitbucket_login, bitbucket_token, bitbucket_secret, +gitlab_token FROM users WHERE id = ? ` // SQL Queries to retrieve a user by their email address const userFindEmailStmt = ` SELECT id, email, password, token, name, gravatar, created, updated, admin, -github_login, github_token, bitbucket_login, bitbucket_token, bitbucket_secret +github_login, github_token, bitbucket_login, bitbucket_token, bitbucket_secret, +gitlab_token FROM users WHERE email = ? ` // SQL Queries to retrieve a list of all users const userStmt = ` SELECT id, email, password, token, name, gravatar, created, updated, admin, -github_login, github_token, bitbucket_login, bitbucket_token, bitbucket_secret +github_login, github_token, bitbucket_login, bitbucket_token, bitbucket_secret, +gitlab_token FROM users ORDER BY name ASC ` diff --git a/pkg/handler/admin.go b/pkg/handler/admin.go index ff21090f..858e615c 100644 --- a/pkg/handler/admin.go +++ b/pkg/handler/admin.go @@ -3,6 +3,7 @@ package handler import ( "fmt" "net/http" + "net/url" "strconv" "time" @@ -170,6 +171,14 @@ func AdminSettingsUpdate(w http.ResponseWriter, r *http.Request, u *User) error settings.GitHubDomain = r.FormValue("GitHubDomain") settings.GitHubApiUrl = r.FormValue("GitHubApiUrl") + // update gitlab settings + settings.GitlabApiUrl = r.FormValue("GitlabApiUrl") + glUrl, err := url.Parse(settings.GitlabApiUrl) + if err != nil { + return RenderError(w, err, http.StatusBadRequest) + } + settings.GitlabDomain = glUrl.Host + // update smtp settings settings.SmtpServer = r.FormValue("SmtpServer") settings.SmtpPort = r.FormValue("SmtpPort") @@ -252,6 +261,8 @@ func InstallPost(w http.ResponseWriter, r *http.Request) error { settings.Scheme = r.FormValue("Scheme") settings.GitHubApiUrl = "https://api.github.com" settings.GitHubDomain = "github.com" + settings.GitlabApiUrl = "https://gitlab.com" + settings.GitlabDomain = "gitlab.com" database.SaveSettings(&settings) // add the user to the session object diff --git a/pkg/handler/auth.go b/pkg/handler/auth.go index 14219a2f..0949c3b4 100644 --- a/pkg/handler/auth.go +++ b/pkg/handler/auth.go @@ -6,10 +6,10 @@ import ( "github.com/drone/drone/pkg/database" . "github.com/drone/drone/pkg/model" - "github.com/drone/go-github/github" - "github.com/drone/go-github/oauth2" "github.com/drone/go-bitbucket/bitbucket" "github.com/drone/go-bitbucket/oauth1" + "github.com/drone/go-github/github" + "github.com/drone/go-github/oauth2" ) // Create the User session. diff --git a/pkg/handler/gitlab.go b/pkg/handler/gitlab.go index d38f6ca7..d88bf99b 100644 --- a/pkg/handler/gitlab.go +++ b/pkg/handler/gitlab.go @@ -44,8 +44,22 @@ func (g *GitlabHandler) Add(w http.ResponseWriter, r *http.Request, u *User) err } func (g *GitlabHandler) Link(w http.ResponseWriter, r *http.Request, u *User) error { - var err error - return err + token := r.FormValue("token") + u.GitlabToken = token + + if err := database.SaveUser(u); err != nil { + return RenderError(w, err, http.StatusBadRequest) + } + + settings := database.SettingsMust() + gl := gogitlab.NewGitlab(settings.GitlabApiUrl, g.apiPath, u.GitlabToken) + _, err := gl.CurrentUser() + if err != nil { + return fmt.Errorf("Private Token is not valid: %q", err) + } + + http.Redirect(w, r, "/new/gitlab", http.StatusSeeOther) + return nil } func (g *GitlabHandler) Create(w http.ResponseWriter, r *http.Request, u *User) error { @@ -125,5 +139,5 @@ func (g *GitlabHandler) newGitlabRepo(u *User, owner, name string) (*Repo, error // ns namespaces user and repo. // Returns user%2Frepo func ns(user, repo string) string { - return fmt.Sprintf("%s%%252F%s", user, repo) + return fmt.Sprintf("%s%%2F%s", user, repo) } diff --git a/pkg/handler/hooks.go b/pkg/handler/hooks.go index 89b09886..57c0e017 100644 --- a/pkg/handler/hooks.go +++ b/pkg/handler/hooks.go @@ -10,8 +10,8 @@ import ( "github.com/drone/drone/pkg/database" . "github.com/drone/drone/pkg/model" "github.com/drone/drone/pkg/queue" - "github.com/drone/go-github/github" "github.com/drone/go-bitbucket/bitbucket" + "github.com/drone/go-github/github" ) type HookHandler struct { diff --git a/pkg/handler/repos.go b/pkg/handler/repos.go index 405f1928..2e489281 100644 --- a/pkg/handler/repos.go +++ b/pkg/handler/repos.go @@ -7,8 +7,8 @@ import ( "github.com/drone/drone/pkg/channel" "github.com/drone/drone/pkg/database" . "github.com/drone/drone/pkg/model" - "github.com/drone/go-github/github" "github.com/drone/go-bitbucket/bitbucket" + "github.com/drone/go-github/github" "launchpad.net/goyaml" ) diff --git a/pkg/handler/testing/gitlab_test.go b/pkg/handler/testing/gitlab_test.go index aa4c623d..b66bf980 100644 --- a/pkg/handler/testing/gitlab_test.go +++ b/pkg/handler/testing/gitlab_test.go @@ -10,8 +10,8 @@ import ( "github.com/drone/drone/pkg/database" "github.com/drone/drone/pkg/handler" - "github.com/drone/drone/pkg/queue" "github.com/drone/drone/pkg/model" + "github.com/drone/drone/pkg/queue" dbtest "github.com/drone/drone/pkg/database/testing" . "github.com/smartystreets/goconvey/convey" @@ -190,11 +190,9 @@ func Test_GitLabCreate(t *testing.T) { // it is just proof-of-concepting a testing strategy, so we'll // revisit later. - // server is a test HTTP server used to provide mock API responses. var glServer *httptest.Server - func SetupGitlabFixtures() { dbtest.Setup() diff --git a/pkg/template/pages/admin_settings.html b/pkg/template/pages/admin_settings.html index 5a1473d5..a6f825a7 100644 --- a/pkg/template/pages/admin_settings.html +++ b/pkg/template/pages/admin_settings.html @@ -50,6 +50,13 @@ +
+
GitLab Settings
+ +
+ +
+
Bitbucket OAuth Consumer Key and Secret.
diff --git a/pkg/template/pages/bitbucket_add.html b/pkg/template/pages/bitbucket_add.html index 80b5886a..7c37276d 100644 --- a/pkg/template/pages/bitbucket_add.html +++ b/pkg/template/pages/bitbucket_add.html @@ -15,7 +15,8 @@ diff --git a/pkg/template/pages/bitbucket_link.html b/pkg/template/pages/bitbucket_link.html index b323010b..7b1f920f 100644 --- a/pkg/template/pages/bitbucket_link.html +++ b/pkg/template/pages/bitbucket_link.html @@ -15,7 +15,8 @@ diff --git a/pkg/template/pages/github_add.html b/pkg/template/pages/github_add.html index 94c0f508..14d26006 100644 --- a/pkg/template/pages/github_add.html +++ b/pkg/template/pages/github_add.html @@ -15,8 +15,8 @@ diff --git a/pkg/template/pages/github_link.html b/pkg/template/pages/github_link.html index 6ed4a16b..27c59172 100644 --- a/pkg/template/pages/github_link.html +++ b/pkg/template/pages/github_link.html @@ -15,8 +15,8 @@ diff --git a/pkg/template/pages/gitlab_add.html b/pkg/template/pages/gitlab_add.html index 9c11953f..cf29eb45 100644 --- a/pkg/template/pages/gitlab_add.html +++ b/pkg/template/pages/gitlab_add.html @@ -1,11 +1,11 @@ -{{ define "title" }}GitHub · Add Repository{{ end }} +{{ define "title" }}GitLab · Add Repository{{ end }} {{ define "content" }}

Repository Setup - GitHub + GitLab

@@ -15,8 +15,8 @@ @@ -25,11 +25,11 @@ Enter your repository details Re-Link Account
-
- + +
- +
diff --git a/pkg/template/pages/gitlab_link.html b/pkg/template/pages/gitlab_link.html index 7eda96fc..917c5311 100644 --- a/pkg/template/pages/gitlab_link.html +++ b/pkg/template/pages/gitlab_link.html @@ -15,8 +15,8 @@ @@ -28,8 +28,6 @@
-
-
Cancel From e2a45df3b810700865face020ca4dc74291d0f7e Mon Sep 17 00:00:00 2001 From: Nurahmadie Date: Sun, 30 Mar 2014 16:26:53 +0000 Subject: [PATCH 04/12] Add initial hook handler --- cmd/droned/drone.go | 2 +- pkg/handler/gitlab.go | 109 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+), 1 deletion(-) diff --git a/cmd/droned/drone.go b/cmd/droned/drone.go index 26c0b747..5228e579 100644 --- a/cmd/droned/drone.go +++ b/cmd/droned/drone.go @@ -197,7 +197,7 @@ func setupHandlers() { m.Post("/hook/bitbucket.org", handler.ErrorHandler(hookHandler.HookBitbucket)) // handlers for GitLab post-commit hooks - //m.Post("/hook/gitlab", handler.ErrorHandler(gitlab.Hook)) + m.Post("/hook/gitlab", handler.ErrorHandler(gitlab.Hook)) // handlers for first-time installation m.Get("/install", handler.ErrorHandler(handler.Install)) diff --git a/pkg/handler/gitlab.go b/pkg/handler/gitlab.go index d88bf99b..9aa73b54 100644 --- a/pkg/handler/gitlab.go +++ b/pkg/handler/gitlab.go @@ -1,9 +1,12 @@ package handler import ( + "database/sql" "fmt" "net/http" + "time" + "github.com/drone/drone/pkg/build/script" "github.com/drone/drone/pkg/database" . "github.com/drone/drone/pkg/model" "github.com/drone/drone/pkg/queue" @@ -136,6 +139,112 @@ func (g *GitlabHandler) newGitlabRepo(u *User, owner, name string) (*Repo, error return repo, err } +func (g *GitlabHandler) Hook(w http.ResponseWriter, r *http.Request) error { + var payload []byte + n, err := r.Body.Read(payload) + if n == 0 { + return fmt.Errorf("Request Empty: %q", err) + } + parsed, err := gogitlab.ParseHook(payload) + if err != nil { + return err + } + if parsed.ObjectKind == "merge_request" { + return g.PullRequestHook(parsed) + } + + if len(parsed.After) == 0 { + return RenderText(w, http.StatusText(http.StatusNotFound), http.StatusNotFound) + } + + rID := r.FormValue("id") + repo, err := database.GetRepoSlug(rID) + if err != nil { + return RenderText(w, http.StatusText(http.StatusNotFound), http.StatusNotFound) + } + + user, err := database.GetUser(repo.UserID) + if err != nil { + return RenderText(w, http.StatusText(http.StatusNotFound), http.StatusNotFound) + } + + _, err = database.GetCommitHash(parsed.After, repo.ID) + if err != nil && err != sql.ErrNoRows { + println("commit already exists") + return RenderText(w, http.StatusText(http.StatusBadGateway), http.StatusBadGateway) + } + + commit := &Commit{} + commit.RepoID = repo.ID + commit.Branch = parsed.Branch() + commit.Hash = parsed.After + commit.Status = "Pending" + commit.Created = time.Now().UTC() + + head := parsed.Head() + commit.Message = head.Message + commit.Timestamp = head.Timestamp + if head.Author != nil { + commit.SetAuthor(head.Author.Email) + } else { + commit.SetAuthor(parsed.UserName) + } + + // get the github settings from the database + settings := database.SettingsMust() + + // get the drone.yml file from GitHub + client := gogitlab.NewGitlab(settings.GitlabApiUrl, g.apiPath, user.GitlabToken) + + content, err := client.RepoRawFile(ns(repo.Owner, repo.Name), commit.Hash, ".drone.yml") + if err != nil { + msg := "No .drone.yml was found in this repository. You need to add one.\n" + if err := saveFailedBuild(commit, msg); err != nil { + return RenderText(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) + } + return RenderText(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest) + } + + // parse the build script + buildscript, err := script.ParseBuild(content, repo.Params) + if err != nil { + msg := "Could not parse your .drone.yml file. It needs to be a valid drone yaml file.\n\n" + err.Error() + "\n" + if err := saveFailedBuild(commit, msg); err != nil { + return RenderText(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) + } + return RenderText(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest) + } + + // save the commit to the database + if err := database.SaveCommit(commit); err != nil { + return RenderText(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) + } + + // save the build to the database + build := &Build{} + build.Slug = "1" // TODO + build.CommitID = commit.ID + build.Created = time.Now().UTC() + build.Status = "Pending" + if err := database.SaveBuild(build); err != nil { + return RenderText(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) + } + + // notify websocket that a new build is pending + //realtime.CommitPending(repo.UserID, repo.TeamID, repo.ID, commit.ID, repo.Private) + //realtime.BuildPending(repo.UserID, repo.TeamID, repo.ID, commit.ID, build.ID, repo.Private) + + g.queue.Add(&queue.BuildTask{Repo: repo, Commit: commit, Build: build, Script: buildscript}) //Push(repo, commit, build, buildscript) + + // OK! + return RenderText(w, http.StatusText(http.StatusOK), http.StatusOK) + +} + +func (g *GitlabHandler) PullRequestHook(p *gogitlab.HookPayload) error { + return fmt.Errorf("Not implemented yet") +} + // ns namespaces user and repo. // Returns user%2Frepo func ns(user, repo string) string { From c295776b87c4bbd0ceefb1d60bbfc721288877a7 Mon Sep 17 00:00:00 2001 From: Nurahmadie Date: Sun, 30 Mar 2014 21:32:20 +0000 Subject: [PATCH 05/12] Set gitlab_token column, and use ioutil for r.Body --- pkg/database/migrate/20140328201430_add_gitlab_columns.go | 6 +++++- pkg/handler/gitlab.go | 7 ++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/pkg/database/migrate/20140328201430_add_gitlab_columns.go b/pkg/database/migrate/20140328201430_add_gitlab_columns.go index f4701390..d1948a09 100644 --- a/pkg/database/migrate/20140328201430_add_gitlab_columns.go +++ b/pkg/database/migrate/20140328201430_add_gitlab_columns.go @@ -25,7 +25,11 @@ func (r *rev20140328201430) Up(mg *MigrationDriver) error { return err } - _, err := mg.AddColumn("users", mg.T.String("gitlab_token")) + if _, err := mg.AddColumn("users", mg.T.String("gitlab_token")); err != nil { + return err + } + + _, err := mg.Tx.Exec(`update users set gitlab_token=?`, "") return err } diff --git a/pkg/handler/gitlab.go b/pkg/handler/gitlab.go index 9aa73b54..4419cac8 100644 --- a/pkg/handler/gitlab.go +++ b/pkg/handler/gitlab.go @@ -3,6 +3,7 @@ package handler import ( "database/sql" "fmt" + "io/ioutil" "net/http" "time" @@ -140,11 +141,7 @@ func (g *GitlabHandler) newGitlabRepo(u *User, owner, name string) (*Repo, error } func (g *GitlabHandler) Hook(w http.ResponseWriter, r *http.Request) error { - var payload []byte - n, err := r.Body.Read(payload) - if n == 0 { - return fmt.Errorf("Request Empty: %q", err) - } + payload, _ := ioutil.ReadAll(r.Body) parsed, err := gogitlab.ParseHook(payload) if err != nil { return err From 0d44a20c63bfb240d85c7c201c6f267a16ceb5f1 Mon Sep 17 00:00:00 2001 From: Nurahmadie Date: Mon, 31 Mar 2014 06:53:47 +0000 Subject: [PATCH 06/12] Fix gitlab account re-link --- cmd/droned/drone.go | 1 + pkg/handler/gitlab.go | 31 +++++++++++++++++++---------- pkg/template/pages/gitlab_add.html | 2 +- pkg/template/pages/gitlab_link.html | 2 +- 4 files changed, 23 insertions(+), 13 deletions(-) diff --git a/cmd/droned/drone.go b/cmd/droned/drone.go index 5228e579..ea7c357c 100644 --- a/cmd/droned/drone.go +++ b/cmd/droned/drone.go @@ -152,6 +152,7 @@ func setupHandlers() { // handler for linking GitLab account m.Post("/link/gitlab", handler.UserHandler(gitlab.Link)) + m.Get("/link/gitlab", handler.UserHandler(gitlab.ReLink)) // handlers for dashboard pages m.Get("/dashboard/team/:team", handler.UserHandler(handler.TeamShow)) diff --git a/pkg/handler/gitlab.go b/pkg/handler/gitlab.go index 4419cac8..d1096dbd 100644 --- a/pkg/handler/gitlab.go +++ b/pkg/handler/gitlab.go @@ -5,6 +5,7 @@ import ( "fmt" "io/ioutil" "net/http" + "strings" "time" "github.com/drone/drone/pkg/build/script" @@ -48,24 +49,32 @@ func (g *GitlabHandler) Add(w http.ResponseWriter, r *http.Request, u *User) err } func (g *GitlabHandler) Link(w http.ResponseWriter, r *http.Request, u *User) error { - token := r.FormValue("token") - u.GitlabToken = token + token := strings.Trim(r.FormValue("token"), " \n\t") - if err := database.SaveUser(u); err != nil { - return RenderError(w, err, http.StatusBadRequest) - } - - settings := database.SettingsMust() - gl := gogitlab.NewGitlab(settings.GitlabApiUrl, g.apiPath, u.GitlabToken) - _, err := gl.CurrentUser() - if err != nil { - return fmt.Errorf("Private Token is not valid: %q", err) + if len(u.GitlabToken) == 0 || token != u.GitlabToken && len(token) > 0 { + u.GitlabToken = token + settings := database.SettingsMust() + gl := gogitlab.NewGitlab(settings.GitlabApiUrl, g.apiPath, u.GitlabToken) + _, err := gl.CurrentUser() + if err != nil { + return fmt.Errorf("Private Token is not valid: %q", err) + } + if err := database.SaveUser(u); err != nil { + return RenderError(w, err, http.StatusBadRequest) + } } http.Redirect(w, r, "/new/gitlab", http.StatusSeeOther) return nil } +func (g *GitlabHandler) ReLink(w http.ResponseWriter, r *http.Request, u *User) error { + data := struct { + User *User + }{u} + return RenderTemplate(w, "gitlab_link.html", &data) +} + func (g *GitlabHandler) Create(w http.ResponseWriter, r *http.Request, u *User) error { teamName := r.FormValue("team") owner := r.FormValue("owner") diff --git a/pkg/template/pages/gitlab_add.html b/pkg/template/pages/gitlab_add.html index cf29eb45..da653284 100644 --- a/pkg/template/pages/gitlab_add.html +++ b/pkg/template/pages/gitlab_add.html @@ -23,7 +23,7 @@
Enter your repository details - Re-Link Account + Re-Link Account
diff --git a/pkg/template/pages/gitlab_link.html b/pkg/template/pages/gitlab_link.html index 917c5311..263a9bce 100644 --- a/pkg/template/pages/gitlab_link.html +++ b/pkg/template/pages/gitlab_link.html @@ -25,7 +25,7 @@
-
+
From 07071119ca8c7e8a431c27e2e8910a83f9eeaaf0 Mon Sep 17 00:00:00 2001 From: Nurahmadie Date: Mon, 31 Mar 2014 11:29:07 +0000 Subject: [PATCH 07/12] Use TrimSpace --- pkg/handler/gitlab.go | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/pkg/handler/gitlab.go b/pkg/handler/gitlab.go index d1096dbd..a2c85dba 100644 --- a/pkg/handler/gitlab.go +++ b/pkg/handler/gitlab.go @@ -49,7 +49,7 @@ func (g *GitlabHandler) Add(w http.ResponseWriter, r *http.Request, u *User) err } func (g *GitlabHandler) Link(w http.ResponseWriter, r *http.Request, u *User) error { - token := strings.Trim(r.FormValue("token"), " \n\t") + token := strings.TrimSpace(r.FormValue("token")) if len(u.GitlabToken) == 0 || token != u.GitlabToken && len(token) > 0 { u.GitlabToken = token @@ -156,7 +156,7 @@ func (g *GitlabHandler) Hook(w http.ResponseWriter, r *http.Request) error { return err } if parsed.ObjectKind == "merge_request" { - return g.PullRequestHook(parsed) + return g.PullRequestHook(w, parsed) } if len(parsed.After) == 0 { @@ -236,19 +236,15 @@ func (g *GitlabHandler) Hook(w http.ResponseWriter, r *http.Request) error { return RenderText(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) } - // notify websocket that a new build is pending - //realtime.CommitPending(repo.UserID, repo.TeamID, repo.ID, commit.ID, repo.Private) - //realtime.BuildPending(repo.UserID, repo.TeamID, repo.ID, commit.ID, build.ID, repo.Private) - - g.queue.Add(&queue.BuildTask{Repo: repo, Commit: commit, Build: build, Script: buildscript}) //Push(repo, commit, build, buildscript) + g.queue.Add(&queue.BuildTask{Repo: repo, Commit: commit, Build: build, Script: buildscript}) // OK! return RenderText(w, http.StatusText(http.StatusOK), http.StatusOK) } -func (g *GitlabHandler) PullRequestHook(p *gogitlab.HookPayload) error { - return fmt.Errorf("Not implemented yet") +func (g *GitlabHandler) PullRequestHook(w http.ResponseWriter, p *gogitlab.HookPayload) error { + return RenderText(w, http.StatusText(http.StatusOK), http.StatusOK) } // ns namespaces user and repo. From 6f10a57f4a56822d7ab218e765c15e614d4979d8 Mon Sep 17 00:00:00 2001 From: Nurahmadie Date: Wed, 2 Apr 2014 02:50:11 +0000 Subject: [PATCH 08/12] Stub for merge request hook handling. GitLab merge request hook payload doesn't provide any information regarding source commits. And since Drone currently doesn't support manual fetch from another remote upstream, merge request hook only supported for maerge request fro within the same repository. --- pkg/handler/gitlab.go | 95 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 93 insertions(+), 2 deletions(-) diff --git a/pkg/handler/gitlab.go b/pkg/handler/gitlab.go index a2c85dba..7a99d373 100644 --- a/pkg/handler/gitlab.go +++ b/pkg/handler/gitlab.go @@ -5,6 +5,7 @@ import ( "fmt" "io/ioutil" "net/http" + "strconv" "strings" "time" @@ -156,7 +157,8 @@ func (g *GitlabHandler) Hook(w http.ResponseWriter, r *http.Request) error { return err } if parsed.ObjectKind == "merge_request" { - return g.PullRequestHook(w, parsed) + fmt.Println(string(payload)) + return g.PullRequestHook(w, r) } if len(parsed.After) == 0 { @@ -243,7 +245,96 @@ func (g *GitlabHandler) Hook(w http.ResponseWriter, r *http.Request) error { } -func (g *GitlabHandler) PullRequestHook(w http.ResponseWriter, p *gogitlab.HookPayload) error { +func (g *GitlabHandler) PullRequestHook(w http.ResponseWriter, r *http.Request) error { + payload, _ := ioutil.ReadAll(r.Body) + p, err := gogitlab.ParseHook(payload) + if err != nil { + return err + } + + obj := p.ObjectAttributes + + // Gitlab may trigger multiple hooks upon updating merge requests status + // only build when it was just opened and the merge hasn't been checked yet. + if !(obj.State == "opened" && obj.MergeStatus == "unchecked") { + fmt.Printf("Ignore GitLab Merge Requests") + return RenderText(w, http.StatusText(http.StatusOK), http.StatusOK) + } + + repo, err := database.GetRepoSlug(r.FormValue("id")) + if err != nil { + return RenderText(w, http.StatusText(http.StatusNotFound), http.StatusNotFound) + } + + user, err := database.GetUser(repo.UserID) + if err != nil { + return RenderText(w, http.StatusText(http.StatusNotFound), http.StatusNotFound) + } + + settings := database.SettingsMust() + + client := gogitlab.NewGitlab(settings.GitlabApiUrl, g.apiPath, user.GitlabToken) + + // GitLab merge-requests hook doesn't include repository data. + // Have to fetch it manually + src, err := client.RepoBranch(strconv.Itoa(obj.SourceProjectId), obj.SourceBranch) + if err != nil { + return err + } + + _, err = database.GetCommitHash(src.Commit.Id, repo.ID) + if err != nil && err != sql.ErrNoRows { + println("commit already exists") + return RenderText(w, http.StatusText(http.StatusBadGateway), http.StatusBadGateway) + } + + commit := &Commit{} + commit.RepoID = repo.ID + commit.Branch = src.Name + commit.Hash = src.Commit.Id + commit.Status = "Pending" + commit.Created = time.Now().UTC() + + commit.Message = src.Commit.Message + commit.Timestamp = src.Commit.AuthoredDateRaw + commit.SetAuthor(src.Commit.Author.Email) + + content, err := client.RepoRawFile(strconv.Itoa(obj.SourceProjectId), commit.Hash, ".drone.yml") + if err != nil { + msg := "No .drone.yml was found in this repository. You need to add one.\n" + if err := saveFailedBuild(commit, msg); err != nil { + return RenderText(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) + } + return RenderText(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest) + } + + // parse the build script + buildscript, err := script.ParseBuild(content, repo.Params) + if err != nil { + msg := "Could not parse your .drone.yml file. It needs to be a valid drone yaml file.\n\n" + err.Error() + "\n" + if err := saveFailedBuild(commit, msg); err != nil { + return RenderText(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) + } + return RenderText(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest) + } + + // save the commit to the database + if err := database.SaveCommit(commit); err != nil { + return RenderText(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) + } + + // save the build to the database + build := &Build{} + build.Slug = "1" // TODO + build.CommitID = commit.ID + build.Created = time.Now().UTC() + build.Status = "Pending" + if err := database.SaveBuild(build); err != nil { + return RenderText(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) + } + + g.queue.Add(&queue.BuildTask{Repo: repo, Commit: commit, Build: build, Script: buildscript}) + return RenderText(w, http.StatusText(http.StatusOK), http.StatusOK) } From 1fca69dadedecb78b95776c82c599c8b633f8ac9 Mon Sep 17 00:00:00 2001 From: Nurahmadie Date: Thu, 3 Apr 2014 00:01:52 +0000 Subject: [PATCH 09/12] Refactor PullRequestHook signature. May parse hook payload only once. --- pkg/handler/gitlab.go | 69 ++++++++++++++++++------------------------- 1 file changed, 28 insertions(+), 41 deletions(-) diff --git a/pkg/handler/gitlab.go b/pkg/handler/gitlab.go index 7a99d373..b2339d59 100644 --- a/pkg/handler/gitlab.go +++ b/pkg/handler/gitlab.go @@ -151,20 +151,6 @@ func (g *GitlabHandler) newGitlabRepo(u *User, owner, name string) (*Repo, error } func (g *GitlabHandler) Hook(w http.ResponseWriter, r *http.Request) error { - payload, _ := ioutil.ReadAll(r.Body) - parsed, err := gogitlab.ParseHook(payload) - if err != nil { - return err - } - if parsed.ObjectKind == "merge_request" { - fmt.Println(string(payload)) - return g.PullRequestHook(w, r) - } - - if len(parsed.After) == 0 { - return RenderText(w, http.StatusText(http.StatusNotFound), http.StatusNotFound) - } - rID := r.FormValue("id") repo, err := database.GetRepoSlug(rID) if err != nil { @@ -176,6 +162,23 @@ func (g *GitlabHandler) Hook(w http.ResponseWriter, r *http.Request) error { return RenderText(w, http.StatusText(http.StatusNotFound), http.StatusNotFound) } + payload, _ := ioutil.ReadAll(r.Body) + parsed, err := gogitlab.ParseHook(payload) + if err != nil { + return err + } + if parsed.ObjectKind == "merge_request" { + fmt.Println(string(payload)) + if err := g.PullRequestHook(parsed, repo, user); err != nil { + return err + } + return RenderText(w, http.StatusText(http.StatusOK), http.StatusOK) + } + + if len(parsed.After) == 0 { + return RenderText(w, http.StatusText(http.StatusNotFound), http.StatusNotFound) + } + _, err = database.GetCommitHash(parsed.After, repo.ID) if err != nil && err != sql.ErrNoRows { println("commit already exists") @@ -245,30 +248,14 @@ func (g *GitlabHandler) Hook(w http.ResponseWriter, r *http.Request) error { } -func (g *GitlabHandler) PullRequestHook(w http.ResponseWriter, r *http.Request) error { - payload, _ := ioutil.ReadAll(r.Body) - p, err := gogitlab.ParseHook(payload) - if err != nil { - return err - } - +func (g *GitlabHandler) PullRequestHook(p *gogitlab.HookPayload, repo *Repo, user *User) error { obj := p.ObjectAttributes // Gitlab may trigger multiple hooks upon updating merge requests status // only build when it was just opened and the merge hasn't been checked yet. if !(obj.State == "opened" && obj.MergeStatus == "unchecked") { - fmt.Printf("Ignore GitLab Merge Requests") - return RenderText(w, http.StatusText(http.StatusOK), http.StatusOK) - } - - repo, err := database.GetRepoSlug(r.FormValue("id")) - if err != nil { - return RenderText(w, http.StatusText(http.StatusNotFound), http.StatusNotFound) - } - - user, err := database.GetUser(repo.UserID) - if err != nil { - return RenderText(w, http.StatusText(http.StatusNotFound), http.StatusNotFound) + println("Ignore GitLab Merge Requests") + return nil } settings := database.SettingsMust() @@ -285,7 +272,7 @@ func (g *GitlabHandler) PullRequestHook(w http.ResponseWriter, r *http.Request) _, err = database.GetCommitHash(src.Commit.Id, repo.ID) if err != nil && err != sql.ErrNoRows { println("commit already exists") - return RenderText(w, http.StatusText(http.StatusBadGateway), http.StatusBadGateway) + return err } commit := &Commit{} @@ -303,9 +290,9 @@ func (g *GitlabHandler) PullRequestHook(w http.ResponseWriter, r *http.Request) if err != nil { msg := "No .drone.yml was found in this repository. You need to add one.\n" if err := saveFailedBuild(commit, msg); err != nil { - return RenderText(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) + return fmt.Errorf("Failed to save build: %q", err) } - return RenderText(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest) + return fmt.Errorf("Error to fetch build script: %q", err) } // parse the build script @@ -313,14 +300,14 @@ func (g *GitlabHandler) PullRequestHook(w http.ResponseWriter, r *http.Request) if err != nil { msg := "Could not parse your .drone.yml file. It needs to be a valid drone yaml file.\n\n" + err.Error() + "\n" if err := saveFailedBuild(commit, msg); err != nil { - return RenderText(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) + return fmt.Errorf("Failed to save build: %q", err) } - return RenderText(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest) + return fmt.Errorf("Failed to parse build script: %q", err) } // save the commit to the database if err := database.SaveCommit(commit); err != nil { - return RenderText(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) + return fmt.Errorf("Failed to save commit: %q", err) } // save the build to the database @@ -330,12 +317,12 @@ func (g *GitlabHandler) PullRequestHook(w http.ResponseWriter, r *http.Request) build.Created = time.Now().UTC() build.Status = "Pending" if err := database.SaveBuild(build); err != nil { - return RenderText(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) + return fmt.Errorf("Failed to save build: %q", err) } g.queue.Add(&queue.BuildTask{Repo: repo, Commit: commit, Build: build, Script: buildscript}) - return RenderText(w, http.StatusText(http.StatusOK), http.StatusOK) + return nil } // ns namespaces user and repo. From f17101be0dc8439c7ad51eef40534b10080865ea Mon Sep 17 00:00:00 2001 From: Nurahmadie Date: Thu, 3 Apr 2014 17:39:37 +0000 Subject: [PATCH 10/12] Set commit.PullRequest for PullRequestHook --- pkg/handler/gitlab.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pkg/handler/gitlab.go b/pkg/handler/gitlab.go index b2339d59..f22c9d88 100644 --- a/pkg/handler/gitlab.go +++ b/pkg/handler/gitlab.go @@ -181,7 +181,7 @@ func (g *GitlabHandler) Hook(w http.ResponseWriter, r *http.Request) error { _, err = database.GetCommitHash(parsed.After, repo.ID) if err != nil && err != sql.ErrNoRows { - println("commit already exists") + fmt.Println("commit already exists") return RenderText(w, http.StatusText(http.StatusBadGateway), http.StatusBadGateway) } @@ -254,7 +254,7 @@ func (g *GitlabHandler) PullRequestHook(p *gogitlab.HookPayload, repo *Repo, use // Gitlab may trigger multiple hooks upon updating merge requests status // only build when it was just opened and the merge hasn't been checked yet. if !(obj.State == "opened" && obj.MergeStatus == "unchecked") { - println("Ignore GitLab Merge Requests") + fmt.Println("Ignore GitLab Merge Requests") return nil } @@ -271,7 +271,7 @@ func (g *GitlabHandler) PullRequestHook(p *gogitlab.HookPayload, repo *Repo, use _, err = database.GetCommitHash(src.Commit.Id, repo.ID) if err != nil && err != sql.ErrNoRows { - println("commit already exists") + fmt.Println("commit already exists") return err } @@ -281,6 +281,7 @@ func (g *GitlabHandler) PullRequestHook(p *gogitlab.HookPayload, repo *Repo, use commit.Hash = src.Commit.Id commit.Status = "Pending" commit.Created = time.Now().UTC() + commit.PullRequest = strconv.Itoa(obj.IId) commit.Message = src.Commit.Message commit.Timestamp = src.Commit.AuthoredDateRaw From fe75126fe15f1b72506688838e9b733913028b18 Mon Sep 17 00:00:00 2001 From: Nurahmadie Date: Thu, 3 Apr 2014 20:20:16 +0000 Subject: [PATCH 11/12] Fix tests --- pkg/handler/testing/gitlab_test.go | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/pkg/handler/testing/gitlab_test.go b/pkg/handler/testing/gitlab_test.go index b66bf980..77fca680 100644 --- a/pkg/handler/testing/gitlab_test.go +++ b/pkg/handler/testing/gitlab_test.go @@ -88,7 +88,7 @@ func Test_GitLabCreate(t *testing.T) { Convey("The result is an error", func() { So(err, ShouldNotBeNil) - So(err.Error(), ShouldEqual, "*Gitlab.buildAndExecRequest failed: 404 Not Found") + So(err.Error(), ShouldStartWith, "*Gitlab.buildAndExecRequestRaw") }) Convey("The repository is not created", func() { @@ -213,7 +213,7 @@ func SetupGitlabFixtures() { // fixture to return a public repository and successfully // create a commit hook. - mux.HandleFunc("/api/v3/projects/example%2Fpublic", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/api/v3/projects/example/public", func(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, `{ "name": "public", "path_with_namespace": "example/public", @@ -221,7 +221,7 @@ func SetupGitlabFixtures() { }`) }) - mux.HandleFunc("/api/v3/projects/example%2Fpublic/hooks", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/api/v3/projects/example/public/hooks", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, `{ "url": "https://example.com/example/public/hooks/1", "id": 1 @@ -232,7 +232,7 @@ func SetupGitlabFixtures() { // fixture to return a private repository and successfully // create a commit hook and ssh deploy key - mux.HandleFunc("/api/v3/projects/example%2Fprivate", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/api/v3/projects/example/private", func(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, `{ "name": "private", "path_with_namespace": "example/private", @@ -240,14 +240,14 @@ func SetupGitlabFixtures() { }`) }) - mux.HandleFunc("/api/v3/projects/example%2Fprivate/hooks", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/api/v3/projects/example/private/hooks", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, `{ "url": "https://example.com/example/private/hooks/1", "id": 1 }`) }) - mux.HandleFunc("/api/v3/projects/example%2Fprivate/keys", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/api/v3/projects/example/private/keys", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, `{ "id": 1, "key": "ssh-rsa AAA...", @@ -259,7 +259,7 @@ func SetupGitlabFixtures() { // ----------------------------------------------------------------------------------- // fixture to return a not found when accessing a github repository. - mux.HandleFunc("/api/v3/projects/example%2Fnotfound", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/api/v3/projects/example/notfound", func(w http.ResponseWriter, r *http.Request) { http.NotFound(w, r) }) @@ -267,7 +267,7 @@ func SetupGitlabFixtures() { // fixture to return a public repository and successfully // create a commit hook. - mux.HandleFunc("/api/v3/projects/example%2Fhookerr", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/api/v3/projects/example/hookerr", func(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, `{ "name": "hookerr", "path_with_namespace": "example/hookerr", @@ -275,7 +275,7 @@ func SetupGitlabFixtures() { }`) }) - mux.HandleFunc("/api/v3/projects/example%2Fhookerr/hooks", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/api/v3/projects/example/hookerr/hooks", func(w http.ResponseWriter, r *http.Request) { http.Error(w, "Forbidden", http.StatusForbidden) }) @@ -283,7 +283,7 @@ func SetupGitlabFixtures() { // fixture to return a private repository and successfully // create a commit hook and ssh deploy key - mux.HandleFunc("/api/v3/projects/example%2Fkeyerr", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/api/v3/projects/example/keyerr", func(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, `{ "name": "keyerr", "path_with_namespace": "example/keyerr", @@ -291,14 +291,14 @@ func SetupGitlabFixtures() { }`) }) - mux.HandleFunc("/api/v3/projects/example%2Fkeyerr/hooks", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/api/v3/projects/example/keyerr/hooks", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, `{ "url": "https://api.github.com/api/v3/projects/example/keyerr/hooks/1", "id": 1 }`) }) - mux.HandleFunc("/api/v3/projects/example%2Fkeyerr/keys", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/api/v3/projects/example/keyerr/keys", func(w http.ResponseWriter, r *http.Request) { http.Error(w, "Forbidden", http.StatusForbidden) }) @@ -306,7 +306,7 @@ func SetupGitlabFixtures() { // fixture to return a public repository and successfully to // test adding a team. - mux.HandleFunc("/api/v3/projects/example%2Fteam", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/api/v3/projects/example/team", func(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, `{ "name": "team", "path_with_namespace": "example/team", @@ -314,7 +314,7 @@ func SetupGitlabFixtures() { }`) }) - mux.HandleFunc("/api/v3/projects/example%2Fteam/hooks", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/api/v3/projects/example/team/hooks", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, `{ "url": "https://api.github.com/api/v3/projects/example/team/hooks/1", "id": 1 From 5724298c6bd3c441e6cd4155ac188eba71fe2943 Mon Sep 17 00:00:00 2001 From: Nurahmadie Date: Fri, 4 Apr 2014 01:28:20 +0000 Subject: [PATCH 12/12] A workaround to use fudanchii/raw-request branch without changing the import path. At least until https://github.com/plouc/go-gitlab-client/pull/8 accepted or Drone officially fork it to `drone/go-gitlab` or when we have package management which can do something like this: gom 'github.com/plouc/go-gitlab-client', :github => 'fudanchii/go-gitlab-client', :branch => 'raw-request' --- Makefile | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 4548d116..bfe9d94c 100644 --- a/Makefile +++ b/Makefile @@ -22,7 +22,7 @@ PKGS := $(addprefix github.com/drone/drone/pkg/,$(PKGS)) all: embed build -deps: +deps: go-gitlab-client [ -d $$GOPATH/src/code.google.com/p/go ] || hg clone -u default https://code.google.com/p/go $$GOPATH/src/code.google.com/p/go [ -d $$GOPATH/src/github.com/dotcloud/docker ] || git clone git://github.com/dotcloud/docker $$GOPATH/src/github.com/dotcloud/docker go get code.google.com/p/go.crypto/bcrypt @@ -42,7 +42,6 @@ deps: #go get github.com/dotcloud/docker/pkg/term go get github.com/drone/go-github/github go get github.com/drone/go-bitbucket/bitbucket - go get github.com/plouc/go-gitlab-client go get github.com/GeertJohan/go.rice go get github.com/GeertJohan/go.rice/rice go get github.com/go-sql-driver/mysql @@ -98,3 +97,7 @@ dpkg: run: bin/droned --port=":8080" --datasource="drone.sqlite" + +go-gitlab-client: + rm -rf $$GOPATH/src/github.com/plouc/go-gitlab-client + git clone -b raw-request https://github.com/fudanchii/go-gitlab-client $$GOPATH/src/github.com/plouc/go-gitlab-client