Skip to content

Commit c67a839

Browse files
authored
Add issue delete notifier (#34592)
Fixes #34591 A reference regarding the deletion of issue webhooks on GitHub: https://docs.github.com/en/webhooks/webhook-events-and-payloads?actionType=deleted#issues
1 parent 75aa23a commit c67a839

File tree

5 files changed

+120
-2
lines changed

5 files changed

+120
-2
lines changed

modules/structs/hook.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,8 @@ const (
286286
HookIssueReOpened HookIssueAction = "reopened"
287287
// HookIssueEdited edited
288288
HookIssueEdited HookIssueAction = "edited"
289+
// HookIssueDeleted is an issue action for deleting an issue
290+
HookIssueDeleted HookIssueAction = "deleted"
289291
// HookIssueAssigned assigned
290292
HookIssueAssigned HookIssueAction = "assigned"
291293
// HookIssueUnassigned unassigned

options/locale/locale_en-US.ini

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2384,7 +2384,7 @@ settings.event_repository = Repository
23842384
settings.event_repository_desc = Repository created or deleted.
23852385
settings.event_header_issue = Issue Events
23862386
settings.event_issues = Issues
2387-
settings.event_issues_desc = Issue opened, closed, reopened, or edited.
2387+
settings.event_issues_desc = Issue opened, closed, reopened, edited or deleted.
23882388
settings.event_issue_assign = Issue Assigned
23892389
settings.event_issue_assign_desc = Issue assigned or unassigned.
23902390
settings.event_issue_label = Issue Labeled
@@ -2395,7 +2395,7 @@ settings.event_issue_comment = Issue Comment
23952395
settings.event_issue_comment_desc = Issue comment created, edited, or deleted.
23962396
settings.event_header_pull_request = Pull Request Events
23972397
settings.event_pull_request = Pull Request
2398-
settings.event_pull_request_desc = Pull request opened, closed, reopened, or edited.
2398+
settings.event_pull_request_desc = Pull request opened, closed, reopened, edited or deleted.
23992399
settings.event_pull_request_assign = Pull Request Assigned
24002400
settings.event_pull_request_assign_desc = Pull request assigned or unassigned.
24012401
settings.event_pull_request_label = Pull Request Labeled

services/webhook/notifier.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,43 @@ func (m *webhookNotifier) NewIssue(ctx context.Context, issue *issues_model.Issu
294294
}
295295
}
296296

297+
func (m *webhookNotifier) DeleteIssue(ctx context.Context, doer *user_model.User, issue *issues_model.Issue) {
298+
permission, _ := access_model.GetUserRepoPermission(ctx, issue.Repo, doer)
299+
if issue.IsPull {
300+
if err := issue.LoadPullRequest(ctx); err != nil {
301+
log.Error("LoadPullRequest: %v", err)
302+
return
303+
}
304+
if err := PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventPullRequest, &api.PullRequestPayload{
305+
Action: api.HookIssueDeleted,
306+
Index: issue.Index,
307+
PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, doer),
308+
Repository: convert.ToRepo(ctx, issue.Repo, permission),
309+
Sender: convert.ToUser(ctx, doer, nil),
310+
}); err != nil {
311+
log.Error("PrepareWebhooks: %v", err)
312+
}
313+
} else {
314+
if err := issue.LoadRepo(ctx); err != nil {
315+
log.Error("issue.LoadRepo: %v", err)
316+
return
317+
}
318+
if err := issue.LoadPoster(ctx); err != nil {
319+
log.Error("issue.LoadPoster: %v", err)
320+
return
321+
}
322+
if err := PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventIssues, &api.IssuePayload{
323+
Action: api.HookIssueDeleted,
324+
Index: issue.Index,
325+
Issue: convert.ToAPIIssue(ctx, issue.Poster, issue),
326+
Repository: convert.ToRepo(ctx, issue.Repo, permission),
327+
Sender: convert.ToUser(ctx, doer, nil),
328+
}); err != nil {
329+
log.Error("PrepareWebhooks: %v", err)
330+
}
331+
}
332+
}
333+
297334
func (m *webhookNotifier) NewPullRequest(ctx context.Context, pull *issues_model.PullRequest, mentions []*user_model.User) {
298335
if err := pull.LoadIssue(ctx); err != nil {
299336
log.Error("pull.LoadIssue: %v", err)

tests/integration/issue_test.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,13 @@ func testNewIssue(t *testing.T, session *TestSession, user, repo, title, content
148148
return issueURL
149149
}
150150

151+
func testIssueDelete(t *testing.T, session *TestSession, issueURL string) {
152+
req := NewRequestWithValues(t, "POST", path.Join(issueURL, "delete"), map[string]string{
153+
"_csrf": GetUserCSRFToken(t, session),
154+
})
155+
session.MakeRequest(t, req, http.StatusSeeOther)
156+
}
157+
151158
func testIssueAssign(t *testing.T, session *TestSession, repoLink string, issueID, assigneeID int64) {
152159
req := NewRequestWithValues(t, "POST", fmt.Sprintf(repoLink+"/issues/assignee?issue_ids=%d", issueID), map[string]string{
153160
"_csrf": GetUserCSRFToken(t, session),

tests/integration/repo_webhook_test.go

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"net/http"
1010
"net/http/httptest"
1111
"net/url"
12+
"path"
1213
"strings"
1314
"testing"
1415

@@ -450,6 +451,39 @@ func Test_WebhookIssue(t *testing.T) {
450451
})
451452
}
452453

454+
func Test_WebhookIssueDelete(t *testing.T) {
455+
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
456+
var payloads []api.IssuePayload
457+
var triggeredEvent string
458+
provider := newMockWebhookProvider(func(r *http.Request) {
459+
content, _ := io.ReadAll(r.Body)
460+
var payload api.IssuePayload
461+
err := json.Unmarshal(content, &payload)
462+
assert.NoError(t, err)
463+
payloads = append(payloads, payload)
464+
triggeredEvent = "issue"
465+
}, http.StatusOK)
466+
defer provider.Close()
467+
468+
// 1. create a new webhook with special webhook for repo1
469+
session := loginUser(t, "user2")
470+
testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "issues")
471+
issueURL := testNewIssue(t, session, "user2", "repo1", "Title1", "Description1")
472+
473+
// 2. trigger the webhook
474+
testIssueDelete(t, session, issueURL)
475+
476+
// 3. validate the webhook is triggered
477+
assert.Equal(t, "issue", triggeredEvent)
478+
require.Len(t, payloads, 2)
479+
assert.EqualValues(t, "deleted", payloads[1].Action)
480+
assert.Equal(t, "repo1", payloads[1].Issue.Repo.Name)
481+
assert.Equal(t, "user2/repo1", payloads[1].Issue.Repo.FullName)
482+
assert.Equal(t, "Title1", payloads[1].Issue.Title)
483+
assert.Equal(t, "Description1", payloads[1].Issue.Body)
484+
})
485+
}
486+
453487
func Test_WebhookIssueAssign(t *testing.T) {
454488
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
455489
var payloads []api.PullRequestPayload
@@ -596,6 +630,44 @@ func Test_WebhookPullRequest(t *testing.T) {
596630
})
597631
}
598632

633+
func Test_WebhookPullRequestDelete(t *testing.T) {
634+
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
635+
var payloads []api.PullRequestPayload
636+
var triggeredEvent string
637+
provider := newMockWebhookProvider(func(r *http.Request) {
638+
content, _ := io.ReadAll(r.Body)
639+
var payload api.PullRequestPayload
640+
err := json.Unmarshal(content, &payload)
641+
assert.NoError(t, err)
642+
payloads = append(payloads, payload)
643+
triggeredEvent = "pull_request"
644+
}, http.StatusOK)
645+
defer provider.Close()
646+
647+
// 1. create a new webhook with special webhook for repo1
648+
session := loginUser(t, "user2")
649+
testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "pull_request")
650+
651+
testAPICreateBranch(t, session, "user2", "repo1", "master", "master2", http.StatusCreated)
652+
653+
repo1 := unittest.AssertExistsAndLoadBean(t, &repo.Repository{ID: 1})
654+
issueURL := testCreatePullToDefaultBranch(t, session, repo1, repo1, "master2", "first pull request")
655+
656+
// 2. trigger the webhook
657+
testIssueDelete(t, session, path.Join(repo1.Link(), "pulls", issueURL))
658+
659+
// 3. validate the webhook is triggered
660+
assert.Equal(t, "pull_request", triggeredEvent)
661+
require.Len(t, payloads, 2)
662+
assert.EqualValues(t, "deleted", payloads[1].Action)
663+
assert.Equal(t, "repo1", payloads[1].PullRequest.Base.Repository.Name)
664+
assert.Equal(t, "user2/repo1", payloads[1].PullRequest.Base.Repository.FullName)
665+
assert.Equal(t, 0, *payloads[1].PullRequest.Additions)
666+
assert.Equal(t, 0, *payloads[1].PullRequest.ChangedFiles)
667+
assert.Equal(t, 0, *payloads[1].PullRequest.Deletions)
668+
})
669+
}
670+
599671
func Test_WebhookPullRequestComment(t *testing.T) {
600672
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
601673
var payloads []api.IssueCommentPayload

0 commit comments

Comments
 (0)