Add more webhooks support and refactor webhook templates directory (#3929)
* add more webhook support * move hooks templates to standalone dir and add more webhooks ui * fix tests * update vendor checksum * add more webhook support * move hooks templates to standalone dir and add more webhooks ui * fix tests * update vendor checksum * update vendor Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com> * load attributes when created release * update comparsion doc
This commit is contained in:
		
							parent
							
								
									188fe6c301
								
							
						
					
					
						commit
						24941a1046
					
				
					 33 changed files with 1010 additions and 118 deletions
				
			
		|  | @ -537,7 +537,7 @@ _Symbols used in table:_ | |||
|     </tr> | ||||
|     <tr> | ||||
|       <td>Webhook support</td> | ||||
|       <td>⁄</td> | ||||
|       <td>✓</td> | ||||
|       <td>✓</td> | ||||
|       <td>✓</td> | ||||
|       <td>✓</td> | ||||
|  |  | |||
|  | @ -618,6 +618,16 @@ func CommitRepoAction(opts CommitRepoActionOptions) error { | |||
| 	case ActionDeleteBranch: // Delete Branch
 | ||||
| 		isHookEventPush = true | ||||
| 
 | ||||
| 		if err = PrepareWebhooks(repo, HookEventDelete, &api.DeletePayload{ | ||||
| 			Ref:        refName, | ||||
| 			RefType:    "branch", | ||||
| 			PusherType: api.PusherTypeUser, | ||||
| 			Repo:       apiRepo, | ||||
| 			Sender:     apiPusher, | ||||
| 		}); err != nil { | ||||
| 			return fmt.Errorf("PrepareWebhooks.(delete branch): %v", err) | ||||
| 		} | ||||
| 
 | ||||
| 	case ActionPushTag: // Create
 | ||||
| 		isHookEventPush = true | ||||
| 
 | ||||
|  | @ -640,6 +650,16 @@ func CommitRepoAction(opts CommitRepoActionOptions) error { | |||
| 		} | ||||
| 	case ActionDeleteTag: // Delete Tag
 | ||||
| 		isHookEventPush = true | ||||
| 
 | ||||
| 		if err = PrepareWebhooks(repo, HookEventDelete, &api.DeletePayload{ | ||||
| 			Ref:        refName, | ||||
| 			RefType:    "tag", | ||||
| 			PusherType: api.PusherTypeUser, | ||||
| 			Repo:       apiRepo, | ||||
| 			Sender:     apiPusher, | ||||
| 		}); err != nil { | ||||
| 			return fmt.Errorf("PrepareWebhooks.(delete tag): %v", err) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if isHookEventPush { | ||||
|  |  | |||
|  | @ -83,9 +83,10 @@ const ( | |||
| type Comment struct { | ||||
| 	ID              int64 `xorm:"pk autoincr"` | ||||
| 	Type            CommentType | ||||
| 	PosterID        int64 `xorm:"INDEX"` | ||||
| 	Poster          *User `xorm:"-"` | ||||
| 	IssueID         int64 `xorm:"INDEX"` | ||||
| 	PosterID        int64  `xorm:"INDEX"` | ||||
| 	Poster          *User  `xorm:"-"` | ||||
| 	IssueID         int64  `xorm:"INDEX"` | ||||
| 	Issue           *Issue `xorm:"-"` | ||||
| 	LabelID         int64 | ||||
| 	Label           *Label `xorm:"-"` | ||||
| 	OldMilestoneID  int64 | ||||
|  | @ -116,6 +117,15 @@ type Comment struct { | |||
| 	ShowTag CommentTag `xorm:"-"` | ||||
| } | ||||
| 
 | ||||
| // LoadIssue loads issue from database
 | ||||
| func (c *Comment) LoadIssue() (err error) { | ||||
| 	if c.Issue != nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	c.Issue, err = GetIssueByID(c.IssueID) | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // AfterLoad is invoked from XORM after setting the values of all fields of this object.
 | ||||
| func (c *Comment) AfterLoad(session *xorm.Session) { | ||||
| 	var err error | ||||
|  | @ -146,40 +156,40 @@ func (c *Comment) AfterDelete() { | |||
| 
 | ||||
| // HTMLURL formats a URL-string to the issue-comment
 | ||||
| func (c *Comment) HTMLURL() string { | ||||
| 	issue, err := GetIssueByID(c.IssueID) | ||||
| 	err := c.LoadIssue() | ||||
| 	if err != nil { // Silently dropping errors :unamused:
 | ||||
| 		log.Error(4, "GetIssueByID(%d): %v", c.IssueID, err) | ||||
| 		log.Error(4, "LoadIssue(%d): %v", c.IssueID, err) | ||||
| 		return "" | ||||
| 	} | ||||
| 	return fmt.Sprintf("%s#%s", issue.HTMLURL(), c.HashTag()) | ||||
| 	return fmt.Sprintf("%s#%s", c.Issue.HTMLURL(), c.HashTag()) | ||||
| } | ||||
| 
 | ||||
| // IssueURL formats a URL-string to the issue
 | ||||
| func (c *Comment) IssueURL() string { | ||||
| 	issue, err := GetIssueByID(c.IssueID) | ||||
| 	err := c.LoadIssue() | ||||
| 	if err != nil { // Silently dropping errors :unamused:
 | ||||
| 		log.Error(4, "GetIssueByID(%d): %v", c.IssueID, err) | ||||
| 		log.Error(4, "LoadIssue(%d): %v", c.IssueID, err) | ||||
| 		return "" | ||||
| 	} | ||||
| 
 | ||||
| 	if issue.IsPull { | ||||
| 	if c.Issue.IsPull { | ||||
| 		return "" | ||||
| 	} | ||||
| 	return issue.HTMLURL() | ||||
| 	return c.Issue.HTMLURL() | ||||
| } | ||||
| 
 | ||||
| // PRURL formats a URL-string to the pull-request
 | ||||
| func (c *Comment) PRURL() string { | ||||
| 	issue, err := GetIssueByID(c.IssueID) | ||||
| 	err := c.LoadIssue() | ||||
| 	if err != nil { // Silently dropping errors :unamused:
 | ||||
| 		log.Error(4, "GetIssueByID(%d): %v", c.IssueID, err) | ||||
| 		log.Error(4, "LoadIssue(%d): %v", c.IssueID, err) | ||||
| 		return "" | ||||
| 	} | ||||
| 
 | ||||
| 	if !issue.IsPull { | ||||
| 	if !c.Issue.IsPull { | ||||
| 		return "" | ||||
| 	} | ||||
| 	return issue.HTMLURL() | ||||
| 	return c.Issue.HTMLURL() | ||||
| } | ||||
| 
 | ||||
| // APIFormat converts a Comment to the api.Comment format
 | ||||
|  | @ -196,9 +206,14 @@ func (c *Comment) APIFormat() *api.Comment { | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| // CommentHashTag returns unique hash tag for comment id.
 | ||||
| func CommentHashTag(id int64) string { | ||||
| 	return fmt.Sprintf("issuecomment-%d", id) | ||||
| } | ||||
| 
 | ||||
| // HashTag returns unique hash tag for comment.
 | ||||
| func (c *Comment) HashTag() string { | ||||
| 	return "issuecomment-" + com.ToStr(c.ID) | ||||
| 	return CommentHashTag(c.ID) | ||||
| } | ||||
| 
 | ||||
| // EventTag returns unique event hash tag for comment.
 | ||||
|  | @ -576,7 +591,7 @@ func CreateComment(opts *CreateCommentOptions) (comment *Comment, err error) { | |||
| 
 | ||||
| // CreateIssueComment creates a plain issue comment.
 | ||||
| func CreateIssueComment(doer *User, repo *Repository, issue *Issue, content string, attachments []string) (*Comment, error) { | ||||
| 	return CreateComment(&CreateCommentOptions{ | ||||
| 	comment, err := CreateComment(&CreateCommentOptions{ | ||||
| 		Type:        CommentTypeComment, | ||||
| 		Doer:        doer, | ||||
| 		Repo:        repo, | ||||
|  | @ -584,6 +599,21 @@ func CreateIssueComment(doer *User, repo *Repository, issue *Issue, content stri | |||
| 		Content:     content, | ||||
| 		Attachments: attachments, | ||||
| 	}) | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf("CreateComment: %v", err) | ||||
| 	} | ||||
| 
 | ||||
| 	mode, _ := AccessLevel(doer.ID, repo) | ||||
| 	if err = PrepareWebhooks(repo, HookEventIssueComment, &api.IssueCommentPayload{ | ||||
| 		Action:     api.HookIssueCommentCreated, | ||||
| 		Issue:      issue.APIFormat(), | ||||
| 		Comment:    comment.APIFormat(), | ||||
| 		Repository: repo.APIFormat(mode), | ||||
| 		Sender:     doer.APIFormat(), | ||||
| 	}); err != nil { | ||||
| 		log.Error(2, "PrepareWebhooks [comment_id: %d]: %v", comment.ID, err) | ||||
| 	} | ||||
| 	return comment, nil | ||||
| } | ||||
| 
 | ||||
| // CreateRefComment creates a commit reference comment to issue.
 | ||||
|  | @ -696,17 +726,41 @@ func GetCommentsByRepoIDSince(repoID, since int64) ([]*Comment, error) { | |||
| } | ||||
| 
 | ||||
| // UpdateComment updates information of comment.
 | ||||
| func UpdateComment(c *Comment) error { | ||||
| func UpdateComment(doer *User, c *Comment, oldContent string) error { | ||||
| 	if _, err := x.ID(c.ID).AllCols().Update(c); err != nil { | ||||
| 		return err | ||||
| 	} else if c.Type == CommentTypeComment { | ||||
| 		UpdateIssueIndexer(c.IssueID) | ||||
| 	} | ||||
| 
 | ||||
| 	if err := c.LoadIssue(); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if err := c.Issue.LoadAttributes(); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	mode, _ := AccessLevel(doer.ID, c.Issue.Repo) | ||||
| 	if err := PrepareWebhooks(c.Issue.Repo, HookEventIssueComment, &api.IssueCommentPayload{ | ||||
| 		Action:  api.HookIssueCommentEdited, | ||||
| 		Issue:   c.Issue.APIFormat(), | ||||
| 		Comment: c.APIFormat(), | ||||
| 		Changes: &api.ChangesPayload{ | ||||
| 			Body: &api.ChangesFromPayload{ | ||||
| 				From: oldContent, | ||||
| 			}, | ||||
| 		}, | ||||
| 		Repository: c.Issue.Repo.APIFormat(mode), | ||||
| 		Sender:     doer.APIFormat(), | ||||
| 	}); err != nil { | ||||
| 		log.Error(2, "PrepareWebhooks [comment_id: %d]: %v", c.ID, err) | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // DeleteComment deletes the comment
 | ||||
| func DeleteComment(comment *Comment) error { | ||||
| func DeleteComment(doer *User, comment *Comment) error { | ||||
| 	sess := x.NewSession() | ||||
| 	defer sess.Close() | ||||
| 	if err := sess.Begin(); err != nil { | ||||
|  | @ -733,5 +787,25 @@ func DeleteComment(comment *Comment) error { | |||
| 	} else if comment.Type == CommentTypeComment { | ||||
| 		UpdateIssueIndexer(comment.IssueID) | ||||
| 	} | ||||
| 
 | ||||
| 	if err := comment.LoadIssue(); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if err := comment.Issue.LoadAttributes(); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	mode, _ := AccessLevel(doer.ID, comment.Issue.Repo) | ||||
| 
 | ||||
| 	if err := PrepareWebhooks(comment.Issue.Repo, HookEventIssueComment, &api.IssueCommentPayload{ | ||||
| 		Action:     api.HookIssueCommentDeleted, | ||||
| 		Issue:      comment.Issue.APIFormat(), | ||||
| 		Comment:    comment.APIFormat(), | ||||
| 		Repository: comment.Issue.Repo.APIFormat(mode), | ||||
| 		Sender:     doer.APIFormat(), | ||||
| 	}); err != nil { | ||||
| 		log.Error(2, "PrepareWebhooks [comment_id: %d]: %v", comment.ID, err) | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
|  |  | |||
|  | @ -5,6 +5,9 @@ | |||
| package models | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 
 | ||||
| 	"code.gitea.io/gitea/modules/log" | ||||
| 	"code.gitea.io/gitea/modules/setting" | ||||
| 	"code.gitea.io/gitea/modules/util" | ||||
| 	api "code.gitea.io/sdk/gitea" | ||||
|  | @ -358,7 +361,49 @@ func ChangeMilestoneAssign(issue *Issue, doer *User, oldMilestoneID int64) (err | |||
| 	if err = changeMilestoneAssign(sess, doer, 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.HookIssueMilestoned | ||||
| 	} else { | ||||
| 		hookAction = api.HookIssueDemilestoned | ||||
| 	} | ||||
| 
 | ||||
| 	if err = issue.LoadAttributes(); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	mode, _ := AccessLevel(doer.ID, issue.Repo) | ||||
| 	if issue.IsPull { | ||||
| 		err = issue.PullRequest.LoadIssue() | ||||
| 		if err != nil { | ||||
| 			log.Error(2, "LoadIssue: %v", err) | ||||
| 			return | ||||
| 		} | ||||
| 		err = PrepareWebhooks(issue.Repo, HookEventPullRequest, &api.PullRequestPayload{ | ||||
| 			Action:      hookAction, | ||||
| 			Index:       issue.Index, | ||||
| 			PullRequest: issue.PullRequest.APIFormat(), | ||||
| 			Repository:  issue.Repo.APIFormat(mode), | ||||
| 			Sender:      doer.APIFormat(), | ||||
| 		}) | ||||
| 	} else { | ||||
| 		err = PrepareWebhooks(issue.Repo, HookEventIssues, &api.IssuePayload{ | ||||
| 			Action:     hookAction, | ||||
| 			Index:      issue.Index, | ||||
| 			Issue:      issue.APIFormat(), | ||||
| 			Repository: issue.Repo.APIFormat(mode), | ||||
| 			Sender:     doer.APIFormat(), | ||||
| 		}) | ||||
| 	} | ||||
| 	if err != nil { | ||||
| 		log.Error(2, "PrepareWebhooks [is_pull: %v]: %v", issue.IsPull, err) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // DeleteMilestoneByRepoID deletes a milestone from a repository.
 | ||||
|  |  | |||
|  | @ -232,6 +232,8 @@ func TestChangeMilestoneAssign(t *testing.T) { | |||
| 	assert.NoError(t, PrepareTestDatabase()) | ||||
| 	issue := AssertExistsAndLoadBean(t, &Issue{RepoID: 1}).(*Issue) | ||||
| 	doer := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User) | ||||
| 	assert.NotNil(t, issue) | ||||
| 	assert.NotNil(t, doer) | ||||
| 
 | ||||
| 	oldMilestoneID := issue.MilestoneID | ||||
| 	issue.MilestoneID = 2 | ||||
|  |  | |||
|  | @ -10,6 +10,7 @@ import ( | |||
| 	"strings" | ||||
| 
 | ||||
| 	"code.gitea.io/git" | ||||
| 	"code.gitea.io/gitea/modules/log" | ||||
| 	"code.gitea.io/gitea/modules/process" | ||||
| 	"code.gitea.io/gitea/modules/setting" | ||||
| 	"code.gitea.io/gitea/modules/util" | ||||
|  | @ -190,8 +191,27 @@ func CreateRelease(gitRepo *git.Repository, rel *Release, attachmentUUIDs []stri | |||
| 	} | ||||
| 
 | ||||
| 	err = addReleaseAttachments(rel.ID, attachmentUUIDs) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	return err | ||||
| 	if !rel.IsDraft { | ||||
| 		if err := rel.LoadAttributes(); err != nil { | ||||
| 			log.Error(2, "LoadAttributes: %v", err) | ||||
| 		} else { | ||||
| 			mode, _ := AccessLevel(rel.PublisherID, rel.Repo) | ||||
| 			if err := PrepareWebhooks(rel.Repo, HookEventRelease, &api.ReleasePayload{ | ||||
| 				Action:     api.HookReleasePublished, | ||||
| 				Release:    rel.APIFormat(), | ||||
| 				Repository: rel.Repo.APIFormat(mode), | ||||
| 				Sender:     rel.Publisher.APIFormat(), | ||||
| 			}); err != nil { | ||||
| 				log.Error(2, "PrepareWebhooks: %v", err) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // GetRelease returns release by given ID.
 | ||||
|  |  | |||
|  | @ -2456,6 +2456,17 @@ func ForkRepository(doer, u *User, oldRepo *Repository, name, desc string) (_ *R | |||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	oldMode, _ := AccessLevel(doer.ID, oldRepo) | ||||
| 	mode, _ := AccessLevel(doer.ID, repo) | ||||
| 
 | ||||
| 	if err = PrepareWebhooks(oldRepo, HookEventFork, &api.ForkPayload{ | ||||
| 		Forkee: repo.APIFormat(mode), | ||||
| 		Repo:   oldRepo.APIFormat(oldMode), | ||||
| 		Sender: doer.APIFormat(), | ||||
| 	}); err != nil { | ||||
| 		log.Error(2, "PrepareWebhooks [repo_id: %d]: %v", oldRepo.ID, err) | ||||
| 	} | ||||
| 
 | ||||
| 	if err = repo.UpdateSize(); err != nil { | ||||
| 		log.Error(4, "Failed to update size for repository: %v", err) | ||||
| 	} | ||||
|  |  | |||
|  | @ -66,10 +66,15 @@ func IsValidHookContentType(name string) bool { | |||
| 
 | ||||
| // HookEvents is a set of web hook events
 | ||||
| type HookEvents struct { | ||||
| 	Create      bool `json:"create"` | ||||
| 	Push        bool `json:"push"` | ||||
| 	PullRequest bool `json:"pull_request"` | ||||
| 	Repository  bool `json:"repository"` | ||||
| 	Create       bool `json:"create"` | ||||
| 	Delete       bool `json:"delete"` | ||||
| 	Fork         bool `json:"fork"` | ||||
| 	Issues       bool `json:"issues"` | ||||
| 	IssueComment bool `json:"issue_comment"` | ||||
| 	Push         bool `json:"push"` | ||||
| 	PullRequest  bool `json:"pull_request"` | ||||
| 	Repository   bool `json:"repository"` | ||||
| 	Release      bool `json:"release"` | ||||
| } | ||||
| 
 | ||||
| // HookEvent represents events that will delivery hook.
 | ||||
|  | @ -155,6 +160,30 @@ func (w *Webhook) HasCreateEvent() bool { | |||
| 		(w.ChooseEvents && w.HookEvents.Create) | ||||
| } | ||||
| 
 | ||||
| // HasDeleteEvent returns true if hook enabled delete event.
 | ||||
| func (w *Webhook) HasDeleteEvent() bool { | ||||
| 	return w.SendEverything || | ||||
| 		(w.ChooseEvents && w.HookEvents.Delete) | ||||
| } | ||||
| 
 | ||||
| // HasForkEvent returns true if hook enabled fork event.
 | ||||
| func (w *Webhook) HasForkEvent() bool { | ||||
| 	return w.SendEverything || | ||||
| 		(w.ChooseEvents && w.HookEvents.Fork) | ||||
| } | ||||
| 
 | ||||
| // HasIssuesEvent returns true if hook enabled issues event.
 | ||||
| func (w *Webhook) HasIssuesEvent() bool { | ||||
| 	return w.SendEverything || | ||||
| 		(w.ChooseEvents && w.HookEvents.Issues) | ||||
| } | ||||
| 
 | ||||
| // HasIssueCommentEvent returns true if hook enabled issue_comment event.
 | ||||
| func (w *Webhook) HasIssueCommentEvent() bool { | ||||
| 	return w.SendEverything || | ||||
| 		(w.ChooseEvents && w.HookEvents.IssueComment) | ||||
| } | ||||
| 
 | ||||
| // HasPushEvent returns true if hook enabled push event.
 | ||||
| func (w *Webhook) HasPushEvent() bool { | ||||
| 	return w.PushOnly || w.SendEverything || | ||||
|  | @ -167,23 +196,46 @@ func (w *Webhook) HasPullRequestEvent() bool { | |||
| 		(w.ChooseEvents && w.HookEvents.PullRequest) | ||||
| } | ||||
| 
 | ||||
| // HasReleaseEvent returns if hook enabled release event.
 | ||||
| func (w *Webhook) HasReleaseEvent() bool { | ||||
| 	return w.SendEverything || | ||||
| 		(w.ChooseEvents && w.HookEvents.Release) | ||||
| } | ||||
| 
 | ||||
| // HasRepositoryEvent returns if hook enabled repository event.
 | ||||
| func (w *Webhook) HasRepositoryEvent() bool { | ||||
| 	return w.SendEverything || | ||||
| 		(w.ChooseEvents && w.HookEvents.Repository) | ||||
| } | ||||
| 
 | ||||
| func (w *Webhook) eventCheckers() []struct { | ||||
| 	has func() bool | ||||
| 	typ HookEventType | ||||
| } { | ||||
| 	return []struct { | ||||
| 		has func() bool | ||||
| 		typ HookEventType | ||||
| 	}{ | ||||
| 		{w.HasCreateEvent, HookEventCreate}, | ||||
| 		{w.HasDeleteEvent, HookEventDelete}, | ||||
| 		{w.HasForkEvent, HookEventFork}, | ||||
| 		{w.HasPushEvent, HookEventPush}, | ||||
| 		{w.HasIssuesEvent, HookEventIssues}, | ||||
| 		{w.HasIssueCommentEvent, HookEventIssueComment}, | ||||
| 		{w.HasPullRequestEvent, HookEventPullRequest}, | ||||
| 		{w.HasRepositoryEvent, HookEventRepository}, | ||||
| 		{w.HasReleaseEvent, HookEventRelease}, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // EventsArray returns an array of hook events
 | ||||
| func (w *Webhook) EventsArray() []string { | ||||
| 	events := make([]string, 0, 3) | ||||
| 	if w.HasCreateEvent() { | ||||
| 		events = append(events, "create") | ||||
| 	} | ||||
| 	if w.HasPushEvent() { | ||||
| 		events = append(events, "push") | ||||
| 	} | ||||
| 	if w.HasPullRequestEvent() { | ||||
| 		events = append(events, "pull_request") | ||||
| 	events := make([]string, 0, 7) | ||||
| 
 | ||||
| 	for _, c := range w.eventCheckers() { | ||||
| 		if c.has() { | ||||
| 			events = append(events, string(c.typ)) | ||||
| 		} | ||||
| 	} | ||||
| 	return events | ||||
| } | ||||
|  | @ -373,10 +425,15 @@ type HookEventType string | |||
| 
 | ||||
| // Types of hook events
 | ||||
| const ( | ||||
| 	HookEventCreate      HookEventType = "create" | ||||
| 	HookEventPush        HookEventType = "push" | ||||
| 	HookEventPullRequest HookEventType = "pull_request" | ||||
| 	HookEventRepository  HookEventType = "repository" | ||||
| 	HookEventCreate       HookEventType = "create" | ||||
| 	HookEventDelete       HookEventType = "delete" | ||||
| 	HookEventFork         HookEventType = "fork" | ||||
| 	HookEventPush         HookEventType = "push" | ||||
| 	HookEventIssues       HookEventType = "issues" | ||||
| 	HookEventIssueComment HookEventType = "issue_comment" | ||||
| 	HookEventPullRequest  HookEventType = "pull_request" | ||||
| 	HookEventRepository   HookEventType = "repository" | ||||
| 	HookEventRelease      HookEventType = "release" | ||||
| ) | ||||
| 
 | ||||
| // HookRequest represents hook task request information.
 | ||||
|  | @ -488,22 +545,11 @@ func PrepareWebhook(w *Webhook, repo *Repository, event HookEventType, p api.Pay | |||
| } | ||||
| 
 | ||||
| func prepareWebhook(e Engine, w *Webhook, repo *Repository, event HookEventType, p api.Payloader) error { | ||||
| 	switch event { | ||||
| 	case HookEventCreate: | ||||
| 		if !w.HasCreateEvent() { | ||||
| 			return nil | ||||
| 		} | ||||
| 	case HookEventPush: | ||||
| 		if !w.HasPushEvent() { | ||||
| 			return nil | ||||
| 		} | ||||
| 	case HookEventPullRequest: | ||||
| 		if !w.HasPullRequestEvent() { | ||||
| 			return nil | ||||
| 		} | ||||
| 	case HookEventRepository: | ||||
| 		if !w.HasRepositoryEvent() { | ||||
| 			return nil | ||||
| 	for _, e := range w.eventCheckers() { | ||||
| 		if event == e.typ { | ||||
| 			if !e.has() { | ||||
| 				return nil | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|  |  | |||
|  | @ -49,6 +49,38 @@ func getDingtalkCreatePayload(p *api.CreatePayload) (*DingtalkPayload, error) { | |||
| 	}, nil | ||||
| } | ||||
| 
 | ||||
| func getDingtalkDeletePayload(p *api.DeletePayload) (*DingtalkPayload, error) { | ||||
| 	// created tag/branch
 | ||||
| 	refName := git.RefEndName(p.Ref) | ||||
| 	title := fmt.Sprintf("[%s] %s %s deleted", p.Repo.FullName, p.RefType, refName) | ||||
| 
 | ||||
| 	return &DingtalkPayload{ | ||||
| 		MsgType: "actionCard", | ||||
| 		ActionCard: dingtalk.ActionCard{ | ||||
| 			Text:        title, | ||||
| 			Title:       title, | ||||
| 			HideAvatar:  "0", | ||||
| 			SingleTitle: fmt.Sprintf("view branch %s", refName), | ||||
| 			SingleURL:   p.Repo.HTMLURL + "/src/" + refName, | ||||
| 		}, | ||||
| 	}, nil | ||||
| } | ||||
| 
 | ||||
| func getDingtalkForkPayload(p *api.ForkPayload) (*DingtalkPayload, error) { | ||||
| 	title := fmt.Sprintf("%s is forked to %s", p.Forkee.FullName, p.Repo.FullName) | ||||
| 
 | ||||
| 	return &DingtalkPayload{ | ||||
| 		MsgType: "actionCard", | ||||
| 		ActionCard: dingtalk.ActionCard{ | ||||
| 			Text:        title, | ||||
| 			Title:       title, | ||||
| 			HideAvatar:  "0", | ||||
| 			SingleTitle: fmt.Sprintf("view forked repo %s", p.Repo.FullName), | ||||
| 			SingleURL:   p.Repo.HTMLURL, | ||||
| 		}, | ||||
| 	}, nil | ||||
| } | ||||
| 
 | ||||
| func getDingtalkPushPayload(p *api.PushPayload) (*DingtalkPayload, error) { | ||||
| 	var ( | ||||
| 		branchName = git.RefEndName(p.Ref) | ||||
|  | @ -98,6 +130,80 @@ func getDingtalkPushPayload(p *api.PushPayload) (*DingtalkPayload, error) { | |||
| 	}, nil | ||||
| } | ||||
| 
 | ||||
| func getDingtalkIssuesPayload(p *api.IssuePayload) (*DingtalkPayload, error) { | ||||
| 	var text, title string | ||||
| 	switch p.Action { | ||||
| 	case api.HookIssueOpened: | ||||
| 		title = fmt.Sprintf("[%s] Issue opened: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title) | ||||
| 		text = p.Issue.Body | ||||
| 	case api.HookIssueClosed: | ||||
| 		title = fmt.Sprintf("[%s] Issue closed: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title) | ||||
| 		text = p.Issue.Body | ||||
| 	case api.HookIssueReOpened: | ||||
| 		title = fmt.Sprintf("[%s] Issue re-opened: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title) | ||||
| 		text = p.Issue.Body | ||||
| 	case api.HookIssueEdited: | ||||
| 		title = fmt.Sprintf("[%s] Issue edited: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title) | ||||
| 		text = p.Issue.Body | ||||
| 	case api.HookIssueAssigned: | ||||
| 		title = fmt.Sprintf("[%s] Issue assigned to %s: #%d %s", p.Repository.FullName, | ||||
| 			p.Issue.Assignee.UserName, p.Index, p.Issue.Title) | ||||
| 		text = p.Issue.Body | ||||
| 	case api.HookIssueUnassigned: | ||||
| 		title = fmt.Sprintf("[%s] Issue unassigned: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title) | ||||
| 		text = p.Issue.Body | ||||
| 	case api.HookIssueLabelUpdated: | ||||
| 		title = fmt.Sprintf("[%s] Pull request labels updated: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title) | ||||
| 		text = p.Issue.Body | ||||
| 	case api.HookIssueLabelCleared: | ||||
| 		title = fmt.Sprintf("[%s] Pull request labels cleared: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title) | ||||
| 		text = p.Issue.Body | ||||
| 	case api.HookIssueSynchronized: | ||||
| 		title = fmt.Sprintf("[%s] Pull request synchronized: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title) | ||||
| 		text = p.Issue.Body | ||||
| 	} | ||||
| 
 | ||||
| 	return &DingtalkPayload{ | ||||
| 		MsgType: "actionCard", | ||||
| 		ActionCard: dingtalk.ActionCard{ | ||||
| 			Text:        text, | ||||
| 			Title:       title, | ||||
| 			HideAvatar:  "0", | ||||
| 			SingleTitle: "view pull request", | ||||
| 			SingleURL:   p.Issue.URL, | ||||
| 		}, | ||||
| 	}, nil | ||||
| } | ||||
| 
 | ||||
| func getDingtalkIssueCommentPayload(p *api.IssueCommentPayload) (*DingtalkPayload, error) { | ||||
| 	title := fmt.Sprintf("#%d %s", p.Issue.Index, p.Issue.Title) | ||||
| 	url := fmt.Sprintf("%s/issues/%d#%s", p.Repository.HTMLURL, p.Issue.Index, CommentHashTag(p.Comment.ID)) | ||||
| 	var content string | ||||
| 	switch p.Action { | ||||
| 	case api.HookIssueCommentCreated: | ||||
| 		title = "New comment: " + title | ||||
| 		content = p.Comment.Body | ||||
| 	case api.HookIssueCommentEdited: | ||||
| 		title = "Comment edited: " + title | ||||
| 		content = p.Comment.Body | ||||
| 	case api.HookIssueCommentDeleted: | ||||
| 		title = "Comment deleted: " + title | ||||
| 		url = fmt.Sprintf("%s/issues/%d", p.Repository.HTMLURL, p.Issue.Index) | ||||
| 		content = p.Comment.Body | ||||
| 	} | ||||
| 
 | ||||
| 	return &DingtalkPayload{ | ||||
| 		MsgType: "actionCard", | ||||
| 		ActionCard: dingtalk.ActionCard{ | ||||
| 			Text:        content, | ||||
| 			Title:       title, | ||||
| 			HideAvatar:  "0", | ||||
| 			SingleTitle: "view pull request", | ||||
| 			SingleURL:   url, | ||||
| 		}, | ||||
| 	}, nil | ||||
| } | ||||
| 
 | ||||
| func getDingtalkPullRequestPayload(p *api.PullRequestPayload) (*DingtalkPayload, error) { | ||||
| 	var text, title string | ||||
| 	switch p.Action { | ||||
|  | @ -182,6 +288,27 @@ func getDingtalkRepositoryPayload(p *api.RepositoryPayload) (*DingtalkPayload, e | |||
| 	return nil, nil | ||||
| } | ||||
| 
 | ||||
| func getDingtalkReleasePayload(p *api.ReleasePayload) (*DingtalkPayload, error) { | ||||
| 	var title, url string | ||||
| 	switch p.Action { | ||||
| 	case api.HookReleasePublished: | ||||
| 		title = fmt.Sprintf("[%s] Release created", p.Release.TagName) | ||||
| 		url = p.Release.URL | ||||
| 		return &DingtalkPayload{ | ||||
| 			MsgType: "actionCard", | ||||
| 			ActionCard: dingtalk.ActionCard{ | ||||
| 				Text:        title, | ||||
| 				Title:       title, | ||||
| 				HideAvatar:  "0", | ||||
| 				SingleTitle: "view repository", | ||||
| 				SingleURL:   url, | ||||
| 			}, | ||||
| 		}, nil | ||||
| 	} | ||||
| 
 | ||||
| 	return nil, nil | ||||
| } | ||||
| 
 | ||||
| // GetDingtalkPayload converts a ding talk webhook into a DingtalkPayload
 | ||||
| func GetDingtalkPayload(p api.Payloader, event HookEventType, meta string) (*DingtalkPayload, error) { | ||||
| 	s := new(DingtalkPayload) | ||||
|  | @ -189,12 +316,22 @@ func GetDingtalkPayload(p api.Payloader, event HookEventType, meta string) (*Din | |||
| 	switch event { | ||||
| 	case HookEventCreate: | ||||
| 		return getDingtalkCreatePayload(p.(*api.CreatePayload)) | ||||
| 	case HookEventDelete: | ||||
| 		return getDingtalkDeletePayload(p.(*api.DeletePayload)) | ||||
| 	case HookEventFork: | ||||
| 		return getDingtalkForkPayload(p.(*api.ForkPayload)) | ||||
| 	case HookEventIssues: | ||||
| 		return getDingtalkIssuesPayload(p.(*api.IssuePayload)) | ||||
| 	case HookEventIssueComment: | ||||
| 		return getDingtalkIssueCommentPayload(p.(*api.IssueCommentPayload)) | ||||
| 	case HookEventPush: | ||||
| 		return getDingtalkPushPayload(p.(*api.PushPayload)) | ||||
| 	case HookEventPullRequest: | ||||
| 		return getDingtalkPullRequestPayload(p.(*api.PullRequestPayload)) | ||||
| 	case HookEventRepository: | ||||
| 		return getDingtalkRepositoryPayload(p.(*api.RepositoryPayload)) | ||||
| 	case HookEventRelease: | ||||
| 		return getDingtalkReleasePayload(p.(*api.ReleasePayload)) | ||||
| 	} | ||||
| 
 | ||||
| 	return s, nil | ||||
|  |  | |||
|  | @ -115,6 +115,51 @@ func getDiscordCreatePayload(p *api.CreatePayload, meta *DiscordMeta) (*DiscordP | |||
| 	}, nil | ||||
| } | ||||
| 
 | ||||
| func getDiscordDeletePayload(p *api.DeletePayload, meta *DiscordMeta) (*DiscordPayload, error) { | ||||
| 	// deleted tag/branch
 | ||||
| 	refName := git.RefEndName(p.Ref) | ||||
| 	title := fmt.Sprintf("[%s] %s %s deleted", p.Repo.FullName, p.RefType, refName) | ||||
| 
 | ||||
| 	return &DiscordPayload{ | ||||
| 		Username:  meta.Username, | ||||
| 		AvatarURL: meta.IconURL, | ||||
| 		Embeds: []DiscordEmbed{ | ||||
| 			{ | ||||
| 				Title: title, | ||||
| 				URL:   p.Repo.HTMLURL + "/src/" + refName, | ||||
| 				Color: warnColor, | ||||
| 				Author: DiscordEmbedAuthor{ | ||||
| 					Name:    p.Sender.UserName, | ||||
| 					URL:     setting.AppURL + p.Sender.UserName, | ||||
| 					IconURL: p.Sender.AvatarURL, | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 	}, nil | ||||
| } | ||||
| 
 | ||||
| func getDiscordForkPayload(p *api.ForkPayload, meta *DiscordMeta) (*DiscordPayload, error) { | ||||
| 	// fork
 | ||||
| 	title := fmt.Sprintf("%s is forked to %s", p.Forkee.FullName, p.Repo.FullName) | ||||
| 
 | ||||
| 	return &DiscordPayload{ | ||||
| 		Username:  meta.Username, | ||||
| 		AvatarURL: meta.IconURL, | ||||
| 		Embeds: []DiscordEmbed{ | ||||
| 			{ | ||||
| 				Title: title, | ||||
| 				URL:   p.Repo.HTMLURL, | ||||
| 				Color: successColor, | ||||
| 				Author: DiscordEmbedAuthor{ | ||||
| 					Name:    p.Sender.UserName, | ||||
| 					URL:     setting.AppURL + p.Sender.UserName, | ||||
| 					IconURL: p.Sender.AvatarURL, | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 	}, nil | ||||
| } | ||||
| 
 | ||||
| func getDiscordPushPayload(p *api.PushPayload, meta *DiscordMeta) (*DiscordPayload, error) { | ||||
| 	var ( | ||||
| 		branchName = git.RefEndName(p.Ref) | ||||
|  | @ -165,6 +210,108 @@ func getDiscordPushPayload(p *api.PushPayload, meta *DiscordMeta) (*DiscordPaylo | |||
| 	}, nil | ||||
| } | ||||
| 
 | ||||
| func getDiscordIssuesPayload(p *api.IssuePayload, meta *DiscordMeta) (*DiscordPayload, error) { | ||||
| 	var text, title string | ||||
| 	var color int | ||||
| 	switch p.Action { | ||||
| 	case api.HookIssueOpened: | ||||
| 		title = fmt.Sprintf("[%s] Issue opened: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title) | ||||
| 		text = p.Issue.Body | ||||
| 		color = warnColor | ||||
| 	case api.HookIssueClosed: | ||||
| 		title = fmt.Sprintf("[%s] Issue closed: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title) | ||||
| 		color = failedColor | ||||
| 		text = p.Issue.Body | ||||
| 	case api.HookIssueReOpened: | ||||
| 		title = fmt.Sprintf("[%s] Issue re-opened: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title) | ||||
| 		text = p.Issue.Body | ||||
| 		color = warnColor | ||||
| 	case api.HookIssueEdited: | ||||
| 		title = fmt.Sprintf("[%s] Issue edited: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title) | ||||
| 		text = p.Issue.Body | ||||
| 		color = warnColor | ||||
| 	case api.HookIssueAssigned: | ||||
| 		title = fmt.Sprintf("[%s] Issue assigned to %s: #%d %s", p.Repository.FullName, | ||||
| 			p.Issue.Assignee.UserName, p.Index, p.Issue.Title) | ||||
| 		text = p.Issue.Body | ||||
| 		color = successColor | ||||
| 	case api.HookIssueUnassigned: | ||||
| 		title = fmt.Sprintf("[%s] Issue unassigned: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title) | ||||
| 		text = p.Issue.Body | ||||
| 		color = warnColor | ||||
| 	case api.HookIssueLabelUpdated: | ||||
| 		title = fmt.Sprintf("[%s] Issue labels updated: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title) | ||||
| 		text = p.Issue.Body | ||||
| 		color = warnColor | ||||
| 	case api.HookIssueLabelCleared: | ||||
| 		title = fmt.Sprintf("[%s] Issue labels cleared: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title) | ||||
| 		text = p.Issue.Body | ||||
| 		color = warnColor | ||||
| 	case api.HookIssueSynchronized: | ||||
| 		title = fmt.Sprintf("[%s] Issue synchronized: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title) | ||||
| 		text = p.Issue.Body | ||||
| 		color = warnColor | ||||
| 	} | ||||
| 
 | ||||
| 	return &DiscordPayload{ | ||||
| 		Username:  meta.Username, | ||||
| 		AvatarURL: meta.IconURL, | ||||
| 		Embeds: []DiscordEmbed{ | ||||
| 			{ | ||||
| 				Title:       title, | ||||
| 				Description: text, | ||||
| 				URL:         p.Issue.URL, | ||||
| 				Color:       color, | ||||
| 				Author: DiscordEmbedAuthor{ | ||||
| 					Name:    p.Sender.UserName, | ||||
| 					URL:     setting.AppURL + p.Sender.UserName, | ||||
| 					IconURL: p.Sender.AvatarURL, | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 	}, nil | ||||
| } | ||||
| 
 | ||||
| func getDiscordIssueCommentPayload(p *api.IssueCommentPayload, discord *DiscordMeta) (*DiscordPayload, error) { | ||||
| 	title := fmt.Sprintf("#%d %s", p.Issue.Index, p.Issue.Title) | ||||
| 	url := fmt.Sprintf("%s/issues/%d#%s", p.Repository.HTMLURL, p.Issue.Index, CommentHashTag(p.Comment.ID)) | ||||
| 	content := "" | ||||
| 	var color int | ||||
| 	switch p.Action { | ||||
| 	case api.HookIssueCommentCreated: | ||||
| 		title = "New comment: " + title | ||||
| 		content = p.Comment.Body | ||||
| 		color = successColor | ||||
| 	case api.HookIssueCommentEdited: | ||||
| 		title = "Comment edited: " + title | ||||
| 		content = p.Comment.Body | ||||
| 		color = warnColor | ||||
| 	case api.HookIssueCommentDeleted: | ||||
| 		title = "Comment deleted: " + title | ||||
| 		url = fmt.Sprintf("%s/issues/%d", p.Repository.HTMLURL, p.Issue.Index) | ||||
| 		content = p.Comment.Body | ||||
| 		color = warnColor | ||||
| 	} | ||||
| 
 | ||||
| 	return &DiscordPayload{ | ||||
| 		Username:  discord.Username, | ||||
| 		AvatarURL: discord.IconURL, | ||||
| 		Embeds: []DiscordEmbed{ | ||||
| 			{ | ||||
| 				Title:       title, | ||||
| 				Description: content, | ||||
| 				URL:         url, | ||||
| 				Color:       color, | ||||
| 				Author: DiscordEmbedAuthor{ | ||||
| 					Name:    p.Sender.UserName, | ||||
| 					URL:     setting.AppURL + p.Sender.UserName, | ||||
| 					IconURL: p.Sender.AvatarURL, | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 	}, nil | ||||
| } | ||||
| 
 | ||||
| func getDiscordPullRequestPayload(p *api.PullRequestPayload, meta *DiscordMeta) (*DiscordPayload, error) { | ||||
| 	var text, title string | ||||
| 	var color int | ||||
|  | @ -267,6 +414,35 @@ func getDiscordRepositoryPayload(p *api.RepositoryPayload, meta *DiscordMeta) (* | |||
| 	}, nil | ||||
| } | ||||
| 
 | ||||
| func getDiscordReleasePayload(p *api.ReleasePayload, meta *DiscordMeta) (*DiscordPayload, error) { | ||||
| 	var title, url string | ||||
| 	var color int | ||||
| 	switch p.Action { | ||||
| 	case api.HookReleasePublished: | ||||
| 		title = fmt.Sprintf("[%s] Release created", p.Release.TagName) | ||||
| 		url = p.Release.URL | ||||
| 		color = successColor | ||||
| 	} | ||||
| 
 | ||||
| 	return &DiscordPayload{ | ||||
| 		Username:  meta.Username, | ||||
| 		AvatarURL: meta.IconURL, | ||||
| 		Embeds: []DiscordEmbed{ | ||||
| 			{ | ||||
| 				Title:       title, | ||||
| 				Description: fmt.Sprintf("%s", p.Release.Note), | ||||
| 				URL:         url, | ||||
| 				Color:       color, | ||||
| 				Author: DiscordEmbedAuthor{ | ||||
| 					Name:    p.Sender.UserName, | ||||
| 					URL:     setting.AppURL + p.Sender.UserName, | ||||
| 					IconURL: p.Sender.AvatarURL, | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 	}, nil | ||||
| } | ||||
| 
 | ||||
| // GetDiscordPayload converts a discord webhook into a DiscordPayload
 | ||||
| func GetDiscordPayload(p api.Payloader, event HookEventType, meta string) (*DiscordPayload, error) { | ||||
| 	s := new(DiscordPayload) | ||||
|  | @ -279,12 +455,22 @@ func GetDiscordPayload(p api.Payloader, event HookEventType, meta string) (*Disc | |||
| 	switch event { | ||||
| 	case HookEventCreate: | ||||
| 		return getDiscordCreatePayload(p.(*api.CreatePayload), discord) | ||||
| 	case HookEventDelete: | ||||
| 		return getDiscordDeletePayload(p.(*api.DeletePayload), discord) | ||||
| 	case HookEventFork: | ||||
| 		return getDiscordForkPayload(p.(*api.ForkPayload), discord) | ||||
| 	case HookEventIssues: | ||||
| 		return getDiscordIssuesPayload(p.(*api.IssuePayload), discord) | ||||
| 	case HookEventIssueComment: | ||||
| 		return getDiscordIssueCommentPayload(p.(*api.IssueCommentPayload), discord) | ||||
| 	case HookEventPush: | ||||
| 		return getDiscordPushPayload(p.(*api.PushPayload), discord) | ||||
| 	case HookEventPullRequest: | ||||
| 		return getDiscordPullRequestPayload(p.(*api.PullRequestPayload), discord) | ||||
| 	case HookEventRepository: | ||||
| 		return getDiscordRepositoryPayload(p.(*api.RepositoryPayload), discord) | ||||
| 	case HookEventRelease: | ||||
| 		return getDiscordReleasePayload(p.(*api.ReleasePayload), discord) | ||||
| 	} | ||||
| 
 | ||||
| 	return s, nil | ||||
|  |  | |||
|  | @ -106,6 +106,122 @@ func getSlackCreatePayload(p *api.CreatePayload, slack *SlackMeta) (*SlackPayloa | |||
| 	}, nil | ||||
| } | ||||
| 
 | ||||
| // getSlackDeletePayload composes Slack payload for delete a branch or tag.
 | ||||
| func getSlackDeletePayload(p *api.DeletePayload, slack *SlackMeta) (*SlackPayload, error) { | ||||
| 	refName := git.RefEndName(p.Ref) | ||||
| 	repoLink := SlackLinkFormatter(p.Repo.HTMLURL, p.Repo.Name) | ||||
| 	text := fmt.Sprintf("[%s:%s] %s deleted by %s", repoLink, refName, p.RefType, p.Sender.UserName) | ||||
| 	return &SlackPayload{ | ||||
| 		Channel:  slack.Channel, | ||||
| 		Text:     text, | ||||
| 		Username: slack.Username, | ||||
| 		IconURL:  slack.IconURL, | ||||
| 	}, nil | ||||
| } | ||||
| 
 | ||||
| // getSlackForkPayload composes Slack payload for forked by a repository.
 | ||||
| func getSlackForkPayload(p *api.ForkPayload, slack *SlackMeta) (*SlackPayload, error) { | ||||
| 	baseLink := SlackLinkFormatter(p.Repo.HTMLURL, p.Repo.Name) | ||||
| 	forkLink := SlackLinkFormatter(p.Forkee.HTMLURL, p.Forkee.FullName) | ||||
| 	text := fmt.Sprintf("%s is forked to %s", baseLink, forkLink) | ||||
| 	return &SlackPayload{ | ||||
| 		Channel:  slack.Channel, | ||||
| 		Text:     text, | ||||
| 		Username: slack.Username, | ||||
| 		IconURL:  slack.IconURL, | ||||
| 	}, nil | ||||
| } | ||||
| 
 | ||||
| func getSlackIssuesPayload(p *api.IssuePayload, 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), | ||||
| 		fmt.Sprintf("#%d %s", p.Index, p.Issue.Title)) | ||||
| 	var text, title, attachmentText string | ||||
| 	switch p.Action { | ||||
| 	case api.HookIssueOpened: | ||||
| 		text = fmt.Sprintf("[%s] Issue submitted by %s", p.Repository.FullName, senderLink) | ||||
| 		title = titleLink | ||||
| 		attachmentText = SlackTextFormatter(p.Issue.Body) | ||||
| 	case api.HookIssueClosed: | ||||
| 		text = fmt.Sprintf("[%s] Issue closed: %s by %s", p.Repository.FullName, titleLink, senderLink) | ||||
| 	case api.HookIssueReOpened: | ||||
| 		text = fmt.Sprintf("[%s] Issue re-opened: %s by %s", p.Repository.FullName, titleLink, senderLink) | ||||
| 	case api.HookIssueEdited: | ||||
| 		text = fmt.Sprintf("[%s] Issue edited: %s by %s", p.Repository.FullName, titleLink, senderLink) | ||||
| 		attachmentText = SlackTextFormatter(p.Issue.Body) | ||||
| 	case api.HookIssueAssigned: | ||||
| 		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.HookIssueUnassigned: | ||||
| 		text = fmt.Sprintf("[%s] Issue unassigned: %s by %s", p.Repository.FullName, titleLink, senderLink) | ||||
| 	case api.HookIssueLabelUpdated: | ||||
| 		text = fmt.Sprintf("[%s] Issue labels updated: %s by %s", p.Repository.FullName, titleLink, senderLink) | ||||
| 	case api.HookIssueLabelCleared: | ||||
| 		text = fmt.Sprintf("[%s] Issue labels cleared: %s by %s", p.Repository.FullName, titleLink, senderLink) | ||||
| 	case api.HookIssueSynchronized: | ||||
| 		text = fmt.Sprintf("[%s] Issue synchronized: %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 getSlackIssueCommentPayload(p *api.IssueCommentPayload, slack *SlackMeta) (*SlackPayload, error) { | ||||
| 	senderLink := SlackLinkFormatter(setting.AppURL+p.Sender.UserName, p.Sender.UserName) | ||||
| 	titleLink := SlackLinkFormatter(fmt.Sprintf("%s/issues/%d#%s", p.Repository.HTMLURL, p.Issue.Index, CommentHashTag(p.Comment.ID)), | ||||
| 		fmt.Sprintf("#%d %s", p.Issue.Index, p.Issue.Title)) | ||||
| 	var text, title, attachmentText string | ||||
| 	switch p.Action { | ||||
| 	case api.HookIssueCommentCreated: | ||||
| 		text = fmt.Sprintf("[%s] New comment created by %s", p.Repository.FullName, senderLink) | ||||
| 		title = titleLink | ||||
| 		attachmentText = SlackTextFormatter(p.Comment.Body) | ||||
| 	case api.HookIssueCommentEdited: | ||||
| 		text = fmt.Sprintf("[%s] Comment edited by %s", p.Repository.FullName, senderLink) | ||||
| 		title = titleLink | ||||
| 		attachmentText = SlackTextFormatter(p.Comment.Body) | ||||
| 	case api.HookIssueCommentDeleted: | ||||
| 		text = fmt.Sprintf("[%s] Comment deleted by %s", p.Repository.FullName, senderLink) | ||||
| 		title = SlackLinkFormatter(fmt.Sprintf("%s/issues/%d", p.Repository.HTMLURL, p.Issue.Index), | ||||
| 			fmt.Sprintf("#%d %s", p.Issue.Index, p.Issue.Title)) | ||||
| 		attachmentText = SlackTextFormatter(p.Comment.Body) | ||||
| 	} | ||||
| 
 | ||||
| 	return &SlackPayload{ | ||||
| 		Channel:  slack.Channel, | ||||
| 		Text:     text, | ||||
| 		Username: slack.Username, | ||||
| 		IconURL:  slack.IconURL, | ||||
| 		Attachments: []SlackAttachment{{ | ||||
| 			Color: slack.Color, | ||||
| 			Title: title, | ||||
| 			Text:  attachmentText, | ||||
| 		}}, | ||||
| 	}, nil | ||||
| } | ||||
| 
 | ||||
| func getSlackReleasePayload(p *api.ReleasePayload, slack *SlackMeta) (*SlackPayload, error) { | ||||
| 	repoLink := SlackLinkFormatter(p.Repository.HTMLURL, p.Repository.Name) | ||||
| 	refLink := SlackLinkFormatter(p.Repository.HTMLURL+"/src/"+p.Release.TagName, p.Release.TagName) | ||||
| 	text := fmt.Sprintf("[%s] new release %s published by %s", repoLink, refLink, p.Sender.UserName) | ||||
| 	return &SlackPayload{ | ||||
| 		Channel:  slack.Channel, | ||||
| 		Text:     text, | ||||
| 		Username: slack.Username, | ||||
| 		IconURL:  slack.IconURL, | ||||
| 	}, nil | ||||
| } | ||||
| 
 | ||||
| func getSlackPushPayload(p *api.PushPayload, slack *SlackMeta) (*SlackPayload, error) { | ||||
| 	// n new commits
 | ||||
| 	var ( | ||||
|  | @ -238,12 +354,22 @@ func GetSlackPayload(p api.Payloader, event HookEventType, meta string) (*SlackP | |||
| 	switch event { | ||||
| 	case HookEventCreate: | ||||
| 		return getSlackCreatePayload(p.(*api.CreatePayload), slack) | ||||
| 	case HookEventDelete: | ||||
| 		return getSlackDeletePayload(p.(*api.DeletePayload), slack) | ||||
| 	case HookEventFork: | ||||
| 		return getSlackForkPayload(p.(*api.ForkPayload), slack) | ||||
| 	case HookEventIssues: | ||||
| 		return getSlackIssuesPayload(p.(*api.IssuePayload), slack) | ||||
| 	case HookEventIssueComment: | ||||
| 		return getSlackIssueCommentPayload(p.(*api.IssueCommentPayload), slack) | ||||
| 	case HookEventPush: | ||||
| 		return getSlackPushPayload(p.(*api.PushPayload), slack) | ||||
| 	case HookEventPullRequest: | ||||
| 		return getSlackPullRequestPayload(p.(*api.PullRequestPayload), slack) | ||||
| 	case HookEventRepository: | ||||
| 		return getSlackRepositoryPayload(p.(*api.RepositoryPayload), slack) | ||||
| 	case HookEventRelease: | ||||
| 		return getSlackReleasePayload(p.(*api.ReleasePayload), slack) | ||||
| 	} | ||||
| 
 | ||||
| 	return s, nil | ||||
|  |  | |||
|  | @ -73,7 +73,7 @@ func TestWebhook_UpdateEvent(t *testing.T) { | |||
| } | ||||
| 
 | ||||
| func TestWebhook_EventsArray(t *testing.T) { | ||||
| 	assert.Equal(t, []string{"create", "push", "pull_request"}, | ||||
| 	assert.Equal(t, []string{"create", "delete", "fork", "push", "issues", "issue_comment", "pull_request", "repository", "release"}, | ||||
| 		(&Webhook{ | ||||
| 			HookEvent: &HookEvent{SendEverything: true}, | ||||
| 		}).EventsArray(), | ||||
|  |  | |||
|  | @ -155,12 +155,17 @@ func (f *ProtectBranchForm) Validate(ctx *macaron.Context, errs binding.Errors) | |||
| 
 | ||||
| // WebhookForm form for changing web hook
 | ||||
| type WebhookForm struct { | ||||
| 	Events      string | ||||
| 	Create      bool | ||||
| 	Push        bool | ||||
| 	PullRequest bool | ||||
| 	Repository  bool | ||||
| 	Active      bool | ||||
| 	Events       string | ||||
| 	Create       bool | ||||
| 	Delete       bool | ||||
| 	Fork         bool | ||||
| 	Issues       bool | ||||
| 	IssueComment bool | ||||
| 	Release      bool | ||||
| 	Push         bool | ||||
| 	PullRequest  bool | ||||
| 	Repository   bool | ||||
| 	Active       bool | ||||
| } | ||||
| 
 | ||||
| // PushOnly if the hook will be triggered when push
 | ||||
|  |  | |||
|  | @ -1000,6 +1000,16 @@ settings.event_send_everything = All Events | |||
| settings.event_choose = Custom Events… | ||||
| settings.event_create = Create | ||||
| settings.event_create_desc = Branch or tag created. | ||||
| settings.event_delete = Delete | ||||
| settings.event_delete_desc = Branch or tag deleted | ||||
| settings.event_fork = Fork | ||||
| settings.event_fork_desc = Repository forked | ||||
| settings.event_issues = Issues | ||||
| settings.event_issues_desc = Issue opened, closed, reopened, edited, assigned, unassigned, label updated, label cleared, milestoned, or demilestoned. | ||||
| settings.event_issue_comment = Issue Comment | ||||
| settings.event_issue_comment_desc = Issue comment created, edited, or deleted. | ||||
| settings.event_release = Release | ||||
| settings.event_release_desc = Release published in a repository. | ||||
| 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 | ||||
|  |  | |||
|  | @ -261,8 +261,9 @@ func editIssueComment(ctx *context.APIContext, form api.EditIssueCommentOption) | |||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	oldContent := comment.Content | ||||
| 	comment.Content = form.Body | ||||
| 	if err := models.UpdateComment(comment); err != nil { | ||||
| 	if err := models.UpdateComment(ctx.User, comment, oldContent); err != nil { | ||||
| 		ctx.Error(500, "UpdateComment", err) | ||||
| 		return | ||||
| 	} | ||||
|  | @ -348,7 +349,7 @@ func deleteIssueComment(ctx *context.APIContext) { | |||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	if err = models.DeleteComment(comment); err != nil { | ||||
| 	if err = models.DeleteComment(ctx.User, comment); err != nil { | ||||
| 		ctx.Error(500, "DeleteCommentByID", err) | ||||
| 		return | ||||
| 	} | ||||
|  |  | |||
|  | @ -7,12 +7,13 @@ package utils | |||
| import ( | ||||
| 	api "code.gitea.io/sdk/gitea" | ||||
| 
 | ||||
| 	"encoding/json" | ||||
| 	"net/http" | ||||
| 
 | ||||
| 	"code.gitea.io/gitea/models" | ||||
| 	"code.gitea.io/gitea/modules/context" | ||||
| 	"code.gitea.io/gitea/routers/api/v1/convert" | ||||
| 	"encoding/json" | ||||
| 	"github.com/Unknwon/com" | ||||
| 	"net/http" | ||||
| ) | ||||
| 
 | ||||
| // GetOrgHook get an organization's webhook. If there is an error, write to
 | ||||
|  | @ -98,9 +99,15 @@ func addHook(ctx *context.APIContext, form *api.CreateHookOption, orgID, repoID | |||
| 		HookEvent: &models.HookEvent{ | ||||
| 			ChooseEvents: true, | ||||
| 			HookEvents: models.HookEvents{ | ||||
| 				Create:      com.IsSliceContainsStr(form.Events, string(models.HookEventCreate)), | ||||
| 				Push:        com.IsSliceContainsStr(form.Events, string(models.HookEventPush)), | ||||
| 				PullRequest: com.IsSliceContainsStr(form.Events, string(models.HookEventPullRequest)), | ||||
| 				Create:       com.IsSliceContainsStr(form.Events, string(models.HookEventCreate)), | ||||
| 				Delete:       com.IsSliceContainsStr(form.Events, string(models.HookEventDelete)), | ||||
| 				Fork:         com.IsSliceContainsStr(form.Events, string(models.HookEventFork)), | ||||
| 				Issues:       com.IsSliceContainsStr(form.Events, string(models.HookEventIssues)), | ||||
| 				IssueComment: com.IsSliceContainsStr(form.Events, string(models.HookEventIssueComment)), | ||||
| 				Push:         com.IsSliceContainsStr(form.Events, string(models.HookEventPush)), | ||||
| 				PullRequest:  com.IsSliceContainsStr(form.Events, string(models.HookEventPullRequest)), | ||||
| 				Repository:   com.IsSliceContainsStr(form.Events, string(models.HookEventRepository)), | ||||
| 				Release:      com.IsSliceContainsStr(form.Events, string(models.HookEventRelease)), | ||||
| 			}, | ||||
| 		}, | ||||
| 		IsActive:     form.Active, | ||||
|  | @ -211,6 +218,16 @@ func editHook(ctx *context.APIContext, form *api.EditHookOption, w *models.Webho | |||
| 	w.Create = com.IsSliceContainsStr(form.Events, string(models.HookEventCreate)) | ||||
| 	w.Push = com.IsSliceContainsStr(form.Events, string(models.HookEventPush)) | ||||
| 	w.PullRequest = com.IsSliceContainsStr(form.Events, string(models.HookEventPullRequest)) | ||||
| 	w.Create = com.IsSliceContainsStr(form.Events, string(models.HookEventCreate)) | ||||
| 	w.Delete = com.IsSliceContainsStr(form.Events, string(models.HookEventDelete)) | ||||
| 	w.Fork = com.IsSliceContainsStr(form.Events, string(models.HookEventFork)) | ||||
| 	w.Issues = com.IsSliceContainsStr(form.Events, string(models.HookEventIssues)) | ||||
| 	w.IssueComment = com.IsSliceContainsStr(form.Events, string(models.HookEventIssueComment)) | ||||
| 	w.Push = com.IsSliceContainsStr(form.Events, string(models.HookEventPush)) | ||||
| 	w.PullRequest = com.IsSliceContainsStr(form.Events, string(models.HookEventPullRequest)) | ||||
| 	w.Repository = com.IsSliceContainsStr(form.Events, string(models.HookEventRepository)) | ||||
| 	w.Release = com.IsSliceContainsStr(form.Events, string(models.HookEventRelease)) | ||||
| 
 | ||||
| 	if err := w.UpdateEvent(); err != nil { | ||||
| 		ctx.Error(500, "UpdateEvent", err) | ||||
| 		return false | ||||
|  |  | |||
|  | @ -1086,6 +1086,7 @@ func UpdateCommentContent(ctx *context.Context) { | |||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	oldContent := comment.Content | ||||
| 	comment.Content = ctx.Query("content") | ||||
| 	if len(comment.Content) == 0 { | ||||
| 		ctx.JSON(200, map[string]interface{}{ | ||||
|  | @ -1093,7 +1094,7 @@ func UpdateCommentContent(ctx *context.Context) { | |||
| 		}) | ||||
| 		return | ||||
| 	} | ||||
| 	if err = models.UpdateComment(comment); err != nil { | ||||
| 	if err = models.UpdateComment(ctx.User, comment, oldContent); err != nil { | ||||
| 		ctx.ServerError("UpdateComment", err) | ||||
| 		return | ||||
| 	} | ||||
|  | @ -1119,7 +1120,7 @@ func DeleteComment(ctx *context.Context) { | |||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	if err = models.DeleteComment(comment); err != nil { | ||||
| 	if err = models.DeleteComment(ctx.User, comment); err != nil { | ||||
| 		ctx.ServerError("DeleteCommentByID", err) | ||||
| 		return | ||||
| 	} | ||||
|  |  | |||
|  | @ -23,9 +23,9 @@ import ( | |||
| ) | ||||
| 
 | ||||
| const ( | ||||
| 	tplHooks      base.TplName = "repo/settings/hooks" | ||||
| 	tplHookNew    base.TplName = "repo/settings/hook_new" | ||||
| 	tplOrgHookNew base.TplName = "org/settings/hook_new" | ||||
| 	tplHooks      base.TplName = "repo/settings/webhook/base" | ||||
| 	tplHookNew    base.TplName = "repo/settings/webhook/new" | ||||
| 	tplOrgHookNew base.TplName = "org/settings/webhook/new" | ||||
| ) | ||||
| 
 | ||||
| // Webhooks render web hooks list page
 | ||||
|  | @ -118,10 +118,15 @@ func ParseHookEvent(form auth.WebhookForm) *models.HookEvent { | |||
| 		SendEverything: form.SendEverything(), | ||||
| 		ChooseEvents:   form.ChooseEvents(), | ||||
| 		HookEvents: models.HookEvents{ | ||||
| 			Create:      form.Create, | ||||
| 			Push:        form.Push, | ||||
| 			PullRequest: form.PullRequest, | ||||
| 			Repository:  form.Repository, | ||||
| 			Create:       form.Create, | ||||
| 			Delete:       form.Delete, | ||||
| 			Fork:         form.Fork, | ||||
| 			Issues:       form.Issues, | ||||
| 			IssueComment: form.IssueComment, | ||||
| 			Release:      form.Release, | ||||
| 			Push:         form.Push, | ||||
| 			PullRequest:  form.PullRequest, | ||||
| 			Repository:   form.Repository, | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -3,7 +3,7 @@ | |||
| 	{{template "repo/header" .}} | ||||
| 	{{template "repo/settings/navbar" .}} | ||||
| 	<div class="ui container"> | ||||
| 		{{template "repo/settings/hook_list" .}} | ||||
| 		{{template "repo/settings/webhook/list" .}} | ||||
| 	</div> | ||||
| </div> | ||||
| {{template "base/footer" .}} | ||||
|  | @ -6,6 +6,6 @@ | |||
| 			<label for="payload_url">{{.i18n.Tr "repo.settings.payload_url"}}</label> | ||||
| 			<input id="payload_url" name="payload_url" type="url" value="{{.Webhook.URL}}" autofocus required> | ||||
| 		</div> | ||||
| 		{{template "repo/settings/hook_settings" .}} | ||||
| 		{{template "repo/settings/webhook/settings" .}} | ||||
| 	</form> | ||||
| {{end}} | ||||
|  | @ -14,6 +14,6 @@ | |||
| 			<label for="icon_url">{{.i18n.Tr "repo.settings.discord_icon_url"}}</label> | ||||
| 			<input id="icon_url" name="icon_url" value="{{.DiscordHook.IconURL}}" placeholder="e.g. https://example.com/img/favicon.png"> | ||||
| 		</div> | ||||
| 		{{template "repo/settings/hook_settings" .}} | ||||
| 		{{template "repo/settings/webhook/settings" .}} | ||||
| 	</form> | ||||
| {{end}} | ||||
|  | @ -23,6 +23,6 @@ | |||
| 			<label for="secret">{{.i18n.Tr "repo.settings.secret"}}</label> | ||||
| 			<input id="secret" name="secret" type="password" value="{{.Webhook.Secret}}" autocomplete="off"> | ||||
| 		</div> | ||||
| 		{{template "repo/settings/hook_settings" .}} | ||||
| 		{{template "repo/settings/webhook/settings" .}} | ||||
| 	</form> | ||||
| {{end}} | ||||
|  | @ -23,6 +23,6 @@ | |||
| 			<label for="secret">{{.i18n.Tr "repo.settings.secret"}}</label> | ||||
| 			<input id="secret" name="secret" type="password" value="{{.Webhook.Secret}}" autocomplete="off"> | ||||
| 		</div> | ||||
| 		{{template "repo/settings/hook_settings" .}} | ||||
| 		{{template "repo/settings/webhook/settings" .}} | ||||
| 	</form> | ||||
| {{end}} | ||||
|  | @ -48,4 +48,4 @@ | |||
| 	</div> | ||||
| </div> | ||||
| 
 | ||||
| {{template "repo/settings/hook_delete_modal" .}} | ||||
| {{template "repo/settings/webhook/delete_modal" .}} | ||||
|  | @ -21,14 +21,14 @@ | |||
| 			</div> | ||||
| 		</h4> | ||||
| 		<div class="ui attached segment"> | ||||
| 			{{template "repo/settings/hook_gitea" .}} | ||||
| 			{{template "repo/settings/hook_gogs" .}} | ||||
| 			{{template "repo/settings/hook_slack" .}} | ||||
| 			{{template "repo/settings/hook_discord" .}} | ||||
| 			{{template "repo/settings/hook_dingtalk" .}} | ||||
| 			{{template "repo/settings/webhook/gitea" .}} | ||||
| 			{{template "repo/settings/webhook/gogs" .}} | ||||
| 			{{template "repo/settings/webhook/slack" .}} | ||||
| 			{{template "repo/settings/webhook/discord" .}} | ||||
| 			{{template "repo/settings/webhook/dingtalk" .}} | ||||
| 		</div> | ||||
| 
 | ||||
| 		{{template "repo/settings/hook_history" .}} | ||||
| 		{{template "repo/settings/webhook/history" .}} | ||||
| 	</div> | ||||
| </div> | ||||
| {{template "base/footer" .}} | ||||
|  | @ -32,6 +32,26 @@ | |||
| 				</div> | ||||
| 			</div> | ||||
| 		</div> | ||||
| 		<!-- Delete --> | ||||
| 		<div class="seven wide column"> | ||||
| 			<div class="field"> | ||||
| 				<div class="ui checkbox"> | ||||
| 					<input class="hidden" name="delete" type="checkbox" tabindex="0" {{if .Webhook.Delete}}checked{{end}}> | ||||
| 					<label>{{.i18n.Tr "repo.settings.event_delete"}}</label> | ||||
| 					<span class="help">{{.i18n.Tr "repo.settings.event_delete_desc"}}</span> | ||||
| 				</div> | ||||
| 			</div> | ||||
| 		</div> | ||||
| 		<!-- Fork --> | ||||
| 		<div class="seven wide column"> | ||||
| 			<div class="field"> | ||||
| 				<div class="ui checkbox"> | ||||
| 					<input class="hidden" name="fork" type="checkbox" tabindex="0" {{if .Webhook.Fork}}checked{{end}}> | ||||
| 					<label>{{.i18n.Tr "repo.settings.event_fork"}}</label> | ||||
| 					<span class="help">{{.i18n.Tr "repo.settings.event_fork_desc"}}</span> | ||||
| 				</div> | ||||
| 			</div> | ||||
| 		</div> | ||||
| 		<!-- Push --> | ||||
| 		<div class="seven wide column"> | ||||
| 			<div class="field"> | ||||
|  | @ -42,6 +62,26 @@ | |||
| 				</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_issues"}}</label> | ||||
| 					<span class="help">{{.i18n.Tr "repo.settings.event_issues_desc"}}</span> | ||||
| 				</div> | ||||
| 			</div> | ||||
| 		</div> | ||||
| 		<!-- Issue Comment --> | ||||
| 		<div class="seven wide column"> | ||||
| 			<div class="field"> | ||||
| 				<div class="ui checkbox"> | ||||
| 					<input class="hidden" name="issue_comment" type="checkbox" tabindex="0" {{if .Webhook.IssueComment}}checked{{end}}> | ||||
| 					<label>{{.i18n.Tr "repo.settings.event_issue_comment"}}</label> | ||||
| 					<span class="help">{{.i18n.Tr "repo.settings.event_issue_comment_desc"}}</span> | ||||
| 				</div> | ||||
| 			</div> | ||||
| 		</div> | ||||
| 		<!-- Pull Request --> | ||||
| 		<div class="seven wide column"> | ||||
| 			<div class="field"> | ||||
|  | @ -62,6 +102,16 @@ | |||
| 				</div> | ||||
| 			</div> | ||||
| 		</div> | ||||
| 		<!-- Release --> | ||||
| 		<div class="seven wide column"> | ||||
| 			<div class="field"> | ||||
| 				<div class="ui checkbox"> | ||||
| 					<input class="hidden" name="release" type="checkbox" tabindex="0" {{if .Webhook.Release}}checked{{end}}> | ||||
| 					<label>{{.i18n.Tr "repo.settings.event_release"}}</label> | ||||
| 					<span class="help">{{.i18n.Tr "repo.settings.event_release_desc"}}</span> | ||||
| 				</div> | ||||
| 			</div> | ||||
| 		</div> | ||||
| 	</div> | ||||
| </div> | ||||
| 
 | ||||
|  | @ -83,4 +133,4 @@ | |||
| 	{{end}} | ||||
| </div> | ||||
| 
 | ||||
| {{template "repo/settings/hook_delete_modal" .}} | ||||
| {{template "repo/settings/webhook/delete_modal" .}} | ||||
|  | @ -23,6 +23,6 @@ | |||
| 			<label for="color">{{.i18n.Tr "repo.settings.slack_color"}}</label> | ||||
| 			<input id="color" name="color" value="{{.SlackHook.Color}}" placeholder="e.g. #dd4b39, good, warning, danger"> | ||||
| 		</div> | ||||
| 		{{template "repo/settings/hook_settings" .}} | ||||
| 		{{template "repo/settings/webhook/settings" .}} | ||||
| 	</form> | ||||
| {{end}} | ||||
							
								
								
									
										122
									
								
								vendor/code.gitea.io/sdk/gitea/hook.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										122
									
								
								vendor/code.gitea.io/sdk/gitea/hook.go
									
									
									
										generated
									
									
										vendored
									
									
								
							|  | @ -172,9 +172,14 @@ type PayloadCommitVerification struct { | |||
| 
 | ||||
| var ( | ||||
| 	_ Payloader = &CreatePayload{} | ||||
| 	_ Payloader = &DeletePayload{} | ||||
| 	_ Payloader = &ForkPayload{} | ||||
| 	_ Payloader = &PushPayload{} | ||||
| 	_ Payloader = &IssuePayload{} | ||||
| 	_ Payloader = &IssueCommentPayload{} | ||||
| 	_ Payloader = &PullRequestPayload{} | ||||
| 	_ Payloader = &RepositoryPayload{} | ||||
| 	_ Payloader = &ReleasePayload{} | ||||
| ) | ||||
| 
 | ||||
| // _________                        __
 | ||||
|  | @ -224,6 +229,123 @@ func ParseCreateHook(raw []byte) (*CreatePayload, error) { | |||
| 	return hook, nil | ||||
| } | ||||
| 
 | ||||
| // ________         .__          __
 | ||||
| // \______ \   ____ |  |   _____/  |_  ____
 | ||||
| //  |    |  \_/ __ \|  | _/ __ \   __\/ __ \
 | ||||
| //  |    `   \  ___/|  |_\  ___/|  | \  ___/
 | ||||
| // /_______  /\___  >____/\___  >__|  \___  >
 | ||||
| //         \/     \/          \/          \/
 | ||||
| 
 | ||||
| // PusherType define the type to push
 | ||||
| type PusherType string | ||||
| 
 | ||||
| // describe all the PusherTypes
 | ||||
| const ( | ||||
| 	PusherTypeUser PusherType = "user" | ||||
| ) | ||||
| 
 | ||||
| // DeletePayload represents delete payload
 | ||||
| type DeletePayload struct { | ||||
| 	Ref        string      `json:"ref"` | ||||
| 	RefType    string      `json:"ref_type"` | ||||
| 	PusherType PusherType  `json:"pusher_type"` | ||||
| 	Repo       *Repository `json:"repository"` | ||||
| 	Sender     *User       `json:"sender"` | ||||
| } | ||||
| 
 | ||||
| // SetSecret implements Payload
 | ||||
| func (p *DeletePayload) SetSecret(secret string) { | ||||
| } | ||||
| 
 | ||||
| // JSONPayload implements Payload
 | ||||
| func (p *DeletePayload) JSONPayload() ([]byte, error) { | ||||
| 	return json.MarshalIndent(p, "", "  ") | ||||
| } | ||||
| 
 | ||||
| // ___________           __
 | ||||
| // \_   _____/__________|  | __
 | ||||
| //  |    __)/  _ \_  __ \  |/ /
 | ||||
| //  |     \(  <_> )  | \/    <
 | ||||
| //  \___  / \____/|__|  |__|_ \
 | ||||
| //      \/                   \/
 | ||||
| 
 | ||||
| // ForkPayload represents fork payload
 | ||||
| type ForkPayload struct { | ||||
| 	Forkee *Repository `json:"forkee"` | ||||
| 	Repo   *Repository `json:"repository"` | ||||
| 	Sender *User       `json:"sender"` | ||||
| } | ||||
| 
 | ||||
| // SetSecret implements Payload
 | ||||
| func (p *ForkPayload) SetSecret(secret string) { | ||||
| } | ||||
| 
 | ||||
| // JSONPayload implements Payload
 | ||||
| func (p *ForkPayload) JSONPayload() ([]byte, error) { | ||||
| 	return json.MarshalIndent(p, "", "  ") | ||||
| } | ||||
| 
 | ||||
| // HookIssueCommentAction defines hook issue comment action
 | ||||
| type HookIssueCommentAction string | ||||
| 
 | ||||
| // all issue comment actions
 | ||||
| const ( | ||||
| 	HookIssueCommentCreated HookIssueCommentAction = "created" | ||||
| 	HookIssueCommentEdited  HookIssueCommentAction = "edited" | ||||
| 	HookIssueCommentDeleted HookIssueCommentAction = "deleted" | ||||
| ) | ||||
| 
 | ||||
| // IssueCommentPayload represents a payload information of issue comment event.
 | ||||
| type IssueCommentPayload struct { | ||||
| 	Action     HookIssueCommentAction `json:"action"` | ||||
| 	Issue      *Issue                 `json:"issue"` | ||||
| 	Comment    *Comment               `json:"comment"` | ||||
| 	Changes    *ChangesPayload        `json:"changes,omitempty"` | ||||
| 	Repository *Repository            `json:"repository"` | ||||
| 	Sender     *User                  `json:"sender"` | ||||
| } | ||||
| 
 | ||||
| // SetSecret implements Payload
 | ||||
| func (p *IssueCommentPayload) SetSecret(secret string) { | ||||
| } | ||||
| 
 | ||||
| // JSONPayload implements Payload
 | ||||
| func (p *IssueCommentPayload) JSONPayload() ([]byte, error) { | ||||
| 	return json.MarshalIndent(p, "", "  ") | ||||
| } | ||||
| 
 | ||||
| // __________       .__
 | ||||
| // \______   \ ____ |  |   ____ _____    ______ ____
 | ||||
| //  |       _// __ \|  | _/ __ \\__  \  /  ___// __ \
 | ||||
| //  |    |   \  ___/|  |_\  ___/ / __ \_\___ \\  ___/
 | ||||
| //  |____|_  /\___  >____/\___  >____  /____  >\___  >
 | ||||
| //         \/     \/          \/     \/     \/     \/
 | ||||
| 
 | ||||
| // HookReleaseAction defines hook release action type
 | ||||
| type HookReleaseAction string | ||||
| 
 | ||||
| // all release actions
 | ||||
| const ( | ||||
| 	HookReleasePublished HookReleaseAction = "published" | ||||
| ) | ||||
| 
 | ||||
| // ReleasePayload represents a payload information of release event.
 | ||||
| type ReleasePayload struct { | ||||
| 	Action     HookReleaseAction `json:"action"` | ||||
| 	Release    *Release          `json:"release"` | ||||
| 	Repository *Repository       `json:"repository"` | ||||
| 	Sender     *User             `json:"sender"` | ||||
| } | ||||
| 
 | ||||
| // SetSecret implements Payload
 | ||||
| func (p *ReleasePayload) SetSecret(secret string) { | ||||
| } | ||||
| 
 | ||||
| // JSONPayload implements Payload
 | ||||
| func (p *ReleasePayload) JSONPayload() ([]byte, error) { | ||||
| 	return json.MarshalIndent(p, "", "  ") | ||||
| } | ||||
| 
 | ||||
| // __________             .__
 | ||||
| // \______   \__ __  _____|  |__
 | ||||
| //  |     ___/  |  \/  ___/  |  \
 | ||||
|  |  | |||
							
								
								
									
										28
									
								
								vendor/code.gitea.io/sdk/gitea/issue.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										28
									
								
								vendor/code.gitea.io/sdk/gitea/issue.go
									
									
									
										generated
									
									
										vendored
									
									
								
							|  | @ -118,14 +118,14 @@ func (c *Client) CreateIssue(owner, repo string, opt CreateIssueOption) (*Issue, | |||
| 
 | ||||
| // EditIssueOption options for editing an issue
 | ||||
| type EditIssueOption struct { | ||||
| 	Title     string     `json:"title"` | ||||
| 	Body      *string    `json:"body"` | ||||
| 	Assignee  *string    `json:"assignee"` | ||||
| 	Assignees []string   `json:"assignees"` | ||||
| 	Milestone *int64     `json:"milestone"` | ||||
| 	State     *string    `json:"state"` | ||||
| 	Title     string   `json:"title"` | ||||
| 	Body      *string  `json:"body"` | ||||
| 	Assignee  *string  `json:"assignee"` | ||||
| 	Assignees []string `json:"assignees"` | ||||
| 	Milestone *int64   `json:"milestone"` | ||||
| 	State     *string  `json:"state"` | ||||
| 	// swagger:strfmt date-time
 | ||||
| 	Deadline  *time.Time `json:"due_date"` | ||||
| 	Deadline *time.Time `json:"due_date"` | ||||
| } | ||||
| 
 | ||||
| // EditIssue modify an existing issue for a given repository
 | ||||
|  | @ -138,3 +138,17 @@ func (c *Client) EditIssue(owner, repo string, index int64, opt EditIssueOption) | |||
| 	return issue, c.getParsedResponse("PATCH", fmt.Sprintf("/repos/%s/%s/issues/%d", owner, repo, index), | ||||
| 		jsonHeader, bytes.NewReader(body), issue) | ||||
| } | ||||
| 
 | ||||
| // EditDeadlineOption options for creating a deadline
 | ||||
| type EditDeadlineOption struct { | ||||
| 	// required:true
 | ||||
| 	// swagger:strfmt date-time
 | ||||
| 	Deadline *time.Time `json:"due_date"` | ||||
| } | ||||
| 
 | ||||
| // IssueDeadline represents an issue deadline
 | ||||
| // swagger:model
 | ||||
| type IssueDeadline struct { | ||||
| 	// swagger:strfmt date-time
 | ||||
| 	Deadline *time.Time `json:"due_date"` | ||||
| } | ||||
|  |  | |||
							
								
								
									
										34
									
								
								vendor/code.gitea.io/sdk/gitea/pull.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										34
									
								
								vendor/code.gitea.io/sdk/gitea/pull.go
									
									
									
										generated
									
									
										vendored
									
									
								
							|  | @ -85,16 +85,16 @@ func (c *Client) GetPullRequest(owner, repo string, index int64) (*PullRequest, | |||
| 
 | ||||
| // CreatePullRequestOption options when creating a pull request
 | ||||
| type CreatePullRequestOption struct { | ||||
| 	Head      string     `json:"head" binding:"Required"` | ||||
| 	Base      string     `json:"base" binding:"Required"` | ||||
| 	Title     string     `json:"title" binding:"Required"` | ||||
| 	Body      string     `json:"body"` | ||||
| 	Assignee  string     `json:"assignee"` | ||||
| 	Assignees []string   `json:"assignees"` | ||||
| 	Milestone int64      `json:"milestone"` | ||||
| 	Labels    []int64    `json:"labels"` | ||||
| 	Head      string   `json:"head" binding:"Required"` | ||||
| 	Base      string   `json:"base" binding:"Required"` | ||||
| 	Title     string   `json:"title" binding:"Required"` | ||||
| 	Body      string   `json:"body"` | ||||
| 	Assignee  string   `json:"assignee"` | ||||
| 	Assignees []string `json:"assignees"` | ||||
| 	Milestone int64    `json:"milestone"` | ||||
| 	Labels    []int64  `json:"labels"` | ||||
| 	// swagger:strfmt date-time
 | ||||
| 	Deadline  *time.Time `json:"due_date"` | ||||
| 	Deadline *time.Time `json:"due_date"` | ||||
| } | ||||
| 
 | ||||
| // CreatePullRequest create pull request with options
 | ||||
|  | @ -110,15 +110,15 @@ func (c *Client) CreatePullRequest(owner, repo string, opt CreatePullRequestOpti | |||
| 
 | ||||
| // EditPullRequestOption options when modify pull request
 | ||||
| type EditPullRequestOption struct { | ||||
| 	Title     string     `json:"title"` | ||||
| 	Body      string     `json:"body"` | ||||
| 	Assignee  string     `json:"assignee"` | ||||
| 	Assignees []string   `json:"assignees"` | ||||
| 	Milestone int64      `json:"milestone"` | ||||
| 	Labels    []int64    `json:"labels"` | ||||
| 	State     *string    `json:"state"` | ||||
| 	Title     string   `json:"title"` | ||||
| 	Body      string   `json:"body"` | ||||
| 	Assignee  string   `json:"assignee"` | ||||
| 	Assignees []string `json:"assignees"` | ||||
| 	Milestone int64    `json:"milestone"` | ||||
| 	Labels    []int64  `json:"labels"` | ||||
| 	State     *string  `json:"state"` | ||||
| 	// swagger:strfmt date-time
 | ||||
| 	Deadline  *time.Time `json:"due_date"` | ||||
| 	Deadline *time.Time `json:"due_date"` | ||||
| } | ||||
| 
 | ||||
| // EditPullRequest modify pull request with PR id and options
 | ||||
|  |  | |||
							
								
								
									
										6
									
								
								vendor/vendor.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								vendor/vendor.json
									
									
									
									
										vendored
									
									
								
							|  | @ -9,10 +9,10 @@ | |||
| 			"revisionTime": "2018-04-21T01:08:19Z" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"checksumSHA1": "WMD6+Qh2+5hd9uiq910pF/Ihylw=", | ||||
| 			"checksumSHA1": "LnxY/6xD4h9dCCJ5nxKEfZZs1Vk=", | ||||
| 			"path": "code.gitea.io/sdk/gitea", | ||||
| 			"revision": "1c8d12f79a51605ed91587aa6b86cf38fc0f987f", | ||||
| 			"revisionTime": "2018-05-01T11:15:19Z" | ||||
| 			"revision": "7fa627fa5d67d18c39d6dd3c6c4db836916bf234", | ||||
| 			"revisionTime": "2018-05-10T12:54:05Z" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"checksumSHA1": "bOODD4Gbw3GfcuQPU2dI40crxxk=", | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue