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  }