Пример #1
0
func webhookHandler(c *integram.Context, wc *integram.WebhookContext) (err error) {
	eventKey := wc.Header("X-Event-Key")

	if eventKey == "" {
		// try the old one Bitbucket POST service

		return oldWebhookHandler(c, wc)
	}

	if _, ok := eventTypeMap[eventKey]; !ok {

		return errors.New("Bad X-Event-Key: " + eventKey)
	}

	c.Log().Debugf("eventKey=%v", eventKey)

	if err != nil {
		return errors.New("JSON deserialization error: " + err.Error())
	}

	switch eventKey {
	case "repo:push":
		event := api.RepoPushEvent{}
		wc.JSON(&event)

		for _, change := range event.Push.Changes {

			msg := c.NewMessage()
			commits := 0
			text := ""

			if len(change.Commits) > 1 {
				anyOherPersonCommits := false
				for _, commit := range change.Commits {
					if commit.Author.User.UUID != event.Actor.UUID {
						anyOherPersonCommits = true
						break
					}
				}
				for _, commit := range change.Commits {
					commits++
					if anyOherPersonCommits {
						text += mention(c, &commit.Author.User) + ": "
					}
					text += m.URL(commit.Message, commit.Links.HTML.Href) + "\n"
				}
				if change.Truncated {
					text += m.URL("... See all", change.Links.Commits.Href) + "\n"
				}
			} else if len(change.Commits) == 1 {
				commits++
				commit := &change.Commits[0]
				if commit.Author.User.UUID != event.Actor.UUID {
					text += mention(c, &commit.Author.User) + ": "
				}

				text += commit.Message + "\n"
			}

			change.New.Target.Author.User.Links.Avatar.Href = strings.Replace(change.New.Target.Author.User.Links.Avatar.Href, "/32/", "/128/", 1)
			wp := ""
			if change.Truncated {
				wp = c.WebPreview("> 5 commits", "@"+commitShort(change.Old.Target.Hash)+" ... @"+commitShort(change.New.Target.Hash), "", change.Links.HTML.Href, change.New.Target.Author.User.Links.Avatar.Href)
			} else if commits > 1 {
				wp = c.WebPreview(fmt.Sprintf("%d commits", commits), "@"+commitShort(change.Old.Target.Hash)+" ... @"+commitShort(change.New.Target.Hash), "", change.Links.HTML.Href, change.New.Target.Author.User.Links.Avatar.Href)
			} else if commits == 1 {
				wp = c.WebPreview("Commit", "@"+commitShort(change.New.Target.Hash), "", change.Commits[0].Links.HTML.Href, change.New.Target.Author.User.Links.Avatar.Href)
			}

			if commits > 0 {
				pushedText := ""
				if change.Forced {
					pushedText = m.URL("❗️ forcibly pushed", wp)
				} else {
					pushedText = m.URL("pushed", wp)
				}
				err = msg.SetTextFmt("%s %s to %s/%s\n%s",
					mention(c, &change.New.Target.Author.User),
					pushedText,
					m.URL(event.Repository.Name, event.Repository.Links.HTML.Href),
					m.URL(change.New.Name, change.New.Links.HTML.Href),
					text).
					AddEventID(commitUniqueID(change.Commits[0].Hash)).
					EnableHTML().
					Send()
			}
		}
	case "issue:created":
		event := api.IssueCreatedEvent{}
		err := wc.JSON(&event)
		if err != nil {
			return err
		}
		event.Issue.Repository = &event.Repository

		c.SetServiceCache(issueUniqueID(event.Repository.FullName, event.Issue.ID), event.Issue, time.Hour*24*365)

		return c.NewMessage().AddEventID(issueUniqueID(event.Repository.FullName, event.Issue.ID)).
			SetInlineKeyboard(issueInlineKeyboard(&event.Issue)).
			SetText(issueText(c, &event.Issue)).
			SetCallbackAction(issueInlineButtonPressed, event.Repository.FullName, event.Issue.ID).
			EnableHTML().Send()
	case "issue:comment_created":
		event := api.IssueCommentCreatedEvent{}
		err := wc.JSON(&event)
		if err != nil {
			return err
		}

		var rm *integram.Message
		if event.Comment.Parent.ID > 0 {
			// actually bitbucket doesn't provide parent id for issue comments for now
			rm, _ = c.FindMessageByEventID(issueCommentUniqueID(event.Repository.FullName, event.Issue.ID, event.Comment.Parent.ID))
		}
		if rm == nil {
			rm, _ = c.FindMessageByEventID(issueUniqueID(event.Repository.FullName, event.Issue.ID))
		}

		msg := c.NewMessage().AddEventID(issueCommentUniqueID(event.Repository.FullName, event.Issue.ID, event.Comment.ID)).EnableHTML()

		if rm != nil {
			return msg.SetReplyToMsgID(rm.MsgID).SetText(fmt.Sprintf("%s: %s", mention(c, &event.Actor), event.Comment.Content.Raw)).Send()
		}
		wp := c.WebPreview("Issue", event.Issue.Title, event.Repository.FullName, event.Comment.Links.HTML.Href, "")
		return msg.SetText(fmt.Sprintf("%s %s: %s", m.URL("💬", wp), mention(c, &event.Actor), event.Comment.Content.Raw)).Send()

	case "repo:commit_comment_created":
		event := api.RepoCommitCommentCreatedEvent{}
		err := wc.JSON(&event)
		if err != nil {
			return err
		}

		var rm *integram.Message
		if event.Comment.Parent.ID > 0 {
			// actually bitbucket doesn't provide parent id for issue comments for now
			rm, _ = c.FindMessageByEventID(commitCommentUniqueID(event.Commit.Hash, event.Comment.Parent.ID))
		}
		if rm == nil {
			rm, _ = c.FindMessageByEventID(commitUniqueID(event.Commit.Hash))
		}

		msg := c.NewMessage().AddEventID(commitCommentUniqueID(event.Commit.Hash, event.Comment.Parent.ID)).EnableHTML()

		if rm != nil {
			return msg.SetReplyToMsgID(rm.MsgID).SetText(fmt.Sprintf("%s: %s", mention(c, &event.Actor), event.Comment.Content.Raw)).Send()
		}
		wp := c.WebPreview("Commit", "@"+event.Commit.Hash[0:10], event.Repository.FullName, event.Comment.Links.HTML.Href, "")
		return msg.SetText(fmt.Sprintf("%s %s: %s", m.URL("💬", wp), mention(c, &event.Actor), event.Comment.Content.Raw)).Send()

	case "issue:updated":
		event := api.IssueUpdatedEvent{}
		err := wc.JSON(&event)
		if err != nil {
			return err
		}
		eventID := issueUniqueID(event.Repository.FullName, event.Issue.ID)
		rm, _ := c.FindMessageByEventID(eventID)

		msg := c.NewMessage().AddEventID(issueCommentUniqueID(event.Repository.FullName, event.Issue.ID, event.Comment.ID)).EnableHTML()

		if event.Comment.Content.Raw != "" {
			event.Comment.Content.Raw = ": " + event.Comment.Content.Raw
		}

		if rm != nil {
			c.EditMessagesTextWithEventID(eventID, issueText(c, &event.Issue))
			// if last Issue message just posted
			if err == nil && time.Now().Sub(rm.Date).Seconds() < 60 {
				return nil
			}

			return msg.SetReplyToMsgID(rm.MsgID).SetText(fmt.Sprintf("%s update the issue%s", mention(c, &event.Actor), event.Comment.Content.Raw)).Send()
		}
		return msg.SetText(fmt.Sprintf("%s updated an issue%s\n%s", mention(c, &event.Actor), event.Comment.Content.Raw, issueText(c, &event.Issue))).Send()

	case "pullrequest:updated":
		event := api.PullRequestCreatedEvent{}
		err := wc.JSON(&event)
		if err != nil {
			return err
		}

		prText := prText(c, &event.PullRequest)

		eventID := prUniqueID(event.Repository.FullName, event.PullRequest.ID)
		rm, _ := c.FindMessageByEventID(eventID)

		msg := c.NewMessage()

		if rm != nil {
			c.EditMessagesTextWithEventID(eventID, prText)
			// if last PR message just posted
			if err == nil && time.Now().Sub(rm.Date).Seconds() < 60 {
				return nil
			}

			msg.SetReplyToMsgID(rm.MsgID)
		} else {
			msg.AddEventID(prUniqueID(event.Repository.FullName, event.PullRequest.ID))
		}

		return msg.
			SetText("✏️ " + prText).
			EnableHTML().Send()
	case "pullrequest:created":
		event := api.PullRequestCreatedEvent{}
		err := wc.JSON(&event)
		if err != nil {
			return err
		}

		c.SetServiceCache(prUniqueID(event.Repository.FullName, event.PullRequest.ID), event.PullRequest, time.Hour*24*365)

		return c.NewMessage().AddEventID(prUniqueID(event.Repository.FullName, event.PullRequest.ID)).
			SetText(prText(c, &event.PullRequest)).
			EnableHTML().Send()

	case "pullrequest:approved":
		event := api.PullRequestApprovedEvent{}
		err := wc.JSON(&event)
		if err != nil {
			return err
		}

		rm, _ := c.FindMessageByEventID(prUniqueID(event.Repository.FullName, event.PullRequest.ID))
		msg := c.NewMessage().EnableHTML()

		if rm != nil {
			return msg.SetReplyToMsgID(rm.MsgID).SetText(fmt.Sprintf("✅ Approved by %s", mention(c, &event.Actor))).Send()
		}
		wp := c.WebPreview("Pull Request", event.PullRequest.Title, "by "+event.PullRequest.Author.DisplayName+" in "+event.Repository.FullName, event.PullRequest.Links.HTML.Href, "")
		return msg.SetText(fmt.Sprintf("✅ %s by %s", m.URL("Approved", wp), mention(c, &event.Actor))).Send()

	case "pullrequest:unapproved":
		event := api.PullRequestApprovalRemovedEvent{}
		err := wc.JSON(&event)
		if err != nil {
			return err
		}

		rm, _ := c.FindMessageByEventID(prUniqueID(event.Repository.FullName, event.PullRequest.ID))
		msg := c.NewMessage().EnableHTML()

		if rm != nil {
			return msg.SetReplyToMsgID(rm.MsgID).SetText(fmt.Sprintf("❌ %s removed approval", mention(c, &event.Actor))).Send()
		}
		wp := c.WebPreview("Pull Request", event.PullRequest.Title, "by "+event.PullRequest.Author.DisplayName+" in "+event.Repository.FullName, event.PullRequest.Links.HTML.Href, "")
		return msg.SetText(fmt.Sprintf("❌ %s %s", mention(c, &event.Actor), m.URL("removed approval", wp))).Send()

	case "pullrequest:fulfilled":
		event := api.PullRequestMergedEvent{}
		err := wc.JSON(&event)
		if err != nil {
			return err
		}

		rm, _ := c.FindMessageByEventID(prUniqueID(event.Repository.FullName, event.PullRequest.ID))
		msg := c.NewMessage().EnableHTML()

		if rm != nil {
			return msg.SetReplyToMsgID(rm.MsgID).SetText(fmt.Sprintf("✅ Merged by %s", mention(c, &event.Actor))).Send()
		}
		wp := c.WebPreview("Pull Request", event.PullRequest.Title, "by "+event.PullRequest.Author.DisplayName+" in "+event.Repository.FullName, event.PullRequest.Links.HTML.Href, "")
		return msg.SetText(fmt.Sprintf("✅ %s by %s", m.URL("Merged", wp), mention(c, &event.Actor))).Send()

	case "pullrequest:rejected":
		event := api.PullRequestDeclinedEvent{}
		err := wc.JSON(&event)
		if err != nil {
			return err
		}

		rm, _ := c.FindMessageByEventID(prUniqueID(event.Repository.FullName, event.PullRequest.ID))
		msg := c.NewMessage().EnableHTML()

		if rm != nil {
			return msg.SetReplyToMsgID(rm.MsgID).SetText(fmt.Sprintf("❌ Declined by %s: %s", mention(c, &event.Actor), event.PullRequest.Reason)).Send()
		}
		wp := c.WebPreview("Pull Request", event.PullRequest.Title, "by "+event.PullRequest.Author.DisplayName+" in "+event.Repository.FullName, event.PullRequest.Links.HTML.Href, "")
		return msg.SetText(fmt.Sprintf("❌ %s by %s", m.URL("Declined", wp), mention(c, &event.Actor))).Send()

	case "pullrequest:comment_created":
		event := api.PullRequestCommentCreatedEvent{}
		err := wc.JSON(&event)
		if err != nil {
			return err
		}

		rm, _ := c.FindMessageByEventID(prUniqueID(event.Repository.FullName, event.PullRequest.ID))

		msg := c.NewMessage().AddEventID(prCommentUniqueID(event.Repository.FullName, event.PullRequest.ID, event.Comment.ID)).EnableHTML()

		if rm != nil {
			return msg.SetReplyToMsgID(rm.MsgID).SetText(fmt.Sprintf("%s: %s", mention(c, &event.Actor), event.Comment.Content.Raw)).Send()
		}
		wp := c.WebPreview("Pull Request", event.PullRequest.Title, event.Repository.FullName, event.PullRequest.Links.HTML.Href, "")
		return msg.SetText(fmt.Sprintf("%s %s: %s", m.URL("💬", wp), mention(c, &event.Actor), event.Comment.Content.Raw)).Send()

	}
	return err

}