Example #1
0
// ParseHook parses the post-commit hook from the Request body
// and returns the required data in a standard format.
func (r *Bitbucket) ParseHook(req *http.Request) (*model.Hook, error) {
	var payload = req.FormValue("payload")
	var hook, err = bitbucket.ParseHook([]byte(payload))
	if err != nil {
		return nil, err
	}

	// verify the payload has the minimum amount of required data.
	if hook.Repo == nil || hook.Commits == nil || len(hook.Commits) == 0 {
		return nil, fmt.Errorf("Invalid Bitbucket post-commit Hook. Missing Repo or Commit data.")
	}

	var author = hook.Commits[len(hook.Commits)-1].RawAuthor
	var matches = emailRegexp.FindStringSubmatch(author)
	if len(matches) == 2 {
		author = matches[1]
	}

	return &model.Hook{
		Owner:     hook.Repo.Owner,
		Repo:      hook.Repo.Slug,
		Sha:       hook.Commits[len(hook.Commits)-1].Hash,
		Branch:    hook.Commits[len(hook.Commits)-1].Branch,
		Author:    author,
		Timestamp: time.Now().UTC().String(),
		Message:   hook.Commits[len(hook.Commits)-1].Message,
	}, nil
}
Example #2
0
// 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)
}