From 13dc52516915f9d061f0649c62e1f82186423d4c Mon Sep 17 00:00:00 2001 From: Chengwei Yang Date: Mon, 24 Aug 2015 18:35:51 +0800 Subject: [PATCH 01/18] doc: clerify install document about start/stop/restart drone Signed-off-by: Chengwei Yang --- doc/setup/install.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/doc/setup/install.md b/doc/setup/install.md index 1f7bb220e..fc140d45e 100644 --- a/doc/setup/install.md +++ b/doc/setup/install.md @@ -33,6 +33,8 @@ Here are some of the Docker options, explained: Drone uses environment variables for runtime settings and configuration, such as GitHub, GitLab, plugins and more. These settings can be provided to Docker using an `--env-file` as seen above. +Once you have your drone container created, then you can start/stop/restart it in below ways. + ## Starting, Stopping, Logs Commands to start, stop and restart Drone: @@ -60,12 +62,8 @@ start on filesystem and started docker stop on runlevel [!2345] respawn -pre-start script - /usr/bin/docker rm -f drone -end script - script - /usr/bin/docker run -a drone + /usr/bin/docker start -a drone end script ``` From 57b2392366280db0797df0f2d74a92c923512538 Mon Sep 17 00:00:00 2001 From: Chengwei Yang Date: Tue, 25 Aug 2015 15:23:27 +0800 Subject: [PATCH 02/18] doc: Fix typo ListAndServerTLS -> ListenAndServeTLS Signed-off-by: Chengwei Yang --- doc/setup/server.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/setup/server.md b/doc/setup/server.md index ddb5b0466..d685271cb 100644 --- a/doc/setup/server.md +++ b/doc/setup/server.md @@ -18,7 +18,7 @@ SERVER_ADDR=":80" ## Server SSL -Drone uses the `ListAndServerTLS` function in the Go standard library to accept `https` connections. If you experience any issues configuring `https` please contact us on [gitter](https://gitter.im/drone/drone). Please do not log an issue saying `https` is broken in Drone (it isn't). +Drone uses the `ListenAndServeTLS` function in the Go standard library to accept `https` connections. If you experience any issues configuring `https` please contact us on [gitter](https://gitter.im/drone/drone). Please do not log an issue saying `https` is broken in Drone (it isn't). This example accepts `HTTPS` connections: From ceacbdd4fe919d7df8a2ff7cd1ab9ac7e65f87c4 Mon Sep 17 00:00:00 2001 From: Chengwei Yang Date: Wed, 26 Aug 2015 16:49:08 +0800 Subject: [PATCH 03/18] Fix default docker host configuration Signed-off-by: Chengwei Yang --- cmd/drone-server/drone.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/drone-server/drone.go b/cmd/drone-server/drone.go index 5c3606a8d..737fa78ba 100644 --- a/cmd/drone-server/drone.go +++ b/cmd/drone-server/drone.go @@ -72,7 +72,7 @@ var conf = struct { func main() { - flag.StringVar(&conf.docker.host, "docker-host", "unix:///var/run/docker/docker.sock", "") + flag.StringVar(&conf.docker.host, "docker-host", "unix:///var/run/docker.sock", "") flag.StringVar(&conf.docker.cert, "docker-cert", "", "") flag.StringVar(&conf.docker.key, "docker-key", "", "") flag.StringVar(&conf.docker.ca, "docker-ca", "", "") From 2577b6cda26d0938da9ee932b4c550f7614f3df2 Mon Sep 17 00:00:00 2001 From: Thomas Boerger Date: Thu, 27 Aug 2015 09:44:46 +0200 Subject: [PATCH 04/18] Integrated logout button into the UI --- .../static/scripts/controllers/users.js | 21 +++++++++++++++---- cmd/drone-server/static/scripts/drone.js | 11 ++++++++++ .../static/scripts/views/layout.html | 3 ++- 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/cmd/drone-server/static/scripts/controllers/users.js b/cmd/drone-server/static/scripts/controllers/users.js index d0849b3df..8a25254bc 100644 --- a/cmd/drone-server/static/scripts/controllers/users.js +++ b/cmd/drone-server/static/scripts/controllers/users.js @@ -6,10 +6,10 @@ $scope.user = payload.data; }); - $scope.number = $stateParams.number || undefined; - $scope.owner = $stateParams.owner || undefined; - $scope.name = $stateParams.name || undefined; - $scope.full_name = $scope.owner + '/' + $scope.name; + $scope.number = $stateParams.number || undefined; + $scope.owner = $stateParams.owner || undefined; + $scope.name = $stateParams.name || undefined; + $scope.full_name = $scope.owner + '/' + $scope.name; } function UserLoginCtrl($scope, $window) { @@ -18,6 +18,18 @@ $scope.error = $window.location.hash.substr(7); } + function UserLogoutCtrl($scope, $window, $state) { + // Remove login information from the local + // storage and redirect to login page + if (localStorage.hasOwnProperty("access_token")) { + localStorage.removeItem("access_token"); + } + + $state.go("login", {}, { + location: "replace" + }); + } + /** * UserCtrl is responsible for managing user settings. */ @@ -115,6 +127,7 @@ .module('drone') .controller('UserHeaderCtrl', UserHeaderCtrl) .controller('UserLoginCtrl', UserLoginCtrl) + .controller('UserLogoutCtrl', UserLogoutCtrl) .controller('UserCtrl', UserCtrl) .controller('UsersCtrl', UsersCtrl); })(); diff --git a/cmd/drone-server/static/scripts/drone.js b/cmd/drone-server/static/scripts/drone.js index 1e9a796b5..09969f40c 100644 --- a/cmd/drone-server/static/scripts/drone.js +++ b/cmd/drone-server/static/scripts/drone.js @@ -89,6 +89,17 @@ }, title: 'Login' }) + .state('logout', { + url: '/logout', + views: { + 'layout': { + templateUrl: '/static/scripts/views/login.html', + controller: 'UserLogoutCtrl', + resolve: resolveUser + } + }, + title: 'Logout' + }) .state('app.profile', { url: '/profile', views: { diff --git a/cmd/drone-server/static/scripts/views/layout.html b/cmd/drone-server/static/scripts/views/layout.html index b57bccb8e..ced66f796 100644 --- a/cmd/drone-server/static/scripts/views/layout.html +++ b/cmd/drone-server/static/scripts/views/layout.html @@ -15,6 +15,7 @@ @@ -71,4 +72,4 @@ header li { .dropdown li > a:hover { background:#F5F7F9; } - \ No newline at end of file + From 7e21566af3f11966e319266f600e3397b24be0e6 Mon Sep 17 00:00:00 2001 From: Thomas Boerger Date: Thu, 27 Aug 2015 10:12:29 +0200 Subject: [PATCH 05/18] Integrated clean task --- make.go | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/make.go b/make.go index 3eea7696b..f85bd28fa 100644 --- a/make.go +++ b/make.go @@ -34,6 +34,7 @@ var steps = map[string]step{ "build": build, "test": test, "image": image, + "clean": clean, } func main() { @@ -170,6 +171,47 @@ func image() error { return nil } +func clean() error { + err := filepath.Walk(".", func(path string, f os.FileInfo, err error) error { + suffixes := []string{ + ".out", + "_bindata.go", + } + + for _, suffix := range suffixes { + if strings.HasSuffix(path, suffix) { + if err := os.Remove(path); err != nil { + return err + } + } + } + + return nil + }) + + if err != nil { + return err + } + + files := []string{ + "bin/drone", + "bin/drone-agent", + "bin/drone-build", + } + + for _, file := range files { + if _, err := os.Stat(file); err != nil { + continue + } + + if err := os.Remove(file); err != nil { + return err + } + } + + return nil +} + // trace is a helper fucntion that writes a command // to stdout similar to bash +x func trace(args []string) { From c2346e3275efe46f1c4dfa13560a69600eb9e1e0 Mon Sep 17 00:00:00 2001 From: Thomas Boerger Date: Thu, 27 Aug 2015 10:53:12 +0200 Subject: [PATCH 06/18] Integrated styles task --- .gitignore | 1 + make.go | 39 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 35e5df54d..63905c71f 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,7 @@ drone.sublime-workspace *.rice-box.go *.db *.txt +*.min.css *.min.js *_bindata.go *.toml diff --git a/make.go b/make.go index f85bd28fa..2383e17d6 100644 --- a/make.go +++ b/make.go @@ -9,6 +9,7 @@ package main import ( "fmt" + "io/ioutil" "os" "os/exec" "path/filepath" @@ -67,10 +68,42 @@ func scripts() error { return nil } -// styles step concatinates the css files. +// styles step concatinates the stylesheet files. func styles() error { - // concatinate styles - // inject css variables? + files := []string{ + "cmd/drone-server/static/styles/reset.css", + "cmd/drone-server/static/styles/fonts.css", + "cmd/drone-server/static/styles/alert.css", + "cmd/drone-server/static/styles/blankslate.css", + "cmd/drone-server/static/styles/list.css", + "cmd/drone-server/static/styles/label.css", + "cmd/drone-server/static/styles/range.css", + "cmd/drone-server/static/styles/switch.css", + "cmd/drone-server/static/styles/main.css", + } + + f, err := os.OpenFile( + "cmd/drone-server/static/styles/drone.min.css", + os.O_CREATE|os.O_RDWR|os.O_TRUNC, + 0660) + + defer f.Close() + + if err != nil { + fmt.Println("Failed to open output file") + return err + } + + for _, input := range files { + content, err := ioutil.ReadFile(input) + + if err != nil { + return err + } + + f.Write(content) + } + return nil } From ab44a65e8143452b584bf8fd030603360182c594 Mon Sep 17 00:00:00 2001 From: Thomas Boerger Date: Thu, 27 Aug 2015 10:57:17 +0200 Subject: [PATCH 07/18] Integrated scripts task --- make.go | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/make.go b/make.go index 2383e17d6..c9a4cd355 100644 --- a/make.go +++ b/make.go @@ -64,7 +64,45 @@ func embed() error { // scripts step concatinates all javascript files. func scripts() error { - // concatinate scripts + files := []string{ + "cmd/drone-server/static/scripts/term.js", + "cmd/drone-server/static/scripts/drone.js", + "cmd/drone-server/static/scripts/controllers/repos.js", + "cmd/drone-server/static/scripts/controllers/builds.js", + "cmd/drone-server/static/scripts/controllers/users.js", + "cmd/drone-server/static/scripts/services/repos.js", + "cmd/drone-server/static/scripts/services/builds.js", + "cmd/drone-server/static/scripts/services/users.js", + "cmd/drone-server/static/scripts/services/logs.js", + "cmd/drone-server/static/scripts/services/tokens.js", + "cmd/drone-server/static/scripts/services/feed.js", + "cmd/drone-server/static/scripts/filters/filter.js", + "cmd/drone-server/static/scripts/filters/gravatar.js", + "cmd/drone-server/static/scripts/filters/time.js", + } + + f, err := os.OpenFile( + "cmd/drone-server/static/scripts/drone.min.js", + os.O_CREATE|os.O_RDWR|os.O_TRUNC, + 0660) + + defer f.Close() + + if err != nil { + fmt.Println("Failed to open output file") + return err + } + + for _, input := range files { + content, err := ioutil.ReadFile(input) + + if err != nil { + return err + } + + f.Write(content) + } + return nil } From d6a546a309e2105d66d58027b907f8960f0bb160 Mon Sep 17 00:00:00 2001 From: Thomas Boerger Date: Thu, 27 Aug 2015 11:03:03 +0200 Subject: [PATCH 08/18] Removed in go implemented tasks from Makefile --- Makefile | 36 +----------------------------------- 1 file changed, 1 insertion(+), 35 deletions(-) diff --git a/Makefile b/Makefile index b2122286a..58694db59 100644 --- a/Makefile +++ b/Makefile @@ -3,16 +3,6 @@ SHA := $(shell git rev-parse --short HEAD) VERSION := 0.4.0-alpha -all: concat bindata build - -deps: - go get github.com/jteeuwen/go-bindata/... - -test: - go vet github.com/drone/drone/pkg/... - go vet github.com/drone/drone/cmd/... - go test -cover -short github.com/drone/drone/pkg/... - # Execute the database test suite against mysql 5.5 # # You can launch a mysql container locally for testing: @@ -22,38 +12,14 @@ test_mysql: TEST_DRIVER="mysql" TEST_DATASOURCE="root@tcp(127.0.0.1:3306)/test" go test -short github.com/drone/drone/pkg/store/builtin mysql -P 3306 --protocol=tcp -u root -e 'drop database test;' -build: - go build -o bin/drone -ldflags "-X main.revision=$(SHA) -X main.version=$(VERSION).$(SHA)" github.com/drone/drone/cmd/drone-server - go build -o bin/drone-agent -ldflags "-X main.revision=$(SHA) -X main.version=$(VERSION).$(SHA)" github.com/drone/drone/cmd/drone-agent - run: - bin/drone-server --debug - -clean: - find . -name "*.out" -delete - find . -name "*_bindata.go" -delete - rm -f bin/drone* - -concat: - cat cmd/drone-server/static/scripts/drone.js \ - cmd/drone-server/static/scripts/services/*.js \ - cmd/drone-server/static/scripts/filters/*.js \ - cmd/drone-server/static/scripts/controllers/*.js \ - cmd/drone-server/static/scripts/term.js > cmd/drone-server/static/scripts/drone.min.js + bin/drone --debug # installs the drone binaries into bin install: install -t /usr/local/bin bin/drone install -t /usr/local/bin bin/drone-agent -# embeds all the static files directly -# into the drone binary file -bindata: - $$GOPATH/bin/go-bindata -o="cmd/drone-server/drone_bindata.go" cmd/drone-server/static/... - -bindata_debug: - $$GOPATH/bin/go-bindata --debug -o="cmd/drone-server/drone_bindata.go" cmd/drone-server/static/... - docker: docker build --file=cmd/drone-build/Dockerfile.alpine --rm=true -t drone/drone-build . From 075fd5e52259c250b072858f9c3980182838d210 Mon Sep 17 00:00:00 2001 From: Thomas Boerger Date: Thu, 27 Aug 2015 11:03:23 +0200 Subject: [PATCH 09/18] Execute the new go make tasks --- .drone.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.drone.yml b/.drone.yml index 87ca16e3c..b1bd7bd56 100644 --- a/.drone.yml +++ b/.drone.yml @@ -9,9 +9,12 @@ script: - go get golang.org/x/tools/cmd/cover - go get golang.org/x/tools/cmd/vet - go get -u github.com/jteeuwen/go-bindata/... - - make bindata deps + + - go run make.go bindata - go run make.go build - - go run make.go vet test + - go run make.go vet + - go run make.go test + - make dist notify: From fd98e26575836729b1a8a2d03126b65404ce2174 Mon Sep 17 00:00:00 2001 From: Kirill Zaitsev Date: Sat, 22 Aug 2015 06:32:22 +0300 Subject: [PATCH 10/18] GitLab service interface --- Godeps/Godeps.json | 2 +- .../Bugagazavr/go-gitlab-client/README.md | 3 + .../examples/projects/main.go | 84 ++++++++++++-- .../examples/repositories/main.go | 32 ++++- .../Bugagazavr/go-gitlab-client/gitlab.go | 29 +++++ .../go-gitlab-client/hook_payload.go | 1 + .../Bugagazavr/go-gitlab-client/hooks.go | 16 ++- .../Bugagazavr/go-gitlab-client/projects.go | 65 +++++++++-- .../go-gitlab-client/projects_test.go | 15 +++ .../go-gitlab-client/repositories.go | 89 +++++++++++++- .../go-gitlab-client/repositories_test.go | 9 ++ .../Bugagazavr/go-gitlab-client/services.go | 19 +++ .../stubs/commits/comments/index.json | 16 +++ .../projects/merge_requests/notes/index.json | 16 +++ cmd/drone-server/drone.go | 16 +++ pkg/remote/builtin/gitlab/gitlab.go | 109 ++++++++++-------- pkg/server/commits.go | 34 ++++++ pkg/server/redirect.go | 61 ++++++++++ pkg/store/builtin/build.go | 12 ++ pkg/store/builtin/build_sql.go | 73 ++++++++++++ pkg/store/store.go | 8 ++ 21 files changed, 629 insertions(+), 80 deletions(-) create mode 100644 Godeps/_workspace/src/github.com/Bugagazavr/go-gitlab-client/services.go create mode 100644 Godeps/_workspace/src/github.com/Bugagazavr/go-gitlab-client/stubs/commits/comments/index.json create mode 100644 Godeps/_workspace/src/github.com/Bugagazavr/go-gitlab-client/stubs/projects/merge_requests/notes/index.json create mode 100644 pkg/server/redirect.go diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index 14f6037e4..089d4c11e 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -12,7 +12,7 @@ }, { "ImportPath": "github.com/Bugagazavr/go-gitlab-client", - "Rev": "912567bb7e65212c910733b3bfa178b11049a70e" + "Rev": "fa361f26087a2ff8fbb267fbe2d82037fc35e51a" }, { "ImportPath": "github.com/BurntSushi/migration", diff --git a/Godeps/_workspace/src/github.com/Bugagazavr/go-gitlab-client/README.md b/Godeps/_workspace/src/github.com/Bugagazavr/go-gitlab-client/README.md index 4e716ee32..7920c5c4b 100644 --- a/Godeps/_workspace/src/github.com/Bugagazavr/go-gitlab-client/README.md +++ b/Godeps/_workspace/src/github.com/Bugagazavr/go-gitlab-client/README.md @@ -18,6 +18,9 @@ go-gitlab-client is a simple client written in golang to consume gitlab API. ###Projects [gitlab api doc](http://doc.gitlab.com/ce/api/projects.html) * list projects * get single project + * list project merge requests + * list notes on merge requests + * add comments to merge requests * ###Repositories [gitlab api doc](http://doc.gitlab.com/ce/api/repositories.html) diff --git a/Godeps/_workspace/src/github.com/Bugagazavr/go-gitlab-client/examples/projects/main.go b/Godeps/_workspace/src/github.com/Bugagazavr/go-gitlab-client/examples/projects/main.go index 26325c19d..80a3d478d 100644 --- a/Godeps/_workspace/src/github.com/Bugagazavr/go-gitlab-client/examples/projects/main.go +++ b/Godeps/_workspace/src/github.com/Bugagazavr/go-gitlab-client/examples/projects/main.go @@ -37,15 +37,30 @@ func main() { var method string flag.StringVar(&method, "m", "", "Specify method to retrieve projects infos, available methods:\n"+ " > -m projects\n"+ - " > -m project -id PROJECT_ID\n"+ - " > -m hooks -id PROJECT_ID\n"+ - " > -m branches -id PROJECT_ID\n"+ - " > -m merge_requests -id PROJECT_ID\n"+ - " > -m team -id PROJECT_ID") + " > -m project -id PROJECT_ID\n"+ + " > -m hooks -id PROJECT_ID\n"+ + " > -m branches -id PROJECT_ID\n"+ + " > -m merge_requests -id PROJECT_ID\n"+ + " > -m merge_request_notes -id PROJECT_ID -merge_id MERGE_REQUEST_ID\n"+ + " > -m merge_request_comment -id PROJECT_ID -merge_id MERGE_REQUEST_ID -comment COMMENT_BODY\n"+ + " > -m team -id PROJECT_ID\n"+ + " > -m add_drone -id PROJECT_ID\n -token DRONE_TOKEN -url DRONE_URL") var id string flag.StringVar(&id, "id", "", "Specify repository id") + var merge_id string + flag.StringVar(&merge_id, "merge_id", "", "Specify merge request id") + + var comment string + flag.StringVar(&comment, "comment", "", "The body of the new comment") + + var drone_token string + flag.StringVar(&drone_token, "drone_token", "", "Drone service token") + + var drone_url string + flag.StringVar(&drone_url, "drone_url", "", "Drone service url") + flag.Usage = func() { fmt.Printf("Usage:\n") flag.PrintDefaults() @@ -151,11 +166,54 @@ func main() { if mr.Assignee != nil { assignee = mr.Assignee.Username } - fmt.Printf(" %s -> %s [%s] author[%s] assignee[%s]\n", - mr.SourceBranch, mr.TargetBranch, mr.State, + fmt.Printf(" (#%d) %s -> %s [%s] author[%s] assignee[%s]\n", + mr.Id, mr.SourceBranch, mr.TargetBranch, mr.State, author, assignee) } + case "merge_request_notes": + fmt.Println("Fetching merge_request notes…") + + if id == "" { + flag.Usage() + return + } + + notes, err := gitlab.MergeRequestNotes(id, merge_id, 0, 30) + if err != nil { + fmt.Println(err.Error()) + return + } + + for _, note := range notes { + author := "" + if note.Author != nil { + author = note.Author.Username + } + fmt.Printf(" [%d] author: %s <%s> %s\n", + note.Id, author, note.CreatedAt, note.Body) + } + + case "merge_request_comment": + fmt.Println("Sending new merge_request comment…") + + if id == "" { + flag.Usage() + return + } + + note, err := gitlab.SendMergeRequestComment(id, merge_id, comment) + if err != nil { + fmt.Println(err.Error()) + return + } + author := "" + if note.Author != nil { + author = note.Author.Username + } + fmt.Printf(" [%d] author: %s <%s> %s\n", + note.Id, author, note.CreatedAt, note.Body) + case "hooks": fmt.Println("Fetching project hooks…") @@ -191,5 +249,17 @@ func main() { for _, member := range members { fmt.Printf("> [%d] %s (%s) since %s\n", member.Id, member.Username, member.Name, member.CreatedAt) } + case "add_drone": + fmt.Println("Adding drone service to project") + + if id == "" || drone_token == "" || drone_url == "" { + flag.Usage() + return + } + + if err := gitlab.AddDroneService(id, map[string]string{"token": drone_token, "drone_url": drone_url}); err != nil { + fmt.Println(err) + return + } } } diff --git a/Godeps/_workspace/src/github.com/Bugagazavr/go-gitlab-client/examples/repositories/main.go b/Godeps/_workspace/src/github.com/Bugagazavr/go-gitlab-client/examples/repositories/main.go index e6591bb91..8a250204c 100644 --- a/Godeps/_workspace/src/github.com/Bugagazavr/go-gitlab-client/examples/repositories/main.go +++ b/Godeps/_workspace/src/github.com/Bugagazavr/go-gitlab-client/examples/repositories/main.go @@ -36,11 +36,19 @@ func main() { " > branches\n"+ " > branch\n"+ " > tags\n"+ - " > commits") + " > commits\n"+ + " > commit_comments -sha COMMIT_SHA\n"+ + " > comment_a_commit -sha COMMIT_SHA -comment COMMENT_BODY") var id string flag.StringVar(&id, "id", "", "Specify repository id") + var sha string + flag.StringVar(&sha, "sha", "", "Specify commit sha") + + var comment string + flag.StringVar(&comment, "comment", "", "The body of the new comment") + flag.Usage = func() { fmt.Printf("Usage:\n") flag.PrintDefaults() @@ -90,7 +98,27 @@ func main() { } for _, commit := range commits { - fmt.Printf("%s > [%s] %s\n", commit.CreatedAt.Format("Mon 02 Jan 15:04"), commit.Author_Name, commit.Title) + fmt.Printf("(%s) %s > [%s] %s\n", commit.Id, commit.CreatedAt.Format("Mon 02 Jan 15:04"), commit.Author_Name, commit.Title) } + case "commit_comments": + fmt.Println("Fetching comments on a repository commit…") + + comments, err := gitlab.RepoCommitComments(id, sha) + if err != nil { + fmt.Println(err.Error()) + } + + for _, c := range comments { + fmt.Printf("[%s] %s\n", c.Author.Username, c.Note) + } + case "comment_a_commit": + fmt.Println("Sending a new comment on a repository commit…") + + c, err := gitlab.SendRepoCommitComment(id, sha, comment) + if err != nil { + fmt.Println(err.Error()) + } + + fmt.Printf("[%s] %s\n", c.Author.Username, c.Note) } } diff --git a/Godeps/_workspace/src/github.com/Bugagazavr/go-gitlab-client/gitlab.go b/Godeps/_workspace/src/github.com/Bugagazavr/go-gitlab-client/gitlab.go index 415dc5ed6..dceb17541 100644 --- a/Godeps/_workspace/src/github.com/Bugagazavr/go-gitlab-client/gitlab.go +++ b/Godeps/_workspace/src/github.com/Bugagazavr/go-gitlab-client/gitlab.go @@ -128,6 +128,35 @@ func (g *Gitlab) ResourceUrlQuery(u string, params, query map[string]string) str } +func (g *Gitlab) ResourceUrlQueryRaw(u string, params, query map[string]string) (string, string) { + if params != nil { + for key, val := range params { + u = strings.Replace(u, key, encodeParameter(val), -1) + } + } + + query_params := url.Values{} + if !g.Bearer { + query_params.Add("private_token", g.Token) + } + + if query != nil { + for key, val := range query { + query_params.Set(key, val) + } + } + + u = g.BaseUrl + g.ApiPath + u + "?" + query_params.Encode() + p, err := url.Parse(u) + if err != nil { + return u, "" + } + + opaque := "//" + p.Host + p.Path + return u, opaque + +} + func (g *Gitlab) ResourceUrlRaw(u string, params map[string]string) (string, string) { if params != nil { diff --git a/Godeps/_workspace/src/github.com/Bugagazavr/go-gitlab-client/hook_payload.go b/Godeps/_workspace/src/github.com/Bugagazavr/go-gitlab-client/hook_payload.go index 8bb7e9add..e4c33c0a2 100644 --- a/Godeps/_workspace/src/github.com/Bugagazavr/go-gitlab-client/hook_payload.go +++ b/Godeps/_workspace/src/github.com/Bugagazavr/go-gitlab-client/hook_payload.go @@ -27,6 +27,7 @@ type HookObjAttr struct { StDiffs string `json:"st_diffs,omitempty"` MergeStatus string `json:"merge_status,omitempty"` TargetProjectId int `json:"target_project_id,omitempty"` + URL string `json:"url,omitempty"` Source *hProject `json:"source,omitempty"` Target *hProject `json:"target,omitempty"` LastCommit *hCommit `json:"last_commit,omitempty"` diff --git a/Godeps/_workspace/src/github.com/Bugagazavr/go-gitlab-client/hooks.go b/Godeps/_workspace/src/github.com/Bugagazavr/go-gitlab-client/hooks.go index 9dd0fe4bb..3f19de7eb 100644 --- a/Godeps/_workspace/src/github.com/Bugagazavr/go-gitlab-client/hooks.go +++ b/Godeps/_workspace/src/github.com/Bugagazavr/go-gitlab-client/hooks.go @@ -88,13 +88,13 @@ Parameters: merge_requests_events Trigger hook on merge_requests events */ -func (g *Gitlab) AddProjectHook(id, hook_url string, push_events, issues_events, merge_requests_events bool) error { +func (g *Gitlab) AddProjectHook(id, hook_url string, push_events, issues_events, merge_requests_events, tag_events bool) error { url, opaque := g.ResourceUrlRaw(project_url_hooks, map[string]string{":id": id}) var err error - body := buildHookQuery(hook_url, push_events, issues_events, merge_requests_events) + body := buildHookQuery(hook_url, push_events, issues_events, merge_requests_events, tag_events) _, err = g.buildAndExecRequestRaw("POST", url, opaque, []byte(body)) return err @@ -115,7 +115,7 @@ Parameters: merge_requests_events Trigger hook on merge_requests events */ -func (g *Gitlab) EditProjectHook(id, hook_id, hook_url string, push_events, issues_events, merge_requests_events bool) error { +func (g *Gitlab) EditProjectHook(id, hook_id, hook_url string, push_events, issues_events, merge_requests_events, tag_events bool) error { url, opaque := g.ResourceUrlRaw(project_url_hook, map[string]string{ ":id": id, @@ -124,7 +124,7 @@ func (g *Gitlab) EditProjectHook(id, hook_id, hook_url string, push_events, issu var err error - body := buildHookQuery(hook_url, push_events, issues_events, merge_requests_events) + body := buildHookQuery(hook_url, push_events, issues_events, merge_requests_events, tag_events) _, err = g.buildAndExecRequestRaw("PUT", url, opaque, []byte(body)) return err @@ -158,7 +158,7 @@ func (g *Gitlab) RemoveProjectHook(id, hook_id string) error { /* Build HTTP query to add or edit hook */ -func buildHookQuery(hook_url string, push_events, issues_events, merge_requests_events bool) string { +func buildHookQuery(hook_url string, push_events, issues_events, merge_requests_events, tag_events bool) string { v := url.Values{} v.Set("url", hook_url) @@ -178,6 +178,10 @@ func buildHookQuery(hook_url string, push_events, issues_events, merge_requests_ } else { v.Set("merge_requests_events", "false") } - + if tag_events { + v.Set("tag_push_events", "true") + } else { + v.Set("tag_push_events", "false") + } return v.Encode() } diff --git a/Godeps/_workspace/src/github.com/Bugagazavr/go-gitlab-client/projects.go b/Godeps/_workspace/src/github.com/Bugagazavr/go-gitlab-client/projects.go index 9de030ec0..b470f57e3 100644 --- a/Godeps/_workspace/src/github.com/Bugagazavr/go-gitlab-client/projects.go +++ b/Godeps/_workspace/src/github.com/Bugagazavr/go-gitlab-client/projects.go @@ -2,19 +2,21 @@ package gogitlab import ( "encoding/json" + "fmt" "strconv" "strings" ) const ( - projects_url = "/projects" // Get a list of projects owned by the authenticated user - projects_search_url = "/projects/search/:query" // Search for projects by name - project_url = "/projects/:id" // Get a specific project, identified by project ID or NAME - project_url_events = "/projects/:id/events" // Get project events - project_url_branches = "/projects/:id/repository/branches" // Lists all branches of a project - project_url_members = "/projects/:id/members" // List project team members - project_url_member = "/projects/:id/members/:user_id" // Get project team member - project_url_merge_requests = "/projects/:id/merge_requests" // List all merge requests of a project + projects_url = "/projects" // Get a list of projects owned by the authenticated user + projects_search_url = "/projects/search/:query" // Search for projects by name + project_url = "/projects/:id" // Get a specific project, identified by project ID or NAME + project_url_events = "/projects/:id/events" // Get project events + project_url_branches = "/projects/:id/repository/branches" // Lists all branches of a project + project_url_members = "/projects/:id/members" // List project team members + project_url_member = "/projects/:id/members/:user_id" // Get project team member + project_url_merge_requests = "/projects/:id/merge_requests" // List all merge requests of a project + merge_request_url_notes = "/projects/:id/merge_requests/:merge_request_id/notes" // Manage comments for a given merge request ) type Member struct { @@ -89,6 +91,14 @@ type MergeRequest struct { Description string `json:"description,omitempty"` } +type MergeRequestNote struct { + Attachment interface{} `json:"attachment"` + Body string `json:"body"` + CreatedAt string `json:"created_at"` + Id int `json:"id"` + Author *Member `json:"author"` +} + /* Get a list of all projects owned by the authenticated user. */ @@ -209,6 +219,43 @@ func (g *Gitlab) ProjectMergeRequests(id string, page int, per_page int, state s return mr, err } +/* +Lists all comments on merge request. +*/ +func (g *Gitlab) MergeRequestNotes(id string, merge_request_id string, page int, per_page int) ([]*MergeRequestNote, error) { + par := map[string]string{":id": id, ":merge_request_id": merge_request_id} + qry := map[string]string{ + "page": strconv.Itoa(page), + "per_page": strconv.Itoa(per_page)} + url := g.ResourceUrlQuery(merge_request_url_notes, par, qry) + + var mr []*MergeRequestNote + + contents, err := g.buildAndExecRequest("GET", url, nil) + if err == nil { + err = json.Unmarshal(contents, &mr) + } + + return mr, err +} + +/* +Creates a new comment on a merge request. +*/ +func (g *Gitlab) SendMergeRequestComment(id string, merge_request_id string, comment string) (*MergeRequestNote, error) { + par := map[string]string{":id": id, ":merge_request_id": merge_request_id} + url := g.ResourceUrlQuery(merge_request_url_notes, par, map[string]string{}) + + var mr *MergeRequestNote + + contents, err := g.buildAndExecRequest("POST", url, []byte(fmt.Sprintf("body=%s", comment))) + if err == nil { + err = json.Unmarshal(contents, &mr) + } + + return mr, err +} + /* Get single project id. @@ -236,7 +283,7 @@ func (g *Gitlab) SearchProjectId(namespace string, name string) (id int, err err } for _, project := range projects { - if project.Namespace.Name == namespace { + if project.Namespace.Name == namespace && strings.ToLower(project.Name) == strings.ToLower(name) { id = project.Id } } diff --git a/Godeps/_workspace/src/github.com/Bugagazavr/go-gitlab-client/projects_test.go b/Godeps/_workspace/src/github.com/Bugagazavr/go-gitlab-client/projects_test.go index 2484d6f48..6fcbda844 100644 --- a/Godeps/_workspace/src/github.com/Bugagazavr/go-gitlab-client/projects_test.go +++ b/Godeps/_workspace/src/github.com/Bugagazavr/go-gitlab-client/projects_test.go @@ -57,6 +57,21 @@ func TestProjectMergeRequests(t *testing.T) { } } +func TestMergeRequestNotes(t *testing.T) { + ts, gitlab := Stub("stubs/projects/merge_requests/notes/index.json") + defer ts.Close() + notes, err := gitlab.MergeRequestNotes("1", "1", 0, 30) + + assert.Equal(t, err, nil) + assert.Equal(t, len(notes), 1) + + if len(notes) > 0 { + assert.Equal(t, notes[0].Id, 301) + assert.Equal(t, notes[0].Body, "Comment for MR") + assert.Equal(t, notes[0].Author.Username, "pipin") + } +} + func TestSearchProjectId(t *testing.T) { ts, gitlab := Stub("stubs/projects/index.json") diff --git a/Godeps/_workspace/src/github.com/Bugagazavr/go-gitlab-client/repositories.go b/Godeps/_workspace/src/github.com/Bugagazavr/go-gitlab-client/repositories.go index 694100e0e..47d54b706 100644 --- a/Godeps/_workspace/src/github.com/Bugagazavr/go-gitlab-client/repositories.go +++ b/Godeps/_workspace/src/github.com/Bugagazavr/go-gitlab-client/repositories.go @@ -2,17 +2,19 @@ package gogitlab import ( "encoding/json" + "fmt" "net/url" "time" ) const ( - repo_url_branches = "/projects/:id/repository/branches" // List repository branches - repo_url_branch = "/projects/:id/repository/branches/:branch" // Get a specific branch of a project. - repo_url_tags = "/projects/:id/repository/tags" // List project repository tags - repo_url_commits = "/projects/:id/repository/commits" // List repository commits - repo_url_tree = "/projects/:id/repository/tree" // List repository tree - repo_url_raw_file = "/projects/:id/repository/blobs/:sha" // Get raw file content for specific commit/branch + repo_url_branches = "/projects/:id/repository/branches" // List repository branches + repo_url_branch = "/projects/:id/repository/branches/:branch" // Get a specific branch of a project. + repo_url_tags = "/projects/:id/repository/tags" // List project repository tags + repo_url_commits = "/projects/:id/repository/commits" // List repository commits + repo_url_commit_comments = "/projects/:id/repository/commits/:sha/comments" // New comment or list of commit comments + repo_url_tree = "/projects/:id/repository/tree" // List repository tree + repo_url_raw_file = "/projects/:id/repository/blobs/:sha" // Get raw file content for specific commit/branch ) type BranchCommit struct { @@ -62,6 +64,14 @@ type File struct { Children []*File } +type CommitComment struct { + Author *Member `json:"author,omitempty"` + Line int `json:"line,omitempty"` + LineType string `json:"line_type,omitempty"` + Note string `json:"note,omitempty"` + Path string `json:"path,omitempty"` +} + /* Get a list of repository branches from a project, sorted by name alphabetically. @@ -195,6 +205,73 @@ func (g *Gitlab) RepoCommits(id string) ([]*Commit, error) { return commits, err } +/* +Get a list of comments in a repository commit. + + GET /projects/:id/repository/commits/:sha/comments + +Parameters: + + id The ID of a project + sha The sha of the commit + +Usage: + + comments, err := gitlab.RepoCommitComments("your_projet_id", "commit_sha") + if err != nil { + fmt.Println(err.Error()) + } + for _, comment := range comments { + fmt.Printf("%+v\n", comment) + } +*/ +func (g *Gitlab) RepoCommitComments(id string, sha string) ([]*CommitComment, error) { + + url, opaque := g.ResourceUrlRaw(repo_url_commit_comments, map[string]string{":id": id, ":sha": sha}) + + var comments []*CommitComment + + contents, err := g.buildAndExecRequestRaw("GET", url, opaque, nil) + if err == nil { + err = json.Unmarshal(contents, &comments) + } + + return comments, err +} + +/* +Create a comment in a repository commit. + + POST /projects/:id/repository/commits/:sha/comments + +Parameters: + + id The ID of a project + sha The sha of the commit + body The body of the comment + +Usage: + + comment, err := gitlab.SendRepoCommitComment("your_projet_id", "commit_sha", "your comment goes here") + if err != nil { + fmt.Println(err.Error()) + } + fmt.Printf("%+v\n", comment) +*/ +func (g *Gitlab) SendRepoCommitComment(id string, sha string, body string) (*CommitComment, error) { + + url, opaque := g.ResourceUrlRaw(repo_url_commit_comments, map[string]string{":id": id, ":sha": sha}) + + var comment *CommitComment + + contents, err := g.buildAndExecRequestRaw("POST", url, opaque, []byte(fmt.Sprintf("note=%s", body))) + if err == nil { + err = json.Unmarshal(contents, &comment) + } + + return comment, err +} + /* Get Raw file content */ diff --git a/Godeps/_workspace/src/github.com/Bugagazavr/go-gitlab-client/repositories_test.go b/Godeps/_workspace/src/github.com/Bugagazavr/go-gitlab-client/repositories_test.go index ab445fbc5..36a4d7bda 100644 --- a/Godeps/_workspace/src/github.com/Bugagazavr/go-gitlab-client/repositories_test.go +++ b/Godeps/_workspace/src/github.com/Bugagazavr/go-gitlab-client/repositories_test.go @@ -41,3 +41,12 @@ func TestRepoCommits(t *testing.T) { assert.Equal(t, len(commits), 2) defer ts.Close() } + +func TestRepoCommitComments(t *testing.T) { + ts, gitlab := Stub("stubs/commits/comments/index.json") + comments, err := gitlab.RepoCommitComments("1", "a9e6a5io4e695923c995ed2e836789b50oi77e0b") + + assert.Equal(t, err, nil) + assert.Equal(t, len(comments), 1) + defer ts.Close() +} diff --git a/Godeps/_workspace/src/github.com/Bugagazavr/go-gitlab-client/services.go b/Godeps/_workspace/src/github.com/Bugagazavr/go-gitlab-client/services.go new file mode 100644 index 000000000..6ef79c283 --- /dev/null +++ b/Godeps/_workspace/src/github.com/Bugagazavr/go-gitlab-client/services.go @@ -0,0 +1,19 @@ +package gogitlab + +const ( + drone_service_url = "/projects/:id/services/drone-ci" +) + +func (g *Gitlab) AddDroneService(id string, params map[string]string) error { + url, opaque := g.ResourceUrlQueryRaw(drone_service_url, map[string]string{":id": id}, params) + + _, err := g.buildAndExecRequestRaw("PUT", url, opaque, nil) + return err +} + +func (g *Gitlab) DeleteDroneService(id string) error { + url, opaque := g.ResourceUrlQueryRaw(drone_service_url, map[string]string{":id": id}, nil) + + _, err := g.buildAndExecRequestRaw("DELETE", url, opaque, nil) + return err +} diff --git a/Godeps/_workspace/src/github.com/Bugagazavr/go-gitlab-client/stubs/commits/comments/index.json b/Godeps/_workspace/src/github.com/Bugagazavr/go-gitlab-client/stubs/commits/comments/index.json new file mode 100644 index 000000000..f3886f5c4 --- /dev/null +++ b/Godeps/_workspace/src/github.com/Bugagazavr/go-gitlab-client/stubs/commits/comments/index.json @@ -0,0 +1,16 @@ +[ + { + "author": { + "id": 1, + "username": "admin", + "email": "admin@local.host", + "name": "Administrator", + "blocked": false, + "created_at": "2012-04-29T08:46:00Z" + }, + "note": "text1", + "path": "example.rb", + "line": 5, + "line_type": "new" + } +] \ No newline at end of file diff --git a/Godeps/_workspace/src/github.com/Bugagazavr/go-gitlab-client/stubs/projects/merge_requests/notes/index.json b/Godeps/_workspace/src/github.com/Bugagazavr/go-gitlab-client/stubs/projects/merge_requests/notes/index.json new file mode 100644 index 000000000..52f57e809 --- /dev/null +++ b/Godeps/_workspace/src/github.com/Bugagazavr/go-gitlab-client/stubs/projects/merge_requests/notes/index.json @@ -0,0 +1,16 @@ +[ + { + "id": 301, + "body": "Comment for MR", + "attachment": null, + "author": { + "id": 1, + "username": "pipin", + "email": "admin@example.com", + "name": "Pip", + "state": "active", + "created_at": "2013-09-30T13:46:01Z" + }, + "created_at": "2013-10-02T08:57:14Z" + } +] \ No newline at end of file diff --git a/cmd/drone-server/drone.go b/cmd/drone-server/drone.go index 737fa78ba..16001ae55 100644 --- a/cmd/drone-server/drone.go +++ b/cmd/drone-server/drone.go @@ -185,6 +185,14 @@ func main() { repo.GET("/logs/:number/:task", server.GetLogs) // repo.POST("/status/:number", server.PostBuildStatus) } + + // Routes for external services + repoExternal := repos.Group("") + { + repoExternal.Use(server.SetRepo()) + + repoExternal.GET("/pr/:number", server.GetPullRequest) + } } badges := api.Group("/badges/:owner/:name") @@ -236,6 +244,14 @@ func main() { auth.POST("", server.GetLogin) } + redirects := r.Group("/redirect") + { + redirects.Use(server.SetDatastore(store)) + redirects.Use(server.SetRepo()) + + redirects.GET("/:owner/:name/commit/:sha", server.RedirectSha) + } + r.SetHTMLTemplate(index()) r.NoRoute(func(c *gin.Context) { c.HTML(200, "index.html", nil) diff --git a/pkg/remote/builtin/gitlab/gitlab.go b/pkg/remote/builtin/gitlab/gitlab.go index a79809bfa..e5c0560dc 100644 --- a/pkg/remote/builtin/gitlab/gitlab.go +++ b/pkg/remote/builtin/gitlab/gitlab.go @@ -6,8 +6,10 @@ import ( "io/ioutil" "net/http" "net/url" + "regexp" "strconv" "strings" + "time" "github.com/drone/drone/Godeps/_workspace/src/github.com/Bugagazavr/go-gitlab-client" "github.com/drone/drone/Godeps/_workspace/src/github.com/hashicorp/golang-lru" @@ -190,25 +192,15 @@ func (r *Gitlab) Activate(user *common.User, repo *common.Repo, k *common.Keypai return err } - title, err := GetKeyTitle(link) + uri, err := url.Parse(link) if err != nil { return err } - // if the repository is private we'll need - // to upload a github key to the repository - if repo.Private { - if err := client.AddProjectDeployKey(id, title, k.Public); err != nil { - return err - } - } + droneUrl := fmt.Sprintf("%s://%s", uri.Scheme, uri.Host) + droneToken := uri.Query().Get("access_token") - // append the repo owner / name to the hook url since gitlab - // doesn't send this detail in the post-commit hook - link += "&owner=" + repo.Owner + "&name=" + repo.Name - - // add the hook - return client.AddProjectHook(id, link, true, false, true) + return client.AddDroneService(id, map[string]string{"token": droneToken, "drone_url": droneUrl}) } // Deactivate removes a repository by removing all the post-commit hooks @@ -220,33 +212,7 @@ func (r *Gitlab) Deactivate(user *common.User, repo *common.Repo, link string) e return err } - keys, err := client.ProjectDeployKeys(id) - if err != nil { - return err - } - var pubkey = strings.TrimSpace(repo.Keys.Public) - for _, k := range keys { - if pubkey == strings.TrimSpace(k.Key) { - if err := client.RemoveProjectDeployKey(id, strconv.Itoa(k.Id)); err != nil { - return err - } - break - } - } - hooks, err := client.ProjectHooks(id) - if err != nil { - return err - } - link += "&owner=" + repo.Owner + "&name=" + repo.Name - for _, h := range hooks { - if link == h.Url { - if err := client.RemoveProjectHook(id, strconv.Itoa(h.Id)); err != nil { - return err - } - break - } - } - return nil + return client.DeleteDroneService(id) } // ParseHook parses the post-commit hook from the Request body @@ -259,20 +225,65 @@ func (r *Gitlab) Hook(req *http.Request) (*common.Hook, error) { return nil, err } - if len(parsed.After) == 0 || parsed.TotalCommitsCount == 0 { + switch parsed.ObjectKind { + case "merge_request": + if (parsed.ObjectAttributes.State != "reopened" || parsed.ObjectAttributes.State != "opened") && parsed.ObjectAttributes.MergeStatus != "unchecked" { + return nil, nil + } + + return mergeRequest(parsed, req) + case "push": + if len(parsed.After) == 0 || parsed.TotalCommitsCount == 0 { + return nil, nil + } + + return push(parsed, req) + default: return nil, nil } +} - if parsed.ObjectKind == "merge_request" { - // NOTE: in gitlab 8.0, gitlab will get same MR models as github - // https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/981/diffs - return nil, nil +func mergeRequest(parsed *gogitlab.HookPayload, req *http.Request) (*common.Hook, error) { + var hook = new(common.Hook) + + re := regexp.MustCompile(".git$") + + hook.Repo = &common.Repo{} + hook.Repo.Owner = req.FormValue("owner") + hook.Repo.Name = req.FormValue("name") + hook.Repo.FullName = fmt.Sprintf("%s/%s", hook.Repo.Owner, hook.Repo.Name) + hook.Repo.Link = re.ReplaceAllString(parsed.ObjectAttributes.Target.HttpUrl, "$1") + hook.Repo.Clone = parsed.ObjectAttributes.Target.HttpUrl + hook.Repo.Branch = "master" + + hook.Commit = &common.Commit{} + hook.Commit.Message = parsed.ObjectAttributes.LastCommit.Message + hook.Commit.Sha = parsed.ObjectAttributes.LastCommit.Id + hook.Commit.Remote = parsed.ObjectAttributes.Source.HttpUrl + + if parsed.ObjectAttributes.Source.HttpUrl == parsed.ObjectAttributes.Target.HttpUrl { + hook.Commit.Ref = fmt.Sprintf("refs/heads/%s", parsed.ObjectAttributes.SourceBranch) + hook.Commit.Branch = parsed.ObjectAttributes.SourceBranch + hook.Commit.Timestamp = time.Now().UTC().Format("2006-01-02 15:04:05.000000000 +0000 MST") + } else { + hook.Commit.Ref = fmt.Sprintf("refs/merge-requests/%d/head", parsed.ObjectAttributes.IId) + hook.Commit.Branch = parsed.ObjectAttributes.SourceBranch + hook.Commit.Timestamp = time.Now().UTC().Format("2006-01-02 15:04:05.000000000 +0000 MST") } - if len(parsed.After) == 0 { - return nil, nil - } + hook.Commit.Author = &common.Author{} + hook.Commit.Author.Login = parsed.ObjectAttributes.LastCommit.Author.Name + hook.Commit.Author.Email = parsed.ObjectAttributes.LastCommit.Author.Email + hook.PullRequest = &common.PullRequest{} + hook.PullRequest.Number = parsed.ObjectAttributes.IId + hook.PullRequest.Title = parsed.ObjectAttributes.Description + hook.PullRequest.Link = parsed.ObjectAttributes.URL + + return hook, nil +} + +func push(parsed *gogitlab.HookPayload, req *http.Request) (*common.Hook, error) { var cloneUrl = parsed.Repository.GitHttpUrl var hook = new(common.Hook) diff --git a/pkg/server/commits.go b/pkg/server/commits.go index bf9b647e1..cead75400 100644 --- a/pkg/server/commits.go +++ b/pkg/server/commits.go @@ -41,6 +41,40 @@ func GetCommit(c *gin.Context) { } } +// GetPullRequest accepts a requests to retvie a pull request +// from the datastore for the given repository and +// pull request number +// +// GET /api/repos/:owner/:name/pr/:number +// +func GetPullRequest(c *gin.Context) { + store := ToDatastore(c) + repo := ToRepo(c) + + // get the token and verify the hook is authorized + if c.Request.FormValue("access_token") != hash(repo.FullName, repo.Hash) { + c.AbortWithStatus(403) + return + } + + num, err := strconv.Atoi(c.Params.ByName("number")) + if err != nil { + c.Fail(400, err) + return + } + build, err := store.BuildPullRequestNumber(repo, num) + if err != nil { + c.Fail(404, err) + return + } + build.Jobs, err = store.JobList(build) + if err != nil { + c.Fail(404, err) + } else { + c.JSON(200, build) + } +} + // GetCommits accepts a request to retrieve a list // of commits from the datastore for the given repository. // diff --git a/pkg/server/redirect.go b/pkg/server/redirect.go new file mode 100644 index 000000000..59a0608f4 --- /dev/null +++ b/pkg/server/redirect.go @@ -0,0 +1,61 @@ +package server + +import ( + "fmt" + "strconv" + + "github.com/drone/drone/Godeps/_workspace/src/github.com/gin-gonic/gin" +) + +// RedirectSha accepts a request to retvie a redirect +// to job from the datastore for the given repository +// and commit sha +// +// GET /redirect/:owner/:name/commit/:sha +// +func RedirectSha(c *gin.Context) { + var branch string + + store := ToDatastore(c) + repo := ToRepo(c) + sha := c.Params.ByName("sha") + + branch = c.Request.FormValue("branch") + if branch == "" { + branch = repo.Branch + } + + build, err := store.BuildSha(repo, sha, branch) + if err != nil { + c.Redirect(301, "/") + return + } + + c.Redirect(301, fmt.Sprintf("/%s/%s/%d", repo.Owner, repo.Name, build.ID)) + return +} + +// RedirectSha accepts a request to retvie a redirect +// to job from the datastore for the given repository +// and pull request number +// +// GET /redirect/:owner/:name/pr/:number +// +func RedirectPullRequest(c *gin.Context) { + store := ToDatastore(c) + repo := ToRepo(c) + num, err := strconv.Atoi(c.Params.ByName("number")) + if err != nil { + c.Redirect(301, "/") + return + } + + build, err := store.BuildPullRequestNumber(repo, num) + if err != nil { + c.Redirect(301, "/") + return + } + + c.Redirect(301, fmt.Sprintf("/%s/%s/%d", repo.Owner, repo.Name, build.ID)) + return +} diff --git a/pkg/store/builtin/build.go b/pkg/store/builtin/build.go index e2b139e53..ba14b19e1 100644 --- a/pkg/store/builtin/build.go +++ b/pkg/store/builtin/build.go @@ -25,6 +25,18 @@ func (db *Buildstore) BuildNumber(repo *types.Repo, seq int) (*types.Build, erro return getBuild(db, rebind(stmtBuildSelectBuildNumber), repo.ID, seq) } +// BuildPullRequest gets the specific build for the +// named repository and pull request number +func (db *Buildstore) BuildPullRequestNumber(repo *types.Repo, seq int) (*types.Build, error) { + return getBuild(db, rebind(stmtBuildSelectPullRequestNumber), repo.ID, seq) +} + +// BuildSha gets the specific build for the +// named repository and sha +func (db *Buildstore) BuildSha(repo *types.Repo, sha, branch string) (*types.Build, error) { + return getBuild(db, rebind(stmtBuildSelectSha), repo.ID, sha, branch) +} + // BuildLast gets the last executed build for the // named repository. func (db *Buildstore) BuildLast(repo *types.Repo, branch string) (*types.Build, error) { diff --git a/pkg/store/builtin/build_sql.go b/pkg/store/builtin/build_sql.go index eabc37285..32b7ce98c 100644 --- a/pkg/store/builtin/build_sql.go +++ b/pkg/store/builtin/build_sql.go @@ -596,6 +596,79 @@ WHERE build_repo_id = ? AND build_number = ? ` +const stmtBuildSelectPullRequestNumber = ` +SELECT + build_id +,build_repo_id +,build_number +,build_status +,build_started +,build_finished +,build_commit_sha +,build_commit_ref +,build_commit_link +,build_commit_branch +,build_commit_message +,build_commit_timestamp +,build_commit_remote +,build_commit_author_login +,build_commit_author_email +,build_pull_request_number +,build_pull_request_title +,build_pull_request_link +,build_pull_request_base_sha +,build_pull_request_base_ref +,build_pull_request_base_link +,build_pull_request_base_branch +,build_pull_request_base_message +,build_pull_request_base_timestamp +,build_pull_request_base_remote +,build_pull_request_base_author_login +,build_pull_request_base_author_email +FROM builds +WHERE build_repo_id = ? +AND build_pull_request_number = ? +ORDER BY build_number DESC +LIMIT 1 +` + +const stmtBuildSelectSha = ` +SELECT + build_id +,build_repo_id +,build_number +,build_status +,build_started +,build_finished +,build_commit_sha +,build_commit_ref +,build_commit_link +,build_commit_branch +,build_commit_message +,build_commit_timestamp +,build_commit_remote +,build_commit_author_login +,build_commit_author_email +,build_pull_request_number +,build_pull_request_title +,build_pull_request_link +,build_pull_request_base_sha +,build_pull_request_base_ref +,build_pull_request_base_link +,build_pull_request_base_branch +,build_pull_request_base_message +,build_pull_request_base_timestamp +,build_pull_request_base_remote +,build_pull_request_base_author_login +,build_pull_request_base_author_email +FROM builds +WHERE build_repo_id = ? +AND build_commit_sha = ? +AND build_commit_branch = ? +ORDER BY build_number DESC +LIMIT 1 +` + const stmtBuildSelectCommitBranch = ` SELECT build_id diff --git a/pkg/store/store.go b/pkg/store/store.go index 92470571f..8b2db4ee2 100644 --- a/pkg/store/store.go +++ b/pkg/store/store.go @@ -131,6 +131,14 @@ type Store interface { // named repository and build number BuildNumber(*types.Repo, int) (*types.Build, error) + // BuildPullRequestNumber gets the specified build number for the + // named repository and build number + BuildPullRequestNumber(*types.Repo, int) (*types.Build, error) + + // BuildSha gets the specified build number for the + // named repository and sha + BuildSha(*types.Repo, string, string) (*types.Build, error) + // BuildLast gets the last executed build for the // named repository and branch BuildLast(*types.Repo, string) (*types.Build, error) From 7716c702be587b5b3c526ae72dab3edcc706e7c5 Mon Sep 17 00:00:00 2001 From: Kirill Zaitsev Date: Sat, 22 Aug 2015 18:06:58 +0300 Subject: [PATCH 11/18] FIxes tests --- pkg/remote/builtin/gitlab/gitlab.go | 3 ++- pkg/store/mock/mock.go | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/pkg/remote/builtin/gitlab/gitlab.go b/pkg/remote/builtin/gitlab/gitlab.go index e5c0560dc..fc6713163 100644 --- a/pkg/remote/builtin/gitlab/gitlab.go +++ b/pkg/remote/builtin/gitlab/gitlab.go @@ -227,7 +227,8 @@ func (r *Gitlab) Hook(req *http.Request) (*common.Hook, error) { switch parsed.ObjectKind { case "merge_request": - if (parsed.ObjectAttributes.State != "reopened" || parsed.ObjectAttributes.State != "opened") && parsed.ObjectAttributes.MergeStatus != "unchecked" { + if parsed.ObjectAttributes.State != "reopened" && parsed.ObjectAttributes.MergeStatus != "unchecked" || + parsed.ObjectAttributes.State != "opened" && parsed.ObjectAttributes.MergeStatus != "unchecked" { return nil, nil } diff --git a/pkg/store/mock/mock.go b/pkg/store/mock/mock.go index b199d5066..603d46d5f 100644 --- a/pkg/store/mock/mock.go +++ b/pkg/store/mock/mock.go @@ -229,6 +229,28 @@ func (m *Store) BuildNumber(_a0 *types.Repo, _a1 int) (*types.Build, error) { return r0, r1 } +func (m *Store) BuildPullRequestNumber(_a0 *types.Repo, _a1 int) (*types.Build, error) { + ret := m.Called(_a0, _a1) + + var r0 *types.Build + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.Build) + } + r1 := ret.Error(1) + + return r0, r1 +} +func (m *Store) BuildSha(_a0 *types.Repo, _a1, _a2 string) (*types.Build, error) { + ret := m.Called(_a0, _a1, _a2) + + var r0 *types.Build + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.Build) + } + r1 := ret.Error(1) + + return r0, r1 +} func (m *Store) BuildLast(_a0 *types.Repo, _a1 string) (*types.Build, error) { ret := m.Called(_a0, _a1) From 00284dd87992227d7438fe1c6b2df465ffdc84ca Mon Sep 17 00:00:00 2001 From: Kirill Zaitsev Date: Sat, 22 Aug 2015 22:06:56 +0300 Subject: [PATCH 12/18] Gitlab testing --- pkg/remote/builtin/gitlab/gitlab_test.go | 149 +++++++++++++++ pkg/remote/builtin/gitlab/testdata/hooks.go | 102 +++++++++++ pkg/remote/builtin/gitlab/testdata/oauth.go | 3 + .../builtin/gitlab/testdata/projects.go | 173 ++++++++++++++++++ .../builtin/gitlab/testdata/testdata.go | 56 ++++++ pkg/remote/builtin/gitlab/testdata/users.go | 24 +++ 6 files changed, 507 insertions(+) create mode 100644 pkg/remote/builtin/gitlab/gitlab_test.go create mode 100644 pkg/remote/builtin/gitlab/testdata/hooks.go create mode 100644 pkg/remote/builtin/gitlab/testdata/oauth.go create mode 100644 pkg/remote/builtin/gitlab/testdata/projects.go create mode 100644 pkg/remote/builtin/gitlab/testdata/testdata.go create mode 100644 pkg/remote/builtin/gitlab/testdata/users.go diff --git a/pkg/remote/builtin/gitlab/gitlab_test.go b/pkg/remote/builtin/gitlab/gitlab_test.go new file mode 100644 index 000000000..832507195 --- /dev/null +++ b/pkg/remote/builtin/gitlab/gitlab_test.go @@ -0,0 +1,149 @@ +package gitlab + +import ( + "bytes" + "fmt" + "net/http" + "testing" + + "github.com/drone/drone/Godeps/_workspace/src/github.com/franela/goblin" + "github.com/drone/drone/pkg/remote/builtin/gitlab/testdata" + "github.com/drone/drone/pkg/types" +) + +func Test_Gitlab(t *testing.T) { + // setup a dummy github server + var server = testdata.NewServer() + defer server.Close() + + var gitlab, err = NewDriver(server.URL + "?client_id=test&client_secret=test") + if err != nil { + panic(err) + } + + var user = types.User{ + Login: "test_user", + Token: "e3b0c44298fc1c149afbf4c8996fb", + } + + var repo = types.Repo{ + Name: "diaspora-client", + Owner: "diaspora", + } + + g := goblin.Goblin(t) + g.Describe("Gitlab Plugin", func() { + // Test repository method + g.Describe("Repo", func() { + g.It("Should return valid repo", func() { + _repo, err := gitlab.Repo(&user, "diaspora", "diaspora-client") + + g.Assert(err == nil).IsTrue() + g.Assert(_repo.Name).Equal("diaspora-client") + g.Assert(_repo.Owner).Equal("diaspora") + g.Assert(_repo.Private).Equal(true) + }) + + g.It("Should return error, when repo not exist", func() { + _, err := gitlab.Repo(&user, "not-existed", "not-existed") + + g.Assert(err != nil).IsTrue() + }) + }) + + // Test permissions method + g.Describe("Perm", func() { + g.It("Should return repo permissions", func() { + perm, err := gitlab.Perm(&user, "diaspora", "diaspora-client") + + fmt.Println(gitlab.(*Gitlab), err) + 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") + + g.Assert(err != nil).IsTrue() + }) + }) + + // Test activate method + g.Describe("Activate", func() { + g.It("Should be success", func() { + err := gitlab.Activate(&user, &repo, &types.Keypair{}, "http://example.com/api/hook/test/test?access_token=token") + + g.Assert(err == nil).IsTrue() + }) + + g.It("Should be failed, when token not given", func() { + err := gitlab.Activate(&user, &repo, &types.Keypair{}, "http://example.com/api/hook/test/test") + + g.Assert(err != nil).IsTrue() + }) + }) + + // Test deactivate method + g.Describe("Deactivate", func() { + g.It("Should be success", func() { + err := gitlab.Deactivate(&user, &repo, "http://example.com/api/hook/test/test?access_token=token") + + g.Assert(err == nil).IsTrue() + }) + }) + + // Test login method + g.Describe("Login", func() { + g.It("Should return user", func() { + user, err := gitlab.Login("valid_token", "") + + g.Assert(err == nil).IsTrue() + g.Assert(user == nil).IsFalse() + }) + + g.It("Should return error, when token is invalid", func() { + _, err := gitlab.Login("invalid_token", "") + + g.Assert(err != nil).IsTrue() + }) + }) + + // Test hook method + g.Describe("Hook", func() { + g.It("Should parse push hoook", func() { + req, _ := http.NewRequest( + "POST", + "http://example.com/api/hook?owner=diaspora&name=diaspora-client", + bytes.NewReader(testdata.PushHook), + ) + + hook, err := gitlab.Hook(req) + + g.Assert(err == nil).IsTrue() + g.Assert(hook.Repo.Owner).Equal("diaspora") + g.Assert(hook.Repo.Name).Equal("diaspora-client") + + g.Assert(hook.PullRequest == nil).IsTrue() + }) + + g.It("Should parse merge request hook", func() { + req, _ := http.NewRequest( + "POST", + "http://example.com/api/hook?owner=diaspora&name=diaspora-client", + bytes.NewReader(testdata.MergeRequestHook), + ) + + hook, err := gitlab.Hook(req) + + g.Assert(err == nil).IsTrue() + g.Assert(hook.Repo.Owner).Equal("diaspora") + g.Assert(hook.Repo.Name).Equal("diaspora-client") + + g.Assert(hook.PullRequest.Number).Equal(1) + g.Assert(hook.PullRequest.Title).Equal("") + }) + }) + }) +} diff --git a/pkg/remote/builtin/gitlab/testdata/hooks.go b/pkg/remote/builtin/gitlab/testdata/hooks.go new file mode 100644 index 000000000..836d29831 --- /dev/null +++ b/pkg/remote/builtin/gitlab/testdata/hooks.go @@ -0,0 +1,102 @@ +package testdata + +var MergeRequestHook = []byte(` +{ + "object_kind": "merge_request", + "user": { + "name": "Administrator", + "username": "root", + "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon" + }, + "object_attributes": { + "id": 99, + "target_branch": "master", + "source_branch": "ms-viewport", + "source_project_id": 14, + "author_id": 51, + "assignee_id": 6, + "title": "MS-Viewport", + "created_at": "2013-12-03T17:23:34Z", + "updated_at": "2013-12-03T17:23:34Z", + "st_commits": null, + "st_diffs": null, + "milestone_id": null, + "state": "opened", + "merge_status": "unchecked", + "target_project_id": 14, + "iid": 1, + "description": "", + "source": { + "name": "awesome_project", + "ssh_url": "ssh://git@example.com/awesome_space/awesome_project.git", + "http_url": "http://example.com/awesome_space/awesome_project.git", + "visibility_level": 20, + "namespace": "awesome_space" + }, + "target": { + "name": "awesome_project", + "ssh_url": "ssh://git@example.com/awesome_space/awesome_project.git", + "http_url": "http://example.com/awesome_space/awesome_project.git", + "visibility_level": 20, + "namespace": "awesome_space" + }, + "last_commit": { + "id": "da1560886d4f094c3e6c9ef40349f7d38b5d27d7", + "message": "fixed readme", + "timestamp": "2012-01-03T23:36:29+02:00", + "url": "http://example.com/awesome_space/awesome_project/commits/da1560886d4f094c3e6c9ef40349f7d38b5d27d7", + "author": { + "name": "GitLab dev user", + "email": "gitlabdev@dv6700.(none)" + } + }, + "url": "http://example.com/diaspora/merge_requests/1", + "action": "open" + } +} +`) + +var PushHook = []byte(` +{ + "object_kind": "push", + "before": "95790bf891e76fee5e1747ab589903a6a1f80f22", + "after": "da1560886d4f094c3e6c9ef40349f7d38b5d27d7", + "ref": "refs/heads/master", + "user_id": 4, + "user_name": "John Smith", + "user_email": "john@example.com", + "project_id": 15, + "repository": { + "name": "Diaspora", + "url": "git@example.com:mike/diasporadiaspora.git", + "description": "", + "homepage": "http://example.com/mike/diaspora", + "git_http_url":"http://example.com/mike/diaspora.git", + "git_ssh_url":"git@example.com:mike/diaspora.git", + "visibility_level":0 + }, + "commits": [ + { + "id": "b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327", + "message": "Update Catalan translation to e38cb41.", + "timestamp": "2011-12-12T14:27:31+02:00", + "url": "http://example.com/mike/diaspora/commit/b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327", + "author": { + "name": "Jordi Mallach", + "email": "jordi@softcatala.org" + } + }, + { + "id": "da1560886d4f094c3e6c9ef40349f7d38b5d27d7", + "message": "fixed readme", + "timestamp": "2012-01-03T23:36:29+02:00", + "url": "http://example.com/mike/diaspora/commit/da1560886d4f094c3e6c9ef40349f7d38b5d27d7", + "author": { + "name": "GitLab dev user", + "email": "gitlabdev@dv6700.(none)" + } + } + ], + "total_commits_count": 4 +} +`) diff --git a/pkg/remote/builtin/gitlab/testdata/oauth.go b/pkg/remote/builtin/gitlab/testdata/oauth.go new file mode 100644 index 000000000..95119d70a --- /dev/null +++ b/pkg/remote/builtin/gitlab/testdata/oauth.go @@ -0,0 +1,3 @@ +package testdata + +var accessTokenPayload = []byte(`access_token=sekret&scope=api&token_type=bearer`) diff --git a/pkg/remote/builtin/gitlab/testdata/projects.go b/pkg/remote/builtin/gitlab/testdata/projects.go new file mode 100644 index 000000000..09bec7366 --- /dev/null +++ b/pkg/remote/builtin/gitlab/testdata/projects.go @@ -0,0 +1,173 @@ +package testdata + +// sample repository list +var projectsPayload = []byte(` +[ + { + "id": 4, + "description": null, + "default_branch": "master", + "public": false, + "visibility_level": 0, + "ssh_url_to_repo": "git@example.com:diaspora/diaspora-client.git", + "http_url_to_repo": "http://example.com/diaspora/diaspora-client.git", + "web_url": "http://example.com/diaspora/diaspora-client", + "owner": { + "id": 3, + "name": "Diaspora", + "created_at": "2013-09-30T13: 46: 02Z" + }, + "name": "Diaspora Client", + "name_with_namespace": "Diaspora / Diaspora Client", + "path": "diaspora-client", + "path_with_namespace": "diaspora/diaspora-client", + "issues_enabled": true, + "merge_requests_enabled": true, + "wiki_enabled": true, + "snippets_enabled": false, + "created_at": "2013-09-30T13: 46: 02Z", + "last_activity_at": "2013-09-30T13: 46: 02Z", + "namespace": { + "created_at": "2013-09-30T13: 46: 02Z", + "description": "", + "id": 3, + "name": "Diaspora", + "owner_id": 1, + "path": "diaspora", + "updated_at": "2013-09-30T13: 46: 02Z" + }, + "archived": false + }, + { + "id": 6, + "description": null, + "default_branch": "master", + "public": false, + "visibility_level": 0, + "ssh_url_to_repo": "git@example.com:brightbox/puppet.git", + "http_url_to_repo": "http://example.com/brightbox/puppet.git", + "web_url": "http://example.com/brightbox/puppet", + "owner": { + "id": 4, + "name": "Brightbox", + "created_at": "2013-09-30T13:46:02Z" + }, + "name": "Puppet", + "name_with_namespace": "Brightbox / Puppet", + "path": "puppet", + "path_with_namespace": "brightbox/puppet", + "issues_enabled": true, + "merge_requests_enabled": true, + "wiki_enabled": true, + "snippets_enabled": false, + "created_at": "2013-09-30T13:46:02Z", + "last_activity_at": "2013-09-30T13:46:02Z", + "namespace": { + "created_at": "2013-09-30T13:46:02Z", + "description": "", + "id": 4, + "name": "Brightbox", + "owner_id": 1, + "path": "brightbox", + "updated_at": "2013-09-30T13:46:02Z" + }, + "archived": false + } +] +`) + +var project4Paylod = []byte(` +{ + "id": 4, + "description": null, + "default_branch": "master", + "public": false, + "visibility_level": 0, + "ssh_url_to_repo": "git@example.com:diaspora/diaspora-client.git", + "http_url_to_repo": "http://example.com/diaspora/diaspora-client.git", + "web_url": "http://example.com/diaspora/diaspora-client", + "owner": { + "id": 3, + "name": "Diaspora", + "created_at": "2013-09-30T13: 46: 02Z" + }, + "name": "Diaspora Client", + "name_with_namespace": "Diaspora / Diaspora Client", + "path": "diaspora-client", + "path_with_namespace": "diaspora/diaspora-client", + "issues_enabled": true, + "merge_requests_enabled": true, + "wiki_enabled": true, + "snippets_enabled": false, + "created_at": "2013-09-30T13: 46: 02Z", + "last_activity_at": "2013-09-30T13: 46: 02Z", + "namespace": { + "created_at": "2013-09-30T13: 46: 02Z", + "description": "", + "id": 3, + "name": "Diaspora", + "owner_id": 1, + "path": "diaspora", + "updated_at": "2013-09-30T13: 46: 02Z" + }, + "archived": false, + "permissions": { + "project_access": { + "access_level": 10, + "notification_level": 3 + }, + "group_access": { + "access_level": 50, + "notification_level": 3 + } + } +} +`) + +var project6Paylod = []byte(` +{ + "id": 6, + "description": null, + "default_branch": "master", + "public": false, + "visibility_level": 0, + "ssh_url_to_repo": "git@example.com:brightbox/puppet.git", + "http_url_to_repo": "http://example.com/brightbox/puppet.git", + "web_url": "http://example.com/brightbox/puppet", + "owner": { + "id": 4, + "name": "Brightbox", + "created_at": "2013-09-30T13:46:02Z" + }, + "name": "Puppet", + "name_with_namespace": "Brightbox / Puppet", + "path": "puppet", + "path_with_namespace": "brightbox/puppet", + "issues_enabled": true, + "merge_requests_enabled": true, + "wiki_enabled": true, + "snippets_enabled": false, + "created_at": "2013-09-30T13:46:02Z", + "last_activity_at": "2013-09-30T13:46:02Z", + "namespace": { + "created_at": "2013-09-30T13:46:02Z", + "description": "", + "id": 4, + "name": "Brightbox", + "owner_id": 1, + "path": "brightbox", + "updated_at": "2013-09-30T13:46:02Z" + }, + "archived": false, + "permissions": { + "project_access": { + "access_level": 10, + "notification_level": 3 + }, + "group_access": { + "access_level": 50, + "notification_level": 3 + } + } +} +`) diff --git a/pkg/remote/builtin/gitlab/testdata/testdata.go b/pkg/remote/builtin/gitlab/testdata/testdata.go new file mode 100644 index 000000000..de36846e1 --- /dev/null +++ b/pkg/remote/builtin/gitlab/testdata/testdata.go @@ -0,0 +1,56 @@ +package testdata + +import ( + "net/http" + "net/http/httptest" +) + +// setup a mock server for testing purposes. +func NewServer() *httptest.Server { + mux := http.NewServeMux() + server := httptest.NewServer(mux) + + // handle requests and serve mock data + mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + //println(r.URL.Path + " " + r.Method) + // evaluate the path to serve a dummy data file + switch r.URL.Path { + case "/api/v3/projects": + w.Write(projectsPayload) + return + case "/api/v3/projects/diaspora/diaspora-client": + w.Write(project4Paylod) + return + case "/api/v3/projects/diaspora/diaspora-client/services/drone-ci": + switch r.Method { + case "PUT": + if r.FormValue("token") == "" { + w.WriteHeader(404) + } else { + w.WriteHeader(201) + } + case "DELETE": + w.WriteHeader(201) + } + + return + case "/oauth/token": + w.Write(accessTokenPayload) + return + case "/api/v3/user": + if r.Header.Get("Authorization") == "Bearer valid_token" { + w.Write(currentUserPayload) + } else { + w.WriteHeader(401) + } + return + } + + // else return a 404 + http.NotFound(w, r) + }) + + // return the server to the client which + // will need to know the base URL path + return server +} diff --git a/pkg/remote/builtin/gitlab/testdata/users.go b/pkg/remote/builtin/gitlab/testdata/users.go new file mode 100644 index 000000000..e7d563697 --- /dev/null +++ b/pkg/remote/builtin/gitlab/testdata/users.go @@ -0,0 +1,24 @@ +package testdata + +var currentUserPayload = []byte(` +{ + "id": 1, + "username": "john_smith", + "email": "john@example.com", + "name": "John Smith", + "private_token": "dd34asd13as", + "state": "active", + "created_at": "2012-05-23T08:00:58Z", + "bio": null, + "skype": "", + "linkedin": "", + "twitter": "", + "website_url": "", + "theme_id": 1, + "color_scheme_id": 2, + "is_admin": false, + "can_create_group": true, + "can_create_project": true, + "projects_limit": 100 +} +`) From ce50e0fd4b5bedfd3e5a7548e268830923f6bfca Mon Sep 17 00:00:00 2001 From: Kirill Zaitsev Date: Sat, 22 Aug 2015 22:55:08 +0300 Subject: [PATCH 13/18] Added push tag event support --- pkg/remote/builtin/gitlab/gitlab.go | 2 +- pkg/remote/builtin/gitlab/gitlab_test.go | 18 +++++++++ pkg/remote/builtin/gitlab/testdata/hooks.go | 44 +++++++++++++++++++++ 3 files changed, 63 insertions(+), 1 deletion(-) diff --git a/pkg/remote/builtin/gitlab/gitlab.go b/pkg/remote/builtin/gitlab/gitlab.go index fc6713163..c6b1bacf3 100644 --- a/pkg/remote/builtin/gitlab/gitlab.go +++ b/pkg/remote/builtin/gitlab/gitlab.go @@ -233,7 +233,7 @@ func (r *Gitlab) Hook(req *http.Request) (*common.Hook, error) { } return mergeRequest(parsed, req) - case "push": + case "tag_push", "push": if len(parsed.After) == 0 || parsed.TotalCommitsCount == 0 { return nil, nil } diff --git a/pkg/remote/builtin/gitlab/gitlab_test.go b/pkg/remote/builtin/gitlab/gitlab_test.go index 832507195..1421f711b 100644 --- a/pkg/remote/builtin/gitlab/gitlab_test.go +++ b/pkg/remote/builtin/gitlab/gitlab_test.go @@ -124,6 +124,24 @@ func Test_Gitlab(t *testing.T) { g.Assert(err == nil).IsTrue() g.Assert(hook.Repo.Owner).Equal("diaspora") g.Assert(hook.Repo.Name).Equal("diaspora-client") + g.Assert(hook.Commit.Ref).Equal("refs/heads/master") + + g.Assert(hook.PullRequest == nil).IsTrue() + }) + + g.It("Should parse tag push hook", func() { + req, _ := http.NewRequest( + "POST", + "http://example.com/api/hook?owner=diaspora&name=diaspora-client", + bytes.NewReader(testdata.TagHook), + ) + + hook, err := gitlab.Hook(req) + + g.Assert(err == nil).IsTrue() + g.Assert(hook.Repo.Owner).Equal("diaspora") + g.Assert(hook.Repo.Name).Equal("diaspora-client") + g.Assert(hook.Commit.Ref).Equal("refs/tags/v1.0.0") g.Assert(hook.PullRequest == nil).IsTrue() }) diff --git a/pkg/remote/builtin/gitlab/testdata/hooks.go b/pkg/remote/builtin/gitlab/testdata/hooks.go index 836d29831..9f4a5cea1 100644 --- a/pkg/remote/builtin/gitlab/testdata/hooks.go +++ b/pkg/remote/builtin/gitlab/testdata/hooks.go @@ -1,5 +1,49 @@ package testdata +var TagHook = []byte(` +{ + "object_kind": "tag_push", + "ref": "refs/tags/v1.0.0", + "before": "0000000000000000000000000000000000000000", + "after": "82b3d5ae55f7080f1e6022629cdb57bfae7cccc7", + "user_id": 1, + "user_name": "John Smith", + "project_id": 1, + "repository": { + "name": "jsmith", + "url": "ssh://git@example.com/jsmith/example.git", + "description": "", + "homepage": "http://example.com/jsmith/example", + "git_http_url":"http://example.com/jsmith/example.git", + "git_ssh_url":"git@example.com:jsmith/example.git", + "visibility_level":0 + }, + "commits": [ + { + "id": "b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327", + "message": "Update Catalan translation to e38cb41.", + "timestamp": "2011-12-12T14:27:31+02:00", + "url": "http://example.com/mike/diaspora/commit/b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327", + "author": { + "name": "Jordi Mallach", + "email": "jordi@softcatala.org" + } + }, + { + "id": "da1560886d4f094c3e6c9ef40349f7d38b5d27d7", + "message": "fixed readme", + "timestamp": "2012-01-03T23:36:29+02:00", + "url": "http://example.com/mike/diaspora/commit/da1560886d4f094c3e6c9ef40349f7d38b5d27d7", + "author": { + "name": "GitLab dev user", + "email": "gitlabdev@dv6700.(none)" + } + } + ], + "total_commits_count": 4 +} +`) + var MergeRequestHook = []byte(` { "object_kind": "merge_request", From 6854d1343eb11ce86235260532ae316566fd5d61 Mon Sep 17 00:00:00 2001 From: Kirilll Zaitsev Date: Sun, 30 Aug 2015 01:18:45 +0300 Subject: [PATCH 14/18] Additional fixes --- cmd/drone-server/drone.go | 10 ++-- pkg/remote/builtin/gitlab/gitlab.go | 7 ++- pkg/server/commits.go | 60 ++++++++++++++++++++---- pkg/server/redirect.go | 11 +++-- pkg/store/builtin/build.go | 15 ++++++ pkg/store/builtin/build_sql.go | 73 ----------------------------- 6 files changed, 87 insertions(+), 89 deletions(-) diff --git a/cmd/drone-server/drone.go b/cmd/drone-server/drone.go index 16001ae55..ea5374b9d 100644 --- a/cmd/drone-server/drone.go +++ b/cmd/drone-server/drone.go @@ -178,8 +178,8 @@ func main() { repo.POST("/watch", server.Subscribe) repo.DELETE("/unwatch", server.Unsubscribe) - repo.GET("/builds", server.GetCommits) - repo.GET("/builds/:number", server.GetCommit) + repo.GET("/builds", server.GetBuilds) + repo.GET("/builds/:number", server.GetBuild) repo.POST("/builds/:number", server.RunBuild) repo.DELETE("/builds/:number", server.KillBuild) repo.GET("/logs/:number/:task", server.GetLogs) @@ -191,7 +191,8 @@ func main() { { repoExternal.Use(server.SetRepo()) - repoExternal.GET("/pr/:number", server.GetPullRequest) + repoExternal.GET("/commits/:sha", server.GetCommit) + repoExternal.GET("/pulls/:number", server.GetPullRequest) } } @@ -249,7 +250,8 @@ func main() { redirects.Use(server.SetDatastore(store)) redirects.Use(server.SetRepo()) - redirects.GET("/:owner/:name/commit/:sha", server.RedirectSha) + redirects.GET("/:owner/:name/commits/:sha", server.RedirectSha) + redirects.GET("/:owner/:name/pulls/:number", server.RedirectPullRequest) } r.SetHTMLTemplate(index()) diff --git a/pkg/remote/builtin/gitlab/gitlab.go b/pkg/remote/builtin/gitlab/gitlab.go index c6b1bacf3..7b67a53c9 100644 --- a/pkg/remote/builtin/gitlab/gitlab.go +++ b/pkg/remote/builtin/gitlab/gitlab.go @@ -199,8 +199,13 @@ func (r *Gitlab) Activate(user *common.User, repo *common.Repo, k *common.Keypai droneUrl := fmt.Sprintf("%s://%s", uri.Scheme, uri.Host) droneToken := uri.Query().Get("access_token") + ssl_verify := strconv.FormatBool(!r.SkipVerify) - return client.AddDroneService(id, map[string]string{"token": droneToken, "drone_url": droneUrl}) + return client.AddDroneService(id, map[string]string{ + "token": droneToken, + "drone_url": droneUrl, + "enable_ssl_verification": ssl_verify, + }) } // Deactivate removes a repository by removing all the post-commit hooks diff --git a/pkg/server/commits.go b/pkg/server/commits.go index cead75400..8455f0b54 100644 --- a/pkg/server/commits.go +++ b/pkg/server/commits.go @@ -20,7 +20,7 @@ import ( // // GET /api/repos/:owner/:name/:number // -func GetCommit(c *gin.Context) { +func GetBuild(c *gin.Context) { store := ToDatastore(c) repo := ToRepo(c) num, err := strconv.Atoi(c.Params.ByName("number")) @@ -41,12 +41,30 @@ func GetCommit(c *gin.Context) { } } +// GetCommits accepts a request to retrieve a list +// of commits from the datastore for the given repository. +// +// GET /api/repos/:owner/:name/builds +// +func GetBuilds(c *gin.Context) { + store := ToDatastore(c) + repo := ToRepo(c) + builds, err := store.BuildList(repo, 20, 0) + if err != nil { + c.Fail(404, err) + } else { + c.JSON(200, builds) + } +} + // GetPullRequest accepts a requests to retvie a pull request // from the datastore for the given repository and // pull request number // -// GET /api/repos/:owner/:name/pr/:number +// GET /api/repos/:owner/:name/pulls/:number // +// REASON: It required by GitLab, becuase we get only +// sha and ref name, but drone uses build numbers func GetPullRequest(c *gin.Context) { store := ToDatastore(c) repo := ToRepo(c) @@ -75,20 +93,46 @@ func GetPullRequest(c *gin.Context) { } } -// GetCommits accepts a request to retrieve a list -// of commits from the datastore for the given repository. +// GetCommit accepts a requests to retvie a sha and branch +// from the datastore for the given repository and +// pull request number // -// GET /api/repos/:owner/:name/builds +// GET /api/repos/:owner/:name/commits/:sha // -func GetCommits(c *gin.Context) { +// REASON: It required by GitLab, becuase we get only +// sha and ref name, but drone uses build numbers +func GetCommit(c *gin.Context) { + var branch string + store := ToDatastore(c) repo := ToRepo(c) - builds, err := store.BuildList(repo, 20, 0) + sha := c.Params.ByName("sha") + + // get the token and verify the hook is authorized + if c.Request.FormValue("access_token") != hash(repo.FullName, repo.Hash) { + c.AbortWithStatus(403) + return + } + + branch = c.Request.FormValue("branch") + if branch == "" { + branch = repo.Branch + } + + build, err := store.BuildSha(repo, sha, branch) + if err != nil { + c.Fail(404, err) + return + } + + build.Jobs, err = store.JobList(build) if err != nil { c.Fail(404, err) } else { - c.JSON(200, builds) + c.JSON(200, build) } + + return } // GetLogs accepts a request to retrieve logs from the diff --git a/pkg/server/redirect.go b/pkg/server/redirect.go index 59a0608f4..cb5657438 100644 --- a/pkg/server/redirect.go +++ b/pkg/server/redirect.go @@ -11,8 +11,10 @@ import ( // to job from the datastore for the given repository // and commit sha // -// GET /redirect/:owner/:name/commit/:sha +// GET /redirect/:owner/:name/commits/:sha // +// REASON: It required by GitLab, becuase we get only +// sha and ref name, but drone uses build numbers func RedirectSha(c *gin.Context) { var branch string @@ -35,12 +37,15 @@ func RedirectSha(c *gin.Context) { return } -// RedirectSha accepts a request to retvie a redirect +// RedirectPullRequest accepts a request to retvie a redirect // to job from the datastore for the given repository // and pull request number // -// GET /redirect/:owner/:name/pr/:number +// GET /redirect/:owner/:name/pulls/:number // +// REASON: It required by GitLab, because we get only +// internal merge request id/ref/sha, but drone uses +// build numbers func RedirectPullRequest(c *gin.Context) { store := ToDatastore(c) repo := ToRepo(c) diff --git a/pkg/store/builtin/build.go b/pkg/store/builtin/build.go index ba14b19e1..5e9ace3eb 100644 --- a/pkg/store/builtin/build.go +++ b/pkg/store/builtin/build.go @@ -112,6 +112,21 @@ func (db *Buildstore) KillBuilds() error { return err2 } +const stmtBuildSelectPullRequestNumber = stmtBuildSelectList + ` +WHERE build_repo_id = ? +AND build_pull_request_number = ? +ORDER BY build_number DESC +LIMIT 1 +` + +const stmtBuildSelectSha = stmtBuildSelectList + ` +WHERE build_repo_id = ? +AND build_commit_sha = ? +AND build_commit_branch = ? +ORDER BY build_number DESC +LIMIT 1 +` + // SQL query to retrieve the latest builds across all branches. const buildListQuery = ` SELECT diff --git a/pkg/store/builtin/build_sql.go b/pkg/store/builtin/build_sql.go index 32b7ce98c..eabc37285 100644 --- a/pkg/store/builtin/build_sql.go +++ b/pkg/store/builtin/build_sql.go @@ -596,79 +596,6 @@ WHERE build_repo_id = ? AND build_number = ? ` -const stmtBuildSelectPullRequestNumber = ` -SELECT - build_id -,build_repo_id -,build_number -,build_status -,build_started -,build_finished -,build_commit_sha -,build_commit_ref -,build_commit_link -,build_commit_branch -,build_commit_message -,build_commit_timestamp -,build_commit_remote -,build_commit_author_login -,build_commit_author_email -,build_pull_request_number -,build_pull_request_title -,build_pull_request_link -,build_pull_request_base_sha -,build_pull_request_base_ref -,build_pull_request_base_link -,build_pull_request_base_branch -,build_pull_request_base_message -,build_pull_request_base_timestamp -,build_pull_request_base_remote -,build_pull_request_base_author_login -,build_pull_request_base_author_email -FROM builds -WHERE build_repo_id = ? -AND build_pull_request_number = ? -ORDER BY build_number DESC -LIMIT 1 -` - -const stmtBuildSelectSha = ` -SELECT - build_id -,build_repo_id -,build_number -,build_status -,build_started -,build_finished -,build_commit_sha -,build_commit_ref -,build_commit_link -,build_commit_branch -,build_commit_message -,build_commit_timestamp -,build_commit_remote -,build_commit_author_login -,build_commit_author_email -,build_pull_request_number -,build_pull_request_title -,build_pull_request_link -,build_pull_request_base_sha -,build_pull_request_base_ref -,build_pull_request_base_link -,build_pull_request_base_branch -,build_pull_request_base_message -,build_pull_request_base_timestamp -,build_pull_request_base_remote -,build_pull_request_base_author_login -,build_pull_request_base_author_email -FROM builds -WHERE build_repo_id = ? -AND build_commit_sha = ? -AND build_commit_branch = ? -ORDER BY build_number DESC -LIMIT 1 -` - const stmtBuildSelectCommitBranch = ` SELECT build_id From 9ded21d7922a9be473779b5916e4717df31f294a Mon Sep 17 00:00:00 2001 From: Kirilll Zaitsev Date: Sun, 30 Aug 2015 03:34:05 +0300 Subject: [PATCH 15/18] Some optimizations --- Godeps/Godeps.json | 2 +- .../examples/projects/main.go | 21 +------------- .../go-gitlab-client/hook_payload.go | 3 +- pkg/remote/builtin/gitlab/gitlab.go | 28 +++++-------------- pkg/remote/builtin/gitlab/gitlab_test.go | 2 +- 5 files changed, 12 insertions(+), 44 deletions(-) diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index 089d4c11e..b2596e4e4 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -12,7 +12,7 @@ }, { "ImportPath": "github.com/Bugagazavr/go-gitlab-client", - "Rev": "fa361f26087a2ff8fbb267fbe2d82037fc35e51a" + "Rev": "e5999f934dc45c41073fc57998a1224a75ff7d50" }, { "ImportPath": "github.com/BurntSushi/migration", diff --git a/Godeps/_workspace/src/github.com/Bugagazavr/go-gitlab-client/examples/projects/main.go b/Godeps/_workspace/src/github.com/Bugagazavr/go-gitlab-client/examples/projects/main.go index 80a3d478d..4eb0b0a6e 100644 --- a/Godeps/_workspace/src/github.com/Bugagazavr/go-gitlab-client/examples/projects/main.go +++ b/Godeps/_workspace/src/github.com/Bugagazavr/go-gitlab-client/examples/projects/main.go @@ -43,8 +43,7 @@ func main() { " > -m merge_requests -id PROJECT_ID\n"+ " > -m merge_request_notes -id PROJECT_ID -merge_id MERGE_REQUEST_ID\n"+ " > -m merge_request_comment -id PROJECT_ID -merge_id MERGE_REQUEST_ID -comment COMMENT_BODY\n"+ - " > -m team -id PROJECT_ID\n"+ - " > -m add_drone -id PROJECT_ID\n -token DRONE_TOKEN -url DRONE_URL") + " > -m team -id PROJECT_ID") var id string flag.StringVar(&id, "id", "", "Specify repository id") @@ -55,12 +54,6 @@ func main() { var comment string flag.StringVar(&comment, "comment", "", "The body of the new comment") - var drone_token string - flag.StringVar(&drone_token, "drone_token", "", "Drone service token") - - var drone_url string - flag.StringVar(&drone_url, "drone_url", "", "Drone service url") - flag.Usage = func() { fmt.Printf("Usage:\n") flag.PrintDefaults() @@ -249,17 +242,5 @@ func main() { for _, member := range members { fmt.Printf("> [%d] %s (%s) since %s\n", member.Id, member.Username, member.Name, member.CreatedAt) } - case "add_drone": - fmt.Println("Adding drone service to project") - - if id == "" || drone_token == "" || drone_url == "" { - flag.Usage() - return - } - - if err := gitlab.AddDroneService(id, map[string]string{"token": drone_token, "drone_url": drone_url}); err != nil { - fmt.Println(err) - return - } } } diff --git a/Godeps/_workspace/src/github.com/Bugagazavr/go-gitlab-client/hook_payload.go b/Godeps/_workspace/src/github.com/Bugagazavr/go-gitlab-client/hook_payload.go index e4c33c0a2..b778e1fb9 100644 --- a/Godeps/_workspace/src/github.com/Bugagazavr/go-gitlab-client/hook_payload.go +++ b/Godeps/_workspace/src/github.com/Bugagazavr/go-gitlab-client/hook_payload.go @@ -27,7 +27,7 @@ type HookObjAttr struct { StDiffs string `json:"st_diffs,omitempty"` MergeStatus string `json:"merge_status,omitempty"` TargetProjectId int `json:"target_project_id,omitempty"` - URL string `json:"url,omitempty"` + Url string `json:"url,omiyempty"` Source *hProject `json:"source,omitempty"` Target *hProject `json:"target,omitempty"` LastCommit *hCommit `json:"last_commit,omitempty"` @@ -38,6 +38,7 @@ type hProject struct { SshUrl string `json:"ssh_url"` HttpUrl string `json:"http_url"` VisibilityLevel int `json:"visibility_level"` + WebUrl string `json:"web_url"` Namespace string `json:"namespace"` } diff --git a/pkg/remote/builtin/gitlab/gitlab.go b/pkg/remote/builtin/gitlab/gitlab.go index 7b67a53c9..74c644851 100644 --- a/pkg/remote/builtin/gitlab/gitlab.go +++ b/pkg/remote/builtin/gitlab/gitlab.go @@ -6,10 +6,8 @@ import ( "io/ioutil" "net/http" "net/url" - "regexp" "strconv" "strings" - "time" "github.com/drone/drone/Godeps/_workspace/src/github.com/Bugagazavr/go-gitlab-client" "github.com/drone/drone/Godeps/_workspace/src/github.com/hashicorp/golang-lru" @@ -232,17 +230,8 @@ func (r *Gitlab) Hook(req *http.Request) (*common.Hook, error) { switch parsed.ObjectKind { case "merge_request": - if parsed.ObjectAttributes.State != "reopened" && parsed.ObjectAttributes.MergeStatus != "unchecked" || - parsed.ObjectAttributes.State != "opened" && parsed.ObjectAttributes.MergeStatus != "unchecked" { - return nil, nil - } - return mergeRequest(parsed, req) case "tag_push", "push": - if len(parsed.After) == 0 || parsed.TotalCommitsCount == 0 { - return nil, nil - } - return push(parsed, req) default: return nil, nil @@ -252,13 +241,11 @@ func (r *Gitlab) Hook(req *http.Request) (*common.Hook, error) { func mergeRequest(parsed *gogitlab.HookPayload, req *http.Request) (*common.Hook, error) { var hook = new(common.Hook) - re := regexp.MustCompile(".git$") - hook.Repo = &common.Repo{} hook.Repo.Owner = req.FormValue("owner") hook.Repo.Name = req.FormValue("name") hook.Repo.FullName = fmt.Sprintf("%s/%s", hook.Repo.Owner, hook.Repo.Name) - hook.Repo.Link = re.ReplaceAllString(parsed.ObjectAttributes.Target.HttpUrl, "$1") + hook.Repo.Link = parsed.ObjectAttributes.Target.WebUrl hook.Repo.Clone = parsed.ObjectAttributes.Target.HttpUrl hook.Repo.Branch = "master" @@ -267,24 +254,23 @@ func mergeRequest(parsed *gogitlab.HookPayload, req *http.Request) (*common.Hook hook.Commit.Sha = parsed.ObjectAttributes.LastCommit.Id hook.Commit.Remote = parsed.ObjectAttributes.Source.HttpUrl - if parsed.ObjectAttributes.Source.HttpUrl == parsed.ObjectAttributes.Target.HttpUrl { + if parsed.ObjectAttributes.SourceProjectId == parsed.ObjectAttributes.TargetProjectId { hook.Commit.Ref = fmt.Sprintf("refs/heads/%s", parsed.ObjectAttributes.SourceBranch) - hook.Commit.Branch = parsed.ObjectAttributes.SourceBranch - hook.Commit.Timestamp = time.Now().UTC().Format("2006-01-02 15:04:05.000000000 +0000 MST") } else { hook.Commit.Ref = fmt.Sprintf("refs/merge-requests/%d/head", parsed.ObjectAttributes.IId) - hook.Commit.Branch = parsed.ObjectAttributes.SourceBranch - hook.Commit.Timestamp = time.Now().UTC().Format("2006-01-02 15:04:05.000000000 +0000 MST") } + hook.Commit.Branch = parsed.ObjectAttributes.SourceBranch + hook.Commit.Timestamp = parsed.ObjectAttributes.LastCommit.Timestamp + hook.Commit.Author = &common.Author{} hook.Commit.Author.Login = parsed.ObjectAttributes.LastCommit.Author.Name hook.Commit.Author.Email = parsed.ObjectAttributes.LastCommit.Author.Email hook.PullRequest = &common.PullRequest{} hook.PullRequest.Number = parsed.ObjectAttributes.IId - hook.PullRequest.Title = parsed.ObjectAttributes.Description - hook.PullRequest.Link = parsed.ObjectAttributes.URL + hook.PullRequest.Title = parsed.ObjectAttributes.Title + hook.PullRequest.Link = parsed.ObjectAttributes.Url return hook, nil } diff --git a/pkg/remote/builtin/gitlab/gitlab_test.go b/pkg/remote/builtin/gitlab/gitlab_test.go index 1421f711b..e694ab930 100644 --- a/pkg/remote/builtin/gitlab/gitlab_test.go +++ b/pkg/remote/builtin/gitlab/gitlab_test.go @@ -160,7 +160,7 @@ func Test_Gitlab(t *testing.T) { g.Assert(hook.Repo.Name).Equal("diaspora-client") g.Assert(hook.PullRequest.Number).Equal(1) - g.Assert(hook.PullRequest.Title).Equal("") + g.Assert(hook.PullRequest.Title).Equal("MS-Viewport") }) }) }) From 8bfc155aee0f7a374375e38927d7074047829422 Mon Sep 17 00:00:00 2001 From: Chengwei Yang Date: Tue, 1 Sep 2015 17:44:30 +0800 Subject: [PATCH 16/18] Fix hook check logic Signed-off-by: Chengwei Yang --- pkg/server/hooks.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/server/hooks.go b/pkg/server/hooks.go index 5a5561add..134621226 100644 --- a/pkg/server/hooks.go +++ b/pkg/server/hooks.go @@ -67,11 +67,11 @@ func PostHook(c *gin.Context) { log.Warnf("ignoring hook. repo %s has no owner.", repo.FullName) c.Writer.WriteHeader(204) return - case !repo.Hooks.Push && hook.PullRequest != nil: + case !repo.Hooks.Push && hook.Commit != nil: log.Infof("ignoring hook. repo %s is disabled.", repo.FullName) c.Writer.WriteHeader(204) return - case !repo.Hooks.PullRequest && hook.PullRequest == nil: + case !repo.Hooks.PullRequest && hook.PullRequest != nil: log.Warnf("ignoring hook. repo %s is disabled for pull requests.", repo.FullName) c.Writer.WriteHeader(204) return From 654dd31cbd377c4e67862fea0273100c14b512f7 Mon Sep 17 00:00:00 2001 From: Kirilll Zaitsev Date: Wed, 2 Sep 2015 05:19:11 +0300 Subject: [PATCH 17/18] Move gitlab routes to gitlab group --- cmd/drone-server/drone.go | 25 +++---- pkg/server/commits.go | 78 --------------------- pkg/server/gitlab.go | 144 ++++++++++++++++++++++++++++++++++++++ pkg/server/redirect.go | 66 ----------------- 4 files changed, 155 insertions(+), 158 deletions(-) create mode 100644 pkg/server/gitlab.go delete mode 100644 pkg/server/redirect.go diff --git a/cmd/drone-server/drone.go b/cmd/drone-server/drone.go index ea5374b9d..3e5977926 100644 --- a/cmd/drone-server/drone.go +++ b/cmd/drone-server/drone.go @@ -185,15 +185,6 @@ func main() { repo.GET("/logs/:number/:task", server.GetLogs) // repo.POST("/status/:number", server.PostBuildStatus) } - - // Routes for external services - repoExternal := repos.Group("") - { - repoExternal.Use(server.SetRepo()) - - repoExternal.GET("/commits/:sha", server.GetCommit) - repoExternal.GET("/pulls/:number", server.GetPullRequest) - } } badges := api.Group("/badges/:owner/:name") @@ -245,13 +236,19 @@ func main() { auth.POST("", server.GetLogin) } - redirects := r.Group("/redirect") + gitlab := r.Group("/gitlab/:owner/:name") { - redirects.Use(server.SetDatastore(store)) - redirects.Use(server.SetRepo()) + gitlab.Use(server.SetDatastore(store)) + gitlab.Use(server.SetRepo()) - redirects.GET("/:owner/:name/commits/:sha", server.RedirectSha) - redirects.GET("/:owner/:name/pulls/:number", server.RedirectPullRequest) + gitlab.GET("/commits/:sha", server.GetCommit) + gitlab.GET("/pulls/:number", server.GetPullRequest) + + redirects := gitlab.Group("/redirect") + { + redirects.GET("/commits/:sha", server.RedirectSha) + redirects.GET("/pulls/:number", server.RedirectPullRequest) + } } r.SetHTMLTemplate(index()) diff --git a/pkg/server/commits.go b/pkg/server/commits.go index 8455f0b54..3c75faad5 100644 --- a/pkg/server/commits.go +++ b/pkg/server/commits.go @@ -57,84 +57,6 @@ func GetBuilds(c *gin.Context) { } } -// GetPullRequest accepts a requests to retvie a pull request -// from the datastore for the given repository and -// pull request number -// -// GET /api/repos/:owner/:name/pulls/:number -// -// REASON: It required by GitLab, becuase we get only -// sha and ref name, but drone uses build numbers -func GetPullRequest(c *gin.Context) { - store := ToDatastore(c) - repo := ToRepo(c) - - // get the token and verify the hook is authorized - if c.Request.FormValue("access_token") != hash(repo.FullName, repo.Hash) { - c.AbortWithStatus(403) - return - } - - num, err := strconv.Atoi(c.Params.ByName("number")) - if err != nil { - c.Fail(400, err) - return - } - build, err := store.BuildPullRequestNumber(repo, num) - if err != nil { - c.Fail(404, err) - return - } - build.Jobs, err = store.JobList(build) - if err != nil { - c.Fail(404, err) - } else { - c.JSON(200, build) - } -} - -// GetCommit accepts a requests to retvie a sha and branch -// from the datastore for the given repository and -// pull request number -// -// GET /api/repos/:owner/:name/commits/:sha -// -// REASON: It required by GitLab, becuase we get only -// sha and ref name, but drone uses build numbers -func GetCommit(c *gin.Context) { - var branch string - - store := ToDatastore(c) - repo := ToRepo(c) - sha := c.Params.ByName("sha") - - // get the token and verify the hook is authorized - if c.Request.FormValue("access_token") != hash(repo.FullName, repo.Hash) { - c.AbortWithStatus(403) - return - } - - branch = c.Request.FormValue("branch") - if branch == "" { - branch = repo.Branch - } - - build, err := store.BuildSha(repo, sha, branch) - if err != nil { - c.Fail(404, err) - return - } - - build.Jobs, err = store.JobList(build) - if err != nil { - c.Fail(404, err) - } else { - c.JSON(200, build) - } - - return -} - // GetLogs accepts a request to retrieve logs from the // datastore for the given repository, build and task // number. diff --git a/pkg/server/gitlab.go b/pkg/server/gitlab.go new file mode 100644 index 000000000..69a4caf1f --- /dev/null +++ b/pkg/server/gitlab.go @@ -0,0 +1,144 @@ +package server + +import ( + "fmt" + "strconv" + + "github.com/drone/drone/Godeps/_workspace/src/github.com/gin-gonic/gin" +) + +// RedirectSha accepts a request to retvie a redirect +// to job from the datastore for the given repository +// and commit sha +// +// GET /gitlab/:owner/:name/redirect/commits/:sha +// +// REASON: It required by GitLab, becuase we get only +// sha and ref name, but drone uses build numbers +func RedirectSha(c *gin.Context) { + var branch string + + store := ToDatastore(c) + repo := ToRepo(c) + sha := c.Params.ByName("sha") + + branch = c.Request.FormValue("branch") + if branch == "" { + branch = repo.Branch + } + + build, err := store.BuildSha(repo, sha, branch) + if err != nil { + c.Redirect(301, "/") + return + } + + c.Redirect(301, fmt.Sprintf("/%s/%s/%d", repo.Owner, repo.Name, build.ID)) + return +} + +// RedirectPullRequest accepts a request to retvie a redirect +// to job from the datastore for the given repository +// and pull request number +// +// GET /gitlab/:owner/:name/redirect/pulls/:number +// +// REASON: It required by GitLab, because we get only +// internal merge request id/ref/sha, but drone uses +// build numbers +func RedirectPullRequest(c *gin.Context) { + store := ToDatastore(c) + repo := ToRepo(c) + num, err := strconv.Atoi(c.Params.ByName("number")) + if err != nil { + c.Redirect(301, "/") + return + } + + build, err := store.BuildPullRequestNumber(repo, num) + if err != nil { + c.Redirect(301, "/") + return + } + + c.Redirect(301, fmt.Sprintf("/%s/%s/%d", repo.Owner, repo.Name, build.ID)) + return +} + +// GetPullRequest accepts a requests to retvie a pull request +// from the datastore for the given repository and +// pull request number +// +// GET /gitlab/:owner/:name/pulls/:number +// +// REASON: It required by GitLab, becuase we get only +// sha and ref name, but drone uses build numbers +func GetPullRequest(c *gin.Context) { + store := ToDatastore(c) + repo := ToRepo(c) + + // get the token and verify the hook is authorized + if c.Request.FormValue("access_token") != hash(repo.FullName, repo.Hash) { + c.AbortWithStatus(403) + return + } + + num, err := strconv.Atoi(c.Params.ByName("number")) + if err != nil { + c.Fail(400, err) + return + } + build, err := store.BuildPullRequestNumber(repo, num) + if err != nil { + c.Fail(404, err) + return + } + build.Jobs, err = store.JobList(build) + if err != nil { + c.Fail(404, err) + } else { + c.JSON(200, build) + } +} + +// GetCommit accepts a requests to retvie a sha and branch +// from the datastore for the given repository and +// pull request number +// +// GET /gitlab/:owner/:name/commits/:sha +// +// REASON: It required by GitLab, becuase we get only +// sha and ref name, but drone uses build numbers +func GetCommit(c *gin.Context) { + var branch string + + store := ToDatastore(c) + repo := ToRepo(c) + sha := c.Params.ByName("sha") + + // get the token and verify the hook is authorized + if c.Request.FormValue("access_token") != hash(repo.FullName, repo.Hash) { + c.AbortWithStatus(403) + return + } + + branch = c.Request.FormValue("branch") + if branch == "" { + branch = repo.Branch + } + + build, err := store.BuildSha(repo, sha, branch) + if err != nil { + c.Fail(404, err) + return + } + + build.Jobs, err = store.JobList(build) + if err != nil { + c.Fail(404, err) + } else { + c.JSON(200, build) + } + + return +} diff --git a/pkg/server/redirect.go b/pkg/server/redirect.go deleted file mode 100644 index cb5657438..000000000 --- a/pkg/server/redirect.go +++ /dev/null @@ -1,66 +0,0 @@ -package server - -import ( - "fmt" - "strconv" - - "github.com/drone/drone/Godeps/_workspace/src/github.com/gin-gonic/gin" -) - -// RedirectSha accepts a request to retvie a redirect -// to job from the datastore for the given repository -// and commit sha -// -// GET /redirect/:owner/:name/commits/:sha -// -// REASON: It required by GitLab, becuase we get only -// sha and ref name, but drone uses build numbers -func RedirectSha(c *gin.Context) { - var branch string - - store := ToDatastore(c) - repo := ToRepo(c) - sha := c.Params.ByName("sha") - - branch = c.Request.FormValue("branch") - if branch == "" { - branch = repo.Branch - } - - build, err := store.BuildSha(repo, sha, branch) - if err != nil { - c.Redirect(301, "/") - return - } - - c.Redirect(301, fmt.Sprintf("/%s/%s/%d", repo.Owner, repo.Name, build.ID)) - return -} - -// RedirectPullRequest accepts a request to retvie a redirect -// to job from the datastore for the given repository -// and pull request number -// -// GET /redirect/:owner/:name/pulls/:number -// -// REASON: It required by GitLab, because we get only -// internal merge request id/ref/sha, but drone uses -// build numbers -func RedirectPullRequest(c *gin.Context) { - store := ToDatastore(c) - repo := ToRepo(c) - num, err := strconv.Atoi(c.Params.ByName("number")) - if err != nil { - c.Redirect(301, "/") - return - } - - build, err := store.BuildPullRequestNumber(repo, num) - if err != nil { - c.Redirect(301, "/") - return - } - - c.Redirect(301, fmt.Sprintf("/%s/%s/%d", repo.Owner, repo.Name, build.ID)) - return -} From e2cdde02bc16b87eb764bf8507c463efb513b9b5 Mon Sep 17 00:00:00 2001 From: Kirilll Zaitsev Date: Wed, 2 Sep 2015 06:42:18 +0300 Subject: [PATCH 18/18] Added clone mode for gitlab, use token mode as default --- doc/setup/gitlab.md | 1 + pkg/hash/hash.go | 12 +++++ pkg/remote/builtin/github/github.go | 2 +- pkg/remote/builtin/gitlab/gitlab.go | 84 +++++++++++++++++------------ pkg/remote/remote.go | 2 +- pkg/server/commits.go | 2 +- pkg/server/gitlab.go | 6 ++- pkg/server/hooks.go | 5 +- pkg/server/repos.go | 11 +--- 9 files changed, 75 insertions(+), 50 deletions(-) create mode 100644 pkg/hash/hash.go diff --git a/doc/setup/gitlab.md b/doc/setup/gitlab.md index cc3dbff47..edcd2afab 100644 --- a/doc/setup/gitlab.md +++ b/doc/setup/gitlab.md @@ -31,6 +31,7 @@ This section lists all connection options used in the connection string format. * `open=false` allows users to self-register. Defaults to false for security reasons. * `orgs=drone,docker` restricts access to these GitLab organizations. **Optional** * `skip_verify=false` skip ca verification if self-signed certificate. Defaults to false for security reasons. +* `clone_mode=token` a strategy for clone authorization, by default use repo token, but can be changed to `oauth` ( This is not secure, because your user token, with full access to your gitlab account will be written to .netrc, and it can be read by all who have access to project builds ) ## Gitlab registration diff --git a/pkg/hash/hash.go b/pkg/hash/hash.go new file mode 100644 index 000000000..3950244cb --- /dev/null +++ b/pkg/hash/hash.go @@ -0,0 +1,12 @@ +package hash + +import ( + "crypto/sha256" + "encoding/hex" +) + +func New(text, salt string) string { + hasher := sha256.New() + hasher.Write([]byte(text + salt)) + return hex.EncodeToString(hasher.Sum(nil)) +} diff --git a/pkg/remote/builtin/github/github.go b/pkg/remote/builtin/github/github.go index 40173ff34..4829565fc 100644 --- a/pkg/remote/builtin/github/github.go +++ b/pkg/remote/builtin/github/github.go @@ -170,7 +170,7 @@ func (g *GitHub) Script(u *common.User, r *common.Repo, b *common.Build) ([]byte // Netrc returns a .netrc file that can be used to clone // private repositories from a remote system. -func (g *GitHub) Netrc(u *common.User) (*common.Netrc, error) { +func (g *GitHub) Netrc(u *common.User, r *common.Repo) (*common.Netrc, error) { url_, err := url.Parse(g.URL) if err != nil { return nil, err diff --git a/pkg/remote/builtin/gitlab/gitlab.go b/pkg/remote/builtin/gitlab/gitlab.go index 74c644851..c100d21c2 100644 --- a/pkg/remote/builtin/gitlab/gitlab.go +++ b/pkg/remote/builtin/gitlab/gitlab.go @@ -11,6 +11,7 @@ import ( "github.com/drone/drone/Godeps/_workspace/src/github.com/Bugagazavr/go-gitlab-client" "github.com/drone/drone/Godeps/_workspace/src/github.com/hashicorp/golang-lru" + "github.com/drone/drone/pkg/hash" "github.com/drone/drone/pkg/oauth2" "github.com/drone/drone/pkg/remote" common "github.com/drone/drone/pkg/types" @@ -26,6 +27,7 @@ type Gitlab struct { Client string Secret string AllowedOrgs []string + CloneMode string Open bool PrivateMode bool SkipVerify bool @@ -54,6 +56,13 @@ func NewDriver(config string) (remote.Remote, error) { gitlab.SkipVerify, _ = strconv.ParseBool(params.Get("skip_verify")) gitlab.Open, _ = strconv.ParseBool(params.Get("open")) + switch params.Get("clone_mode") { + case "oauth": + gitlab.CloneMode = "oauth" + default: + gitlab.CloneMode = "token" + } + // this is a temp workaround gitlab.Search, _ = strconv.ParseBool(params.Get("search")) @@ -64,8 +73,8 @@ func NewDriver(config string) (remote.Remote, error) { return &gitlab, err } -func (r *Gitlab) Login(token, secret string) (*common.User, error) { - client := NewClient(r.URL, token, r.SkipVerify) +func (g *Gitlab) Login(token, secret string) (*common.User, error) { + client := NewClient(g.URL, token, g.SkipVerify) var login, err = client.CurrentUser() if err != nil { return nil, err @@ -79,20 +88,20 @@ func (r *Gitlab) Login(token, secret string) (*common.User, error) { if strings.HasPrefix(login.AvatarUrl, "http") { user.Avatar = login.AvatarUrl } else { - user.Avatar = r.URL + "/" + login.AvatarUrl + user.Avatar = g.URL + "/" + login.AvatarUrl } return &user, nil } // Orgs fetches the organizations for the given user. -func (r *Gitlab) Orgs(u *common.User) ([]string, error) { +func (g *Gitlab) Orgs(u *common.User) ([]string, error) { return nil, nil } // Repo fetches the named repository from the remote system. -func (r *Gitlab) Repo(u *common.User, owner, name string) (*common.Repo, error) { - client := NewClient(r.URL, u.Token, r.SkipVerify) - id, err := GetProjectId(r, client, owner, name) +func (g *Gitlab) Repo(u *common.User, owner, name string) (*common.Repo, error) { + client := NewClient(g.URL, u.Token, g.SkipVerify) + id, err := GetProjectId(g, client, owner, name) if err != nil { return nil, err } @@ -113,7 +122,7 @@ func (r *Gitlab) Repo(u *common.User, owner, name string) (*common.Repo, error) repo.Branch = repo_.DefaultBranch } - if r.PrivateMode { + if g.PrivateMode { repo.Private = true } else { repo.Private = !repo_.Public @@ -123,15 +132,15 @@ func (r *Gitlab) Repo(u *common.User, owner, name string) (*common.Repo, error) } // Perm fetches the named repository from the remote system. -func (r *Gitlab) Perm(u *common.User, owner, name string) (*common.Perm, error) { +func (g *Gitlab) Perm(u *common.User, owner, name string) (*common.Perm, error) { key := fmt.Sprintf("%s/%s/%s", u.Login, owner, name) - val, ok := r.cache.Get(key) + val, ok := g.cache.Get(key) if ok { return val.(*common.Perm), nil } - client := NewClient(r.URL, u.Token, r.SkipVerify) - id, err := GetProjectId(r, client, owner, name) + client := NewClient(g.URL, u.Token, g.SkipVerify) + id, err := GetProjectId(g, client, owner, name) if err != nil { return nil, err } @@ -144,15 +153,15 @@ func (r *Gitlab) Perm(u *common.User, owner, name string) (*common.Perm, error) m.Admin = IsAdmin(repo) m.Pull = IsRead(repo) m.Push = IsWrite(repo) - r.cache.Add(key, m) + g.cache.Add(key, m) return m, nil } // GetScript fetches the build script (.drone.yml) from the remote // repository and returns in string format. -func (r *Gitlab) Script(user *common.User, repo *common.Repo, build *common.Build) ([]byte, error) { - var client = NewClient(r.URL, user.Token, r.SkipVerify) - id, err := GetProjectId(r, client, repo.Owner, repo.Name) +func (g *Gitlab) Script(user *common.User, repo *common.Repo, build *common.Build) ([]byte, error) { + var client = NewClient(g.URL, user.Token, g.SkipVerify) + id, err := GetProjectId(g, client, repo.Owner, repo.Name) if err != nil { return nil, err } @@ -163,29 +172,36 @@ func (r *Gitlab) Script(user *common.User, repo *common.Repo, build *common.Buil // NOTE Currently gitlab doesn't support status for commits and events, // 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 (r *Gitlab) Status(u *common.User, repo *common.Repo, b *common.Build) error { +func (g *Gitlab) Status(u *common.User, repo *common.Repo, b *common.Build) error { return nil } // Netrc returns a .netrc file that can be used to clone // private repositories from a remote system. -func (r *Gitlab) Netrc(u *common.User) (*common.Netrc, error) { - url_, err := url.Parse(r.URL) +func (g *Gitlab) Netrc(u *common.User, r *common.Repo) (*common.Netrc, error) { + url_, err := url.Parse(g.URL) if err != nil { return nil, err } netrc := &common.Netrc{} - netrc.Login = "oauth2" - netrc.Password = u.Token + + switch g.CloneMode { + case "oauth": + netrc.Login = "oauth2" + netrc.Password = u.Token + case "token": + netrc.Login = "drone-ci-token" + netrc.Password = hash.New(r.FullName, r.Hash) + } netrc.Machine = url_.Host return netrc, nil } // Activate activates a repository by adding a Post-commit hook and // a Public Deploy key, if applicable. -func (r *Gitlab) Activate(user *common.User, repo *common.Repo, k *common.Keypair, link string) error { - var client = NewClient(r.URL, user.Token, r.SkipVerify) - id, err := GetProjectId(r, client, repo.Owner, repo.Name) +func (g *Gitlab) Activate(user *common.User, repo *common.Repo, k *common.Keypair, link string) error { + var client = NewClient(g.URL, user.Token, g.SkipVerify) + id, err := GetProjectId(g, client, repo.Owner, repo.Name) if err != nil { return err } @@ -197,7 +213,7 @@ func (r *Gitlab) Activate(user *common.User, repo *common.Repo, k *common.Keypai droneUrl := fmt.Sprintf("%s://%s", uri.Scheme, uri.Host) droneToken := uri.Query().Get("access_token") - ssl_verify := strconv.FormatBool(!r.SkipVerify) + ssl_verify := strconv.FormatBool(!g.SkipVerify) return client.AddDroneService(id, map[string]string{ "token": droneToken, @@ -208,9 +224,9 @@ func (r *Gitlab) Activate(user *common.User, repo *common.Repo, k *common.Keypai // Deactivate removes a repository by removing all the post-commit hooks // which are equal to link and removing the SSH deploy key. -func (r *Gitlab) Deactivate(user *common.User, repo *common.Repo, link string) error { - var client = NewClient(r.URL, user.Token, r.SkipVerify) - id, err := GetProjectId(r, client, repo.Owner, repo.Name) +func (g *Gitlab) Deactivate(user *common.User, repo *common.Repo, link string) error { + var client = NewClient(g.URL, user.Token, g.SkipVerify) + id, err := GetProjectId(g, client, repo.Owner, repo.Name) if err != nil { return err } @@ -220,7 +236,7 @@ func (r *Gitlab) Deactivate(user *common.User, repo *common.Repo, link string) e // ParseHook parses the post-commit hook from the Request body // and returns the required data in a standard format. -func (r *Gitlab) Hook(req *http.Request) (*common.Hook, error) { +func (g *Gitlab) Hook(req *http.Request) (*common.Hook, error) { defer req.Body.Close() var payload, _ = ioutil.ReadAll(req.Body) var parsed, err = gogitlab.ParseHook(payload) @@ -341,16 +357,16 @@ func (g *Gitlab) Oauth2Transport(r *http.Request) *oauth2.Transport { } // Accessor method, to allowed remote organizations field. -func (r *Gitlab) GetOrgs() []string { - return r.AllowedOrgs +func (g *Gitlab) GetOrgs() []string { + return g.AllowedOrgs } // Accessor method, to open field. -func (r *Gitlab) GetOpen() bool { - return r.Open +func (g *Gitlab) GetOpen() bool { + return g.Open } // return default scope for GitHub -func (r *Gitlab) Scope() string { +func (g *Gitlab) Scope() string { return DefaultScope } diff --git a/pkg/remote/remote.go b/pkg/remote/remote.go index 7453a7856..9d6367414 100644 --- a/pkg/remote/remote.go +++ b/pkg/remote/remote.go @@ -64,7 +64,7 @@ type Remote interface { // Netrc returns a .netrc file that can be used to clone // private repositories from a remote system. - Netrc(u *types.User) (*types.Netrc, error) + Netrc(u *types.User, r *types.Repo) (*types.Netrc, error) // Activate activates a repository by creating the post-commit hook and // adding the SSH deploy key, if applicable. diff --git a/pkg/server/commits.go b/pkg/server/commits.go index 3c75faad5..c2a97eb0c 100644 --- a/pkg/server/commits.go +++ b/pkg/server/commits.go @@ -166,7 +166,7 @@ func RunBuild(c *gin.Context) { return } - netrc, err := remote.Netrc(user) + netrc, err := remote.Netrc(user, repo) if err != nil { c.Fail(500, err) return diff --git a/pkg/server/gitlab.go b/pkg/server/gitlab.go index 69a4caf1f..adbf53b98 100644 --- a/pkg/server/gitlab.go +++ b/pkg/server/gitlab.go @@ -5,6 +5,8 @@ import ( "strconv" "github.com/drone/drone/Godeps/_workspace/src/github.com/gin-gonic/gin" + + "github.com/drone/drone/pkg/hash" ) // RedirectSha accepts a request to retvie a redirect @@ -78,7 +80,7 @@ func GetPullRequest(c *gin.Context) { repo := ToRepo(c) // get the token and verify the hook is authorized - if c.Request.FormValue("access_token") != hash(repo.FullName, repo.Hash) { + if c.Request.FormValue("access_token") != hash.New(repo.FullName, repo.Hash) { c.AbortWithStatus(403) return } @@ -117,7 +119,7 @@ func GetCommit(c *gin.Context) { sha := c.Params.ByName("sha") // get the token and verify the hook is authorized - if c.Request.FormValue("access_token") != hash(repo.FullName, repo.Hash) { + if c.Request.FormValue("access_token") != hash.New(repo.FullName, repo.Hash) { c.AbortWithStatus(403) return } diff --git a/pkg/server/hooks.go b/pkg/server/hooks.go index 134621226..d54caa1db 100644 --- a/pkg/server/hooks.go +++ b/pkg/server/hooks.go @@ -5,6 +5,7 @@ import ( log "github.com/drone/drone/Godeps/_workspace/src/github.com/Sirupsen/logrus" "github.com/drone/drone/Godeps/_workspace/src/github.com/gin-gonic/gin" + "github.com/drone/drone/pkg/hash" "github.com/drone/drone/pkg/queue" common "github.com/drone/drone/pkg/types" "github.com/drone/drone/pkg/yaml" @@ -56,7 +57,7 @@ func PostHook(c *gin.Context) { } // get the token and verify the hook is authorized - if c.Request.FormValue("access_token") != hash(repo.FullName, repo.Hash) { + if c.Request.FormValue("access_token") != hash.New(repo.FullName, repo.Hash) { log.Errorf("invalid token sent with hook.") c.AbortWithStatus(403) return @@ -128,7 +129,7 @@ func PostHook(c *gin.Context) { }) } - netrc, err := remote.Netrc(user) + netrc, err := remote.Netrc(user, repo) if err != nil { log.Errorf("failure to generate netrc for %s. %s", repo.FullName, err) c.Fail(500, err) diff --git a/pkg/server/repos.go b/pkg/server/repos.go index 8e7809160..09933faaa 100644 --- a/pkg/server/repos.go +++ b/pkg/server/repos.go @@ -1,14 +1,13 @@ package server import ( - "crypto/sha256" - "encoding/hex" "encoding/json" "fmt" "github.com/drone/drone/Godeps/_workspace/src/github.com/gin-gonic/gin" "github.com/drone/drone/Godeps/_workspace/src/github.com/gin-gonic/gin/binding" + "github.com/drone/drone/pkg/hash" "github.com/drone/drone/pkg/remote" common "github.com/drone/drone/pkg/types" "github.com/drone/drone/pkg/utils/httputil" @@ -209,7 +208,7 @@ func PostRepo(c *gin.Context) { link := fmt.Sprintf( "%s/api/hook?access_token=%s", httputil.GetURL(c.Request), - hash(r.FullName, r.Hash), + hash.New(r.FullName, r.Hash), ) // generate an RSA key and add to the repo @@ -316,9 +315,3 @@ func perms(remote remote.Remote, u *common.User, r *common.Repo) *common.Perm { } return p } - -func hash(text, salt string) string { - hasher := sha256.New() - hasher.Write([]byte(text + salt)) - return hex.EncodeToString(hasher.Sum(nil)) -}