Kaynağa Gözat

webhook: support Issues event (#2319)

Also addresses #3485.
Unknwon 8 yıl önce
ebeveyn
işleme
c93731339f

+ 4 - 2
conf/locale/locale_en-US.ini

@@ -760,10 +760,12 @@ settings.event_delete = Delete
 settings.event_delete_desc = Branch or tag deleted
 settings.event_fork = Fork
 settings.event_fork_desc = Repository forked
-settings.event_pull_request = Pull Request
-settings.event_pull_request_desc = Pull request opened, closed, reopened, edited, assigned, unassigned, label updated, label cleared, or synchronized.
 settings.event_push = Push
 settings.event_push_desc = Git push to a repository
+settings.event_issue = Issues
+settings.event_issue_desc = Issue opened, closed, reopened, edited, assigned, unassigned, label updated, label cleared, milestoned, or demilestoned.
+settings.event_pull_request = Pull Request
+settings.event_pull_request_desc = Pull request opened, closed, reopened, edited, assigned, unassigned, label updated, label cleared, milestoned, demilestoned, or synchronized.
 settings.active = Active
 settings.active_helper = Details regarding the event which triggered the hook will be delivered as well.
 settings.add_hook_success = New webhook has been added.

+ 1 - 1
gogs.go

@@ -16,7 +16,7 @@ import (
 	"github.com/gogits/gogs/modules/setting"
 )
 
-const APP_VER = "0.10.10.0308"
+const APP_VER = "0.10.11.0308"
 
 func init() {
 	setting.AppVer = APP_VER

+ 93 - 15
models/issue.go

@@ -230,7 +230,7 @@ func (issue *Issue) sendLabelUpdatedWebhook(doer *User) {
 	if issue.IsPull {
 		err = issue.PullRequest.LoadIssue()
 		if err != nil {
-			log.Error(4, "LoadIssue: %v", err)
+			log.Error(2, "LoadIssue: %v", err)
 			return
 		}
 		err = PrepareWebhooks(issue.Repo, HOOK_EVENT_PULL_REQUEST, &api.PullRequestPayload{
@@ -240,9 +240,17 @@ func (issue *Issue) sendLabelUpdatedWebhook(doer *User) {
 			Repository:  issue.Repo.APIFormat(nil),
 			Sender:      doer.APIFormat(),
 		})
+	} else {
+		err = PrepareWebhooks(issue.Repo, HOOK_EVENT_ISSUES, &api.IssuesPayload{
+			Action:     api.HOOK_ISSUE_LABEL_UPDATED,
+			Index:      issue.Index,
+			Issue:      issue.APIFormat(),
+			Repository: issue.Repo.APIFormat(nil),
+			Sender:     doer.APIFormat(),
+		})
 	}
 	if err != nil {
-		log.Error(4, "PrepareWebhooks [is_pull: %v]: %v", issue.IsPull, err)
+		log.Error(2, "PrepareWebhooks [is_pull: %v]: %v", issue.IsPull, err)
 	} else {
 		go HookQueue.Add(issue.RepoID)
 	}
@@ -334,7 +342,7 @@ func (issue *Issue) ClearLabels(doer *User) (err error) {
 	if issue.IsPull {
 		err = issue.PullRequest.LoadIssue()
 		if err != nil {
-			log.Error(4, "LoadIssue: %v", err)
+			log.Error(2, "LoadIssue: %v", err)
 			return
 		}
 		err = PrepareWebhooks(issue.Repo, HOOK_EVENT_PULL_REQUEST, &api.PullRequestPayload{
@@ -344,9 +352,17 @@ func (issue *Issue) ClearLabels(doer *User) (err error) {
 			Repository:  issue.Repo.APIFormat(nil),
 			Sender:      doer.APIFormat(),
 		})
+	} else {
+		err = PrepareWebhooks(issue.Repo, HOOK_EVENT_ISSUES, &api.IssuesPayload{
+			Action:     api.HOOK_ISSUE_LABEL_CLEARED,
+			Index:      issue.Index,
+			Issue:      issue.APIFormat(),
+			Repository: issue.Repo.APIFormat(nil),
+			Sender:     doer.APIFormat(),
+		})
 	}
 	if err != nil {
-		log.Error(4, "PrepareWebhooks [is_pull: %v]: %v", issue.IsPull, err)
+		log.Error(2, "PrepareWebhooks [is_pull: %v]: %v", issue.IsPull, err)
 	} else {
 		go HookQueue.Add(issue.RepoID)
 	}
@@ -470,9 +486,22 @@ func (issue *Issue) ChangeStatus(doer *User, repo *Repository, isClosed bool) (e
 			apiPullRequest.Action = api.HOOK_ISSUE_REOPENED
 		}
 		err = PrepareWebhooks(repo, HOOK_EVENT_PULL_REQUEST, apiPullRequest)
+	} else {
+		apiIssues := &api.IssuesPayload{
+			Index:      issue.Index,
+			Issue:      issue.APIFormat(),
+			Repository: repo.APIFormat(nil),
+			Sender:     doer.APIFormat(),
+		}
+		if isClosed {
+			apiIssues.Action = api.HOOK_ISSUE_CLOSED
+		} else {
+			apiIssues.Action = api.HOOK_ISSUE_REOPENED
+		}
+		err = PrepareWebhooks(repo, HOOK_EVENT_ISSUES, apiIssues)
 	}
 	if err != nil {
-		log.Error(4, "PrepareWebhooks [is_pull: %v, is_closed: %v]: %v", issue.IsPull, isClosed, err)
+		log.Error(2, "PrepareWebhooks [is_pull: %v, is_closed: %v]: %v", issue.IsPull, isClosed, err)
 	} else {
 		go HookQueue.Add(repo.ID)
 	}
@@ -490,20 +519,33 @@ func (issue *Issue) ChangeTitle(doer *User, title string) (err error) {
 	if issue.IsPull {
 		issue.PullRequest.Issue = issue
 		err = PrepareWebhooks(issue.Repo, HOOK_EVENT_PULL_REQUEST, &api.PullRequestPayload{
+			Action:      api.HOOK_ISSUE_EDITED,
+			Index:       issue.Index,
+			PullRequest: issue.PullRequest.APIFormat(),
+			Changes: &api.ChangesPayload{
+				Title: &api.ChangesFromPayload{
+					From: oldTitle,
+				},
+			},
+			Repository: issue.Repo.APIFormat(nil),
+			Sender:     doer.APIFormat(),
+		})
+	} else {
+		err = PrepareWebhooks(issue.Repo, HOOK_EVENT_ISSUES, &api.IssuesPayload{
 			Action: api.HOOK_ISSUE_EDITED,
 			Index:  issue.Index,
+			Issue:  issue.APIFormat(),
 			Changes: &api.ChangesPayload{
 				Title: &api.ChangesFromPayload{
 					From: oldTitle,
 				},
 			},
-			PullRequest: issue.PullRequest.APIFormat(),
-			Repository:  issue.Repo.APIFormat(nil),
-			Sender:      doer.APIFormat(),
+			Repository: issue.Repo.APIFormat(nil),
+			Sender:     doer.APIFormat(),
 		})
 	}
 	if err != nil {
-		log.Error(4, "PrepareWebhooks [is_pull: %v]: %v", issue.IsPull, err)
+		log.Error(2, "PrepareWebhooks [is_pull: %v]: %v", issue.IsPull, err)
 	} else {
 		go HookQueue.Add(issue.RepoID)
 	}
@@ -521,20 +563,33 @@ func (issue *Issue) ChangeContent(doer *User, content string) (err error) {
 	if issue.IsPull {
 		issue.PullRequest.Issue = issue
 		err = PrepareWebhooks(issue.Repo, HOOK_EVENT_PULL_REQUEST, &api.PullRequestPayload{
+			Action:      api.HOOK_ISSUE_EDITED,
+			Index:       issue.Index,
+			PullRequest: issue.PullRequest.APIFormat(),
+			Changes: &api.ChangesPayload{
+				Body: &api.ChangesFromPayload{
+					From: oldContent,
+				},
+			},
+			Repository: issue.Repo.APIFormat(nil),
+			Sender:     doer.APIFormat(),
+		})
+	} else {
+		err = PrepareWebhooks(issue.Repo, HOOK_EVENT_ISSUES, &api.IssuesPayload{
 			Action: api.HOOK_ISSUE_EDITED,
 			Index:  issue.Index,
+			Issue:  issue.APIFormat(),
 			Changes: &api.ChangesPayload{
 				Body: &api.ChangesFromPayload{
 					From: oldContent,
 				},
 			},
-			PullRequest: issue.PullRequest.APIFormat(),
-			Repository:  issue.Repo.APIFormat(nil),
-			Sender:      doer.APIFormat(),
+			Repository: issue.Repo.APIFormat(nil),
+			Sender:     doer.APIFormat(),
 		})
 	}
 	if err != nil {
-		log.Error(4, "PrepareWebhooks [is_pull: %v]: %v", issue.IsPull, err)
+		log.Error(2, "PrepareWebhooks [is_pull: %v]: %v", issue.IsPull, err)
 	} else {
 		go HookQueue.Add(issue.RepoID)
 	}
@@ -570,6 +625,19 @@ func (issue *Issue) ChangeAssignee(doer *User, assigneeID int64) (err error) {
 			apiPullRequest.Action = api.HOOK_ISSUE_ASSIGNED
 		}
 		err = PrepareWebhooks(issue.Repo, HOOK_EVENT_PULL_REQUEST, apiPullRequest)
+	} else {
+		apiIssues := &api.IssuesPayload{
+			Index:      issue.Index,
+			Issue:      issue.APIFormat(),
+			Repository: issue.Repo.APIFormat(nil),
+			Sender:     doer.APIFormat(),
+		}
+		if isRemoveAssignee {
+			apiIssues.Action = api.HOOK_ISSUE_UNASSIGNED
+		} else {
+			apiIssues.Action = api.HOOK_ISSUE_ASSIGNED
+		}
+		err = PrepareWebhooks(issue.Repo, HOOK_EVENT_ISSUES, apiIssues)
 	}
 	if err != nil {
 		log.Error(4, "PrepareWebhooks [is_pull: %v, remove_assignee: %v]: %v", issue.IsPull, isRemoveAssignee, err)
@@ -715,10 +783,20 @@ func NewIssue(repo *Repository, issue *Issue, labelIDs []int64, uuids []string)
 		RepoName:     repo.Name,
 		IsPrivate:    repo.IsPrivate,
 	}); err != nil {
-		log.Error(4, "NotifyWatchers: %v", err)
+		log.Error(2, "NotifyWatchers: %v", err)
 	}
 	if err = issue.MailParticipants(); err != nil {
-		log.Error(4, "MailParticipants: %v", err)
+		log.Error(2, "MailParticipants: %v", err)
+	}
+
+	if err = PrepareWebhooks(repo, HOOK_EVENT_ISSUES, &api.IssuesPayload{
+		Action:     api.HOOK_ISSUE_OPENED,
+		Index:      issue.Index,
+		Issue:      issue.APIFormat(),
+		Repository: repo.APIFormat(nil),
+		Sender:     issue.Poster.APIFormat(),
+	}); err != nil {
+		log.Error(2, "PrepareWebhooks: %v", err)
 	}
 
 	return nil

+ 18 - 2
models/issue_label.go

@@ -240,7 +240,13 @@ func newIssueLabel(e *xorm.Session, issue *Issue, label *Label) (err error) {
 	if issue.IsClosed {
 		label.NumClosedIssues++
 	}
-	return updateLabel(e, label)
+
+	if err = updateLabel(e, label); err != nil {
+		return fmt.Errorf("updateLabel: %v", err)
+	}
+
+	issue.Labels = append(issue.Labels, label)
+	return nil
 }
 
 // NewIssueLabel creates a new issue-label relation.
@@ -313,7 +319,17 @@ func deleteIssueLabel(e *xorm.Session, issue *Issue, label *Label) (err error) {
 	if issue.IsClosed {
 		label.NumClosedIssues--
 	}
-	return updateLabel(e, label)
+	if err = updateLabel(e, label); err != nil {
+		return fmt.Errorf("updateLabel: %v", err)
+	}
+
+	for i := range issue.Labels {
+		if issue.Labels[i].ID == label.ID {
+			issue.Labels = append(issue.Labels[:i], issue.Labels[i+1:]...)
+			break
+		}
+	}
+	return nil
 }
 
 // DeleteIssueLabel deletes issue-label relation.

+ 48 - 2
models/milestone.go

@@ -5,9 +5,11 @@
 package models
 
 import (
+	"fmt"
 	"time"
 
 	"github.com/go-xorm/xorm"
+	log "gopkg.in/clog.v1"
 
 	api "github.com/gogits/go-gogs-client"
 
@@ -272,6 +274,8 @@ func changeMilestoneAssign(e *xorm.Session, issue *Issue, oldMilestoneID int64)
 		} else if _, err = e.Exec("UPDATE `issue_user` SET milestone_id = 0 WHERE issue_id = ?", issue.ID); err != nil {
 			return err
 		}
+
+		issue.Milestone = nil
 	}
 
 	if issue.MilestoneID > 0 {
@@ -290,13 +294,15 @@ func changeMilestoneAssign(e *xorm.Session, issue *Issue, oldMilestoneID int64)
 		} else if _, err = e.Exec("UPDATE `issue_user` SET milestone_id = ? WHERE issue_id = ?", m.ID, issue.ID); err != nil {
 			return err
 		}
+
+		issue.Milestone = m
 	}
 
 	return updateIssue(e, issue)
 }
 
 // ChangeMilestoneAssign changes assignment of milestone for issue.
-func ChangeMilestoneAssign(issue *Issue, oldMilestoneID int64) (err error) {
+func ChangeMilestoneAssign(doer *User, issue *Issue, oldMilestoneID int64) (err error) {
 	sess := x.NewSession()
 	defer sess.Close()
 	if err = sess.Begin(); err != nil {
@@ -306,7 +312,47 @@ func ChangeMilestoneAssign(issue *Issue, oldMilestoneID int64) (err error) {
 	if err = changeMilestoneAssign(sess, issue, oldMilestoneID); err != nil {
 		return err
 	}
-	return sess.Commit()
+
+	if err = sess.Commit(); err != nil {
+		return fmt.Errorf("Commit: %v", err)
+	}
+
+	var hookAction api.HookIssueAction
+	if issue.MilestoneID > 0 {
+		hookAction = api.HOOK_ISSUE_MILESTONED
+	} else {
+		hookAction = api.HOOK_ISSUE_DEMILESTONED
+	}
+
+	if issue.IsPull {
+		err = issue.PullRequest.LoadIssue()
+		if err != nil {
+			log.Error(2, "LoadIssue: %v", err)
+			return
+		}
+		err = PrepareWebhooks(issue.Repo, HOOK_EVENT_PULL_REQUEST, &api.PullRequestPayload{
+			Action:      hookAction,
+			Index:       issue.Index,
+			PullRequest: issue.PullRequest.APIFormat(),
+			Repository:  issue.Repo.APIFormat(nil),
+			Sender:      doer.APIFormat(),
+		})
+	} else {
+		err = PrepareWebhooks(issue.Repo, HOOK_EVENT_ISSUES, &api.IssuesPayload{
+			Action:     hookAction,
+			Index:      issue.Index,
+			Issue:      issue.APIFormat(),
+			Repository: issue.Repo.APIFormat(nil),
+			Sender:     doer.APIFormat(),
+		})
+	}
+	if err != nil {
+		log.Error(2, "PrepareWebhooks [is_pull: %v]: %v", issue.IsPull, err)
+	} else {
+		go HookQueue.Add(issue.RepoID)
+	}
+
+	return nil
 }
 
 // DeleteMilestoneOfRepoByID deletes a milestone from a repository.

+ 5 - 4
models/pull.go

@@ -437,9 +437,10 @@ func NewPullRequest(repo *Repository, pull *Issue, labelIDs []int64, uuids []str
 		RepoName:     repo.Name,
 		IsPrivate:    repo.IsPrivate,
 	}); err != nil {
-		log.Error(4, "NotifyWatchers: %v", err)
-	} else if err = pull.MailParticipants(); err != nil {
-		log.Error(4, "MailParticipants: %v", err)
+		log.Error(2, "NotifyWatchers: %v", err)
+	}
+	if err = pull.MailParticipants(); err != nil {
+		log.Error(2, "MailParticipants: %v", err)
 	}
 
 	pr.Issue = pull
@@ -451,7 +452,7 @@ func NewPullRequest(repo *Repository, pull *Issue, labelIDs []int64, uuids []str
 		Repository:  repo.APIFormat(nil),
 		Sender:      pull.Poster.APIFormat(),
 	}); err != nil {
-		log.Error(4, "PrepareWebhooks: %v", err)
+		log.Error(2, "PrepareWebhooks: %v", err)
 	}
 	go HookQueue.Add(repo.ID)
 

+ 12 - 0
models/webhook.go

@@ -66,6 +66,7 @@ type HookEvents struct {
 	Delete      bool `json:"delete"`
 	Fork        bool `json:"fork"`
 	Push        bool `json:"push"`
+	Issues      bool `json:"issues"`
 	PullRequest bool `json:"pull_request"`
 }
 
@@ -176,6 +177,12 @@ func (w *Webhook) HasPushEvent() bool {
 		(w.ChooseEvents && w.HookEvents.Push)
 }
 
+// HasIssuesEvent returns true if hook enabled issues event.
+func (w *Webhook) HasIssuesEvent() bool {
+	return w.SendEverything ||
+		(w.ChooseEvents && w.HookEvents.Issues)
+}
+
 // HasPullRequestEvent returns true if hook enabled pull request event.
 func (w *Webhook) HasPullRequestEvent() bool {
 	return w.SendEverything ||
@@ -360,6 +367,7 @@ const (
 	HOOK_EVENT_DELETE       HookEventType = "delete"
 	HOOK_EVENT_FORK         HookEventType = "fork"
 	HOOK_EVENT_PUSH         HookEventType = "push"
+	HOOK_EVENT_ISSUES       HookEventType = "issues"
 	HOOK_EVENT_PULL_REQUEST HookEventType = "pull_request"
 )
 
@@ -492,6 +500,10 @@ func prepareHookTasks(e Engine, repo *Repository, event HookEventType, p api.Pay
 			if !w.HasPushEvent() {
 				continue
 			}
+		case HOOK_EVENT_ISSUES:
+			if !w.HasIssuesEvent() {
+				continue
+			}
 		case HOOK_EVENT_PULL_REQUEST:
 			if !w.HasPullRequestEvent() {
 				continue

+ 82 - 0
models/webhook_discord.go

@@ -169,6 +169,78 @@ func getDiscordPushPayload(p *api.PushPayload, slack *SlackMeta) (*DiscordPayloa
 	}, nil
 }
 
+func getDiscordIssuesPayload(p *api.IssuesPayload, slack *SlackMeta) (*DiscordPayload, error) {
+	title := fmt.Sprintf("#%d %s", p.Index, p.Issue.Title)
+	url := fmt.Sprintf("%s/issues/%d", p.Repository.HTMLURL, p.Index)
+	content := ""
+	fields := make([]*DiscordEmbedFieldObject, 0, 1)
+	switch p.Action {
+	case api.HOOK_ISSUE_OPENED:
+		title = "New issue: " + title
+		content = p.Issue.Body
+	case api.HOOK_ISSUE_CLOSED:
+		title = "Issue closed: " + title
+	case api.HOOK_ISSUE_REOPENED:
+		title = "Issue re-opened: " + title
+	case api.HOOK_ISSUE_EDITED:
+		title = "Issue edited: " + title
+		content = p.Issue.Body
+	case api.HOOK_ISSUE_ASSIGNED:
+		title = "Issue assigned: " + title
+		fields = []*DiscordEmbedFieldObject{{
+			Name:  "New Assignee",
+			Value: p.Issue.Assignee.UserName,
+		}}
+	case api.HOOK_ISSUE_UNASSIGNED:
+		title = "Issue unassigned: " + title
+	case api.HOOK_ISSUE_LABEL_UPDATED:
+		title = "Issue labels updated: " + title
+		labels := make([]string, len(p.Issue.Labels))
+		for i := range p.Issue.Labels {
+			labels[i] = p.Issue.Labels[i].Name
+		}
+		if len(labels) == 0 {
+			labels = []string{"<empty>"}
+		}
+		fields = []*DiscordEmbedFieldObject{{
+			Name:  "Labels",
+			Value: strings.Join(labels, ", "),
+		}}
+	case api.HOOK_ISSUE_LABEL_CLEARED:
+		title = "Issue labels cleared: " + title
+	case api.HOOK_ISSUE_SYNCHRONIZED:
+		title = "Issue synchronized: " + title
+	case api.HOOK_ISSUE_MILESTONED:
+		title = "Issue milestoned: " + title
+		fields = []*DiscordEmbedFieldObject{{
+			Name:  "New Milestone",
+			Value: p.Issue.Milestone.Title,
+		}}
+	case api.HOOK_ISSUE_DEMILESTONED:
+		title = "Issue demilestoned: " + title
+	}
+
+	color, _ := strconv.ParseInt(strings.TrimLeft(slack.Color, "#"), 16, 32)
+	return &DiscordPayload{
+		Username:  slack.Username,
+		AvatarURL: slack.IconURL,
+		Embeds: []*DiscordEmbedObject{{
+			Title:       title,
+			Description: content,
+			URL:         url,
+			Color:       int(color),
+			Footer: &DiscordEmbedFooterObject{
+				Text: p.Repository.FullName,
+			},
+			Author: &DiscordEmbedAuthorObject{
+				Name:    p.Sender.UserName,
+				IconURL: p.Sender.AvatarUrl,
+			},
+			Fields: fields,
+		}},
+	}, nil
+}
+
 func getDiscordPullRequestPayload(p *api.PullRequestPayload, slack *SlackMeta) (*DiscordPayload, error) {
 	title := fmt.Sprintf("#%d %s", p.Index, p.PullRequest.Title)
 	url := fmt.Sprintf("%s/pulls/%d", p.Repository.HTMLURL, p.Index)
@@ -211,6 +283,14 @@ func getDiscordPullRequestPayload(p *api.PullRequestPayload, slack *SlackMeta) (
 		title = "Pull request labels cleared: " + title
 	case api.HOOK_ISSUE_SYNCHRONIZED:
 		title = "Pull request synchronized: " + title
+	case api.HOOK_ISSUE_MILESTONED:
+		title = "Pull request milestoned: " + title
+		fields = []*DiscordEmbedFieldObject{{
+			Name:  "New Milestone",
+			Value: p.PullRequest.Milestone.Title,
+		}}
+	case api.HOOK_ISSUE_DEMILESTONED:
+		title = "Pull request demilestoned: " + title
 	}
 
 	color, _ := strconv.ParseInt(strings.TrimLeft(slack.Color, "#"), 16, 32)
@@ -249,6 +329,8 @@ func GetDiscordPayload(p api.Payloader, event HookEventType, meta string) (paylo
 		payload, err = getDiscordForkPayload(p.(*api.ForkPayload))
 	case HOOK_EVENT_PUSH:
 		payload, err = getDiscordPushPayload(p.(*api.PushPayload), slack)
+	case HOOK_EVENT_ISSUES:
+		payload, err = getDiscordIssuesPayload(p.(*api.IssuesPayload), slack)
 	case HOOK_EVENT_PULL_REQUEST:
 		payload, err = getDiscordPullRequestPayload(p.(*api.PullRequestPayload), slack)
 	}

+ 52 - 0
models/webhook_slack.go

@@ -145,6 +145,52 @@ func getSlackPushPayload(p *api.PushPayload, slack *SlackMeta) (*SlackPayload, e
 	}, nil
 }
 
+func getSlackIssuesPayload(p *api.IssuesPayload, slack *SlackMeta) (*SlackPayload, error) {
+	senderLink := SlackLinkFormatter(setting.AppUrl+p.Sender.UserName, p.Sender.UserName)
+	titleLink := SlackLinkFormatter(fmt.Sprintf("%s/issues/%d", p.Repository.HTMLURL, p.Index),
+		fmt.Sprintf("#%d %s", p.Index, p.Issue.Title))
+	var text, title, attachmentText string
+	switch p.Action {
+	case api.HOOK_ISSUE_OPENED:
+		text = fmt.Sprintf("[%s] New issue created by %s", p.Repository.FullName, senderLink)
+		title = titleLink
+		attachmentText = SlackTextFormatter(p.Issue.Body)
+	case api.HOOK_ISSUE_CLOSED:
+		text = fmt.Sprintf("[%s] Issue closed: %s by %s", p.Repository.FullName, titleLink, senderLink)
+	case api.HOOK_ISSUE_REOPENED:
+		text = fmt.Sprintf("[%s] Issue re-opened: %s by %s", p.Repository.FullName, titleLink, senderLink)
+	case api.HOOK_ISSUE_EDITED:
+		text = fmt.Sprintf("[%s] Issue edited: %s by %s", p.Repository.FullName, titleLink, senderLink)
+		attachmentText = SlackTextFormatter(p.Issue.Body)
+	case api.HOOK_ISSUE_ASSIGNED:
+		text = fmt.Sprintf("[%s] Issue assigned to %s: %s by %s", p.Repository.FullName,
+			SlackLinkFormatter(setting.AppUrl+p.Issue.Assignee.UserName, p.Issue.Assignee.UserName),
+			titleLink, senderLink)
+	case api.HOOK_ISSUE_UNASSIGNED:
+		text = fmt.Sprintf("[%s] Issue unassigned: %s by %s", p.Repository.FullName, titleLink, senderLink)
+	case api.HOOK_ISSUE_LABEL_UPDATED:
+		text = fmt.Sprintf("[%s] Issue labels updated: %s by %s", p.Repository.FullName, titleLink, senderLink)
+	case api.HOOK_ISSUE_LABEL_CLEARED:
+		text = fmt.Sprintf("[%s] Issue labels cleared: %s by %s", p.Repository.FullName, titleLink, senderLink)
+	case api.HOOK_ISSUE_MILESTONED:
+		text = fmt.Sprintf("[%s] Issue milestoned: %s by %s", p.Repository.FullName, titleLink, senderLink)
+	case api.HOOK_ISSUE_DEMILESTONED:
+		text = fmt.Sprintf("[%s] Issue demilestoned: %s by %s", p.Repository.FullName, titleLink, senderLink)
+	}
+
+	return &SlackPayload{
+		Channel:  slack.Channel,
+		Text:     text,
+		Username: slack.Username,
+		IconURL:  slack.IconURL,
+		Attachments: []*SlackAttachment{{
+			Color: slack.Color,
+			Title: title,
+			Text:  attachmentText,
+		}},
+	}, nil
+}
+
 func getSlackPullRequestPayload(p *api.PullRequestPayload, slack *SlackMeta) (*SlackPayload, error) {
 	senderLink := SlackLinkFormatter(setting.AppUrl+p.Sender.UserName, p.Sender.UserName)
 	titleLink := SlackLinkFormatter(fmt.Sprintf("%s/pulls/%d", p.Repository.HTMLURL, p.Index),
@@ -178,6 +224,10 @@ func getSlackPullRequestPayload(p *api.PullRequestPayload, slack *SlackMeta) (*S
 		text = fmt.Sprintf("[%s] Pull request labels cleared: %s by %s", p.Repository.FullName, titleLink, senderLink)
 	case api.HOOK_ISSUE_SYNCHRONIZED:
 		text = fmt.Sprintf("[%s] Pull request synchronized: %s by %s", p.Repository.FullName, titleLink, senderLink)
+	case api.HOOK_ISSUE_MILESTONED:
+		text = fmt.Sprintf("[%s] Pull request milestoned: %s by %s", p.Repository.FullName, titleLink, senderLink)
+	case api.HOOK_ISSUE_DEMILESTONED:
+		text = fmt.Sprintf("[%s] Pull request demilestoned: %s by %s", p.Repository.FullName, titleLink, senderLink)
 	}
 
 	return &SlackPayload{
@@ -208,6 +258,8 @@ func GetSlackPayload(p api.Payloader, event HookEventType, meta string) (payload
 		payload, err = getSlackForkPayload(p.(*api.ForkPayload))
 	case HOOK_EVENT_PUSH:
 		payload, err = getSlackPushPayload(p.(*api.PushPayload), slack)
+	case HOOK_EVENT_ISSUES:
+		payload, err = getSlackIssuesPayload(p.(*api.IssuesPayload), slack)
 	case HOOK_EVENT_PULL_REQUEST:
 		payload, err = getSlackPullRequestPayload(p.(*api.PullRequestPayload), slack)
 	}

Dosya farkı çok büyük olduğundan ihmal edildi
+ 6 - 6
modules/bindata/bindata.go


+ 1 - 0
modules/form/repo.go

@@ -138,6 +138,7 @@ type Webhook struct {
 	Delete      bool
 	Fork        bool
 	Push        bool
+	Issues      bool
 	PullRequest bool
 	Active      bool
 }

+ 1 - 1
routers/api/v1/repo/issue.go

@@ -171,7 +171,7 @@ func EditIssue(ctx *context.APIContext, form api.EditIssueOption) {
 		issue.MilestoneID != *form.Milestone {
 		oldMilestoneID := issue.MilestoneID
 		issue.MilestoneID = *form.Milestone
-		if err = models.ChangeMilestoneAssign(issue, oldMilestoneID); err != nil {
+		if err = models.ChangeMilestoneAssign(ctx.User, issue, oldMilestoneID); err != nil {
 			ctx.Error(500, "ChangeMilestoneAssign", err)
 			return
 		}

+ 1 - 1
routers/repo/issue.go

@@ -771,7 +771,7 @@ func UpdateIssueMilestone(ctx *context.Context) {
 
 	// Not check for invalid milestone id and give responsibility to owners.
 	issue.MilestoneID = milestoneID
-	if err := models.ChangeMilestoneAssign(issue, oldMilestoneID); err != nil {
+	if err := models.ChangeMilestoneAssign(ctx.User, issue, oldMilestoneID); err != nil {
 		ctx.Handle(500, "ChangeMilestoneAssign", err)
 		return
 	}

+ 1 - 0
routers/repo/webhook.go

@@ -113,6 +113,7 @@ func ParseHookEvent(f form.Webhook) *models.HookEvent {
 			Delete:      f.Delete,
 			Fork:        f.Fork,
 			Push:        f.Push,
+			Issues:      f.Issues,
 			PullRequest: f.PullRequest,
 		},
 	}

+ 1 - 1
templates/.VERSION

@@ -1 +1 @@
-0.10.10.0308
+0.10.11.0308

+ 10 - 0
templates/repo/settings/webhook_settings.tmpl

@@ -62,6 +62,16 @@
 				</div>
 			</div>
 		</div>
+		<!-- Issues -->
+		<div class="seven wide column">
+			<div class="field">
+				<div class="ui checkbox">
+					<input class="hidden" name="issues" type="checkbox" tabindex="0" {{if .Webhook.Issues}}checked{{end}}>
+					<label>{{.i18n.Tr "repo.settings.event_issue"}}</label>
+					<span class="help">{{.i18n.Tr "repo.settings.event_issue_desc"}}</span>
+				</div>
+			</div>
+		</div>
 		<!-- Pull Request -->
 		<div class="seven wide column">
 			<div class="field">

+ 1 - 1
vendor/github.com/gogits/go-gogs-client/gogs.go

@@ -14,7 +14,7 @@ import (
 )
 
 func Version() string {
-	return "0.12.7"
+	return "0.12.8"
 }
 
 // Client represents a Gogs API client.

+ 16 - 1
vendor/github.com/gogits/go-gogs-client/repo_hook.go

@@ -239,6 +239,8 @@ const (
 	HOOK_ISSUE_UNASSIGNED    HookIssueAction = "unassigned"
 	HOOK_ISSUE_LABEL_UPDATED HookIssueAction = "label_updated"
 	HOOK_ISSUE_LABEL_CLEARED HookIssueAction = "label_cleared"
+	HOOK_ISSUE_MILESTONED    HookIssueAction = "milestoned"
+	HOOK_ISSUE_DEMILESTONED  HookIssueAction = "demilestoned"
 	HOOK_ISSUE_SYNCHRONIZED  HookIssueAction = "synchronized"
 )
 
@@ -251,6 +253,19 @@ type ChangesPayload struct {
 	Body  *ChangesFromPayload `json:"body,omitempty"`
 }
 
+type IssuesPayload struct {
+	Action     HookIssueAction `json:"action"`
+	Index      int64           `json:"number"`
+	Issue      *Issue          `json:"issue"`
+	Changes    *ChangesPayload `json:"changes,omitempty"`
+	Repository *Repository     `json:"repository"`
+	Sender     *User           `json:"sender"`
+}
+
+func (p *IssuesPayload) JSONPayload() ([]byte, error) {
+	return json.MarshalIndent(p, "", "  ")
+}
+
 // __________      .__  .__    __________                                     __
 // \______   \__ __|  | |  |   \______   \ ____  ________ __   ____   _______/  |_
 //  |     ___/  |  \  | |  |    |       _// __ \/ ____/  |  \_/ __ \ /  ___/\   __\
@@ -262,8 +277,8 @@ type ChangesPayload struct {
 type PullRequestPayload struct {
 	Action      HookIssueAction `json:"action"`
 	Index       int64           `json:"number"`
-	Changes     *ChangesPayload `json:"changes,omitempty"`
 	PullRequest *PullRequest    `json:"pull_request"`
+	Changes     *ChangesPayload `json:"changes,omitempty"`
 	Repository  *Repository     `json:"repository"`
 	Sender      *User           `json:"sender"`
 }

+ 2 - 1
vendor/github.com/gogits/go-gogs-client/user.go

@@ -18,12 +18,13 @@ type User struct {
 	AvatarUrl string `json:"avatar_url"`
 }
 
-// MarshalJSON implements the json.Marshaler interface for User, adding field(s) for backward compatibility
+// MarshalJSON implements the json.Marshaler interface for User
 func (u User) MarshalJSON() ([]byte, error) {
 	// Re-declaring User to avoid recursion
 	type shadow User
 	return json.Marshal(struct {
 		shadow
+		// LEGACY [Gogs 1.0]: remove field(s) for backward compatibility
 		CompatUserName string `json:"username"`
 	}{shadow(u), u.UserName})
 }

+ 3 - 3
vendor/vendor.json

@@ -165,10 +165,10 @@
 			"revisionTime": "2017-02-19T18:16:29Z"
 		},
 		{
-			"checksumSHA1": "sAGNvN2IXzD+rra6Y9sxJBpR4L8=",
+			"checksumSHA1": "Ut3Nu1GaTwTt+Q4k+t9tV3/3nF8=",
 			"path": "github.com/gogits/go-gogs-client",
-			"revision": "264a3d5bc98e108f17cc055338dbf4b94faf0d21",
-			"revisionTime": "2017-02-25T08:33:02Z"
+			"revision": "559fec59f2c88391ba624da5c40f77c49d8c84eb",
+			"revisionTime": "2017-03-09T05:00:34Z"
 		},
 		{
 			"checksumSHA1": "p4yoFWgDiTfpu1JYgh26t6+VDTk=",

Bu fark içinde çok fazla dosya değişikliği olduğu için bazı dosyalar gösterilmiyor