mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-31 21:28:11 +09:00 
			
		
		
		
	Webhooks: for issue close/reopen action, add commit ID that caused it (#22583)
The `commit_id` property name is the same as equivalent functionality in GitHub. If the action was not caused by a commit, an empty string is used. This can for example be used to automatically add a Resolved label to an issue fixed by a commit, or clear it when the issue is reopened.
This commit is contained in:
		
				
					committed by
					
						 GitHub
						GitHub
					
				
			
			
				
	
			
			
			
						parent
						
							a31fedd2c2
						
					
				
				
					commit
					c8139c0f64
				
			| @@ -56,7 +56,7 @@ func (a *actionNotifier) NotifyNewIssue(ctx context.Context, issue *issues_model | |||||||
| } | } | ||||||
|  |  | ||||||
| // NotifyIssueChangeStatus notifies close or reopen issue to notifiers | // NotifyIssueChangeStatus notifies close or reopen issue to notifiers | ||||||
| func (a *actionNotifier) NotifyIssueChangeStatus(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, actionComment *issues_model.Comment, closeOrReopen bool) { | func (a *actionNotifier) NotifyIssueChangeStatus(ctx context.Context, doer *user_model.User, commitID string, issue *issues_model.Issue, actionComment *issues_model.Comment, closeOrReopen bool) { | ||||||
| 	// Compose comment action, could be plain comment, close or reopen issue/pull request. | 	// Compose comment action, could be plain comment, close or reopen issue/pull request. | ||||||
| 	// This object will be used to notify watchers in the end of function. | 	// This object will be used to notify watchers in the end of function. | ||||||
| 	act := &activities_model.Action{ | 	act := &activities_model.Action{ | ||||||
|   | |||||||
| @@ -23,7 +23,7 @@ type Notifier interface { | |||||||
| 	NotifyRenameRepository(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, oldRepoName string) | 	NotifyRenameRepository(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, oldRepoName string) | ||||||
| 	NotifyTransferRepository(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, oldOwnerName string) | 	NotifyTransferRepository(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, oldOwnerName string) | ||||||
| 	NotifyNewIssue(ctx context.Context, issue *issues_model.Issue, mentions []*user_model.User) | 	NotifyNewIssue(ctx context.Context, issue *issues_model.Issue, mentions []*user_model.User) | ||||||
| 	NotifyIssueChangeStatus(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, actionComment *issues_model.Comment, closeOrReopen bool) | 	NotifyIssueChangeStatus(ctx context.Context, doer *user_model.User, commitID string, issue *issues_model.Issue, actionComment *issues_model.Comment, closeOrReopen bool) | ||||||
| 	NotifyDeleteIssue(ctx context.Context, doer *user_model.User, issue *issues_model.Issue) | 	NotifyDeleteIssue(ctx context.Context, doer *user_model.User, issue *issues_model.Issue) | ||||||
| 	NotifyIssueChangeMilestone(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, oldMilestoneID int64) | 	NotifyIssueChangeMilestone(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, oldMilestoneID int64) | ||||||
| 	NotifyIssueChangeAssignee(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, assignee *user_model.User, removed bool, comment *issues_model.Comment) | 	NotifyIssueChangeAssignee(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, assignee *user_model.User, removed bool, comment *issues_model.Comment) | ||||||
|   | |||||||
| @@ -32,7 +32,7 @@ func (*NullNotifier) NotifyNewIssue(ctx context.Context, issue *issues_model.Iss | |||||||
| } | } | ||||||
|  |  | ||||||
| // NotifyIssueChangeStatus places a place holder function | // NotifyIssueChangeStatus places a place holder function | ||||||
| func (*NullNotifier) NotifyIssueChangeStatus(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, actionComment *issues_model.Comment, isClosed bool) { | func (*NullNotifier) NotifyIssueChangeStatus(ctx context.Context, doer *user_model.User, commitID string, issue *issues_model.Issue, actionComment *issues_model.Comment, isClosed bool) { | ||||||
| } | } | ||||||
|  |  | ||||||
| // NotifyDeleteIssue notify when some issue deleted | // NotifyDeleteIssue notify when some issue deleted | ||||||
|   | |||||||
| @@ -54,7 +54,7 @@ func (m *mailNotifier) NotifyNewIssue(ctx context.Context, issue *issues_model.I | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func (m *mailNotifier) NotifyIssueChangeStatus(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, actionComment *issues_model.Comment, isClosed bool) { | func (m *mailNotifier) NotifyIssueChangeStatus(ctx context.Context, doer *user_model.User, commitID string, issue *issues_model.Issue, actionComment *issues_model.Comment, isClosed bool) { | ||||||
| 	var actionType activities_model.ActionType | 	var actionType activities_model.ActionType | ||||||
| 	if issue.IsPull { | 	if issue.IsPull { | ||||||
| 		if isClosed { | 		if isClosed { | ||||||
|   | |||||||
| @@ -77,9 +77,9 @@ func NotifyNewIssue(ctx context.Context, issue *issues_model.Issue, mentions []* | |||||||
| } | } | ||||||
|  |  | ||||||
| // NotifyIssueChangeStatus notifies close or reopen issue to notifiers | // NotifyIssueChangeStatus notifies close or reopen issue to notifiers | ||||||
| func NotifyIssueChangeStatus(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, actionComment *issues_model.Comment, closeOrReopen bool) { | func NotifyIssueChangeStatus(ctx context.Context, doer *user_model.User, commitID string, issue *issues_model.Issue, actionComment *issues_model.Comment, closeOrReopen bool) { | ||||||
| 	for _, notifier := range notifiers { | 	for _, notifier := range notifiers { | ||||||
| 		notifier.NotifyIssueChangeStatus(ctx, doer, issue, actionComment, closeOrReopen) | 		notifier.NotifyIssueChangeStatus(ctx, doer, commitID, issue, actionComment, closeOrReopen) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -93,7 +93,7 @@ func (ns *notificationService) NotifyNewIssue(ctx context.Context, issue *issues | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func (ns *notificationService) NotifyIssueChangeStatus(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, actionComment *issues_model.Comment, isClosed bool) { | func (ns *notificationService) NotifyIssueChangeStatus(ctx context.Context, doer *user_model.User, commitID string, issue *issues_model.Issue, actionComment *issues_model.Comment, isClosed bool) { | ||||||
| 	_ = ns.issueQueue.Push(issueNotificationOpts{ | 	_ = ns.issueQueue.Push(issueNotificationOpts{ | ||||||
| 		IssueID:              issue.ID, | 		IssueID:              issue.ID, | ||||||
| 		NotificationAuthorID: doer.ID, | 		NotificationAuthorID: doer.ID, | ||||||
|   | |||||||
| @@ -352,6 +352,7 @@ type IssuePayload struct { | |||||||
| 	Issue      *Issue          `json:"issue"` | 	Issue      *Issue          `json:"issue"` | ||||||
| 	Repository *Repository     `json:"repository"` | 	Repository *Repository     `json:"repository"` | ||||||
| 	Sender     *User           `json:"sender"` | 	Sender     *User           `json:"sender"` | ||||||
|  | 	CommitID   string          `json:"commit_id"` | ||||||
| } | } | ||||||
|  |  | ||||||
| // JSONPayload encodes the IssuePayload to JSON, with an indentation of two spaces. | // JSONPayload encodes the IssuePayload to JSON, with an indentation of two spaces. | ||||||
| @@ -386,6 +387,7 @@ type PullRequestPayload struct { | |||||||
| 	PullRequest *PullRequest    `json:"pull_request"` | 	PullRequest *PullRequest    `json:"pull_request"` | ||||||
| 	Repository  *Repository     `json:"repository"` | 	Repository  *Repository     `json:"repository"` | ||||||
| 	Sender      *User           `json:"sender"` | 	Sender      *User           `json:"sender"` | ||||||
|  | 	CommitID    string          `json:"commit_id"` | ||||||
| 	Review      *ReviewPayload  `json:"review"` | 	Review      *ReviewPayload  `json:"review"` | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -654,7 +654,7 @@ func CreateIssue(ctx *context.APIContext) { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if form.Closed { | 	if form.Closed { | ||||||
| 		if err := issue_service.ChangeStatus(issue, ctx.Doer, true); err != nil { | 		if err := issue_service.ChangeStatus(issue, ctx.Doer, "", true); err != nil { | ||||||
| 			if issues_model.IsErrDependenciesLeft(err) { | 			if issues_model.IsErrDependenciesLeft(err) { | ||||||
| 				ctx.Error(http.StatusPreconditionFailed, "DependenciesLeft", "cannot close this issue because it still has open dependencies") | 				ctx.Error(http.StatusPreconditionFailed, "DependenciesLeft", "cannot close this issue because it still has open dependencies") | ||||||
| 				return | 				return | ||||||
| @@ -826,7 +826,7 @@ func EditIssue(ctx *context.APIContext) { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if statusChangeComment != nil { | 	if statusChangeComment != nil { | ||||||
| 		notification.NotifyIssueChangeStatus(ctx, ctx.Doer, issue, statusChangeComment, issue.IsClosed) | 		notification.NotifyIssueChangeStatus(ctx, ctx.Doer, "", issue, statusChangeComment, issue.IsClosed) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// Refetch from database to assign some automatic values | 	// Refetch from database to assign some automatic values | ||||||
|   | |||||||
| @@ -600,7 +600,7 @@ func EditPullRequest(ctx *context.APIContext) { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if statusChangeComment != nil { | 	if statusChangeComment != nil { | ||||||
| 		notification.NotifyIssueChangeStatus(ctx, ctx.Doer, issue, statusChangeComment, issue.IsClosed) | 		notification.NotifyIssueChangeStatus(ctx, ctx.Doer, "", issue, statusChangeComment, issue.IsClosed) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// change pull target branch | 	// change pull target branch | ||||||
|   | |||||||
| @@ -2599,7 +2599,7 @@ func UpdateIssueStatus(ctx *context.Context) { | |||||||
| 	} | 	} | ||||||
| 	for _, issue := range issues { | 	for _, issue := range issues { | ||||||
| 		if issue.IsClosed != isClosed { | 		if issue.IsClosed != isClosed { | ||||||
| 			if err := issue_service.ChangeStatus(issue, ctx.Doer, isClosed); err != nil { | 			if err := issue_service.ChangeStatus(issue, ctx.Doer, "", isClosed); err != nil { | ||||||
| 				if issues_model.IsErrDependenciesLeft(err) { | 				if issues_model.IsErrDependenciesLeft(err) { | ||||||
| 					ctx.JSON(http.StatusPreconditionFailed, map[string]interface{}{ | 					ctx.JSON(http.StatusPreconditionFailed, map[string]interface{}{ | ||||||
| 						"error": "cannot close this issue because it still has open dependencies", | 						"error": "cannot close this issue because it still has open dependencies", | ||||||
| @@ -2696,7 +2696,7 @@ func NewComment(ctx *context.Context) { | |||||||
| 				ctx.Flash.Info(ctx.Tr("repo.pulls.open_unmerged_pull_exists", pr.Index)) | 				ctx.Flash.Info(ctx.Tr("repo.pulls.open_unmerged_pull_exists", pr.Index)) | ||||||
| 			} else { | 			} else { | ||||||
| 				isClosed := form.Status == "close" | 				isClosed := form.Status == "close" | ||||||
| 				if err := issue_service.ChangeStatus(issue, ctx.Doer, isClosed); err != nil { | 				if err := issue_service.ChangeStatus(issue, ctx.Doer, "", isClosed); err != nil { | ||||||
| 					log.Error("ChangeStatus: %v", err) | 					log.Error("ChangeStatus: %v", err) | ||||||
|  |  | ||||||
| 					if issues_model.IsErrDependenciesLeft(err) { | 					if issues_model.IsErrDependenciesLeft(err) { | ||||||
|   | |||||||
| @@ -193,7 +193,7 @@ func UpdateIssuesCommit(doer *user_model.User, repo *repo_model.Repository, comm | |||||||
| 			} | 			} | ||||||
| 			if close != refIssue.IsClosed { | 			if close != refIssue.IsClosed { | ||||||
| 				refIssue.Repo = refRepo | 				refIssue.Repo = refRepo | ||||||
| 				if err := ChangeStatus(refIssue, doer, close); err != nil { | 				if err := ChangeStatus(refIssue, doer, c.Sha1, close); err != nil { | ||||||
| 					return err | 					return err | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
|   | |||||||
| @@ -14,13 +14,13 @@ import ( | |||||||
| ) | ) | ||||||
|  |  | ||||||
| // ChangeStatus changes issue status to open or closed. | // ChangeStatus changes issue status to open or closed. | ||||||
| func ChangeStatus(issue *issues_model.Issue, doer *user_model.User, closed bool) error { | func ChangeStatus(issue *issues_model.Issue, doer *user_model.User, commitID string, closed bool) error { | ||||||
| 	return changeStatusCtx(db.DefaultContext, issue, doer, closed) | 	return changeStatusCtx(db.DefaultContext, issue, doer, commitID, closed) | ||||||
| } | } | ||||||
|  |  | ||||||
| // changeStatusCtx changes issue status to open or closed. | // changeStatusCtx changes issue status to open or closed. | ||||||
| // TODO: if context is not db.DefaultContext we get a deadlock!!! | // TODO: if context is not db.DefaultContext we get a deadlock!!! | ||||||
| func changeStatusCtx(ctx context.Context, issue *issues_model.Issue, doer *user_model.User, closed bool) error { | func changeStatusCtx(ctx context.Context, issue *issues_model.Issue, doer *user_model.User, commitID string, closed bool) error { | ||||||
| 	comment, err := issues_model.ChangeIssueStatus(ctx, issue, doer, closed) | 	comment, err := issues_model.ChangeIssueStatus(ctx, issue, doer, closed) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		if issues_model.IsErrDependenciesLeft(err) && closed { | 		if issues_model.IsErrDependenciesLeft(err) && closed { | ||||||
| @@ -37,7 +37,7 @@ func changeStatusCtx(ctx context.Context, issue *issues_model.Issue, doer *user_ | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	notification.NotifyIssueChangeStatus(ctx, doer, issue, comment, closed) | 	notification.NotifyIssueChangeStatus(ctx, doer, commitID, issue, comment, closed) | ||||||
|  |  | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|   | |||||||
| @@ -225,7 +225,7 @@ func Merge(ctx context.Context, pr *issues_model.PullRequest, doer *user_model.U | |||||||
| 		} | 		} | ||||||
| 		close := ref.RefAction == references.XRefActionCloses | 		close := ref.RefAction == references.XRefActionCloses | ||||||
| 		if close != ref.Issue.IsClosed { | 		if close != ref.Issue.IsClosed { | ||||||
| 			if err = issue_service.ChangeStatus(ref.Issue, doer, close); err != nil { | 			if err = issue_service.ChangeStatus(ref.Issue, doer, pr.MergedCommitID, close); err != nil { | ||||||
| 				// Allow ErrDependenciesLeft | 				// Allow ErrDependenciesLeft | ||||||
| 				if !issues_model.IsErrDependenciesLeft(err) { | 				if !issues_model.IsErrDependenciesLeft(err) { | ||||||
| 					return err | 					return err | ||||||
|   | |||||||
| @@ -532,7 +532,7 @@ func CloseBranchPulls(doer *user_model.User, repoID int64, branch string) error | |||||||
|  |  | ||||||
| 	var errs errlist | 	var errs errlist | ||||||
| 	for _, pr := range prs { | 	for _, pr := range prs { | ||||||
| 		if err = issue_service.ChangeStatus(pr.Issue, doer, true); err != nil && !issues_model.IsErrPullWasClosed(err) && !issues_model.IsErrDependenciesLeft(err) { | 		if err = issue_service.ChangeStatus(pr.Issue, doer, "", true); err != nil && !issues_model.IsErrPullWasClosed(err) && !issues_model.IsErrDependenciesLeft(err) { | ||||||
| 			errs = append(errs, err) | 			errs = append(errs, err) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| @@ -566,7 +566,7 @@ func CloseRepoBranchesPulls(ctx context.Context, doer *user_model.User, repo *re | |||||||
| 			if pr.BaseRepoID == repo.ID { | 			if pr.BaseRepoID == repo.ID { | ||||||
| 				continue | 				continue | ||||||
| 			} | 			} | ||||||
| 			if err = issue_service.ChangeStatus(pr.Issue, doer, true); err != nil && !issues_model.IsErrPullWasClosed(err) { | 			if err = issue_service.ChangeStatus(pr.Issue, doer, "", true); err != nil && !issues_model.IsErrPullWasClosed(err) { | ||||||
| 				errs = append(errs, err) | 				errs = append(errs, err) | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|   | |||||||
| @@ -229,7 +229,7 @@ func (m *webhookNotifier) NotifyIssueChangeTitle(ctx context.Context, doer *user | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func (m *webhookNotifier) NotifyIssueChangeStatus(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, actionComment *issues_model.Comment, isClosed bool) { | func (m *webhookNotifier) NotifyIssueChangeStatus(ctx context.Context, doer *user_model.User, commitID string, issue *issues_model.Issue, actionComment *issues_model.Comment, isClosed bool) { | ||||||
| 	mode, _ := access_model.AccessLevel(ctx, issue.Poster, issue.Repo) | 	mode, _ := access_model.AccessLevel(ctx, issue.Poster, issue.Repo) | ||||||
| 	var err error | 	var err error | ||||||
| 	if issue.IsPull { | 	if issue.IsPull { | ||||||
| @@ -243,6 +243,7 @@ func (m *webhookNotifier) NotifyIssueChangeStatus(ctx context.Context, doer *use | |||||||
| 			PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil), | 			PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil), | ||||||
| 			Repository:  convert.ToRepo(ctx, issue.Repo, mode), | 			Repository:  convert.ToRepo(ctx, issue.Repo, mode), | ||||||
| 			Sender:      convert.ToUser(doer, nil), | 			Sender:      convert.ToUser(doer, nil), | ||||||
|  | 			CommitID:    commitID, | ||||||
| 		} | 		} | ||||||
| 		if isClosed { | 		if isClosed { | ||||||
| 			apiPullRequest.Action = api.HookIssueClosed | 			apiPullRequest.Action = api.HookIssueClosed | ||||||
| @@ -256,6 +257,7 @@ func (m *webhookNotifier) NotifyIssueChangeStatus(ctx context.Context, doer *use | |||||||
| 			Issue:      convert.ToAPIIssue(ctx, issue), | 			Issue:      convert.ToAPIIssue(ctx, issue), | ||||||
| 			Repository: convert.ToRepo(ctx, issue.Repo, mode), | 			Repository: convert.ToRepo(ctx, issue.Repo, mode), | ||||||
| 			Sender:     convert.ToUser(doer, nil), | 			Sender:     convert.ToUser(doer, nil), | ||||||
|  | 			CommitID:   commitID, | ||||||
| 		} | 		} | ||||||
| 		if isClosed { | 		if isClosed { | ||||||
| 			apiIssue.Action = api.HookIssueClosed | 			apiIssue.Action = api.HookIssueClosed | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user