From 64c7ebf9581de6fc5511a8f3f16ea8bf4f102bcc Mon Sep 17 00:00:00 2001 From: jaqra Date: Wed, 11 Sep 2019 01:29:51 +0300 Subject: [PATCH] Implement issue reference cross comment --- models/issue.go | 10 +++ models/issue_comment.go | 75 +++++++++++++++++++ options/locale/locale_en-US.ini | 1 + routers/repo/issue.go | 15 ++++ .../repo/issue/view_content/comments.tmpl | 11 +++ 5 files changed, 112 insertions(+) diff --git a/models/issue.go b/models/issue.go index b849f97bd4252..0ad6e68418542 100644 --- a/models/issue.go +++ b/models/issue.go @@ -1225,6 +1225,16 @@ func NewIssue(repo *Repository, issue *Issue, labelIDs []int64, assigneeIDs []in go HookQueue.Add(issue.RepoID) } + err = FindAndCreateIssueRef(issue.Poster, repo, issue, issue.Content) + if err != nil { + return err + } + + err = FindAndCreateIssueRef(issue.Poster, repo, issue, issue.Title) + if err != nil { + return err + } + return nil } diff --git a/models/issue_comment.go b/models/issue_comment.go index ad1a59e9d385e..79f83dc1162ae 100644 --- a/models/issue_comment.go +++ b/models/issue_comment.go @@ -9,6 +9,7 @@ package models import ( "bytes" "fmt" + "html" "strings" "code.gitea.io/gitea/modules/git" @@ -858,6 +859,11 @@ func CreateIssueComment(doer *User, repo *Repository, issue *Issue, content stri return nil, fmt.Errorf("CreateComment: %v", err) } + err = FindAndCreateIssueRef(doer, repo, issue, content) + if err != nil { + return nil, err + } + mode, _ := AccessLevel(doer, repo) if err = PrepareWebhooks(repo, HookEventIssueComment, &api.IssueCommentPayload{ Action: api.HookIssueCommentCreated, @@ -873,6 +879,51 @@ func CreateIssueComment(doer *User, repo *Repository, issue *Issue, content stri return comment, nil } +// FindAndCreateIssueRef Search message for issue ref and create cross ref comment +func FindAndCreateIssueRef(doer *User, repo *Repository, issue *Issue, message string) error { + refMarked := make(map[int64]bool) + var refRepo *Repository + var err error + for _, m := range issueReferenceKeywordsPat.FindAllStringSubmatch(message, -1) { + if len(m[3]) == 0 { + continue + } + ref := m[3] + + // issue is from another repo + if len(m[1]) > 0 && len(m[2]) > 0 { + refRepo, err = GetRepositoryFromMatch(m[1], m[2]) + if err != nil { + continue + } + } else { + refRepo = repo + } + refIssue, err := getIssueFromRef(refRepo, ref) + if err != nil { + return err + } + + if refIssue == nil || refMarked[refIssue.ID] { + continue + } + refMarked[refIssue.ID] = true + + issueType := "issues" + + if issue.IsPull { + issueType = "pull" + } + + message := fmt.Sprintf(`%s`, repo.Link(), issueType, issue.ID, html.EscapeString(issue.Title)) + if err = CreateIssueRefComment(doer, refRepo, refIssue, message); err != nil { + return err + } + } + + return nil +} + // CreateCodeComment creates a plain code comment at the specified line / path func CreateCodeComment(doer *User, repo *Repository, issue *Issue, content, treePath string, line, reviewID int64) (*Comment, error) { var commitID, patch string @@ -955,6 +1006,30 @@ func CreateRefComment(doer *User, repo *Repository, issue *Issue, content, commi return err } +// CreateIssueRefComment creates a issue reference comment to issue. +func CreateIssueRefComment(doer *User, repo *Repository, issue *Issue, content string) error { + // Check if same reference from same issue has already existed. + has, err := x.Get(&Comment{ + Type: CommentTypeIssueRef, + IssueID: issue.ID, + Content: content, + }) + if err != nil { + return fmt.Errorf("CreateIssueRefComment (check has): %v", err) + } else if has { + return nil + } + + _, err = CreateComment(&CreateCommentOptions{ + Type: CommentTypeIssueRef, + Doer: doer, + Repo: repo, + Issue: issue, + Content: content, + }) + return err +} + // GetCommentByID returns the comment by given ID. func GetCommentByID(id int64) (*Comment, error) { c := new(Comment) diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index e577727314954..797e32a9b11af 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -832,6 +832,7 @@ issues.reopen_comment_issue = Comment and Reopen issues.create_comment = Comment issues.closed_at = `closed %[2]s` issues.reopened_at = `reopened %[2]s` +issues.issue_ref_at = `referenced this issue from %s` issues.commit_ref_at = `referenced this issue from a commit %[2]s` issues.poster = Poster issues.collaborator = Collaborator diff --git a/routers/repo/issue.go b/routers/repo/issue.go index a865bd0ad11ed..ff4252ff83d0d 100644 --- a/routers/repo/issue.go +++ b/routers/repo/issue.go @@ -1051,6 +1051,11 @@ func UpdateIssueTitle(ctx *context.Context) { return } + if err := models.FindAndCreateIssueRef(ctx.User, ctx.Repo.Repository, issue, title); err != nil { + ctx.ServerError("FindAndCreateIssueRef", err) + return + } + notification.NotifyIssueChangeTitle(ctx.User, issue, oldTitle) ctx.JSON(200, map[string]interface{}{ @@ -1076,6 +1081,11 @@ func UpdateIssueContent(ctx *context.Context) { return } + if err := models.FindAndCreateIssueRef(ctx.User, ctx.Repo.Repository, issue, content); err != nil { + ctx.ServerError("FindAndCreateIssueRef", err) + return + } + ctx.JSON(200, map[string]interface{}{ "content": string(markdown.Render([]byte(issue.Content), ctx.Query("context"), ctx.Repo.Repository.ComposeMetas())), }) @@ -1348,6 +1358,11 @@ func UpdateCommentContent(ctx *context.Context) { return } + if err = models.FindAndCreateIssueRef(ctx.User, ctx.Repo.Repository, comment.Issue, comment.Content); err != nil { + ctx.ServerError("FindAndCreateIssueRef", err) + return + } + notification.NotifyUpdateComment(ctx.User, comment, oldContent) ctx.JSON(200, map[string]interface{}{ diff --git a/templates/repo/issue/view_content/comments.tmpl b/templates/repo/issue/view_content/comments.tmpl index 68303cf1ca28c..81da31666594a 100644 --- a/templates/repo/issue/view_content/comments.tmpl +++ b/templates/repo/issue/view_content/comments.tmpl @@ -96,6 +96,17 @@ {{.Poster.GetDisplayName}} {{$.i18n.Tr "repo.issues.closed_at" .EventTag $createdStr | Safe}} + {{else if eq .Type 3}} +
+ + + + + + {{.Poster.GetDisplayName}} + {{$.i18n.Tr "repo.issues.issue_ref_at" .Content | Safe}} + +
{{else if eq .Type 4}}