117 lines
3.5 KiB
Go
117 lines
3.5 KiB
Go
|
package handler
|
||
|
|
||
|
import (
|
||
|
"database/sql"
|
||
|
"net/http"
|
||
|
"time"
|
||
|
|
||
|
"github.com/drone/drone/pkg/build/script"
|
||
|
"github.com/drone/drone/pkg/database"
|
||
|
. "github.com/drone/drone/pkg/model"
|
||
|
"github.com/drone/drone/pkg/queue"
|
||
|
"github.com/drone/go-bitbucket/bitbucket"
|
||
|
)
|
||
|
|
||
|
type BitbucketHandler struct {
|
||
|
queue *queue.Queue
|
||
|
}
|
||
|
|
||
|
func NewBitbucketHandler(queue *queue.Queue) *BitbucketHandler {
|
||
|
return &BitbucketHandler{
|
||
|
queue: queue,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Processes a generic POST-RECEIVE Bitbucket hook and
|
||
|
// attempts to trigger a build.
|
||
|
func (h *BitbucketHandler) Hook(w http.ResponseWriter, r *http.Request) error {
|
||
|
// get the payload from the request
|
||
|
payload := r.FormValue("payload")
|
||
|
|
||
|
// parse the post-commit hook
|
||
|
hook, err := bitbucket.ParseHook([]byte(payload))
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
// get the repo from the URL
|
||
|
repoId := r.FormValue("id")
|
||
|
|
||
|
// get the repo from the database, return error if not found
|
||
|
repo, err := database.GetRepoSlug(repoId)
|
||
|
if err != nil {
|
||
|
return RenderText(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
|
||
|
}
|
||
|
|
||
|
// Get the user that owns the repository
|
||
|
user, err := database.GetUser(repo.UserID)
|
||
|
if err != nil {
|
||
|
return RenderText(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
|
||
|
}
|
||
|
|
||
|
// Verify that the commit doesn't already exist.
|
||
|
// We should never build the same commit twice.
|
||
|
_, err = database.GetCommitHash(hook.Commits[len(hook.Commits)-1].Hash, repo.ID)
|
||
|
if err != nil && err != sql.ErrNoRows {
|
||
|
return RenderText(w, http.StatusText(http.StatusBadGateway), http.StatusBadGateway)
|
||
|
}
|
||
|
|
||
|
commit := &Commit{}
|
||
|
commit.RepoID = repo.ID
|
||
|
commit.Branch = hook.Commits[len(hook.Commits)-1].Branch
|
||
|
commit.Hash = hook.Commits[len(hook.Commits)-1].Hash
|
||
|
commit.Status = "Pending"
|
||
|
commit.Created = time.Now().UTC()
|
||
|
commit.Message = hook.Commits[len(hook.Commits)-1].Message
|
||
|
commit.Timestamp = time.Now().UTC().String()
|
||
|
commit.SetAuthor(hook.Commits[len(hook.Commits)-1].Author)
|
||
|
|
||
|
// get the github settings from the database
|
||
|
settings := database.SettingsMust()
|
||
|
|
||
|
// create the Bitbucket client
|
||
|
client := bitbucket.New(
|
||
|
settings.BitbucketKey,
|
||
|
settings.BitbucketSecret,
|
||
|
user.BitbucketToken,
|
||
|
user.BitbucketSecret,
|
||
|
)
|
||
|
|
||
|
// get the yaml from the database
|
||
|
raw, err := client.Sources.Find(repo.Owner, repo.Name, commit.Hash, ".drone.yml")
|
||
|
if err != nil {
|
||
|
return RenderText(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
|
||
|
}
|
||
|
|
||
|
// parse the build script
|
||
|
buildscript, err := script.ParseBuild([]byte(raw.Data), repo.Params)
|
||
|
if err != nil {
|
||
|
msg := "Could not parse your .drone.yml file. It needs to be a valid drone yaml file.\n\n" + err.Error() + "\n"
|
||
|
if err := saveFailedBuild(commit, msg); err != nil {
|
||
|
return RenderText(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
||
|
}
|
||
|
return RenderText(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
|
||
|
}
|
||
|
|
||
|
// save the commit to the database
|
||
|
if err := database.SaveCommit(commit); err != nil {
|
||
|
return RenderText(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
||
|
}
|
||
|
|
||
|
// save the build to the database
|
||
|
build := &Build{}
|
||
|
build.Slug = "1" // TODO
|
||
|
build.CommitID = commit.ID
|
||
|
build.Created = time.Now().UTC()
|
||
|
build.Status = "Pending"
|
||
|
if err := database.SaveBuild(build); err != nil {
|
||
|
return RenderText(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
||
|
}
|
||
|
|
||
|
// send the build to the queue
|
||
|
h.queue.Add(&queue.BuildTask{Repo: repo, Commit: commit, Build: build, Script: buildscript})
|
||
|
|
||
|
// OK!
|
||
|
return RenderText(w, http.StatusText(http.StatusOK), http.StatusOK)
|
||
|
}
|