github.com/kvattikuti/drone@v0.2.1-0.20140603034306-d400229a327a/pkg/handler/bitbucket.go (about) 1 package handler 2 3 import ( 4 "database/sql" 5 "net/http" 6 "time" 7 8 "github.com/drone/drone/pkg/build/script" 9 "github.com/drone/drone/pkg/database" 10 . "github.com/drone/drone/pkg/model" 11 "github.com/drone/drone/pkg/queue" 12 "github.com/drone/go-bitbucket/bitbucket" 13 ) 14 15 type BitbucketHandler struct { 16 queue *queue.Queue 17 } 18 19 func NewBitbucketHandler(queue *queue.Queue) *BitbucketHandler { 20 return &BitbucketHandler{ 21 queue: queue, 22 } 23 } 24 25 // Processes a generic POST-RECEIVE Bitbucket hook and 26 // attempts to trigger a build. 27 func (h *BitbucketHandler) Hook(w http.ResponseWriter, r *http.Request) error { 28 // get the payload from the request 29 payload := r.FormValue("payload") 30 31 // parse the post-commit hook 32 hook, err := bitbucket.ParseHook([]byte(payload)) 33 if err != nil { 34 return err 35 } 36 37 // get the repo from the URL 38 repoId := r.FormValue("id") 39 40 // get the repo from the database, return error if not found 41 repo, err := database.GetRepoSlug(repoId) 42 if err != nil { 43 return RenderText(w, http.StatusText(http.StatusNotFound), http.StatusNotFound) 44 } 45 46 // Get the user that owns the repository 47 user, err := database.GetUser(repo.UserID) 48 if err != nil { 49 return RenderText(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest) 50 } 51 52 // Verify that the commit doesn't already exist. 53 // We should never build the same commit twice. 54 _, err = database.GetCommitHash(hook.Commits[len(hook.Commits)-1].Hash, repo.ID) 55 if err != nil && err != sql.ErrNoRows { 56 return RenderText(w, http.StatusText(http.StatusBadGateway), http.StatusBadGateway) 57 } 58 59 commit := &Commit{} 60 commit.RepoID = repo.ID 61 commit.Branch = hook.Commits[len(hook.Commits)-1].Branch 62 commit.Hash = hook.Commits[len(hook.Commits)-1].Hash 63 commit.Status = "Pending" 64 commit.Created = time.Now().UTC() 65 commit.Message = hook.Commits[len(hook.Commits)-1].Message 66 commit.Timestamp = time.Now().UTC().String() 67 commit.SetAuthor(hook.Commits[len(hook.Commits)-1].Author) 68 69 // get the github settings from the database 70 settings := database.SettingsMust() 71 72 // create the Bitbucket client 73 client := bitbucket.New( 74 settings.BitbucketKey, 75 settings.BitbucketSecret, 76 user.BitbucketToken, 77 user.BitbucketSecret, 78 ) 79 80 // get the yaml from the database 81 raw, err := client.Sources.Find(repo.Owner, repo.Name, commit.Hash, ".drone.yml") 82 if err != nil { 83 return RenderText(w, http.StatusText(http.StatusNotFound), http.StatusNotFound) 84 } 85 86 // parse the build script 87 buildscript, err := script.ParseBuild([]byte(raw.Data), repo.Params) 88 if err != nil { 89 msg := "Could not parse your .drone.yml file. It needs to be a valid drone yaml file.\n\n" + err.Error() + "\n" 90 if err := saveFailedBuild(commit, msg); err != nil { 91 return RenderText(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) 92 } 93 return RenderText(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest) 94 } 95 96 // save the commit to the database 97 if err := database.SaveCommit(commit); err != nil { 98 return RenderText(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) 99 } 100 101 // save the build to the database 102 build := &Build{} 103 build.Slug = "1" // TODO 104 build.CommitID = commit.ID 105 build.Created = time.Now().UTC() 106 build.Status = "Pending" 107 if err := database.SaveBuild(build); err != nil { 108 return RenderText(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) 109 } 110 111 // send the build to the queue 112 h.queue.Add(&queue.BuildTask{Repo: repo, Commit: commit, Build: build, Script: buildscript}) 113 114 // OK! 115 return RenderText(w, http.StatusText(http.StatusOK), http.StatusOK) 116 }