Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reference issues from pull requests and other issues #8137

Merged
merged 37 commits into from
Sep 20, 2019
Merged
Show file tree
Hide file tree
Changes from 35 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
78c3778
Update ref comment
guillep2k Sep 9, 2019
b4d5dd3
Generate comment on simple ref
guillep2k Sep 10, 2019
235694a
Make fmt + remove unneeded repo load
guillep2k Sep 10, 2019
64e4b42
Add TODO comments
guillep2k Sep 10, 2019
7edef31
Add ref-check in issue creation; re-arrange template
guillep2k Sep 10, 2019
2fbdf4c
Merge branch 'master' of github.com:go-gitea/gitea into xref-issues
guillep2k Sep 11, 2019
11eb10c
Make unit tests pass; rearrange code
guillep2k Sep 11, 2019
e4c21f6
Make fmt
guillep2k Sep 11, 2019
9f85400
Filter out xref comment if user can't see the referencing issue
guillep2k Sep 11, 2019
dd8cbe2
Add TODOs
guillep2k Sep 11, 2019
272aeda
Merge branch 'master' of github.com:go-gitea/gitea into xref-issues
guillep2k Sep 11, 2019
ecba703
Add cross reference
guillep2k Sep 11, 2019
cc85b0f
Rearrange code; add cross-repository references
guillep2k Sep 12, 2019
c92b919
Merge branch 'master' of github.com:go-gitea/gitea into xref-issues
guillep2k Sep 12, 2019
145e1a9
Striketrhough obsolete references
guillep2k Sep 12, 2019
3fd20eb
Remove unnecesary TODO
guillep2k Sep 12, 2019
ba36bc6
Add "not supported" note
guillep2k Sep 12, 2019
0bf9216
Support for edits and deletes, and issue title
guillep2k Sep 12, 2019
fefd405
Revert changes to go.mod
guillep2k Sep 12, 2019
7f4aedf
Fix fmt
guillep2k Sep 12, 2019
7fef0b7
Merge branch 'master' of github.com:go-gitea/gitea into xref-issues
guillep2k Sep 12, 2019
4f24ee9
Add support for xref from API
guillep2k Sep 12, 2019
2c83866
Add first integration test
guillep2k Sep 12, 2019
c4fcdd6
Add integration tests
guillep2k Sep 12, 2019
31304f5
Correct formatting
guillep2k Sep 12, 2019
8b2b0d6
Fix add comment test
guillep2k Sep 12, 2019
fcc6bf0
Add migration
guillep2k Sep 12, 2019
610291c
Remove outdated comments; fix typo
guillep2k Sep 12, 2019
5312037
Some code refactoring and rearranging
guillep2k Sep 14, 2019
ca2f7bf
Merge branch 'master' into xref-issues
guillep2k Sep 14, 2019
f7ffc51
Rename findCrossReferences to createCrossReferences
guillep2k Sep 18, 2019
9ffb74b
Delete xrefs when repository is deleted
guillep2k Sep 18, 2019
66392e1
Corrections as suggested by @lafriks
guillep2k Sep 18, 2019
49bbe79
Prepare for merge
guillep2k Sep 18, 2019
d157ea8
Merge master into xref-issues
guillep2k Sep 18, 2019
92246b5
Fix log for errors
guillep2k Sep 19, 2019
ec51461
Merge branch 'master' into xref-issues
guillep2k Sep 19, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 103 additions & 1 deletion integrations/issue_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
package integrations

import (
"fmt"
"net/http"
"path"
"strconv"
Expand Down Expand Up @@ -136,7 +137,7 @@ func testNewIssue(t *testing.T, session *TestSession, user, repo, title, content
return issueURL
}

func testIssueAddComment(t *testing.T, session *TestSession, issueURL, content, status string) {
func testIssueAddComment(t *testing.T, session *TestSession, issueURL, content, status string) int64 {

req := NewRequest(t, "GET", issueURL)
resp := session.MakeRequest(t, req, http.StatusOK)
Expand All @@ -161,6 +162,13 @@ func testIssueAddComment(t *testing.T, session *TestSession, issueURL, content,

val := htmlDoc.doc.Find(".comment-list .comments .comment .render-content p").Eq(commentCount).Text()
assert.Equal(t, content, val)

idAttr, has := htmlDoc.doc.Find(".comment-list .comments .comment").Eq(commentCount).Attr("id")
idStr := idAttr[strings.LastIndexByte(idAttr, '-')+1:]
assert.True(t, has)
id, err := strconv.Atoi(idStr)
assert.NoError(t, err)
return int64(id)
}

func TestNewIssue(t *testing.T) {
Expand All @@ -184,3 +192,97 @@ func TestIssueCommentClose(t *testing.T) {
val := htmlDoc.doc.Find(".comment-list .comments .comment .render-content p").First().Text()
assert.Equal(t, "Description", val)
}

func TestIssueCrossReference(t *testing.T) {
prepareTestEnv(t)

// Issue that will be referenced
_, issueBase := testIssueWithBean(t, "user2", 1, "Title", "Description")

// Ref from issue title
issueRefURL, issueRef := testIssueWithBean(t, "user2", 1, fmt.Sprintf("Title ref #%d", issueBase.Index), "Description")
models.AssertExistsAndLoadBean(t, &models.Comment{
IssueID: issueBase.ID,
RefRepoID: 1,
RefIssueID: issueRef.ID,
RefCommentID: 0,
RefIsPull: false,
RefAction: models.XRefActionNone})

// Edit title, neuter ref
testIssueChangeInfo(t, "user2", issueRefURL, "title", "Title no ref")
models.AssertExistsAndLoadBean(t, &models.Comment{
IssueID: issueBase.ID,
RefRepoID: 1,
RefIssueID: issueRef.ID,
RefCommentID: 0,
RefIsPull: false,
RefAction: models.XRefActionNeutered})

// Ref from issue content
issueRefURL, issueRef = testIssueWithBean(t, "user2", 1, "TitleXRef", fmt.Sprintf("Description ref #%d", issueBase.Index))
models.AssertExistsAndLoadBean(t, &models.Comment{
IssueID: issueBase.ID,
RefRepoID: 1,
RefIssueID: issueRef.ID,
RefCommentID: 0,
RefIsPull: false,
RefAction: models.XRefActionNone})

// Edit content, neuter ref
testIssueChangeInfo(t, "user2", issueRefURL, "content", "Description no ref")
models.AssertExistsAndLoadBean(t, &models.Comment{
IssueID: issueBase.ID,
RefRepoID: 1,
RefIssueID: issueRef.ID,
RefCommentID: 0,
RefIsPull: false,
RefAction: models.XRefActionNeutered})

// Ref from a comment
session := loginUser(t, "user2")
commentID := testIssueAddComment(t, session, issueRefURL, fmt.Sprintf("Adding ref from comment #%d", issueBase.Index), "")
comment := &models.Comment{
IssueID: issueBase.ID,
RefRepoID: 1,
RefIssueID: issueRef.ID,
RefCommentID: commentID,
RefIsPull: false,
RefAction: models.XRefActionNone}
models.AssertExistsAndLoadBean(t, comment)

// Ref from a different repository
issueRefURL, issueRef = testIssueWithBean(t, "user12", 10, "TitleXRef", fmt.Sprintf("Description ref user2/repo1#%d", issueBase.Index))
models.AssertExistsAndLoadBean(t, &models.Comment{
IssueID: issueBase.ID,
RefRepoID: 10,
RefIssueID: issueRef.ID,
RefCommentID: 0,
RefIsPull: false,
RefAction: models.XRefActionNone})
}

func testIssueWithBean(t *testing.T, user string, repoID int64, title, content string) (string, *models.Issue) {
session := loginUser(t, user)
issueURL := testNewIssue(t, session, user, fmt.Sprintf("repo%d", repoID), title, content)
indexStr := issueURL[strings.LastIndexByte(issueURL, '/')+1:]
index, err := strconv.Atoi(indexStr)
assert.NoError(t, err, "Invalid issue href: %s", issueURL)
issue := &models.Issue{RepoID: repoID, Index: int64(index)}
models.AssertExistsAndLoadBean(t, issue)
return issueURL, issue
}

func testIssueChangeInfo(t *testing.T, user, issueURL, info string, value string) {
session := loginUser(t, user)

req := NewRequest(t, "GET", issueURL)
resp := session.MakeRequest(t, req, http.StatusOK)
htmlDoc := NewHTMLParser(t, resp.Body)

req = NewRequestWithValues(t, "POST", path.Join(issueURL, info), map[string]string{
"_csrf": htmlDoc.GetCSRF(),
info: value,
})
_ = session.MakeRequest(t, req, http.StatusOK)
}
57 changes: 52 additions & 5 deletions models/issue.go
Original file line number Diff line number Diff line change
Expand Up @@ -595,8 +595,9 @@ func (issue *Issue) ClearLabels(doer *User) (err error) {
if err = sess.Commit(); err != nil {
return fmt.Errorf("Commit: %v", err)
}
sess.Close()

if err = issue.loadPoster(x); err != nil {
if err = issue.LoadPoster(); err != nil {
return fmt.Errorf("loadPoster: %v", err)
}

Expand Down Expand Up @@ -870,9 +871,18 @@ func (issue *Issue) ChangeTitle(doer *User, title string) (err error) {
return fmt.Errorf("createChangeTitleComment: %v", err)
}

if err = issue.neuterCrossReferences(sess); err != nil {
return err
}

if err = issue.addCrossReferences(sess, doer); err != nil {
return err
}

if err = sess.Commit(); err != nil {
return err
}
sess.Close()

mode, _ := AccessLevel(issue.Poster, issue.Repo)
if issue.IsPull {
Expand Down Expand Up @@ -939,9 +949,26 @@ func (issue *Issue) ChangeContent(doer *User, content string) (err error) {
oldContent := issue.Content
issue.Content = content

if err = UpdateIssueCols(issue, "content"); err != nil {
sess := x.NewSession()
defer sess.Close()
if err = sess.Begin(); err != nil {
return err
}

if err = updateIssueCols(sess, issue, "content"); err != nil {
return fmt.Errorf("UpdateIssueCols: %v", err)
}
if err = issue.neuterCrossReferences(sess); err != nil {
return err
}
if err = issue.addCrossReferences(sess, doer); err != nil {
return err
}

if err = sess.Commit(); err != nil {
return err
}
sess.Close()

mode, _ := AccessLevel(issue.Poster, issue.Repo)
if issue.IsPull {
Expand Down Expand Up @@ -1171,8 +1198,10 @@ func newIssue(e *xorm.Session, doer *User, opts NewIssueOptions) (err error) {
}
}
}

return opts.Issue.loadAttributes(e)
if err = opts.Issue.loadAttributes(e); err != nil {
return err
}
return opts.Issue.addCrossReferences(e, doer)
}

// NewIssue creates new issue with labels for repository.
Expand All @@ -1199,6 +1228,7 @@ func NewIssue(repo *Repository, issue *Issue, labelIDs []int64, assigneeIDs []in
if err = sess.Commit(); err != nil {
return fmt.Errorf("Commit: %v", err)
}
sess.Close()

if err = NotifyWatchers(&Action{
ActUserID: issue.Poster.ID,
Expand Down Expand Up @@ -1785,7 +1815,24 @@ func updateIssue(e Engine, issue *Issue) error {

// UpdateIssue updates all fields of given issue.
func UpdateIssue(issue *Issue) error {
return updateIssue(x, issue)
sess := x.NewSession()
defer sess.Close()
if err := sess.Begin(); err != nil {
return err
}
if err := updateIssue(sess, issue); err != nil {
return err
}
if err := issue.neuterCrossReferences(sess); err != nil {
return err
}
if err := issue.loadPoster(sess); err != nil {
return err
}
if err := issue.addCrossReferences(sess, issue.Poster); err != nil {
return err
}
return sess.Commit()
}

// UpdateIssueDeadline updates an issue deadline and adds comments. Setting a deadline to 0 means deleting it.
Expand Down
61 changes: 55 additions & 6 deletions models/issue_comment.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,14 +142,30 @@ type Comment struct {
Review *Review `xorm:"-"`
ReviewID int64 `xorm:"index"`
Invalidated bool

// Reference an issue or pull from another comment, issue or PR
// All information is about the origin of the reference
RefRepoID int64 `xorm:"index"` // Repo where the referencing
RefIssueID int64 `xorm:"index"`
RefCommentID int64 `xorm:"index"` // 0 if origin is Issue title or content (or PR's)
RefAction XRefAction `xorm:"SMALLINT"` // What hapens if RefIssueID resolves
RefIsPull bool

RefRepo *Repository `xorm:"-"`
RefIssue *Issue `xorm:"-"`
RefComment *Comment `xorm:"-"`
}

// LoadIssue loads issue from database
func (c *Comment) LoadIssue() (err error) {
return c.loadIssue(x)
}

func (c *Comment) loadIssue(e Engine) (err error) {
if c.Issue != nil {
return nil
}
c.Issue, err = GetIssueByID(c.IssueID)
c.Issue, err = getIssueByID(e, c.IssueID)
guillep2k marked this conversation as resolved.
Show resolved Hide resolved
return
}

Expand Down Expand Up @@ -527,6 +543,11 @@ func createComment(e *xorm.Session, opts *CreateCommentOptions) (_ *Comment, err
TreePath: opts.TreePath,
ReviewID: opts.ReviewID,
Patch: opts.Patch,
RefRepoID: opts.RefRepoID,
RefIssueID: opts.RefIssueID,
RefCommentID: opts.RefCommentID,
RefAction: opts.RefAction,
RefIsPull: opts.RefIsPull,
}
if _, err = e.Insert(comment); err != nil {
return nil, err
Expand All @@ -540,6 +561,10 @@ func createComment(e *xorm.Session, opts *CreateCommentOptions) (_ *Comment, err
return nil, err
}

if err = comment.addCrossReferences(e, opts.Doer); err != nil {
return nil, err
}

return comment, nil
}

Expand Down Expand Up @@ -794,6 +819,11 @@ type CreateCommentOptions struct {
ReviewID int64
Content string
Attachments []string // UUIDs of attachments
RefRepoID int64
RefIssueID int64
RefCommentID int64
RefAction XRefAction
RefIsPull bool
}

// CreateComment creates comment of issue or commit.
Expand Down Expand Up @@ -934,21 +964,33 @@ func FindComments(opts FindCommentsOptions) ([]*Comment, error) {

// UpdateComment updates information of comment.
func UpdateComment(doer *User, c *Comment, oldContent string) error {
if _, err := x.ID(c.ID).AllCols().Update(c); err != nil {
sess := x.NewSession()
defer sess.Close()
if err := sess.Begin(); err != nil {
return err
}

if err := c.LoadPoster(); err != nil {
if _, err := sess.ID(c.ID).AllCols().Update(c); err != nil {
return err
}
if err := c.LoadIssue(); err != nil {
if err := c.loadIssue(sess); err != nil {
return err
}
if err := c.neuterCrossReferences(sess); err != nil {
return err
}
if err := c.addCrossReferences(sess, doer); err != nil {
return err
}
if err := sess.Commit(); err != nil {
return fmt.Errorf("Commit: %v", err)
}
sess.Close()

if err := c.Issue.LoadAttributes(); err != nil {
if err := c.LoadPoster(); err != nil {
return err
}
if err := c.loadPoster(x); err != nil {
if err := c.Issue.LoadAttributes(); err != nil {
return err
}

Expand Down Expand Up @@ -996,6 +1038,10 @@ func DeleteComment(doer *User, comment *Comment) error {
return err
}

if err := comment.neuterCrossReferences(sess); err != nil {
return err
}

if err := sess.Commit(); err != nil {
return err
}
Expand All @@ -1014,6 +1060,9 @@ func DeleteComment(doer *User, comment *Comment) error {
if err := comment.loadPoster(x); err != nil {
return err
}
if err := comment.neuterCrossReferences(x); err != nil {
return err
}

mode, _ := AccessLevel(doer, comment.Issue.Repo)

Expand Down
Loading