Move issues related files into models/issues (#19931)
* Move access and repo permission to models/perm/access * fix test * fix git test * Move functions sequence * Some improvements per @KN4CK3R and @delvh * Move issues related code to models/issues * Move some issues related sub package * Merge * Fix test * Fix test * Fix test * Fix test * Rename some files
This commit is contained in:
parent
3708ca8e28
commit
1a9821f57a
180 changed files with 3667 additions and 3677 deletions
|
@ -10,7 +10,7 @@ import (
|
||||||
"net/url"
|
"net/url"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
@ -23,9 +23,9 @@ import (
|
||||||
func TestAPIListRepoComments(t *testing.T) {
|
func TestAPIListRepoComments(t *testing.T) {
|
||||||
defer prepareTestEnv(t)()
|
defer prepareTestEnv(t)()
|
||||||
|
|
||||||
comment := unittest.AssertExistsAndLoadBean(t, &models.Comment{},
|
comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{},
|
||||||
unittest.Cond("type = ?", models.CommentTypeComment)).(*models.Comment)
|
unittest.Cond("type = ?", issues_model.CommentTypeComment)).(*issues_model.Comment)
|
||||||
issue := unittest.AssertExistsAndLoadBean(t, &models.Issue{ID: comment.IssueID}).(*models.Issue)
|
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: comment.IssueID}).(*issues_model.Issue)
|
||||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID}).(*repo_model.Repository)
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID}).(*repo_model.Repository)
|
||||||
repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User)
|
repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User)
|
||||||
|
|
||||||
|
@ -38,10 +38,10 @@ func TestAPIListRepoComments(t *testing.T) {
|
||||||
DecodeJSON(t, resp, &apiComments)
|
DecodeJSON(t, resp, &apiComments)
|
||||||
assert.Len(t, apiComments, 2)
|
assert.Len(t, apiComments, 2)
|
||||||
for _, apiComment := range apiComments {
|
for _, apiComment := range apiComments {
|
||||||
c := &models.Comment{ID: apiComment.ID}
|
c := &issues_model.Comment{ID: apiComment.ID}
|
||||||
unittest.AssertExistsAndLoadBean(t, c,
|
unittest.AssertExistsAndLoadBean(t, c,
|
||||||
unittest.Cond("type = ?", models.CommentTypeComment))
|
unittest.Cond("type = ?", issues_model.CommentTypeComment))
|
||||||
unittest.AssertExistsAndLoadBean(t, &models.Issue{ID: c.IssueID, RepoID: repo.ID})
|
unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: c.IssueID, RepoID: repo.ID})
|
||||||
}
|
}
|
||||||
|
|
||||||
// test before and since filters
|
// test before and since filters
|
||||||
|
@ -69,9 +69,9 @@ func TestAPIListRepoComments(t *testing.T) {
|
||||||
func TestAPIListIssueComments(t *testing.T) {
|
func TestAPIListIssueComments(t *testing.T) {
|
||||||
defer prepareTestEnv(t)()
|
defer prepareTestEnv(t)()
|
||||||
|
|
||||||
comment := unittest.AssertExistsAndLoadBean(t, &models.Comment{},
|
comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{},
|
||||||
unittest.Cond("type = ?", models.CommentTypeComment)).(*models.Comment)
|
unittest.Cond("type = ?", issues_model.CommentTypeComment)).(*issues_model.Comment)
|
||||||
issue := unittest.AssertExistsAndLoadBean(t, &models.Issue{ID: comment.IssueID}).(*models.Issue)
|
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: comment.IssueID}).(*issues_model.Issue)
|
||||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID}).(*repo_model.Repository)
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID}).(*repo_model.Repository)
|
||||||
repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User)
|
repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User)
|
||||||
|
|
||||||
|
@ -82,8 +82,8 @@ func TestAPIListIssueComments(t *testing.T) {
|
||||||
|
|
||||||
var comments []*api.Comment
|
var comments []*api.Comment
|
||||||
DecodeJSON(t, resp, &comments)
|
DecodeJSON(t, resp, &comments)
|
||||||
expectedCount := unittest.GetCount(t, &models.Comment{IssueID: issue.ID},
|
expectedCount := unittest.GetCount(t, &issues_model.Comment{IssueID: issue.ID},
|
||||||
unittest.Cond("type = ?", models.CommentTypeComment))
|
unittest.Cond("type = ?", issues_model.CommentTypeComment))
|
||||||
assert.EqualValues(t, expectedCount, len(comments))
|
assert.EqualValues(t, expectedCount, len(comments))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,7 +91,7 @@ func TestAPICreateComment(t *testing.T) {
|
||||||
defer prepareTestEnv(t)()
|
defer prepareTestEnv(t)()
|
||||||
const commentBody = "Comment body"
|
const commentBody = "Comment body"
|
||||||
|
|
||||||
issue := unittest.AssertExistsAndLoadBean(t, &models.Issue{}).(*models.Issue)
|
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{}).(*issues_model.Issue)
|
||||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID}).(*repo_model.Repository)
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID}).(*repo_model.Repository)
|
||||||
repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User)
|
repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User)
|
||||||
|
|
||||||
|
@ -107,13 +107,13 @@ func TestAPICreateComment(t *testing.T) {
|
||||||
var updatedComment api.Comment
|
var updatedComment api.Comment
|
||||||
DecodeJSON(t, resp, &updatedComment)
|
DecodeJSON(t, resp, &updatedComment)
|
||||||
assert.EqualValues(t, commentBody, updatedComment.Body)
|
assert.EqualValues(t, commentBody, updatedComment.Body)
|
||||||
unittest.AssertExistsAndLoadBean(t, &models.Comment{ID: updatedComment.ID, IssueID: issue.ID, Content: commentBody})
|
unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: updatedComment.ID, IssueID: issue.ID, Content: commentBody})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAPIGetComment(t *testing.T) {
|
func TestAPIGetComment(t *testing.T) {
|
||||||
defer prepareTestEnv(t)()
|
defer prepareTestEnv(t)()
|
||||||
|
|
||||||
comment := unittest.AssertExistsAndLoadBean(t, &models.Comment{ID: 2}).(*models.Comment)
|
comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: 2}).(*issues_model.Comment)
|
||||||
assert.NoError(t, comment.LoadIssue())
|
assert.NoError(t, comment.LoadIssue())
|
||||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: comment.Issue.RepoID}).(*repo_model.Repository)
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: comment.Issue.RepoID}).(*repo_model.Repository)
|
||||||
repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User)
|
repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User)
|
||||||
|
@ -141,9 +141,9 @@ func TestAPIEditComment(t *testing.T) {
|
||||||
defer prepareTestEnv(t)()
|
defer prepareTestEnv(t)()
|
||||||
const newCommentBody = "This is the new comment body"
|
const newCommentBody = "This is the new comment body"
|
||||||
|
|
||||||
comment := unittest.AssertExistsAndLoadBean(t, &models.Comment{},
|
comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{},
|
||||||
unittest.Cond("type = ?", models.CommentTypeComment)).(*models.Comment)
|
unittest.Cond("type = ?", issues_model.CommentTypeComment)).(*issues_model.Comment)
|
||||||
issue := unittest.AssertExistsAndLoadBean(t, &models.Issue{ID: comment.IssueID}).(*models.Issue)
|
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: comment.IssueID}).(*issues_model.Issue)
|
||||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID}).(*repo_model.Repository)
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID}).(*repo_model.Repository)
|
||||||
repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User)
|
repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User)
|
||||||
|
|
||||||
|
@ -160,15 +160,15 @@ func TestAPIEditComment(t *testing.T) {
|
||||||
DecodeJSON(t, resp, &updatedComment)
|
DecodeJSON(t, resp, &updatedComment)
|
||||||
assert.EqualValues(t, comment.ID, updatedComment.ID)
|
assert.EqualValues(t, comment.ID, updatedComment.ID)
|
||||||
assert.EqualValues(t, newCommentBody, updatedComment.Body)
|
assert.EqualValues(t, newCommentBody, updatedComment.Body)
|
||||||
unittest.AssertExistsAndLoadBean(t, &models.Comment{ID: comment.ID, IssueID: issue.ID, Content: newCommentBody})
|
unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: comment.ID, IssueID: issue.ID, Content: newCommentBody})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAPIDeleteComment(t *testing.T) {
|
func TestAPIDeleteComment(t *testing.T) {
|
||||||
defer prepareTestEnv(t)()
|
defer prepareTestEnv(t)()
|
||||||
|
|
||||||
comment := unittest.AssertExistsAndLoadBean(t, &models.Comment{},
|
comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{},
|
||||||
unittest.Cond("type = ?", models.CommentTypeComment)).(*models.Comment)
|
unittest.Cond("type = ?", issues_model.CommentTypeComment)).(*issues_model.Comment)
|
||||||
issue := unittest.AssertExistsAndLoadBean(t, &models.Issue{ID: comment.IssueID}).(*models.Issue)
|
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: comment.IssueID}).(*issues_model.Issue)
|
||||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID}).(*repo_model.Repository)
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID}).(*repo_model.Repository)
|
||||||
repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User)
|
repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User)
|
||||||
|
|
||||||
|
@ -178,14 +178,14 @@ func TestAPIDeleteComment(t *testing.T) {
|
||||||
repoOwner.Name, repo.Name, comment.ID, token)
|
repoOwner.Name, repo.Name, comment.ID, token)
|
||||||
session.MakeRequest(t, req, http.StatusNoContent)
|
session.MakeRequest(t, req, http.StatusNoContent)
|
||||||
|
|
||||||
unittest.AssertNotExistsBean(t, &models.Comment{ID: comment.ID})
|
unittest.AssertNotExistsBean(t, &issues_model.Comment{ID: comment.ID})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAPIListIssueTimeline(t *testing.T) {
|
func TestAPIListIssueTimeline(t *testing.T) {
|
||||||
defer prepareTestEnv(t)()
|
defer prepareTestEnv(t)()
|
||||||
|
|
||||||
// load comment
|
// load comment
|
||||||
issue := unittest.AssertExistsAndLoadBean(t, &models.Issue{ID: 1}).(*models.Issue)
|
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1}).(*issues_model.Issue)
|
||||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID}).(*repo_model.Repository)
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID}).(*repo_model.Repository)
|
||||||
repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User)
|
repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User)
|
||||||
|
|
||||||
|
@ -199,6 +199,6 @@ func TestAPIListIssueTimeline(t *testing.T) {
|
||||||
// lists extracted directly from DB are the same
|
// lists extracted directly from DB are the same
|
||||||
var comments []*api.TimelineComment
|
var comments []*api.TimelineComment
|
||||||
DecodeJSON(t, resp, &comments)
|
DecodeJSON(t, resp, &comments)
|
||||||
expectedCount := unittest.GetCount(t, &models.Comment{IssueID: issue.ID})
|
expectedCount := unittest.GetCount(t, &issues_model.Comment{IssueID: issue.ID})
|
||||||
assert.EqualValues(t, expectedCount, len(comments))
|
assert.EqualValues(t, expectedCount, len(comments))
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
@ -37,7 +37,7 @@ func TestAPIModifyLabels(t *testing.T) {
|
||||||
resp := session.MakeRequest(t, req, http.StatusCreated)
|
resp := session.MakeRequest(t, req, http.StatusCreated)
|
||||||
apiLabel := new(api.Label)
|
apiLabel := new(api.Label)
|
||||||
DecodeJSON(t, resp, &apiLabel)
|
DecodeJSON(t, resp, &apiLabel)
|
||||||
dbLabel := unittest.AssertExistsAndLoadBean(t, &models.Label{ID: apiLabel.ID, RepoID: repo.ID}).(*models.Label)
|
dbLabel := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: apiLabel.ID, RepoID: repo.ID}).(*issues_model.Label)
|
||||||
assert.EqualValues(t, dbLabel.Name, apiLabel.Name)
|
assert.EqualValues(t, dbLabel.Name, apiLabel.Name)
|
||||||
assert.EqualValues(t, strings.TrimLeft(dbLabel.Color, "#"), apiLabel.Color)
|
assert.EqualValues(t, strings.TrimLeft(dbLabel.Color, "#"), apiLabel.Color)
|
||||||
|
|
||||||
|
@ -92,8 +92,8 @@ func TestAPIAddIssueLabels(t *testing.T) {
|
||||||
assert.NoError(t, unittest.LoadFixtures())
|
assert.NoError(t, unittest.LoadFixtures())
|
||||||
|
|
||||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository)
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository)
|
||||||
issue := unittest.AssertExistsAndLoadBean(t, &models.Issue{RepoID: repo.ID}).(*models.Issue)
|
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{RepoID: repo.ID}).(*issues_model.Issue)
|
||||||
_ = unittest.AssertExistsAndLoadBean(t, &models.Label{RepoID: repo.ID, ID: 2}).(*models.Label)
|
_ = unittest.AssertExistsAndLoadBean(t, &issues_model.Label{RepoID: repo.ID, ID: 2}).(*issues_model.Label)
|
||||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User)
|
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User)
|
||||||
|
|
||||||
session := loginUser(t, owner.Name)
|
session := loginUser(t, owner.Name)
|
||||||
|
@ -106,17 +106,17 @@ func TestAPIAddIssueLabels(t *testing.T) {
|
||||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||||
var apiLabels []*api.Label
|
var apiLabels []*api.Label
|
||||||
DecodeJSON(t, resp, &apiLabels)
|
DecodeJSON(t, resp, &apiLabels)
|
||||||
assert.Len(t, apiLabels, unittest.GetCount(t, &models.IssueLabel{IssueID: issue.ID}))
|
assert.Len(t, apiLabels, unittest.GetCount(t, &issues_model.IssueLabel{IssueID: issue.ID}))
|
||||||
|
|
||||||
unittest.AssertExistsAndLoadBean(t, &models.IssueLabel{IssueID: issue.ID, LabelID: 2})
|
unittest.AssertExistsAndLoadBean(t, &issues_model.IssueLabel{IssueID: issue.ID, LabelID: 2})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAPIReplaceIssueLabels(t *testing.T) {
|
func TestAPIReplaceIssueLabels(t *testing.T) {
|
||||||
assert.NoError(t, unittest.LoadFixtures())
|
assert.NoError(t, unittest.LoadFixtures())
|
||||||
|
|
||||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository)
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository)
|
||||||
issue := unittest.AssertExistsAndLoadBean(t, &models.Issue{RepoID: repo.ID}).(*models.Issue)
|
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{RepoID: repo.ID}).(*issues_model.Issue)
|
||||||
label := unittest.AssertExistsAndLoadBean(t, &models.Label{RepoID: repo.ID}).(*models.Label)
|
label := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{RepoID: repo.ID}).(*issues_model.Label)
|
||||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User)
|
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User)
|
||||||
|
|
||||||
session := loginUser(t, owner.Name)
|
session := loginUser(t, owner.Name)
|
||||||
|
@ -133,8 +133,8 @@ func TestAPIReplaceIssueLabels(t *testing.T) {
|
||||||
assert.EqualValues(t, label.ID, apiLabels[0].ID)
|
assert.EqualValues(t, label.ID, apiLabels[0].ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
unittest.AssertCount(t, &models.IssueLabel{IssueID: issue.ID}, 1)
|
unittest.AssertCount(t, &issues_model.IssueLabel{IssueID: issue.ID}, 1)
|
||||||
unittest.AssertExistsAndLoadBean(t, &models.IssueLabel{IssueID: issue.ID, LabelID: label.ID})
|
unittest.AssertExistsAndLoadBean(t, &issues_model.IssueLabel{IssueID: issue.ID, LabelID: label.ID})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAPIModifyOrgLabels(t *testing.T) {
|
func TestAPIModifyOrgLabels(t *testing.T) {
|
||||||
|
@ -156,7 +156,7 @@ func TestAPIModifyOrgLabels(t *testing.T) {
|
||||||
resp := session.MakeRequest(t, req, http.StatusCreated)
|
resp := session.MakeRequest(t, req, http.StatusCreated)
|
||||||
apiLabel := new(api.Label)
|
apiLabel := new(api.Label)
|
||||||
DecodeJSON(t, resp, &apiLabel)
|
DecodeJSON(t, resp, &apiLabel)
|
||||||
dbLabel := unittest.AssertExistsAndLoadBean(t, &models.Label{ID: apiLabel.ID, OrgID: owner.ID}).(*models.Label)
|
dbLabel := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: apiLabel.ID, OrgID: owner.ID}).(*issues_model.Label)
|
||||||
assert.EqualValues(t, dbLabel.Name, apiLabel.Name)
|
assert.EqualValues(t, dbLabel.Name, apiLabel.Name)
|
||||||
assert.EqualValues(t, strings.TrimLeft(dbLabel.Color, "#"), apiLabel.Color)
|
assert.EqualValues(t, strings.TrimLeft(dbLabel.Color, "#"), apiLabel.Color)
|
||||||
|
|
||||||
|
|
|
@ -10,8 +10,8 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/convert"
|
"code.gitea.io/gitea/modules/convert"
|
||||||
|
@ -23,7 +23,7 @@ import (
|
||||||
func TestAPIIssuesReactions(t *testing.T) {
|
func TestAPIIssuesReactions(t *testing.T) {
|
||||||
defer prepareTestEnv(t)()
|
defer prepareTestEnv(t)()
|
||||||
|
|
||||||
issue := unittest.AssertExistsAndLoadBean(t, &models.Issue{ID: 1}).(*models.Issue)
|
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1}).(*issues_model.Issue)
|
||||||
_ = issue.LoadRepo(db.DefaultContext)
|
_ = issue.LoadRepo(db.DefaultContext)
|
||||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: issue.Repo.OwnerID}).(*user_model.User)
|
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: issue.Repo.OwnerID}).(*user_model.User)
|
||||||
|
|
||||||
|
@ -80,7 +80,7 @@ func TestAPIIssuesReactions(t *testing.T) {
|
||||||
func TestAPICommentReactions(t *testing.T) {
|
func TestAPICommentReactions(t *testing.T) {
|
||||||
defer prepareTestEnv(t)()
|
defer prepareTestEnv(t)()
|
||||||
|
|
||||||
comment := unittest.AssertExistsAndLoadBean(t, &models.Comment{ID: 2}).(*models.Comment)
|
comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: 2}).(*issues_model.Comment)
|
||||||
_ = comment.LoadIssue()
|
_ = comment.LoadIssue()
|
||||||
issue := comment.Issue
|
issue := comment.Issue
|
||||||
_ = issue.LoadRepo(db.DefaultContext)
|
_ = issue.LoadRepo(db.DefaultContext)
|
||||||
|
|
|
@ -8,8 +8,8 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
@ -30,8 +30,8 @@ func TestAPIListStopWatches(t *testing.T) {
|
||||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||||
var apiWatches []*api.StopWatch
|
var apiWatches []*api.StopWatch
|
||||||
DecodeJSON(t, resp, &apiWatches)
|
DecodeJSON(t, resp, &apiWatches)
|
||||||
stopwatch := unittest.AssertExistsAndLoadBean(t, &models.Stopwatch{UserID: owner.ID}).(*models.Stopwatch)
|
stopwatch := unittest.AssertExistsAndLoadBean(t, &issues_model.Stopwatch{UserID: owner.ID}).(*issues_model.Stopwatch)
|
||||||
issue := unittest.AssertExistsAndLoadBean(t, &models.Issue{ID: stopwatch.IssueID}).(*models.Issue)
|
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: stopwatch.IssueID}).(*issues_model.Issue)
|
||||||
if assert.Len(t, apiWatches, 1) {
|
if assert.Len(t, apiWatches, 1) {
|
||||||
assert.EqualValues(t, stopwatch.CreatedUnix.AsTime().Unix(), apiWatches[0].Created.Unix())
|
assert.EqualValues(t, stopwatch.CreatedUnix.AsTime().Unix(), apiWatches[0].Created.Unix())
|
||||||
assert.EqualValues(t, issue.Index, apiWatches[0].IssueIndex)
|
assert.EqualValues(t, issue.Index, apiWatches[0].IssueIndex)
|
||||||
|
@ -45,7 +45,7 @@ func TestAPIListStopWatches(t *testing.T) {
|
||||||
func TestAPIStopStopWatches(t *testing.T) {
|
func TestAPIStopStopWatches(t *testing.T) {
|
||||||
defer prepareTestEnv(t)()
|
defer prepareTestEnv(t)()
|
||||||
|
|
||||||
issue := unittest.AssertExistsAndLoadBean(t, &models.Issue{ID: 2}).(*models.Issue)
|
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2}).(*issues_model.Issue)
|
||||||
_ = issue.LoadRepo(db.DefaultContext)
|
_ = issue.LoadRepo(db.DefaultContext)
|
||||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: issue.Repo.OwnerID}).(*user_model.User)
|
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: issue.Repo.OwnerID}).(*user_model.User)
|
||||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
|
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
|
||||||
|
@ -61,7 +61,7 @@ func TestAPIStopStopWatches(t *testing.T) {
|
||||||
func TestAPICancelStopWatches(t *testing.T) {
|
func TestAPICancelStopWatches(t *testing.T) {
|
||||||
defer prepareTestEnv(t)()
|
defer prepareTestEnv(t)()
|
||||||
|
|
||||||
issue := unittest.AssertExistsAndLoadBean(t, &models.Issue{ID: 1}).(*models.Issue)
|
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1}).(*issues_model.Issue)
|
||||||
_ = issue.LoadRepo(db.DefaultContext)
|
_ = issue.LoadRepo(db.DefaultContext)
|
||||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: issue.Repo.OwnerID}).(*user_model.User)
|
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: issue.Repo.OwnerID}).(*user_model.User)
|
||||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User)
|
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User)
|
||||||
|
@ -77,7 +77,7 @@ func TestAPICancelStopWatches(t *testing.T) {
|
||||||
func TestAPIStartStopWatches(t *testing.T) {
|
func TestAPIStartStopWatches(t *testing.T) {
|
||||||
defer prepareTestEnv(t)()
|
defer prepareTestEnv(t)()
|
||||||
|
|
||||||
issue := unittest.AssertExistsAndLoadBean(t, &models.Issue{ID: 3}).(*models.Issue)
|
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 3}).(*issues_model.Issue)
|
||||||
_ = issue.LoadRepo(db.DefaultContext)
|
_ = issue.LoadRepo(db.DefaultContext)
|
||||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: issue.Repo.OwnerID}).(*user_model.User)
|
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: issue.Repo.OwnerID}).(*user_model.User)
|
||||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
|
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
|
||||||
|
|
|
@ -9,7 +9,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
@ -21,18 +21,18 @@ import (
|
||||||
func TestAPIIssueSubscriptions(t *testing.T) {
|
func TestAPIIssueSubscriptions(t *testing.T) {
|
||||||
defer prepareTestEnv(t)()
|
defer prepareTestEnv(t)()
|
||||||
|
|
||||||
issue1 := unittest.AssertExistsAndLoadBean(t, &models.Issue{ID: 1}).(*models.Issue)
|
issue1 := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1}).(*issues_model.Issue)
|
||||||
issue2 := unittest.AssertExistsAndLoadBean(t, &models.Issue{ID: 2}).(*models.Issue)
|
issue2 := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2}).(*issues_model.Issue)
|
||||||
issue3 := unittest.AssertExistsAndLoadBean(t, &models.Issue{ID: 3}).(*models.Issue)
|
issue3 := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 3}).(*issues_model.Issue)
|
||||||
issue4 := unittest.AssertExistsAndLoadBean(t, &models.Issue{ID: 4}).(*models.Issue)
|
issue4 := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 4}).(*issues_model.Issue)
|
||||||
issue5 := unittest.AssertExistsAndLoadBean(t, &models.Issue{ID: 8}).(*models.Issue)
|
issue5 := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 8}).(*issues_model.Issue)
|
||||||
|
|
||||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: issue1.PosterID}).(*user_model.User)
|
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: issue1.PosterID}).(*user_model.User)
|
||||||
|
|
||||||
session := loginUser(t, owner.Name)
|
session := loginUser(t, owner.Name)
|
||||||
token := getTokenForLoggedInUser(t, session)
|
token := getTokenForLoggedInUser(t, session)
|
||||||
|
|
||||||
testSubscription := func(issue *models.Issue, isWatching bool) {
|
testSubscription := func(issue *issues_model.Issue, isWatching bool) {
|
||||||
issueRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID}).(*repo_model.Repository)
|
issueRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID}).(*repo_model.Repository)
|
||||||
|
|
||||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d/subscriptions/check?token=%s", issueRepo.OwnerName, issueRepo.Name, issue.Index, token)
|
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d/subscriptions/check?token=%s", issueRepo.OwnerName, issueRepo.Name, issue.Index, token)
|
||||||
|
|
|
@ -11,7 +11,8 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
"code.gitea.io/gitea/models/db"
|
||||||
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
@ -34,9 +35,9 @@ func TestAPIListIssues(t *testing.T) {
|
||||||
resp := session.MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK)
|
resp := session.MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK)
|
||||||
var apiIssues []*api.Issue
|
var apiIssues []*api.Issue
|
||||||
DecodeJSON(t, resp, &apiIssues)
|
DecodeJSON(t, resp, &apiIssues)
|
||||||
assert.Len(t, apiIssues, unittest.GetCount(t, &models.Issue{RepoID: repo.ID}))
|
assert.Len(t, apiIssues, unittest.GetCount(t, &issues_model.Issue{RepoID: repo.ID}))
|
||||||
for _, apiIssue := range apiIssues {
|
for _, apiIssue := range apiIssues {
|
||||||
unittest.AssertExistsAndLoadBean(t, &models.Issue{ID: apiIssue.ID, RepoID: repo.ID})
|
unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: apiIssue.ID, RepoID: repo.ID})
|
||||||
}
|
}
|
||||||
|
|
||||||
// test milestone filter
|
// test milestone filter
|
||||||
|
@ -91,7 +92,7 @@ func TestAPICreateIssue(t *testing.T) {
|
||||||
assert.Equal(t, body, apiIssue.Body)
|
assert.Equal(t, body, apiIssue.Body)
|
||||||
assert.Equal(t, title, apiIssue.Title)
|
assert.Equal(t, title, apiIssue.Title)
|
||||||
|
|
||||||
unittest.AssertExistsAndLoadBean(t, &models.Issue{
|
unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{
|
||||||
RepoID: repoBefore.ID,
|
RepoID: repoBefore.ID,
|
||||||
AssigneeID: owner.ID,
|
AssigneeID: owner.ID,
|
||||||
Content: body,
|
Content: body,
|
||||||
|
@ -106,10 +107,10 @@ func TestAPICreateIssue(t *testing.T) {
|
||||||
func TestAPIEditIssue(t *testing.T) {
|
func TestAPIEditIssue(t *testing.T) {
|
||||||
defer prepareTestEnv(t)()
|
defer prepareTestEnv(t)()
|
||||||
|
|
||||||
issueBefore := unittest.AssertExistsAndLoadBean(t, &models.Issue{ID: 10}).(*models.Issue)
|
issueBefore := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 10}).(*issues_model.Issue)
|
||||||
repoBefore := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issueBefore.RepoID}).(*repo_model.Repository)
|
repoBefore := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issueBefore.RepoID}).(*repo_model.Repository)
|
||||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repoBefore.OwnerID}).(*user_model.User)
|
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repoBefore.OwnerID}).(*user_model.User)
|
||||||
assert.NoError(t, issueBefore.LoadAttributes())
|
assert.NoError(t, issueBefore.LoadAttributes(db.DefaultContext))
|
||||||
assert.Equal(t, int64(1019307200), int64(issueBefore.DeadlineUnix))
|
assert.Equal(t, int64(1019307200), int64(issueBefore.DeadlineUnix))
|
||||||
assert.Equal(t, api.StateOpen, issueBefore.State())
|
assert.Equal(t, api.StateOpen, issueBefore.State())
|
||||||
|
|
||||||
|
@ -137,12 +138,12 @@ func TestAPIEditIssue(t *testing.T) {
|
||||||
var apiIssue api.Issue
|
var apiIssue api.Issue
|
||||||
DecodeJSON(t, resp, &apiIssue)
|
DecodeJSON(t, resp, &apiIssue)
|
||||||
|
|
||||||
issueAfter := unittest.AssertExistsAndLoadBean(t, &models.Issue{ID: 10}).(*models.Issue)
|
issueAfter := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 10}).(*issues_model.Issue)
|
||||||
repoAfter := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issueBefore.RepoID}).(*repo_model.Repository)
|
repoAfter := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issueBefore.RepoID}).(*repo_model.Repository)
|
||||||
|
|
||||||
// check deleted user
|
// check deleted user
|
||||||
assert.Equal(t, int64(500), issueAfter.PosterID)
|
assert.Equal(t, int64(500), issueAfter.PosterID)
|
||||||
assert.NoError(t, issueAfter.LoadAttributes())
|
assert.NoError(t, issueAfter.LoadAttributes(db.DefaultContext))
|
||||||
assert.Equal(t, int64(-1), issueAfter.PosterID)
|
assert.Equal(t, int64(-1), issueAfter.PosterID)
|
||||||
assert.Equal(t, int64(-1), issueBefore.PosterID)
|
assert.Equal(t, int64(-1), issueBefore.PosterID)
|
||||||
assert.Equal(t, int64(-1), apiIssue.Poster.ID)
|
assert.Equal(t, int64(-1), apiIssue.Poster.ID)
|
||||||
|
|
|
@ -10,8 +10,8 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
|
@ -23,7 +23,7 @@ func TestAPIGetTrackedTimes(t *testing.T) {
|
||||||
defer prepareTestEnv(t)()
|
defer prepareTestEnv(t)()
|
||||||
|
|
||||||
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
|
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
|
||||||
issue2 := unittest.AssertExistsAndLoadBean(t, &models.Issue{ID: 2}).(*models.Issue)
|
issue2 := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2}).(*issues_model.Issue)
|
||||||
assert.NoError(t, issue2.LoadRepo(db.DefaultContext))
|
assert.NoError(t, issue2.LoadRepo(db.DefaultContext))
|
||||||
|
|
||||||
session := loginUser(t, user2.Name)
|
session := loginUser(t, user2.Name)
|
||||||
|
@ -33,7 +33,7 @@ func TestAPIGetTrackedTimes(t *testing.T) {
|
||||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||||
var apiTimes api.TrackedTimeList
|
var apiTimes api.TrackedTimeList
|
||||||
DecodeJSON(t, resp, &apiTimes)
|
DecodeJSON(t, resp, &apiTimes)
|
||||||
expect, err := models.GetTrackedTimes(db.DefaultContext, &models.FindTrackedTimesOptions{IssueID: issue2.ID})
|
expect, err := issues_model.GetTrackedTimes(db.DefaultContext, &issues_model.FindTrackedTimesOptions{IssueID: issue2.ID})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Len(t, apiTimes, 3)
|
assert.Len(t, apiTimes, 3)
|
||||||
|
|
||||||
|
@ -64,8 +64,8 @@ func TestAPIGetTrackedTimes(t *testing.T) {
|
||||||
func TestAPIDeleteTrackedTime(t *testing.T) {
|
func TestAPIDeleteTrackedTime(t *testing.T) {
|
||||||
defer prepareTestEnv(t)()
|
defer prepareTestEnv(t)()
|
||||||
|
|
||||||
time6 := unittest.AssertExistsAndLoadBean(t, &models.TrackedTime{ID: 6}).(*models.TrackedTime)
|
time6 := unittest.AssertExistsAndLoadBean(t, &issues_model.TrackedTime{ID: 6}).(*issues_model.TrackedTime)
|
||||||
issue2 := unittest.AssertExistsAndLoadBean(t, &models.Issue{ID: 2}).(*models.Issue)
|
issue2 := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2}).(*issues_model.Issue)
|
||||||
assert.NoError(t, issue2.LoadRepo(db.DefaultContext))
|
assert.NoError(t, issue2.LoadRepo(db.DefaultContext))
|
||||||
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
|
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
|
||||||
|
|
||||||
|
@ -76,14 +76,14 @@ func TestAPIDeleteTrackedTime(t *testing.T) {
|
||||||
req := NewRequestf(t, "DELETE", "/api/v1/repos/%s/%s/issues/%d/times/%d?token=%s", user2.Name, issue2.Repo.Name, issue2.Index, time6.ID, token)
|
req := NewRequestf(t, "DELETE", "/api/v1/repos/%s/%s/issues/%d/times/%d?token=%s", user2.Name, issue2.Repo.Name, issue2.Index, time6.ID, token)
|
||||||
session.MakeRequest(t, req, http.StatusForbidden)
|
session.MakeRequest(t, req, http.StatusForbidden)
|
||||||
|
|
||||||
time3 := unittest.AssertExistsAndLoadBean(t, &models.TrackedTime{ID: 3}).(*models.TrackedTime)
|
time3 := unittest.AssertExistsAndLoadBean(t, &issues_model.TrackedTime{ID: 3}).(*issues_model.TrackedTime)
|
||||||
req = NewRequestf(t, "DELETE", "/api/v1/repos/%s/%s/issues/%d/times/%d?token=%s", user2.Name, issue2.Repo.Name, issue2.Index, time3.ID, token)
|
req = NewRequestf(t, "DELETE", "/api/v1/repos/%s/%s/issues/%d/times/%d?token=%s", user2.Name, issue2.Repo.Name, issue2.Index, time3.ID, token)
|
||||||
session.MakeRequest(t, req, http.StatusNoContent)
|
session.MakeRequest(t, req, http.StatusNoContent)
|
||||||
// Delete non existing time
|
// Delete non existing time
|
||||||
session.MakeRequest(t, req, http.StatusNotFound)
|
session.MakeRequest(t, req, http.StatusNotFound)
|
||||||
|
|
||||||
// Reset time of user 2 on issue 2
|
// Reset time of user 2 on issue 2
|
||||||
trackedSeconds, err := models.GetTrackedSeconds(db.DefaultContext, models.FindTrackedTimesOptions{IssueID: 2, UserID: 2})
|
trackedSeconds, err := issues_model.GetTrackedSeconds(db.DefaultContext, issues_model.FindTrackedTimesOptions{IssueID: 2, UserID: 2})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, int64(3661), trackedSeconds)
|
assert.Equal(t, int64(3661), trackedSeconds)
|
||||||
|
|
||||||
|
@ -91,7 +91,7 @@ func TestAPIDeleteTrackedTime(t *testing.T) {
|
||||||
session.MakeRequest(t, req, http.StatusNoContent)
|
session.MakeRequest(t, req, http.StatusNoContent)
|
||||||
session.MakeRequest(t, req, http.StatusNotFound)
|
session.MakeRequest(t, req, http.StatusNotFound)
|
||||||
|
|
||||||
trackedSeconds, err = models.GetTrackedSeconds(db.DefaultContext, models.FindTrackedTimesOptions{IssueID: 2, UserID: 2})
|
trackedSeconds, err = issues_model.GetTrackedSeconds(db.DefaultContext, issues_model.FindTrackedTimesOptions{IssueID: 2, UserID: 2})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, int64(0), trackedSeconds)
|
assert.Equal(t, int64(0), trackedSeconds)
|
||||||
}
|
}
|
||||||
|
@ -99,7 +99,7 @@ func TestAPIDeleteTrackedTime(t *testing.T) {
|
||||||
func TestAPIAddTrackedTimes(t *testing.T) {
|
func TestAPIAddTrackedTimes(t *testing.T) {
|
||||||
defer prepareTestEnv(t)()
|
defer prepareTestEnv(t)()
|
||||||
|
|
||||||
issue2 := unittest.AssertExistsAndLoadBean(t, &models.Issue{ID: 2}).(*models.Issue)
|
issue2 := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2}).(*issues_model.Issue)
|
||||||
assert.NoError(t, issue2.LoadRepo(db.DefaultContext))
|
assert.NoError(t, issue2.LoadRepo(db.DefaultContext))
|
||||||
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
|
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
|
||||||
admin := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User)
|
admin := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User)
|
||||||
|
|
|
@ -8,7 +8,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
|
@ -18,7 +18,7 @@ import (
|
||||||
|
|
||||||
func TestAPIPullCommits(t *testing.T) {
|
func TestAPIPullCommits(t *testing.T) {
|
||||||
defer prepareTestEnv(t)()
|
defer prepareTestEnv(t)()
|
||||||
pullIssue := unittest.AssertExistsAndLoadBean(t, &models.PullRequest{ID: 2}).(*models.PullRequest)
|
pullIssue := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 2}).(*issues_model.PullRequest)
|
||||||
assert.NoError(t, pullIssue.LoadIssue())
|
assert.NoError(t, pullIssue.LoadIssue())
|
||||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: pullIssue.HeadRepoID}).(*repo_model.Repository)
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: pullIssue.HeadRepoID}).(*repo_model.Repository)
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,8 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
"code.gitea.io/gitea/models/db"
|
||||||
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
"code.gitea.io/gitea/modules/json"
|
"code.gitea.io/gitea/modules/json"
|
||||||
|
@ -20,8 +21,8 @@ import (
|
||||||
|
|
||||||
func TestAPIPullReview(t *testing.T) {
|
func TestAPIPullReview(t *testing.T) {
|
||||||
defer prepareTestEnv(t)()
|
defer prepareTestEnv(t)()
|
||||||
pullIssue := unittest.AssertExistsAndLoadBean(t, &models.Issue{ID: 3}).(*models.Issue)
|
pullIssue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 3}).(*issues_model.Issue)
|
||||||
assert.NoError(t, pullIssue.LoadAttributes())
|
assert.NoError(t, pullIssue.LoadAttributes(db.DefaultContext))
|
||||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: pullIssue.RepoID}).(*repo_model.Repository)
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: pullIssue.RepoID}).(*repo_model.Repository)
|
||||||
|
|
||||||
// test ListPullReviews
|
// test ListPullReviews
|
||||||
|
@ -64,7 +65,7 @@ func TestAPIPullReview(t *testing.T) {
|
||||||
assert.EqualValues(t, *reviews[5], review)
|
assert.EqualValues(t, *reviews[5], review)
|
||||||
|
|
||||||
// test GetPullReviewComments
|
// test GetPullReviewComments
|
||||||
comment := unittest.AssertExistsAndLoadBean(t, &models.Comment{ID: 7}).(*models.Comment)
|
comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: 7}).(*issues_model.Comment)
|
||||||
req = NewRequestf(t, http.MethodGet, "/api/v1/repos/%s/%s/pulls/%d/reviews/%d/comments?token=%s", repo.OwnerName, repo.Name, pullIssue.Index, 10, token)
|
req = NewRequestf(t, http.MethodGet, "/api/v1/repos/%s/%s/pulls/%d/reviews/%d/comments?token=%s", repo.OwnerName, repo.Name, pullIssue.Index, 10, token)
|
||||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||||
var reviewComments []*api.PullReviewComment
|
var reviewComments []*api.PullReviewComment
|
||||||
|
@ -199,8 +200,8 @@ func TestAPIPullReview(t *testing.T) {
|
||||||
|
|
||||||
// test get review requests
|
// test get review requests
|
||||||
// to make it simple, use same api with get review
|
// to make it simple, use same api with get review
|
||||||
pullIssue12 := unittest.AssertExistsAndLoadBean(t, &models.Issue{ID: 12}).(*models.Issue)
|
pullIssue12 := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 12}).(*issues_model.Issue)
|
||||||
assert.NoError(t, pullIssue12.LoadAttributes())
|
assert.NoError(t, pullIssue12.LoadAttributes(db.DefaultContext))
|
||||||
repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: pullIssue12.RepoID}).(*repo_model.Repository)
|
repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: pullIssue12.RepoID}).(*repo_model.Repository)
|
||||||
|
|
||||||
req = NewRequestf(t, http.MethodGet, "/api/v1/repos/%s/%s/pulls/%d/reviews?token=%s", repo3.OwnerName, repo3.Name, pullIssue12.Index, token)
|
req = NewRequestf(t, http.MethodGet, "/api/v1/repos/%s/%s/pulls/%d/reviews?token=%s", repo3.OwnerName, repo3.Name, pullIssue12.Index, token)
|
||||||
|
@ -223,8 +224,8 @@ func TestAPIPullReview(t *testing.T) {
|
||||||
|
|
||||||
func TestAPIPullReviewRequest(t *testing.T) {
|
func TestAPIPullReviewRequest(t *testing.T) {
|
||||||
defer prepareTestEnv(t)()
|
defer prepareTestEnv(t)()
|
||||||
pullIssue := unittest.AssertExistsAndLoadBean(t, &models.Issue{ID: 3}).(*models.Issue)
|
pullIssue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 3}).(*issues_model.Issue)
|
||||||
assert.NoError(t, pullIssue.LoadAttributes())
|
assert.NoError(t, pullIssue.LoadAttributes(db.DefaultContext))
|
||||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: pullIssue.RepoID}).(*repo_model.Repository)
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: pullIssue.RepoID}).(*repo_model.Repository)
|
||||||
|
|
||||||
// Test add Review Request
|
// Test add Review Request
|
||||||
|
@ -268,8 +269,8 @@ func TestAPIPullReviewRequest(t *testing.T) {
|
||||||
session.MakeRequest(t, req, http.StatusNoContent)
|
session.MakeRequest(t, req, http.StatusNoContent)
|
||||||
|
|
||||||
// Test team review request
|
// Test team review request
|
||||||
pullIssue12 := unittest.AssertExistsAndLoadBean(t, &models.Issue{ID: 12}).(*models.Issue)
|
pullIssue12 := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 12}).(*issues_model.Issue)
|
||||||
assert.NoError(t, pullIssue12.LoadAttributes())
|
assert.NoError(t, pullIssue12.LoadAttributes(db.DefaultContext))
|
||||||
repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: pullIssue12.RepoID}).(*repo_model.Repository)
|
repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: pullIssue12.RepoID}).(*repo_model.Repository)
|
||||||
|
|
||||||
// Test add Team Review Request
|
// Test add Team Review Request
|
||||||
|
|
|
@ -9,7 +9,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
@ -33,7 +33,7 @@ func TestAPIViewPulls(t *testing.T) {
|
||||||
|
|
||||||
var pulls []*api.PullRequest
|
var pulls []*api.PullRequest
|
||||||
DecodeJSON(t, resp, &pulls)
|
DecodeJSON(t, resp, &pulls)
|
||||||
expectedLen := unittest.GetCount(t, &models.Issue{RepoID: repo.ID}, unittest.Cond("is_pull = ?", true))
|
expectedLen := unittest.GetCount(t, &issues_model.Issue{RepoID: repo.ID}, unittest.Cond("is_pull = ?", true))
|
||||||
assert.Len(t, pulls, expectedLen)
|
assert.Len(t, pulls, expectedLen)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ func TestAPIMergePullWIP(t *testing.T) {
|
||||||
defer prepareTestEnv(t)()
|
defer prepareTestEnv(t)()
|
||||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository)
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository)
|
||||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User)
|
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User)
|
||||||
pr := unittest.AssertExistsAndLoadBean(t, &models.PullRequest{Status: models.PullRequestStatusMergeable}, unittest.Cond("has_merged = ?", false)).(*models.PullRequest)
|
pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{Status: issues_model.PullRequestStatusMergeable}, unittest.Cond("has_merged = ?", false)).(*issues_model.PullRequest)
|
||||||
pr.LoadIssue()
|
pr.LoadIssue()
|
||||||
issue_service.ChangeTitle(pr.Issue, owner, setting.Repository.PullRequest.WorkInProgressPrefixes[0]+" "+pr.Issue.Title)
|
issue_service.ChangeTitle(pr.Issue, owner, setting.Repository.PullRequest.WorkInProgressPrefixes[0]+" "+pr.Issue.Title)
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
"code.gitea.io/gitea/models/organization"
|
"code.gitea.io/gitea/models/organization"
|
||||||
access_model "code.gitea.io/gitea/models/perm/access"
|
access_model "code.gitea.io/gitea/models/perm/access"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
|
@ -24,7 +24,7 @@ func assertUserDeleted(t *testing.T, userID int64) {
|
||||||
unittest.AssertNotExistsBean(t, &repo_model.Repository{OwnerID: userID})
|
unittest.AssertNotExistsBean(t, &repo_model.Repository{OwnerID: userID})
|
||||||
unittest.AssertNotExistsBean(t, &access_model.Access{UserID: userID})
|
unittest.AssertNotExistsBean(t, &access_model.Access{UserID: userID})
|
||||||
unittest.AssertNotExistsBean(t, &organization.OrgUser{UID: userID})
|
unittest.AssertNotExistsBean(t, &organization.OrgUser{UID: userID})
|
||||||
unittest.AssertNotExistsBean(t, &models.IssueUser{UID: userID})
|
unittest.AssertNotExistsBean(t, &issues_model.IssueUser{UID: userID})
|
||||||
unittest.AssertNotExistsBean(t, &organization.TeamUser{UID: userID})
|
unittest.AssertNotExistsBean(t, &organization.TeamUser{UID: userID})
|
||||||
unittest.AssertNotExistsBean(t, &repo_model.Star{UID: userID})
|
unittest.AssertNotExistsBean(t, &repo_model.Star{UID: userID})
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,8 +17,8 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
"code.gitea.io/gitea/models/perm"
|
"code.gitea.io/gitea/models/perm"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
|
@ -715,7 +715,7 @@ func doCreateAgitFlowPull(dstPath string, ctx *APITestContext, baseBranch, headB
|
||||||
defer gitRepo.Close()
|
defer gitRepo.Close()
|
||||||
|
|
||||||
var (
|
var (
|
||||||
pr1, pr2 *models.PullRequest
|
pr1, pr2 *issues_model.PullRequest
|
||||||
commit string
|
commit string
|
||||||
)
|
)
|
||||||
repo, err := repo_model.GetRepositoryByOwnerAndName(ctx.Username, ctx.Reponame)
|
repo, err := repo_model.GetRepositoryByOwnerAndName(ctx.Username, ctx.Reponame)
|
||||||
|
@ -723,7 +723,7 @@ func doCreateAgitFlowPull(dstPath string, ctx *APITestContext, baseBranch, headB
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
pullNum := unittest.GetCount(t, &models.PullRequest{})
|
pullNum := unittest.GetCount(t, &issues_model.PullRequest{})
|
||||||
|
|
||||||
t.Run("CreateHeadBranch", doGitCreateBranch(dstPath, headBranch))
|
t.Run("CreateHeadBranch", doGitCreateBranch(dstPath, headBranch))
|
||||||
|
|
||||||
|
@ -759,11 +759,11 @@ func doCreateAgitFlowPull(dstPath string, ctx *APITestContext, baseBranch, headB
|
||||||
if !assert.NoError(t, err) {
|
if !assert.NoError(t, err) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
unittest.AssertCount(t, &models.PullRequest{}, pullNum+1)
|
unittest.AssertCount(t, &issues_model.PullRequest{}, pullNum+1)
|
||||||
pr1 = unittest.AssertExistsAndLoadBean(t, &models.PullRequest{
|
pr1 = unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{
|
||||||
HeadRepoID: repo.ID,
|
HeadRepoID: repo.ID,
|
||||||
Flow: models.PullRequestFlowAGit,
|
Flow: issues_model.PullRequestFlowAGit,
|
||||||
}).(*models.PullRequest)
|
}).(*issues_model.PullRequest)
|
||||||
if !assert.NotEmpty(t, pr1) {
|
if !assert.NotEmpty(t, pr1) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -780,12 +780,12 @@ func doCreateAgitFlowPull(dstPath string, ctx *APITestContext, baseBranch, headB
|
||||||
if !assert.NoError(t, err) {
|
if !assert.NoError(t, err) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
unittest.AssertCount(t, &models.PullRequest{}, pullNum+2)
|
unittest.AssertCount(t, &issues_model.PullRequest{}, pullNum+2)
|
||||||
pr2 = unittest.AssertExistsAndLoadBean(t, &models.PullRequest{
|
pr2 = unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{
|
||||||
HeadRepoID: repo.ID,
|
HeadRepoID: repo.ID,
|
||||||
Index: pr1.Index + 1,
|
Index: pr1.Index + 1,
|
||||||
Flow: models.PullRequestFlowAGit,
|
Flow: issues_model.PullRequestFlowAGit,
|
||||||
}).(*models.PullRequest)
|
}).(*issues_model.PullRequest)
|
||||||
if !assert.NotEmpty(t, pr2) {
|
if !assert.NotEmpty(t, pr2) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -833,7 +833,7 @@ func doCreateAgitFlowPull(dstPath string, ctx *APITestContext, baseBranch, headB
|
||||||
if !assert.NoError(t, err) {
|
if !assert.NoError(t, err) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
unittest.AssertCount(t, &models.PullRequest{}, pullNum+2)
|
unittest.AssertCount(t, &issues_model.PullRequest{}, pullNum+2)
|
||||||
prMsg, err := doAPIGetPullRequest(*ctx, ctx.Username, ctx.Reponame, pr1.Index)(t)
|
prMsg, err := doAPIGetPullRequest(*ctx, ctx.Username, ctx.Reponame, pr1.Index)(t)
|
||||||
if !assert.NoError(t, err) {
|
if !assert.NoError(t, err) {
|
||||||
return
|
return
|
||||||
|
@ -845,7 +845,7 @@ func doCreateAgitFlowPull(dstPath string, ctx *APITestContext, baseBranch, headB
|
||||||
if !assert.NoError(t, err) {
|
if !assert.NoError(t, err) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
unittest.AssertCount(t, &models.PullRequest{}, pullNum+2)
|
unittest.AssertCount(t, &issues_model.PullRequest{}, pullNum+2)
|
||||||
prMsg, err = doAPIGetPullRequest(*ctx, ctx.Username, ctx.Reponame, pr2.Index)(t)
|
prMsg, err = doAPIGetPullRequest(*ctx, ctx.Username, ctx.Reponame, pr2.Index)(t)
|
||||||
if !assert.NoError(t, err) {
|
if !assert.NoError(t, err) {
|
||||||
return
|
return
|
||||||
|
|
|
@ -14,7 +14,8 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
"code.gitea.io/gitea/models/db"
|
||||||
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
@ -34,16 +35,16 @@ func getIssuesSelection(t testing.TB, htmlDoc *HTMLDoc) *goquery.Selection {
|
||||||
return issueList.Find("li").Find(".title")
|
return issueList.Find("li").Find(".title")
|
||||||
}
|
}
|
||||||
|
|
||||||
func getIssue(t *testing.T, repoID int64, issueSelection *goquery.Selection) *models.Issue {
|
func getIssue(t *testing.T, repoID int64, issueSelection *goquery.Selection) *issues_model.Issue {
|
||||||
href, exists := issueSelection.Attr("href")
|
href, exists := issueSelection.Attr("href")
|
||||||
assert.True(t, exists)
|
assert.True(t, exists)
|
||||||
indexStr := href[strings.LastIndexByte(href, '/')+1:]
|
indexStr := href[strings.LastIndexByte(href, '/')+1:]
|
||||||
index, err := strconv.Atoi(indexStr)
|
index, err := strconv.Atoi(indexStr)
|
||||||
assert.NoError(t, err, "Invalid issue href: %s", href)
|
assert.NoError(t, err, "Invalid issue href: %s", href)
|
||||||
return unittest.AssertExistsAndLoadBean(t, &models.Issue{RepoID: repoID, Index: int64(index)}).(*models.Issue)
|
return unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{RepoID: repoID, Index: int64(index)}).(*issues_model.Issue)
|
||||||
}
|
}
|
||||||
|
|
||||||
func assertMatch(t testing.TB, issue *models.Issue, keyword string) {
|
func assertMatch(t testing.TB, issue *issues_model.Issue, keyword string) {
|
||||||
matches := strings.Contains(strings.ToLower(issue.Title), keyword) ||
|
matches := strings.Contains(strings.ToLower(issue.Title), keyword) ||
|
||||||
strings.Contains(strings.ToLower(issue.Content), keyword)
|
strings.Contains(strings.ToLower(issue.Content), keyword)
|
||||||
for _, comment := range issue.Comments {
|
for _, comment := range issue.Comments {
|
||||||
|
@ -75,7 +76,7 @@ func TestViewIssuesSortByType(t *testing.T) {
|
||||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||||
issuesSelection := getIssuesSelection(t, htmlDoc)
|
issuesSelection := getIssuesSelection(t, htmlDoc)
|
||||||
expectedNumIssues := unittest.GetCount(t,
|
expectedNumIssues := unittest.GetCount(t,
|
||||||
&models.Issue{RepoID: repo.ID, PosterID: user.ID},
|
&issues_model.Issue{RepoID: repo.ID, PosterID: user.ID},
|
||||||
unittest.Cond("is_closed=?", false),
|
unittest.Cond("is_closed=?", false),
|
||||||
unittest.Cond("is_pull=?", false),
|
unittest.Cond("is_pull=?", false),
|
||||||
)
|
)
|
||||||
|
@ -94,10 +95,10 @@ func TestViewIssuesKeyword(t *testing.T) {
|
||||||
defer prepareTestEnv(t)()
|
defer prepareTestEnv(t)()
|
||||||
|
|
||||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository)
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository)
|
||||||
issue := unittest.AssertExistsAndLoadBean(t, &models.Issue{
|
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{
|
||||||
RepoID: repo.ID,
|
RepoID: repo.ID,
|
||||||
Index: 1,
|
Index: 1,
|
||||||
}).(*models.Issue)
|
}).(*issues_model.Issue)
|
||||||
issues.UpdateIssueIndexer(issue)
|
issues.UpdateIssueIndexer(issue)
|
||||||
time.Sleep(time.Second * 1)
|
time.Sleep(time.Second * 1)
|
||||||
const keyword = "first"
|
const keyword = "first"
|
||||||
|
@ -238,7 +239,7 @@ func TestIssueCrossReference(t *testing.T) {
|
||||||
|
|
||||||
// Ref from issue title
|
// Ref from issue title
|
||||||
issueRefURL, issueRef := testIssueWithBean(t, "user2", 1, fmt.Sprintf("Title ref #%d", issueBase.Index), "Description")
|
issueRefURL, issueRef := testIssueWithBean(t, "user2", 1, fmt.Sprintf("Title ref #%d", issueBase.Index), "Description")
|
||||||
unittest.AssertExistsAndLoadBean(t, &models.Comment{
|
unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{
|
||||||
IssueID: issueBase.ID,
|
IssueID: issueBase.ID,
|
||||||
RefRepoID: 1,
|
RefRepoID: 1,
|
||||||
RefIssueID: issueRef.ID,
|
RefIssueID: issueRef.ID,
|
||||||
|
@ -249,7 +250,7 @@ func TestIssueCrossReference(t *testing.T) {
|
||||||
|
|
||||||
// Edit title, neuter ref
|
// Edit title, neuter ref
|
||||||
testIssueChangeInfo(t, "user2", issueRefURL, "title", "Title no ref")
|
testIssueChangeInfo(t, "user2", issueRefURL, "title", "Title no ref")
|
||||||
unittest.AssertExistsAndLoadBean(t, &models.Comment{
|
unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{
|
||||||
IssueID: issueBase.ID,
|
IssueID: issueBase.ID,
|
||||||
RefRepoID: 1,
|
RefRepoID: 1,
|
||||||
RefIssueID: issueRef.ID,
|
RefIssueID: issueRef.ID,
|
||||||
|
@ -260,7 +261,7 @@ func TestIssueCrossReference(t *testing.T) {
|
||||||
|
|
||||||
// Ref from issue content
|
// Ref from issue content
|
||||||
issueRefURL, issueRef = testIssueWithBean(t, "user2", 1, "TitleXRef", fmt.Sprintf("Description ref #%d", issueBase.Index))
|
issueRefURL, issueRef = testIssueWithBean(t, "user2", 1, "TitleXRef", fmt.Sprintf("Description ref #%d", issueBase.Index))
|
||||||
unittest.AssertExistsAndLoadBean(t, &models.Comment{
|
unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{
|
||||||
IssueID: issueBase.ID,
|
IssueID: issueBase.ID,
|
||||||
RefRepoID: 1,
|
RefRepoID: 1,
|
||||||
RefIssueID: issueRef.ID,
|
RefIssueID: issueRef.ID,
|
||||||
|
@ -271,7 +272,7 @@ func TestIssueCrossReference(t *testing.T) {
|
||||||
|
|
||||||
// Edit content, neuter ref
|
// Edit content, neuter ref
|
||||||
testIssueChangeInfo(t, "user2", issueRefURL, "content", "Description no ref")
|
testIssueChangeInfo(t, "user2", issueRefURL, "content", "Description no ref")
|
||||||
unittest.AssertExistsAndLoadBean(t, &models.Comment{
|
unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{
|
||||||
IssueID: issueBase.ID,
|
IssueID: issueBase.ID,
|
||||||
RefRepoID: 1,
|
RefRepoID: 1,
|
||||||
RefIssueID: issueRef.ID,
|
RefIssueID: issueRef.ID,
|
||||||
|
@ -283,7 +284,7 @@ func TestIssueCrossReference(t *testing.T) {
|
||||||
// Ref from a comment
|
// Ref from a comment
|
||||||
session := loginUser(t, "user2")
|
session := loginUser(t, "user2")
|
||||||
commentID := testIssueAddComment(t, session, issueRefURL, fmt.Sprintf("Adding ref from comment #%d", issueBase.Index), "")
|
commentID := testIssueAddComment(t, session, issueRefURL, fmt.Sprintf("Adding ref from comment #%d", issueBase.Index), "")
|
||||||
comment := &models.Comment{
|
comment := &issues_model.Comment{
|
||||||
IssueID: issueBase.ID,
|
IssueID: issueBase.ID,
|
||||||
RefRepoID: 1,
|
RefRepoID: 1,
|
||||||
RefIssueID: issueRef.ID,
|
RefIssueID: issueRef.ID,
|
||||||
|
@ -295,7 +296,7 @@ func TestIssueCrossReference(t *testing.T) {
|
||||||
|
|
||||||
// Ref from a different repository
|
// Ref from a different repository
|
||||||
_, issueRef = testIssueWithBean(t, "user12", 10, "TitleXRef", fmt.Sprintf("Description ref user2/repo1#%d", issueBase.Index))
|
_, issueRef = testIssueWithBean(t, "user12", 10, "TitleXRef", fmt.Sprintf("Description ref user2/repo1#%d", issueBase.Index))
|
||||||
unittest.AssertExistsAndLoadBean(t, &models.Comment{
|
unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{
|
||||||
IssueID: issueBase.ID,
|
IssueID: issueBase.ID,
|
||||||
RefRepoID: 10,
|
RefRepoID: 10,
|
||||||
RefIssueID: issueRef.ID,
|
RefIssueID: issueRef.ID,
|
||||||
|
@ -305,13 +306,13 @@ func TestIssueCrossReference(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func testIssueWithBean(t *testing.T, user string, repoID int64, title, content string) (string, *models.Issue) {
|
func testIssueWithBean(t *testing.T, user string, repoID int64, title, content string) (string, *issues_model.Issue) {
|
||||||
session := loginUser(t, user)
|
session := loginUser(t, user)
|
||||||
issueURL := testNewIssue(t, session, user, fmt.Sprintf("repo%d", repoID), title, content)
|
issueURL := testNewIssue(t, session, user, fmt.Sprintf("repo%d", repoID), title, content)
|
||||||
indexStr := issueURL[strings.LastIndexByte(issueURL, '/')+1:]
|
indexStr := issueURL[strings.LastIndexByte(issueURL, '/')+1:]
|
||||||
index, err := strconv.Atoi(indexStr)
|
index, err := strconv.Atoi(indexStr)
|
||||||
assert.NoError(t, err, "Invalid issue href: %s", issueURL)
|
assert.NoError(t, err, "Invalid issue href: %s", issueURL)
|
||||||
issue := &models.Issue{RepoID: repoID, Index: int64(index)}
|
issue := &issues_model.Issue{RepoID: repoID, Index: int64(index)}
|
||||||
unittest.AssertExistsAndLoadBean(t, issue)
|
unittest.AssertExistsAndLoadBean(t, issue)
|
||||||
return issueURL, issue
|
return issueURL, issue
|
||||||
}
|
}
|
||||||
|
@ -511,10 +512,10 @@ func TestSearchIssuesWithLabels(t *testing.T) {
|
||||||
func TestGetIssueInfo(t *testing.T) {
|
func TestGetIssueInfo(t *testing.T) {
|
||||||
defer prepareTestEnv(t)()
|
defer prepareTestEnv(t)()
|
||||||
|
|
||||||
issue := unittest.AssertExistsAndLoadBean(t, &models.Issue{ID: 10}).(*models.Issue)
|
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 10}).(*issues_model.Issue)
|
||||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID}).(*repo_model.Repository)
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID}).(*repo_model.Repository)
|
||||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User)
|
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User)
|
||||||
assert.NoError(t, issue.LoadAttributes())
|
assert.NoError(t, issue.LoadAttributes(db.DefaultContext))
|
||||||
assert.Equal(t, int64(1019307200), int64(issue.DeadlineUnix))
|
assert.Equal(t, int64(1019307200), int64(issue.DeadlineUnix))
|
||||||
assert.Equal(t, api.StateOpen, issue.State())
|
assert.Equal(t, api.StateOpen, issue.State())
|
||||||
|
|
||||||
|
@ -532,10 +533,10 @@ func TestGetIssueInfo(t *testing.T) {
|
||||||
func TestUpdateIssueDeadline(t *testing.T) {
|
func TestUpdateIssueDeadline(t *testing.T) {
|
||||||
defer prepareTestEnv(t)()
|
defer prepareTestEnv(t)()
|
||||||
|
|
||||||
issueBefore := unittest.AssertExistsAndLoadBean(t, &models.Issue{ID: 10}).(*models.Issue)
|
issueBefore := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 10}).(*issues_model.Issue)
|
||||||
repoBefore := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issueBefore.RepoID}).(*repo_model.Repository)
|
repoBefore := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issueBefore.RepoID}).(*repo_model.Repository)
|
||||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repoBefore.OwnerID}).(*user_model.User)
|
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repoBefore.OwnerID}).(*user_model.User)
|
||||||
assert.NoError(t, issueBefore.LoadAttributes())
|
assert.NoError(t, issueBefore.LoadAttributes(db.DefaultContext))
|
||||||
assert.Equal(t, int64(1019307200), int64(issueBefore.DeadlineUnix))
|
assert.Equal(t, int64(1019307200), int64(issueBefore.DeadlineUnix))
|
||||||
assert.Equal(t, api.StateOpen, issueBefore.State())
|
assert.Equal(t, api.StateOpen, issueBefore.State())
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ import (
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
"code.gitea.io/gitea/models"
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
@ -233,12 +234,12 @@ func TestCantMergeConflict(t *testing.T) {
|
||||||
Name: "repo1",
|
Name: "repo1",
|
||||||
}).(*repo_model.Repository)
|
}).(*repo_model.Repository)
|
||||||
|
|
||||||
pr := unittest.AssertExistsAndLoadBean(t, &models.PullRequest{
|
pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{
|
||||||
HeadRepoID: repo1.ID,
|
HeadRepoID: repo1.ID,
|
||||||
BaseRepoID: repo1.ID,
|
BaseRepoID: repo1.ID,
|
||||||
HeadBranch: "conflict",
|
HeadBranch: "conflict",
|
||||||
BaseBranch: "base",
|
BaseBranch: "base",
|
||||||
}).(*models.PullRequest)
|
}).(*issues_model.PullRequest)
|
||||||
|
|
||||||
gitRepo, err := git.OpenRepository(git.DefaultContext, repo_model.RepoPath(user1.Name, repo1.Name))
|
gitRepo, err := git.OpenRepository(git.DefaultContext, repo_model.RepoPath(user1.Name, repo1.Name))
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
@ -335,12 +336,12 @@ func TestCantMergeUnrelated(t *testing.T) {
|
||||||
// Now this PR could be marked conflict - or at least a race may occur - so drop down to pure code at this point...
|
// Now this PR could be marked conflict - or at least a race may occur - so drop down to pure code at this point...
|
||||||
gitRepo, err := git.OpenRepository(git.DefaultContext, path)
|
gitRepo, err := git.OpenRepository(git.DefaultContext, path)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
pr := unittest.AssertExistsAndLoadBean(t, &models.PullRequest{
|
pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{
|
||||||
HeadRepoID: repo1.ID,
|
HeadRepoID: repo1.ID,
|
||||||
BaseRepoID: repo1.ID,
|
BaseRepoID: repo1.ID,
|
||||||
HeadBranch: "unrelated",
|
HeadBranch: "unrelated",
|
||||||
BaseBranch: "base",
|
BaseBranch: "base",
|
||||||
}).(*models.PullRequest)
|
}).(*issues_model.PullRequest)
|
||||||
|
|
||||||
err = pull.Merge(context.Background(), pr, user1, gitRepo, repo_model.MergeStyleMerge, "", "UNRELATED")
|
err = pull.Merge(context.Background(), pr, user1, gitRepo, repo_model.MergeStyleMerge, "", "UNRELATED")
|
||||||
assert.Error(t, err, "Merge should return an error due to unrelated")
|
assert.Error(t, err, "Merge should return an error due to unrelated")
|
||||||
|
@ -387,7 +388,7 @@ func TestConflictChecking(t *testing.T) {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// create Pull to merge the important-secrets branch into main branch.
|
// create Pull to merge the important-secrets branch into main branch.
|
||||||
pullIssue := &models.Issue{
|
pullIssue := &issues_model.Issue{
|
||||||
RepoID: baseRepo.ID,
|
RepoID: baseRepo.ID,
|
||||||
Title: "PR with conflict!",
|
Title: "PR with conflict!",
|
||||||
PosterID: user.ID,
|
PosterID: user.ID,
|
||||||
|
@ -395,26 +396,26 @@ func TestConflictChecking(t *testing.T) {
|
||||||
IsPull: true,
|
IsPull: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
pullRequest := &models.PullRequest{
|
pullRequest := &issues_model.PullRequest{
|
||||||
HeadRepoID: baseRepo.ID,
|
HeadRepoID: baseRepo.ID,
|
||||||
BaseRepoID: baseRepo.ID,
|
BaseRepoID: baseRepo.ID,
|
||||||
HeadBranch: "important-secrets",
|
HeadBranch: "important-secrets",
|
||||||
BaseBranch: "main",
|
BaseBranch: "main",
|
||||||
HeadRepo: baseRepo,
|
HeadRepo: baseRepo,
|
||||||
BaseRepo: baseRepo,
|
BaseRepo: baseRepo,
|
||||||
Type: models.PullRequestGitea,
|
Type: issues_model.PullRequestGitea,
|
||||||
}
|
}
|
||||||
err = pull.NewPullRequest(git.DefaultContext, baseRepo, pullIssue, nil, nil, pullRequest, nil)
|
err = pull.NewPullRequest(git.DefaultContext, baseRepo, pullIssue, nil, nil, pullRequest, nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
issue := unittest.AssertExistsAndLoadBean(t, &models.Issue{Title: "PR with conflict!"}).(*models.Issue)
|
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{Title: "PR with conflict!"}).(*issues_model.Issue)
|
||||||
conflictingPR, err := models.GetPullRequestByIssueID(db.DefaultContext, issue.ID)
|
conflictingPR, err := issues_model.GetPullRequestByIssueID(db.DefaultContext, issue.ID)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// Ensure conflictedFiles is populated.
|
// Ensure conflictedFiles is populated.
|
||||||
assert.Equal(t, 1, len(conflictingPR.ConflictedFiles))
|
assert.Equal(t, 1, len(conflictingPR.ConflictedFiles))
|
||||||
// Check if status is correct.
|
// Check if status is correct.
|
||||||
assert.Equal(t, models.PullRequestStatusConflict, conflictingPR.Status)
|
assert.Equal(t, issues_model.PullRequestStatusConflict, conflictingPR.Status)
|
||||||
// Ensure that mergeable returns false
|
// Ensure that mergeable returns false
|
||||||
assert.False(t, conflictingPR.Mergeable())
|
assert.False(t, conflictingPR.Mergeable())
|
||||||
})
|
})
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
"code.gitea.io/gitea/models"
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
|
@ -78,7 +79,7 @@ func TestAPIPullUpdateByRebase(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func createOutdatedPR(t *testing.T, actor, forkOrg *user_model.User) *models.PullRequest {
|
func createOutdatedPR(t *testing.T, actor, forkOrg *user_model.User) *issues_model.PullRequest {
|
||||||
baseRepo, err := repo_service.CreateRepository(actor, actor, models.CreateRepoOptions{
|
baseRepo, err := repo_service.CreateRepository(actor, actor, models.CreateRepoOptions{
|
||||||
Name: "repo-pr-update",
|
Name: "repo-pr-update",
|
||||||
Description: "repo-tmp-pr-update description",
|
Description: "repo-tmp-pr-update description",
|
||||||
|
@ -146,27 +147,27 @@ func createOutdatedPR(t *testing.T, actor, forkOrg *user_model.User) *models.Pul
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// create Pull
|
// create Pull
|
||||||
pullIssue := &models.Issue{
|
pullIssue := &issues_model.Issue{
|
||||||
RepoID: baseRepo.ID,
|
RepoID: baseRepo.ID,
|
||||||
Title: "Test Pull -to-update-",
|
Title: "Test Pull -to-update-",
|
||||||
PosterID: actor.ID,
|
PosterID: actor.ID,
|
||||||
Poster: actor,
|
Poster: actor,
|
||||||
IsPull: true,
|
IsPull: true,
|
||||||
}
|
}
|
||||||
pullRequest := &models.PullRequest{
|
pullRequest := &issues_model.PullRequest{
|
||||||
HeadRepoID: headRepo.ID,
|
HeadRepoID: headRepo.ID,
|
||||||
BaseRepoID: baseRepo.ID,
|
BaseRepoID: baseRepo.ID,
|
||||||
HeadBranch: "newBranch",
|
HeadBranch: "newBranch",
|
||||||
BaseBranch: "master",
|
BaseBranch: "master",
|
||||||
HeadRepo: headRepo,
|
HeadRepo: headRepo,
|
||||||
BaseRepo: baseRepo,
|
BaseRepo: baseRepo,
|
||||||
Type: models.PullRequestGitea,
|
Type: issues_model.PullRequestGitea,
|
||||||
}
|
}
|
||||||
err = pull_service.NewPullRequest(git.DefaultContext, baseRepo, pullIssue, nil, nil, pullRequest, nil)
|
err = pull_service.NewPullRequest(git.DefaultContext, baseRepo, pullIssue, nil, nil, pullRequest, nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
issue := unittest.AssertExistsAndLoadBean(t, &models.Issue{Title: "Test Pull -to-update-"}).(*models.Issue)
|
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{Title: "Test Pull -to-update-"}).(*issues_model.Issue)
|
||||||
pr, err := models.GetPullRequestByIssueID(db.DefaultContext, issue.ID)
|
pr, err := issues_model.GetPullRequestByIssueID(db.DefaultContext, issue.ID)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
return pr
|
return pr
|
||||||
|
|
|
@ -8,7 +8,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
@ -237,8 +237,8 @@ func TestListStopWatches(t *testing.T) {
|
||||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||||
var apiWatches []*api.StopWatch
|
var apiWatches []*api.StopWatch
|
||||||
DecodeJSON(t, resp, &apiWatches)
|
DecodeJSON(t, resp, &apiWatches)
|
||||||
stopwatch := unittest.AssertExistsAndLoadBean(t, &models.Stopwatch{UserID: owner.ID}).(*models.Stopwatch)
|
stopwatch := unittest.AssertExistsAndLoadBean(t, &issues_model.Stopwatch{UserID: owner.ID}).(*issues_model.Stopwatch)
|
||||||
issue := unittest.AssertExistsAndLoadBean(t, &models.Issue{ID: stopwatch.IssueID}).(*models.Issue)
|
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: stopwatch.IssueID}).(*issues_model.Issue)
|
||||||
if assert.Len(t, apiWatches, 1) {
|
if assert.Len(t, apiWatches, 1) {
|
||||||
assert.EqualValues(t, stopwatch.CreatedUnix.AsTime().Unix(), apiWatches[0].Created.Unix())
|
assert.EqualValues(t, stopwatch.CreatedUnix.AsTime().Unix(), apiWatches[0].Created.Unix())
|
||||||
assert.EqualValues(t, issue.Index, apiWatches[0].IssueIndex)
|
assert.EqualValues(t, issue.Index, apiWatches[0].IssueIndex)
|
||||||
|
|
|
@ -15,6 +15,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
"code.gitea.io/gitea/models/organization"
|
"code.gitea.io/gitea/models/organization"
|
||||||
access_model "code.gitea.io/gitea/models/perm/access"
|
access_model "code.gitea.io/gitea/models/perm/access"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
|
@ -76,7 +77,7 @@ type Action struct {
|
||||||
RepoID int64 `xorm:"INDEX"`
|
RepoID int64 `xorm:"INDEX"`
|
||||||
Repo *repo_model.Repository `xorm:"-"`
|
Repo *repo_model.Repository `xorm:"-"`
|
||||||
CommentID int64 `xorm:"INDEX"`
|
CommentID int64 `xorm:"INDEX"`
|
||||||
Comment *Comment `xorm:"-"`
|
Comment *issues_model.Comment `xorm:"-"`
|
||||||
IsDeleted bool `xorm:"INDEX NOT NULL DEFAULT false"`
|
IsDeleted bool `xorm:"INDEX NOT NULL DEFAULT false"`
|
||||||
RefName string
|
RefName string
|
||||||
IsPrivate bool `xorm:"INDEX NOT NULL DEFAULT false"`
|
IsPrivate bool `xorm:"INDEX NOT NULL DEFAULT false"`
|
||||||
|
@ -223,7 +224,7 @@ func (a *Action) getCommentLink(ctx context.Context) string {
|
||||||
return "#"
|
return "#"
|
||||||
}
|
}
|
||||||
if a.Comment == nil && a.CommentID != 0 {
|
if a.Comment == nil && a.CommentID != 0 {
|
||||||
a.Comment, _ = GetCommentByID(ctx, a.CommentID)
|
a.Comment, _ = issues_model.GetCommentByID(ctx, a.CommentID)
|
||||||
}
|
}
|
||||||
if a.Comment != nil {
|
if a.Comment != nil {
|
||||||
return a.Comment.HTMLURL()
|
return a.Comment.HTMLURL()
|
||||||
|
@ -238,7 +239,7 @@ func (a *Action) getCommentLink(ctx context.Context) string {
|
||||||
return "#"
|
return "#"
|
||||||
}
|
}
|
||||||
|
|
||||||
issue, err := getIssueByID(ctx, issueID)
|
issue, err := issues_model.GetIssueByID(ctx, issueID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "#"
|
return "#"
|
||||||
}
|
}
|
||||||
|
@ -295,7 +296,7 @@ func (a *Action) GetIssueInfos() []string {
|
||||||
// with the action.
|
// with the action.
|
||||||
func (a *Action) GetIssueTitle() string {
|
func (a *Action) GetIssueTitle() string {
|
||||||
index, _ := strconv.ParseInt(a.GetIssueInfos()[0], 10, 64)
|
index, _ := strconv.ParseInt(a.GetIssueInfos()[0], 10, 64)
|
||||||
issue, err := GetIssueByIndex(a.RepoID, index)
|
issue, err := issues_model.GetIssueByIndex(a.RepoID, index)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("GetIssueByIndex: %v", err)
|
log.Error("GetIssueByIndex: %v", err)
|
||||||
return "500 when get issue"
|
return "500 when get issue"
|
||||||
|
@ -307,7 +308,7 @@ func (a *Action) GetIssueTitle() string {
|
||||||
// this action.
|
// this action.
|
||||||
func (a *Action) GetIssueContent() string {
|
func (a *Action) GetIssueContent() string {
|
||||||
index, _ := strconv.ParseInt(a.GetIssueInfos()[0], 10, 64)
|
index, _ := strconv.ParseInt(a.GetIssueInfos()[0], 10, 64)
|
||||||
issue, err := GetIssueByIndex(a.RepoID, index)
|
issue, err := issues_model.GetIssueByIndex(a.RepoID, index)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("GetIssueByIndex: %v", err)
|
log.Error("GetIssueByIndex: %v", err)
|
||||||
return "500 when get issue"
|
return "500 when get issue"
|
||||||
|
@ -572,3 +573,20 @@ func NotifyWatchersActions(acts []*Action) error {
|
||||||
}
|
}
|
||||||
return committer.Commit()
|
return committer.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeleteIssueActions delete all actions related with issueID
|
||||||
|
func DeleteIssueActions(ctx context.Context, repoID, issueID int64) error {
|
||||||
|
// delete actions assigned to this issue
|
||||||
|
subQuery := builder.Select("`id`").
|
||||||
|
From("`comment`").
|
||||||
|
Where(builder.Eq{"`issue_id`": issueID})
|
||||||
|
if _, err := db.GetEngine(ctx).In("comment_id", subQuery).Delete(&Action{}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := db.GetEngine(ctx).Table("action").Where("repo_id = ?", repoID).
|
||||||
|
In("op_type", ActionCreateIssue, ActionCreatePullRequest).
|
||||||
|
Where("content LIKE ?", strconv.FormatInt(issueID, 10)+"|%").
|
||||||
|
Delete(&Action{})
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
|
@ -228,3 +228,46 @@ func TestGetFeedsCorrupted(t *testing.T) {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Len(t, actions, 0)
|
assert.Len(t, actions, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestConsistencyUpdateAction(t *testing.T) {
|
||||||
|
if !setting.Database.UseSQLite3 {
|
||||||
|
t.Skip("Test is only for SQLite database.")
|
||||||
|
}
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
id := 8
|
||||||
|
unittest.AssertExistsAndLoadBean(t, &Action{
|
||||||
|
ID: int64(id),
|
||||||
|
})
|
||||||
|
_, err := db.GetEngine(db.DefaultContext).Exec(`UPDATE action SET created_unix = "" WHERE id = ?`, id)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
actions := make([]*Action, 0, 1)
|
||||||
|
//
|
||||||
|
// XORM returns an error when created_unix is a string
|
||||||
|
//
|
||||||
|
err = db.GetEngine(db.DefaultContext).Where("id = ?", id).Find(&actions)
|
||||||
|
if assert.Error(t, err) {
|
||||||
|
assert.Contains(t, err.Error(), "type string to a int64: invalid syntax")
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// Get rid of incorrectly set created_unix
|
||||||
|
//
|
||||||
|
count, err := CountActionCreatedUnixString()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.EqualValues(t, 1, count)
|
||||||
|
count, err = FixActionCreatedUnixString()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.EqualValues(t, 1, count)
|
||||||
|
|
||||||
|
count, err = CountActionCreatedUnixString()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.EqualValues(t, 0, count)
|
||||||
|
count, err = FixActionCreatedUnixString()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.EqualValues(t, 0, count)
|
||||||
|
|
||||||
|
//
|
||||||
|
// XORM must be happy now
|
||||||
|
//
|
||||||
|
assert.NoError(t, db.GetEngine(db.DefaultContext).Where("id = ?", id).Find(&actions))
|
||||||
|
unittest.CheckConsistencyFor(t, &Action{})
|
||||||
|
}
|
||||||
|
|
|
@ -1,80 +0,0 @@
|
||||||
// Copyright 2022 The Gitea Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a MIT-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package models
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
|
||||||
git_model "code.gitea.io/gitea/models/git"
|
|
||||||
"code.gitea.io/gitea/modules/log"
|
|
||||||
)
|
|
||||||
|
|
||||||
// HasEnoughApprovals returns true if pr has enough granted approvals.
|
|
||||||
func HasEnoughApprovals(ctx context.Context, protectBranch *git_model.ProtectedBranch, pr *PullRequest) bool {
|
|
||||||
if protectBranch.RequiredApprovals == 0 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return GetGrantedApprovalsCount(ctx, protectBranch, pr) >= protectBranch.RequiredApprovals
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetGrantedApprovalsCount returns the number of granted approvals for pr. A granted approval must be authored by a user in an approval whitelist.
|
|
||||||
func GetGrantedApprovalsCount(ctx context.Context, protectBranch *git_model.ProtectedBranch, pr *PullRequest) int64 {
|
|
||||||
sess := db.GetEngine(ctx).Where("issue_id = ?", pr.IssueID).
|
|
||||||
And("type = ?", ReviewTypeApprove).
|
|
||||||
And("official = ?", true).
|
|
||||||
And("dismissed = ?", false)
|
|
||||||
if protectBranch.DismissStaleApprovals {
|
|
||||||
sess = sess.And("stale = ?", false)
|
|
||||||
}
|
|
||||||
approvals, err := sess.Count(new(Review))
|
|
||||||
if err != nil {
|
|
||||||
log.Error("GetGrantedApprovalsCount: %v", err)
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
return approvals
|
|
||||||
}
|
|
||||||
|
|
||||||
// MergeBlockedByRejectedReview returns true if merge is blocked by rejected reviews
|
|
||||||
func MergeBlockedByRejectedReview(ctx context.Context, protectBranch *git_model.ProtectedBranch, pr *PullRequest) bool {
|
|
||||||
if !protectBranch.BlockOnRejectedReviews {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
rejectExist, err := db.GetEngine(ctx).Where("issue_id = ?", pr.IssueID).
|
|
||||||
And("type = ?", ReviewTypeReject).
|
|
||||||
And("official = ?", true).
|
|
||||||
And("dismissed = ?", false).
|
|
||||||
Exist(new(Review))
|
|
||||||
if err != nil {
|
|
||||||
log.Error("MergeBlockedByRejectedReview: %v", err)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
return rejectExist
|
|
||||||
}
|
|
||||||
|
|
||||||
// MergeBlockedByOfficialReviewRequests block merge because of some review request to official reviewer
|
|
||||||
// of from official review
|
|
||||||
func MergeBlockedByOfficialReviewRequests(ctx context.Context, protectBranch *git_model.ProtectedBranch, pr *PullRequest) bool {
|
|
||||||
if !protectBranch.BlockOnOfficialReviewRequests {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
has, err := db.GetEngine(ctx).Where("issue_id = ?", pr.IssueID).
|
|
||||||
And("type = ?", ReviewTypeRequest).
|
|
||||||
And("official = ?", true).
|
|
||||||
Exist(new(Review))
|
|
||||||
if err != nil {
|
|
||||||
log.Error("MergeBlockedByOfficialReviewRequests: %v", err)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
return has
|
|
||||||
}
|
|
||||||
|
|
||||||
// MergeBlockedByOutdatedBranch returns true if merge is blocked by an outdated head branch
|
|
||||||
func MergeBlockedByOutdatedBranch(protectBranch *git_model.ProtectedBranch, pr *PullRequest) bool {
|
|
||||||
return protectBranch.BlockOnOutdatedBranch && pr.CommitsBehind > 0
|
|
||||||
}
|
|
|
@ -5,7 +5,6 @@
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
admin_model "code.gitea.io/gitea/models/admin"
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
@ -14,151 +13,6 @@ import (
|
||||||
"xorm.io/builder"
|
"xorm.io/builder"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CountOrphanedLabels return count of labels witch are broken and not accessible via ui anymore
|
|
||||||
func CountOrphanedLabels() (int64, error) {
|
|
||||||
noref, err := db.GetEngine(db.DefaultContext).Table("label").Where("repo_id=? AND org_id=?", 0, 0).Count("label.id")
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
norepo, err := db.GetEngine(db.DefaultContext).Table("label").
|
|
||||||
Where(builder.And(
|
|
||||||
builder.Gt{"repo_id": 0},
|
|
||||||
builder.NotIn("repo_id", builder.Select("id").From("repository")),
|
|
||||||
)).
|
|
||||||
Count()
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
noorg, err := db.GetEngine(db.DefaultContext).Table("label").
|
|
||||||
Where(builder.And(
|
|
||||||
builder.Gt{"org_id": 0},
|
|
||||||
builder.NotIn("org_id", builder.Select("id").From("user")),
|
|
||||||
)).
|
|
||||||
Count()
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return noref + norepo + noorg, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteOrphanedLabels delete labels witch are broken and not accessible via ui anymore
|
|
||||||
func DeleteOrphanedLabels() error {
|
|
||||||
// delete labels with no reference
|
|
||||||
if _, err := db.GetEngine(db.DefaultContext).Table("label").Where("repo_id=? AND org_id=?", 0, 0).Delete(new(Label)); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// delete labels with none existing repos
|
|
||||||
if _, err := db.GetEngine(db.DefaultContext).
|
|
||||||
Where(builder.And(
|
|
||||||
builder.Gt{"repo_id": 0},
|
|
||||||
builder.NotIn("repo_id", builder.Select("id").From("repository")),
|
|
||||||
)).
|
|
||||||
Delete(Label{}); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// delete labels with none existing orgs
|
|
||||||
if _, err := db.GetEngine(db.DefaultContext).
|
|
||||||
Where(builder.And(
|
|
||||||
builder.Gt{"org_id": 0},
|
|
||||||
builder.NotIn("org_id", builder.Select("id").From("user")),
|
|
||||||
)).
|
|
||||||
Delete(Label{}); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CountOrphanedIssueLabels return count of IssueLabels witch have no label behind anymore
|
|
||||||
func CountOrphanedIssueLabels() (int64, error) {
|
|
||||||
return db.GetEngine(db.DefaultContext).Table("issue_label").
|
|
||||||
NotIn("label_id", builder.Select("id").From("label")).
|
|
||||||
Count()
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteOrphanedIssueLabels delete IssueLabels witch have no label behind anymore
|
|
||||||
func DeleteOrphanedIssueLabels() error {
|
|
||||||
_, err := db.GetEngine(db.DefaultContext).
|
|
||||||
NotIn("label_id", builder.Select("id").From("label")).
|
|
||||||
Delete(IssueLabel{})
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// CountOrphanedIssues count issues without a repo
|
|
||||||
func CountOrphanedIssues() (int64, error) {
|
|
||||||
return db.GetEngine(db.DefaultContext).Table("issue").
|
|
||||||
Join("LEFT", "repository", "issue.repo_id=repository.id").
|
|
||||||
Where(builder.IsNull{"repository.id"}).
|
|
||||||
Select("COUNT(`issue`.`id`)").
|
|
||||||
Count()
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteOrphanedIssues delete issues without a repo
|
|
||||||
func DeleteOrphanedIssues() error {
|
|
||||||
ctx, committer, err := db.TxContext()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer committer.Close()
|
|
||||||
|
|
||||||
var ids []int64
|
|
||||||
|
|
||||||
if err := db.GetEngine(ctx).Table("issue").Distinct("issue.repo_id").
|
|
||||||
Join("LEFT", "repository", "issue.repo_id=repository.id").
|
|
||||||
Where(builder.IsNull{"repository.id"}).GroupBy("issue.repo_id").
|
|
||||||
Find(&ids); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
var attachmentPaths []string
|
|
||||||
for i := range ids {
|
|
||||||
paths, err := deleteIssuesByRepoID(ctx, ids[i])
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
attachmentPaths = append(attachmentPaths, paths...)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := committer.Commit(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
committer.Close()
|
|
||||||
|
|
||||||
// Remove issue attachment files.
|
|
||||||
for i := range attachmentPaths {
|
|
||||||
admin_model.RemoveAllWithNotice(db.DefaultContext, "Delete issue attachment", attachmentPaths[i])
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CountOrphanedObjects count subjects with have no existing refobject anymore
|
|
||||||
func CountOrphanedObjects(subject, refobject, joinCond string) (int64, error) {
|
|
||||||
return db.GetEngine(db.DefaultContext).Table("`"+subject+"`").
|
|
||||||
Join("LEFT", "`"+refobject+"`", joinCond).
|
|
||||||
Where(builder.IsNull{"`" + refobject + "`.id"}).
|
|
||||||
Select("COUNT(`" + subject + "`.`id`)").
|
|
||||||
Count()
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteOrphanedObjects delete subjects with have no existing refobject anymore
|
|
||||||
func DeleteOrphanedObjects(subject, refobject, joinCond string) error {
|
|
||||||
subQuery := builder.Select("`"+subject+"`.id").
|
|
||||||
From("`"+subject+"`").
|
|
||||||
Join("LEFT", "`"+refobject+"`", joinCond).
|
|
||||||
Where(builder.IsNull{"`" + refobject + "`.id"})
|
|
||||||
sql, args, err := builder.Delete(builder.In("id", subQuery)).From("`" + subject + "`").ToSQL()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_, err = db.GetEngine(db.DefaultContext).Exec(append([]interface{}{sql}, args...)...)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// CountNullArchivedRepository counts the number of repositories with is_archived is null
|
// CountNullArchivedRepository counts the number of repositories with is_archived is null
|
||||||
func CountNullArchivedRepository() (int64, error) {
|
func CountNullArchivedRepository() (int64, error) {
|
||||||
return db.GetEngine(db.DefaultContext).Where(builder.IsNull{"is_archived"}).Count(new(repo_model.Repository))
|
return db.GetEngine(db.DefaultContext).Where(builder.IsNull{"is_archived"}).Count(new(repo_model.Repository))
|
||||||
|
@ -181,74 +35,6 @@ func FixWrongUserType() (int64, error) {
|
||||||
return db.GetEngine(db.DefaultContext).Where(builder.Eq{"type": 0}.And(builder.Neq{"num_teams": 0})).Cols("type").NoAutoTime().Update(&user_model.User{Type: 1})
|
return db.GetEngine(db.DefaultContext).Where(builder.Eq{"type": 0}.And(builder.Neq{"num_teams": 0})).Cols("type").NoAutoTime().Update(&user_model.User{Type: 1})
|
||||||
}
|
}
|
||||||
|
|
||||||
// CountCommentTypeLabelWithEmptyLabel count label comments with empty label
|
|
||||||
func CountCommentTypeLabelWithEmptyLabel() (int64, error) {
|
|
||||||
return db.GetEngine(db.DefaultContext).Where(builder.Eq{"type": CommentTypeLabel, "label_id": 0}).Count(new(Comment))
|
|
||||||
}
|
|
||||||
|
|
||||||
// FixCommentTypeLabelWithEmptyLabel count label comments with empty label
|
|
||||||
func FixCommentTypeLabelWithEmptyLabel() (int64, error) {
|
|
||||||
return db.GetEngine(db.DefaultContext).Where(builder.Eq{"type": CommentTypeLabel, "label_id": 0}).Delete(new(Comment))
|
|
||||||
}
|
|
||||||
|
|
||||||
// CountCommentTypeLabelWithOutsideLabels count label comments with outside label
|
|
||||||
func CountCommentTypeLabelWithOutsideLabels() (int64, error) {
|
|
||||||
return db.GetEngine(db.DefaultContext).Where("comment.type = ? AND ((label.org_id = 0 AND issue.repo_id != label.repo_id) OR (label.repo_id = 0 AND label.org_id != repository.owner_id))", CommentTypeLabel).
|
|
||||||
Table("comment").
|
|
||||||
Join("inner", "label", "label.id = comment.label_id").
|
|
||||||
Join("inner", "issue", "issue.id = comment.issue_id ").
|
|
||||||
Join("inner", "repository", "issue.repo_id = repository.id").
|
|
||||||
Count(new(Comment))
|
|
||||||
}
|
|
||||||
|
|
||||||
// FixCommentTypeLabelWithOutsideLabels count label comments with outside label
|
|
||||||
func FixCommentTypeLabelWithOutsideLabels() (int64, error) {
|
|
||||||
res, err := db.GetEngine(db.DefaultContext).Exec(`DELETE FROM comment WHERE comment.id IN (
|
|
||||||
SELECT il_too.id FROM (
|
|
||||||
SELECT com.id
|
|
||||||
FROM comment AS com
|
|
||||||
INNER JOIN label ON com.label_id = label.id
|
|
||||||
INNER JOIN issue on issue.id = com.issue_id
|
|
||||||
INNER JOIN repository ON issue.repo_id = repository.id
|
|
||||||
WHERE
|
|
||||||
com.type = ? AND ((label.org_id = 0 AND issue.repo_id != label.repo_id) OR (label.repo_id = 0 AND label.org_id != repository.owner_id))
|
|
||||||
) AS il_too)`, CommentTypeLabel)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return res.RowsAffected()
|
|
||||||
}
|
|
||||||
|
|
||||||
// CountIssueLabelWithOutsideLabels count label comments with outside label
|
|
||||||
func CountIssueLabelWithOutsideLabels() (int64, error) {
|
|
||||||
return db.GetEngine(db.DefaultContext).Where(builder.Expr("(label.org_id = 0 AND issue.repo_id != label.repo_id) OR (label.repo_id = 0 AND label.org_id != repository.owner_id)")).
|
|
||||||
Table("issue_label").
|
|
||||||
Join("inner", "label", "issue_label.label_id = label.id ").
|
|
||||||
Join("inner", "issue", "issue.id = issue_label.issue_id ").
|
|
||||||
Join("inner", "repository", "issue.repo_id = repository.id").
|
|
||||||
Count(new(IssueLabel))
|
|
||||||
}
|
|
||||||
|
|
||||||
// FixIssueLabelWithOutsideLabels fix label comments with outside label
|
|
||||||
func FixIssueLabelWithOutsideLabels() (int64, error) {
|
|
||||||
res, err := db.GetEngine(db.DefaultContext).Exec(`DELETE FROM issue_label WHERE issue_label.id IN (
|
|
||||||
SELECT il_too.id FROM (
|
|
||||||
SELECT il_too_too.id
|
|
||||||
FROM issue_label AS il_too_too
|
|
||||||
INNER JOIN label ON il_too_too.label_id = label.id
|
|
||||||
INNER JOIN issue on issue.id = il_too_too.issue_id
|
|
||||||
INNER JOIN repository on repository.id = issue.repo_id
|
|
||||||
WHERE
|
|
||||||
(label.org_id = 0 AND issue.repo_id != label.repo_id) OR (label.repo_id = 0 AND label.org_id != repository.owner_id)
|
|
||||||
) AS il_too )`)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return res.RowsAffected()
|
|
||||||
}
|
|
||||||
|
|
||||||
// CountActionCreatedUnixString count actions where created_unix is an empty string
|
// CountActionCreatedUnixString count actions where created_unix is an empty string
|
||||||
func CountActionCreatedUnixString() (int64, error) {
|
func CountActionCreatedUnixString() (int64, error) {
|
||||||
if setting.Database.UseSQLite3 {
|
if setting.Database.UseSQLite3 {
|
||||||
|
|
|
@ -1,149 +0,0 @@
|
||||||
// Copyright 2021 Gitea. All rights reserved.
|
|
||||||
// Use of this source code is governed by a MIT-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package models
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
|
||||||
issues_model "code.gitea.io/gitea/models/issues"
|
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
|
||||||
"code.gitea.io/gitea/models/unittest"
|
|
||||||
"code.gitea.io/gitea/modules/setting"
|
|
||||||
"code.gitea.io/gitea/modules/timeutil"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestDeleteOrphanedObjects(t *testing.T) {
|
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
|
||||||
|
|
||||||
countBefore, err := db.GetEngine(db.DefaultContext).Count(&PullRequest{})
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
_, err = db.GetEngine(db.DefaultContext).Insert(&PullRequest{IssueID: 1000}, &PullRequest{IssueID: 1001}, &PullRequest{IssueID: 1003})
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
orphaned, err := CountOrphanedObjects("pull_request", "issue", "pull_request.issue_id=issue.id")
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.EqualValues(t, 3, orphaned)
|
|
||||||
|
|
||||||
err = DeleteOrphanedObjects("pull_request", "issue", "pull_request.issue_id=issue.id")
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
countAfter, err := db.GetEngine(db.DefaultContext).Count(&PullRequest{})
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.EqualValues(t, countBefore, countAfter)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNewMilestone(t *testing.T) {
|
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
|
||||||
milestone := &issues_model.Milestone{
|
|
||||||
RepoID: 1,
|
|
||||||
Name: "milestoneName",
|
|
||||||
Content: "milestoneContent",
|
|
||||||
}
|
|
||||||
|
|
||||||
assert.NoError(t, issues_model.NewMilestone(milestone))
|
|
||||||
unittest.AssertExistsAndLoadBean(t, milestone)
|
|
||||||
unittest.CheckConsistencyFor(t, &repo_model.Repository{ID: milestone.RepoID}, &issues_model.Milestone{})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestChangeMilestoneStatus(t *testing.T) {
|
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
|
||||||
milestone := unittest.AssertExistsAndLoadBean(t, &issues_model.Milestone{ID: 1}).(*issues_model.Milestone)
|
|
||||||
|
|
||||||
assert.NoError(t, issues_model.ChangeMilestoneStatus(milestone, true))
|
|
||||||
unittest.AssertExistsAndLoadBean(t, &issues_model.Milestone{ID: 1}, "is_closed=1")
|
|
||||||
unittest.CheckConsistencyFor(t, &repo_model.Repository{ID: milestone.RepoID}, &issues_model.Milestone{})
|
|
||||||
|
|
||||||
assert.NoError(t, issues_model.ChangeMilestoneStatus(milestone, false))
|
|
||||||
unittest.AssertExistsAndLoadBean(t, &issues_model.Milestone{ID: 1}, "is_closed=0")
|
|
||||||
unittest.CheckConsistencyFor(t, &repo_model.Repository{ID: milestone.RepoID}, &issues_model.Milestone{})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDeleteMilestoneByRepoID(t *testing.T) {
|
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
|
||||||
assert.NoError(t, issues_model.DeleteMilestoneByRepoID(1, 1))
|
|
||||||
unittest.AssertNotExistsBean(t, &issues_model.Milestone{ID: 1})
|
|
||||||
unittest.CheckConsistencyFor(t, &repo_model.Repository{ID: 1})
|
|
||||||
|
|
||||||
assert.NoError(t, issues_model.DeleteMilestoneByRepoID(unittest.NonexistentID, unittest.NonexistentID))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestUpdateMilestone(t *testing.T) {
|
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
|
||||||
|
|
||||||
milestone := unittest.AssertExistsAndLoadBean(t, &issues_model.Milestone{ID: 1}).(*issues_model.Milestone)
|
|
||||||
milestone.Name = " newMilestoneName "
|
|
||||||
milestone.Content = "newMilestoneContent"
|
|
||||||
assert.NoError(t, issues_model.UpdateMilestone(milestone, milestone.IsClosed))
|
|
||||||
milestone = unittest.AssertExistsAndLoadBean(t, &issues_model.Milestone{ID: 1}).(*issues_model.Milestone)
|
|
||||||
assert.EqualValues(t, "newMilestoneName", milestone.Name)
|
|
||||||
unittest.CheckConsistencyFor(t, &issues_model.Milestone{})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestUpdateMilestoneCounters(t *testing.T) {
|
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
|
||||||
issue := unittest.AssertExistsAndLoadBean(t, &Issue{MilestoneID: 1},
|
|
||||||
"is_closed=0").(*Issue)
|
|
||||||
|
|
||||||
issue.IsClosed = true
|
|
||||||
issue.ClosedUnix = timeutil.TimeStampNow()
|
|
||||||
_, err := db.GetEngine(db.DefaultContext).ID(issue.ID).Cols("is_closed", "closed_unix").Update(issue)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.NoError(t, issues_model.UpdateMilestoneCounters(db.DefaultContext, issue.MilestoneID))
|
|
||||||
unittest.CheckConsistencyFor(t, &issues_model.Milestone{})
|
|
||||||
|
|
||||||
issue.IsClosed = false
|
|
||||||
issue.ClosedUnix = 0
|
|
||||||
_, err = db.GetEngine(db.DefaultContext).ID(issue.ID).Cols("is_closed", "closed_unix").Update(issue)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.NoError(t, issues_model.UpdateMilestoneCounters(db.DefaultContext, issue.MilestoneID))
|
|
||||||
unittest.CheckConsistencyFor(t, &issues_model.Milestone{})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestConsistencyUpdateAction(t *testing.T) {
|
|
||||||
if !setting.Database.UseSQLite3 {
|
|
||||||
t.Skip("Test is only for SQLite database.")
|
|
||||||
}
|
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
|
||||||
id := 8
|
|
||||||
unittest.AssertExistsAndLoadBean(t, &Action{
|
|
||||||
ID: int64(id),
|
|
||||||
})
|
|
||||||
_, err := db.GetEngine(db.DefaultContext).Exec(`UPDATE action SET created_unix = "" WHERE id = ?`, id)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
actions := make([]*Action, 0, 1)
|
|
||||||
//
|
|
||||||
// XORM returns an error when created_unix is a string
|
|
||||||
//
|
|
||||||
err = db.GetEngine(db.DefaultContext).Where("id = ?", id).Find(&actions)
|
|
||||||
if assert.Error(t, err) {
|
|
||||||
assert.Contains(t, err.Error(), "type string to a int64: invalid syntax")
|
|
||||||
}
|
|
||||||
//
|
|
||||||
// Get rid of incorrectly set created_unix
|
|
||||||
//
|
|
||||||
count, err := CountActionCreatedUnixString()
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.EqualValues(t, 1, count)
|
|
||||||
count, err = FixActionCreatedUnixString()
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.EqualValues(t, 1, count)
|
|
||||||
|
|
||||||
count, err = CountActionCreatedUnixString()
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.EqualValues(t, 0, count)
|
|
||||||
count, err = FixActionCreatedUnixString()
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.EqualValues(t, 0, count)
|
|
||||||
|
|
||||||
//
|
|
||||||
// XORM must be happy now
|
|
||||||
//
|
|
||||||
assert.NoError(t, db.GetEngine(db.DefaultContext).Where("id = ?", id).Find(&actions))
|
|
||||||
unittest.CheckConsistencyFor(t, &Action{})
|
|
||||||
}
|
|
27
models/db/consistency.go
Normal file
27
models/db/consistency.go
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
// Copyright 2022 The Gitea Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package db
|
||||||
|
|
||||||
|
import "xorm.io/builder"
|
||||||
|
|
||||||
|
// CountOrphanedObjects count subjects with have no existing refobject anymore
|
||||||
|
func CountOrphanedObjects(subject, refobject, joinCond string) (int64, error) {
|
||||||
|
return GetEngine(DefaultContext).Table("`"+subject+"`").
|
||||||
|
Join("LEFT", "`"+refobject+"`", joinCond).
|
||||||
|
Where(builder.IsNull{"`" + refobject + "`.id"}).
|
||||||
|
Select("COUNT(`" + subject + "`.`id`)").
|
||||||
|
Count()
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteOrphanedObjects delete subjects with have no existing refobject anymore
|
||||||
|
func DeleteOrphanedObjects(subject, refobject, joinCond string) error {
|
||||||
|
subQuery := builder.Select("`"+subject+"`.id").
|
||||||
|
From("`"+subject+"`").
|
||||||
|
Join("LEFT", "`"+refobject+"`", joinCond).
|
||||||
|
Where(builder.IsNull{"`" + refobject + "`.id"})
|
||||||
|
b := builder.Delete(builder.In("id", subQuery)).From("`" + subject + "`")
|
||||||
|
_, err := GetEngine(DefaultContext).Exec(b)
|
||||||
|
return err
|
||||||
|
}
|
|
@ -20,21 +20,21 @@ type ResourceIndex struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpsertResourceIndex the function will not return until it acquires the lock or receives an error.
|
// UpsertResourceIndex the function will not return until it acquires the lock or receives an error.
|
||||||
func UpsertResourceIndex(e Engine, tableName string, groupID int64) (err error) {
|
func UpsertResourceIndex(ctx context.Context, tableName string, groupID int64) (err error) {
|
||||||
// An atomic UPSERT operation (INSERT/UPDATE) is the only operation
|
// An atomic UPSERT operation (INSERT/UPDATE) is the only operation
|
||||||
// that ensures that the key is actually locked.
|
// that ensures that the key is actually locked.
|
||||||
switch {
|
switch {
|
||||||
case setting.Database.UseSQLite3 || setting.Database.UsePostgreSQL:
|
case setting.Database.UseSQLite3 || setting.Database.UsePostgreSQL:
|
||||||
_, err = e.Exec(fmt.Sprintf("INSERT INTO %s (group_id, max_index) "+
|
_, err = Exec(ctx, fmt.Sprintf("INSERT INTO %s (group_id, max_index) "+
|
||||||
"VALUES (?,1) ON CONFLICT (group_id) DO UPDATE SET max_index = %s.max_index+1",
|
"VALUES (?,1) ON CONFLICT (group_id) DO UPDATE SET max_index = %s.max_index+1",
|
||||||
tableName, tableName), groupID)
|
tableName, tableName), groupID)
|
||||||
case setting.Database.UseMySQL:
|
case setting.Database.UseMySQL:
|
||||||
_, err = e.Exec(fmt.Sprintf("INSERT INTO %s (group_id, max_index) "+
|
_, err = Exec(ctx, fmt.Sprintf("INSERT INTO %s (group_id, max_index) "+
|
||||||
"VALUES (?,1) ON DUPLICATE KEY UPDATE max_index = max_index+1", tableName),
|
"VALUES (?,1) ON DUPLICATE KEY UPDATE max_index = max_index+1", tableName),
|
||||||
groupID)
|
groupID)
|
||||||
case setting.Database.UseMSSQL:
|
case setting.Database.UseMSSQL:
|
||||||
// https://weblogs.sqlteam.com/dang/2009/01/31/upsert-race-condition-with-merge/
|
// https://weblogs.sqlteam.com/dang/2009/01/31/upsert-race-condition-with-merge/
|
||||||
_, err = e.Exec(fmt.Sprintf("MERGE %s WITH (HOLDLOCK) as target "+
|
_, err = Exec(ctx, fmt.Sprintf("MERGE %s WITH (HOLDLOCK) as target "+
|
||||||
"USING (SELECT ? AS group_id) AS src "+
|
"USING (SELECT ? AS group_id) AS src "+
|
||||||
"ON src.group_id = target.group_id "+
|
"ON src.group_id = target.group_id "+
|
||||||
"WHEN MATCHED THEN UPDATE SET target.max_index = target.max_index+1 "+
|
"WHEN MATCHED THEN UPDATE SET target.max_index = target.max_index+1 "+
|
||||||
|
@ -82,30 +82,29 @@ func DeleteResouceIndex(ctx context.Context, tableName string, groupID int64) er
|
||||||
|
|
||||||
// getNextResourceIndex return the next index
|
// getNextResourceIndex return the next index
|
||||||
func getNextResourceIndex(tableName string, groupID int64) (int64, error) {
|
func getNextResourceIndex(tableName string, groupID int64) (int64, error) {
|
||||||
sess := x.NewSession()
|
ctx, commiter, err := TxContext()
|
||||||
defer sess.Close()
|
|
||||||
if err := sess.Begin(); err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
var preIdx int64
|
|
||||||
_, err := sess.SQL(fmt.Sprintf("SELECT max_index FROM %s WHERE group_id = ?", tableName), groupID).Get(&preIdx)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
defer commiter.Close()
|
||||||
|
var preIdx int64
|
||||||
|
if _, err := GetEngine(ctx).SQL(fmt.Sprintf("SELECT max_index FROM %s WHERE group_id = ?", tableName), groupID).Get(&preIdx); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
if err := UpsertResourceIndex(sess, tableName, groupID); err != nil {
|
if err := UpsertResourceIndex(ctx, tableName, groupID); err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var curIdx int64
|
var curIdx int64
|
||||||
has, err := sess.SQL(fmt.Sprintf("SELECT max_index FROM %s WHERE group_id = ? AND max_index=?", tableName), groupID, preIdx+1).Get(&curIdx)
|
has, err := GetEngine(ctx).SQL(fmt.Sprintf("SELECT max_index FROM %s WHERE group_id = ? AND max_index=?", tableName), groupID, preIdx+1).Get(&curIdx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
if !has {
|
if !has {
|
||||||
return 0, ErrResouceOutdated
|
return 0, ErrResouceOutdated
|
||||||
}
|
}
|
||||||
if err := sess.Commit(); err != nil {
|
if err := commiter.Commit(); err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
return curIdx, nil
|
return curIdx, nil
|
||||||
|
|
|
@ -10,6 +10,11 @@ import (
|
||||||
"xorm.io/xorm"
|
"xorm.io/xorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// DefaultMaxInSize represents default variables number on IN () in SQL
|
||||||
|
DefaultMaxInSize = 50
|
||||||
|
)
|
||||||
|
|
||||||
// Paginator is the base for different ListOptions types
|
// Paginator is the base for different ListOptions types
|
||||||
type Paginator interface {
|
type Paginator interface {
|
||||||
GetSkipTake() (skip, take int)
|
GetSkipTake() (skip, take int)
|
||||||
|
|
376
models/error.go
376
models/error.go
|
@ -405,22 +405,6 @@ func (err ErrFilePathProtected) Error() string {
|
||||||
return fmt.Sprintf("path is protected and can not be changed [path: %s]", err.Path)
|
return fmt.Sprintf("path is protected and can not be changed [path: %s]", err.Path)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ErrUserDoesNotHaveAccessToRepo represets an error where the user doesn't has access to a given repo.
|
|
||||||
type ErrUserDoesNotHaveAccessToRepo struct {
|
|
||||||
UserID int64
|
|
||||||
RepoName string
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsErrUserDoesNotHaveAccessToRepo checks if an error is a ErrRepoFileAlreadyExists.
|
|
||||||
func IsErrUserDoesNotHaveAccessToRepo(err error) bool {
|
|
||||||
_, ok := err.(ErrUserDoesNotHaveAccessToRepo)
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func (err ErrUserDoesNotHaveAccessToRepo) Error() string {
|
|
||||||
return fmt.Sprintf("user doesn't have access to repo [user_id: %d, repo_name: %s]", err.UserID, err.RepoName)
|
|
||||||
}
|
|
||||||
|
|
||||||
// __________ .__
|
// __________ .__
|
||||||
// \______ \____________ ____ ____ | |__
|
// \______ \____________ ____ ____ | |__
|
||||||
// | | _/\_ __ \__ \ / \_/ ___\| | \
|
// | | _/\_ __ \__ \ / \_/ ___\| | \
|
||||||
|
@ -580,162 +564,6 @@ func (err ErrSHAOrCommitIDNotProvided) Error() string {
|
||||||
return "a SHA or commit ID must be proved when updating a file"
|
return "a SHA or commit ID must be proved when updating a file"
|
||||||
}
|
}
|
||||||
|
|
||||||
// .___
|
|
||||||
// | | ______ ________ __ ____
|
|
||||||
// | |/ ___// ___/ | \_/ __ \
|
|
||||||
// | |\___ \ \___ \| | /\ ___/
|
|
||||||
// |___/____ >____ >____/ \___ >
|
|
||||||
// \/ \/ \/
|
|
||||||
|
|
||||||
// ErrIssueNotExist represents a "IssueNotExist" kind of error.
|
|
||||||
type ErrIssueNotExist struct {
|
|
||||||
ID int64
|
|
||||||
RepoID int64
|
|
||||||
Index int64
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsErrIssueNotExist checks if an error is a ErrIssueNotExist.
|
|
||||||
func IsErrIssueNotExist(err error) bool {
|
|
||||||
_, ok := err.(ErrIssueNotExist)
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func (err ErrIssueNotExist) Error() string {
|
|
||||||
return fmt.Sprintf("issue does not exist [id: %d, repo_id: %d, index: %d]", err.ID, err.RepoID, err.Index)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrIssueIsClosed represents a "IssueIsClosed" kind of error.
|
|
||||||
type ErrIssueIsClosed struct {
|
|
||||||
ID int64
|
|
||||||
RepoID int64
|
|
||||||
Index int64
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsErrIssueIsClosed checks if an error is a ErrIssueNotExist.
|
|
||||||
func IsErrIssueIsClosed(err error) bool {
|
|
||||||
_, ok := err.(ErrIssueIsClosed)
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func (err ErrIssueIsClosed) Error() string {
|
|
||||||
return fmt.Sprintf("issue is closed [id: %d, repo_id: %d, index: %d]", err.ID, err.RepoID, err.Index)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrNewIssueInsert is used when the INSERT statement in newIssue fails
|
|
||||||
type ErrNewIssueInsert struct {
|
|
||||||
OriginalError error
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsErrNewIssueInsert checks if an error is a ErrNewIssueInsert.
|
|
||||||
func IsErrNewIssueInsert(err error) bool {
|
|
||||||
_, ok := err.(ErrNewIssueInsert)
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func (err ErrNewIssueInsert) Error() string {
|
|
||||||
return err.OriginalError.Error()
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrIssueWasClosed is used when close a closed issue
|
|
||||||
type ErrIssueWasClosed struct {
|
|
||||||
ID int64
|
|
||||||
Index int64
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsErrIssueWasClosed checks if an error is a ErrIssueWasClosed.
|
|
||||||
func IsErrIssueWasClosed(err error) bool {
|
|
||||||
_, ok := err.(ErrIssueWasClosed)
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func (err ErrIssueWasClosed) Error() string {
|
|
||||||
return fmt.Sprintf("Issue [%d] %d was already closed", err.ID, err.Index)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrPullWasClosed is used close a closed pull request
|
|
||||||
type ErrPullWasClosed struct {
|
|
||||||
ID int64
|
|
||||||
Index int64
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsErrPullWasClosed checks if an error is a ErrErrPullWasClosed.
|
|
||||||
func IsErrPullWasClosed(err error) bool {
|
|
||||||
_, ok := err.(ErrPullWasClosed)
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func (err ErrPullWasClosed) Error() string {
|
|
||||||
return fmt.Sprintf("Pull request [%d] %d was already closed", err.ID, err.Index)
|
|
||||||
}
|
|
||||||
|
|
||||||
// __________ .__ .__ __________ __
|
|
||||||
// \______ \__ __| | | |\______ \ ____ ________ __ ____ _______/ |_
|
|
||||||
// | ___/ | \ | | | | _// __ \/ ____/ | \_/ __ \ / ___/\ __\
|
|
||||||
// | | | | / |_| |_| | \ ___< <_| | | /\ ___/ \___ \ | |
|
|
||||||
// |____| |____/|____/____/____|_ /\___ >__ |____/ \___ >____ > |__|
|
|
||||||
// \/ \/ |__| \/ \/
|
|
||||||
|
|
||||||
// ErrPullRequestNotExist represents a "PullRequestNotExist" kind of error.
|
|
||||||
type ErrPullRequestNotExist struct {
|
|
||||||
ID int64
|
|
||||||
IssueID int64
|
|
||||||
HeadRepoID int64
|
|
||||||
BaseRepoID int64
|
|
||||||
HeadBranch string
|
|
||||||
BaseBranch string
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsErrPullRequestNotExist checks if an error is a ErrPullRequestNotExist.
|
|
||||||
func IsErrPullRequestNotExist(err error) bool {
|
|
||||||
_, ok := err.(ErrPullRequestNotExist)
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func (err ErrPullRequestNotExist) Error() string {
|
|
||||||
return fmt.Sprintf("pull request does not exist [id: %d, issue_id: %d, head_repo_id: %d, base_repo_id: %d, head_branch: %s, base_branch: %s]",
|
|
||||||
err.ID, err.IssueID, err.HeadRepoID, err.BaseRepoID, err.HeadBranch, err.BaseBranch)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrPullRequestAlreadyExists represents a "PullRequestAlreadyExists"-error
|
|
||||||
type ErrPullRequestAlreadyExists struct {
|
|
||||||
ID int64
|
|
||||||
IssueID int64
|
|
||||||
HeadRepoID int64
|
|
||||||
BaseRepoID int64
|
|
||||||
HeadBranch string
|
|
||||||
BaseBranch string
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsErrPullRequestAlreadyExists checks if an error is a ErrPullRequestAlreadyExists.
|
|
||||||
func IsErrPullRequestAlreadyExists(err error) bool {
|
|
||||||
_, ok := err.(ErrPullRequestAlreadyExists)
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
// Error does pretty-printing :D
|
|
||||||
func (err ErrPullRequestAlreadyExists) Error() string {
|
|
||||||
return fmt.Sprintf("pull request already exists for these targets [id: %d, issue_id: %d, head_repo_id: %d, base_repo_id: %d, head_branch: %s, base_branch: %s]",
|
|
||||||
err.ID, err.IssueID, err.HeadRepoID, err.BaseRepoID, err.HeadBranch, err.BaseBranch)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrPullRequestHeadRepoMissing represents a "ErrPullRequestHeadRepoMissing" error
|
|
||||||
type ErrPullRequestHeadRepoMissing struct {
|
|
||||||
ID int64
|
|
||||||
HeadRepoID int64
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsErrErrPullRequestHeadRepoMissing checks if an error is a ErrPullRequestHeadRepoMissing.
|
|
||||||
func IsErrErrPullRequestHeadRepoMissing(err error) bool {
|
|
||||||
_, ok := err.(ErrPullRequestHeadRepoMissing)
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
// Error does pretty-printing :D
|
|
||||||
func (err ErrPullRequestHeadRepoMissing) Error() string {
|
|
||||||
return fmt.Sprintf("pull request head repo missing [id: %d, head_repo_id: %d]",
|
|
||||||
err.ID, err.HeadRepoID)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrInvalidMergeStyle represents an error if merging with disabled merge strategy
|
// ErrInvalidMergeStyle represents an error if merging with disabled merge strategy
|
||||||
type ErrInvalidMergeStyle struct {
|
type ErrInvalidMergeStyle struct {
|
||||||
ID int64
|
ID int64
|
||||||
|
@ -830,29 +658,6 @@ func (err ErrPullRequestHasMerged) Error() string {
|
||||||
err.ID, err.IssueID, err.HeadRepoID, err.BaseRepoID, err.HeadBranch, err.BaseBranch)
|
err.ID, err.IssueID, err.HeadRepoID, err.BaseRepoID, err.HeadBranch, err.BaseBranch)
|
||||||
}
|
}
|
||||||
|
|
||||||
// _________ __
|
|
||||||
// \_ ___ \ ____ _____ _____ ____ _____/ |_
|
|
||||||
// / \ \/ / _ \ / \ / \_/ __ \ / \ __\
|
|
||||||
// \ \___( <_> ) Y Y \ Y Y \ ___/| | \ |
|
|
||||||
// \______ /\____/|__|_| /__|_| /\___ >___| /__|
|
|
||||||
// \/ \/ \/ \/ \/
|
|
||||||
|
|
||||||
// ErrCommentNotExist represents a "CommentNotExist" kind of error.
|
|
||||||
type ErrCommentNotExist struct {
|
|
||||||
ID int64
|
|
||||||
IssueID int64
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsErrCommentNotExist checks if an error is a ErrCommentNotExist.
|
|
||||||
func IsErrCommentNotExist(err error) bool {
|
|
||||||
_, ok := err.(ErrCommentNotExist)
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func (err ErrCommentNotExist) Error() string {
|
|
||||||
return fmt.Sprintf("comment does not exist [id: %d, issue_id: %d]", err.ID, err.IssueID)
|
|
||||||
}
|
|
||||||
|
|
||||||
// _________ __ __ .__
|
// _________ __ __ .__
|
||||||
// / _____// |_ ____ ________ _ _______ _/ |_ ____ | |__
|
// / _____// |_ ____ ________ _ _______ _/ |_ ____ | |__
|
||||||
// \_____ \\ __\/ _ \\____ \ \/ \/ /\__ \\ __\/ ___\| | \
|
// \_____ \\ __\/ _ \\____ \ \/ \/ /\__ \\ __\/ ___\| | \
|
||||||
|
@ -897,60 +702,6 @@ func (err ErrTrackedTimeNotExist) Error() string {
|
||||||
return fmt.Sprintf("tracked time does not exist [id: %d]", err.ID)
|
return fmt.Sprintf("tracked time does not exist [id: %d]", err.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// .____ ___. .__
|
|
||||||
// | | _____ \_ |__ ____ | |
|
|
||||||
// | | \__ \ | __ \_/ __ \| |
|
|
||||||
// | |___ / __ \| \_\ \ ___/| |__
|
|
||||||
// |_______ (____ /___ /\___ >____/
|
|
||||||
// \/ \/ \/ \/
|
|
||||||
|
|
||||||
// ErrRepoLabelNotExist represents a "RepoLabelNotExist" kind of error.
|
|
||||||
type ErrRepoLabelNotExist struct {
|
|
||||||
LabelID int64
|
|
||||||
RepoID int64
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsErrRepoLabelNotExist checks if an error is a RepoErrLabelNotExist.
|
|
||||||
func IsErrRepoLabelNotExist(err error) bool {
|
|
||||||
_, ok := err.(ErrRepoLabelNotExist)
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func (err ErrRepoLabelNotExist) Error() string {
|
|
||||||
return fmt.Sprintf("label does not exist [label_id: %d, repo_id: %d]", err.LabelID, err.RepoID)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrOrgLabelNotExist represents a "OrgLabelNotExist" kind of error.
|
|
||||||
type ErrOrgLabelNotExist struct {
|
|
||||||
LabelID int64
|
|
||||||
OrgID int64
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsErrOrgLabelNotExist checks if an error is a OrgErrLabelNotExist.
|
|
||||||
func IsErrOrgLabelNotExist(err error) bool {
|
|
||||||
_, ok := err.(ErrOrgLabelNotExist)
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func (err ErrOrgLabelNotExist) Error() string {
|
|
||||||
return fmt.Sprintf("label does not exist [label_id: %d, org_id: %d]", err.LabelID, err.OrgID)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrLabelNotExist represents a "LabelNotExist" kind of error.
|
|
||||||
type ErrLabelNotExist struct {
|
|
||||||
LabelID int64
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsErrLabelNotExist checks if an error is a ErrLabelNotExist.
|
|
||||||
func IsErrLabelNotExist(err error) bool {
|
|
||||||
_, ok := err.(ErrLabelNotExist)
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func (err ErrLabelNotExist) Error() string {
|
|
||||||
return fmt.Sprintf("label does not exist [label_id: %d]", err.LabelID)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ____ ___ .__ .___
|
// ____ ___ .__ .___
|
||||||
// | | \______ | | _________ __| _/
|
// | | \______ | | _________ __| _/
|
||||||
// | | /\____ \| | / _ \__ \ / __ |
|
// | | /\____ \| | / _ \__ \ / __ |
|
||||||
|
@ -974,130 +725,3 @@ func IsErrUploadNotExist(err error) bool {
|
||||||
func (err ErrUploadNotExist) Error() string {
|
func (err ErrUploadNotExist) Error() string {
|
||||||
return fmt.Sprintf("attachment does not exist [id: %d, uuid: %s]", err.ID, err.UUID)
|
return fmt.Sprintf("attachment does not exist [id: %d, uuid: %s]", err.ID, err.UUID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// .___ ________ .___ .__
|
|
||||||
// | | ______ ________ __ ____ \______ \ ____ ______ ____ ____ __| _/____ ____ ____ |__| ____ ______
|
|
||||||
// | |/ ___// ___/ | \_/ __ \ | | \_/ __ \\____ \_/ __ \ / \ / __ |/ __ \ / \_/ ___\| |/ __ \ / ___/
|
|
||||||
// | |\___ \ \___ \| | /\ ___/ | ` \ ___/| |_> > ___/| | \/ /_/ \ ___/| | \ \___| \ ___/ \___ \
|
|
||||||
// |___/____ >____ >____/ \___ >_______ /\___ > __/ \___ >___| /\____ |\___ >___| /\___ >__|\___ >____ >
|
|
||||||
// \/ \/ \/ \/ \/|__| \/ \/ \/ \/ \/ \/ \/ \/
|
|
||||||
|
|
||||||
// ErrDependencyExists represents a "DependencyAlreadyExists" kind of error.
|
|
||||||
type ErrDependencyExists struct {
|
|
||||||
IssueID int64
|
|
||||||
DependencyID int64
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsErrDependencyExists checks if an error is a ErrDependencyExists.
|
|
||||||
func IsErrDependencyExists(err error) bool {
|
|
||||||
_, ok := err.(ErrDependencyExists)
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func (err ErrDependencyExists) Error() string {
|
|
||||||
return fmt.Sprintf("issue dependency does already exist [issue id: %d, dependency id: %d]", err.IssueID, err.DependencyID)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrDependencyNotExists represents a "DependencyAlreadyExists" kind of error.
|
|
||||||
type ErrDependencyNotExists struct {
|
|
||||||
IssueID int64
|
|
||||||
DependencyID int64
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsErrDependencyNotExists checks if an error is a ErrDependencyExists.
|
|
||||||
func IsErrDependencyNotExists(err error) bool {
|
|
||||||
_, ok := err.(ErrDependencyNotExists)
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func (err ErrDependencyNotExists) Error() string {
|
|
||||||
return fmt.Sprintf("issue dependency does not exist [issue id: %d, dependency id: %d]", err.IssueID, err.DependencyID)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrCircularDependency represents a "DependencyCircular" kind of error.
|
|
||||||
type ErrCircularDependency struct {
|
|
||||||
IssueID int64
|
|
||||||
DependencyID int64
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsErrCircularDependency checks if an error is a ErrCircularDependency.
|
|
||||||
func IsErrCircularDependency(err error) bool {
|
|
||||||
_, ok := err.(ErrCircularDependency)
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func (err ErrCircularDependency) Error() string {
|
|
||||||
return fmt.Sprintf("circular dependencies exists (two issues blocking each other) [issue id: %d, dependency id: %d]", err.IssueID, err.DependencyID)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrDependenciesLeft represents an error where the issue you're trying to close still has dependencies left.
|
|
||||||
type ErrDependenciesLeft struct {
|
|
||||||
IssueID int64
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsErrDependenciesLeft checks if an error is a ErrDependenciesLeft.
|
|
||||||
func IsErrDependenciesLeft(err error) bool {
|
|
||||||
_, ok := err.(ErrDependenciesLeft)
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func (err ErrDependenciesLeft) Error() string {
|
|
||||||
return fmt.Sprintf("issue has open dependencies [issue id: %d]", err.IssueID)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrUnknownDependencyType represents an error where an unknown dependency type was passed
|
|
||||||
type ErrUnknownDependencyType struct {
|
|
||||||
Type DependencyType
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsErrUnknownDependencyType checks if an error is ErrUnknownDependencyType
|
|
||||||
func IsErrUnknownDependencyType(err error) bool {
|
|
||||||
_, ok := err.(ErrUnknownDependencyType)
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func (err ErrUnknownDependencyType) Error() string {
|
|
||||||
return fmt.Sprintf("unknown dependency type [type: %d]", err.Type)
|
|
||||||
}
|
|
||||||
|
|
||||||
// __________ .__
|
|
||||||
// \______ \ _______ _|__| ______ _ __
|
|
||||||
// | _// __ \ \/ / |/ __ \ \/ \/ /
|
|
||||||
// | | \ ___/\ /| \ ___/\ /
|
|
||||||
// |____|_ /\___ >\_/ |__|\___ >\/\_/
|
|
||||||
// \/ \/ \/
|
|
||||||
|
|
||||||
// ErrReviewNotExist represents a "ReviewNotExist" kind of error.
|
|
||||||
type ErrReviewNotExist struct {
|
|
||||||
ID int64
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsErrReviewNotExist checks if an error is a ErrReviewNotExist.
|
|
||||||
func IsErrReviewNotExist(err error) bool {
|
|
||||||
_, ok := err.(ErrReviewNotExist)
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func (err ErrReviewNotExist) Error() string {
|
|
||||||
return fmt.Sprintf("review does not exist [id: %d]", err.ID)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrNotValidReviewRequest an not allowed review request modify
|
|
||||||
type ErrNotValidReviewRequest struct {
|
|
||||||
Reason string
|
|
||||||
UserID int64
|
|
||||||
RepoID int64
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsErrNotValidReviewRequest checks if an error is a ErrNotValidReviewRequest.
|
|
||||||
func IsErrNotValidReviewRequest(err error) bool {
|
|
||||||
_, ok := err.(ErrNotValidReviewRequest)
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func (err ErrNotValidReviewRequest) Error() string {
|
|
||||||
return fmt.Sprintf("%s [user_id: %d, repo_id: %d]",
|
|
||||||
err.Reason,
|
|
||||||
err.UserID,
|
|
||||||
err.RepoID)
|
|
||||||
}
|
|
||||||
|
|
|
@ -7,9 +7,9 @@ package git_test
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
git_model "code.gitea.io/gitea/models/git"
|
git_model "code.gitea.io/gitea/models/git"
|
||||||
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
|
|
||||||
|
@ -120,10 +120,10 @@ func TestRenameBranch(t *testing.T) {
|
||||||
repo1 = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository)
|
repo1 = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository)
|
||||||
assert.Equal(t, "main", repo1.DefaultBranch)
|
assert.Equal(t, "main", repo1.DefaultBranch)
|
||||||
|
|
||||||
pull := unittest.AssertExistsAndLoadBean(t, &models.PullRequest{ID: 1}).(*models.PullRequest) // merged
|
pull := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 1}).(*issues_model.PullRequest) // merged
|
||||||
assert.Equal(t, "master", pull.BaseBranch)
|
assert.Equal(t, "master", pull.BaseBranch)
|
||||||
|
|
||||||
pull = unittest.AssertExistsAndLoadBean(t, &models.PullRequest{ID: 2}).(*models.PullRequest) // open
|
pull = unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 2}).(*issues_model.PullRequest) // open
|
||||||
assert.Equal(t, "main", pull.BaseBranch)
|
assert.Equal(t, "main", pull.BaseBranch)
|
||||||
|
|
||||||
renamedBranch := unittest.AssertExistsAndLoadBean(t, &git_model.RenamedBranch{ID: 2}).(*git_model.RenamedBranch)
|
renamedBranch := unittest.AssertExistsAndLoadBean(t, &git_model.RenamedBranch{ID: 2}).(*git_model.RenamedBranch)
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
_ "code.gitea.io/gitea/models"
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,394 +0,0 @@
|
||||||
// Copyright 2017 The Gitea Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a MIT-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package models
|
|
||||||
|
|
||||||
import (
|
|
||||||
"html/template"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
|
||||||
"code.gitea.io/gitea/models/unittest"
|
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
// TODO TestGetLabelTemplateFile
|
|
||||||
|
|
||||||
func TestLabel_CalOpenIssues(t *testing.T) {
|
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
|
||||||
label := unittest.AssertExistsAndLoadBean(t, &Label{ID: 1}).(*Label)
|
|
||||||
label.CalOpenIssues()
|
|
||||||
assert.EqualValues(t, 2, label.NumOpenIssues)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestLabel_ForegroundColor(t *testing.T) {
|
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
|
||||||
label := unittest.AssertExistsAndLoadBean(t, &Label{ID: 1}).(*Label)
|
|
||||||
assert.Equal(t, template.CSS("#000"), label.ForegroundColor())
|
|
||||||
|
|
||||||
label = unittest.AssertExistsAndLoadBean(t, &Label{ID: 2}).(*Label)
|
|
||||||
assert.Equal(t, template.CSS("#fff"), label.ForegroundColor())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNewLabels(t *testing.T) {
|
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
|
||||||
labels := []*Label{
|
|
||||||
{RepoID: 2, Name: "labelName2", Color: "#123456"},
|
|
||||||
{RepoID: 3, Name: "labelName3", Color: "#123"},
|
|
||||||
{RepoID: 4, Name: "labelName4", Color: "ABCDEF"},
|
|
||||||
{RepoID: 5, Name: "labelName5", Color: "DEF"},
|
|
||||||
}
|
|
||||||
assert.Error(t, NewLabel(db.DefaultContext, &Label{RepoID: 3, Name: "invalid Color", Color: ""}))
|
|
||||||
assert.Error(t, NewLabel(db.DefaultContext, &Label{RepoID: 3, Name: "invalid Color", Color: "#45G"}))
|
|
||||||
assert.Error(t, NewLabel(db.DefaultContext, &Label{RepoID: 3, Name: "invalid Color", Color: "#12345G"}))
|
|
||||||
assert.Error(t, NewLabel(db.DefaultContext, &Label{RepoID: 3, Name: "invalid Color", Color: "45G"}))
|
|
||||||
assert.Error(t, NewLabel(db.DefaultContext, &Label{RepoID: 3, Name: "invalid Color", Color: "12345G"}))
|
|
||||||
for _, label := range labels {
|
|
||||||
unittest.AssertNotExistsBean(t, label)
|
|
||||||
}
|
|
||||||
assert.NoError(t, NewLabels(labels...))
|
|
||||||
for _, label := range labels {
|
|
||||||
unittest.AssertExistsAndLoadBean(t, label, unittest.Cond("id = ?", label.ID))
|
|
||||||
}
|
|
||||||
unittest.CheckConsistencyFor(t, &Label{}, &repo_model.Repository{})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetLabelByID(t *testing.T) {
|
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
|
||||||
label, err := GetLabelByID(db.DefaultContext, 1)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.EqualValues(t, 1, label.ID)
|
|
||||||
|
|
||||||
_, err = GetLabelByID(db.DefaultContext, unittest.NonexistentID)
|
|
||||||
assert.True(t, IsErrLabelNotExist(err))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetLabelInRepoByName(t *testing.T) {
|
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
|
||||||
label, err := GetLabelInRepoByName(db.DefaultContext, 1, "label1")
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.EqualValues(t, 1, label.ID)
|
|
||||||
assert.Equal(t, "label1", label.Name)
|
|
||||||
|
|
||||||
_, err = GetLabelInRepoByName(db.DefaultContext, 1, "")
|
|
||||||
assert.True(t, IsErrRepoLabelNotExist(err))
|
|
||||||
|
|
||||||
_, err = GetLabelInRepoByName(db.DefaultContext, unittest.NonexistentID, "nonexistent")
|
|
||||||
assert.True(t, IsErrRepoLabelNotExist(err))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetLabelInRepoByNames(t *testing.T) {
|
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
|
||||||
labelIDs, err := GetLabelIDsInRepoByNames(1, []string{"label1", "label2"})
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
assert.Len(t, labelIDs, 2)
|
|
||||||
|
|
||||||
assert.Equal(t, int64(1), labelIDs[0])
|
|
||||||
assert.Equal(t, int64(2), labelIDs[1])
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetLabelInRepoByNamesDiscardsNonExistentLabels(t *testing.T) {
|
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
|
||||||
// label3 doesn't exists.. See labels.yml
|
|
||||||
labelIDs, err := GetLabelIDsInRepoByNames(1, []string{"label1", "label2", "label3"})
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
assert.Len(t, labelIDs, 2)
|
|
||||||
|
|
||||||
assert.Equal(t, int64(1), labelIDs[0])
|
|
||||||
assert.Equal(t, int64(2), labelIDs[1])
|
|
||||||
assert.NoError(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetLabelInRepoByID(t *testing.T) {
|
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
|
||||||
label, err := GetLabelInRepoByID(db.DefaultContext, 1, 1)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.EqualValues(t, 1, label.ID)
|
|
||||||
|
|
||||||
_, err = GetLabelInRepoByID(db.DefaultContext, 1, -1)
|
|
||||||
assert.True(t, IsErrRepoLabelNotExist(err))
|
|
||||||
|
|
||||||
_, err = GetLabelInRepoByID(db.DefaultContext, unittest.NonexistentID, unittest.NonexistentID)
|
|
||||||
assert.True(t, IsErrRepoLabelNotExist(err))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetLabelsInRepoByIDs(t *testing.T) {
|
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
|
||||||
labels, err := GetLabelsInRepoByIDs(1, []int64{1, 2, unittest.NonexistentID})
|
|
||||||
assert.NoError(t, err)
|
|
||||||
if assert.Len(t, labels, 2) {
|
|
||||||
assert.EqualValues(t, 1, labels[0].ID)
|
|
||||||
assert.EqualValues(t, 2, labels[1].ID)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetLabelsByRepoID(t *testing.T) {
|
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
|
||||||
testSuccess := func(repoID int64, sortType string, expectedIssueIDs []int64) {
|
|
||||||
labels, err := GetLabelsByRepoID(db.DefaultContext, repoID, sortType, db.ListOptions{})
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Len(t, labels, len(expectedIssueIDs))
|
|
||||||
for i, label := range labels {
|
|
||||||
assert.EqualValues(t, expectedIssueIDs[i], label.ID)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
testSuccess(1, "leastissues", []int64{2, 1})
|
|
||||||
testSuccess(1, "mostissues", []int64{1, 2})
|
|
||||||
testSuccess(1, "reversealphabetically", []int64{2, 1})
|
|
||||||
testSuccess(1, "default", []int64{1, 2})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Org versions
|
|
||||||
|
|
||||||
func TestGetLabelInOrgByName(t *testing.T) {
|
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
|
||||||
label, err := GetLabelInOrgByName(db.DefaultContext, 3, "orglabel3")
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.EqualValues(t, 3, label.ID)
|
|
||||||
assert.Equal(t, "orglabel3", label.Name)
|
|
||||||
|
|
||||||
_, err = GetLabelInOrgByName(db.DefaultContext, 3, "")
|
|
||||||
assert.True(t, IsErrOrgLabelNotExist(err))
|
|
||||||
|
|
||||||
_, err = GetLabelInOrgByName(db.DefaultContext, 0, "orglabel3")
|
|
||||||
assert.True(t, IsErrOrgLabelNotExist(err))
|
|
||||||
|
|
||||||
_, err = GetLabelInOrgByName(db.DefaultContext, -1, "orglabel3")
|
|
||||||
assert.True(t, IsErrOrgLabelNotExist(err))
|
|
||||||
|
|
||||||
_, err = GetLabelInOrgByName(db.DefaultContext, unittest.NonexistentID, "nonexistent")
|
|
||||||
assert.True(t, IsErrOrgLabelNotExist(err))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetLabelInOrgByNames(t *testing.T) {
|
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
|
||||||
labelIDs, err := GetLabelIDsInOrgByNames(3, []string{"orglabel3", "orglabel4"})
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
assert.Len(t, labelIDs, 2)
|
|
||||||
|
|
||||||
assert.Equal(t, int64(3), labelIDs[0])
|
|
||||||
assert.Equal(t, int64(4), labelIDs[1])
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetLabelInOrgByNamesDiscardsNonExistentLabels(t *testing.T) {
|
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
|
||||||
// orglabel99 doesn't exists.. See labels.yml
|
|
||||||
labelIDs, err := GetLabelIDsInOrgByNames(3, []string{"orglabel3", "orglabel4", "orglabel99"})
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
assert.Len(t, labelIDs, 2)
|
|
||||||
|
|
||||||
assert.Equal(t, int64(3), labelIDs[0])
|
|
||||||
assert.Equal(t, int64(4), labelIDs[1])
|
|
||||||
assert.NoError(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetLabelInOrgByID(t *testing.T) {
|
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
|
||||||
label, err := GetLabelInOrgByID(db.DefaultContext, 3, 3)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.EqualValues(t, 3, label.ID)
|
|
||||||
|
|
||||||
_, err = GetLabelInOrgByID(db.DefaultContext, 3, -1)
|
|
||||||
assert.True(t, IsErrOrgLabelNotExist(err))
|
|
||||||
|
|
||||||
_, err = GetLabelInOrgByID(db.DefaultContext, 0, 3)
|
|
||||||
assert.True(t, IsErrOrgLabelNotExist(err))
|
|
||||||
|
|
||||||
_, err = GetLabelInOrgByID(db.DefaultContext, -1, 3)
|
|
||||||
assert.True(t, IsErrOrgLabelNotExist(err))
|
|
||||||
|
|
||||||
_, err = GetLabelInOrgByID(db.DefaultContext, unittest.NonexistentID, unittest.NonexistentID)
|
|
||||||
assert.True(t, IsErrOrgLabelNotExist(err))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetLabelsInOrgByIDs(t *testing.T) {
|
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
|
||||||
labels, err := GetLabelsInOrgByIDs(3, []int64{3, 4, unittest.NonexistentID})
|
|
||||||
assert.NoError(t, err)
|
|
||||||
if assert.Len(t, labels, 2) {
|
|
||||||
assert.EqualValues(t, 3, labels[0].ID)
|
|
||||||
assert.EqualValues(t, 4, labels[1].ID)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetLabelsByOrgID(t *testing.T) {
|
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
|
||||||
testSuccess := func(orgID int64, sortType string, expectedIssueIDs []int64) {
|
|
||||||
labels, err := GetLabelsByOrgID(db.DefaultContext, orgID, sortType, db.ListOptions{})
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Len(t, labels, len(expectedIssueIDs))
|
|
||||||
for i, label := range labels {
|
|
||||||
assert.EqualValues(t, expectedIssueIDs[i], label.ID)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
testSuccess(3, "leastissues", []int64{3, 4})
|
|
||||||
testSuccess(3, "mostissues", []int64{4, 3})
|
|
||||||
testSuccess(3, "reversealphabetically", []int64{4, 3})
|
|
||||||
testSuccess(3, "default", []int64{3, 4})
|
|
||||||
|
|
||||||
var err error
|
|
||||||
_, err = GetLabelsByOrgID(db.DefaultContext, 0, "leastissues", db.ListOptions{})
|
|
||||||
assert.True(t, IsErrOrgLabelNotExist(err))
|
|
||||||
|
|
||||||
_, err = GetLabelsByOrgID(db.DefaultContext, -1, "leastissues", db.ListOptions{})
|
|
||||||
assert.True(t, IsErrOrgLabelNotExist(err))
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
|
|
||||||
func TestGetLabelsByIssueID(t *testing.T) {
|
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
|
||||||
labels, err := GetLabelsByIssueID(db.DefaultContext, 1)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
if assert.Len(t, labels, 1) {
|
|
||||||
assert.EqualValues(t, 1, labels[0].ID)
|
|
||||||
}
|
|
||||||
|
|
||||||
labels, err = GetLabelsByIssueID(db.DefaultContext, unittest.NonexistentID)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Len(t, labels, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestUpdateLabel(t *testing.T) {
|
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
|
||||||
label := unittest.AssertExistsAndLoadBean(t, &Label{ID: 1}).(*Label)
|
|
||||||
// make sure update wont overwrite it
|
|
||||||
update := &Label{
|
|
||||||
ID: label.ID,
|
|
||||||
Color: "#ffff00",
|
|
||||||
Name: "newLabelName",
|
|
||||||
Description: label.Description,
|
|
||||||
}
|
|
||||||
label.Color = update.Color
|
|
||||||
label.Name = update.Name
|
|
||||||
assert.NoError(t, UpdateLabel(update))
|
|
||||||
newLabel := unittest.AssertExistsAndLoadBean(t, &Label{ID: 1}).(*Label)
|
|
||||||
assert.EqualValues(t, label.ID, newLabel.ID)
|
|
||||||
assert.EqualValues(t, label.Color, newLabel.Color)
|
|
||||||
assert.EqualValues(t, label.Name, newLabel.Name)
|
|
||||||
assert.EqualValues(t, label.Description, newLabel.Description)
|
|
||||||
unittest.CheckConsistencyFor(t, &Label{}, &repo_model.Repository{})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDeleteLabel(t *testing.T) {
|
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
|
||||||
label := unittest.AssertExistsAndLoadBean(t, &Label{ID: 1}).(*Label)
|
|
||||||
assert.NoError(t, DeleteLabel(label.RepoID, label.ID))
|
|
||||||
unittest.AssertNotExistsBean(t, &Label{ID: label.ID, RepoID: label.RepoID})
|
|
||||||
|
|
||||||
assert.NoError(t, DeleteLabel(label.RepoID, label.ID))
|
|
||||||
unittest.AssertNotExistsBean(t, &Label{ID: label.ID})
|
|
||||||
|
|
||||||
assert.NoError(t, DeleteLabel(unittest.NonexistentID, unittest.NonexistentID))
|
|
||||||
unittest.CheckConsistencyFor(t, &Label{}, &repo_model.Repository{})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestHasIssueLabel(t *testing.T) {
|
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
|
||||||
assert.True(t, HasIssueLabel(db.DefaultContext, 1, 1))
|
|
||||||
assert.False(t, HasIssueLabel(db.DefaultContext, 1, 2))
|
|
||||||
assert.False(t, HasIssueLabel(db.DefaultContext, unittest.NonexistentID, unittest.NonexistentID))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNewIssueLabel(t *testing.T) {
|
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
|
||||||
label := unittest.AssertExistsAndLoadBean(t, &Label{ID: 2}).(*Label)
|
|
||||||
issue := unittest.AssertExistsAndLoadBean(t, &Issue{ID: 1}).(*Issue)
|
|
||||||
doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
|
|
||||||
|
|
||||||
// add new IssueLabel
|
|
||||||
prevNumIssues := label.NumIssues
|
|
||||||
assert.NoError(t, NewIssueLabel(issue, label, doer))
|
|
||||||
unittest.AssertExistsAndLoadBean(t, &IssueLabel{IssueID: issue.ID, LabelID: label.ID})
|
|
||||||
unittest.AssertExistsAndLoadBean(t, &Comment{
|
|
||||||
Type: CommentTypeLabel,
|
|
||||||
PosterID: doer.ID,
|
|
||||||
IssueID: issue.ID,
|
|
||||||
LabelID: label.ID,
|
|
||||||
Content: "1",
|
|
||||||
})
|
|
||||||
label = unittest.AssertExistsAndLoadBean(t, &Label{ID: 2}).(*Label)
|
|
||||||
assert.EqualValues(t, prevNumIssues+1, label.NumIssues)
|
|
||||||
|
|
||||||
// re-add existing IssueLabel
|
|
||||||
assert.NoError(t, NewIssueLabel(issue, label, doer))
|
|
||||||
unittest.CheckConsistencyFor(t, &Issue{}, &Label{})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNewIssueLabels(t *testing.T) {
|
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
|
||||||
label1 := unittest.AssertExistsAndLoadBean(t, &Label{ID: 1}).(*Label)
|
|
||||||
label2 := unittest.AssertExistsAndLoadBean(t, &Label{ID: 2}).(*Label)
|
|
||||||
issue := unittest.AssertExistsAndLoadBean(t, &Issue{ID: 5}).(*Issue)
|
|
||||||
doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
|
|
||||||
|
|
||||||
assert.NoError(t, NewIssueLabels(issue, []*Label{label1, label2}, doer))
|
|
||||||
unittest.AssertExistsAndLoadBean(t, &IssueLabel{IssueID: issue.ID, LabelID: label1.ID})
|
|
||||||
unittest.AssertExistsAndLoadBean(t, &Comment{
|
|
||||||
Type: CommentTypeLabel,
|
|
||||||
PosterID: doer.ID,
|
|
||||||
IssueID: issue.ID,
|
|
||||||
LabelID: label1.ID,
|
|
||||||
Content: "1",
|
|
||||||
})
|
|
||||||
unittest.AssertExistsAndLoadBean(t, &IssueLabel{IssueID: issue.ID, LabelID: label1.ID})
|
|
||||||
label1 = unittest.AssertExistsAndLoadBean(t, &Label{ID: 1}).(*Label)
|
|
||||||
assert.EqualValues(t, 3, label1.NumIssues)
|
|
||||||
assert.EqualValues(t, 1, label1.NumClosedIssues)
|
|
||||||
label2 = unittest.AssertExistsAndLoadBean(t, &Label{ID: 2}).(*Label)
|
|
||||||
assert.EqualValues(t, 1, label2.NumIssues)
|
|
||||||
assert.EqualValues(t, 1, label2.NumClosedIssues)
|
|
||||||
|
|
||||||
// corner case: test empty slice
|
|
||||||
assert.NoError(t, NewIssueLabels(issue, []*Label{}, doer))
|
|
||||||
|
|
||||||
unittest.CheckConsistencyFor(t, &Issue{}, &Label{})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDeleteIssueLabel(t *testing.T) {
|
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
|
||||||
testSuccess := func(labelID, issueID, doerID int64) {
|
|
||||||
label := unittest.AssertExistsAndLoadBean(t, &Label{ID: labelID}).(*Label)
|
|
||||||
issue := unittest.AssertExistsAndLoadBean(t, &Issue{ID: issueID}).(*Issue)
|
|
||||||
doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: doerID}).(*user_model.User)
|
|
||||||
|
|
||||||
expectedNumIssues := label.NumIssues
|
|
||||||
expectedNumClosedIssues := label.NumClosedIssues
|
|
||||||
if unittest.BeanExists(t, &IssueLabel{IssueID: issueID, LabelID: labelID}) {
|
|
||||||
expectedNumIssues--
|
|
||||||
if issue.IsClosed {
|
|
||||||
expectedNumClosedIssues--
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx, committer, err := db.TxContext()
|
|
||||||
defer committer.Close()
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.NoError(t, DeleteIssueLabel(ctx, issue, label, doer))
|
|
||||||
assert.NoError(t, committer.Commit())
|
|
||||||
|
|
||||||
unittest.AssertNotExistsBean(t, &IssueLabel{IssueID: issueID, LabelID: labelID})
|
|
||||||
unittest.AssertExistsAndLoadBean(t, &Comment{
|
|
||||||
Type: CommentTypeLabel,
|
|
||||||
PosterID: doerID,
|
|
||||||
IssueID: issueID,
|
|
||||||
LabelID: labelID,
|
|
||||||
}, `content=""`)
|
|
||||||
label = unittest.AssertExistsAndLoadBean(t, &Label{ID: labelID}).(*Label)
|
|
||||||
assert.EqualValues(t, expectedNumIssues, label.NumIssues)
|
|
||||||
assert.EqualValues(t, expectedNumClosedIssues, label.NumClosedIssues)
|
|
||||||
}
|
|
||||||
testSuccess(1, 1, 2)
|
|
||||||
testSuccess(2, 5, 2)
|
|
||||||
testSuccess(1, 1, 2) // delete non-existent IssueLabel
|
|
||||||
|
|
||||||
unittest.CheckConsistencyFor(t, &Issue{}, &Label{})
|
|
||||||
}
|
|
|
@ -1,78 +0,0 @@
|
||||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a MIT-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package models
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
|
||||||
"code.gitea.io/gitea/models/unittest"
|
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
|
||||||
"code.gitea.io/gitea/modules/timeutil"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestCancelStopwatch(t *testing.T) {
|
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
|
||||||
|
|
||||||
user1, err := user_model.GetUserByID(1)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
issue1, err := GetIssueByID(1)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
issue2, err := GetIssueByID(2)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
err = CancelStopwatch(user1, issue1)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
unittest.AssertNotExistsBean(t, &Stopwatch{UserID: user1.ID, IssueID: issue1.ID})
|
|
||||||
|
|
||||||
_ = unittest.AssertExistsAndLoadBean(t, &Comment{Type: CommentTypeCancelTracking, PosterID: user1.ID, IssueID: issue1.ID})
|
|
||||||
|
|
||||||
assert.Nil(t, CancelStopwatch(user1, issue2))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestStopwatchExists(t *testing.T) {
|
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
|
||||||
|
|
||||||
assert.True(t, StopwatchExists(1, 1))
|
|
||||||
assert.False(t, StopwatchExists(1, 2))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestHasUserStopwatch(t *testing.T) {
|
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
|
||||||
|
|
||||||
exists, sw, err := HasUserStopwatch(db.DefaultContext, 1)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.True(t, exists)
|
|
||||||
assert.Equal(t, int64(1), sw.ID)
|
|
||||||
|
|
||||||
exists, _, err = HasUserStopwatch(db.DefaultContext, 3)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.False(t, exists)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCreateOrStopIssueStopwatch(t *testing.T) {
|
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
|
||||||
|
|
||||||
user2, err := user_model.GetUserByID(2)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
user3, err := user_model.GetUserByID(3)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
issue1, err := GetIssueByID(1)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
issue2, err := GetIssueByID(2)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
assert.NoError(t, CreateOrStopIssueStopwatch(user3, issue1))
|
|
||||||
sw := unittest.AssertExistsAndLoadBean(t, &Stopwatch{UserID: 3, IssueID: 1}).(*Stopwatch)
|
|
||||||
assert.LessOrEqual(t, sw.CreatedUnix, timeutil.TimeStampNow())
|
|
||||||
|
|
||||||
assert.NoError(t, CreateOrStopIssueStopwatch(user2, issue2))
|
|
||||||
unittest.AssertNotExistsBean(t, &Stopwatch{UserID: 2, IssueID: 2})
|
|
||||||
unittest.AssertExistsAndLoadBean(t, &TrackedTime{UserID: 2, IssueID: 2})
|
|
||||||
}
|
|
|
@ -1,61 +0,0 @@
|
||||||
// Copyright 2017 The Gogs Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a MIT-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package models
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
|
||||||
"code.gitea.io/gitea/models/unittest"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Test_newIssueUsers(t *testing.T) {
|
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
|
||||||
|
|
||||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository)
|
|
||||||
newIssue := &Issue{
|
|
||||||
RepoID: repo.ID,
|
|
||||||
PosterID: 4,
|
|
||||||
Index: 6,
|
|
||||||
Title: "newTestIssueTitle",
|
|
||||||
Content: "newTestIssueContent",
|
|
||||||
}
|
|
||||||
|
|
||||||
// artificially insert new issue
|
|
||||||
unittest.AssertSuccessfulInsert(t, newIssue)
|
|
||||||
|
|
||||||
assert.NoError(t, newIssueUsers(db.DefaultContext, repo, newIssue))
|
|
||||||
|
|
||||||
// issue_user table should now have entries for new issue
|
|
||||||
unittest.AssertExistsAndLoadBean(t, &IssueUser{IssueID: newIssue.ID, UID: newIssue.PosterID})
|
|
||||||
unittest.AssertExistsAndLoadBean(t, &IssueUser{IssueID: newIssue.ID, UID: repo.OwnerID})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestUpdateIssueUserByRead(t *testing.T) {
|
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
|
||||||
issue := unittest.AssertExistsAndLoadBean(t, &Issue{ID: 1}).(*Issue)
|
|
||||||
|
|
||||||
assert.NoError(t, UpdateIssueUserByRead(4, issue.ID))
|
|
||||||
unittest.AssertExistsAndLoadBean(t, &IssueUser{IssueID: issue.ID, UID: 4}, "is_read=1")
|
|
||||||
|
|
||||||
assert.NoError(t, UpdateIssueUserByRead(4, issue.ID))
|
|
||||||
unittest.AssertExistsAndLoadBean(t, &IssueUser{IssueID: issue.ID, UID: 4}, "is_read=1")
|
|
||||||
|
|
||||||
assert.NoError(t, UpdateIssueUserByRead(unittest.NonexistentID, unittest.NonexistentID))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestUpdateIssueUsersByMentions(t *testing.T) {
|
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
|
||||||
issue := unittest.AssertExistsAndLoadBean(t, &Issue{ID: 1}).(*Issue)
|
|
||||||
|
|
||||||
uids := []int64{2, 5}
|
|
||||||
assert.NoError(t, UpdateIssueUsersByMentions(db.DefaultContext, issue.ID, uids))
|
|
||||||
for _, uid := range uids {
|
|
||||||
unittest.AssertExistsAndLoadBean(t, &IssueUser{IssueID: issue.ID, UID: uid}, "is_mentioned=1")
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -2,7 +2,7 @@
|
||||||
// Use of this source code is governed by a MIT-style
|
// Use of this source code is governed by a MIT-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package models
|
package issues
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
|
@ -2,12 +2,13 @@
|
||||||
// Use of this source code is governed by a MIT-style
|
// Use of this source code is governed by a MIT-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package models
|
package issues_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
|
||||||
|
@ -18,27 +19,27 @@ func TestUpdateAssignee(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
// Fake issue with assignees
|
// Fake issue with assignees
|
||||||
issue, err := GetIssueWithAttrsByID(1)
|
issue, err := issues_model.GetIssueWithAttrsByID(1)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// Assign multiple users
|
// Assign multiple users
|
||||||
user2, err := user_model.GetUserByID(2)
|
user2, err := user_model.GetUserByID(2)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
_, _, err = ToggleIssueAssignee(issue, &user_model.User{ID: 1}, user2.ID)
|
_, _, err = issues_model.ToggleIssueAssignee(issue, &user_model.User{ID: 1}, user2.ID)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
user3, err := user_model.GetUserByID(3)
|
user3, err := user_model.GetUserByID(3)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
_, _, err = ToggleIssueAssignee(issue, &user_model.User{ID: 1}, user3.ID)
|
_, _, err = issues_model.ToggleIssueAssignee(issue, &user_model.User{ID: 1}, user3.ID)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
user1, err := user_model.GetUserByID(1) // This user is already assigned (see the definition in fixtures), so running UpdateAssignee should unassign him
|
user1, err := user_model.GetUserByID(1) // This user is already assigned (see the definition in fixtures), so running UpdateAssignee should unassign him
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
_, _, err = ToggleIssueAssignee(issue, &user_model.User{ID: 1}, user1.ID)
|
_, _, err = issues_model.ToggleIssueAssignee(issue, &user_model.User{ID: 1}, user1.ID)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// Check if he got removed
|
// Check if he got removed
|
||||||
isAssigned, err := IsUserAssignedToIssue(db.DefaultContext, issue, user1)
|
isAssigned, err := issues_model.IsUserAssignedToIssue(db.DefaultContext, issue, user1)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.False(t, isAssigned)
|
assert.False(t, isAssigned)
|
||||||
|
|
||||||
|
@ -54,12 +55,12 @@ func TestUpdateAssignee(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the user is assigned
|
// Check if the user is assigned
|
||||||
isAssigned, err = IsUserAssignedToIssue(db.DefaultContext, issue, user2)
|
isAssigned, err = issues_model.IsUserAssignedToIssue(db.DefaultContext, issue, user2)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.True(t, isAssigned)
|
assert.True(t, isAssigned)
|
||||||
|
|
||||||
// This user should not be assigned
|
// This user should not be assigned
|
||||||
isAssigned, err = IsUserAssignedToIssue(db.DefaultContext, issue, &user_model.User{ID: 4})
|
isAssigned, err = issues_model.IsUserAssignedToIssue(db.DefaultContext, issue, &user_model.User{ID: 4})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.False(t, isAssigned)
|
assert.False(t, isAssigned)
|
||||||
}
|
}
|
||||||
|
@ -70,22 +71,22 @@ func TestMakeIDsFromAPIAssigneesToAdd(t *testing.T) {
|
||||||
_ = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User)
|
_ = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User)
|
||||||
_ = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
|
_ = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
|
||||||
|
|
||||||
IDs, err := MakeIDsFromAPIAssigneesToAdd("", []string{""})
|
IDs, err := issues_model.MakeIDsFromAPIAssigneesToAdd("", []string{""})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, []int64{}, IDs)
|
assert.Equal(t, []int64{}, IDs)
|
||||||
|
|
||||||
_, err = MakeIDsFromAPIAssigneesToAdd("", []string{"none_existing_user"})
|
_, err = issues_model.MakeIDsFromAPIAssigneesToAdd("", []string{"none_existing_user"})
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
|
|
||||||
IDs, err = MakeIDsFromAPIAssigneesToAdd("user1", []string{"user1"})
|
IDs, err = issues_model.MakeIDsFromAPIAssigneesToAdd("user1", []string{"user1"})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, []int64{1}, IDs)
|
assert.Equal(t, []int64{1}, IDs)
|
||||||
|
|
||||||
IDs, err = MakeIDsFromAPIAssigneesToAdd("user2", []string{""})
|
IDs, err = issues_model.MakeIDsFromAPIAssigneesToAdd("user2", []string{""})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, []int64{2}, IDs)
|
assert.Equal(t, []int64{2}, IDs)
|
||||||
|
|
||||||
IDs, err = MakeIDsFromAPIAssigneesToAdd("", []string{"user1", "user2"})
|
IDs, err = issues_model.MakeIDsFromAPIAssigneesToAdd("", []string{"user1", "user2"})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, []int64{1, 2}, IDs)
|
assert.Equal(t, []int64{1, 2}, IDs)
|
||||||
}
|
}
|
|
@ -4,7 +4,7 @@
|
||||||
// Use of this source code is governed by a MIT-style
|
// Use of this source code is governed by a MIT-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package models
|
package issues
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
@ -16,7 +16,6 @@ import (
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
git_model "code.gitea.io/gitea/models/git"
|
git_model "code.gitea.io/gitea/models/git"
|
||||||
issues_model "code.gitea.io/gitea/models/issues"
|
|
||||||
"code.gitea.io/gitea/models/organization"
|
"code.gitea.io/gitea/models/organization"
|
||||||
project_model "code.gitea.io/gitea/models/project"
|
project_model "code.gitea.io/gitea/models/project"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
|
@ -34,6 +33,22 @@ import (
|
||||||
"xorm.io/xorm"
|
"xorm.io/xorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ErrCommentNotExist represents a "CommentNotExist" kind of error.
|
||||||
|
type ErrCommentNotExist struct {
|
||||||
|
ID int64
|
||||||
|
IssueID int64
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsErrCommentNotExist checks if an error is a ErrCommentNotExist.
|
||||||
|
func IsErrCommentNotExist(err error) bool {
|
||||||
|
_, ok := err.(ErrCommentNotExist)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err ErrCommentNotExist) Error() string {
|
||||||
|
return fmt.Sprintf("comment does not exist [id: %d, issue_id: %d]", err.ID, err.IssueID)
|
||||||
|
}
|
||||||
|
|
||||||
// CommentType defines whether a comment is just a simple comment, an action (like close) or a reference.
|
// CommentType defines whether a comment is just a simple comment, an action (like close) or a reference.
|
||||||
type CommentType int
|
type CommentType int
|
||||||
|
|
||||||
|
@ -216,8 +231,8 @@ type Comment struct {
|
||||||
Project *project_model.Project `xorm:"-"`
|
Project *project_model.Project `xorm:"-"`
|
||||||
OldMilestoneID int64
|
OldMilestoneID int64
|
||||||
MilestoneID int64
|
MilestoneID int64
|
||||||
OldMilestone *issues_model.Milestone `xorm:"-"`
|
OldMilestone *Milestone `xorm:"-"`
|
||||||
Milestone *issues_model.Milestone `xorm:"-"`
|
Milestone *Milestone `xorm:"-"`
|
||||||
TimeID int64
|
TimeID int64
|
||||||
Time *TrackedTime `xorm:"-"`
|
Time *TrackedTime `xorm:"-"`
|
||||||
AssigneeID int64
|
AssigneeID int64
|
||||||
|
@ -251,7 +266,7 @@ type Comment struct {
|
||||||
CommitSHA string `xorm:"VARCHAR(40)"`
|
CommitSHA string `xorm:"VARCHAR(40)"`
|
||||||
|
|
||||||
Attachments []*repo_model.Attachment `xorm:"-"`
|
Attachments []*repo_model.Attachment `xorm:"-"`
|
||||||
Reactions issues_model.ReactionList `xorm:"-"`
|
Reactions ReactionList `xorm:"-"`
|
||||||
|
|
||||||
// For view issue page.
|
// For view issue page.
|
||||||
ShowRole RoleDescriptor `xorm:"-"`
|
ShowRole RoleDescriptor `xorm:"-"`
|
||||||
|
@ -299,7 +314,7 @@ func (c *Comment) LoadIssueCtx(ctx context.Context) (err error) {
|
||||||
if c.Issue != nil {
|
if c.Issue != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
c.Issue, err = getIssueByID(ctx, c.IssueID)
|
c.Issue, err = GetIssueByID(ctx, c.IssueID)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -503,7 +518,7 @@ func (c *Comment) LoadProject() error {
|
||||||
// LoadMilestone if comment.Type is CommentTypeMilestone, then load milestone
|
// LoadMilestone if comment.Type is CommentTypeMilestone, then load milestone
|
||||||
func (c *Comment) LoadMilestone() error {
|
func (c *Comment) LoadMilestone() error {
|
||||||
if c.OldMilestoneID > 0 {
|
if c.OldMilestoneID > 0 {
|
||||||
var oldMilestone issues_model.Milestone
|
var oldMilestone Milestone
|
||||||
has, err := db.GetEngine(db.DefaultContext).ID(c.OldMilestoneID).Get(&oldMilestone)
|
has, err := db.GetEngine(db.DefaultContext).ID(c.OldMilestoneID).Get(&oldMilestone)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -513,7 +528,7 @@ func (c *Comment) LoadMilestone() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.MilestoneID > 0 {
|
if c.MilestoneID > 0 {
|
||||||
var milestone issues_model.Milestone
|
var milestone Milestone
|
||||||
has, err := db.GetEngine(db.DefaultContext).ID(c.MilestoneID).Get(&milestone)
|
has, err := db.GetEngine(db.DefaultContext).ID(c.MilestoneID).Get(&milestone)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -625,7 +640,7 @@ func (c *Comment) LoadDepIssueDetails() (err error) {
|
||||||
if c.DependentIssueID <= 0 || c.DependentIssue != nil {
|
if c.DependentIssueID <= 0 || c.DependentIssue != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
c.DependentIssue, err = getIssueByID(db.DefaultContext, c.DependentIssueID)
|
c.DependentIssue, err = GetIssueByID(db.DefaultContext, c.DependentIssueID)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -643,7 +658,7 @@ func (c *Comment) loadReactions(ctx context.Context, repo *repo_model.Repository
|
||||||
if c.Reactions != nil {
|
if c.Reactions != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
c.Reactions, _, err = issues_model.FindReactions(ctx, issues_model.FindReactionsOptions{
|
c.Reactions, _, err = FindReactions(ctx, FindReactionsOptions{
|
||||||
IssueID: c.IssueID,
|
IssueID: c.IssueID,
|
||||||
CommentID: c.ID,
|
CommentID: c.ID,
|
||||||
})
|
})
|
||||||
|
@ -823,7 +838,7 @@ func CreateCommentCtx(ctx context.Context, opts *CreateCommentOptions) (_ *Comme
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = comment.addCrossReferences(ctx, opts.Doer, false); err != nil {
|
if err = comment.AddCrossReferences(ctx, opts.Doer, false); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1128,7 +1143,7 @@ func UpdateComment(c *Comment, doer *user_model.User) error {
|
||||||
if err := c.LoadIssueCtx(ctx); err != nil {
|
if err := c.LoadIssueCtx(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := c.addCrossReferences(ctx, doer, true); err != nil {
|
if err := c.AddCrossReferences(ctx, doer, true); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := committer.Commit(); err != nil {
|
if err := committer.Commit(); err != nil {
|
||||||
|
@ -1139,27 +1154,13 @@ func UpdateComment(c *Comment, doer *user_model.User) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteComment deletes the comment
|
// DeleteComment deletes the comment
|
||||||
func DeleteComment(comment *Comment) error {
|
func DeleteComment(ctx context.Context, comment *Comment) error {
|
||||||
ctx, committer, err := db.TxContext()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer committer.Close()
|
|
||||||
|
|
||||||
if err := deleteComment(ctx, comment); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return committer.Commit()
|
|
||||||
}
|
|
||||||
|
|
||||||
func deleteComment(ctx context.Context, comment *Comment) error {
|
|
||||||
e := db.GetEngine(ctx)
|
e := db.GetEngine(ctx)
|
||||||
if _, err := e.ID(comment.ID).NoAutoCondition().Delete(comment); err != nil {
|
if _, err := e.ID(comment.ID).NoAutoCondition().Delete(comment); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := db.DeleteByBean(ctx, &issues_model.ContentHistory{
|
if _, err := db.DeleteByBean(ctx, &ContentHistory{
|
||||||
CommentID: comment.ID,
|
CommentID: comment.ID,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -1170,7 +1171,11 @@ func deleteComment(ctx context.Context, comment *Comment) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if _, err := e.Where("comment_id = ?", comment.ID).Cols("is_deleted").Update(&Action{IsDeleted: true}); err != nil {
|
if _, err := e.Table("action").
|
||||||
|
Where("comment_id = ?", comment.ID).
|
||||||
|
Update(map[string]interface{}{
|
||||||
|
"is_deleted": true,
|
||||||
|
}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1178,7 +1183,7 @@ func deleteComment(ctx context.Context, comment *Comment) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return issues_model.DeleteReaction(ctx, &issues_model.ReactionOptions{CommentID: comment.ID})
|
return DeleteReaction(ctx, &ReactionOptions{CommentID: comment.ID})
|
||||||
}
|
}
|
||||||
|
|
||||||
// CodeComments represents comments on code by using this structure: FILENAME -> LINE (+ == proposed; - == previous) -> COMMENTS
|
// CodeComments represents comments on code by using this structure: FILENAME -> LINE (+ == proposed; - == previous) -> COMMENTS
|
||||||
|
@ -1500,3 +1505,42 @@ func (c *Comment) GetExternalName() string { return c.OriginalAuthor }
|
||||||
|
|
||||||
// GetExternalID ExternalUserRemappable interface
|
// GetExternalID ExternalUserRemappable interface
|
||||||
func (c *Comment) GetExternalID() int64 { return c.OriginalAuthorID }
|
func (c *Comment) GetExternalID() int64 { return c.OriginalAuthorID }
|
||||||
|
|
||||||
|
// CountCommentTypeLabelWithEmptyLabel count label comments with empty label
|
||||||
|
func CountCommentTypeLabelWithEmptyLabel() (int64, error) {
|
||||||
|
return db.GetEngine(db.DefaultContext).Where(builder.Eq{"type": CommentTypeLabel, "label_id": 0}).Count(new(Comment))
|
||||||
|
}
|
||||||
|
|
||||||
|
// FixCommentTypeLabelWithEmptyLabel count label comments with empty label
|
||||||
|
func FixCommentTypeLabelWithEmptyLabel() (int64, error) {
|
||||||
|
return db.GetEngine(db.DefaultContext).Where(builder.Eq{"type": CommentTypeLabel, "label_id": 0}).Delete(new(Comment))
|
||||||
|
}
|
||||||
|
|
||||||
|
// CountCommentTypeLabelWithOutsideLabels count label comments with outside label
|
||||||
|
func CountCommentTypeLabelWithOutsideLabels() (int64, error) {
|
||||||
|
return db.GetEngine(db.DefaultContext).Where("comment.type = ? AND ((label.org_id = 0 AND issue.repo_id != label.repo_id) OR (label.repo_id = 0 AND label.org_id != repository.owner_id))", CommentTypeLabel).
|
||||||
|
Table("comment").
|
||||||
|
Join("inner", "label", "label.id = comment.label_id").
|
||||||
|
Join("inner", "issue", "issue.id = comment.issue_id ").
|
||||||
|
Join("inner", "repository", "issue.repo_id = repository.id").
|
||||||
|
Count()
|
||||||
|
}
|
||||||
|
|
||||||
|
// FixCommentTypeLabelWithOutsideLabels count label comments with outside label
|
||||||
|
func FixCommentTypeLabelWithOutsideLabels() (int64, error) {
|
||||||
|
res, err := db.GetEngine(db.DefaultContext).Exec(`DELETE FROM comment WHERE comment.id IN (
|
||||||
|
SELECT il_too.id FROM (
|
||||||
|
SELECT com.id
|
||||||
|
FROM comment AS com
|
||||||
|
INNER JOIN label ON com.label_id = label.id
|
||||||
|
INNER JOIN issue on issue.id = com.issue_id
|
||||||
|
INNER JOIN repository ON issue.repo_id = repository.id
|
||||||
|
WHERE
|
||||||
|
com.type = ? AND ((label.org_id = 0 AND issue.repo_id != label.repo_id) OR (label.repo_id = 0 AND label.org_id != repository.owner_id))
|
||||||
|
) AS il_too)`, CommentTypeLabel)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.RowsAffected()
|
||||||
|
}
|
|
@ -2,13 +2,12 @@
|
||||||
// Use of this source code is governed by a MIT-style
|
// Use of this source code is governed by a MIT-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package models
|
package issues
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
issues_model "code.gitea.io/gitea/models/issues"
|
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/container"
|
"code.gitea.io/gitea/modules/container"
|
||||||
|
@ -36,7 +35,7 @@ func (comments CommentList) loadPosters(ctx context.Context) error {
|
||||||
posterMaps := make(map[int64]*user_model.User, len(posterIDs))
|
posterMaps := make(map[int64]*user_model.User, len(posterIDs))
|
||||||
left := len(posterIDs)
|
left := len(posterIDs)
|
||||||
for left > 0 {
|
for left > 0 {
|
||||||
limit := defaultMaxInSize
|
limit := db.DefaultMaxInSize
|
||||||
if left < limit {
|
if left < limit {
|
||||||
limit = left
|
limit = left
|
||||||
}
|
}
|
||||||
|
@ -80,7 +79,7 @@ func (comments CommentList) getLabelIDs() []int64 {
|
||||||
return container.KeysInt64(ids)
|
return container.KeysInt64(ids)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (comments CommentList) loadLabels(ctx context.Context) error {
|
func (comments CommentList) loadLabels(ctx context.Context) error { //nolint
|
||||||
if len(comments) == 0 {
|
if len(comments) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -89,7 +88,7 @@ func (comments CommentList) loadLabels(ctx context.Context) error {
|
||||||
commentLabels := make(map[int64]*Label, len(labelIDs))
|
commentLabels := make(map[int64]*Label, len(labelIDs))
|
||||||
left := len(labelIDs)
|
left := len(labelIDs)
|
||||||
for left > 0 {
|
for left > 0 {
|
||||||
limit := defaultMaxInSize
|
limit := db.DefaultMaxInSize
|
||||||
if left < limit {
|
if left < limit {
|
||||||
limit = left
|
limit = left
|
||||||
}
|
}
|
||||||
|
@ -140,10 +139,10 @@ func (comments CommentList) loadMilestones(ctx context.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
milestoneMaps := make(map[int64]*issues_model.Milestone, len(milestoneIDs))
|
milestoneMaps := make(map[int64]*Milestone, len(milestoneIDs))
|
||||||
left := len(milestoneIDs)
|
left := len(milestoneIDs)
|
||||||
for left > 0 {
|
for left > 0 {
|
||||||
limit := defaultMaxInSize
|
limit := db.DefaultMaxInSize
|
||||||
if left < limit {
|
if left < limit {
|
||||||
limit = left
|
limit = left
|
||||||
}
|
}
|
||||||
|
@ -183,10 +182,10 @@ func (comments CommentList) loadOldMilestones(ctx context.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
milestoneMaps := make(map[int64]*issues_model.Milestone, len(milestoneIDs))
|
milestoneMaps := make(map[int64]*Milestone, len(milestoneIDs))
|
||||||
left := len(milestoneIDs)
|
left := len(milestoneIDs)
|
||||||
for left > 0 {
|
for left > 0 {
|
||||||
limit := defaultMaxInSize
|
limit := db.DefaultMaxInSize
|
||||||
if left < limit {
|
if left < limit {
|
||||||
limit = left
|
limit = left
|
||||||
}
|
}
|
||||||
|
@ -225,7 +224,7 @@ func (comments CommentList) loadAssignees(ctx context.Context) error {
|
||||||
assignees := make(map[int64]*user_model.User, len(assigneeIDs))
|
assignees := make(map[int64]*user_model.User, len(assigneeIDs))
|
||||||
left := len(assigneeIDs)
|
left := len(assigneeIDs)
|
||||||
for left > 0 {
|
for left > 0 {
|
||||||
limit := defaultMaxInSize
|
limit := db.DefaultMaxInSize
|
||||||
if left < limit {
|
if left < limit {
|
||||||
limit = left
|
limit = left
|
||||||
}
|
}
|
||||||
|
@ -299,7 +298,7 @@ func (comments CommentList) loadIssues(ctx context.Context) error {
|
||||||
issues := make(map[int64]*Issue, len(issueIDs))
|
issues := make(map[int64]*Issue, len(issueIDs))
|
||||||
left := len(issueIDs)
|
left := len(issueIDs)
|
||||||
for left > 0 {
|
for left > 0 {
|
||||||
limit := defaultMaxInSize
|
limit := db.DefaultMaxInSize
|
||||||
if left < limit {
|
if left < limit {
|
||||||
limit = left
|
limit = left
|
||||||
}
|
}
|
||||||
|
@ -357,7 +356,7 @@ func (comments CommentList) loadDependentIssues(ctx context.Context) error {
|
||||||
issues := make(map[int64]*Issue, len(issueIDs))
|
issues := make(map[int64]*Issue, len(issueIDs))
|
||||||
left := len(issueIDs)
|
left := len(issueIDs)
|
||||||
for left > 0 {
|
for left > 0 {
|
||||||
limit := defaultMaxInSize
|
limit := db.DefaultMaxInSize
|
||||||
if left < limit {
|
if left < limit {
|
||||||
limit = left
|
limit = left
|
||||||
}
|
}
|
||||||
|
@ -406,7 +405,7 @@ func (comments CommentList) loadAttachments(ctx context.Context) (err error) {
|
||||||
commentsIDs := comments.getCommentIDs()
|
commentsIDs := comments.getCommentIDs()
|
||||||
left := len(commentsIDs)
|
left := len(commentsIDs)
|
||||||
for left > 0 {
|
for left > 0 {
|
||||||
limit := defaultMaxInSize
|
limit := db.DefaultMaxInSize
|
||||||
if left < limit {
|
if left < limit {
|
||||||
limit = left
|
limit = left
|
||||||
}
|
}
|
||||||
|
@ -449,7 +448,7 @@ func (comments CommentList) getReviewIDs() []int64 {
|
||||||
return container.KeysInt64(ids)
|
return container.KeysInt64(ids)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (comments CommentList) loadReviews(ctx context.Context) error {
|
func (comments CommentList) loadReviews(ctx context.Context) error { //nolint
|
||||||
if len(comments) == 0 {
|
if len(comments) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -458,7 +457,7 @@ func (comments CommentList) loadReviews(ctx context.Context) error {
|
||||||
reviews := make(map[int64]*Review, len(reviewIDs))
|
reviews := make(map[int64]*Review, len(reviewIDs))
|
||||||
left := len(reviewIDs)
|
left := len(reviewIDs)
|
||||||
for left > 0 {
|
for left > 0 {
|
||||||
limit := defaultMaxInSize
|
limit := db.DefaultMaxInSize
|
||||||
if left < limit {
|
if left < limit {
|
||||||
limit = left
|
limit = left
|
||||||
}
|
}
|
|
@ -2,13 +2,14 @@
|
||||||
// Use of this source code is governed by a MIT-style
|
// Use of this source code is governed by a MIT-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package models
|
package issues_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
@ -19,13 +20,13 @@ import (
|
||||||
func TestCreateComment(t *testing.T) {
|
func TestCreateComment(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
issue := unittest.AssertExistsAndLoadBean(t, &Issue{}).(*Issue)
|
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{}).(*issues_model.Issue)
|
||||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID}).(*repo_model.Repository)
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID}).(*repo_model.Repository)
|
||||||
doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User)
|
doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User)
|
||||||
|
|
||||||
now := time.Now().Unix()
|
now := time.Now().Unix()
|
||||||
comment, err := CreateComment(&CreateCommentOptions{
|
comment, err := issues_model.CreateComment(&issues_model.CreateCommentOptions{
|
||||||
Type: CommentTypeComment,
|
Type: issues_model.CommentTypeComment,
|
||||||
Doer: doer,
|
Doer: doer,
|
||||||
Repo: repo,
|
Repo: repo,
|
||||||
Issue: issue,
|
Issue: issue,
|
||||||
|
@ -34,23 +35,23 @@ func TestCreateComment(t *testing.T) {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
then := time.Now().Unix()
|
then := time.Now().Unix()
|
||||||
|
|
||||||
assert.EqualValues(t, CommentTypeComment, comment.Type)
|
assert.EqualValues(t, issues_model.CommentTypeComment, comment.Type)
|
||||||
assert.EqualValues(t, "Hello", comment.Content)
|
assert.EqualValues(t, "Hello", comment.Content)
|
||||||
assert.EqualValues(t, issue.ID, comment.IssueID)
|
assert.EqualValues(t, issue.ID, comment.IssueID)
|
||||||
assert.EqualValues(t, doer.ID, comment.PosterID)
|
assert.EqualValues(t, doer.ID, comment.PosterID)
|
||||||
unittest.AssertInt64InRange(t, now, then, int64(comment.CreatedUnix))
|
unittest.AssertInt64InRange(t, now, then, int64(comment.CreatedUnix))
|
||||||
unittest.AssertExistsAndLoadBean(t, comment) // assert actually added to DB
|
unittest.AssertExistsAndLoadBean(t, comment) // assert actually added to DB
|
||||||
|
|
||||||
updatedIssue := unittest.AssertExistsAndLoadBean(t, &Issue{ID: issue.ID}).(*Issue)
|
updatedIssue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: issue.ID}).(*issues_model.Issue)
|
||||||
unittest.AssertInt64InRange(t, now, then, int64(updatedIssue.UpdatedUnix))
|
unittest.AssertInt64InRange(t, now, then, int64(updatedIssue.UpdatedUnix))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFetchCodeComments(t *testing.T) {
|
func TestFetchCodeComments(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
issue := unittest.AssertExistsAndLoadBean(t, &Issue{ID: 2}).(*Issue)
|
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2}).(*issues_model.Issue)
|
||||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User)
|
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User)
|
||||||
res, err := FetchCodeComments(db.DefaultContext, issue, user)
|
res, err := issues_model.FetchCodeComments(db.DefaultContext, issue, user)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Contains(t, res, "README.md")
|
assert.Contains(t, res, "README.md")
|
||||||
assert.Contains(t, res["README.md"], int64(4))
|
assert.Contains(t, res["README.md"], int64(4))
|
||||||
|
@ -58,7 +59,7 @@ func TestFetchCodeComments(t *testing.T) {
|
||||||
assert.Equal(t, int64(4), res["README.md"][4][0].ID)
|
assert.Equal(t, int64(4), res["README.md"][4][0].ID)
|
||||||
|
|
||||||
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
|
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
|
||||||
res, err = FetchCodeComments(db.DefaultContext, issue, user2)
|
res, err = issues_model.FetchCodeComments(db.DefaultContext, issue, user2)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Len(t, res, 1)
|
assert.Len(t, res, 1)
|
||||||
}
|
}
|
|
@ -53,13 +53,13 @@ func SaveIssueContentHistory(ctx context.Context, posterID, issueID, commentID i
|
||||||
}
|
}
|
||||||
// We only keep at most 20 history revisions now. It is enough in most cases.
|
// We only keep at most 20 history revisions now. It is enough in most cases.
|
||||||
// If there is a special requirement to keep more, we can consider introducing a new setting option then, but not now.
|
// If there is a special requirement to keep more, we can consider introducing a new setting option then, but not now.
|
||||||
keepLimitedContentHistory(ctx, issueID, commentID, 20)
|
KeepLimitedContentHistory(ctx, issueID, commentID, 20)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// keepLimitedContentHistory keeps at most `limit` history revisions, it will hard delete out-dated revisions, sorting by revision interval
|
// KeepLimitedContentHistory keeps at most `limit` history revisions, it will hard delete out-dated revisions, sorting by revision interval
|
||||||
// we can ignore all errors in this function, so we just log them
|
// we can ignore all errors in this function, so we just log them
|
||||||
func keepLimitedContentHistory(ctx context.Context, issueID, commentID int64, limit int) {
|
func KeepLimitedContentHistory(ctx context.Context, issueID, commentID int64, limit int) {
|
||||||
type IDEditTime struct {
|
type IDEditTime struct {
|
||||||
ID int64
|
ID int64
|
||||||
EditedUnix timeutil.TimeStamp
|
EditedUnix timeutil.TimeStamp
|
||||||
|
|
|
@ -2,12 +2,13 @@
|
||||||
// Use of this source code is governed by a MIT-style
|
// Use of this source code is governed by a MIT-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package issues
|
package issues_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
"code.gitea.io/gitea/modules/timeutil"
|
"code.gitea.io/gitea/modules/timeutil"
|
||||||
|
|
||||||
|
@ -20,20 +21,20 @@ func TestContentHistory(t *testing.T) {
|
||||||
dbCtx := db.DefaultContext
|
dbCtx := db.DefaultContext
|
||||||
timeStampNow := timeutil.TimeStampNow()
|
timeStampNow := timeutil.TimeStampNow()
|
||||||
|
|
||||||
_ = SaveIssueContentHistory(dbCtx, 1, 10, 0, timeStampNow, "i-a", true)
|
_ = issues_model.SaveIssueContentHistory(dbCtx, 1, 10, 0, timeStampNow, "i-a", true)
|
||||||
_ = SaveIssueContentHistory(dbCtx, 1, 10, 0, timeStampNow.Add(2), "i-b", false)
|
_ = issues_model.SaveIssueContentHistory(dbCtx, 1, 10, 0, timeStampNow.Add(2), "i-b", false)
|
||||||
_ = SaveIssueContentHistory(dbCtx, 1, 10, 0, timeStampNow.Add(7), "i-c", false)
|
_ = issues_model.SaveIssueContentHistory(dbCtx, 1, 10, 0, timeStampNow.Add(7), "i-c", false)
|
||||||
|
|
||||||
_ = SaveIssueContentHistory(dbCtx, 1, 10, 100, timeStampNow, "c-a", true)
|
_ = issues_model.SaveIssueContentHistory(dbCtx, 1, 10, 100, timeStampNow, "c-a", true)
|
||||||
_ = SaveIssueContentHistory(dbCtx, 1, 10, 100, timeStampNow.Add(5), "c-b", false)
|
_ = issues_model.SaveIssueContentHistory(dbCtx, 1, 10, 100, timeStampNow.Add(5), "c-b", false)
|
||||||
_ = SaveIssueContentHistory(dbCtx, 1, 10, 100, timeStampNow.Add(20), "c-c", false)
|
_ = issues_model.SaveIssueContentHistory(dbCtx, 1, 10, 100, timeStampNow.Add(20), "c-c", false)
|
||||||
_ = SaveIssueContentHistory(dbCtx, 1, 10, 100, timeStampNow.Add(50), "c-d", false)
|
_ = issues_model.SaveIssueContentHistory(dbCtx, 1, 10, 100, timeStampNow.Add(50), "c-d", false)
|
||||||
_ = SaveIssueContentHistory(dbCtx, 1, 10, 100, timeStampNow.Add(51), "c-e", false)
|
_ = issues_model.SaveIssueContentHistory(dbCtx, 1, 10, 100, timeStampNow.Add(51), "c-e", false)
|
||||||
|
|
||||||
h1, _ := GetIssueContentHistoryByID(dbCtx, 1)
|
h1, _ := issues_model.GetIssueContentHistoryByID(dbCtx, 1)
|
||||||
assert.EqualValues(t, 1, h1.ID)
|
assert.EqualValues(t, 1, h1.ID)
|
||||||
|
|
||||||
m, _ := QueryIssueContentHistoryEditedCountMap(dbCtx, 10)
|
m, _ := issues_model.QueryIssueContentHistoryEditedCountMap(dbCtx, 10)
|
||||||
assert.Equal(t, 3, m[0])
|
assert.Equal(t, 3, m[0])
|
||||||
assert.Equal(t, 5, m[100])
|
assert.Equal(t, 5, m[100])
|
||||||
|
|
||||||
|
@ -48,31 +49,31 @@ func TestContentHistory(t *testing.T) {
|
||||||
}
|
}
|
||||||
_ = db.GetEngine(dbCtx).Sync2(&User{})
|
_ = db.GetEngine(dbCtx).Sync2(&User{})
|
||||||
|
|
||||||
list1, _ := FetchIssueContentHistoryList(dbCtx, 10, 0)
|
list1, _ := issues_model.FetchIssueContentHistoryList(dbCtx, 10, 0)
|
||||||
assert.Len(t, list1, 3)
|
assert.Len(t, list1, 3)
|
||||||
list2, _ := FetchIssueContentHistoryList(dbCtx, 10, 100)
|
list2, _ := issues_model.FetchIssueContentHistoryList(dbCtx, 10, 100)
|
||||||
assert.Len(t, list2, 5)
|
assert.Len(t, list2, 5)
|
||||||
|
|
||||||
hasHistory1, _ := HasIssueContentHistory(dbCtx, 10, 0)
|
hasHistory1, _ := issues_model.HasIssueContentHistory(dbCtx, 10, 0)
|
||||||
assert.True(t, hasHistory1)
|
assert.True(t, hasHistory1)
|
||||||
hasHistory2, _ := HasIssueContentHistory(dbCtx, 10, 1)
|
hasHistory2, _ := issues_model.HasIssueContentHistory(dbCtx, 10, 1)
|
||||||
assert.False(t, hasHistory2)
|
assert.False(t, hasHistory2)
|
||||||
|
|
||||||
h6, h6Prev, _ := GetIssueContentHistoryAndPrev(dbCtx, 6)
|
h6, h6Prev, _ := issues_model.GetIssueContentHistoryAndPrev(dbCtx, 6)
|
||||||
assert.EqualValues(t, 6, h6.ID)
|
assert.EqualValues(t, 6, h6.ID)
|
||||||
assert.EqualValues(t, 5, h6Prev.ID)
|
assert.EqualValues(t, 5, h6Prev.ID)
|
||||||
|
|
||||||
// soft-delete
|
// soft-delete
|
||||||
_ = SoftDeleteIssueContentHistory(dbCtx, 5)
|
_ = issues_model.SoftDeleteIssueContentHistory(dbCtx, 5)
|
||||||
h6, h6Prev, _ = GetIssueContentHistoryAndPrev(dbCtx, 6)
|
h6, h6Prev, _ = issues_model.GetIssueContentHistoryAndPrev(dbCtx, 6)
|
||||||
assert.EqualValues(t, 6, h6.ID)
|
assert.EqualValues(t, 6, h6.ID)
|
||||||
assert.EqualValues(t, 4, h6Prev.ID)
|
assert.EqualValues(t, 4, h6Prev.ID)
|
||||||
|
|
||||||
// only keep 3 history revisions for comment_id=100, the first and the last should never be deleted
|
// only keep 3 history revisions for comment_id=100, the first and the last should never be deleted
|
||||||
keepLimitedContentHistory(dbCtx, 10, 100, 3)
|
issues_model.KeepLimitedContentHistory(dbCtx, 10, 100, 3)
|
||||||
list1, _ = FetchIssueContentHistoryList(dbCtx, 10, 0)
|
list1, _ = issues_model.FetchIssueContentHistoryList(dbCtx, 10, 0)
|
||||||
assert.Len(t, list1, 3)
|
assert.Len(t, list1, 3)
|
||||||
list2, _ = FetchIssueContentHistoryList(dbCtx, 10, 100)
|
list2, _ = issues_model.FetchIssueContentHistoryList(dbCtx, 10, 100)
|
||||||
assert.Len(t, list2, 3)
|
assert.Len(t, list2, 3)
|
||||||
assert.EqualValues(t, 8, list2[0].HistoryID)
|
assert.EqualValues(t, 8, list2[0].HistoryID)
|
||||||
assert.EqualValues(t, 7, list2[1].HistoryID)
|
assert.EqualValues(t, 7, list2[1].HistoryID)
|
||||||
|
|
|
@ -2,16 +2,95 @@
|
||||||
// Use of this source code is governed by a MIT-style
|
// Use of this source code is governed by a MIT-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package models
|
package issues
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/timeutil"
|
"code.gitea.io/gitea/modules/timeutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ErrDependencyExists represents a "DependencyAlreadyExists" kind of error.
|
||||||
|
type ErrDependencyExists struct {
|
||||||
|
IssueID int64
|
||||||
|
DependencyID int64
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsErrDependencyExists checks if an error is a ErrDependencyExists.
|
||||||
|
func IsErrDependencyExists(err error) bool {
|
||||||
|
_, ok := err.(ErrDependencyExists)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err ErrDependencyExists) Error() string {
|
||||||
|
return fmt.Sprintf("issue dependency does already exist [issue id: %d, dependency id: %d]", err.IssueID, err.DependencyID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrDependencyNotExists represents a "DependencyAlreadyExists" kind of error.
|
||||||
|
type ErrDependencyNotExists struct {
|
||||||
|
IssueID int64
|
||||||
|
DependencyID int64
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsErrDependencyNotExists checks if an error is a ErrDependencyExists.
|
||||||
|
func IsErrDependencyNotExists(err error) bool {
|
||||||
|
_, ok := err.(ErrDependencyNotExists)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err ErrDependencyNotExists) Error() string {
|
||||||
|
return fmt.Sprintf("issue dependency does not exist [issue id: %d, dependency id: %d]", err.IssueID, err.DependencyID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrCircularDependency represents a "DependencyCircular" kind of error.
|
||||||
|
type ErrCircularDependency struct {
|
||||||
|
IssueID int64
|
||||||
|
DependencyID int64
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsErrCircularDependency checks if an error is a ErrCircularDependency.
|
||||||
|
func IsErrCircularDependency(err error) bool {
|
||||||
|
_, ok := err.(ErrCircularDependency)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err ErrCircularDependency) Error() string {
|
||||||
|
return fmt.Sprintf("circular dependencies exists (two issues blocking each other) [issue id: %d, dependency id: %d]", err.IssueID, err.DependencyID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrDependenciesLeft represents an error where the issue you're trying to close still has dependencies left.
|
||||||
|
type ErrDependenciesLeft struct {
|
||||||
|
IssueID int64
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsErrDependenciesLeft checks if an error is a ErrDependenciesLeft.
|
||||||
|
func IsErrDependenciesLeft(err error) bool {
|
||||||
|
_, ok := err.(ErrDependenciesLeft)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err ErrDependenciesLeft) Error() string {
|
||||||
|
return fmt.Sprintf("issue has open dependencies [issue id: %d]", err.IssueID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrUnknownDependencyType represents an error where an unknown dependency type was passed
|
||||||
|
type ErrUnknownDependencyType struct {
|
||||||
|
Type DependencyType
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsErrUnknownDependencyType checks if an error is ErrUnknownDependencyType
|
||||||
|
func IsErrUnknownDependencyType(err error) bool {
|
||||||
|
_, ok := err.(ErrUnknownDependencyType)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err ErrUnknownDependencyType) Error() string {
|
||||||
|
return fmt.Sprintf("unknown dependency type [type: %d]", err.Type)
|
||||||
|
}
|
||||||
|
|
||||||
// IssueDependency represents an issue dependency
|
// IssueDependency represents an issue dependency
|
||||||
type IssueDependency struct {
|
type IssueDependency struct {
|
||||||
ID int64 `xorm:"pk autoincr"`
|
ID int64 `xorm:"pk autoincr"`
|
|
@ -2,12 +2,13 @@
|
||||||
// Use of this source code is governed by a MIT-style
|
// Use of this source code is governed by a MIT-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package models
|
package issues_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
|
||||||
|
@ -21,42 +22,42 @@ func TestCreateIssueDependency(t *testing.T) {
|
||||||
user1, err := user_model.GetUserByID(1)
|
user1, err := user_model.GetUserByID(1)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
issue1, err := GetIssueByID(1)
|
issue1, err := issues_model.GetIssueByID(db.DefaultContext, 1)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
issue2, err := GetIssueByID(2)
|
issue2, err := issues_model.GetIssueByID(db.DefaultContext, 2)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// Create a dependency and check if it was successful
|
// Create a dependency and check if it was successful
|
||||||
err = CreateIssueDependency(user1, issue1, issue2)
|
err = issues_model.CreateIssueDependency(user1, issue1, issue2)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// Do it again to see if it will check if the dependency already exists
|
// Do it again to see if it will check if the dependency already exists
|
||||||
err = CreateIssueDependency(user1, issue1, issue2)
|
err = issues_model.CreateIssueDependency(user1, issue1, issue2)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.True(t, IsErrDependencyExists(err))
|
assert.True(t, issues_model.IsErrDependencyExists(err))
|
||||||
|
|
||||||
// Check for circular dependencies
|
// Check for circular dependencies
|
||||||
err = CreateIssueDependency(user1, issue2, issue1)
|
err = issues_model.CreateIssueDependency(user1, issue2, issue1)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.True(t, IsErrCircularDependency(err))
|
assert.True(t, issues_model.IsErrCircularDependency(err))
|
||||||
|
|
||||||
_ = unittest.AssertExistsAndLoadBean(t, &Comment{Type: CommentTypeAddDependency, PosterID: user1.ID, IssueID: issue1.ID})
|
_ = unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{Type: issues_model.CommentTypeAddDependency, PosterID: user1.ID, IssueID: issue1.ID})
|
||||||
|
|
||||||
// Check if dependencies left is correct
|
// Check if dependencies left is correct
|
||||||
left, err := IssueNoDependenciesLeft(db.DefaultContext, issue1)
|
left, err := issues_model.IssueNoDependenciesLeft(db.DefaultContext, issue1)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.False(t, left)
|
assert.False(t, left)
|
||||||
|
|
||||||
// Close #2 and check again
|
// Close #2 and check again
|
||||||
_, err = ChangeIssueStatus(db.DefaultContext, issue2, user1, true)
|
_, err = issues_model.ChangeIssueStatus(db.DefaultContext, issue2, user1, true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
left, err = IssueNoDependenciesLeft(db.DefaultContext, issue1)
|
left, err = issues_model.IssueNoDependenciesLeft(db.DefaultContext, issue1)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.True(t, left)
|
assert.True(t, left)
|
||||||
|
|
||||||
// Test removing the dependency
|
// Test removing the dependency
|
||||||
err = RemoveIssueDependency(user1, issue1, issue2, DependencyTypeBlockedBy)
|
err = issues_model.RemoveIssueDependency(user1, issue1, issue2, issues_model.DependencyTypeBlockedBy)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
|
@ -3,7 +3,7 @@
|
||||||
// Use of this source code is governed by a MIT-style
|
// Use of this source code is governed by a MIT-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package models
|
package issues
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
@ -16,7 +16,6 @@ import (
|
||||||
admin_model "code.gitea.io/gitea/models/admin"
|
admin_model "code.gitea.io/gitea/models/admin"
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
"code.gitea.io/gitea/models/foreignreference"
|
"code.gitea.io/gitea/models/foreignreference"
|
||||||
issues_model "code.gitea.io/gitea/models/issues"
|
|
||||||
"code.gitea.io/gitea/models/organization"
|
"code.gitea.io/gitea/models/organization"
|
||||||
"code.gitea.io/gitea/models/perm"
|
"code.gitea.io/gitea/models/perm"
|
||||||
access_model "code.gitea.io/gitea/models/perm/access"
|
access_model "code.gitea.io/gitea/models/perm/access"
|
||||||
|
@ -29,7 +28,6 @@ import (
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/references"
|
"code.gitea.io/gitea/modules/references"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/modules/storage"
|
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
"code.gitea.io/gitea/modules/timeutil"
|
"code.gitea.io/gitea/modules/timeutil"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
|
@ -38,6 +36,71 @@ import (
|
||||||
"xorm.io/xorm"
|
"xorm.io/xorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ErrIssueNotExist represents a "IssueNotExist" kind of error.
|
||||||
|
type ErrIssueNotExist struct {
|
||||||
|
ID int64
|
||||||
|
RepoID int64
|
||||||
|
Index int64
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsErrIssueNotExist checks if an error is a ErrIssueNotExist.
|
||||||
|
func IsErrIssueNotExist(err error) bool {
|
||||||
|
_, ok := err.(ErrIssueNotExist)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err ErrIssueNotExist) Error() string {
|
||||||
|
return fmt.Sprintf("issue does not exist [id: %d, repo_id: %d, index: %d]", err.ID, err.RepoID, err.Index)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrIssueIsClosed represents a "IssueIsClosed" kind of error.
|
||||||
|
type ErrIssueIsClosed struct {
|
||||||
|
ID int64
|
||||||
|
RepoID int64
|
||||||
|
Index int64
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsErrIssueIsClosed checks if an error is a ErrIssueNotExist.
|
||||||
|
func IsErrIssueIsClosed(err error) bool {
|
||||||
|
_, ok := err.(ErrIssueIsClosed)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err ErrIssueIsClosed) Error() string {
|
||||||
|
return fmt.Sprintf("issue is closed [id: %d, repo_id: %d, index: %d]", err.ID, err.RepoID, err.Index)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrNewIssueInsert is used when the INSERT statement in newIssue fails
|
||||||
|
type ErrNewIssueInsert struct {
|
||||||
|
OriginalError error
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsErrNewIssueInsert checks if an error is a ErrNewIssueInsert.
|
||||||
|
func IsErrNewIssueInsert(err error) bool {
|
||||||
|
_, ok := err.(ErrNewIssueInsert)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err ErrNewIssueInsert) Error() string {
|
||||||
|
return err.OriginalError.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrIssueWasClosed is used when close a closed issue
|
||||||
|
type ErrIssueWasClosed struct {
|
||||||
|
ID int64
|
||||||
|
Index int64
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsErrIssueWasClosed checks if an error is a ErrIssueWasClosed.
|
||||||
|
func IsErrIssueWasClosed(err error) bool {
|
||||||
|
_, ok := err.(ErrIssueWasClosed)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err ErrIssueWasClosed) Error() string {
|
||||||
|
return fmt.Sprintf("Issue [%d] %d was already closed", err.ID, err.Index)
|
||||||
|
}
|
||||||
|
|
||||||
// Issue represents an issue or pull request of repository.
|
// Issue represents an issue or pull request of repository.
|
||||||
type Issue struct {
|
type Issue struct {
|
||||||
ID int64 `xorm:"pk autoincr"`
|
ID int64 `xorm:"pk autoincr"`
|
||||||
|
@ -53,7 +116,7 @@ type Issue struct {
|
||||||
RenderedContent string `xorm:"-"`
|
RenderedContent string `xorm:"-"`
|
||||||
Labels []*Label `xorm:"-"`
|
Labels []*Label `xorm:"-"`
|
||||||
MilestoneID int64 `xorm:"INDEX"`
|
MilestoneID int64 `xorm:"INDEX"`
|
||||||
Milestone *issues_model.Milestone `xorm:"-"`
|
Milestone *Milestone `xorm:"-"`
|
||||||
Project *project_model.Project `xorm:"-"`
|
Project *project_model.Project `xorm:"-"`
|
||||||
Priority int
|
Priority int
|
||||||
AssigneeID int64 `xorm:"-"`
|
AssigneeID int64 `xorm:"-"`
|
||||||
|
@ -73,7 +136,7 @@ type Issue struct {
|
||||||
|
|
||||||
Attachments []*repo_model.Attachment `xorm:"-"`
|
Attachments []*repo_model.Attachment `xorm:"-"`
|
||||||
Comments []*Comment `xorm:"-"`
|
Comments []*Comment `xorm:"-"`
|
||||||
Reactions issues_model.ReactionList `xorm:"-"`
|
Reactions ReactionList `xorm:"-"`
|
||||||
TotalTrackedTime int64 `xorm:"-"`
|
TotalTrackedTime int64 `xorm:"-"`
|
||||||
Assignees []*user_model.User `xorm:"-"`
|
Assignees []*user_model.User `xorm:"-"`
|
||||||
ForeignReference *foreignreference.ForeignReference `xorm:"-"`
|
ForeignReference *foreignreference.ForeignReference `xorm:"-"`
|
||||||
|
@ -107,7 +170,8 @@ func init() {
|
||||||
db.RegisterModel(new(IssueIndex))
|
db.RegisterModel(new(IssueIndex))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (issue *Issue) loadTotalTimes(ctx context.Context) (err error) {
|
// LoadTotalTimes load total tracked time
|
||||||
|
func (issue *Issue) LoadTotalTimes(ctx context.Context) (err error) {
|
||||||
opts := FindTrackedTimesOptions{IssueID: issue.ID}
|
opts := FindTrackedTimesOptions{IssueID: issue.ID}
|
||||||
issue.TotalTrackedTime, err = opts.toSession(db.GetEngine(ctx)).SumInt(&TrackedTime{}, "time")
|
issue.TotalTrackedTime, err = opts.toSession(db.GetEngine(ctx)).SumInt(&TrackedTime{}, "time")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -237,7 +301,7 @@ func (issue *Issue) loadReactions(ctx context.Context) (err error) {
|
||||||
if issue.Reactions != nil {
|
if issue.Reactions != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
reactions, _, err := issues_model.FindReactions(ctx, issues_model.FindReactionsOptions{
|
reactions, _, err := FindReactions(ctx, FindReactionsOptions{
|
||||||
IssueID: issue.ID,
|
IssueID: issue.ID,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -247,7 +311,7 @@ func (issue *Issue) loadReactions(ctx context.Context) (err error) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// Load reaction user data
|
// Load reaction user data
|
||||||
if _, err := issues_model.ReactionList(reactions).LoadUsers(ctx, issue.Repo); err != nil {
|
if _, err := ReactionList(reactions).LoadUsers(ctx, issue.Repo); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -292,15 +356,16 @@ func (issue *Issue) loadForeignReference(ctx context.Context) (err error) {
|
||||||
|
|
||||||
func (issue *Issue) loadMilestone(ctx context.Context) (err error) {
|
func (issue *Issue) loadMilestone(ctx context.Context) (err error) {
|
||||||
if (issue.Milestone == nil || issue.Milestone.ID != issue.MilestoneID) && issue.MilestoneID > 0 {
|
if (issue.Milestone == nil || issue.Milestone.ID != issue.MilestoneID) && issue.MilestoneID > 0 {
|
||||||
issue.Milestone, err = issues_model.GetMilestoneByRepoID(ctx, issue.RepoID, issue.MilestoneID)
|
issue.Milestone, err = GetMilestoneByRepoID(ctx, issue.RepoID, issue.MilestoneID)
|
||||||
if err != nil && !issues_model.IsErrMilestoneNotExist(err) {
|
if err != nil && !IsErrMilestoneNotExist(err) {
|
||||||
return fmt.Errorf("getMilestoneByRepoID [repo_id: %d, milestone_id: %d]: %v", issue.RepoID, issue.MilestoneID, err)
|
return fmt.Errorf("getMilestoneByRepoID [repo_id: %d, milestone_id: %d]: %v", issue.RepoID, issue.MilestoneID, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (issue *Issue) loadAttributes(ctx context.Context) (err error) {
|
// LoadAttributes loads the attribute of this issue.
|
||||||
|
func (issue *Issue) LoadAttributes(ctx context.Context) (err error) {
|
||||||
if err = issue.LoadRepo(ctx); err != nil {
|
if err = issue.LoadRepo(ctx); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -345,7 +410,7 @@ func (issue *Issue) loadAttributes(ctx context.Context) (err error) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if issue.isTimetrackerEnabled(ctx) {
|
if issue.isTimetrackerEnabled(ctx) {
|
||||||
if err = issue.loadTotalTimes(ctx); err != nil {
|
if err = issue.LoadTotalTimes(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -357,11 +422,6 @@ func (issue *Issue) loadAttributes(ctx context.Context) (err error) {
|
||||||
return issue.loadReactions(ctx)
|
return issue.loadReactions(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadAttributes loads the attribute of this issue.
|
|
||||||
func (issue *Issue) LoadAttributes() error {
|
|
||||||
return issue.loadAttributes(db.DefaultContext)
|
|
||||||
}
|
|
||||||
|
|
||||||
// LoadMilestone load milestone of this issue.
|
// LoadMilestone load milestone of this issue.
|
||||||
func (issue *Issue) LoadMilestone() error {
|
func (issue *Issue) LoadMilestone() error {
|
||||||
return issue.loadMilestone(db.DefaultContext)
|
return issue.loadMilestone(db.DefaultContext)
|
||||||
|
@ -590,15 +650,6 @@ func ReplaceIssueLabels(issue *Issue, labels []*Label, doer *user_model.User) (e
|
||||||
return committer.Commit()
|
return committer.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadBy sets issue to be read by given user.
|
|
||||||
func (issue *Issue) ReadBy(ctx context.Context, userID int64) error {
|
|
||||||
if err := UpdateIssueUserByRead(userID, issue.ID); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return setIssueNotificationStatusReadIfUnread(ctx, userID, issue.ID)
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateIssueCols updates cols of issue
|
// UpdateIssueCols updates cols of issue
|
||||||
func UpdateIssueCols(ctx context.Context, issue *Issue, cols ...string) error {
|
func UpdateIssueCols(ctx context.Context, issue *Issue, cols ...string) error {
|
||||||
if _, err := db.GetEngine(ctx).ID(issue.ID).Cols(cols...).Update(issue); err != nil {
|
if _, err := db.GetEngine(ctx).ID(issue.ID).Cols(cols...).Update(issue); err != nil {
|
||||||
|
@ -609,7 +660,7 @@ func UpdateIssueCols(ctx context.Context, issue *Issue, cols ...string) error {
|
||||||
|
|
||||||
func changeIssueStatus(ctx context.Context, issue *Issue, doer *user_model.User, isClosed, isMergePull bool) (*Comment, error) {
|
func changeIssueStatus(ctx context.Context, issue *Issue, doer *user_model.User, isClosed, isMergePull bool) (*Comment, error) {
|
||||||
// Reload the issue
|
// Reload the issue
|
||||||
currentIssue, err := getIssueByID(ctx, issue.ID)
|
currentIssue, err := GetIssueByID(ctx, issue.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -666,7 +717,7 @@ func doChangeIssueStatus(ctx context.Context, issue *Issue, doer *user_model.Use
|
||||||
|
|
||||||
// Update issue count of milestone
|
// Update issue count of milestone
|
||||||
if issue.MilestoneID > 0 {
|
if issue.MilestoneID > 0 {
|
||||||
if err := issues_model.UpdateMilestoneCounters(ctx, issue.MilestoneID); err != nil {
|
if err := UpdateMilestoneCounters(ctx, issue.MilestoneID); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -730,7 +781,7 @@ func ChangeIssueTitle(issue *Issue, doer *user_model.User, oldTitle string) (err
|
||||||
if _, err = CreateCommentCtx(ctx, opts); err != nil {
|
if _, err = CreateCommentCtx(ctx, opts); err != nil {
|
||||||
return fmt.Errorf("createComment: %v", err)
|
return fmt.Errorf("createComment: %v", err)
|
||||||
}
|
}
|
||||||
if err = issue.addCrossReferences(ctx, doer, true); err != nil {
|
if err = issue.AddCrossReferences(ctx, doer, true); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -772,7 +823,7 @@ func ChangeIssueRef(issue *Issue, doer *user_model.User, oldRef string) (err err
|
||||||
|
|
||||||
// AddDeletePRBranchComment adds delete branch comment for pull request issue
|
// AddDeletePRBranchComment adds delete branch comment for pull request issue
|
||||||
func AddDeletePRBranchComment(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, issueID int64, branchName string) error {
|
func AddDeletePRBranchComment(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, issueID int64, branchName string) error {
|
||||||
issue, err := getIssueByID(ctx, issueID)
|
issue, err := GetIssueByID(ctx, issueID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -815,12 +866,12 @@ func ChangeIssueContent(issue *Issue, doer *user_model.User, content string) (er
|
||||||
}
|
}
|
||||||
defer committer.Close()
|
defer committer.Close()
|
||||||
|
|
||||||
hasContentHistory, err := issues_model.HasIssueContentHistory(ctx, issue.ID, 0)
|
hasContentHistory, err := HasIssueContentHistory(ctx, issue.ID, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("HasIssueContentHistory: %v", err)
|
return fmt.Errorf("HasIssueContentHistory: %v", err)
|
||||||
}
|
}
|
||||||
if !hasContentHistory {
|
if !hasContentHistory {
|
||||||
if err = issues_model.SaveIssueContentHistory(ctx, issue.PosterID, issue.ID, 0,
|
if err = SaveIssueContentHistory(ctx, issue.PosterID, issue.ID, 0,
|
||||||
issue.CreatedUnix, issue.Content, true); err != nil {
|
issue.CreatedUnix, issue.Content, true); err != nil {
|
||||||
return fmt.Errorf("SaveIssueContentHistory: %v", err)
|
return fmt.Errorf("SaveIssueContentHistory: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -832,12 +883,12 @@ func ChangeIssueContent(issue *Issue, doer *user_model.User, content string) (er
|
||||||
return fmt.Errorf("UpdateIssueCols: %v", err)
|
return fmt.Errorf("UpdateIssueCols: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = issues_model.SaveIssueContentHistory(ctx, doer.ID, issue.ID, 0,
|
if err = SaveIssueContentHistory(ctx, doer.ID, issue.ID, 0,
|
||||||
timeutil.TimeStampNow(), issue.Content, false); err != nil {
|
timeutil.TimeStampNow(), issue.Content, false); err != nil {
|
||||||
return fmt.Errorf("SaveIssueContentHistory: %v", err)
|
return fmt.Errorf("SaveIssueContentHistory: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = issue.addCrossReferences(ctx, doer, true); err != nil {
|
if err = issue.AddCrossReferences(ctx, doer, true); err != nil {
|
||||||
return fmt.Errorf("addCrossReferences: %v", err)
|
return fmt.Errorf("addCrossReferences: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -907,13 +958,14 @@ type NewIssueOptions struct {
|
||||||
IsPull bool
|
IsPull bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func newIssue(ctx context.Context, doer *user_model.User, opts NewIssueOptions) (err error) {
|
// NewIssueWithIndex creates issue with given index
|
||||||
|
func NewIssueWithIndex(ctx context.Context, doer *user_model.User, opts NewIssueOptions) (err error) {
|
||||||
e := db.GetEngine(ctx)
|
e := db.GetEngine(ctx)
|
||||||
opts.Issue.Title = strings.TrimSpace(opts.Issue.Title)
|
opts.Issue.Title = strings.TrimSpace(opts.Issue.Title)
|
||||||
|
|
||||||
if opts.Issue.MilestoneID > 0 {
|
if opts.Issue.MilestoneID > 0 {
|
||||||
milestone, err := issues_model.GetMilestoneByRepoID(ctx, opts.Issue.RepoID, opts.Issue.MilestoneID)
|
milestone, err := GetMilestoneByRepoID(ctx, opts.Issue.RepoID, opts.Issue.MilestoneID)
|
||||||
if err != nil && !issues_model.IsErrMilestoneNotExist(err) {
|
if err != nil && !IsErrMilestoneNotExist(err) {
|
||||||
return fmt.Errorf("getMilestoneByID: %v", err)
|
return fmt.Errorf("getMilestoneByID: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -937,7 +989,7 @@ func newIssue(ctx context.Context, doer *user_model.User, opts NewIssueOptions)
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.Issue.MilestoneID > 0 {
|
if opts.Issue.MilestoneID > 0 {
|
||||||
if err := issues_model.UpdateMilestoneCounters(ctx, opts.Issue.MilestoneID); err != nil {
|
if err := UpdateMilestoneCounters(ctx, opts.Issue.MilestoneID); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -987,7 +1039,7 @@ func newIssue(ctx context.Context, doer *user_model.User, opts NewIssueOptions)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = newIssueUsers(ctx, opts.Repo, opts.Issue); err != nil {
|
if err = NewIssueUsers(ctx, opts.Repo, opts.Issue); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1004,36 +1056,11 @@ func newIssue(ctx context.Context, doer *user_model.User, opts NewIssueOptions)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err = opts.Issue.loadAttributes(ctx); err != nil {
|
if err = opts.Issue.LoadAttributes(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return opts.Issue.addCrossReferences(ctx, doer, false)
|
return opts.Issue.AddCrossReferences(ctx, doer, false)
|
||||||
}
|
|
||||||
|
|
||||||
// RecalculateIssueIndexForRepo create issue_index for repo if not exist and
|
|
||||||
// update it based on highest index of existing issues assigned to a repo
|
|
||||||
func RecalculateIssueIndexForRepo(repoID int64) error {
|
|
||||||
ctx, committer, err := db.TxContext()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer committer.Close()
|
|
||||||
|
|
||||||
if err := db.UpsertResourceIndex(db.GetEngine(ctx), "issue_index", repoID); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
var max int64
|
|
||||||
if _, err := db.GetEngine(ctx).Select(" MAX(`index`)").Table("issue").Where("repo_id=?", repoID).Get(&max); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := db.GetEngine(ctx).Exec("UPDATE `issue_index` SET max_index=? WHERE group_id=?", max, repoID); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return committer.Commit()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewIssue creates new issue with labels for repository.
|
// NewIssue creates new issue with labels for repository.
|
||||||
|
@ -1051,13 +1078,13 @@ func NewIssue(repo *repo_model.Repository, issue *Issue, labelIDs []int64, uuids
|
||||||
}
|
}
|
||||||
defer committer.Close()
|
defer committer.Close()
|
||||||
|
|
||||||
if err = newIssue(ctx, issue.Poster, NewIssueOptions{
|
if err = NewIssueWithIndex(ctx, issue.Poster, NewIssueOptions{
|
||||||
Repo: repo,
|
Repo: repo,
|
||||||
Issue: issue,
|
Issue: issue,
|
||||||
LabelIDs: labelIDs,
|
LabelIDs: labelIDs,
|
||||||
Attachments: uuids,
|
Attachments: uuids,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
if IsErrUserDoesNotHaveAccessToRepo(err) || IsErrNewIssueInsert(err) {
|
if repo_model.IsErrUserDoesNotHaveAccessToRepo(err) || IsErrNewIssueInsert(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return fmt.Errorf("newIssue: %v", err)
|
return fmt.Errorf("newIssue: %v", err)
|
||||||
|
@ -1114,10 +1141,11 @@ func GetIssueWithAttrsByIndex(repoID, index int64) (*Issue, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return issue, issue.LoadAttributes()
|
return issue, issue.LoadAttributes(db.DefaultContext)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getIssueByID(ctx context.Context, id int64) (*Issue, error) {
|
// GetIssueByID returns an issue by given ID.
|
||||||
|
func GetIssueByID(ctx context.Context, id int64) (*Issue, error) {
|
||||||
issue := new(Issue)
|
issue := new(Issue)
|
||||||
has, err := db.GetEngine(ctx).ID(id).Get(issue)
|
has, err := db.GetEngine(ctx).ID(id).Get(issue)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1130,16 +1158,11 @@ func getIssueByID(ctx context.Context, id int64) (*Issue, error) {
|
||||||
|
|
||||||
// GetIssueWithAttrsByID returns an issue with attributes by given ID.
|
// GetIssueWithAttrsByID returns an issue with attributes by given ID.
|
||||||
func GetIssueWithAttrsByID(id int64) (*Issue, error) {
|
func GetIssueWithAttrsByID(id int64) (*Issue, error) {
|
||||||
issue, err := getIssueByID(db.DefaultContext, id)
|
issue, err := GetIssueByID(db.DefaultContext, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return issue, issue.loadAttributes(db.DefaultContext)
|
return issue, issue.LoadAttributes(db.DefaultContext)
|
||||||
}
|
|
||||||
|
|
||||||
// GetIssueByID returns an issue by given ID.
|
|
||||||
func GetIssueByID(id int64) (*Issue, error) {
|
|
||||||
return getIssueByID(db.DefaultContext, id)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetIssuesByIDs return issues with the given IDs.
|
// GetIssuesByIDs return issues with the given IDs.
|
||||||
|
@ -1156,7 +1179,7 @@ func GetIssueIDsByRepoID(ctx context.Context, repoID int64) ([]int64, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// IssuesOptions represents options of an issue.
|
// IssuesOptions represents options of an issue.
|
||||||
type IssuesOptions struct {
|
type IssuesOptions struct { //nolint
|
||||||
db.ListOptions
|
db.ListOptions
|
||||||
RepoID int64 // overwrites RepoCond if not 0
|
RepoID int64 // overwrites RepoCond if not 0
|
||||||
RepoCond builder.Cond
|
RepoCond builder.Cond
|
||||||
|
@ -1534,7 +1557,7 @@ func GetParticipantsIDsByIssueID(issueID int64) ([]int64, error) {
|
||||||
|
|
||||||
// IsUserParticipantsOfIssue return true if user is participants of an issue
|
// IsUserParticipantsOfIssue return true if user is participants of an issue
|
||||||
func IsUserParticipantsOfIssue(user *user_model.User, issue *Issue) bool {
|
func IsUserParticipantsOfIssue(user *user_model.User, issue *Issue) bool {
|
||||||
userIDs, err := issue.getParticipantIDsByIssue(db.DefaultContext)
|
userIDs, err := issue.GetParticipantIDsByIssue(db.DefaultContext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err.Error())
|
log.Error(err.Error())
|
||||||
return false
|
return false
|
||||||
|
@ -1577,17 +1600,6 @@ const (
|
||||||
FilterModeYourRepositories
|
FilterModeYourRepositories
|
||||||
)
|
)
|
||||||
|
|
||||||
func parseCountResult(results []map[string][]byte) int64 {
|
|
||||||
if len(results) == 0 {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
for _, result := range results[0] {
|
|
||||||
c, _ := strconv.ParseInt(string(result), 10, 64)
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// IssueStatsOptions contains parameters accepted by GetIssueStats.
|
// IssueStatsOptions contains parameters accepted by GetIssueStats.
|
||||||
type IssueStatsOptions struct {
|
type IssueStatsOptions struct {
|
||||||
RepoID int64
|
RepoID int64
|
||||||
|
@ -1602,14 +1614,15 @@ type IssueStatsOptions struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
// MaxQueryParameters represents the max query parameters
|
||||||
// When queries are broken down in parts because of the number
|
// When queries are broken down in parts because of the number
|
||||||
// of parameters, attempt to break by this amount
|
// of parameters, attempt to break by this amount
|
||||||
maxQueryParameters = 300
|
MaxQueryParameters = 300
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetIssueStats returns issue statistic information by given conditions.
|
// GetIssueStats returns issue statistic information by given conditions.
|
||||||
func GetIssueStats(opts *IssueStatsOptions) (*IssueStats, error) {
|
func GetIssueStats(opts *IssueStatsOptions) (*IssueStats, error) {
|
||||||
if len(opts.IssueIDs) <= maxQueryParameters {
|
if len(opts.IssueIDs) <= MaxQueryParameters {
|
||||||
return getIssueStatsChunk(opts, opts.IssueIDs)
|
return getIssueStatsChunk(opts, opts.IssueIDs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1619,7 +1632,7 @@ func GetIssueStats(opts *IssueStatsOptions) (*IssueStats, error) {
|
||||||
// ids in a temporary table and join from them.
|
// ids in a temporary table and join from them.
|
||||||
accum := &IssueStats{}
|
accum := &IssueStats{}
|
||||||
for i := 0; i < len(opts.IssueIDs); {
|
for i := 0; i < len(opts.IssueIDs); {
|
||||||
chunk := i + maxQueryParameters
|
chunk := i + MaxQueryParameters
|
||||||
if chunk > len(opts.IssueIDs) {
|
if chunk > len(opts.IssueIDs) {
|
||||||
chunk = len(opts.IssueIDs)
|
chunk = len(opts.IssueIDs)
|
||||||
}
|
}
|
||||||
|
@ -1950,7 +1963,7 @@ func UpdateIssueByAPI(issue *Issue, doer *user_model.User) (statusChangeComment
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reload the issue
|
// Reload the issue
|
||||||
currentIssue, err := getIssueByID(ctx, issue.ID)
|
currentIssue, err := GetIssueByID(ctx, issue.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, err
|
return nil, false, err
|
||||||
}
|
}
|
||||||
|
@ -1985,7 +1998,7 @@ func UpdateIssueByAPI(issue *Issue, doer *user_model.User) (statusChangeComment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := issue.addCrossReferences(ctx, doer, true); err != nil {
|
if err := issue.AddCrossReferences(ctx, doer, true); err != nil {
|
||||||
return nil, false, err
|
return nil, false, err
|
||||||
}
|
}
|
||||||
return statusChangeComment, titleChanged, committer.Commit()
|
return statusChangeComment, titleChanged, committer.Commit()
|
||||||
|
@ -2016,22 +2029,8 @@ func UpdateIssueDeadline(issue *Issue, deadlineUnix timeutil.TimeStamp, doer *us
|
||||||
return committer.Commit()
|
return committer.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteIssue deletes the issue
|
// DeleteInIssue delete records in beans with external key issue_id = ?
|
||||||
func DeleteIssue(issue *Issue) error {
|
func DeleteInIssue(ctx context.Context, issueID int64, beans ...interface{}) error {
|
||||||
ctx, committer, err := db.TxContext()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer committer.Close()
|
|
||||||
|
|
||||||
if err := deleteIssue(ctx, issue); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return committer.Commit()
|
|
||||||
}
|
|
||||||
|
|
||||||
func deleteInIssue(ctx context.Context, issueID int64, beans ...interface{}) error {
|
|
||||||
e := db.GetEngine(ctx)
|
e := db.GetEngine(ctx)
|
||||||
for _, bean := range beans {
|
for _, bean := range beans {
|
||||||
if _, err := e.In("issue_id", issueID).Delete(bean); err != nil {
|
if _, err := e.In("issue_id", issueID).Delete(bean); err != nil {
|
||||||
|
@ -2041,103 +2040,14 @@ func deleteInIssue(ctx context.Context, issueID int64, beans ...interface{}) err
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func deleteIssue(ctx context.Context, issue *Issue) error {
|
|
||||||
e := db.GetEngine(ctx)
|
|
||||||
if _, err := e.ID(issue.ID).NoAutoCondition().Delete(issue); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if issue.IsPull {
|
|
||||||
if _, err := e.ID(issue.RepoID).Decr("num_pulls").Update(new(repo_model.Repository)); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if issue.IsClosed {
|
|
||||||
if _, err := e.ID(issue.RepoID).Decr("num_closed_pulls").Update(new(repo_model.Repository)); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if _, err := e.ID(issue.RepoID).Decr("num_issues").Update(new(repo_model.Repository)); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if issue.IsClosed {
|
|
||||||
if _, err := e.ID(issue.RepoID).Decr("num_closed_issues").Update(new(repo_model.Repository)); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// delete actions assigned to this issue
|
|
||||||
subQuery := builder.Select("`id`").
|
|
||||||
From("`comment`").
|
|
||||||
Where(builder.Eq{"`issue_id`": issue.ID})
|
|
||||||
if _, err := e.In("comment_id", subQuery).Delete(&Action{}); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := e.Table("action").Where("repo_id = ?", issue.RepoID).
|
|
||||||
In("op_type", ActionCreateIssue, ActionCreatePullRequest).
|
|
||||||
Where("content LIKE ?", strconv.FormatInt(issue.ID, 10)+"|%").
|
|
||||||
Delete(&Action{}); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// find attachments related to this issue and remove them
|
|
||||||
var attachments []*repo_model.Attachment
|
|
||||||
if err := e.In("issue_id", issue.ID).Find(&attachments); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := range attachments {
|
|
||||||
admin_model.RemoveStorageWithNotice(ctx, storage.Attachments, "Delete issue attachment", attachments[i].RelativePath())
|
|
||||||
}
|
|
||||||
|
|
||||||
// delete all database data still assigned to this issue
|
|
||||||
if err := deleteInIssue(ctx, issue.ID,
|
|
||||||
&issues_model.ContentHistory{},
|
|
||||||
&Comment{},
|
|
||||||
&IssueLabel{},
|
|
||||||
&IssueDependency{},
|
|
||||||
&IssueAssignees{},
|
|
||||||
&IssueUser{},
|
|
||||||
&Notification{},
|
|
||||||
&issues_model.Reaction{},
|
|
||||||
&IssueWatch{},
|
|
||||||
&Stopwatch{},
|
|
||||||
&TrackedTime{},
|
|
||||||
&project_model.ProjectIssue{},
|
|
||||||
&repo_model.Attachment{},
|
|
||||||
&PullRequest{},
|
|
||||||
); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// References to this issue in other issues
|
|
||||||
if _, err := e.In("ref_issue_id", issue.ID).Delete(&Comment{}); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete dependencies for issues in other repositories
|
|
||||||
if _, err := e.In("dependency_id", issue.ID).Delete(&IssueDependency{}); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// delete from dependent issues
|
|
||||||
if _, err := e.In("dependent_issue_id", issue.ID).Delete(&Comment{}); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DependencyInfo represents high level information about an issue which is a dependency of another issue.
|
// DependencyInfo represents high level information about an issue which is a dependency of another issue.
|
||||||
type DependencyInfo struct {
|
type DependencyInfo struct {
|
||||||
Issue `xorm:"extends"`
|
Issue `xorm:"extends"`
|
||||||
repo_model.Repository `xorm:"extends"`
|
repo_model.Repository `xorm:"extends"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// getParticipantIDsByIssue returns all userIDs who are participated in comments of an issue and issue author
|
// GetParticipantIDsByIssue returns all userIDs who are participated in comments of an issue and issue author
|
||||||
func (issue *Issue) getParticipantIDsByIssue(ctx context.Context) ([]int64, error) {
|
func (issue *Issue) GetParticipantIDsByIssue(ctx context.Context) ([]int64, error) {
|
||||||
if issue == nil {
|
if issue == nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
@ -2196,9 +2106,9 @@ func (issue *Issue) BlockingDependencies(ctx context.Context) (issueDeps []*Depe
|
||||||
|
|
||||||
func updateIssueClosedNum(ctx context.Context, issue *Issue) (err error) {
|
func updateIssueClosedNum(ctx context.Context, issue *Issue) (err error) {
|
||||||
if issue.IsPull {
|
if issue.IsPull {
|
||||||
err = repoStatsCorrectNumClosed(ctx, issue.RepoID, true, "num_closed_pulls")
|
err = repo_model.StatsCorrectNumClosed(ctx, issue.RepoID, true, "num_closed_pulls")
|
||||||
} else {
|
} else {
|
||||||
err = repoStatsCorrectNumClosed(ctx, issue.RepoID, false, "num_closed_issues")
|
err = repo_model.StatsCorrectNumClosed(ctx, issue.RepoID, false, "num_closed_issues")
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -2363,6 +2273,17 @@ func UpdateIssuesMigrationsByType(gitServiceType api.GitServiceType, originalAut
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func migratedIssueCond(tp api.GitServiceType) builder.Cond {
|
||||||
|
return builder.In("issue_id",
|
||||||
|
builder.Select("issue.id").
|
||||||
|
From("issue").
|
||||||
|
InnerJoin("repository", "issue.repo_id = repository.id").
|
||||||
|
Where(builder.Eq{
|
||||||
|
"repository.original_service_type": tp,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// UpdateReactionsMigrationsByType updates all migrated repositories' reactions from gitServiceType to replace originalAuthorID to posterID
|
// UpdateReactionsMigrationsByType updates all migrated repositories' reactions from gitServiceType to replace originalAuthorID to posterID
|
||||||
func UpdateReactionsMigrationsByType(gitServiceType api.GitServiceType, originalAuthorID string, userID int64) error {
|
func UpdateReactionsMigrationsByType(gitServiceType api.GitServiceType, originalAuthorID string, userID int64) error {
|
||||||
_, err := db.GetEngine(db.DefaultContext).Table("reaction").
|
_, err := db.GetEngine(db.DefaultContext).Table("reaction").
|
||||||
|
@ -2376,13 +2297,14 @@ func UpdateReactionsMigrationsByType(gitServiceType api.GitServiceType, original
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func deleteIssuesByRepoID(ctx context.Context, repoID int64) (attachmentPaths []string, err error) {
|
// DeleteIssuesByRepoID deletes issues by repositories id
|
||||||
|
func DeleteIssuesByRepoID(ctx context.Context, repoID int64) (attachmentPaths []string, err error) {
|
||||||
deleteCond := builder.Select("id").From("issue").Where(builder.Eq{"issue.repo_id": repoID})
|
deleteCond := builder.Select("id").From("issue").Where(builder.Eq{"issue.repo_id": repoID})
|
||||||
|
|
||||||
sess := db.GetEngine(ctx)
|
sess := db.GetEngine(ctx)
|
||||||
// Delete content histories
|
// Delete content histories
|
||||||
if _, err = sess.In("issue_id", deleteCond).
|
if _, err = sess.In("issue_id", deleteCond).
|
||||||
Delete(&issues_model.ContentHistory{}); err != nil {
|
Delete(&ContentHistory{}); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2410,7 +2332,7 @@ func deleteIssuesByRepoID(ctx context.Context, repoID int64) (attachmentPaths []
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err = sess.In("issue_id", deleteCond).
|
if _, err = sess.In("issue_id", deleteCond).
|
||||||
Delete(&issues_model.Reaction{}); err != nil {
|
Delete(&Reaction{}); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2477,3 +2399,50 @@ func (issue *Issue) GetExternalName() string { return issue.OriginalAuthor }
|
||||||
|
|
||||||
// GetExternalID ExternalUserRemappable interface
|
// GetExternalID ExternalUserRemappable interface
|
||||||
func (issue *Issue) GetExternalID() int64 { return issue.OriginalAuthorID }
|
func (issue *Issue) GetExternalID() int64 { return issue.OriginalAuthorID }
|
||||||
|
|
||||||
|
// CountOrphanedIssues count issues without a repo
|
||||||
|
func CountOrphanedIssues() (int64, error) {
|
||||||
|
return db.GetEngine(db.DefaultContext).Table("issue").
|
||||||
|
Join("LEFT", "repository", "issue.repo_id=repository.id").
|
||||||
|
Where(builder.IsNull{"repository.id"}).
|
||||||
|
Select("COUNT(`issue`.`id`)").
|
||||||
|
Count()
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteOrphanedIssues delete issues without a repo
|
||||||
|
func DeleteOrphanedIssues() error {
|
||||||
|
ctx, committer, err := db.TxContext()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer committer.Close()
|
||||||
|
|
||||||
|
var ids []int64
|
||||||
|
|
||||||
|
if err := db.GetEngine(ctx).Table("issue").Distinct("issue.repo_id").
|
||||||
|
Join("LEFT", "repository", "issue.repo_id=repository.id").
|
||||||
|
Where(builder.IsNull{"repository.id"}).GroupBy("issue.repo_id").
|
||||||
|
Find(&ids); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var attachmentPaths []string
|
||||||
|
for i := range ids {
|
||||||
|
paths, err := DeleteIssuesByRepoID(ctx, ids[i])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
attachmentPaths = append(attachmentPaths, paths...)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := committer.Commit(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
committer.Close()
|
||||||
|
|
||||||
|
// Remove issue attachment files.
|
||||||
|
for i := range attachmentPaths {
|
||||||
|
admin_model.RemoveAllWithNotice(db.DefaultContext, "Delete issue attachment", attachmentPaths[i])
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
32
models/issues/issue_index.go
Normal file
32
models/issues/issue_index.go
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
// Copyright 2017 The Gitea Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package issues
|
||||||
|
|
||||||
|
import "code.gitea.io/gitea/models/db"
|
||||||
|
|
||||||
|
// RecalculateIssueIndexForRepo create issue_index for repo if not exist and
|
||||||
|
// update it based on highest index of existing issues assigned to a repo
|
||||||
|
func RecalculateIssueIndexForRepo(repoID int64) error {
|
||||||
|
ctx, committer, err := db.TxContext()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer committer.Close()
|
||||||
|
|
||||||
|
if err := db.UpsertResourceIndex(ctx, "issue_index", repoID); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var max int64
|
||||||
|
if _, err := db.GetEngine(ctx).Select(" MAX(`index`)").Table("issue").Where("repo_id=?", repoID).Get(&max); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := db.GetEngine(ctx).Exec("UPDATE `issue_index` SET max_index=? WHERE group_id=?", max, repoID); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return committer.Commit()
|
||||||
|
}
|
|
@ -2,14 +2,13 @@
|
||||||
// Use of this source code is governed by a MIT-style
|
// Use of this source code is governed by a MIT-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package models
|
package issues
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
issues_model "code.gitea.io/gitea/models/issues"
|
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/container"
|
"code.gitea.io/gitea/modules/container"
|
||||||
|
@ -20,11 +19,6 @@ import (
|
||||||
// IssueList defines a list of issues
|
// IssueList defines a list of issues
|
||||||
type IssueList []*Issue
|
type IssueList []*Issue
|
||||||
|
|
||||||
const (
|
|
||||||
// default variables number on IN () in SQL
|
|
||||||
defaultMaxInSize = 50
|
|
||||||
)
|
|
||||||
|
|
||||||
// get the repo IDs to be loaded later, these IDs are for issue.Repo and issue.PullRequest.HeadRepo
|
// get the repo IDs to be loaded later, these IDs are for issue.Repo and issue.PullRequest.HeadRepo
|
||||||
func (issues IssueList) getRepoIDs() []int64 {
|
func (issues IssueList) getRepoIDs() []int64 {
|
||||||
repoIDs := make(map[int64]struct{}, len(issues))
|
repoIDs := make(map[int64]struct{}, len(issues))
|
||||||
|
@ -48,7 +42,7 @@ func (issues IssueList) loadRepositories(ctx context.Context) ([]*repo_model.Rep
|
||||||
repoMaps := make(map[int64]*repo_model.Repository, len(repoIDs))
|
repoMaps := make(map[int64]*repo_model.Repository, len(repoIDs))
|
||||||
left := len(repoIDs)
|
left := len(repoIDs)
|
||||||
for left > 0 {
|
for left > 0 {
|
||||||
limit := defaultMaxInSize
|
limit := db.DefaultMaxInSize
|
||||||
if left < limit {
|
if left < limit {
|
||||||
limit = left
|
limit = left
|
||||||
}
|
}
|
||||||
|
@ -102,7 +96,7 @@ func (issues IssueList) loadPosters(ctx context.Context) error {
|
||||||
posterMaps := make(map[int64]*user_model.User, len(posterIDs))
|
posterMaps := make(map[int64]*user_model.User, len(posterIDs))
|
||||||
left := len(posterIDs)
|
left := len(posterIDs)
|
||||||
for left > 0 {
|
for left > 0 {
|
||||||
limit := defaultMaxInSize
|
limit := db.DefaultMaxInSize
|
||||||
if left < limit {
|
if left < limit {
|
||||||
limit = left
|
limit = left
|
||||||
}
|
}
|
||||||
|
@ -150,7 +144,7 @@ func (issues IssueList) loadLabels(ctx context.Context) error {
|
||||||
issueIDs := issues.getIssueIDs()
|
issueIDs := issues.getIssueIDs()
|
||||||
left := len(issueIDs)
|
left := len(issueIDs)
|
||||||
for left > 0 {
|
for left > 0 {
|
||||||
limit := defaultMaxInSize
|
limit := db.DefaultMaxInSize
|
||||||
if left < limit {
|
if left < limit {
|
||||||
limit = left
|
limit = left
|
||||||
}
|
}
|
||||||
|
@ -205,10 +199,10 @@ func (issues IssueList) loadMilestones(ctx context.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
milestoneMaps := make(map[int64]*issues_model.Milestone, len(milestoneIDs))
|
milestoneMaps := make(map[int64]*Milestone, len(milestoneIDs))
|
||||||
left := len(milestoneIDs)
|
left := len(milestoneIDs)
|
||||||
for left > 0 {
|
for left > 0 {
|
||||||
limit := defaultMaxInSize
|
limit := db.DefaultMaxInSize
|
||||||
if left < limit {
|
if left < limit {
|
||||||
limit = left
|
limit = left
|
||||||
}
|
}
|
||||||
|
@ -242,7 +236,7 @@ func (issues IssueList) loadAssignees(ctx context.Context) error {
|
||||||
issueIDs := issues.getIssueIDs()
|
issueIDs := issues.getIssueIDs()
|
||||||
left := len(issueIDs)
|
left := len(issueIDs)
|
||||||
for left > 0 {
|
for left > 0 {
|
||||||
limit := defaultMaxInSize
|
limit := db.DefaultMaxInSize
|
||||||
if left < limit {
|
if left < limit {
|
||||||
limit = left
|
limit = left
|
||||||
}
|
}
|
||||||
|
@ -298,7 +292,7 @@ func (issues IssueList) loadPullRequests(ctx context.Context) error {
|
||||||
pullRequestMaps := make(map[int64]*PullRequest, len(issuesIDs))
|
pullRequestMaps := make(map[int64]*PullRequest, len(issuesIDs))
|
||||||
left := len(issuesIDs)
|
left := len(issuesIDs)
|
||||||
for left > 0 {
|
for left > 0 {
|
||||||
limit := defaultMaxInSize
|
limit := db.DefaultMaxInSize
|
||||||
if left < limit {
|
if left < limit {
|
||||||
limit = left
|
limit = left
|
||||||
}
|
}
|
||||||
|
@ -342,7 +336,7 @@ func (issues IssueList) loadAttachments(ctx context.Context) (err error) {
|
||||||
issuesIDs := issues.getIssueIDs()
|
issuesIDs := issues.getIssueIDs()
|
||||||
left := len(issuesIDs)
|
left := len(issuesIDs)
|
||||||
for left > 0 {
|
for left > 0 {
|
||||||
limit := defaultMaxInSize
|
limit := db.DefaultMaxInSize
|
||||||
if left < limit {
|
if left < limit {
|
||||||
limit = left
|
limit = left
|
||||||
}
|
}
|
||||||
|
@ -387,7 +381,7 @@ func (issues IssueList) loadComments(ctx context.Context, cond builder.Cond) (er
|
||||||
issuesIDs := issues.getIssueIDs()
|
issuesIDs := issues.getIssueIDs()
|
||||||
left := len(issuesIDs)
|
left := len(issuesIDs)
|
||||||
for left > 0 {
|
for left > 0 {
|
||||||
limit := defaultMaxInSize
|
limit := db.DefaultMaxInSize
|
||||||
if left < limit {
|
if left < limit {
|
||||||
limit = left
|
limit = left
|
||||||
}
|
}
|
||||||
|
@ -443,7 +437,7 @@ func (issues IssueList) loadTotalTrackedTimes(ctx context.Context) (err error) {
|
||||||
|
|
||||||
left := len(ids)
|
left := len(ids)
|
||||||
for left > 0 {
|
for left > 0 {
|
||||||
limit := defaultMaxInSize
|
limit := db.DefaultMaxInSize
|
||||||
if left < limit {
|
if left < limit {
|
||||||
limit = left
|
limit = left
|
||||||
}
|
}
|
|
@ -2,11 +2,12 @@
|
||||||
// Use of this source code is governed by a MIT-style
|
// Use of this source code is governed by a MIT-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package models
|
package issues_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
|
||||||
|
@ -16,10 +17,10 @@ import (
|
||||||
func TestIssueList_LoadRepositories(t *testing.T) {
|
func TestIssueList_LoadRepositories(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
issueList := IssueList{
|
issueList := issues_model.IssueList{
|
||||||
unittest.AssertExistsAndLoadBean(t, &Issue{ID: 1}).(*Issue),
|
unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1}).(*issues_model.Issue),
|
||||||
unittest.AssertExistsAndLoadBean(t, &Issue{ID: 2}).(*Issue),
|
unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2}).(*issues_model.Issue),
|
||||||
unittest.AssertExistsAndLoadBean(t, &Issue{ID: 4}).(*Issue),
|
unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 4}).(*issues_model.Issue),
|
||||||
}
|
}
|
||||||
|
|
||||||
repos, err := issueList.LoadRepositories()
|
repos, err := issueList.LoadRepositories()
|
||||||
|
@ -33,9 +34,9 @@ func TestIssueList_LoadRepositories(t *testing.T) {
|
||||||
func TestIssueList_LoadAttributes(t *testing.T) {
|
func TestIssueList_LoadAttributes(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
setting.Service.EnableTimetracking = true
|
setting.Service.EnableTimetracking = true
|
||||||
issueList := IssueList{
|
issueList := issues_model.IssueList{
|
||||||
unittest.AssertExistsAndLoadBean(t, &Issue{ID: 1}).(*Issue),
|
unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1}).(*issues_model.Issue),
|
||||||
unittest.AssertExistsAndLoadBean(t, &Issue{ID: 4}).(*Issue),
|
unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 4}).(*issues_model.Issue),
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.NoError(t, issueList.LoadAttributes())
|
assert.NoError(t, issueList.LoadAttributes())
|
||||||
|
@ -43,7 +44,7 @@ func TestIssueList_LoadAttributes(t *testing.T) {
|
||||||
assert.EqualValues(t, issue.RepoID, issue.Repo.ID)
|
assert.EqualValues(t, issue.RepoID, issue.Repo.ID)
|
||||||
for _, label := range issue.Labels {
|
for _, label := range issue.Labels {
|
||||||
assert.EqualValues(t, issue.RepoID, label.RepoID)
|
assert.EqualValues(t, issue.RepoID, label.RepoID)
|
||||||
unittest.AssertExistsAndLoadBean(t, &IssueLabel{IssueID: issue.ID, LabelID: label.ID})
|
unittest.AssertExistsAndLoadBean(t, &issues_model.IssueLabel{IssueID: issue.ID, LabelID: label.ID})
|
||||||
}
|
}
|
||||||
if issue.PosterID > 0 {
|
if issue.PosterID > 0 {
|
||||||
assert.EqualValues(t, issue.PosterID, issue.Poster.ID)
|
assert.EqualValues(t, issue.PosterID, issue.Poster.ID)
|
|
@ -2,7 +2,7 @@
|
||||||
// Use of this source code is governed by a MIT-style
|
// Use of this source code is governed by a MIT-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package models
|
package issues
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
|
@ -2,7 +2,7 @@
|
||||||
// Use of this source code is governed by a MIT-style
|
// Use of this source code is governed by a MIT-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package models
|
package issues
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
|
@ -2,7 +2,7 @@
|
||||||
// Use of this source code is governed by a MIT-style
|
// Use of this source code is governed by a MIT-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package models
|
package issues_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
@ -29,18 +29,18 @@ func TestIssue_ReplaceLabels(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
testSuccess := func(issueID int64, labelIDs []int64) {
|
testSuccess := func(issueID int64, labelIDs []int64) {
|
||||||
issue := unittest.AssertExistsAndLoadBean(t, &Issue{ID: issueID}).(*Issue)
|
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: issueID}).(*issues_model.Issue)
|
||||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID}).(*repo_model.Repository)
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID}).(*repo_model.Repository)
|
||||||
doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User)
|
doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User)
|
||||||
|
|
||||||
labels := make([]*Label, len(labelIDs))
|
labels := make([]*issues_model.Label, len(labelIDs))
|
||||||
for i, labelID := range labelIDs {
|
for i, labelID := range labelIDs {
|
||||||
labels[i] = unittest.AssertExistsAndLoadBean(t, &Label{ID: labelID, RepoID: repo.ID}).(*Label)
|
labels[i] = unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: labelID, RepoID: repo.ID}).(*issues_model.Label)
|
||||||
}
|
}
|
||||||
assert.NoError(t, ReplaceIssueLabels(issue, labels, doer))
|
assert.NoError(t, issues_model.ReplaceIssueLabels(issue, labels, doer))
|
||||||
unittest.AssertCount(t, &IssueLabel{IssueID: issueID}, len(labelIDs))
|
unittest.AssertCount(t, &issues_model.IssueLabel{IssueID: issueID}, len(labelIDs))
|
||||||
for _, labelID := range labelIDs {
|
for _, labelID := range labelIDs {
|
||||||
unittest.AssertExistsAndLoadBean(t, &IssueLabel{IssueID: issueID, LabelID: labelID})
|
unittest.AssertExistsAndLoadBean(t, &issues_model.IssueLabel{IssueID: issueID, LabelID: labelID})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,15 +52,15 @@ func TestIssue_ReplaceLabels(t *testing.T) {
|
||||||
func Test_GetIssueIDsByRepoID(t *testing.T) {
|
func Test_GetIssueIDsByRepoID(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
ids, err := GetIssueIDsByRepoID(db.DefaultContext, 1)
|
ids, err := issues_model.GetIssueIDsByRepoID(db.DefaultContext, 1)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Len(t, ids, 5)
|
assert.Len(t, ids, 5)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestIssueAPIURL(t *testing.T) {
|
func TestIssueAPIURL(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
issue := unittest.AssertExistsAndLoadBean(t, &Issue{ID: 1}).(*Issue)
|
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1}).(*issues_model.Issue)
|
||||||
err := issue.LoadAttributes()
|
err := issue.LoadAttributes(db.DefaultContext)
|
||||||
|
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, "https://try.gitea.io/api/v1/repos/user2/repo1/issues/1", issue.APIURL())
|
assert.Equal(t, "https://try.gitea.io/api/v1/repos/user2/repo1/issues/1", issue.APIURL())
|
||||||
|
@ -69,7 +69,7 @@ func TestIssueAPIURL(t *testing.T) {
|
||||||
func TestGetIssuesByIDs(t *testing.T) {
|
func TestGetIssuesByIDs(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
testSuccess := func(expectedIssueIDs, nonExistentIssueIDs []int64) {
|
testSuccess := func(expectedIssueIDs, nonExistentIssueIDs []int64) {
|
||||||
issues, err := GetIssuesByIDs(db.DefaultContext, append(expectedIssueIDs, nonExistentIssueIDs...))
|
issues, err := issues_model.GetIssuesByIDs(db.DefaultContext, append(expectedIssueIDs, nonExistentIssueIDs...))
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
actualIssueIDs := make([]int64, len(issues))
|
actualIssueIDs := make([]int64, len(issues))
|
||||||
for i, issue := range issues {
|
for i, issue := range issues {
|
||||||
|
@ -85,9 +85,9 @@ func TestGetParticipantIDsByIssue(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
checkParticipants := func(issueID int64, userIDs []int) {
|
checkParticipants := func(issueID int64, userIDs []int) {
|
||||||
issue, err := GetIssueByID(issueID)
|
issue, err := issues_model.GetIssueByID(db.DefaultContext, issueID)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
participants, err := issue.getParticipantIDsByIssue(db.DefaultContext)
|
participants, err := issue.GetParticipantIDsByIssue(db.DefaultContext)
|
||||||
if assert.NoError(t, err) {
|
if assert.NoError(t, err) {
|
||||||
participantsIDs := make([]int, len(participants))
|
participantsIDs := make([]int, len(participants))
|
||||||
for i, uid := range participants {
|
for i, uid := range participants {
|
||||||
|
@ -117,16 +117,16 @@ func TestIssue_ClearLabels(t *testing.T) {
|
||||||
}
|
}
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
issue := unittest.AssertExistsAndLoadBean(t, &Issue{ID: test.issueID}).(*Issue)
|
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: test.issueID}).(*issues_model.Issue)
|
||||||
doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: test.doerID}).(*user_model.User)
|
doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: test.doerID}).(*user_model.User)
|
||||||
assert.NoError(t, ClearIssueLabels(issue, doer))
|
assert.NoError(t, issues_model.ClearIssueLabels(issue, doer))
|
||||||
unittest.AssertNotExistsBean(t, &IssueLabel{IssueID: test.issueID})
|
unittest.AssertNotExistsBean(t, &issues_model.IssueLabel{IssueID: test.issueID})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUpdateIssueCols(t *testing.T) {
|
func TestUpdateIssueCols(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
issue := unittest.AssertExistsAndLoadBean(t, &Issue{}).(*Issue)
|
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{}).(*issues_model.Issue)
|
||||||
|
|
||||||
const newTitle = "New Title for unit test"
|
const newTitle = "New Title for unit test"
|
||||||
issue.Title = newTitle
|
issue.Title = newTitle
|
||||||
|
@ -135,10 +135,10 @@ func TestUpdateIssueCols(t *testing.T) {
|
||||||
issue.Content = "This should have no effect"
|
issue.Content = "This should have no effect"
|
||||||
|
|
||||||
now := time.Now().Unix()
|
now := time.Now().Unix()
|
||||||
assert.NoError(t, UpdateIssueCols(db.DefaultContext, issue, "name"))
|
assert.NoError(t, issues_model.UpdateIssueCols(db.DefaultContext, issue, "name"))
|
||||||
then := time.Now().Unix()
|
then := time.Now().Unix()
|
||||||
|
|
||||||
updatedIssue := unittest.AssertExistsAndLoadBean(t, &Issue{ID: issue.ID}).(*Issue)
|
updatedIssue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: issue.ID}).(*issues_model.Issue)
|
||||||
assert.EqualValues(t, newTitle, updatedIssue.Title)
|
assert.EqualValues(t, newTitle, updatedIssue.Title)
|
||||||
assert.EqualValues(t, prevContent, updatedIssue.Content)
|
assert.EqualValues(t, prevContent, updatedIssue.Content)
|
||||||
unittest.AssertInt64InRange(t, now, then, int64(updatedIssue.UpdatedUnix))
|
unittest.AssertInt64InRange(t, now, then, int64(updatedIssue.UpdatedUnix))
|
||||||
|
@ -147,18 +147,18 @@ func TestUpdateIssueCols(t *testing.T) {
|
||||||
func TestIssues(t *testing.T) {
|
func TestIssues(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
for _, test := range []struct {
|
for _, test := range []struct {
|
||||||
Opts IssuesOptions
|
Opts issues_model.IssuesOptions
|
||||||
ExpectedIssueIDs []int64
|
ExpectedIssueIDs []int64
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
IssuesOptions{
|
issues_model.IssuesOptions{
|
||||||
AssigneeID: 1,
|
AssigneeID: 1,
|
||||||
SortType: "oldest",
|
SortType: "oldest",
|
||||||
},
|
},
|
||||||
[]int64{1, 6},
|
[]int64{1, 6},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
IssuesOptions{
|
issues_model.IssuesOptions{
|
||||||
RepoCond: builder.In("repo_id", 1, 3),
|
RepoCond: builder.In("repo_id", 1, 3),
|
||||||
SortType: "oldest",
|
SortType: "oldest",
|
||||||
ListOptions: db.ListOptions{
|
ListOptions: db.ListOptions{
|
||||||
|
@ -169,7 +169,7 @@ func TestIssues(t *testing.T) {
|
||||||
[]int64{1, 2, 3, 5},
|
[]int64{1, 2, 3, 5},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
IssuesOptions{
|
issues_model.IssuesOptions{
|
||||||
LabelIDs: []int64{1},
|
LabelIDs: []int64{1},
|
||||||
ListOptions: db.ListOptions{
|
ListOptions: db.ListOptions{
|
||||||
Page: 1,
|
Page: 1,
|
||||||
|
@ -179,7 +179,7 @@ func TestIssues(t *testing.T) {
|
||||||
[]int64{2, 1},
|
[]int64{2, 1},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
IssuesOptions{
|
issues_model.IssuesOptions{
|
||||||
LabelIDs: []int64{1, 2},
|
LabelIDs: []int64{1, 2},
|
||||||
ListOptions: db.ListOptions{
|
ListOptions: db.ListOptions{
|
||||||
Page: 1,
|
Page: 1,
|
||||||
|
@ -189,7 +189,7 @@ func TestIssues(t *testing.T) {
|
||||||
[]int64{}, // issues with **both** label 1 and 2, none of these issues matches, TODO: add more tests
|
[]int64{}, // issues with **both** label 1 and 2, none of these issues matches, TODO: add more tests
|
||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
issues, err := Issues(&test.Opts)
|
issues, err := issues_model.Issues(&test.Opts)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
if assert.Len(t, issues, len(test.ExpectedIssueIDs)) {
|
if assert.Len(t, issues, len(test.ExpectedIssueIDs)) {
|
||||||
for i, issue := range issues {
|
for i, issue := range issues {
|
||||||
|
@ -202,16 +202,16 @@ func TestIssues(t *testing.T) {
|
||||||
func TestGetUserIssueStats(t *testing.T) {
|
func TestGetUserIssueStats(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
for _, test := range []struct {
|
for _, test := range []struct {
|
||||||
Opts UserIssueStatsOptions
|
Opts issues_model.UserIssueStatsOptions
|
||||||
ExpectedIssueStats IssueStats
|
ExpectedIssueStats issues_model.IssueStats
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
UserIssueStatsOptions{
|
issues_model.UserIssueStatsOptions{
|
||||||
UserID: 1,
|
UserID: 1,
|
||||||
RepoIDs: []int64{1},
|
RepoIDs: []int64{1},
|
||||||
FilterMode: FilterModeAll,
|
FilterMode: issues_model.FilterModeAll,
|
||||||
},
|
},
|
||||||
IssueStats{
|
issues_model.IssueStats{
|
||||||
YourRepositoriesCount: 1, // 6
|
YourRepositoriesCount: 1, // 6
|
||||||
AssignCount: 1, // 6
|
AssignCount: 1, // 6
|
||||||
CreateCount: 1, // 6
|
CreateCount: 1, // 6
|
||||||
|
@ -220,13 +220,13 @@ func TestGetUserIssueStats(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
UserIssueStatsOptions{
|
issues_model.UserIssueStatsOptions{
|
||||||
UserID: 1,
|
UserID: 1,
|
||||||
RepoIDs: []int64{1},
|
RepoIDs: []int64{1},
|
||||||
FilterMode: FilterModeAll,
|
FilterMode: issues_model.FilterModeAll,
|
||||||
IsClosed: true,
|
IsClosed: true,
|
||||||
},
|
},
|
||||||
IssueStats{
|
issues_model.IssueStats{
|
||||||
YourRepositoriesCount: 1, // 6
|
YourRepositoriesCount: 1, // 6
|
||||||
AssignCount: 0,
|
AssignCount: 0,
|
||||||
CreateCount: 0,
|
CreateCount: 0,
|
||||||
|
@ -235,11 +235,11 @@ func TestGetUserIssueStats(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
UserIssueStatsOptions{
|
issues_model.UserIssueStatsOptions{
|
||||||
UserID: 1,
|
UserID: 1,
|
||||||
FilterMode: FilterModeAssign,
|
FilterMode: issues_model.FilterModeAssign,
|
||||||
},
|
},
|
||||||
IssueStats{
|
issues_model.IssueStats{
|
||||||
YourRepositoriesCount: 1, // 6
|
YourRepositoriesCount: 1, // 6
|
||||||
AssignCount: 1, // 6
|
AssignCount: 1, // 6
|
||||||
CreateCount: 1, // 6
|
CreateCount: 1, // 6
|
||||||
|
@ -248,11 +248,11 @@ func TestGetUserIssueStats(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
UserIssueStatsOptions{
|
issues_model.UserIssueStatsOptions{
|
||||||
UserID: 1,
|
UserID: 1,
|
||||||
FilterMode: FilterModeCreate,
|
FilterMode: issues_model.FilterModeCreate,
|
||||||
},
|
},
|
||||||
IssueStats{
|
issues_model.IssueStats{
|
||||||
YourRepositoriesCount: 1, // 6
|
YourRepositoriesCount: 1, // 6
|
||||||
AssignCount: 1, // 6
|
AssignCount: 1, // 6
|
||||||
CreateCount: 1, // 6
|
CreateCount: 1, // 6
|
||||||
|
@ -261,11 +261,11 @@ func TestGetUserIssueStats(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
UserIssueStatsOptions{
|
issues_model.UserIssueStatsOptions{
|
||||||
UserID: 1,
|
UserID: 1,
|
||||||
FilterMode: FilterModeMention,
|
FilterMode: issues_model.FilterModeMention,
|
||||||
},
|
},
|
||||||
IssueStats{
|
issues_model.IssueStats{
|
||||||
YourRepositoriesCount: 1, // 6
|
YourRepositoriesCount: 1, // 6
|
||||||
AssignCount: 1, // 6
|
AssignCount: 1, // 6
|
||||||
CreateCount: 1, // 6
|
CreateCount: 1, // 6
|
||||||
|
@ -275,12 +275,12 @@ func TestGetUserIssueStats(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
UserIssueStatsOptions{
|
issues_model.UserIssueStatsOptions{
|
||||||
UserID: 1,
|
UserID: 1,
|
||||||
FilterMode: FilterModeCreate,
|
FilterMode: issues_model.FilterModeCreate,
|
||||||
IssueIDs: []int64{1},
|
IssueIDs: []int64{1},
|
||||||
},
|
},
|
||||||
IssueStats{
|
issues_model.IssueStats{
|
||||||
YourRepositoriesCount: 1, // 1
|
YourRepositoriesCount: 1, // 1
|
||||||
AssignCount: 1, // 1
|
AssignCount: 1, // 1
|
||||||
CreateCount: 1, // 1
|
CreateCount: 1, // 1
|
||||||
|
@ -289,13 +289,13 @@ func TestGetUserIssueStats(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
UserIssueStatsOptions{
|
issues_model.UserIssueStatsOptions{
|
||||||
UserID: 2,
|
UserID: 2,
|
||||||
Org: unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}).(*organization.Organization),
|
Org: unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}).(*organization.Organization),
|
||||||
Team: unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 7}).(*organization.Team),
|
Team: unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 7}).(*organization.Team),
|
||||||
FilterMode: FilterModeAll,
|
FilterMode: issues_model.FilterModeAll,
|
||||||
},
|
},
|
||||||
IssueStats{
|
issues_model.IssueStats{
|
||||||
YourRepositoriesCount: 2,
|
YourRepositoriesCount: 2,
|
||||||
AssignCount: 1,
|
AssignCount: 1,
|
||||||
CreateCount: 1,
|
CreateCount: 1,
|
||||||
|
@ -304,7 +304,7 @@ func TestGetUserIssueStats(t *testing.T) {
|
||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
t.Run(fmt.Sprintf("%#v", test.Opts), func(t *testing.T) {
|
t.Run(fmt.Sprintf("%#v", test.Opts), func(t *testing.T) {
|
||||||
stats, err := GetUserIssueStats(test.Opts)
|
stats, err := issues_model.GetUserIssueStats(test.Opts)
|
||||||
if !assert.NoError(t, err) {
|
if !assert.NoError(t, err) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -315,31 +315,31 @@ func TestGetUserIssueStats(t *testing.T) {
|
||||||
|
|
||||||
func TestIssue_loadTotalTimes(t *testing.T) {
|
func TestIssue_loadTotalTimes(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
ms, err := GetIssueByID(2)
|
ms, err := issues_model.GetIssueByID(db.DefaultContext, 2)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NoError(t, ms.loadTotalTimes(db.DefaultContext))
|
assert.NoError(t, ms.LoadTotalTimes(db.DefaultContext))
|
||||||
assert.Equal(t, int64(3682), ms.TotalTrackedTime)
|
assert.Equal(t, int64(3682), ms.TotalTrackedTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestIssue_SearchIssueIDsByKeyword(t *testing.T) {
|
func TestIssue_SearchIssueIDsByKeyword(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
total, ids, err := SearchIssueIDsByKeyword(context.TODO(), "issue2", []int64{1}, 10, 0)
|
total, ids, err := issues_model.SearchIssueIDsByKeyword(context.TODO(), "issue2", []int64{1}, 10, 0)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.EqualValues(t, 1, total)
|
assert.EqualValues(t, 1, total)
|
||||||
assert.EqualValues(t, []int64{2}, ids)
|
assert.EqualValues(t, []int64{2}, ids)
|
||||||
|
|
||||||
total, ids, err = SearchIssueIDsByKeyword(context.TODO(), "first", []int64{1}, 10, 0)
|
total, ids, err = issues_model.SearchIssueIDsByKeyword(context.TODO(), "first", []int64{1}, 10, 0)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.EqualValues(t, 1, total)
|
assert.EqualValues(t, 1, total)
|
||||||
assert.EqualValues(t, []int64{1}, ids)
|
assert.EqualValues(t, []int64{1}, ids)
|
||||||
|
|
||||||
total, ids, err = SearchIssueIDsByKeyword(context.TODO(), "for", []int64{1}, 10, 0)
|
total, ids, err = issues_model.SearchIssueIDsByKeyword(context.TODO(), "for", []int64{1}, 10, 0)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.EqualValues(t, 5, total)
|
assert.EqualValues(t, 5, total)
|
||||||
assert.ElementsMatch(t, []int64{1, 2, 3, 5, 11}, ids)
|
assert.ElementsMatch(t, []int64{1, 2, 3, 5, 11}, ids)
|
||||||
|
|
||||||
// issue1's comment id 2
|
// issue1's comment id 2
|
||||||
total, ids, err = SearchIssueIDsByKeyword(context.TODO(), "good", []int64{1}, 10, 0)
|
total, ids, err = issues_model.SearchIssueIDsByKeyword(context.TODO(), "good", []int64{1}, 10, 0)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.EqualValues(t, 1, total)
|
assert.EqualValues(t, 1, total)
|
||||||
assert.EqualValues(t, []int64{1}, ids)
|
assert.EqualValues(t, []int64{1}, ids)
|
||||||
|
@ -349,23 +349,23 @@ func TestGetRepoIDsForIssuesOptions(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
|
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
|
||||||
for _, test := range []struct {
|
for _, test := range []struct {
|
||||||
Opts IssuesOptions
|
Opts issues_model.IssuesOptions
|
||||||
ExpectedRepoIDs []int64
|
ExpectedRepoIDs []int64
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
IssuesOptions{
|
issues_model.IssuesOptions{
|
||||||
AssigneeID: 2,
|
AssigneeID: 2,
|
||||||
},
|
},
|
||||||
[]int64{3, 32},
|
[]int64{3, 32},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
IssuesOptions{
|
issues_model.IssuesOptions{
|
||||||
RepoCond: builder.In("repo_id", 1, 2),
|
RepoCond: builder.In("repo_id", 1, 2),
|
||||||
},
|
},
|
||||||
[]int64{1, 2},
|
[]int64{1, 2},
|
||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
repoIDs, err := GetRepoIDsForIssuesOptions(&test.Opts, user)
|
repoIDs, err := issues_model.GetRepoIDsForIssuesOptions(&test.Opts, user)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
if assert.Len(t, repoIDs, len(test.ExpectedRepoIDs)) {
|
if assert.Len(t, repoIDs, len(test.ExpectedRepoIDs)) {
|
||||||
for i, repoID := range repoIDs {
|
for i, repoID := range repoIDs {
|
||||||
|
@ -375,20 +375,20 @@ func TestGetRepoIDsForIssuesOptions(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func testInsertIssue(t *testing.T, title, content string, expectIndex int64) *Issue {
|
func testInsertIssue(t *testing.T, title, content string, expectIndex int64) *issues_model.Issue {
|
||||||
var newIssue Issue
|
var newIssue issues_model.Issue
|
||||||
t.Run(title, func(t *testing.T) {
|
t.Run(title, func(t *testing.T) {
|
||||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository)
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository)
|
||||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
|
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
|
||||||
|
|
||||||
issue := Issue{
|
issue := issues_model.Issue{
|
||||||
RepoID: repo.ID,
|
RepoID: repo.ID,
|
||||||
PosterID: user.ID,
|
PosterID: user.ID,
|
||||||
Poster: user,
|
Poster: user,
|
||||||
Title: title,
|
Title: title,
|
||||||
Content: content,
|
Content: content,
|
||||||
}
|
}
|
||||||
err := NewIssue(repo, &issue, nil, nil)
|
err := issues_model.NewIssue(repo, &issue, nil, nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
has, err := db.GetEngine(db.DefaultContext).ID(issue.ID).Get(&newIssue)
|
has, err := db.GetEngine(db.DefaultContext).ID(issue.ID).Get(&newIssue)
|
||||||
|
@ -408,75 +408,23 @@ func TestIssue_InsertIssue(t *testing.T) {
|
||||||
|
|
||||||
// there are 5 issues and max index is 5 on repository 1, so this one should 6
|
// there are 5 issues and max index is 5 on repository 1, so this one should 6
|
||||||
issue := testInsertIssue(t, "my issue1", "special issue's comments?", 6)
|
issue := testInsertIssue(t, "my issue1", "special issue's comments?", 6)
|
||||||
_, err := db.GetEngine(db.DefaultContext).ID(issue.ID).Delete(new(Issue))
|
_, err := db.GetEngine(db.DefaultContext).ID(issue.ID).Delete(new(issues_model.Issue))
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
issue = testInsertIssue(t, `my issue2, this is my son's love \n \r \ `, "special issue's '' comments?", 7)
|
issue = testInsertIssue(t, `my issue2, this is my son's love \n \r \ `, "special issue's '' comments?", 7)
|
||||||
_, err = db.GetEngine(db.DefaultContext).ID(issue.ID).Delete(new(Issue))
|
_, err = db.GetEngine(db.DefaultContext).ID(issue.ID).Delete(new(issues_model.Issue))
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestIssue_DeleteIssue(t *testing.T) {
|
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
|
||||||
|
|
||||||
issueIDs, err := GetIssueIDsByRepoID(db.DefaultContext, 1)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.EqualValues(t, 5, len(issueIDs))
|
|
||||||
|
|
||||||
issue := &Issue{
|
|
||||||
RepoID: 1,
|
|
||||||
ID: issueIDs[2],
|
|
||||||
}
|
|
||||||
|
|
||||||
err = DeleteIssue(issue)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
issueIDs, err = GetIssueIDsByRepoID(db.DefaultContext, 1)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.EqualValues(t, 4, len(issueIDs))
|
|
||||||
|
|
||||||
// check attachment removal
|
|
||||||
attachments, err := repo_model.GetAttachmentsByIssueID(db.DefaultContext, 4)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
issue, err = GetIssueByID(4)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
err = DeleteIssue(issue)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.EqualValues(t, 2, len(attachments))
|
|
||||||
for i := range attachments {
|
|
||||||
attachment, err := repo_model.GetAttachmentByUUID(db.DefaultContext, attachments[i].UUID)
|
|
||||||
assert.Error(t, err)
|
|
||||||
assert.True(t, repo_model.IsErrAttachmentNotExist(err))
|
|
||||||
assert.Nil(t, attachment)
|
|
||||||
}
|
|
||||||
|
|
||||||
// check issue dependencies
|
|
||||||
user, err := user_model.GetUserByID(1)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
issue1, err := GetIssueByID(1)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
issue2, err := GetIssueByID(2)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
err = CreateIssueDependency(user, issue1, issue2)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
left, err := IssueNoDependenciesLeft(db.DefaultContext, issue1)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.False(t, left)
|
|
||||||
err = DeleteIssue(&Issue{ID: 2})
|
|
||||||
assert.NoError(t, err)
|
|
||||||
left, err = IssueNoDependenciesLeft(db.DefaultContext, issue1)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.True(t, left)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestIssue_ResolveMentions(t *testing.T) {
|
func TestIssue_ResolveMentions(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
testSuccess := func(owner, repo, doer string, mentions []string, expected []int64) {
|
testSuccess := func(owner, repo, doer string, mentions []string, expected []int64) {
|
||||||
o := unittest.AssertExistsAndLoadBean(t, &user_model.User{LowerName: owner}).(*user_model.User)
|
o := unittest.AssertExistsAndLoadBean(t, &user_model.User{LowerName: owner}).(*user_model.User)
|
||||||
r := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerID: o.ID, LowerName: repo}).(*repo_model.Repository)
|
r := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerID: o.ID, LowerName: repo}).(*repo_model.Repository)
|
||||||
issue := &Issue{RepoID: r.ID}
|
issue := &issues_model.Issue{RepoID: r.ID}
|
||||||
d := unittest.AssertExistsAndLoadBean(t, &user_model.User{LowerName: doer}).(*user_model.User)
|
d := unittest.AssertExistsAndLoadBean(t, &user_model.User{LowerName: doer}).(*user_model.User)
|
||||||
resolved, err := ResolveIssueMentionsByVisibility(db.DefaultContext, issue, d, mentions)
|
resolved, err := issues_model.ResolveIssueMentionsByVisibility(db.DefaultContext, issue, d, mentions)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
ids := make([]int64, len(resolved))
|
ids := make([]int64, len(resolved))
|
||||||
for i, user := range resolved {
|
for i, user := range resolved {
|
||||||
|
@ -523,7 +471,7 @@ func TestCorrectIssueStats(t *testing.T) {
|
||||||
// Each new issues will have a constant description "Bugs are nasty"
|
// Each new issues will have a constant description "Bugs are nasty"
|
||||||
// Which will be used later on.
|
// Which will be used later on.
|
||||||
|
|
||||||
issueAmount := maxQueryParameters + 10
|
issueAmount := issues_model.MaxQueryParameters + 10
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
for i := 0; i < issueAmount; i++ {
|
for i := 0; i < issueAmount; i++ {
|
||||||
|
@ -536,7 +484,7 @@ func TestCorrectIssueStats(t *testing.T) {
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
|
|
||||||
// Now we will get all issueID's that match the "Bugs are nasty" query.
|
// Now we will get all issueID's that match the "Bugs are nasty" query.
|
||||||
total, ids, err := SearchIssueIDsByKeyword(context.TODO(), "Bugs are nasty", []int64{1}, issueAmount, 0)
|
total, ids, err := issues_model.SearchIssueIDsByKeyword(context.TODO(), "Bugs are nasty", []int64{1}, issueAmount, 0)
|
||||||
|
|
||||||
// Just to be sure.
|
// Just to be sure.
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
@ -544,7 +492,7 @@ func TestCorrectIssueStats(t *testing.T) {
|
||||||
|
|
||||||
// Now we will call the GetIssueStats with these IDs and if working,
|
// Now we will call the GetIssueStats with these IDs and if working,
|
||||||
// get the correct stats back.
|
// get the correct stats back.
|
||||||
issueStats, err := GetIssueStats(&IssueStatsOptions{
|
issueStats, err := issues_model.GetIssueStats(&issues_model.IssueStatsOptions{
|
||||||
RepoID: 1,
|
RepoID: 1,
|
||||||
IssueIDs: ids,
|
IssueIDs: ids,
|
||||||
})
|
})
|
||||||
|
@ -556,19 +504,19 @@ func TestCorrectIssueStats(t *testing.T) {
|
||||||
|
|
||||||
func TestIssueForeignReference(t *testing.T) {
|
func TestIssueForeignReference(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
issue := unittest.AssertExistsAndLoadBean(t, &Issue{ID: 4}).(*Issue)
|
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 4}).(*issues_model.Issue)
|
||||||
assert.NotEqualValues(t, issue.Index, issue.ID) // make sure they are different to avoid false positive
|
assert.NotEqualValues(t, issue.Index, issue.ID) // make sure they are different to avoid false positive
|
||||||
|
|
||||||
// it is fine for an issue to not have a foreign reference
|
// it is fine for an issue to not have a foreign reference
|
||||||
err := issue.LoadAttributes()
|
err := issue.LoadAttributes(db.DefaultContext)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Nil(t, issue.ForeignReference)
|
assert.Nil(t, issue.ForeignReference)
|
||||||
|
|
||||||
var foreignIndex int64 = 12345
|
var foreignIndex int64 = 12345
|
||||||
_, err = GetIssueByForeignIndex(context.Background(), issue.RepoID, foreignIndex)
|
_, err = issues_model.GetIssueByForeignIndex(context.Background(), issue.RepoID, foreignIndex)
|
||||||
assert.True(t, foreignreference.IsErrLocalIndexNotExist(err))
|
assert.True(t, foreignreference.IsErrLocalIndexNotExist(err))
|
||||||
|
|
||||||
_, err = db.GetEngine(db.DefaultContext).Insert(&foreignreference.ForeignReference{
|
err = db.Insert(db.DefaultContext, &foreignreference.ForeignReference{
|
||||||
LocalIndex: issue.Index,
|
LocalIndex: issue.Index,
|
||||||
ForeignIndex: strconv.FormatInt(foreignIndex, 10),
|
ForeignIndex: strconv.FormatInt(foreignIndex, 10),
|
||||||
RepoID: issue.RepoID,
|
RepoID: issue.RepoID,
|
||||||
|
@ -576,12 +524,12 @@ func TestIssueForeignReference(t *testing.T) {
|
||||||
})
|
})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
err = issue.LoadAttributes()
|
err = issue.LoadAttributes(db.DefaultContext)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
assert.EqualValues(t, issue.ForeignReference.ForeignIndex, strconv.FormatInt(foreignIndex, 10))
|
assert.EqualValues(t, issue.ForeignReference.ForeignIndex, strconv.FormatInt(foreignIndex, 10))
|
||||||
|
|
||||||
found, err := GetIssueByForeignIndex(context.Background(), issue.RepoID, foreignIndex)
|
found, err := issues_model.GetIssueByForeignIndex(context.Background(), issue.RepoID, foreignIndex)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.EqualValues(t, found.Index, issue.Index)
|
assert.EqualValues(t, found.Index, issue.Index)
|
||||||
}
|
}
|
||||||
|
@ -608,7 +556,7 @@ func TestLoadTotalTrackedTime(t *testing.T) {
|
||||||
|
|
||||||
func TestCountIssues(t *testing.T) {
|
func TestCountIssues(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
count, err := CountIssues(&IssuesOptions{})
|
count, err := issues_model.CountIssues(&issues_model.IssuesOptions{})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.EqualValues(t, 17, count)
|
assert.EqualValues(t, 17, count)
|
||||||
}
|
}
|
|
@ -2,7 +2,7 @@
|
||||||
// Use of this source code is governed by a MIT-style
|
// Use of this source code is governed by a MIT-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package models
|
package issues
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
@ -25,7 +25,8 @@ func init() {
|
||||||
db.RegisterModel(new(IssueUser))
|
db.RegisterModel(new(IssueUser))
|
||||||
}
|
}
|
||||||
|
|
||||||
func newIssueUsers(ctx context.Context, repo *repo_model.Repository, issue *Issue) error {
|
// NewIssueUsers inserts an issue related users
|
||||||
|
func NewIssueUsers(ctx context.Context, repo *repo_model.Repository, issue *Issue) error {
|
||||||
assignees, err := repo_model.GetRepoAssignees(ctx, repo)
|
assignees, err := repo_model.GetRepoAssignees(ctx, repo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("getAssignees: %v", err)
|
return fmt.Errorf("getAssignees: %v", err)
|
62
models/issues/issue_user_test.go
Normal file
62
models/issues/issue_user_test.go
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
// Copyright 2017 The Gogs Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package issues_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/models/db"
|
||||||
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
|
"code.gitea.io/gitea/models/unittest"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_NewIssueUsers(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository)
|
||||||
|
newIssue := &issues_model.Issue{
|
||||||
|
RepoID: repo.ID,
|
||||||
|
PosterID: 4,
|
||||||
|
Index: 6,
|
||||||
|
Title: "newTestIssueTitle",
|
||||||
|
Content: "newTestIssueContent",
|
||||||
|
}
|
||||||
|
|
||||||
|
// artificially insert new issue
|
||||||
|
unittest.AssertSuccessfulInsert(t, newIssue)
|
||||||
|
|
||||||
|
assert.NoError(t, issues_model.NewIssueUsers(db.DefaultContext, repo, newIssue))
|
||||||
|
|
||||||
|
// issue_user table should now have entries for new issue
|
||||||
|
unittest.AssertExistsAndLoadBean(t, &issues_model.IssueUser{IssueID: newIssue.ID, UID: newIssue.PosterID})
|
||||||
|
unittest.AssertExistsAndLoadBean(t, &issues_model.IssueUser{IssueID: newIssue.ID, UID: repo.OwnerID})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUpdateIssueUserByRead(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1}).(*issues_model.Issue)
|
||||||
|
|
||||||
|
assert.NoError(t, issues_model.UpdateIssueUserByRead(4, issue.ID))
|
||||||
|
unittest.AssertExistsAndLoadBean(t, &issues_model.IssueUser{IssueID: issue.ID, UID: 4}, "is_read=1")
|
||||||
|
|
||||||
|
assert.NoError(t, issues_model.UpdateIssueUserByRead(4, issue.ID))
|
||||||
|
unittest.AssertExistsAndLoadBean(t, &issues_model.IssueUser{IssueID: issue.ID, UID: 4}, "is_read=1")
|
||||||
|
|
||||||
|
assert.NoError(t, issues_model.UpdateIssueUserByRead(unittest.NonexistentID, unittest.NonexistentID))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUpdateIssueUsersByMentions(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1}).(*issues_model.Issue)
|
||||||
|
|
||||||
|
uids := []int64{2, 5}
|
||||||
|
assert.NoError(t, issues_model.UpdateIssueUsersByMentions(db.DefaultContext, issue.ID, uids))
|
||||||
|
for _, uid := range uids {
|
||||||
|
unittest.AssertExistsAndLoadBean(t, &issues_model.IssueUser{IssueID: issue.ID, UID: uid}, "is_mentioned=1")
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,7 +2,7 @@
|
||||||
// Use of this source code is governed by a MIT-style
|
// Use of this source code is governed by a MIT-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package models
|
package issues
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
@ -125,7 +125,8 @@ func CountIssueWatchers(ctx context.Context, issueID int64) (int64, error) {
|
||||||
Join("INNER", "`user`", "`user`.id = `issue_watch`.user_id").Count(new(IssueWatch))
|
Join("INNER", "`user`", "`user`.id = `issue_watch`.user_id").Count(new(IssueWatch))
|
||||||
}
|
}
|
||||||
|
|
||||||
func removeIssueWatchersByRepoID(ctx context.Context, userID, repoID int64) error {
|
// RemoveIssueWatchersByRepoID remove issue watchers by repoID
|
||||||
|
func RemoveIssueWatchersByRepoID(ctx context.Context, userID, repoID int64) error {
|
||||||
_, err := db.GetEngine(ctx).
|
_, err := db.GetEngine(ctx).
|
||||||
Join("INNER", "issue", "`issue`.id = `issue_watch`.issue_id AND `issue`.repo_id = ?", repoID).
|
Join("INNER", "issue", "`issue`.id = `issue_watch`.issue_id AND `issue`.repo_id = ?", repoID).
|
||||||
Where("`issue_watch`.user_id = ?", userID).
|
Where("`issue_watch`.user_id = ?", userID).
|
|
@ -2,12 +2,13 @@
|
||||||
// Use of this source code is governed by a MIT-style
|
// Use of this source code is governed by a MIT-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package models
|
package issues_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
@ -16,28 +17,28 @@ import (
|
||||||
func TestCreateOrUpdateIssueWatch(t *testing.T) {
|
func TestCreateOrUpdateIssueWatch(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
assert.NoError(t, CreateOrUpdateIssueWatch(3, 1, true))
|
assert.NoError(t, issues_model.CreateOrUpdateIssueWatch(3, 1, true))
|
||||||
iw := unittest.AssertExistsAndLoadBean(t, &IssueWatch{UserID: 3, IssueID: 1}).(*IssueWatch)
|
iw := unittest.AssertExistsAndLoadBean(t, &issues_model.IssueWatch{UserID: 3, IssueID: 1}).(*issues_model.IssueWatch)
|
||||||
assert.True(t, iw.IsWatching)
|
assert.True(t, iw.IsWatching)
|
||||||
|
|
||||||
assert.NoError(t, CreateOrUpdateIssueWatch(1, 1, false))
|
assert.NoError(t, issues_model.CreateOrUpdateIssueWatch(1, 1, false))
|
||||||
iw = unittest.AssertExistsAndLoadBean(t, &IssueWatch{UserID: 1, IssueID: 1}).(*IssueWatch)
|
iw = unittest.AssertExistsAndLoadBean(t, &issues_model.IssueWatch{UserID: 1, IssueID: 1}).(*issues_model.IssueWatch)
|
||||||
assert.False(t, iw.IsWatching)
|
assert.False(t, iw.IsWatching)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetIssueWatch(t *testing.T) {
|
func TestGetIssueWatch(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
_, exists, err := GetIssueWatch(db.DefaultContext, 9, 1)
|
_, exists, err := issues_model.GetIssueWatch(db.DefaultContext, 9, 1)
|
||||||
assert.True(t, exists)
|
assert.True(t, exists)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
iw, exists, err := GetIssueWatch(db.DefaultContext, 2, 2)
|
iw, exists, err := issues_model.GetIssueWatch(db.DefaultContext, 2, 2)
|
||||||
assert.True(t, exists)
|
assert.True(t, exists)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.False(t, iw.IsWatching)
|
assert.False(t, iw.IsWatching)
|
||||||
|
|
||||||
_, exists, err = GetIssueWatch(db.DefaultContext, 3, 1)
|
_, exists, err = issues_model.GetIssueWatch(db.DefaultContext, 3, 1)
|
||||||
assert.False(t, exists)
|
assert.False(t, exists)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
@ -45,22 +46,22 @@ func TestGetIssueWatch(t *testing.T) {
|
||||||
func TestGetIssueWatchers(t *testing.T) {
|
func TestGetIssueWatchers(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
iws, err := GetIssueWatchers(db.DefaultContext, 1, db.ListOptions{})
|
iws, err := issues_model.GetIssueWatchers(db.DefaultContext, 1, db.ListOptions{})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
// Watcher is inactive, thus 0
|
// Watcher is inactive, thus 0
|
||||||
assert.Len(t, iws, 0)
|
assert.Len(t, iws, 0)
|
||||||
|
|
||||||
iws, err = GetIssueWatchers(db.DefaultContext, 2, db.ListOptions{})
|
iws, err = issues_model.GetIssueWatchers(db.DefaultContext, 2, db.ListOptions{})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
// Watcher is explicit not watching
|
// Watcher is explicit not watching
|
||||||
assert.Len(t, iws, 0)
|
assert.Len(t, iws, 0)
|
||||||
|
|
||||||
iws, err = GetIssueWatchers(db.DefaultContext, 5, db.ListOptions{})
|
iws, err = issues_model.GetIssueWatchers(db.DefaultContext, 5, db.ListOptions{})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
// Issue has no Watchers
|
// Issue has no Watchers
|
||||||
assert.Len(t, iws, 0)
|
assert.Len(t, iws, 0)
|
||||||
|
|
||||||
iws, err = GetIssueWatchers(db.DefaultContext, 7, db.ListOptions{})
|
iws, err = issues_model.GetIssueWatchers(db.DefaultContext, 7, db.ListOptions{})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
// Issue has one watcher
|
// Issue has one watcher
|
||||||
assert.Len(t, iws, 1)
|
assert.Len(t, iws, 1)
|
|
@ -2,7 +2,7 @@
|
||||||
// Use of this source code is governed by a MIT-style
|
// Use of this source code is governed by a MIT-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package models
|
package issues
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
@ -55,15 +55,8 @@ func neuterCrossReferencesIds(ctx context.Context, ids []int64) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// .___
|
// AddCrossReferences add cross repositories references.
|
||||||
// | | ______ ________ __ ____
|
func (issue *Issue) AddCrossReferences(stdCtx context.Context, doer *user_model.User, removeOld bool) error {
|
||||||
// | |/ ___// ___/ | \_/ __ \
|
|
||||||
// | |\___ \ \___ \| | /\ ___/
|
|
||||||
// |___/____ >____ >____/ \___ >
|
|
||||||
// \/ \/ \/
|
|
||||||
//
|
|
||||||
|
|
||||||
func (issue *Issue) addCrossReferences(stdCtx context.Context, doer *user_model.User, removeOld bool) error {
|
|
||||||
var commentType CommentType
|
var commentType CommentType
|
||||||
if issue.IsPull {
|
if issue.IsPull {
|
||||||
commentType = CommentTypePullRef
|
commentType = CommentTypePullRef
|
||||||
|
@ -237,15 +230,8 @@ func (issue *Issue) verifyReferencedIssue(stdCtx context.Context, ctx *crossRefe
|
||||||
return refIssue, refAction, nil
|
return refIssue, refAction, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// _________ __
|
// AddCrossReferences add cross references
|
||||||
// \_ ___ \ ____ _____ _____ ____ _____/ |_
|
func (comment *Comment) AddCrossReferences(stdCtx context.Context, doer *user_model.User, removeOld bool) error {
|
||||||
// / \ \/ / _ \ / \ / \_/ __ \ / \ __\
|
|
||||||
// \ \___( <_> ) Y Y \ Y Y \ ___/| | \ |
|
|
||||||
// \______ /\____/|__|_| /__|_| /\___ >___| /__|
|
|
||||||
// \/ \/ \/ \/ \/
|
|
||||||
//
|
|
||||||
|
|
||||||
func (comment *Comment) addCrossReferences(stdCtx context.Context, doer *user_model.User, removeOld bool) error {
|
|
||||||
if comment.Type != CommentTypeCode && comment.Type != CommentTypeComment {
|
if comment.Type != CommentTypeCode && comment.Type != CommentTypeComment {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -280,7 +266,7 @@ func (comment *Comment) LoadRefIssue() (err error) {
|
||||||
if comment.RefIssue != nil {
|
if comment.RefIssue != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
comment.RefIssue, err = GetIssueByID(comment.RefIssueID)
|
comment.RefIssue, err = GetIssueByID(db.DefaultContext, comment.RefIssueID)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
err = comment.RefIssue.LoadRepo(db.DefaultContext)
|
err = comment.RefIssue.LoadRepo(db.DefaultContext)
|
||||||
}
|
}
|
|
@ -2,13 +2,14 @@
|
||||||
// Use of this source code is governed by a MIT-style
|
// Use of this source code is governed by a MIT-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package models
|
package issues_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
@ -26,8 +27,8 @@ func TestXRef_AddCrossReferences(t *testing.T) {
|
||||||
// PR to close issue #1
|
// PR to close issue #1
|
||||||
content := fmt.Sprintf("content2, closes #%d", itarget.Index)
|
content := fmt.Sprintf("content2, closes #%d", itarget.Index)
|
||||||
pr := testCreateIssue(t, 1, 2, "title2", content, true)
|
pr := testCreateIssue(t, 1, 2, "title2", content, true)
|
||||||
ref := unittest.AssertExistsAndLoadBean(t, &Comment{IssueID: itarget.ID, RefIssueID: pr.ID, RefCommentID: 0}).(*Comment)
|
ref := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: itarget.ID, RefIssueID: pr.ID, RefCommentID: 0}).(*issues_model.Comment)
|
||||||
assert.Equal(t, CommentTypePullRef, ref.Type)
|
assert.Equal(t, issues_model.CommentTypePullRef, ref.Type)
|
||||||
assert.Equal(t, pr.RepoID, ref.RefRepoID)
|
assert.Equal(t, pr.RepoID, ref.RefRepoID)
|
||||||
assert.True(t, ref.RefIsPull)
|
assert.True(t, ref.RefIsPull)
|
||||||
assert.Equal(t, references.XRefActionCloses, ref.RefAction)
|
assert.Equal(t, references.XRefActionCloses, ref.RefAction)
|
||||||
|
@ -35,8 +36,8 @@ func TestXRef_AddCrossReferences(t *testing.T) {
|
||||||
// Comment on PR to reopen issue #1
|
// Comment on PR to reopen issue #1
|
||||||
content = fmt.Sprintf("content2, reopens #%d", itarget.Index)
|
content = fmt.Sprintf("content2, reopens #%d", itarget.Index)
|
||||||
c := testCreateComment(t, 1, 2, pr.ID, content)
|
c := testCreateComment(t, 1, 2, pr.ID, content)
|
||||||
ref = unittest.AssertExistsAndLoadBean(t, &Comment{IssueID: itarget.ID, RefIssueID: pr.ID, RefCommentID: c.ID}).(*Comment)
|
ref = unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: itarget.ID, RefIssueID: pr.ID, RefCommentID: c.ID}).(*issues_model.Comment)
|
||||||
assert.Equal(t, CommentTypeCommentRef, ref.Type)
|
assert.Equal(t, issues_model.CommentTypeCommentRef, ref.Type)
|
||||||
assert.Equal(t, pr.RepoID, ref.RefRepoID)
|
assert.Equal(t, pr.RepoID, ref.RefRepoID)
|
||||||
assert.True(t, ref.RefIsPull)
|
assert.True(t, ref.RefIsPull)
|
||||||
assert.Equal(t, references.XRefActionReopens, ref.RefAction)
|
assert.Equal(t, references.XRefActionReopens, ref.RefAction)
|
||||||
|
@ -44,8 +45,8 @@ func TestXRef_AddCrossReferences(t *testing.T) {
|
||||||
// Issue mentioning issue #1
|
// Issue mentioning issue #1
|
||||||
content = fmt.Sprintf("content3, mentions #%d", itarget.Index)
|
content = fmt.Sprintf("content3, mentions #%d", itarget.Index)
|
||||||
i := testCreateIssue(t, 1, 2, "title3", content, false)
|
i := testCreateIssue(t, 1, 2, "title3", content, false)
|
||||||
ref = unittest.AssertExistsAndLoadBean(t, &Comment{IssueID: itarget.ID, RefIssueID: i.ID, RefCommentID: 0}).(*Comment)
|
ref = unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: itarget.ID, RefIssueID: i.ID, RefCommentID: 0}).(*issues_model.Comment)
|
||||||
assert.Equal(t, CommentTypeIssueRef, ref.Type)
|
assert.Equal(t, issues_model.CommentTypeIssueRef, ref.Type)
|
||||||
assert.Equal(t, pr.RepoID, ref.RefRepoID)
|
assert.Equal(t, pr.RepoID, ref.RefRepoID)
|
||||||
assert.False(t, ref.RefIsPull)
|
assert.False(t, ref.RefIsPull)
|
||||||
assert.Equal(t, references.XRefActionNone, ref.RefAction)
|
assert.Equal(t, references.XRefActionNone, ref.RefAction)
|
||||||
|
@ -56,8 +57,8 @@ func TestXRef_AddCrossReferences(t *testing.T) {
|
||||||
// Cross-reference to issue #4 by admin
|
// Cross-reference to issue #4 by admin
|
||||||
content = fmt.Sprintf("content5, mentions user3/repo3#%d", itarget.Index)
|
content = fmt.Sprintf("content5, mentions user3/repo3#%d", itarget.Index)
|
||||||
i = testCreateIssue(t, 2, 1, "title5", content, false)
|
i = testCreateIssue(t, 2, 1, "title5", content, false)
|
||||||
ref = unittest.AssertExistsAndLoadBean(t, &Comment{IssueID: itarget.ID, RefIssueID: i.ID, RefCommentID: 0}).(*Comment)
|
ref = unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: itarget.ID, RefIssueID: i.ID, RefCommentID: 0}).(*issues_model.Comment)
|
||||||
assert.Equal(t, CommentTypeIssueRef, ref.Type)
|
assert.Equal(t, issues_model.CommentTypeIssueRef, ref.Type)
|
||||||
assert.Equal(t, i.RepoID, ref.RefRepoID)
|
assert.Equal(t, i.RepoID, ref.RefRepoID)
|
||||||
assert.False(t, ref.RefIsPull)
|
assert.False(t, ref.RefIsPull)
|
||||||
assert.Equal(t, references.XRefActionNone, ref.RefAction)
|
assert.Equal(t, references.XRefActionNone, ref.RefAction)
|
||||||
|
@ -65,7 +66,7 @@ func TestXRef_AddCrossReferences(t *testing.T) {
|
||||||
// Cross-reference to issue #4 with no permission
|
// Cross-reference to issue #4 with no permission
|
||||||
content = fmt.Sprintf("content6, mentions user3/repo3#%d", itarget.Index)
|
content = fmt.Sprintf("content6, mentions user3/repo3#%d", itarget.Index)
|
||||||
i = testCreateIssue(t, 4, 5, "title6", content, false)
|
i = testCreateIssue(t, 4, 5, "title6", content, false)
|
||||||
unittest.AssertNotExistsBean(t, &Comment{IssueID: itarget.ID, RefIssueID: i.ID, RefCommentID: 0})
|
unittest.AssertNotExistsBean(t, &issues_model.Comment{IssueID: itarget.ID, RefIssueID: i.ID, RefCommentID: 0})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestXRef_NeuterCrossReferences(t *testing.T) {
|
func TestXRef_NeuterCrossReferences(t *testing.T) {
|
||||||
|
@ -77,16 +78,16 @@ func TestXRef_NeuterCrossReferences(t *testing.T) {
|
||||||
// Issue mentioning issue #1
|
// Issue mentioning issue #1
|
||||||
title := fmt.Sprintf("title2, mentions #%d", itarget.Index)
|
title := fmt.Sprintf("title2, mentions #%d", itarget.Index)
|
||||||
i := testCreateIssue(t, 1, 2, title, "content2", false)
|
i := testCreateIssue(t, 1, 2, title, "content2", false)
|
||||||
ref := unittest.AssertExistsAndLoadBean(t, &Comment{IssueID: itarget.ID, RefIssueID: i.ID, RefCommentID: 0}).(*Comment)
|
ref := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: itarget.ID, RefIssueID: i.ID, RefCommentID: 0}).(*issues_model.Comment)
|
||||||
assert.Equal(t, CommentTypeIssueRef, ref.Type)
|
assert.Equal(t, issues_model.CommentTypeIssueRef, ref.Type)
|
||||||
assert.Equal(t, references.XRefActionNone, ref.RefAction)
|
assert.Equal(t, references.XRefActionNone, ref.RefAction)
|
||||||
|
|
||||||
d := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
|
d := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
|
||||||
i.Title = "title2, no mentions"
|
i.Title = "title2, no mentions"
|
||||||
assert.NoError(t, ChangeIssueTitle(i, d, title))
|
assert.NoError(t, issues_model.ChangeIssueTitle(i, d, title))
|
||||||
|
|
||||||
ref = unittest.AssertExistsAndLoadBean(t, &Comment{IssueID: itarget.ID, RefIssueID: i.ID, RefCommentID: 0}).(*Comment)
|
ref = unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: itarget.ID, RefIssueID: i.ID, RefCommentID: 0}).(*issues_model.Comment)
|
||||||
assert.Equal(t, CommentTypeIssueRef, ref.Type)
|
assert.Equal(t, issues_model.CommentTypeIssueRef, ref.Type)
|
||||||
assert.Equal(t, references.XRefActionNeutered, ref.RefAction)
|
assert.Equal(t, references.XRefActionNeutered, ref.RefAction)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,25 +99,25 @@ func TestXRef_ResolveCrossReferences(t *testing.T) {
|
||||||
i1 := testCreateIssue(t, 1, 2, "title1", "content1", false)
|
i1 := testCreateIssue(t, 1, 2, "title1", "content1", false)
|
||||||
i2 := testCreateIssue(t, 1, 2, "title2", "content2", false)
|
i2 := testCreateIssue(t, 1, 2, "title2", "content2", false)
|
||||||
i3 := testCreateIssue(t, 1, 2, "title3", "content3", false)
|
i3 := testCreateIssue(t, 1, 2, "title3", "content3", false)
|
||||||
_, err := ChangeIssueStatus(db.DefaultContext, i3, d, true)
|
_, err := issues_model.ChangeIssueStatus(db.DefaultContext, i3, d, true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
pr := testCreatePR(t, 1, 2, "titlepr", fmt.Sprintf("closes #%d", i1.Index))
|
pr := testCreatePR(t, 1, 2, "titlepr", fmt.Sprintf("closes #%d", i1.Index))
|
||||||
rp := unittest.AssertExistsAndLoadBean(t, &Comment{IssueID: i1.ID, RefIssueID: pr.Issue.ID, RefCommentID: 0}).(*Comment)
|
rp := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: i1.ID, RefIssueID: pr.Issue.ID, RefCommentID: 0}).(*issues_model.Comment)
|
||||||
|
|
||||||
c1 := testCreateComment(t, 1, 2, pr.Issue.ID, fmt.Sprintf("closes #%d", i2.Index))
|
c1 := testCreateComment(t, 1, 2, pr.Issue.ID, fmt.Sprintf("closes #%d", i2.Index))
|
||||||
r1 := unittest.AssertExistsAndLoadBean(t, &Comment{IssueID: i2.ID, RefIssueID: pr.Issue.ID, RefCommentID: c1.ID}).(*Comment)
|
r1 := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: i2.ID, RefIssueID: pr.Issue.ID, RefCommentID: c1.ID}).(*issues_model.Comment)
|
||||||
|
|
||||||
// Must be ignored
|
// Must be ignored
|
||||||
c2 := testCreateComment(t, 1, 2, pr.Issue.ID, fmt.Sprintf("mentions #%d", i2.Index))
|
c2 := testCreateComment(t, 1, 2, pr.Issue.ID, fmt.Sprintf("mentions #%d", i2.Index))
|
||||||
unittest.AssertExistsAndLoadBean(t, &Comment{IssueID: i2.ID, RefIssueID: pr.Issue.ID, RefCommentID: c2.ID})
|
unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: i2.ID, RefIssueID: pr.Issue.ID, RefCommentID: c2.ID})
|
||||||
|
|
||||||
// Must be superseded by c4/r4
|
// Must be superseded by c4/r4
|
||||||
c3 := testCreateComment(t, 1, 2, pr.Issue.ID, fmt.Sprintf("reopens #%d", i3.Index))
|
c3 := testCreateComment(t, 1, 2, pr.Issue.ID, fmt.Sprintf("reopens #%d", i3.Index))
|
||||||
unittest.AssertExistsAndLoadBean(t, &Comment{IssueID: i3.ID, RefIssueID: pr.Issue.ID, RefCommentID: c3.ID})
|
unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: i3.ID, RefIssueID: pr.Issue.ID, RefCommentID: c3.ID})
|
||||||
|
|
||||||
c4 := testCreateComment(t, 1, 2, pr.Issue.ID, fmt.Sprintf("closes #%d", i3.Index))
|
c4 := testCreateComment(t, 1, 2, pr.Issue.ID, fmt.Sprintf("closes #%d", i3.Index))
|
||||||
r4 := unittest.AssertExistsAndLoadBean(t, &Comment{IssueID: i3.ID, RefIssueID: pr.Issue.ID, RefCommentID: c4.ID}).(*Comment)
|
r4 := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: i3.ID, RefIssueID: pr.Issue.ID, RefCommentID: c4.ID}).(*issues_model.Comment)
|
||||||
|
|
||||||
refs, err := pr.ResolveCrossReferences(db.DefaultContext)
|
refs, err := pr.ResolveCrossReferences(db.DefaultContext)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
@ -126,13 +127,13 @@ func TestXRef_ResolveCrossReferences(t *testing.T) {
|
||||||
assert.Equal(t, r4.ID, refs[2].ID, "bad ref r4: %+v", refs[2])
|
assert.Equal(t, r4.ID, refs[2].ID, "bad ref r4: %+v", refs[2])
|
||||||
}
|
}
|
||||||
|
|
||||||
func testCreateIssue(t *testing.T, repo, doer int64, title, content string, ispull bool) *Issue {
|
func testCreateIssue(t *testing.T, repo, doer int64, title, content string, ispull bool) *issues_model.Issue {
|
||||||
r := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repo}).(*repo_model.Repository)
|
r := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repo}).(*repo_model.Repository)
|
||||||
d := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: doer}).(*user_model.User)
|
d := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: doer}).(*user_model.User)
|
||||||
|
|
||||||
idx, err := db.GetNextResourceIndex("issue_index", r.ID)
|
idx, err := db.GetNextResourceIndex("issue_index", r.ID)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
i := &Issue{
|
i := &issues_model.Issue{
|
||||||
RepoID: r.ID,
|
RepoID: r.ID,
|
||||||
PosterID: d.ID,
|
PosterID: d.ID,
|
||||||
Poster: d,
|
Poster: d,
|
||||||
|
@ -145,39 +146,39 @@ func testCreateIssue(t *testing.T, repo, doer int64, title, content string, ispu
|
||||||
ctx, committer, err := db.TxContext()
|
ctx, committer, err := db.TxContext()
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
defer committer.Close()
|
defer committer.Close()
|
||||||
err = newIssue(ctx, d, NewIssueOptions{
|
err = issues_model.NewIssueWithIndex(ctx, d, issues_model.NewIssueOptions{
|
||||||
Repo: r,
|
Repo: r,
|
||||||
Issue: i,
|
Issue: i,
|
||||||
})
|
})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
i, err = getIssueByID(ctx, i.ID)
|
i, err = issues_model.GetIssueByID(ctx, i.ID)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NoError(t, i.addCrossReferences(ctx, d, false))
|
assert.NoError(t, i.AddCrossReferences(ctx, d, false))
|
||||||
assert.NoError(t, committer.Commit())
|
assert.NoError(t, committer.Commit())
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
|
|
||||||
func testCreatePR(t *testing.T, repo, doer int64, title, content string) *PullRequest {
|
func testCreatePR(t *testing.T, repo, doer int64, title, content string) *issues_model.PullRequest {
|
||||||
r := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repo}).(*repo_model.Repository)
|
r := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repo}).(*repo_model.Repository)
|
||||||
d := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: doer}).(*user_model.User)
|
d := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: doer}).(*user_model.User)
|
||||||
i := &Issue{RepoID: r.ID, PosterID: d.ID, Poster: d, Title: title, Content: content, IsPull: true}
|
i := &issues_model.Issue{RepoID: r.ID, PosterID: d.ID, Poster: d, Title: title, Content: content, IsPull: true}
|
||||||
pr := &PullRequest{HeadRepoID: repo, BaseRepoID: repo, HeadBranch: "head", BaseBranch: "base", Status: PullRequestStatusMergeable}
|
pr := &issues_model.PullRequest{HeadRepoID: repo, BaseRepoID: repo, HeadBranch: "head", BaseBranch: "base", Status: issues_model.PullRequestStatusMergeable}
|
||||||
assert.NoError(t, NewPullRequest(db.DefaultContext, r, i, nil, nil, pr))
|
assert.NoError(t, issues_model.NewPullRequest(db.DefaultContext, r, i, nil, nil, pr))
|
||||||
pr.Issue = i
|
pr.Issue = i
|
||||||
return pr
|
return pr
|
||||||
}
|
}
|
||||||
|
|
||||||
func testCreateComment(t *testing.T, repo, doer, issue int64, content string) *Comment {
|
func testCreateComment(t *testing.T, repo, doer, issue int64, content string) *issues_model.Comment {
|
||||||
d := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: doer}).(*user_model.User)
|
d := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: doer}).(*user_model.User)
|
||||||
i := unittest.AssertExistsAndLoadBean(t, &Issue{ID: issue}).(*Issue)
|
i := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: issue}).(*issues_model.Issue)
|
||||||
c := &Comment{Type: CommentTypeComment, PosterID: doer, Poster: d, IssueID: issue, Issue: i, Content: content}
|
c := &issues_model.Comment{Type: issues_model.CommentTypeComment, PosterID: doer, Poster: d, IssueID: issue, Issue: i, Content: content}
|
||||||
|
|
||||||
ctx, committer, err := db.TxContext()
|
ctx, committer, err := db.TxContext()
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
defer committer.Close()
|
defer committer.Close()
|
||||||
err = db.Insert(ctx, c)
|
err = db.Insert(ctx, c)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NoError(t, c.addCrossReferences(ctx, d, false))
|
assert.NoError(t, c.AddCrossReferences(ctx, d, false))
|
||||||
assert.NoError(t, committer.Commit())
|
assert.NoError(t, committer.Commit())
|
||||||
return c
|
return c
|
||||||
}
|
}
|
|
@ -3,7 +3,7 @@
|
||||||
// Use of this source code is governed by a MIT-style
|
// Use of this source code is governed by a MIT-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package models
|
package issues
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
@ -21,6 +21,53 @@ import (
|
||||||
"xorm.io/builder"
|
"xorm.io/builder"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ErrRepoLabelNotExist represents a "RepoLabelNotExist" kind of error.
|
||||||
|
type ErrRepoLabelNotExist struct {
|
||||||
|
LabelID int64
|
||||||
|
RepoID int64
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsErrRepoLabelNotExist checks if an error is a RepoErrLabelNotExist.
|
||||||
|
func IsErrRepoLabelNotExist(err error) bool {
|
||||||
|
_, ok := err.(ErrRepoLabelNotExist)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err ErrRepoLabelNotExist) Error() string {
|
||||||
|
return fmt.Sprintf("label does not exist [label_id: %d, repo_id: %d]", err.LabelID, err.RepoID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrOrgLabelNotExist represents a "OrgLabelNotExist" kind of error.
|
||||||
|
type ErrOrgLabelNotExist struct {
|
||||||
|
LabelID int64
|
||||||
|
OrgID int64
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsErrOrgLabelNotExist checks if an error is a OrgErrLabelNotExist.
|
||||||
|
func IsErrOrgLabelNotExist(err error) bool {
|
||||||
|
_, ok := err.(ErrOrgLabelNotExist)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err ErrOrgLabelNotExist) Error() string {
|
||||||
|
return fmt.Sprintf("label does not exist [label_id: %d, org_id: %d]", err.LabelID, err.OrgID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrLabelNotExist represents a "LabelNotExist" kind of error.
|
||||||
|
type ErrLabelNotExist struct {
|
||||||
|
LabelID int64
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsErrLabelNotExist checks if an error is a ErrLabelNotExist.
|
||||||
|
func IsErrLabelNotExist(err error) bool {
|
||||||
|
_, ok := err.(ErrLabelNotExist)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err ErrLabelNotExist) Error() string {
|
||||||
|
return fmt.Sprintf("label does not exist [label_id: %d]", err.LabelID)
|
||||||
|
}
|
||||||
|
|
||||||
// LabelColorPattern is a regexp witch can validate LabelColor
|
// LabelColorPattern is a regexp witch can validate LabelColor
|
||||||
var LabelColorPattern = regexp.MustCompile("^#?(?:[0-9a-fA-F]{6}|[0-9a-fA-F]{3})$")
|
var LabelColorPattern = regexp.MustCompile("^#?(?:[0-9a-fA-F]{6}|[0-9a-fA-F]{3})$")
|
||||||
|
|
||||||
|
@ -671,7 +718,8 @@ func DeleteIssueLabel(ctx context.Context, issue *Issue, label *Label, doer *use
|
||||||
return issue.LoadLabels(ctx)
|
return issue.LoadLabels(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func deleteLabelsByRepoID(ctx context.Context, repoID int64) error {
|
// DeleteLabelsByRepoID deletes labels of some repository
|
||||||
|
func DeleteLabelsByRepoID(ctx context.Context, repoID int64) error {
|
||||||
deleteCond := builder.Select("id").From("label").Where(builder.Eq{"label.repo_id": repoID})
|
deleteCond := builder.Select("id").From("label").Where(builder.Eq{"label.repo_id": repoID})
|
||||||
|
|
||||||
if _, err := db.GetEngine(ctx).In("label_id", deleteCond).
|
if _, err := db.GetEngine(ctx).In("label_id", deleteCond).
|
||||||
|
@ -682,3 +730,107 @@ func deleteLabelsByRepoID(ctx context.Context, repoID int64) error {
|
||||||
_, err := db.DeleteByBean(ctx, &Label{RepoID: repoID})
|
_, err := db.DeleteByBean(ctx, &Label{RepoID: repoID})
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CountOrphanedLabels return count of labels witch are broken and not accessible via ui anymore
|
||||||
|
func CountOrphanedLabels() (int64, error) {
|
||||||
|
noref, err := db.GetEngine(db.DefaultContext).Table("label").Where("repo_id=? AND org_id=?", 0, 0).Count("label.id")
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
norepo, err := db.GetEngine(db.DefaultContext).Table("label").
|
||||||
|
Where(builder.And(
|
||||||
|
builder.Gt{"repo_id": 0},
|
||||||
|
builder.NotIn("repo_id", builder.Select("id").From("repository")),
|
||||||
|
)).
|
||||||
|
Count()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
noorg, err := db.GetEngine(db.DefaultContext).Table("label").
|
||||||
|
Where(builder.And(
|
||||||
|
builder.Gt{"org_id": 0},
|
||||||
|
builder.NotIn("org_id", builder.Select("id").From("user")),
|
||||||
|
)).
|
||||||
|
Count()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return noref + norepo + noorg, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteOrphanedLabels delete labels witch are broken and not accessible via ui anymore
|
||||||
|
func DeleteOrphanedLabels() error {
|
||||||
|
// delete labels with no reference
|
||||||
|
if _, err := db.GetEngine(db.DefaultContext).Table("label").Where("repo_id=? AND org_id=?", 0, 0).Delete(new(Label)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete labels with none existing repos
|
||||||
|
if _, err := db.GetEngine(db.DefaultContext).
|
||||||
|
Where(builder.And(
|
||||||
|
builder.Gt{"repo_id": 0},
|
||||||
|
builder.NotIn("repo_id", builder.Select("id").From("repository")),
|
||||||
|
)).
|
||||||
|
Delete(Label{}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete labels with none existing orgs
|
||||||
|
if _, err := db.GetEngine(db.DefaultContext).
|
||||||
|
Where(builder.And(
|
||||||
|
builder.Gt{"org_id": 0},
|
||||||
|
builder.NotIn("org_id", builder.Select("id").From("user")),
|
||||||
|
)).
|
||||||
|
Delete(Label{}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CountOrphanedIssueLabels return count of IssueLabels witch have no label behind anymore
|
||||||
|
func CountOrphanedIssueLabels() (int64, error) {
|
||||||
|
return db.GetEngine(db.DefaultContext).Table("issue_label").
|
||||||
|
NotIn("label_id", builder.Select("id").From("label")).
|
||||||
|
Count()
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteOrphanedIssueLabels delete IssueLabels witch have no label behind anymore
|
||||||
|
func DeleteOrphanedIssueLabels() error {
|
||||||
|
_, err := db.GetEngine(db.DefaultContext).
|
||||||
|
NotIn("label_id", builder.Select("id").From("label")).
|
||||||
|
Delete(IssueLabel{})
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// CountIssueLabelWithOutsideLabels count label comments with outside label
|
||||||
|
func CountIssueLabelWithOutsideLabels() (int64, error) {
|
||||||
|
return db.GetEngine(db.DefaultContext).Where(builder.Expr("(label.org_id = 0 AND issue.repo_id != label.repo_id) OR (label.repo_id = 0 AND label.org_id != repository.owner_id)")).
|
||||||
|
Table("issue_label").
|
||||||
|
Join("inner", "label", "issue_label.label_id = label.id ").
|
||||||
|
Join("inner", "issue", "issue.id = issue_label.issue_id ").
|
||||||
|
Join("inner", "repository", "issue.repo_id = repository.id").
|
||||||
|
Count(new(IssueLabel))
|
||||||
|
}
|
||||||
|
|
||||||
|
// FixIssueLabelWithOutsideLabels fix label comments with outside label
|
||||||
|
func FixIssueLabelWithOutsideLabels() (int64, error) {
|
||||||
|
res, err := db.GetEngine(db.DefaultContext).Exec(`DELETE FROM issue_label WHERE issue_label.id IN (
|
||||||
|
SELECT il_too.id FROM (
|
||||||
|
SELECT il_too_too.id
|
||||||
|
FROM issue_label AS il_too_too
|
||||||
|
INNER JOIN label ON il_too_too.label_id = label.id
|
||||||
|
INNER JOIN issue on issue.id = il_too_too.issue_id
|
||||||
|
INNER JOIN repository on repository.id = issue.repo_id
|
||||||
|
WHERE
|
||||||
|
(label.org_id = 0 AND issue.repo_id != label.repo_id) OR (label.repo_id = 0 AND label.org_id != repository.owner_id)
|
||||||
|
) AS il_too )`)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.RowsAffected()
|
||||||
|
}
|
395
models/issues/label_test.go
Normal file
395
models/issues/label_test.go
Normal file
|
@ -0,0 +1,395 @@
|
||||||
|
// Copyright 2017 The Gitea Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package issues_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"html/template"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/models/db"
|
||||||
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
|
"code.gitea.io/gitea/models/unittest"
|
||||||
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TODO TestGetLabelTemplateFile
|
||||||
|
|
||||||
|
func TestLabel_CalOpenIssues(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
label := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 1}).(*issues_model.Label)
|
||||||
|
label.CalOpenIssues()
|
||||||
|
assert.EqualValues(t, 2, label.NumOpenIssues)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLabel_ForegroundColor(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
label := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 1}).(*issues_model.Label)
|
||||||
|
assert.Equal(t, template.CSS("#000"), label.ForegroundColor())
|
||||||
|
|
||||||
|
label = unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 2}).(*issues_model.Label)
|
||||||
|
assert.Equal(t, template.CSS("#fff"), label.ForegroundColor())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewLabels(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
labels := []*issues_model.Label{
|
||||||
|
{RepoID: 2, Name: "labelName2", Color: "#123456"},
|
||||||
|
{RepoID: 3, Name: "labelName3", Color: "#123"},
|
||||||
|
{RepoID: 4, Name: "labelName4", Color: "ABCDEF"},
|
||||||
|
{RepoID: 5, Name: "labelName5", Color: "DEF"},
|
||||||
|
}
|
||||||
|
assert.Error(t, issues_model.NewLabel(db.DefaultContext, &issues_model.Label{RepoID: 3, Name: "invalid Color", Color: ""}))
|
||||||
|
assert.Error(t, issues_model.NewLabel(db.DefaultContext, &issues_model.Label{RepoID: 3, Name: "invalid Color", Color: "#45G"}))
|
||||||
|
assert.Error(t, issues_model.NewLabel(db.DefaultContext, &issues_model.Label{RepoID: 3, Name: "invalid Color", Color: "#12345G"}))
|
||||||
|
assert.Error(t, issues_model.NewLabel(db.DefaultContext, &issues_model.Label{RepoID: 3, Name: "invalid Color", Color: "45G"}))
|
||||||
|
assert.Error(t, issues_model.NewLabel(db.DefaultContext, &issues_model.Label{RepoID: 3, Name: "invalid Color", Color: "12345G"}))
|
||||||
|
for _, label := range labels {
|
||||||
|
unittest.AssertNotExistsBean(t, label)
|
||||||
|
}
|
||||||
|
assert.NoError(t, issues_model.NewLabels(labels...))
|
||||||
|
for _, label := range labels {
|
||||||
|
unittest.AssertExistsAndLoadBean(t, label, unittest.Cond("id = ?", label.ID))
|
||||||
|
}
|
||||||
|
unittest.CheckConsistencyFor(t, &issues_model.Label{}, &repo_model.Repository{})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetLabelByID(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
label, err := issues_model.GetLabelByID(db.DefaultContext, 1)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.EqualValues(t, 1, label.ID)
|
||||||
|
|
||||||
|
_, err = issues_model.GetLabelByID(db.DefaultContext, unittest.NonexistentID)
|
||||||
|
assert.True(t, issues_model.IsErrLabelNotExist(err))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetLabelInRepoByName(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
label, err := issues_model.GetLabelInRepoByName(db.DefaultContext, 1, "label1")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.EqualValues(t, 1, label.ID)
|
||||||
|
assert.Equal(t, "label1", label.Name)
|
||||||
|
|
||||||
|
_, err = issues_model.GetLabelInRepoByName(db.DefaultContext, 1, "")
|
||||||
|
assert.True(t, issues_model.IsErrRepoLabelNotExist(err))
|
||||||
|
|
||||||
|
_, err = issues_model.GetLabelInRepoByName(db.DefaultContext, unittest.NonexistentID, "nonexistent")
|
||||||
|
assert.True(t, issues_model.IsErrRepoLabelNotExist(err))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetLabelInRepoByNames(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
labelIDs, err := issues_model.GetLabelIDsInRepoByNames(1, []string{"label1", "label2"})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
assert.Len(t, labelIDs, 2)
|
||||||
|
|
||||||
|
assert.Equal(t, int64(1), labelIDs[0])
|
||||||
|
assert.Equal(t, int64(2), labelIDs[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetLabelInRepoByNamesDiscardsNonExistentLabels(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
// label3 doesn't exists.. See labels.yml
|
||||||
|
labelIDs, err := issues_model.GetLabelIDsInRepoByNames(1, []string{"label1", "label2", "label3"})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
assert.Len(t, labelIDs, 2)
|
||||||
|
|
||||||
|
assert.Equal(t, int64(1), labelIDs[0])
|
||||||
|
assert.Equal(t, int64(2), labelIDs[1])
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetLabelInRepoByID(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
label, err := issues_model.GetLabelInRepoByID(db.DefaultContext, 1, 1)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.EqualValues(t, 1, label.ID)
|
||||||
|
|
||||||
|
_, err = issues_model.GetLabelInRepoByID(db.DefaultContext, 1, -1)
|
||||||
|
assert.True(t, issues_model.IsErrRepoLabelNotExist(err))
|
||||||
|
|
||||||
|
_, err = issues_model.GetLabelInRepoByID(db.DefaultContext, unittest.NonexistentID, unittest.NonexistentID)
|
||||||
|
assert.True(t, issues_model.IsErrRepoLabelNotExist(err))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetLabelsInRepoByIDs(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
labels, err := issues_model.GetLabelsInRepoByIDs(1, []int64{1, 2, unittest.NonexistentID})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
if assert.Len(t, labels, 2) {
|
||||||
|
assert.EqualValues(t, 1, labels[0].ID)
|
||||||
|
assert.EqualValues(t, 2, labels[1].ID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetLabelsByRepoID(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
testSuccess := func(repoID int64, sortType string, expectedIssueIDs []int64) {
|
||||||
|
labels, err := issues_model.GetLabelsByRepoID(db.DefaultContext, repoID, sortType, db.ListOptions{})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, labels, len(expectedIssueIDs))
|
||||||
|
for i, label := range labels {
|
||||||
|
assert.EqualValues(t, expectedIssueIDs[i], label.ID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
testSuccess(1, "leastissues", []int64{2, 1})
|
||||||
|
testSuccess(1, "mostissues", []int64{1, 2})
|
||||||
|
testSuccess(1, "reversealphabetically", []int64{2, 1})
|
||||||
|
testSuccess(1, "default", []int64{1, 2})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Org versions
|
||||||
|
|
||||||
|
func TestGetLabelInOrgByName(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
label, err := issues_model.GetLabelInOrgByName(db.DefaultContext, 3, "orglabel3")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.EqualValues(t, 3, label.ID)
|
||||||
|
assert.Equal(t, "orglabel3", label.Name)
|
||||||
|
|
||||||
|
_, err = issues_model.GetLabelInOrgByName(db.DefaultContext, 3, "")
|
||||||
|
assert.True(t, issues_model.IsErrOrgLabelNotExist(err))
|
||||||
|
|
||||||
|
_, err = issues_model.GetLabelInOrgByName(db.DefaultContext, 0, "orglabel3")
|
||||||
|
assert.True(t, issues_model.IsErrOrgLabelNotExist(err))
|
||||||
|
|
||||||
|
_, err = issues_model.GetLabelInOrgByName(db.DefaultContext, -1, "orglabel3")
|
||||||
|
assert.True(t, issues_model.IsErrOrgLabelNotExist(err))
|
||||||
|
|
||||||
|
_, err = issues_model.GetLabelInOrgByName(db.DefaultContext, unittest.NonexistentID, "nonexistent")
|
||||||
|
assert.True(t, issues_model.IsErrOrgLabelNotExist(err))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetLabelInOrgByNames(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
labelIDs, err := issues_model.GetLabelIDsInOrgByNames(3, []string{"orglabel3", "orglabel4"})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
assert.Len(t, labelIDs, 2)
|
||||||
|
|
||||||
|
assert.Equal(t, int64(3), labelIDs[0])
|
||||||
|
assert.Equal(t, int64(4), labelIDs[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetLabelInOrgByNamesDiscardsNonExistentLabels(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
// orglabel99 doesn't exists.. See labels.yml
|
||||||
|
labelIDs, err := issues_model.GetLabelIDsInOrgByNames(3, []string{"orglabel3", "orglabel4", "orglabel99"})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
assert.Len(t, labelIDs, 2)
|
||||||
|
|
||||||
|
assert.Equal(t, int64(3), labelIDs[0])
|
||||||
|
assert.Equal(t, int64(4), labelIDs[1])
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetLabelInOrgByID(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
label, err := issues_model.GetLabelInOrgByID(db.DefaultContext, 3, 3)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.EqualValues(t, 3, label.ID)
|
||||||
|
|
||||||
|
_, err = issues_model.GetLabelInOrgByID(db.DefaultContext, 3, -1)
|
||||||
|
assert.True(t, issues_model.IsErrOrgLabelNotExist(err))
|
||||||
|
|
||||||
|
_, err = issues_model.GetLabelInOrgByID(db.DefaultContext, 0, 3)
|
||||||
|
assert.True(t, issues_model.IsErrOrgLabelNotExist(err))
|
||||||
|
|
||||||
|
_, err = issues_model.GetLabelInOrgByID(db.DefaultContext, -1, 3)
|
||||||
|
assert.True(t, issues_model.IsErrOrgLabelNotExist(err))
|
||||||
|
|
||||||
|
_, err = issues_model.GetLabelInOrgByID(db.DefaultContext, unittest.NonexistentID, unittest.NonexistentID)
|
||||||
|
assert.True(t, issues_model.IsErrOrgLabelNotExist(err))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetLabelsInOrgByIDs(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
labels, err := issues_model.GetLabelsInOrgByIDs(3, []int64{3, 4, unittest.NonexistentID})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
if assert.Len(t, labels, 2) {
|
||||||
|
assert.EqualValues(t, 3, labels[0].ID)
|
||||||
|
assert.EqualValues(t, 4, labels[1].ID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetLabelsByOrgID(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
testSuccess := func(orgID int64, sortType string, expectedIssueIDs []int64) {
|
||||||
|
labels, err := issues_model.GetLabelsByOrgID(db.DefaultContext, orgID, sortType, db.ListOptions{})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, labels, len(expectedIssueIDs))
|
||||||
|
for i, label := range labels {
|
||||||
|
assert.EqualValues(t, expectedIssueIDs[i], label.ID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
testSuccess(3, "leastissues", []int64{3, 4})
|
||||||
|
testSuccess(3, "mostissues", []int64{4, 3})
|
||||||
|
testSuccess(3, "reversealphabetically", []int64{4, 3})
|
||||||
|
testSuccess(3, "default", []int64{3, 4})
|
||||||
|
|
||||||
|
var err error
|
||||||
|
_, err = issues_model.GetLabelsByOrgID(db.DefaultContext, 0, "leastissues", db.ListOptions{})
|
||||||
|
assert.True(t, issues_model.IsErrOrgLabelNotExist(err))
|
||||||
|
|
||||||
|
_, err = issues_model.GetLabelsByOrgID(db.DefaultContext, -1, "leastissues", db.ListOptions{})
|
||||||
|
assert.True(t, issues_model.IsErrOrgLabelNotExist(err))
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
func TestGetLabelsByIssueID(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
labels, err := issues_model.GetLabelsByIssueID(db.DefaultContext, 1)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
if assert.Len(t, labels, 1) {
|
||||||
|
assert.EqualValues(t, 1, labels[0].ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
labels, err = issues_model.GetLabelsByIssueID(db.DefaultContext, unittest.NonexistentID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, labels, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUpdateLabel(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
label := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 1}).(*issues_model.Label)
|
||||||
|
// make sure update wont overwrite it
|
||||||
|
update := &issues_model.Label{
|
||||||
|
ID: label.ID,
|
||||||
|
Color: "#ffff00",
|
||||||
|
Name: "newLabelName",
|
||||||
|
Description: label.Description,
|
||||||
|
}
|
||||||
|
label.Color = update.Color
|
||||||
|
label.Name = update.Name
|
||||||
|
assert.NoError(t, issues_model.UpdateLabel(update))
|
||||||
|
newLabel := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 1}).(*issues_model.Label)
|
||||||
|
assert.EqualValues(t, label.ID, newLabel.ID)
|
||||||
|
assert.EqualValues(t, label.Color, newLabel.Color)
|
||||||
|
assert.EqualValues(t, label.Name, newLabel.Name)
|
||||||
|
assert.EqualValues(t, label.Description, newLabel.Description)
|
||||||
|
unittest.CheckConsistencyFor(t, &issues_model.Label{}, &repo_model.Repository{})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeleteLabel(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
label := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 1}).(*issues_model.Label)
|
||||||
|
assert.NoError(t, issues_model.DeleteLabel(label.RepoID, label.ID))
|
||||||
|
unittest.AssertNotExistsBean(t, &issues_model.Label{ID: label.ID, RepoID: label.RepoID})
|
||||||
|
|
||||||
|
assert.NoError(t, issues_model.DeleteLabel(label.RepoID, label.ID))
|
||||||
|
unittest.AssertNotExistsBean(t, &issues_model.Label{ID: label.ID})
|
||||||
|
|
||||||
|
assert.NoError(t, issues_model.DeleteLabel(unittest.NonexistentID, unittest.NonexistentID))
|
||||||
|
unittest.CheckConsistencyFor(t, &issues_model.Label{}, &repo_model.Repository{})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHasIssueLabel(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
assert.True(t, issues_model.HasIssueLabel(db.DefaultContext, 1, 1))
|
||||||
|
assert.False(t, issues_model.HasIssueLabel(db.DefaultContext, 1, 2))
|
||||||
|
assert.False(t, issues_model.HasIssueLabel(db.DefaultContext, unittest.NonexistentID, unittest.NonexistentID))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewIssueLabel(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
label := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 2}).(*issues_model.Label)
|
||||||
|
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1}).(*issues_model.Issue)
|
||||||
|
doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
|
||||||
|
|
||||||
|
// add new IssueLabel
|
||||||
|
prevNumIssues := label.NumIssues
|
||||||
|
assert.NoError(t, issues_model.NewIssueLabel(issue, label, doer))
|
||||||
|
unittest.AssertExistsAndLoadBean(t, &issues_model.IssueLabel{IssueID: issue.ID, LabelID: label.ID})
|
||||||
|
unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{
|
||||||
|
Type: issues_model.CommentTypeLabel,
|
||||||
|
PosterID: doer.ID,
|
||||||
|
IssueID: issue.ID,
|
||||||
|
LabelID: label.ID,
|
||||||
|
Content: "1",
|
||||||
|
})
|
||||||
|
label = unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 2}).(*issues_model.Label)
|
||||||
|
assert.EqualValues(t, prevNumIssues+1, label.NumIssues)
|
||||||
|
|
||||||
|
// re-add existing IssueLabel
|
||||||
|
assert.NoError(t, issues_model.NewIssueLabel(issue, label, doer))
|
||||||
|
unittest.CheckConsistencyFor(t, &issues_model.Issue{}, &issues_model.Label{})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewIssueLabels(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
label1 := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 1}).(*issues_model.Label)
|
||||||
|
label2 := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 2}).(*issues_model.Label)
|
||||||
|
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 5}).(*issues_model.Issue)
|
||||||
|
doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
|
||||||
|
|
||||||
|
assert.NoError(t, issues_model.NewIssueLabels(issue, []*issues_model.Label{label1, label2}, doer))
|
||||||
|
unittest.AssertExistsAndLoadBean(t, &issues_model.IssueLabel{IssueID: issue.ID, LabelID: label1.ID})
|
||||||
|
unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{
|
||||||
|
Type: issues_model.CommentTypeLabel,
|
||||||
|
PosterID: doer.ID,
|
||||||
|
IssueID: issue.ID,
|
||||||
|
LabelID: label1.ID,
|
||||||
|
Content: "1",
|
||||||
|
})
|
||||||
|
unittest.AssertExistsAndLoadBean(t, &issues_model.IssueLabel{IssueID: issue.ID, LabelID: label1.ID})
|
||||||
|
label1 = unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 1}).(*issues_model.Label)
|
||||||
|
assert.EqualValues(t, 3, label1.NumIssues)
|
||||||
|
assert.EqualValues(t, 1, label1.NumClosedIssues)
|
||||||
|
label2 = unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 2}).(*issues_model.Label)
|
||||||
|
assert.EqualValues(t, 1, label2.NumIssues)
|
||||||
|
assert.EqualValues(t, 1, label2.NumClosedIssues)
|
||||||
|
|
||||||
|
// corner case: test empty slice
|
||||||
|
assert.NoError(t, issues_model.NewIssueLabels(issue, []*issues_model.Label{}, doer))
|
||||||
|
|
||||||
|
unittest.CheckConsistencyFor(t, &issues_model.Issue{}, &issues_model.Label{})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeleteIssueLabel(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
testSuccess := func(labelID, issueID, doerID int64) {
|
||||||
|
label := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: labelID}).(*issues_model.Label)
|
||||||
|
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: issueID}).(*issues_model.Issue)
|
||||||
|
doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: doerID}).(*user_model.User)
|
||||||
|
|
||||||
|
expectedNumIssues := label.NumIssues
|
||||||
|
expectedNumClosedIssues := label.NumClosedIssues
|
||||||
|
if unittest.BeanExists(t, &issues_model.IssueLabel{IssueID: issueID, LabelID: labelID}) {
|
||||||
|
expectedNumIssues--
|
||||||
|
if issue.IsClosed {
|
||||||
|
expectedNumClosedIssues--
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, committer, err := db.TxContext()
|
||||||
|
defer committer.Close()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NoError(t, issues_model.DeleteIssueLabel(ctx, issue, label, doer))
|
||||||
|
assert.NoError(t, committer.Commit())
|
||||||
|
|
||||||
|
unittest.AssertNotExistsBean(t, &issues_model.IssueLabel{IssueID: issueID, LabelID: labelID})
|
||||||
|
unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{
|
||||||
|
Type: issues_model.CommentTypeLabel,
|
||||||
|
PosterID: doerID,
|
||||||
|
IssueID: issueID,
|
||||||
|
LabelID: labelID,
|
||||||
|
}, `content=""`)
|
||||||
|
label = unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: labelID}).(*issues_model.Label)
|
||||||
|
assert.EqualValues(t, expectedNumIssues, label.NumIssues)
|
||||||
|
assert.EqualValues(t, expectedNumClosedIssues, label.NumClosedIssues)
|
||||||
|
}
|
||||||
|
testSuccess(1, 1, 2)
|
||||||
|
testSuccess(2, 5, 2)
|
||||||
|
testSuccess(1, 1, 2) // delete non-existent IssueLabel
|
||||||
|
|
||||||
|
unittest.CheckConsistencyFor(t, &issues_model.Issue{}, &issues_model.Label{})
|
||||||
|
}
|
|
@ -2,14 +2,20 @@
|
||||||
// Use of this source code is governed by a MIT-style
|
// Use of this source code is governed by a MIT-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package issues
|
package issues_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
_ "code.gitea.io/gitea/models"
|
||||||
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
|
_ "code.gitea.io/gitea/models/repo"
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
|
_ "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -17,14 +23,18 @@ func init() {
|
||||||
setting.LoadForTest()
|
setting.LoadForTest()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestFixturesAreConsistent(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
unittest.CheckConsistencyFor(t,
|
||||||
|
&issues_model.Issue{},
|
||||||
|
&issues_model.PullRequest{},
|
||||||
|
&issues_model.Milestone{},
|
||||||
|
&issues_model.Label{},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
func TestMain(m *testing.M) {
|
||||||
unittest.MainTest(m, &unittest.TestOptions{
|
unittest.MainTest(m, &unittest.TestOptions{
|
||||||
GiteaRootPath: filepath.Join("..", ".."),
|
GiteaRootPath: filepath.Join("..", ".."),
|
||||||
FixtureFiles: []string{
|
|
||||||
"reaction.yml",
|
|
||||||
"user.yml",
|
|
||||||
"repository.yml",
|
|
||||||
"milestone.yml",
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -292,11 +292,17 @@ func DeleteMilestoneByRepoID(repoID, id int64) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
numMilestones, err := countRepoMilestones(ctx, repo.ID)
|
numMilestones, err := CountMilestones(ctx, GetMilestonesOption{
|
||||||
|
RepoID: repo.ID,
|
||||||
|
State: api.StateAll,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
numClosedMilestones, err := countRepoClosedMilestones(ctx, repo.ID)
|
numClosedMilestones, err := CountMilestones(ctx, GetMilestonesOption{
|
||||||
|
RepoID: repo.ID,
|
||||||
|
State: api.StateClosed,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -428,13 +434,6 @@ func GetMilestonesByRepoIDs(repoIDs []int64, page int, isClosed bool, sortType s
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ____ _ _
|
|
||||||
// / ___|| |_ __ _| |_ ___
|
|
||||||
// \___ \| __/ _` | __/ __|
|
|
||||||
// ___) | || (_| | |_\__ \
|
|
||||||
// |____/ \__\__,_|\__|___/
|
|
||||||
//
|
|
||||||
|
|
||||||
// MilestonesStats represents milestone statistic information.
|
// MilestonesStats represents milestone statistic information.
|
||||||
type MilestonesStats struct {
|
type MilestonesStats struct {
|
||||||
OpenCount, ClosedCount int64
|
OpenCount, ClosedCount int64
|
||||||
|
@ -503,23 +502,13 @@ func GetMilestonesStatsByRepoCondAndKw(repoCond builder.Cond, keyword string) (*
|
||||||
return stats, nil
|
return stats, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func countRepoMilestones(ctx context.Context, repoID int64) (int64, error) {
|
// CountMilestones returns number of milestones in given repository with other options
|
||||||
|
func CountMilestones(ctx context.Context, opts GetMilestonesOption) (int64, error) {
|
||||||
return db.GetEngine(ctx).
|
return db.GetEngine(ctx).
|
||||||
Where("repo_id=?", repoID).
|
Where(opts.toCond()).
|
||||||
Count(new(Milestone))
|
Count(new(Milestone))
|
||||||
}
|
}
|
||||||
|
|
||||||
func countRepoClosedMilestones(ctx context.Context, repoID int64) (int64, error) {
|
|
||||||
return db.GetEngine(ctx).
|
|
||||||
Where("repo_id=? AND is_closed=?", repoID, true).
|
|
||||||
Count(new(Milestone))
|
|
||||||
}
|
|
||||||
|
|
||||||
// CountRepoClosedMilestones returns number of closed milestones in given repository.
|
|
||||||
func CountRepoClosedMilestones(repoID int64) (int64, error) {
|
|
||||||
return countRepoClosedMilestones(db.DefaultContext, repoID)
|
|
||||||
}
|
|
||||||
|
|
||||||
// CountMilestonesByRepoCond map from repo conditions to number of milestones matching the options`
|
// CountMilestonesByRepoCond map from repo conditions to number of milestones matching the options`
|
||||||
func CountMilestonesByRepoCond(repoCond builder.Cond, isClosed bool) (map[int64]int64, error) {
|
func CountMilestonesByRepoCond(repoCond builder.Cond, isClosed bool) (map[int64]int64, error) {
|
||||||
sess := db.GetEngine(db.DefaultContext).Where("is_closed = ?", isClosed)
|
sess := db.GetEngine(db.DefaultContext).Where("is_closed = ?", isClosed)
|
||||||
|
|
|
@ -2,44 +2,46 @@
|
||||||
// Use of this source code is governed by a MIT-style
|
// Use of this source code is governed by a MIT-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package issues
|
package issues_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"sort"
|
"sort"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
|
"code.gitea.io/gitea/modules/timeutil"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"xorm.io/builder"
|
"xorm.io/builder"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMilestone_State(t *testing.T) {
|
func TestMilestone_State(t *testing.T) {
|
||||||
assert.Equal(t, api.StateOpen, (&Milestone{IsClosed: false}).State())
|
assert.Equal(t, api.StateOpen, (&issues_model.Milestone{IsClosed: false}).State())
|
||||||
assert.Equal(t, api.StateClosed, (&Milestone{IsClosed: true}).State())
|
assert.Equal(t, api.StateClosed, (&issues_model.Milestone{IsClosed: true}).State())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetMilestoneByRepoID(t *testing.T) {
|
func TestGetMilestoneByRepoID(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
milestone, err := GetMilestoneByRepoID(db.DefaultContext, 1, 1)
|
milestone, err := issues_model.GetMilestoneByRepoID(db.DefaultContext, 1, 1)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.EqualValues(t, 1, milestone.ID)
|
assert.EqualValues(t, 1, milestone.ID)
|
||||||
assert.EqualValues(t, 1, milestone.RepoID)
|
assert.EqualValues(t, 1, milestone.RepoID)
|
||||||
|
|
||||||
_, err = GetMilestoneByRepoID(db.DefaultContext, unittest.NonexistentID, unittest.NonexistentID)
|
_, err = issues_model.GetMilestoneByRepoID(db.DefaultContext, unittest.NonexistentID, unittest.NonexistentID)
|
||||||
assert.True(t, IsErrMilestoneNotExist(err))
|
assert.True(t, issues_model.IsErrMilestoneNotExist(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetMilestonesByRepoID(t *testing.T) {
|
func TestGetMilestonesByRepoID(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
test := func(repoID int64, state api.StateType) {
|
test := func(repoID int64, state api.StateType) {
|
||||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID}).(*repo_model.Repository)
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID}).(*repo_model.Repository)
|
||||||
milestones, _, err := GetMilestones(GetMilestonesOption{
|
milestones, _, err := issues_model.GetMilestones(issues_model.GetMilestonesOption{
|
||||||
RepoID: repo.ID,
|
RepoID: repo.ID,
|
||||||
State: state,
|
State: state,
|
||||||
})
|
})
|
||||||
|
@ -76,7 +78,7 @@ func TestGetMilestonesByRepoID(t *testing.T) {
|
||||||
test(3, api.StateClosed)
|
test(3, api.StateClosed)
|
||||||
test(3, api.StateAll)
|
test(3, api.StateAll)
|
||||||
|
|
||||||
milestones, _, err := GetMilestones(GetMilestonesOption{
|
milestones, _, err := issues_model.GetMilestones(issues_model.GetMilestonesOption{
|
||||||
RepoID: unittest.NonexistentID,
|
RepoID: unittest.NonexistentID,
|
||||||
State: api.StateOpen,
|
State: api.StateOpen,
|
||||||
})
|
})
|
||||||
|
@ -87,9 +89,9 @@ func TestGetMilestonesByRepoID(t *testing.T) {
|
||||||
func TestGetMilestones(t *testing.T) {
|
func TestGetMilestones(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository)
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository)
|
||||||
test := func(sortType string, sortCond func(*Milestone) int) {
|
test := func(sortType string, sortCond func(*issues_model.Milestone) int) {
|
||||||
for _, page := range []int{0, 1} {
|
for _, page := range []int{0, 1} {
|
||||||
milestones, _, err := GetMilestones(GetMilestonesOption{
|
milestones, _, err := issues_model.GetMilestones(issues_model.GetMilestonesOption{
|
||||||
ListOptions: db.ListOptions{
|
ListOptions: db.ListOptions{
|
||||||
Page: page,
|
Page: page,
|
||||||
PageSize: setting.UI.IssuePagingNum,
|
PageSize: setting.UI.IssuePagingNum,
|
||||||
|
@ -106,7 +108,7 @@ func TestGetMilestones(t *testing.T) {
|
||||||
}
|
}
|
||||||
assert.True(t, sort.IntsAreSorted(values))
|
assert.True(t, sort.IntsAreSorted(values))
|
||||||
|
|
||||||
milestones, _, err = GetMilestones(GetMilestonesOption{
|
milestones, _, err = issues_model.GetMilestones(issues_model.GetMilestonesOption{
|
||||||
ListOptions: db.ListOptions{
|
ListOptions: db.ListOptions{
|
||||||
Page: page,
|
Page: page,
|
||||||
PageSize: setting.UI.IssuePagingNum,
|
PageSize: setting.UI.IssuePagingNum,
|
||||||
|
@ -125,22 +127,22 @@ func TestGetMilestones(t *testing.T) {
|
||||||
assert.True(t, sort.IntsAreSorted(values))
|
assert.True(t, sort.IntsAreSorted(values))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
test("furthestduedate", func(milestone *Milestone) int {
|
test("furthestduedate", func(milestone *issues_model.Milestone) int {
|
||||||
return -int(milestone.DeadlineUnix)
|
return -int(milestone.DeadlineUnix)
|
||||||
})
|
})
|
||||||
test("leastcomplete", func(milestone *Milestone) int {
|
test("leastcomplete", func(milestone *issues_model.Milestone) int {
|
||||||
return milestone.Completeness
|
return milestone.Completeness
|
||||||
})
|
})
|
||||||
test("mostcomplete", func(milestone *Milestone) int {
|
test("mostcomplete", func(milestone *issues_model.Milestone) int {
|
||||||
return -milestone.Completeness
|
return -milestone.Completeness
|
||||||
})
|
})
|
||||||
test("leastissues", func(milestone *Milestone) int {
|
test("leastissues", func(milestone *issues_model.Milestone) int {
|
||||||
return milestone.NumIssues
|
return milestone.NumIssues
|
||||||
})
|
})
|
||||||
test("mostissues", func(milestone *Milestone) int {
|
test("mostissues", func(milestone *issues_model.Milestone) int {
|
||||||
return -milestone.NumIssues
|
return -milestone.NumIssues
|
||||||
})
|
})
|
||||||
test("soonestduedate", func(milestone *Milestone) int {
|
test("soonestduedate", func(milestone *issues_model.Milestone) int {
|
||||||
return int(milestone.DeadlineUnix)
|
return int(milestone.DeadlineUnix)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -149,7 +151,10 @@ func TestCountRepoMilestones(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
test := func(repoID int64) {
|
test := func(repoID int64) {
|
||||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID}).(*repo_model.Repository)
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID}).(*repo_model.Repository)
|
||||||
count, err := countRepoMilestones(db.DefaultContext, repoID)
|
count, err := issues_model.CountMilestones(db.DefaultContext, issues_model.GetMilestonesOption{
|
||||||
|
RepoID: repoID,
|
||||||
|
State: api.StateAll,
|
||||||
|
})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.EqualValues(t, repo.NumMilestones, count)
|
assert.EqualValues(t, repo.NumMilestones, count)
|
||||||
}
|
}
|
||||||
|
@ -157,7 +162,10 @@ func TestCountRepoMilestones(t *testing.T) {
|
||||||
test(2)
|
test(2)
|
||||||
test(3)
|
test(3)
|
||||||
|
|
||||||
count, err := countRepoMilestones(db.DefaultContext, unittest.NonexistentID)
|
count, err := issues_model.CountMilestones(db.DefaultContext, issues_model.GetMilestonesOption{
|
||||||
|
RepoID: unittest.NonexistentID,
|
||||||
|
State: api.StateAll,
|
||||||
|
})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.EqualValues(t, 0, count)
|
assert.EqualValues(t, 0, count)
|
||||||
}
|
}
|
||||||
|
@ -166,7 +174,10 @@ func TestCountRepoClosedMilestones(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
test := func(repoID int64) {
|
test := func(repoID int64) {
|
||||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID}).(*repo_model.Repository)
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID}).(*repo_model.Repository)
|
||||||
count, err := CountRepoClosedMilestones(repoID)
|
count, err := issues_model.CountMilestones(db.DefaultContext, issues_model.GetMilestonesOption{
|
||||||
|
RepoID: repoID,
|
||||||
|
State: api.StateClosed,
|
||||||
|
})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.EqualValues(t, repo.NumClosedMilestones, count)
|
assert.EqualValues(t, repo.NumClosedMilestones, count)
|
||||||
}
|
}
|
||||||
|
@ -174,7 +185,10 @@ func TestCountRepoClosedMilestones(t *testing.T) {
|
||||||
test(2)
|
test(2)
|
||||||
test(3)
|
test(3)
|
||||||
|
|
||||||
count, err := CountRepoClosedMilestones(unittest.NonexistentID)
|
count, err := issues_model.CountMilestones(db.DefaultContext, issues_model.GetMilestonesOption{
|
||||||
|
RepoID: unittest.NonexistentID,
|
||||||
|
State: api.StateClosed,
|
||||||
|
})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.EqualValues(t, 0, count)
|
assert.EqualValues(t, 0, count)
|
||||||
}
|
}
|
||||||
|
@ -188,12 +202,12 @@ func TestCountMilestonesByRepoIDs(t *testing.T) {
|
||||||
repo1OpenCount, repo1ClosedCount := milestonesCount(1)
|
repo1OpenCount, repo1ClosedCount := milestonesCount(1)
|
||||||
repo2OpenCount, repo2ClosedCount := milestonesCount(2)
|
repo2OpenCount, repo2ClosedCount := milestonesCount(2)
|
||||||
|
|
||||||
openCounts, err := CountMilestonesByRepoCond(builder.In("repo_id", []int64{1, 2}), false)
|
openCounts, err := issues_model.CountMilestonesByRepoCond(builder.In("repo_id", []int64{1, 2}), false)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.EqualValues(t, repo1OpenCount, openCounts[1])
|
assert.EqualValues(t, repo1OpenCount, openCounts[1])
|
||||||
assert.EqualValues(t, repo2OpenCount, openCounts[2])
|
assert.EqualValues(t, repo2OpenCount, openCounts[2])
|
||||||
|
|
||||||
closedCounts, err := CountMilestonesByRepoCond(builder.In("repo_id", []int64{1, 2}), true)
|
closedCounts, err := issues_model.CountMilestonesByRepoCond(builder.In("repo_id", []int64{1, 2}), true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.EqualValues(t, repo1ClosedCount, closedCounts[1])
|
assert.EqualValues(t, repo1ClosedCount, closedCounts[1])
|
||||||
assert.EqualValues(t, repo2ClosedCount, closedCounts[2])
|
assert.EqualValues(t, repo2ClosedCount, closedCounts[2])
|
||||||
|
@ -203,9 +217,9 @@ func TestGetMilestonesByRepoIDs(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository)
|
repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository)
|
||||||
repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}).(*repo_model.Repository)
|
repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}).(*repo_model.Repository)
|
||||||
test := func(sortType string, sortCond func(*Milestone) int) {
|
test := func(sortType string, sortCond func(*issues_model.Milestone) int) {
|
||||||
for _, page := range []int{0, 1} {
|
for _, page := range []int{0, 1} {
|
||||||
openMilestones, err := GetMilestonesByRepoIDs([]int64{repo1.ID, repo2.ID}, page, false, sortType)
|
openMilestones, err := issues_model.GetMilestonesByRepoIDs([]int64{repo1.ID, repo2.ID}, page, false, sortType)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Len(t, openMilestones, repo1.NumOpenMilestones+repo2.NumOpenMilestones)
|
assert.Len(t, openMilestones, repo1.NumOpenMilestones+repo2.NumOpenMilestones)
|
||||||
values := make([]int, len(openMilestones))
|
values := make([]int, len(openMilestones))
|
||||||
|
@ -214,7 +228,7 @@ func TestGetMilestonesByRepoIDs(t *testing.T) {
|
||||||
}
|
}
|
||||||
assert.True(t, sort.IntsAreSorted(values))
|
assert.True(t, sort.IntsAreSorted(values))
|
||||||
|
|
||||||
closedMilestones, err := GetMilestonesByRepoIDs([]int64{repo1.ID, repo2.ID}, page, true, sortType)
|
closedMilestones, err := issues_model.GetMilestonesByRepoIDs([]int64{repo1.ID, repo2.ID}, page, true, sortType)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Len(t, closedMilestones, repo1.NumClosedMilestones+repo2.NumClosedMilestones)
|
assert.Len(t, closedMilestones, repo1.NumClosedMilestones+repo2.NumClosedMilestones)
|
||||||
values = make([]int, len(closedMilestones))
|
values = make([]int, len(closedMilestones))
|
||||||
|
@ -224,22 +238,22 @@ func TestGetMilestonesByRepoIDs(t *testing.T) {
|
||||||
assert.True(t, sort.IntsAreSorted(values))
|
assert.True(t, sort.IntsAreSorted(values))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
test("furthestduedate", func(milestone *Milestone) int {
|
test("furthestduedate", func(milestone *issues_model.Milestone) int {
|
||||||
return -int(milestone.DeadlineUnix)
|
return -int(milestone.DeadlineUnix)
|
||||||
})
|
})
|
||||||
test("leastcomplete", func(milestone *Milestone) int {
|
test("leastcomplete", func(milestone *issues_model.Milestone) int {
|
||||||
return milestone.Completeness
|
return milestone.Completeness
|
||||||
})
|
})
|
||||||
test("mostcomplete", func(milestone *Milestone) int {
|
test("mostcomplete", func(milestone *issues_model.Milestone) int {
|
||||||
return -milestone.Completeness
|
return -milestone.Completeness
|
||||||
})
|
})
|
||||||
test("leastissues", func(milestone *Milestone) int {
|
test("leastissues", func(milestone *issues_model.Milestone) int {
|
||||||
return milestone.NumIssues
|
return milestone.NumIssues
|
||||||
})
|
})
|
||||||
test("mostissues", func(milestone *Milestone) int {
|
test("mostissues", func(milestone *issues_model.Milestone) int {
|
||||||
return -milestone.NumIssues
|
return -milestone.NumIssues
|
||||||
})
|
})
|
||||||
test("soonestduedate", func(milestone *Milestone) int {
|
test("soonestduedate", func(milestone *issues_model.Milestone) int {
|
||||||
return int(milestone.DeadlineUnix)
|
return int(milestone.DeadlineUnix)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -249,7 +263,7 @@ func TestGetMilestonesStats(t *testing.T) {
|
||||||
|
|
||||||
test := func(repoID int64) {
|
test := func(repoID int64) {
|
||||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID}).(*repo_model.Repository)
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID}).(*repo_model.Repository)
|
||||||
stats, err := GetMilestonesStatsByRepoCond(builder.And(builder.Eq{"repo_id": repoID}))
|
stats, err := issues_model.GetMilestonesStatsByRepoCond(builder.And(builder.Eq{"repo_id": repoID}))
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.EqualValues(t, repo.NumMilestones-repo.NumClosedMilestones, stats.OpenCount)
|
assert.EqualValues(t, repo.NumMilestones-repo.NumClosedMilestones, stats.OpenCount)
|
||||||
assert.EqualValues(t, repo.NumClosedMilestones, stats.ClosedCount)
|
assert.EqualValues(t, repo.NumClosedMilestones, stats.ClosedCount)
|
||||||
|
@ -258,7 +272,7 @@ func TestGetMilestonesStats(t *testing.T) {
|
||||||
test(2)
|
test(2)
|
||||||
test(3)
|
test(3)
|
||||||
|
|
||||||
stats, err := GetMilestonesStatsByRepoCond(builder.And(builder.Eq{"repo_id": unittest.NonexistentID}))
|
stats, err := issues_model.GetMilestonesStatsByRepoCond(builder.And(builder.Eq{"repo_id": unittest.NonexistentID}))
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.EqualValues(t, 0, stats.OpenCount)
|
assert.EqualValues(t, 0, stats.OpenCount)
|
||||||
assert.EqualValues(t, 0, stats.ClosedCount)
|
assert.EqualValues(t, 0, stats.ClosedCount)
|
||||||
|
@ -266,8 +280,75 @@ func TestGetMilestonesStats(t *testing.T) {
|
||||||
repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository)
|
repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository)
|
||||||
repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}).(*repo_model.Repository)
|
repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}).(*repo_model.Repository)
|
||||||
|
|
||||||
milestoneStats, err := GetMilestonesStatsByRepoCond(builder.In("repo_id", []int64{repo1.ID, repo2.ID}))
|
milestoneStats, err := issues_model.GetMilestonesStatsByRepoCond(builder.In("repo_id", []int64{repo1.ID, repo2.ID}))
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.EqualValues(t, repo1.NumOpenMilestones+repo2.NumOpenMilestones, milestoneStats.OpenCount)
|
assert.EqualValues(t, repo1.NumOpenMilestones+repo2.NumOpenMilestones, milestoneStats.OpenCount)
|
||||||
assert.EqualValues(t, repo1.NumClosedMilestones+repo2.NumClosedMilestones, milestoneStats.ClosedCount)
|
assert.EqualValues(t, repo1.NumClosedMilestones+repo2.NumClosedMilestones, milestoneStats.ClosedCount)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestNewMilestone(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
milestone := &issues_model.Milestone{
|
||||||
|
RepoID: 1,
|
||||||
|
Name: "milestoneName",
|
||||||
|
Content: "milestoneContent",
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.NoError(t, issues_model.NewMilestone(milestone))
|
||||||
|
unittest.AssertExistsAndLoadBean(t, milestone)
|
||||||
|
unittest.CheckConsistencyFor(t, &repo_model.Repository{ID: milestone.RepoID}, &issues_model.Milestone{})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestChangeMilestoneStatus(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
milestone := unittest.AssertExistsAndLoadBean(t, &issues_model.Milestone{ID: 1}).(*issues_model.Milestone)
|
||||||
|
|
||||||
|
assert.NoError(t, issues_model.ChangeMilestoneStatus(milestone, true))
|
||||||
|
unittest.AssertExistsAndLoadBean(t, &issues_model.Milestone{ID: 1}, "is_closed=1")
|
||||||
|
unittest.CheckConsistencyFor(t, &repo_model.Repository{ID: milestone.RepoID}, &issues_model.Milestone{})
|
||||||
|
|
||||||
|
assert.NoError(t, issues_model.ChangeMilestoneStatus(milestone, false))
|
||||||
|
unittest.AssertExistsAndLoadBean(t, &issues_model.Milestone{ID: 1}, "is_closed=0")
|
||||||
|
unittest.CheckConsistencyFor(t, &repo_model.Repository{ID: milestone.RepoID}, &issues_model.Milestone{})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeleteMilestoneByRepoID(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
assert.NoError(t, issues_model.DeleteMilestoneByRepoID(1, 1))
|
||||||
|
unittest.AssertNotExistsBean(t, &issues_model.Milestone{ID: 1})
|
||||||
|
unittest.CheckConsistencyFor(t, &repo_model.Repository{ID: 1})
|
||||||
|
|
||||||
|
assert.NoError(t, issues_model.DeleteMilestoneByRepoID(unittest.NonexistentID, unittest.NonexistentID))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUpdateMilestone(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
|
milestone := unittest.AssertExistsAndLoadBean(t, &issues_model.Milestone{ID: 1}).(*issues_model.Milestone)
|
||||||
|
milestone.Name = " newMilestoneName "
|
||||||
|
milestone.Content = "newMilestoneContent"
|
||||||
|
assert.NoError(t, issues_model.UpdateMilestone(milestone, milestone.IsClosed))
|
||||||
|
milestone = unittest.AssertExistsAndLoadBean(t, &issues_model.Milestone{ID: 1}).(*issues_model.Milestone)
|
||||||
|
assert.EqualValues(t, "newMilestoneName", milestone.Name)
|
||||||
|
unittest.CheckConsistencyFor(t, &issues_model.Milestone{})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUpdateMilestoneCounters(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{MilestoneID: 1},
|
||||||
|
"is_closed=0").(*issues_model.Issue)
|
||||||
|
|
||||||
|
issue.IsClosed = true
|
||||||
|
issue.ClosedUnix = timeutil.TimeStampNow()
|
||||||
|
_, err := db.GetEngine(db.DefaultContext).ID(issue.ID).Cols("is_closed", "closed_unix").Update(issue)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NoError(t, issues_model.UpdateMilestoneCounters(db.DefaultContext, issue.MilestoneID))
|
||||||
|
unittest.CheckConsistencyFor(t, &issues_model.Milestone{})
|
||||||
|
|
||||||
|
issue.IsClosed = false
|
||||||
|
issue.ClosedUnix = 0
|
||||||
|
_, err = db.GetEngine(db.DefaultContext).ID(issue.ID).Cols("is_closed", "closed_unix").Update(issue)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NoError(t, issues_model.UpdateMilestoneCounters(db.DefaultContext, issue.MilestoneID))
|
||||||
|
unittest.CheckConsistencyFor(t, &issues_model.Milestone{})
|
||||||
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
// Use of this source code is governed by a MIT-style
|
// Use of this source code is governed by a MIT-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package models
|
package issues
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
@ -25,6 +25,83 @@ import (
|
||||||
"xorm.io/builder"
|
"xorm.io/builder"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ErrPullRequestNotExist represents a "PullRequestNotExist" kind of error.
|
||||||
|
type ErrPullRequestNotExist struct {
|
||||||
|
ID int64
|
||||||
|
IssueID int64
|
||||||
|
HeadRepoID int64
|
||||||
|
BaseRepoID int64
|
||||||
|
HeadBranch string
|
||||||
|
BaseBranch string
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsErrPullRequestNotExist checks if an error is a ErrPullRequestNotExist.
|
||||||
|
func IsErrPullRequestNotExist(err error) bool {
|
||||||
|
_, ok := err.(ErrPullRequestNotExist)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err ErrPullRequestNotExist) Error() string {
|
||||||
|
return fmt.Sprintf("pull request does not exist [id: %d, issue_id: %d, head_repo_id: %d, base_repo_id: %d, head_branch: %s, base_branch: %s]",
|
||||||
|
err.ID, err.IssueID, err.HeadRepoID, err.BaseRepoID, err.HeadBranch, err.BaseBranch)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrPullRequestAlreadyExists represents a "PullRequestAlreadyExists"-error
|
||||||
|
type ErrPullRequestAlreadyExists struct {
|
||||||
|
ID int64
|
||||||
|
IssueID int64
|
||||||
|
HeadRepoID int64
|
||||||
|
BaseRepoID int64
|
||||||
|
HeadBranch string
|
||||||
|
BaseBranch string
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsErrPullRequestAlreadyExists checks if an error is a ErrPullRequestAlreadyExists.
|
||||||
|
func IsErrPullRequestAlreadyExists(err error) bool {
|
||||||
|
_, ok := err.(ErrPullRequestAlreadyExists)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error does pretty-printing :D
|
||||||
|
func (err ErrPullRequestAlreadyExists) Error() string {
|
||||||
|
return fmt.Sprintf("pull request already exists for these targets [id: %d, issue_id: %d, head_repo_id: %d, base_repo_id: %d, head_branch: %s, base_branch: %s]",
|
||||||
|
err.ID, err.IssueID, err.HeadRepoID, err.BaseRepoID, err.HeadBranch, err.BaseBranch)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrPullRequestHeadRepoMissing represents a "ErrPullRequestHeadRepoMissing" error
|
||||||
|
type ErrPullRequestHeadRepoMissing struct {
|
||||||
|
ID int64
|
||||||
|
HeadRepoID int64
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsErrErrPullRequestHeadRepoMissing checks if an error is a ErrPullRequestHeadRepoMissing.
|
||||||
|
func IsErrErrPullRequestHeadRepoMissing(err error) bool {
|
||||||
|
_, ok := err.(ErrPullRequestHeadRepoMissing)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error does pretty-printing :D
|
||||||
|
func (err ErrPullRequestHeadRepoMissing) Error() string {
|
||||||
|
return fmt.Sprintf("pull request head repo missing [id: %d, head_repo_id: %d]",
|
||||||
|
err.ID, err.HeadRepoID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrPullWasClosed is used close a closed pull request
|
||||||
|
type ErrPullWasClosed struct {
|
||||||
|
ID int64
|
||||||
|
Index int64
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsErrPullWasClosed checks if an error is a ErrErrPullWasClosed.
|
||||||
|
func IsErrPullWasClosed(err error) bool {
|
||||||
|
_, ok := err.(ErrPullWasClosed)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err ErrPullWasClosed) Error() string {
|
||||||
|
return fmt.Sprintf("Pull request [%d] %d was already closed", err.ID, err.Index)
|
||||||
|
}
|
||||||
|
|
||||||
// PullRequestType defines pull request type
|
// PullRequestType defines pull request type
|
||||||
type PullRequestType int
|
type PullRequestType int
|
||||||
|
|
||||||
|
@ -98,7 +175,8 @@ func init() {
|
||||||
db.RegisterModel(new(PullRequest))
|
db.RegisterModel(new(PullRequest))
|
||||||
}
|
}
|
||||||
|
|
||||||
func deletePullsByBaseRepoID(ctx context.Context, repoID int64) error {
|
// DeletePullsByBaseRepoID deletes all pull requests by the base repository ID
|
||||||
|
func DeletePullsByBaseRepoID(ctx context.Context, repoID int64) error {
|
||||||
deleteCond := builder.Select("id").From("pull_request").Where(builder.Eq{"pull_request.base_repo_id": repoID})
|
deleteCond := builder.Select("id").From("pull_request").Where(builder.Eq{"pull_request.base_repo_id": repoID})
|
||||||
|
|
||||||
// Delete scheduled auto merges
|
// Delete scheduled auto merges
|
||||||
|
@ -219,7 +297,7 @@ func (pr *PullRequest) LoadIssueCtx(ctx context.Context) (err error) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
pr.Issue, err = getIssueByID(ctx, pr.IssueID)
|
pr.Issue, err = GetIssueByID(ctx, pr.IssueID)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
pr.Issue.PullRequest = pr
|
pr.Issue.PullRequest = pr
|
||||||
}
|
}
|
||||||
|
@ -420,14 +498,14 @@ func NewPullRequest(outerCtx context.Context, repo *repo_model.Repository, issue
|
||||||
defer committer.Close()
|
defer committer.Close()
|
||||||
ctx.WithContext(outerCtx)
|
ctx.WithContext(outerCtx)
|
||||||
|
|
||||||
if err = newIssue(ctx, issue.Poster, NewIssueOptions{
|
if err = NewIssueWithIndex(ctx, issue.Poster, NewIssueOptions{
|
||||||
Repo: repo,
|
Repo: repo,
|
||||||
Issue: issue,
|
Issue: issue,
|
||||||
LabelIDs: labelIDs,
|
LabelIDs: labelIDs,
|
||||||
Attachments: uuids,
|
Attachments: uuids,
|
||||||
IsPull: true,
|
IsPull: true,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
if IsErrUserDoesNotHaveAccessToRepo(err) || IsErrNewIssueInsert(err) {
|
if repo_model.IsErrUserDoesNotHaveAccessToRepo(err) || IsErrNewIssueInsert(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return fmt.Errorf("newIssue: %v", err)
|
return fmt.Errorf("newIssue: %v", err)
|
||||||
|
@ -691,3 +769,70 @@ func (pr *PullRequest) Mergeable() bool {
|
||||||
return pr.Status != PullRequestStatusChecking && pr.Status != PullRequestStatusConflict &&
|
return pr.Status != PullRequestStatusChecking && pr.Status != PullRequestStatusConflict &&
|
||||||
pr.Status != PullRequestStatusError && !pr.IsWorkInProgress()
|
pr.Status != PullRequestStatusError && !pr.IsWorkInProgress()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HasEnoughApprovals returns true if pr has enough granted approvals.
|
||||||
|
func HasEnoughApprovals(ctx context.Context, protectBranch *git_model.ProtectedBranch, pr *PullRequest) bool {
|
||||||
|
if protectBranch.RequiredApprovals == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return GetGrantedApprovalsCount(ctx, protectBranch, pr) >= protectBranch.RequiredApprovals
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetGrantedApprovalsCount returns the number of granted approvals for pr. A granted approval must be authored by a user in an approval whitelist.
|
||||||
|
func GetGrantedApprovalsCount(ctx context.Context, protectBranch *git_model.ProtectedBranch, pr *PullRequest) int64 {
|
||||||
|
sess := db.GetEngine(ctx).Where("issue_id = ?", pr.IssueID).
|
||||||
|
And("type = ?", ReviewTypeApprove).
|
||||||
|
And("official = ?", true).
|
||||||
|
And("dismissed = ?", false)
|
||||||
|
if protectBranch.DismissStaleApprovals {
|
||||||
|
sess = sess.And("stale = ?", false)
|
||||||
|
}
|
||||||
|
approvals, err := sess.Count(new(Review))
|
||||||
|
if err != nil {
|
||||||
|
log.Error("GetGrantedApprovalsCount: %v", err)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return approvals
|
||||||
|
}
|
||||||
|
|
||||||
|
// MergeBlockedByRejectedReview returns true if merge is blocked by rejected reviews
|
||||||
|
func MergeBlockedByRejectedReview(ctx context.Context, protectBranch *git_model.ProtectedBranch, pr *PullRequest) bool {
|
||||||
|
if !protectBranch.BlockOnRejectedReviews {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
rejectExist, err := db.GetEngine(ctx).Where("issue_id = ?", pr.IssueID).
|
||||||
|
And("type = ?", ReviewTypeReject).
|
||||||
|
And("official = ?", true).
|
||||||
|
And("dismissed = ?", false).
|
||||||
|
Exist(new(Review))
|
||||||
|
if err != nil {
|
||||||
|
log.Error("MergeBlockedByRejectedReview: %v", err)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return rejectExist
|
||||||
|
}
|
||||||
|
|
||||||
|
// MergeBlockedByOfficialReviewRequests block merge because of some review request to official reviewer
|
||||||
|
// of from official review
|
||||||
|
func MergeBlockedByOfficialReviewRequests(ctx context.Context, protectBranch *git_model.ProtectedBranch, pr *PullRequest) bool {
|
||||||
|
if !protectBranch.BlockOnOfficialReviewRequests {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
has, err := db.GetEngine(ctx).Where("issue_id = ?", pr.IssueID).
|
||||||
|
And("type = ?", ReviewTypeRequest).
|
||||||
|
And("official = ?", true).
|
||||||
|
Exist(new(Review))
|
||||||
|
if err != nil {
|
||||||
|
log.Error("MergeBlockedByOfficialReviewRequests: %v", err)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return has
|
||||||
|
}
|
||||||
|
|
||||||
|
// MergeBlockedByOutdatedBranch returns true if merge is blocked by an outdated head branch
|
||||||
|
func MergeBlockedByOutdatedBranch(protectBranch *git_model.ProtectedBranch, pr *PullRequest) bool {
|
||||||
|
return protectBranch.BlockOnOutdatedBranch && pr.CommitsBehind > 0
|
||||||
|
}
|
|
@ -2,7 +2,7 @@
|
||||||
// Use of this source code is governed by a MIT-style
|
// Use of this source code is governed by a MIT-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package models
|
package issues
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
|
@ -2,12 +2,13 @@
|
||||||
// Use of this source code is governed by a MIT-style
|
// Use of this source code is governed by a MIT-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package models
|
package issues_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
@ -15,7 +16,7 @@ import (
|
||||||
|
|
||||||
func TestPullRequest_LoadAttributes(t *testing.T) {
|
func TestPullRequest_LoadAttributes(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
pr := unittest.AssertExistsAndLoadBean(t, &PullRequest{ID: 1}).(*PullRequest)
|
pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 1}).(*issues_model.PullRequest)
|
||||||
assert.NoError(t, pr.LoadAttributes())
|
assert.NoError(t, pr.LoadAttributes())
|
||||||
assert.NotNil(t, pr.Merger)
|
assert.NotNil(t, pr.Merger)
|
||||||
assert.Equal(t, pr.MergerID, pr.Merger.ID)
|
assert.Equal(t, pr.MergerID, pr.Merger.ID)
|
||||||
|
@ -23,7 +24,7 @@ func TestPullRequest_LoadAttributes(t *testing.T) {
|
||||||
|
|
||||||
func TestPullRequest_LoadIssue(t *testing.T) {
|
func TestPullRequest_LoadIssue(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
pr := unittest.AssertExistsAndLoadBean(t, &PullRequest{ID: 1}).(*PullRequest)
|
pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 1}).(*issues_model.PullRequest)
|
||||||
assert.NoError(t, pr.LoadIssue())
|
assert.NoError(t, pr.LoadIssue())
|
||||||
assert.NotNil(t, pr.Issue)
|
assert.NotNil(t, pr.Issue)
|
||||||
assert.Equal(t, int64(2), pr.Issue.ID)
|
assert.Equal(t, int64(2), pr.Issue.ID)
|
||||||
|
@ -34,7 +35,7 @@ func TestPullRequest_LoadIssue(t *testing.T) {
|
||||||
|
|
||||||
func TestPullRequest_LoadBaseRepo(t *testing.T) {
|
func TestPullRequest_LoadBaseRepo(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
pr := unittest.AssertExistsAndLoadBean(t, &PullRequest{ID: 1}).(*PullRequest)
|
pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 1}).(*issues_model.PullRequest)
|
||||||
assert.NoError(t, pr.LoadBaseRepo())
|
assert.NoError(t, pr.LoadBaseRepo())
|
||||||
assert.NotNil(t, pr.BaseRepo)
|
assert.NotNil(t, pr.BaseRepo)
|
||||||
assert.Equal(t, pr.BaseRepoID, pr.BaseRepo.ID)
|
assert.Equal(t, pr.BaseRepoID, pr.BaseRepo.ID)
|
||||||
|
@ -45,7 +46,7 @@ func TestPullRequest_LoadBaseRepo(t *testing.T) {
|
||||||
|
|
||||||
func TestPullRequest_LoadHeadRepo(t *testing.T) {
|
func TestPullRequest_LoadHeadRepo(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
pr := unittest.AssertExistsAndLoadBean(t, &PullRequest{ID: 1}).(*PullRequest)
|
pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 1}).(*issues_model.PullRequest)
|
||||||
assert.NoError(t, pr.LoadHeadRepo())
|
assert.NoError(t, pr.LoadHeadRepo())
|
||||||
assert.NotNil(t, pr.HeadRepo)
|
assert.NotNil(t, pr.HeadRepo)
|
||||||
assert.Equal(t, pr.HeadRepoID, pr.HeadRepo.ID)
|
assert.Equal(t, pr.HeadRepoID, pr.HeadRepo.ID)
|
||||||
|
@ -57,7 +58,7 @@ func TestPullRequest_LoadHeadRepo(t *testing.T) {
|
||||||
|
|
||||||
func TestPullRequestsNewest(t *testing.T) {
|
func TestPullRequestsNewest(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
prs, count, err := PullRequests(1, &PullRequestsOptions{
|
prs, count, err := issues_model.PullRequests(1, &issues_model.PullRequestsOptions{
|
||||||
ListOptions: db.ListOptions{
|
ListOptions: db.ListOptions{
|
||||||
Page: 1,
|
Page: 1,
|
||||||
},
|
},
|
||||||
|
@ -76,7 +77,7 @@ func TestPullRequestsNewest(t *testing.T) {
|
||||||
|
|
||||||
func TestPullRequestsOldest(t *testing.T) {
|
func TestPullRequestsOldest(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
prs, count, err := PullRequests(1, &PullRequestsOptions{
|
prs, count, err := issues_model.PullRequests(1, &issues_model.PullRequestsOptions{
|
||||||
ListOptions: db.ListOptions{
|
ListOptions: db.ListOptions{
|
||||||
Page: 1,
|
Page: 1,
|
||||||
},
|
},
|
||||||
|
@ -95,30 +96,30 @@ func TestPullRequestsOldest(t *testing.T) {
|
||||||
|
|
||||||
func TestGetUnmergedPullRequest(t *testing.T) {
|
func TestGetUnmergedPullRequest(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
pr, err := GetUnmergedPullRequest(1, 1, "branch2", "master", PullRequestFlowGithub)
|
pr, err := issues_model.GetUnmergedPullRequest(1, 1, "branch2", "master", issues_model.PullRequestFlowGithub)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, int64(2), pr.ID)
|
assert.Equal(t, int64(2), pr.ID)
|
||||||
|
|
||||||
_, err = GetUnmergedPullRequest(1, 9223372036854775807, "branch1", "master", PullRequestFlowGithub)
|
_, err = issues_model.GetUnmergedPullRequest(1, 9223372036854775807, "branch1", "master", issues_model.PullRequestFlowGithub)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.True(t, IsErrPullRequestNotExist(err))
|
assert.True(t, issues_model.IsErrPullRequestNotExist(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHasUnmergedPullRequestsByHeadInfo(t *testing.T) {
|
func TestHasUnmergedPullRequestsByHeadInfo(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
exist, err := HasUnmergedPullRequestsByHeadInfo(db.DefaultContext, 1, "branch2")
|
exist, err := issues_model.HasUnmergedPullRequestsByHeadInfo(db.DefaultContext, 1, "branch2")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, true, exist)
|
assert.Equal(t, true, exist)
|
||||||
|
|
||||||
exist, err = HasUnmergedPullRequestsByHeadInfo(db.DefaultContext, 1, "not_exist_branch")
|
exist, err = issues_model.HasUnmergedPullRequestsByHeadInfo(db.DefaultContext, 1, "not_exist_branch")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, false, exist)
|
assert.Equal(t, false, exist)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetUnmergedPullRequestsByHeadInfo(t *testing.T) {
|
func TestGetUnmergedPullRequestsByHeadInfo(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
prs, err := GetUnmergedPullRequestsByHeadInfo(1, "branch2")
|
prs, err := issues_model.GetUnmergedPullRequestsByHeadInfo(1, "branch2")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Len(t, prs, 1)
|
assert.Len(t, prs, 1)
|
||||||
for _, pr := range prs {
|
for _, pr := range prs {
|
||||||
|
@ -129,7 +130,7 @@ func TestGetUnmergedPullRequestsByHeadInfo(t *testing.T) {
|
||||||
|
|
||||||
func TestGetUnmergedPullRequestsByBaseInfo(t *testing.T) {
|
func TestGetUnmergedPullRequestsByBaseInfo(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
prs, err := GetUnmergedPullRequestsByBaseInfo(1, "master")
|
prs, err := issues_model.GetUnmergedPullRequestsByBaseInfo(1, "master")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Len(t, prs, 1)
|
assert.Len(t, prs, 1)
|
||||||
pr := prs[0]
|
pr := prs[0]
|
||||||
|
@ -140,51 +141,51 @@ func TestGetUnmergedPullRequestsByBaseInfo(t *testing.T) {
|
||||||
|
|
||||||
func TestGetPullRequestByIndex(t *testing.T) {
|
func TestGetPullRequestByIndex(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
pr, err := GetPullRequestByIndex(db.DefaultContext, 1, 2)
|
pr, err := issues_model.GetPullRequestByIndex(db.DefaultContext, 1, 2)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, int64(1), pr.BaseRepoID)
|
assert.Equal(t, int64(1), pr.BaseRepoID)
|
||||||
assert.Equal(t, int64(2), pr.Index)
|
assert.Equal(t, int64(2), pr.Index)
|
||||||
|
|
||||||
_, err = GetPullRequestByIndex(db.DefaultContext, 9223372036854775807, 9223372036854775807)
|
_, err = issues_model.GetPullRequestByIndex(db.DefaultContext, 9223372036854775807, 9223372036854775807)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.True(t, IsErrPullRequestNotExist(err))
|
assert.True(t, issues_model.IsErrPullRequestNotExist(err))
|
||||||
|
|
||||||
_, err = GetPullRequestByIndex(db.DefaultContext, 1, 0)
|
_, err = issues_model.GetPullRequestByIndex(db.DefaultContext, 1, 0)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.True(t, IsErrPullRequestNotExist(err))
|
assert.True(t, issues_model.IsErrPullRequestNotExist(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetPullRequestByID(t *testing.T) {
|
func TestGetPullRequestByID(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
pr, err := GetPullRequestByID(db.DefaultContext, 1)
|
pr, err := issues_model.GetPullRequestByID(db.DefaultContext, 1)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, int64(1), pr.ID)
|
assert.Equal(t, int64(1), pr.ID)
|
||||||
assert.Equal(t, int64(2), pr.IssueID)
|
assert.Equal(t, int64(2), pr.IssueID)
|
||||||
|
|
||||||
_, err = GetPullRequestByID(db.DefaultContext, 9223372036854775807)
|
_, err = issues_model.GetPullRequestByID(db.DefaultContext, 9223372036854775807)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.True(t, IsErrPullRequestNotExist(err))
|
assert.True(t, issues_model.IsErrPullRequestNotExist(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetPullRequestByIssueID(t *testing.T) {
|
func TestGetPullRequestByIssueID(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
pr, err := GetPullRequestByIssueID(db.DefaultContext, 2)
|
pr, err := issues_model.GetPullRequestByIssueID(db.DefaultContext, 2)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, int64(2), pr.IssueID)
|
assert.Equal(t, int64(2), pr.IssueID)
|
||||||
|
|
||||||
_, err = GetPullRequestByIssueID(db.DefaultContext, 9223372036854775807)
|
_, err = issues_model.GetPullRequestByIssueID(db.DefaultContext, 9223372036854775807)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.True(t, IsErrPullRequestNotExist(err))
|
assert.True(t, issues_model.IsErrPullRequestNotExist(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPullRequest_Update(t *testing.T) {
|
func TestPullRequest_Update(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
pr := unittest.AssertExistsAndLoadBean(t, &PullRequest{ID: 1}).(*PullRequest)
|
pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 1}).(*issues_model.PullRequest)
|
||||||
pr.BaseBranch = "baseBranch"
|
pr.BaseBranch = "baseBranch"
|
||||||
pr.HeadBranch = "headBranch"
|
pr.HeadBranch = "headBranch"
|
||||||
pr.Update()
|
pr.Update()
|
||||||
|
|
||||||
pr = unittest.AssertExistsAndLoadBean(t, &PullRequest{ID: pr.ID}).(*PullRequest)
|
pr = unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: pr.ID}).(*issues_model.PullRequest)
|
||||||
assert.Equal(t, "baseBranch", pr.BaseBranch)
|
assert.Equal(t, "baseBranch", pr.BaseBranch)
|
||||||
assert.Equal(t, "headBranch", pr.HeadBranch)
|
assert.Equal(t, "headBranch", pr.HeadBranch)
|
||||||
unittest.CheckConsistencyFor(t, pr)
|
unittest.CheckConsistencyFor(t, pr)
|
||||||
|
@ -192,14 +193,14 @@ func TestPullRequest_Update(t *testing.T) {
|
||||||
|
|
||||||
func TestPullRequest_UpdateCols(t *testing.T) {
|
func TestPullRequest_UpdateCols(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
pr := &PullRequest{
|
pr := &issues_model.PullRequest{
|
||||||
ID: 1,
|
ID: 1,
|
||||||
BaseBranch: "baseBranch",
|
BaseBranch: "baseBranch",
|
||||||
HeadBranch: "headBranch",
|
HeadBranch: "headBranch",
|
||||||
}
|
}
|
||||||
assert.NoError(t, pr.UpdateCols("head_branch"))
|
assert.NoError(t, pr.UpdateCols("head_branch"))
|
||||||
|
|
||||||
pr = unittest.AssertExistsAndLoadBean(t, &PullRequest{ID: 1}).(*PullRequest)
|
pr = unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 1}).(*issues_model.PullRequest)
|
||||||
assert.Equal(t, "master", pr.BaseBranch)
|
assert.Equal(t, "master", pr.BaseBranch)
|
||||||
assert.Equal(t, "headBranch", pr.HeadBranch)
|
assert.Equal(t, "headBranch", pr.HeadBranch)
|
||||||
unittest.CheckConsistencyFor(t, pr)
|
unittest.CheckConsistencyFor(t, pr)
|
||||||
|
@ -208,17 +209,17 @@ func TestPullRequest_UpdateCols(t *testing.T) {
|
||||||
func TestPullRequestList_LoadAttributes(t *testing.T) {
|
func TestPullRequestList_LoadAttributes(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
prs := []*PullRequest{
|
prs := []*issues_model.PullRequest{
|
||||||
unittest.AssertExistsAndLoadBean(t, &PullRequest{ID: 1}).(*PullRequest),
|
unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 1}).(*issues_model.PullRequest),
|
||||||
unittest.AssertExistsAndLoadBean(t, &PullRequest{ID: 2}).(*PullRequest),
|
unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 2}).(*issues_model.PullRequest),
|
||||||
}
|
}
|
||||||
assert.NoError(t, PullRequestList(prs).LoadAttributes())
|
assert.NoError(t, issues_model.PullRequestList(prs).LoadAttributes())
|
||||||
for _, pr := range prs {
|
for _, pr := range prs {
|
||||||
assert.NotNil(t, pr.Issue)
|
assert.NotNil(t, pr.Issue)
|
||||||
assert.Equal(t, pr.IssueID, pr.Issue.ID)
|
assert.Equal(t, pr.IssueID, pr.Issue.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.NoError(t, PullRequestList([]*PullRequest{}).LoadAttributes())
|
assert.NoError(t, issues_model.PullRequestList([]*issues_model.PullRequest{}).LoadAttributes())
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO TestAddTestPullRequestTask
|
// TODO TestAddTestPullRequestTask
|
||||||
|
@ -226,7 +227,7 @@ func TestPullRequestList_LoadAttributes(t *testing.T) {
|
||||||
func TestPullRequest_IsWorkInProgress(t *testing.T) {
|
func TestPullRequest_IsWorkInProgress(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
pr := unittest.AssertExistsAndLoadBean(t, &PullRequest{ID: 2}).(*PullRequest)
|
pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 2}).(*issues_model.PullRequest)
|
||||||
pr.LoadIssue()
|
pr.LoadIssue()
|
||||||
|
|
||||||
assert.False(t, pr.IsWorkInProgress())
|
assert.False(t, pr.IsWorkInProgress())
|
||||||
|
@ -241,7 +242,7 @@ func TestPullRequest_IsWorkInProgress(t *testing.T) {
|
||||||
func TestPullRequest_GetWorkInProgressPrefixWorkInProgress(t *testing.T) {
|
func TestPullRequest_GetWorkInProgressPrefixWorkInProgress(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
pr := unittest.AssertExistsAndLoadBean(t, &PullRequest{ID: 2}).(*PullRequest)
|
pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 2}).(*issues_model.PullRequest)
|
||||||
pr.LoadIssue()
|
pr.LoadIssue()
|
||||||
|
|
||||||
assert.Empty(t, pr.GetWorkInProgressPrefix())
|
assert.Empty(t, pr.GetWorkInProgressPrefix())
|
||||||
|
@ -253,3 +254,24 @@ func TestPullRequest_GetWorkInProgressPrefixWorkInProgress(t *testing.T) {
|
||||||
pr.Issue.Title = "[wip] " + original
|
pr.Issue.Title = "[wip] " + original
|
||||||
assert.Equal(t, "[wip]", pr.GetWorkInProgressPrefix())
|
assert.Equal(t, "[wip]", pr.GetWorkInProgressPrefix())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDeleteOrphanedObjects(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
|
countBefore, err := db.GetEngine(db.DefaultContext).Count(&issues_model.PullRequest{})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
_, err = db.GetEngine(db.DefaultContext).Insert(&issues_model.PullRequest{IssueID: 1000}, &issues_model.PullRequest{IssueID: 1001}, &issues_model.PullRequest{IssueID: 1003})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
orphaned, err := db.CountOrphanedObjects("pull_request", "issue", "pull_request.issue_id=issue.id")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.EqualValues(t, 3, orphaned)
|
||||||
|
|
||||||
|
err = db.DeleteOrphanedObjects("pull_request", "issue", "pull_request.issue_id=issue.id")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
countAfter, err := db.GetEngine(db.DefaultContext).Count(&issues_model.PullRequest{})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.EqualValues(t, countBefore, countAfter)
|
||||||
|
}
|
|
@ -2,12 +2,13 @@
|
||||||
// Use of this source code is governed by a MIT-style
|
// Use of this source code is governed by a MIT-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package issues
|
package issues_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
@ -17,12 +18,12 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func addReaction(t *testing.T, doerID, issueID, commentID int64, content string) {
|
func addReaction(t *testing.T, doerID, issueID, commentID int64, content string) {
|
||||||
var reaction *Reaction
|
var reaction *issues_model.Reaction
|
||||||
var err error
|
var err error
|
||||||
if commentID == 0 {
|
if commentID == 0 {
|
||||||
reaction, err = CreateIssueReaction(doerID, issueID, content)
|
reaction, err = issues_model.CreateIssueReaction(doerID, issueID, content)
|
||||||
} else {
|
} else {
|
||||||
reaction, err = CreateCommentReaction(doerID, issueID, commentID, content)
|
reaction, err = issues_model.CreateCommentReaction(doerID, issueID, commentID, content)
|
||||||
}
|
}
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NotNil(t, reaction)
|
assert.NotNil(t, reaction)
|
||||||
|
@ -37,7 +38,7 @@ func TestIssueAddReaction(t *testing.T) {
|
||||||
|
|
||||||
addReaction(t, user1.ID, issue1ID, 0, "heart")
|
addReaction(t, user1.ID, issue1ID, 0, "heart")
|
||||||
|
|
||||||
unittest.AssertExistsAndLoadBean(t, &Reaction{Type: "heart", UserID: user1.ID, IssueID: issue1ID})
|
unittest.AssertExistsAndLoadBean(t, &issues_model.Reaction{Type: "heart", UserID: user1.ID, IssueID: issue1ID})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestIssueAddDuplicateReaction(t *testing.T) {
|
func TestIssueAddDuplicateReaction(t *testing.T) {
|
||||||
|
@ -49,15 +50,15 @@ func TestIssueAddDuplicateReaction(t *testing.T) {
|
||||||
|
|
||||||
addReaction(t, user1.ID, issue1ID, 0, "heart")
|
addReaction(t, user1.ID, issue1ID, 0, "heart")
|
||||||
|
|
||||||
reaction, err := CreateReaction(&ReactionOptions{
|
reaction, err := issues_model.CreateReaction(&issues_model.ReactionOptions{
|
||||||
DoerID: user1.ID,
|
DoerID: user1.ID,
|
||||||
IssueID: issue1ID,
|
IssueID: issue1ID,
|
||||||
Type: "heart",
|
Type: "heart",
|
||||||
})
|
})
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.Equal(t, ErrReactionAlreadyExist{Reaction: "heart"}, err)
|
assert.Equal(t, issues_model.ErrReactionAlreadyExist{Reaction: "heart"}, err)
|
||||||
|
|
||||||
existingR := unittest.AssertExistsAndLoadBean(t, &Reaction{Type: "heart", UserID: user1.ID, IssueID: issue1ID}).(*Reaction)
|
existingR := unittest.AssertExistsAndLoadBean(t, &issues_model.Reaction{Type: "heart", UserID: user1.ID, IssueID: issue1ID}).(*issues_model.Reaction)
|
||||||
assert.Equal(t, existingR.ID, reaction.ID)
|
assert.Equal(t, existingR.ID, reaction.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,10 +71,10 @@ func TestIssueDeleteReaction(t *testing.T) {
|
||||||
|
|
||||||
addReaction(t, user1.ID, issue1ID, 0, "heart")
|
addReaction(t, user1.ID, issue1ID, 0, "heart")
|
||||||
|
|
||||||
err := DeleteIssueReaction(user1.ID, issue1ID, "heart")
|
err := issues_model.DeleteIssueReaction(user1.ID, issue1ID, "heart")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
unittest.AssertNotExistsBean(t, &Reaction{Type: "heart", UserID: user1.ID, IssueID: issue1ID})
|
unittest.AssertNotExistsBean(t, &issues_model.Reaction{Type: "heart", UserID: user1.ID, IssueID: issue1ID})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestIssueReactionCount(t *testing.T) {
|
func TestIssueReactionCount(t *testing.T) {
|
||||||
|
@ -98,7 +99,7 @@ func TestIssueReactionCount(t *testing.T) {
|
||||||
addReaction(t, user4.ID, issueID, 0, "heart")
|
addReaction(t, user4.ID, issueID, 0, "heart")
|
||||||
addReaction(t, ghost.ID, issueID, 0, "-1")
|
addReaction(t, ghost.ID, issueID, 0, "-1")
|
||||||
|
|
||||||
reactionsList, _, err := FindReactions(db.DefaultContext, FindReactionsOptions{
|
reactionsList, _, err := issues_model.FindReactions(db.DefaultContext, issues_model.FindReactionsOptions{
|
||||||
IssueID: issueID,
|
IssueID: issueID,
|
||||||
})
|
})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
@ -128,7 +129,7 @@ func TestIssueCommentAddReaction(t *testing.T) {
|
||||||
|
|
||||||
addReaction(t, user1.ID, issue1ID, comment1ID, "heart")
|
addReaction(t, user1.ID, issue1ID, comment1ID, "heart")
|
||||||
|
|
||||||
unittest.AssertExistsAndLoadBean(t, &Reaction{Type: "heart", UserID: user1.ID, IssueID: issue1ID, CommentID: comment1ID})
|
unittest.AssertExistsAndLoadBean(t, &issues_model.Reaction{Type: "heart", UserID: user1.ID, IssueID: issue1ID, CommentID: comment1ID})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestIssueCommentDeleteReaction(t *testing.T) {
|
func TestIssueCommentDeleteReaction(t *testing.T) {
|
||||||
|
@ -147,7 +148,7 @@ func TestIssueCommentDeleteReaction(t *testing.T) {
|
||||||
addReaction(t, user3.ID, issue1ID, comment1ID, "heart")
|
addReaction(t, user3.ID, issue1ID, comment1ID, "heart")
|
||||||
addReaction(t, user4.ID, issue1ID, comment1ID, "+1")
|
addReaction(t, user4.ID, issue1ID, comment1ID, "+1")
|
||||||
|
|
||||||
reactionsList, _, err := FindReactions(db.DefaultContext, FindReactionsOptions{
|
reactionsList, _, err := issues_model.FindReactions(db.DefaultContext, issues_model.FindReactionsOptions{
|
||||||
IssueID: issue1ID,
|
IssueID: issue1ID,
|
||||||
CommentID: comment1ID,
|
CommentID: comment1ID,
|
||||||
})
|
})
|
||||||
|
@ -168,7 +169,7 @@ func TestIssueCommentReactionCount(t *testing.T) {
|
||||||
var comment1ID int64 = 1
|
var comment1ID int64 = 1
|
||||||
|
|
||||||
addReaction(t, user1.ID, issue1ID, comment1ID, "heart")
|
addReaction(t, user1.ID, issue1ID, comment1ID, "heart")
|
||||||
assert.NoError(t, DeleteCommentReaction(user1.ID, issue1ID, comment1ID, "heart"))
|
assert.NoError(t, issues_model.DeleteCommentReaction(user1.ID, issue1ID, comment1ID, "heart"))
|
||||||
|
|
||||||
unittest.AssertNotExistsBean(t, &Reaction{Type: "heart", UserID: user1.ID, IssueID: issue1ID, CommentID: comment1ID})
|
unittest.AssertNotExistsBean(t, &issues_model.Reaction{Type: "heart", UserID: user1.ID, IssueID: issue1ID, CommentID: comment1ID})
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
// Use of this source code is governed by a MIT-style
|
// Use of this source code is governed by a MIT-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package models
|
package issues
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
@ -17,11 +17,47 @@ import (
|
||||||
"code.gitea.io/gitea/models/unit"
|
"code.gitea.io/gitea/models/unit"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/base"
|
"code.gitea.io/gitea/modules/base"
|
||||||
|
"code.gitea.io/gitea/modules/structs"
|
||||||
"code.gitea.io/gitea/modules/timeutil"
|
"code.gitea.io/gitea/modules/timeutil"
|
||||||
|
|
||||||
"xorm.io/builder"
|
"xorm.io/builder"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ErrReviewNotExist represents a "ReviewNotExist" kind of error.
|
||||||
|
type ErrReviewNotExist struct {
|
||||||
|
ID int64
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsErrReviewNotExist checks if an error is a ErrReviewNotExist.
|
||||||
|
func IsErrReviewNotExist(err error) bool {
|
||||||
|
_, ok := err.(ErrReviewNotExist)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err ErrReviewNotExist) Error() string {
|
||||||
|
return fmt.Sprintf("review does not exist [id: %d]", err.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrNotValidReviewRequest an not allowed review request modify
|
||||||
|
type ErrNotValidReviewRequest struct {
|
||||||
|
Reason string
|
||||||
|
UserID int64
|
||||||
|
RepoID int64
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsErrNotValidReviewRequest checks if an error is a ErrNotValidReviewRequest.
|
||||||
|
func IsErrNotValidReviewRequest(err error) bool {
|
||||||
|
_, ok := err.(ErrNotValidReviewRequest)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err ErrNotValidReviewRequest) Error() string {
|
||||||
|
return fmt.Sprintf("%s [user_id: %d, repo_id: %d]",
|
||||||
|
err.Reason,
|
||||||
|
err.UserID,
|
||||||
|
err.RepoID)
|
||||||
|
}
|
||||||
|
|
||||||
// ReviewType defines the sort of feedback a review gives
|
// ReviewType defines the sort of feedback a review gives
|
||||||
type ReviewType int
|
type ReviewType int
|
||||||
|
|
||||||
|
@ -105,7 +141,7 @@ func (r *Review) loadIssue(ctx context.Context) (err error) {
|
||||||
if r.Issue != nil {
|
if r.Issue != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
r.Issue, err = getIssueByID(ctx, r.IssueID)
|
r.Issue, err = GetIssueByID(ctx, r.IssueID)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -967,3 +1003,16 @@ func (r *Review) GetExternalName() string { return r.OriginalAuthor }
|
||||||
|
|
||||||
// GetExternalID ExternalUserRemappable interface
|
// GetExternalID ExternalUserRemappable interface
|
||||||
func (r *Review) GetExternalID() int64 { return r.OriginalAuthorID }
|
func (r *Review) GetExternalID() int64 { return r.OriginalAuthorID }
|
||||||
|
|
||||||
|
// UpdateReviewsMigrationsByType updates reviews' migrations information via given git service type and original id and poster id
|
||||||
|
func UpdateReviewsMigrationsByType(tp structs.GitServiceType, originalAuthorID string, posterID int64) error {
|
||||||
|
_, err := db.GetEngine(db.DefaultContext).Table("review").
|
||||||
|
Where("original_author_id = ?", originalAuthorID).
|
||||||
|
And(migratedIssueCond(tp)).
|
||||||
|
Update(map[string]interface{}{
|
||||||
|
"reviewer_id": posterID,
|
||||||
|
"original_author": "",
|
||||||
|
"original_author_id": 0,
|
||||||
|
})
|
||||||
|
return err
|
||||||
|
}
|
|
@ -2,12 +2,13 @@
|
||||||
// Use of this source code is governed by a MIT-style
|
// Use of this source code is governed by a MIT-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package models
|
package issues_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
|
||||||
|
@ -16,34 +17,34 @@ import (
|
||||||
|
|
||||||
func TestGetReviewByID(t *testing.T) {
|
func TestGetReviewByID(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
review, err := GetReviewByID(db.DefaultContext, 1)
|
review, err := issues_model.GetReviewByID(db.DefaultContext, 1)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, "Demo Review", review.Content)
|
assert.Equal(t, "Demo Review", review.Content)
|
||||||
assert.Equal(t, ReviewTypeApprove, review.Type)
|
assert.Equal(t, issues_model.ReviewTypeApprove, review.Type)
|
||||||
|
|
||||||
_, err = GetReviewByID(db.DefaultContext, 23892)
|
_, err = issues_model.GetReviewByID(db.DefaultContext, 23892)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.True(t, IsErrReviewNotExist(err), "IsErrReviewNotExist")
|
assert.True(t, issues_model.IsErrReviewNotExist(err), "IsErrReviewNotExist")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestReview_LoadAttributes(t *testing.T) {
|
func TestReview_LoadAttributes(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
review := unittest.AssertExistsAndLoadBean(t, &Review{ID: 1}).(*Review)
|
review := unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 1}).(*issues_model.Review)
|
||||||
assert.NoError(t, review.LoadAttributes(db.DefaultContext))
|
assert.NoError(t, review.LoadAttributes(db.DefaultContext))
|
||||||
assert.NotNil(t, review.Issue)
|
assert.NotNil(t, review.Issue)
|
||||||
assert.NotNil(t, review.Reviewer)
|
assert.NotNil(t, review.Reviewer)
|
||||||
|
|
||||||
invalidReview1 := unittest.AssertExistsAndLoadBean(t, &Review{ID: 2}).(*Review)
|
invalidReview1 := unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 2}).(*issues_model.Review)
|
||||||
assert.Error(t, invalidReview1.LoadAttributes(db.DefaultContext))
|
assert.Error(t, invalidReview1.LoadAttributes(db.DefaultContext))
|
||||||
|
|
||||||
invalidReview2 := unittest.AssertExistsAndLoadBean(t, &Review{ID: 3}).(*Review)
|
invalidReview2 := unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 3}).(*issues_model.Review)
|
||||||
assert.Error(t, invalidReview2.LoadAttributes(db.DefaultContext))
|
assert.Error(t, invalidReview2.LoadAttributes(db.DefaultContext))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestReview_LoadCodeComments(t *testing.T) {
|
func TestReview_LoadCodeComments(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
review := unittest.AssertExistsAndLoadBean(t, &Review{ID: 4}).(*Review)
|
review := unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 4}).(*issues_model.Review)
|
||||||
assert.NoError(t, review.LoadAttributes(db.DefaultContext))
|
assert.NoError(t, review.LoadAttributes(db.DefaultContext))
|
||||||
assert.NoError(t, review.LoadCodeComments(db.DefaultContext))
|
assert.NoError(t, review.LoadCodeComments(db.DefaultContext))
|
||||||
assert.Len(t, review.CodeComments, 1)
|
assert.Len(t, review.CodeComments, 1)
|
||||||
|
@ -51,18 +52,18 @@ func TestReview_LoadCodeComments(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestReviewType_Icon(t *testing.T) {
|
func TestReviewType_Icon(t *testing.T) {
|
||||||
assert.Equal(t, "check", ReviewTypeApprove.Icon())
|
assert.Equal(t, "check", issues_model.ReviewTypeApprove.Icon())
|
||||||
assert.Equal(t, "diff", ReviewTypeReject.Icon())
|
assert.Equal(t, "diff", issues_model.ReviewTypeReject.Icon())
|
||||||
assert.Equal(t, "comment", ReviewTypeComment.Icon())
|
assert.Equal(t, "comment", issues_model.ReviewTypeComment.Icon())
|
||||||
assert.Equal(t, "comment", ReviewTypeUnknown.Icon())
|
assert.Equal(t, "comment", issues_model.ReviewTypeUnknown.Icon())
|
||||||
assert.Equal(t, "dot-fill", ReviewTypeRequest.Icon())
|
assert.Equal(t, "dot-fill", issues_model.ReviewTypeRequest.Icon())
|
||||||
assert.Equal(t, "comment", ReviewType(6).Icon())
|
assert.Equal(t, "comment", issues_model.ReviewType(6).Icon())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFindReviews(t *testing.T) {
|
func TestFindReviews(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
reviews, err := FindReviews(db.DefaultContext, FindReviewOptions{
|
reviews, err := issues_model.FindReviews(db.DefaultContext, issues_model.FindReviewOptions{
|
||||||
Type: ReviewTypeApprove,
|
Type: issues_model.ReviewTypeApprove,
|
||||||
IssueID: 2,
|
IssueID: 2,
|
||||||
ReviewerID: 1,
|
ReviewerID: 1,
|
||||||
})
|
})
|
||||||
|
@ -73,66 +74,66 @@ func TestFindReviews(t *testing.T) {
|
||||||
|
|
||||||
func TestGetCurrentReview(t *testing.T) {
|
func TestGetCurrentReview(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
issue := unittest.AssertExistsAndLoadBean(t, &Issue{ID: 2}).(*Issue)
|
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2}).(*issues_model.Issue)
|
||||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User)
|
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User)
|
||||||
|
|
||||||
review, err := GetCurrentReview(db.DefaultContext, user, issue)
|
review, err := issues_model.GetCurrentReview(db.DefaultContext, user, issue)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NotNil(t, review)
|
assert.NotNil(t, review)
|
||||||
assert.Equal(t, ReviewTypePending, review.Type)
|
assert.Equal(t, issues_model.ReviewTypePending, review.Type)
|
||||||
assert.Equal(t, "Pending Review", review.Content)
|
assert.Equal(t, "Pending Review", review.Content)
|
||||||
|
|
||||||
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 7}).(*user_model.User)
|
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 7}).(*user_model.User)
|
||||||
review2, err := GetCurrentReview(db.DefaultContext, user2, issue)
|
review2, err := issues_model.GetCurrentReview(db.DefaultContext, user2, issue)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.True(t, IsErrReviewNotExist(err))
|
assert.True(t, issues_model.IsErrReviewNotExist(err))
|
||||||
assert.Nil(t, review2)
|
assert.Nil(t, review2)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCreateReview(t *testing.T) {
|
func TestCreateReview(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
issue := unittest.AssertExistsAndLoadBean(t, &Issue{ID: 2}).(*Issue)
|
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2}).(*issues_model.Issue)
|
||||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User)
|
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User)
|
||||||
|
|
||||||
review, err := CreateReview(db.DefaultContext, CreateReviewOptions{
|
review, err := issues_model.CreateReview(db.DefaultContext, issues_model.CreateReviewOptions{
|
||||||
Content: "New Review",
|
Content: "New Review",
|
||||||
Type: ReviewTypePending,
|
Type: issues_model.ReviewTypePending,
|
||||||
Issue: issue,
|
Issue: issue,
|
||||||
Reviewer: user,
|
Reviewer: user,
|
||||||
})
|
})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, "New Review", review.Content)
|
assert.Equal(t, "New Review", review.Content)
|
||||||
unittest.AssertExistsAndLoadBean(t, &Review{Content: "New Review"})
|
unittest.AssertExistsAndLoadBean(t, &issues_model.Review{Content: "New Review"})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetReviewersByIssueID(t *testing.T) {
|
func TestGetReviewersByIssueID(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
issue := unittest.AssertExistsAndLoadBean(t, &Issue{ID: 3}).(*Issue)
|
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 3}).(*issues_model.Issue)
|
||||||
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
|
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
|
||||||
user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}).(*user_model.User)
|
user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}).(*user_model.User)
|
||||||
user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}).(*user_model.User)
|
user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}).(*user_model.User)
|
||||||
|
|
||||||
expectedReviews := []*Review{}
|
expectedReviews := []*issues_model.Review{}
|
||||||
expectedReviews = append(expectedReviews,
|
expectedReviews = append(expectedReviews,
|
||||||
&Review{
|
&issues_model.Review{
|
||||||
Reviewer: user3,
|
Reviewer: user3,
|
||||||
Type: ReviewTypeReject,
|
Type: issues_model.ReviewTypeReject,
|
||||||
UpdatedUnix: 946684812,
|
UpdatedUnix: 946684812,
|
||||||
},
|
},
|
||||||
&Review{
|
&issues_model.Review{
|
||||||
Reviewer: user4,
|
Reviewer: user4,
|
||||||
Type: ReviewTypeApprove,
|
Type: issues_model.ReviewTypeApprove,
|
||||||
UpdatedUnix: 946684813,
|
UpdatedUnix: 946684813,
|
||||||
},
|
},
|
||||||
&Review{
|
&issues_model.Review{
|
||||||
Reviewer: user2,
|
Reviewer: user2,
|
||||||
Type: ReviewTypeReject,
|
Type: issues_model.ReviewTypeReject,
|
||||||
UpdatedUnix: 946684814,
|
UpdatedUnix: 946684814,
|
||||||
})
|
})
|
||||||
|
|
||||||
allReviews, err := GetReviewersByIssueID(issue.ID)
|
allReviews, err := issues_model.GetReviewersByIssueID(issue.ID)
|
||||||
for _, reviewer := range allReviews {
|
for _, reviewer := range allReviews {
|
||||||
assert.NoError(t, reviewer.LoadReviewer())
|
assert.NoError(t, reviewer.LoadReviewer())
|
||||||
}
|
}
|
||||||
|
@ -149,53 +150,53 @@ func TestGetReviewersByIssueID(t *testing.T) {
|
||||||
func TestDismissReview(t *testing.T) {
|
func TestDismissReview(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
rejectReviewExample := unittest.AssertExistsAndLoadBean(t, &Review{ID: 9}).(*Review)
|
rejectReviewExample := unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 9}).(*issues_model.Review)
|
||||||
requestReviewExample := unittest.AssertExistsAndLoadBean(t, &Review{ID: 11}).(*Review)
|
requestReviewExample := unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 11}).(*issues_model.Review)
|
||||||
approveReviewExample := unittest.AssertExistsAndLoadBean(t, &Review{ID: 8}).(*Review)
|
approveReviewExample := unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 8}).(*issues_model.Review)
|
||||||
assert.False(t, rejectReviewExample.Dismissed)
|
assert.False(t, rejectReviewExample.Dismissed)
|
||||||
assert.False(t, requestReviewExample.Dismissed)
|
assert.False(t, requestReviewExample.Dismissed)
|
||||||
assert.False(t, approveReviewExample.Dismissed)
|
assert.False(t, approveReviewExample.Dismissed)
|
||||||
|
|
||||||
assert.NoError(t, DismissReview(rejectReviewExample, true))
|
assert.NoError(t, issues_model.DismissReview(rejectReviewExample, true))
|
||||||
rejectReviewExample = unittest.AssertExistsAndLoadBean(t, &Review{ID: 9}).(*Review)
|
rejectReviewExample = unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 9}).(*issues_model.Review)
|
||||||
requestReviewExample = unittest.AssertExistsAndLoadBean(t, &Review{ID: 11}).(*Review)
|
requestReviewExample = unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 11}).(*issues_model.Review)
|
||||||
assert.True(t, rejectReviewExample.Dismissed)
|
assert.True(t, rejectReviewExample.Dismissed)
|
||||||
assert.False(t, requestReviewExample.Dismissed)
|
assert.False(t, requestReviewExample.Dismissed)
|
||||||
|
|
||||||
assert.NoError(t, DismissReview(requestReviewExample, true))
|
assert.NoError(t, issues_model.DismissReview(requestReviewExample, true))
|
||||||
rejectReviewExample = unittest.AssertExistsAndLoadBean(t, &Review{ID: 9}).(*Review)
|
rejectReviewExample = unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 9}).(*issues_model.Review)
|
||||||
requestReviewExample = unittest.AssertExistsAndLoadBean(t, &Review{ID: 11}).(*Review)
|
requestReviewExample = unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 11}).(*issues_model.Review)
|
||||||
assert.True(t, rejectReviewExample.Dismissed)
|
assert.True(t, rejectReviewExample.Dismissed)
|
||||||
assert.False(t, requestReviewExample.Dismissed)
|
assert.False(t, requestReviewExample.Dismissed)
|
||||||
assert.False(t, approveReviewExample.Dismissed)
|
assert.False(t, approveReviewExample.Dismissed)
|
||||||
|
|
||||||
assert.NoError(t, DismissReview(requestReviewExample, true))
|
assert.NoError(t, issues_model.DismissReview(requestReviewExample, true))
|
||||||
rejectReviewExample = unittest.AssertExistsAndLoadBean(t, &Review{ID: 9}).(*Review)
|
rejectReviewExample = unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 9}).(*issues_model.Review)
|
||||||
requestReviewExample = unittest.AssertExistsAndLoadBean(t, &Review{ID: 11}).(*Review)
|
requestReviewExample = unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 11}).(*issues_model.Review)
|
||||||
assert.True(t, rejectReviewExample.Dismissed)
|
assert.True(t, rejectReviewExample.Dismissed)
|
||||||
assert.False(t, requestReviewExample.Dismissed)
|
assert.False(t, requestReviewExample.Dismissed)
|
||||||
assert.False(t, approveReviewExample.Dismissed)
|
assert.False(t, approveReviewExample.Dismissed)
|
||||||
|
|
||||||
assert.NoError(t, DismissReview(requestReviewExample, false))
|
assert.NoError(t, issues_model.DismissReview(requestReviewExample, false))
|
||||||
rejectReviewExample = unittest.AssertExistsAndLoadBean(t, &Review{ID: 9}).(*Review)
|
rejectReviewExample = unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 9}).(*issues_model.Review)
|
||||||
requestReviewExample = unittest.AssertExistsAndLoadBean(t, &Review{ID: 11}).(*Review)
|
requestReviewExample = unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 11}).(*issues_model.Review)
|
||||||
assert.True(t, rejectReviewExample.Dismissed)
|
assert.True(t, rejectReviewExample.Dismissed)
|
||||||
assert.False(t, requestReviewExample.Dismissed)
|
assert.False(t, requestReviewExample.Dismissed)
|
||||||
assert.False(t, approveReviewExample.Dismissed)
|
assert.False(t, approveReviewExample.Dismissed)
|
||||||
|
|
||||||
assert.NoError(t, DismissReview(requestReviewExample, false))
|
assert.NoError(t, issues_model.DismissReview(requestReviewExample, false))
|
||||||
rejectReviewExample = unittest.AssertExistsAndLoadBean(t, &Review{ID: 9}).(*Review)
|
rejectReviewExample = unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 9}).(*issues_model.Review)
|
||||||
requestReviewExample = unittest.AssertExistsAndLoadBean(t, &Review{ID: 11}).(*Review)
|
requestReviewExample = unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 11}).(*issues_model.Review)
|
||||||
assert.True(t, rejectReviewExample.Dismissed)
|
assert.True(t, rejectReviewExample.Dismissed)
|
||||||
assert.False(t, requestReviewExample.Dismissed)
|
assert.False(t, requestReviewExample.Dismissed)
|
||||||
assert.False(t, approveReviewExample.Dismissed)
|
assert.False(t, approveReviewExample.Dismissed)
|
||||||
|
|
||||||
assert.NoError(t, DismissReview(rejectReviewExample, false))
|
assert.NoError(t, issues_model.DismissReview(rejectReviewExample, false))
|
||||||
assert.False(t, rejectReviewExample.Dismissed)
|
assert.False(t, rejectReviewExample.Dismissed)
|
||||||
assert.False(t, requestReviewExample.Dismissed)
|
assert.False(t, requestReviewExample.Dismissed)
|
||||||
assert.False(t, approveReviewExample.Dismissed)
|
assert.False(t, approveReviewExample.Dismissed)
|
||||||
|
|
||||||
assert.NoError(t, DismissReview(approveReviewExample, true))
|
assert.NoError(t, issues_model.DismissReview(approveReviewExample, true))
|
||||||
assert.False(t, rejectReviewExample.Dismissed)
|
assert.False(t, rejectReviewExample.Dismissed)
|
||||||
assert.False(t, requestReviewExample.Dismissed)
|
assert.False(t, requestReviewExample.Dismissed)
|
||||||
assert.True(t, approveReviewExample.Dismissed)
|
assert.True(t, approveReviewExample.Dismissed)
|
|
@ -2,7 +2,7 @@
|
||||||
// Use of this source code is governed by a MIT-style
|
// Use of this source code is governed by a MIT-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package models
|
package issues
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
@ -215,7 +215,7 @@ func CreateIssueStopwatch(ctx context.Context, user *user_model.User, issue *Iss
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if exists {
|
if exists {
|
||||||
issue, err := getIssueByID(ctx, sw.IssueID)
|
issue, err := GetIssueByID(ctx, sw.IssueID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
79
models/issues/stopwatch_test.go
Normal file
79
models/issues/stopwatch_test.go
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package issues_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/models/db"
|
||||||
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
|
"code.gitea.io/gitea/models/unittest"
|
||||||
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
"code.gitea.io/gitea/modules/timeutil"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCancelStopwatch(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
|
user1, err := user_model.GetUserByID(1)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
issue1, err := issues_model.GetIssueByID(db.DefaultContext, 1)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
issue2, err := issues_model.GetIssueByID(db.DefaultContext, 2)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
err = issues_model.CancelStopwatch(user1, issue1)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
unittest.AssertNotExistsBean(t, &issues_model.Stopwatch{UserID: user1.ID, IssueID: issue1.ID})
|
||||||
|
|
||||||
|
_ = unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{Type: issues_model.CommentTypeCancelTracking, PosterID: user1.ID, IssueID: issue1.ID})
|
||||||
|
|
||||||
|
assert.Nil(t, issues_model.CancelStopwatch(user1, issue2))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStopwatchExists(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
|
assert.True(t, issues_model.StopwatchExists(1, 1))
|
||||||
|
assert.False(t, issues_model.StopwatchExists(1, 2))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHasUserStopwatch(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
|
exists, sw, err := issues_model.HasUserStopwatch(db.DefaultContext, 1)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.True(t, exists)
|
||||||
|
assert.Equal(t, int64(1), sw.ID)
|
||||||
|
|
||||||
|
exists, _, err = issues_model.HasUserStopwatch(db.DefaultContext, 3)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.False(t, exists)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateOrStopIssueStopwatch(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
|
user2, err := user_model.GetUserByID(2)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
user3, err := user_model.GetUserByID(3)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
issue1, err := issues_model.GetIssueByID(db.DefaultContext, 1)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
issue2, err := issues_model.GetIssueByID(db.DefaultContext, 2)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
assert.NoError(t, issues_model.CreateOrStopIssueStopwatch(user3, issue1))
|
||||||
|
sw := unittest.AssertExistsAndLoadBean(t, &issues_model.Stopwatch{UserID: 3, IssueID: 1}).(*issues_model.Stopwatch)
|
||||||
|
assert.LessOrEqual(t, sw.CreatedUnix, timeutil.TimeStampNow())
|
||||||
|
|
||||||
|
assert.NoError(t, issues_model.CreateOrStopIssueStopwatch(user2, issue2))
|
||||||
|
unittest.AssertNotExistsBean(t, &issues_model.Stopwatch{UserID: 2, IssueID: 2})
|
||||||
|
unittest.AssertExistsAndLoadBean(t, &issues_model.TrackedTime{UserID: 2, IssueID: 2})
|
||||||
|
}
|
|
@ -2,7 +2,7 @@
|
||||||
// Use of this source code is governed by a MIT-style
|
// Use of this source code is governed by a MIT-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package models
|
package issues
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
@ -48,7 +48,7 @@ func (t *TrackedTime) LoadAttributes() (err error) {
|
||||||
|
|
||||||
func (t *TrackedTime) loadAttributes(ctx context.Context) (err error) {
|
func (t *TrackedTime) loadAttributes(ctx context.Context) (err error) {
|
||||||
if t.Issue == nil {
|
if t.Issue == nil {
|
||||||
t.Issue, err = getIssueByID(ctx, t.IssueID)
|
t.Issue, err = GetIssueByID(ctx, t.IssueID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
|
@ -2,13 +2,14 @@
|
||||||
// Use of this source code is governed by a MIT-style
|
// Use of this source code is governed by a MIT-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package models
|
package issues_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
|
||||||
|
@ -21,20 +22,20 @@ func TestAddTime(t *testing.T) {
|
||||||
user3, err := user_model.GetUserByID(3)
|
user3, err := user_model.GetUserByID(3)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
issue1, err := GetIssueByID(1)
|
issue1, err := issues_model.GetIssueByID(db.DefaultContext, 1)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// 3661 = 1h 1min 1s
|
// 3661 = 1h 1min 1s
|
||||||
trackedTime, err := AddTime(user3, issue1, 3661, time.Now())
|
trackedTime, err := issues_model.AddTime(user3, issue1, 3661, time.Now())
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, int64(3), trackedTime.UserID)
|
assert.Equal(t, int64(3), trackedTime.UserID)
|
||||||
assert.Equal(t, int64(1), trackedTime.IssueID)
|
assert.Equal(t, int64(1), trackedTime.IssueID)
|
||||||
assert.Equal(t, int64(3661), trackedTime.Time)
|
assert.Equal(t, int64(3661), trackedTime.Time)
|
||||||
|
|
||||||
tt := unittest.AssertExistsAndLoadBean(t, &TrackedTime{UserID: 3, IssueID: 1}).(*TrackedTime)
|
tt := unittest.AssertExistsAndLoadBean(t, &issues_model.TrackedTime{UserID: 3, IssueID: 1}).(*issues_model.TrackedTime)
|
||||||
assert.Equal(t, int64(3661), tt.Time)
|
assert.Equal(t, int64(3661), tt.Time)
|
||||||
|
|
||||||
comment := unittest.AssertExistsAndLoadBean(t, &Comment{Type: CommentTypeAddTimeManual, PosterID: 3, IssueID: 1}).(*Comment)
|
comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{Type: issues_model.CommentTypeAddTimeManual, PosterID: 3, IssueID: 1}).(*issues_model.Comment)
|
||||||
assert.Equal(t, comment.Content, "1 hour 1 minute")
|
assert.Equal(t, comment.Content, "1 hour 1 minute")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,39 +43,39 @@ func TestGetTrackedTimes(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
// by Issue
|
// by Issue
|
||||||
times, err := GetTrackedTimes(db.DefaultContext, &FindTrackedTimesOptions{IssueID: 1})
|
times, err := issues_model.GetTrackedTimes(db.DefaultContext, &issues_model.FindTrackedTimesOptions{IssueID: 1})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Len(t, times, 1)
|
assert.Len(t, times, 1)
|
||||||
assert.Equal(t, int64(400), times[0].Time)
|
assert.Equal(t, int64(400), times[0].Time)
|
||||||
|
|
||||||
times, err = GetTrackedTimes(db.DefaultContext, &FindTrackedTimesOptions{IssueID: -1})
|
times, err = issues_model.GetTrackedTimes(db.DefaultContext, &issues_model.FindTrackedTimesOptions{IssueID: -1})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Len(t, times, 0)
|
assert.Len(t, times, 0)
|
||||||
|
|
||||||
// by User
|
// by User
|
||||||
times, err = GetTrackedTimes(db.DefaultContext, &FindTrackedTimesOptions{UserID: 1})
|
times, err = issues_model.GetTrackedTimes(db.DefaultContext, &issues_model.FindTrackedTimesOptions{UserID: 1})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Len(t, times, 3)
|
assert.Len(t, times, 3)
|
||||||
assert.Equal(t, int64(400), times[0].Time)
|
assert.Equal(t, int64(400), times[0].Time)
|
||||||
|
|
||||||
times, err = GetTrackedTimes(db.DefaultContext, &FindTrackedTimesOptions{UserID: 3})
|
times, err = issues_model.GetTrackedTimes(db.DefaultContext, &issues_model.FindTrackedTimesOptions{UserID: 3})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Len(t, times, 0)
|
assert.Len(t, times, 0)
|
||||||
|
|
||||||
// by Repo
|
// by Repo
|
||||||
times, err = GetTrackedTimes(db.DefaultContext, &FindTrackedTimesOptions{RepositoryID: 2})
|
times, err = issues_model.GetTrackedTimes(db.DefaultContext, &issues_model.FindTrackedTimesOptions{RepositoryID: 2})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Len(t, times, 3)
|
assert.Len(t, times, 3)
|
||||||
assert.Equal(t, int64(1), times[0].Time)
|
assert.Equal(t, int64(1), times[0].Time)
|
||||||
issue, err := GetIssueByID(times[0].IssueID)
|
issue, err := issues_model.GetIssueByID(db.DefaultContext, times[0].IssueID)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, issue.RepoID, int64(2))
|
assert.Equal(t, issue.RepoID, int64(2))
|
||||||
|
|
||||||
times, err = GetTrackedTimes(db.DefaultContext, &FindTrackedTimesOptions{RepositoryID: 1})
|
times, err = issues_model.GetTrackedTimes(db.DefaultContext, &issues_model.FindTrackedTimesOptions{RepositoryID: 1})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Len(t, times, 5)
|
assert.Len(t, times, 5)
|
||||||
|
|
||||||
times, err = GetTrackedTimes(db.DefaultContext, &FindTrackedTimesOptions{RepositoryID: 10})
|
times, err = issues_model.GetTrackedTimes(db.DefaultContext, &issues_model.FindTrackedTimesOptions{RepositoryID: 10})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Len(t, times, 0)
|
assert.Len(t, times, 0)
|
||||||
}
|
}
|
||||||
|
@ -82,7 +83,7 @@ func TestGetTrackedTimes(t *testing.T) {
|
||||||
func TestTotalTimes(t *testing.T) {
|
func TestTotalTimes(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
total, err := TotalTimes(&FindTrackedTimesOptions{IssueID: 1})
|
total, err := issues_model.TotalTimes(&issues_model.FindTrackedTimesOptions{IssueID: 1})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Len(t, total, 1)
|
assert.Len(t, total, 1)
|
||||||
for user, time := range total {
|
for user, time := range total {
|
||||||
|
@ -90,7 +91,7 @@ func TestTotalTimes(t *testing.T) {
|
||||||
assert.Equal(t, "6 minutes 40 seconds", time)
|
assert.Equal(t, "6 minutes 40 seconds", time)
|
||||||
}
|
}
|
||||||
|
|
||||||
total, err = TotalTimes(&FindTrackedTimesOptions{IssueID: 2})
|
total, err = issues_model.TotalTimes(&issues_model.FindTrackedTimesOptions{IssueID: 2})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Len(t, total, 2)
|
assert.Len(t, total, 2)
|
||||||
for user, time := range total {
|
for user, time := range total {
|
||||||
|
@ -103,7 +104,7 @@ func TestTotalTimes(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
total, err = TotalTimes(&FindTrackedTimesOptions{IssueID: 5})
|
total, err = issues_model.TotalTimes(&issues_model.FindTrackedTimesOptions{IssueID: 5})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Len(t, total, 1)
|
assert.Len(t, total, 1)
|
||||||
for user, time := range total {
|
for user, time := range total {
|
||||||
|
@ -111,7 +112,7 @@ func TestTotalTimes(t *testing.T) {
|
||||||
assert.Equal(t, "1 second", time)
|
assert.Equal(t, "1 second", time)
|
||||||
}
|
}
|
||||||
|
|
||||||
total, err = TotalTimes(&FindTrackedTimesOptions{IssueID: 4})
|
total, err = issues_model.TotalTimes(&issues_model.FindTrackedTimesOptions{IssueID: 4})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Len(t, total, 2)
|
assert.Len(t, total, 2)
|
||||||
}
|
}
|
|
@ -7,7 +7,6 @@ package models
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
issues_model "code.gitea.io/gitea/models/issues"
|
|
||||||
"code.gitea.io/gitea/models/organization"
|
"code.gitea.io/gitea/models/organization"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
|
@ -28,10 +27,6 @@ func TestFixturesAreConsistent(t *testing.T) {
|
||||||
unittest.CheckConsistencyFor(t,
|
unittest.CheckConsistencyFor(t,
|
||||||
&user_model.User{},
|
&user_model.User{},
|
||||||
&repo_model.Repository{},
|
&repo_model.Repository{},
|
||||||
&Issue{},
|
|
||||||
&PullRequest{},
|
|
||||||
&issues_model.Milestone{},
|
|
||||||
&Label{},
|
|
||||||
&organization.Team{},
|
&organization.Team{},
|
||||||
&Action{})
|
&Action{})
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,8 +10,6 @@ import (
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
issues_model "code.gitea.io/gitea/models/issues"
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
"code.gitea.io/gitea/modules/structs"
|
"code.gitea.io/gitea/modules/structs"
|
||||||
|
|
||||||
"xorm.io/builder"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// InsertMilestones creates milestones of repository.
|
// InsertMilestones creates milestones of repository.
|
||||||
|
@ -41,7 +39,7 @@ func InsertMilestones(ms ...*issues_model.Milestone) (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// InsertIssues insert issues to database
|
// InsertIssues insert issues to database
|
||||||
func InsertIssues(issues ...*Issue) error {
|
func InsertIssues(issues ...*issues_model.Issue) error {
|
||||||
ctx, committer, err := db.TxContext()
|
ctx, committer, err := db.TxContext()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -56,14 +54,14 @@ func InsertIssues(issues ...*Issue) error {
|
||||||
return committer.Commit()
|
return committer.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
func insertIssue(ctx context.Context, issue *Issue) error {
|
func insertIssue(ctx context.Context, issue *issues_model.Issue) error {
|
||||||
sess := db.GetEngine(ctx)
|
sess := db.GetEngine(ctx)
|
||||||
if _, err := sess.NoAutoTime().Insert(issue); err != nil {
|
if _, err := sess.NoAutoTime().Insert(issue); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
issueLabels := make([]IssueLabel, 0, len(issue.Labels))
|
issueLabels := make([]issues_model.IssueLabel, 0, len(issue.Labels))
|
||||||
for _, label := range issue.Labels {
|
for _, label := range issue.Labels {
|
||||||
issueLabels = append(issueLabels, IssueLabel{
|
issueLabels = append(issueLabels, issues_model.IssueLabel{
|
||||||
IssueID: issue.ID,
|
IssueID: issue.ID,
|
||||||
LabelID: label.ID,
|
LabelID: label.ID,
|
||||||
})
|
})
|
||||||
|
@ -95,7 +93,7 @@ func insertIssue(ctx context.Context, issue *Issue) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// InsertIssueComments inserts many comments of issues.
|
// InsertIssueComments inserts many comments of issues.
|
||||||
func InsertIssueComments(comments []*Comment) error {
|
func InsertIssueComments(comments []*issues_model.Comment) error {
|
||||||
if len(comments) == 0 {
|
if len(comments) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -127,7 +125,8 @@ func InsertIssueComments(comments []*Comment) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
for issueID := range issueIDs {
|
for issueID := range issueIDs {
|
||||||
if _, err := db.Exec(ctx, "UPDATE issue set num_comments = (SELECT count(*) FROM comment WHERE issue_id = ? AND `type`=?) WHERE id = ?", issueID, CommentTypeComment, issueID); err != nil {
|
if _, err := db.Exec(ctx, "UPDATE issue set num_comments = (SELECT count(*) FROM comment WHERE issue_id = ? AND `type`=?) WHERE id = ?",
|
||||||
|
issueID, issues_model.CommentTypeComment, issueID); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -135,7 +134,7 @@ func InsertIssueComments(comments []*Comment) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// InsertPullRequests inserted pull requests
|
// InsertPullRequests inserted pull requests
|
||||||
func InsertPullRequests(prs ...*PullRequest) error {
|
func InsertPullRequests(prs ...*issues_model.PullRequest) error {
|
||||||
ctx, committer, err := db.TxContext()
|
ctx, committer, err := db.TxContext()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -182,37 +181,13 @@ func InsertReleases(rels ...*Release) error {
|
||||||
return committer.Commit()
|
return committer.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
func migratedIssueCond(tp structs.GitServiceType) builder.Cond {
|
|
||||||
return builder.In("issue_id",
|
|
||||||
builder.Select("issue.id").
|
|
||||||
From("issue").
|
|
||||||
InnerJoin("repository", "issue.repo_id = repository.id").
|
|
||||||
Where(builder.Eq{
|
|
||||||
"repository.original_service_type": tp,
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateReviewsMigrationsByType updates reviews' migrations information via given git service type and original id and poster id
|
|
||||||
func UpdateReviewsMigrationsByType(tp structs.GitServiceType, originalAuthorID string, posterID int64) error {
|
|
||||||
_, err := db.GetEngine(db.DefaultContext).Table("review").
|
|
||||||
Where("original_author_id = ?", originalAuthorID).
|
|
||||||
And(migratedIssueCond(tp)).
|
|
||||||
Update(map[string]interface{}{
|
|
||||||
"reviewer_id": posterID,
|
|
||||||
"original_author": "",
|
|
||||||
"original_author_id": 0,
|
|
||||||
})
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateMigrationsByType updates all migrated repositories' posterid from gitServiceType to replace originalAuthorID to posterID
|
// UpdateMigrationsByType updates all migrated repositories' posterid from gitServiceType to replace originalAuthorID to posterID
|
||||||
func UpdateMigrationsByType(tp structs.GitServiceType, externalUserID string, userID int64) error {
|
func UpdateMigrationsByType(tp structs.GitServiceType, externalUserID string, userID int64) error {
|
||||||
if err := UpdateIssuesMigrationsByType(tp, externalUserID, userID); err != nil {
|
if err := issues_model.UpdateIssuesMigrationsByType(tp, externalUserID, userID); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := UpdateCommentsMigrationsByType(tp, externalUserID, userID); err != nil {
|
if err := issues_model.UpdateCommentsMigrationsByType(tp, externalUserID, userID); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -220,8 +195,8 @@ func UpdateMigrationsByType(tp structs.GitServiceType, externalUserID string, us
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := UpdateReactionsMigrationsByType(tp, externalUserID, userID); err != nil {
|
if err := issues_model.UpdateReactionsMigrationsByType(tp, externalUserID, userID); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return UpdateReviewsMigrationsByType(tp, externalUserID, userID)
|
return issues_model.UpdateReviewsMigrationsByType(tp, externalUserID, userID)
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,7 @@ func assertCreateIssues(t *testing.T, isPull bool) {
|
||||||
reponame := "repo1"
|
reponame := "repo1"
|
||||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{Name: reponame}).(*repo_model.Repository)
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{Name: reponame}).(*repo_model.Repository)
|
||||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User)
|
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User)
|
||||||
label := unittest.AssertExistsAndLoadBean(t, &Label{ID: 1}).(*Label)
|
label := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 1}).(*issues_model.Label)
|
||||||
milestone := unittest.AssertExistsAndLoadBean(t, &issues_model.Milestone{ID: 1}).(*issues_model.Milestone)
|
milestone := unittest.AssertExistsAndLoadBean(t, &issues_model.Milestone{ID: 1}).(*issues_model.Milestone)
|
||||||
assert.EqualValues(t, milestone.ID, 1)
|
assert.EqualValues(t, milestone.ID, 1)
|
||||||
reaction := &issues_model.Reaction{
|
reaction := &issues_model.Reaction{
|
||||||
|
@ -51,7 +51,7 @@ func assertCreateIssues(t *testing.T, isPull bool) {
|
||||||
|
|
||||||
foreignIndex := int64(12345)
|
foreignIndex := int64(12345)
|
||||||
title := "issuetitle1"
|
title := "issuetitle1"
|
||||||
is := &Issue{
|
is := &issues_model.Issue{
|
||||||
RepoID: repo.ID,
|
RepoID: repo.ID,
|
||||||
MilestoneID: milestone.ID,
|
MilestoneID: milestone.ID,
|
||||||
Repo: repo,
|
Repo: repo,
|
||||||
|
@ -61,7 +61,7 @@ func assertCreateIssues(t *testing.T, isPull bool) {
|
||||||
PosterID: owner.ID,
|
PosterID: owner.ID,
|
||||||
Poster: owner,
|
Poster: owner,
|
||||||
IsClosed: true,
|
IsClosed: true,
|
||||||
Labels: []*Label{label},
|
Labels: []*issues_model.Label{label},
|
||||||
Reactions: []*issues_model.Reaction{reaction},
|
Reactions: []*issues_model.Reaction{reaction},
|
||||||
ForeignReference: &foreignreference.ForeignReference{
|
ForeignReference: &foreignreference.ForeignReference{
|
||||||
ForeignIndex: strconv.FormatInt(foreignIndex, 10),
|
ForeignIndex: strconv.FormatInt(foreignIndex, 10),
|
||||||
|
@ -72,9 +72,9 @@ func assertCreateIssues(t *testing.T, isPull bool) {
|
||||||
err := InsertIssues(is)
|
err := InsertIssues(is)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
i := unittest.AssertExistsAndLoadBean(t, &Issue{Title: title}).(*Issue)
|
i := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{Title: title}).(*issues_model.Issue)
|
||||||
assert.Nil(t, i.ForeignReference)
|
assert.Nil(t, i.ForeignReference)
|
||||||
err = i.LoadAttributes()
|
err = i.LoadAttributes(db.DefaultContext)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.EqualValues(t, strconv.FormatInt(foreignIndex, 10), i.ForeignReference.ForeignIndex)
|
assert.EqualValues(t, strconv.FormatInt(foreignIndex, 10), i.ForeignReference.ForeignIndex)
|
||||||
unittest.AssertExistsAndLoadBean(t, &issues_model.Reaction{Type: "heart", UserID: owner.ID, IssueID: i.ID})
|
unittest.AssertExistsAndLoadBean(t, &issues_model.Reaction{Type: "heart", UserID: owner.ID, IssueID: i.ID})
|
||||||
|
@ -90,7 +90,7 @@ func TestMigrate_CreateIssuesIsPullTrue(t *testing.T) {
|
||||||
|
|
||||||
func TestMigrate_InsertIssueComments(t *testing.T) {
|
func TestMigrate_InsertIssueComments(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
issue := unittest.AssertExistsAndLoadBean(t, &Issue{ID: 1}).(*Issue)
|
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1}).(*issues_model.Issue)
|
||||||
_ = issue.LoadRepo(db.DefaultContext)
|
_ = issue.LoadRepo(db.DefaultContext)
|
||||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: issue.Repo.OwnerID}).(*user_model.User)
|
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: issue.Repo.OwnerID}).(*user_model.User)
|
||||||
reaction := &issues_model.Reaction{
|
reaction := &issues_model.Reaction{
|
||||||
|
@ -98,7 +98,7 @@ func TestMigrate_InsertIssueComments(t *testing.T) {
|
||||||
UserID: owner.ID,
|
UserID: owner.ID,
|
||||||
}
|
}
|
||||||
|
|
||||||
comment := &Comment{
|
comment := &issues_model.Comment{
|
||||||
PosterID: owner.ID,
|
PosterID: owner.ID,
|
||||||
Poster: owner,
|
Poster: owner,
|
||||||
IssueID: issue.ID,
|
IssueID: issue.ID,
|
||||||
|
@ -106,13 +106,13 @@ func TestMigrate_InsertIssueComments(t *testing.T) {
|
||||||
Reactions: []*issues_model.Reaction{reaction},
|
Reactions: []*issues_model.Reaction{reaction},
|
||||||
}
|
}
|
||||||
|
|
||||||
err := InsertIssueComments([]*Comment{comment})
|
err := InsertIssueComments([]*issues_model.Comment{comment})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
issueModified := unittest.AssertExistsAndLoadBean(t, &Issue{ID: 1}).(*Issue)
|
issueModified := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1}).(*issues_model.Issue)
|
||||||
assert.EqualValues(t, issue.NumComments+1, issueModified.NumComments)
|
assert.EqualValues(t, issue.NumComments+1, issueModified.NumComments)
|
||||||
|
|
||||||
unittest.CheckConsistencyFor(t, &Issue{})
|
unittest.CheckConsistencyFor(t, &issues_model.Issue{})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMigrate_InsertPullRequests(t *testing.T) {
|
func TestMigrate_InsertPullRequests(t *testing.T) {
|
||||||
|
@ -121,7 +121,7 @@ func TestMigrate_InsertPullRequests(t *testing.T) {
|
||||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{Name: reponame}).(*repo_model.Repository)
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{Name: reponame}).(*repo_model.Repository)
|
||||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User)
|
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User)
|
||||||
|
|
||||||
i := &Issue{
|
i := &issues_model.Issue{
|
||||||
RepoID: repo.ID,
|
RepoID: repo.ID,
|
||||||
Repo: repo,
|
Repo: repo,
|
||||||
Title: "title1",
|
Title: "title1",
|
||||||
|
@ -131,16 +131,16 @@ func TestMigrate_InsertPullRequests(t *testing.T) {
|
||||||
Poster: owner,
|
Poster: owner,
|
||||||
}
|
}
|
||||||
|
|
||||||
p := &PullRequest{
|
p := &issues_model.PullRequest{
|
||||||
Issue: i,
|
Issue: i,
|
||||||
}
|
}
|
||||||
|
|
||||||
err := InsertPullRequests(p)
|
err := InsertPullRequests(p)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
_ = unittest.AssertExistsAndLoadBean(t, &PullRequest{IssueID: i.ID}).(*PullRequest)
|
_ = unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{IssueID: i.ID}).(*issues_model.PullRequest)
|
||||||
|
|
||||||
unittest.CheckConsistencyFor(t, &Issue{}, &PullRequest{})
|
unittest.CheckConsistencyFor(t, &issues_model.Issue{}, &issues_model.PullRequest{})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMigrate_InsertReleases(t *testing.T) {
|
func TestMigrate_InsertReleases(t *testing.T) {
|
||||||
|
|
|
@ -131,7 +131,7 @@ func addBranchProtectionCanPushAndEnableWhitelist(x *xorm.Engine) error {
|
||||||
Authorize int
|
Authorize int
|
||||||
}
|
}
|
||||||
|
|
||||||
// getUserRepoPermission static function based on models.IsOfficialReviewer at 5d78792385
|
// getUserRepoPermission static function based on issues_model.IsOfficialReviewer at 5d78792385
|
||||||
getUserRepoPermission := func(sess *xorm.Session, repo *Repository, user *User) (Permission, error) {
|
getUserRepoPermission := func(sess *xorm.Session, repo *Repository, user *User) (Permission, error) {
|
||||||
var perm Permission
|
var perm Permission
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
"code.gitea.io/gitea/models/organization"
|
"code.gitea.io/gitea/models/organization"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
"code.gitea.io/gitea/models/unit"
|
"code.gitea.io/gitea/models/unit"
|
||||||
|
@ -66,9 +67,9 @@ type Notification struct {
|
||||||
|
|
||||||
UpdatedBy int64 `xorm:"INDEX NOT NULL"`
|
UpdatedBy int64 `xorm:"INDEX NOT NULL"`
|
||||||
|
|
||||||
Issue *Issue `xorm:"-"`
|
Issue *issues_model.Issue `xorm:"-"`
|
||||||
Repository *repo_model.Repository `xorm:"-"`
|
Repository *repo_model.Repository `xorm:"-"`
|
||||||
Comment *Comment `xorm:"-"`
|
Comment *issues_model.Comment `xorm:"-"`
|
||||||
User *user_model.User `xorm:"-"`
|
User *user_model.User `xorm:"-"`
|
||||||
|
|
||||||
CreatedUnix timeutil.TimeStamp `xorm:"created INDEX NOT NULL"`
|
CreatedUnix timeutil.TimeStamp `xorm:"created INDEX NOT NULL"`
|
||||||
|
@ -204,7 +205,7 @@ func createOrUpdateIssueNotifications(ctx context.Context, issueID, commentID, n
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
issue, err := getIssueByID(ctx, issueID)
|
issue, err := issues_model.GetIssueByID(ctx, issueID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -214,14 +215,14 @@ func createOrUpdateIssueNotifications(ctx context.Context, issueID, commentID, n
|
||||||
toNotify[receiverID] = struct{}{}
|
toNotify[receiverID] = struct{}{}
|
||||||
} else {
|
} else {
|
||||||
toNotify = make(map[int64]struct{}, 32)
|
toNotify = make(map[int64]struct{}, 32)
|
||||||
issueWatches, err := GetIssueWatchersIDs(ctx, issueID, true)
|
issueWatches, err := issues_model.GetIssueWatchersIDs(ctx, issueID, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, id := range issueWatches {
|
for _, id := range issueWatches {
|
||||||
toNotify[id] = struct{}{}
|
toNotify[id] = struct{}{}
|
||||||
}
|
}
|
||||||
if !(issue.IsPull && HasWorkInProgressPrefix(issue.Title)) {
|
if !(issue.IsPull && issues_model.HasWorkInProgressPrefix(issue.Title)) {
|
||||||
repoWatches, err := repo_model.GetRepoWatchersIDs(ctx, issue.RepoID)
|
repoWatches, err := repo_model.GetRepoWatchersIDs(ctx, issue.RepoID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -230,7 +231,7 @@ func createOrUpdateIssueNotifications(ctx context.Context, issueID, commentID, n
|
||||||
toNotify[id] = struct{}{}
|
toNotify[id] = struct{}{}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
issueParticipants, err := issue.getParticipantIDsByIssue(ctx)
|
issueParticipants, err := issue.GetParticipantIDsByIssue(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -241,7 +242,7 @@ func createOrUpdateIssueNotifications(ctx context.Context, issueID, commentID, n
|
||||||
// dont notify user who cause notification
|
// dont notify user who cause notification
|
||||||
delete(toNotify, notificationAuthorID)
|
delete(toNotify, notificationAuthorID)
|
||||||
// explicit unwatch on issue
|
// explicit unwatch on issue
|
||||||
issueUnWatches, err := GetIssueWatchersIDs(ctx, issueID, false)
|
issueUnWatches, err := issues_model.GetIssueWatchersIDs(ctx, issueID, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -303,7 +304,7 @@ func notificationExists(notifications []*Notification, issueID, userID int64) bo
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func createIssueNotification(ctx context.Context, userID int64, issue *Issue, commentID, updatedByID int64) error {
|
func createIssueNotification(ctx context.Context, userID int64, issue *issues_model.Issue, commentID, updatedByID int64) error {
|
||||||
notification := &Notification{
|
notification := &Notification{
|
||||||
UserID: userID,
|
UserID: userID,
|
||||||
RepoID: issue.RepoID,
|
RepoID: issue.RepoID,
|
||||||
|
@ -415,21 +416,21 @@ func (n *Notification) loadRepo(ctx context.Context) (err error) {
|
||||||
|
|
||||||
func (n *Notification) loadIssue(ctx context.Context) (err error) {
|
func (n *Notification) loadIssue(ctx context.Context) (err error) {
|
||||||
if n.Issue == nil && n.IssueID != 0 {
|
if n.Issue == nil && n.IssueID != 0 {
|
||||||
n.Issue, err = getIssueByID(ctx, n.IssueID)
|
n.Issue, err = issues_model.GetIssueByID(ctx, n.IssueID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("getIssueByID [%d]: %v", n.IssueID, err)
|
return fmt.Errorf("getIssueByID [%d]: %v", n.IssueID, err)
|
||||||
}
|
}
|
||||||
return n.Issue.loadAttributes(ctx)
|
return n.Issue.LoadAttributes(ctx)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Notification) loadComment(ctx context.Context) (err error) {
|
func (n *Notification) loadComment(ctx context.Context) (err error) {
|
||||||
if n.Comment == nil && n.CommentID != 0 {
|
if n.Comment == nil && n.CommentID != 0 {
|
||||||
n.Comment, err = GetCommentByID(ctx, n.CommentID)
|
n.Comment, err = issues_model.GetCommentByID(ctx, n.CommentID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if IsErrCommentNotExist(err) {
|
if issues_model.IsErrCommentNotExist(err) {
|
||||||
return ErrCommentNotExist{
|
return issues_model.ErrCommentNotExist{
|
||||||
ID: n.CommentID,
|
ID: n.CommentID,
|
||||||
IssueID: n.IssueID,
|
IssueID: n.IssueID,
|
||||||
}
|
}
|
||||||
|
@ -456,7 +457,7 @@ func (n *Notification) GetRepo() (*repo_model.Repository, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetIssue returns the issue of the notification
|
// GetIssue returns the issue of the notification
|
||||||
func (n *Notification) GetIssue() (*Issue, error) {
|
func (n *Notification) GetIssue() (*issues_model.Issue, error) {
|
||||||
return n.Issue, n.loadIssue(db.DefaultContext)
|
return n.Issue, n.loadIssue(db.DefaultContext)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -489,7 +490,7 @@ func (nl NotificationList) LoadAttributes() error {
|
||||||
var err error
|
var err error
|
||||||
for i := 0; i < len(nl); i++ {
|
for i := 0; i < len(nl); i++ {
|
||||||
err = nl[i].LoadAttributes()
|
err = nl[i].LoadAttributes()
|
||||||
if err != nil && !IsErrCommentNotExist(err) {
|
if err != nil && !issues_model.IsErrCommentNotExist(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -519,7 +520,7 @@ func (nl NotificationList) LoadRepos() (repo_model.RepositoryList, []int, error)
|
||||||
repos := make(map[int64]*repo_model.Repository, len(repoIDs))
|
repos := make(map[int64]*repo_model.Repository, len(repoIDs))
|
||||||
left := len(repoIDs)
|
left := len(repoIDs)
|
||||||
for left > 0 {
|
for left > 0 {
|
||||||
limit := defaultMaxInSize
|
limit := db.DefaultMaxInSize
|
||||||
if left < limit {
|
if left < limit {
|
||||||
limit = left
|
limit = left
|
||||||
}
|
}
|
||||||
|
@ -592,22 +593,22 @@ func (nl NotificationList) LoadIssues() ([]int, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
issueIDs := nl.getPendingIssueIDs()
|
issueIDs := nl.getPendingIssueIDs()
|
||||||
issues := make(map[int64]*Issue, len(issueIDs))
|
issues := make(map[int64]*issues_model.Issue, len(issueIDs))
|
||||||
left := len(issueIDs)
|
left := len(issueIDs)
|
||||||
for left > 0 {
|
for left > 0 {
|
||||||
limit := defaultMaxInSize
|
limit := db.DefaultMaxInSize
|
||||||
if left < limit {
|
if left < limit {
|
||||||
limit = left
|
limit = left
|
||||||
}
|
}
|
||||||
rows, err := db.GetEngine(db.DefaultContext).
|
rows, err := db.GetEngine(db.DefaultContext).
|
||||||
In("id", issueIDs[:limit]).
|
In("id", issueIDs[:limit]).
|
||||||
Rows(new(Issue))
|
Rows(new(issues_model.Issue))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var issue Issue
|
var issue issues_model.Issue
|
||||||
err = rows.Scan(&issue)
|
err = rows.Scan(&issue)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
rows.Close()
|
rows.Close()
|
||||||
|
@ -678,22 +679,22 @@ func (nl NotificationList) LoadComments() ([]int, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
commentIDs := nl.getPendingCommentIDs()
|
commentIDs := nl.getPendingCommentIDs()
|
||||||
comments := make(map[int64]*Comment, len(commentIDs))
|
comments := make(map[int64]*issues_model.Comment, len(commentIDs))
|
||||||
left := len(commentIDs)
|
left := len(commentIDs)
|
||||||
for left > 0 {
|
for left > 0 {
|
||||||
limit := defaultMaxInSize
|
limit := db.DefaultMaxInSize
|
||||||
if left < limit {
|
if left < limit {
|
||||||
limit = left
|
limit = left
|
||||||
}
|
}
|
||||||
rows, err := db.GetEngine(db.DefaultContext).
|
rows, err := db.GetEngine(db.DefaultContext).
|
||||||
In("id", commentIDs[:limit]).
|
In("id", commentIDs[:limit]).
|
||||||
Rows(new(Comment))
|
Rows(new(issues_model.Comment))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var comment Comment
|
var comment issues_model.Comment
|
||||||
err = rows.Scan(&comment)
|
err = rows.Scan(&comment)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
rows.Close()
|
rows.Close()
|
||||||
|
@ -747,6 +748,15 @@ func GetUIDsAndNotificationCounts(since, until timeutil.TimeStamp) ([]UserIDCoun
|
||||||
return res, db.GetEngine(db.DefaultContext).SQL(sql, since, until, NotificationStatusUnread).Find(&res)
|
return res, db.GetEngine(db.DefaultContext).SQL(sql, since, until, NotificationStatusUnread).Find(&res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetIssueReadBy sets issue to be read by given user.
|
||||||
|
func SetIssueReadBy(ctx context.Context, issueID, userID int64) error {
|
||||||
|
if err := issues_model.UpdateIssueUserByRead(userID, issueID); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return setIssueNotificationStatusReadIfUnread(ctx, userID, issueID)
|
||||||
|
}
|
||||||
|
|
||||||
func setIssueNotificationStatusReadIfUnread(ctx context.Context, userID, issueID int64) error {
|
func setIssueNotificationStatusReadIfUnread(ctx context.Context, userID, issueID int64) error {
|
||||||
notification, err := getIssueNotification(ctx, userID, issueID)
|
notification, err := getIssueNotification(ctx, userID, issueID)
|
||||||
// ignore if not exists
|
// ignore if not exists
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
|
||||||
|
@ -16,14 +17,14 @@ import (
|
||||||
|
|
||||||
func TestCreateOrUpdateIssueNotifications(t *testing.T) {
|
func TestCreateOrUpdateIssueNotifications(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
issue := unittest.AssertExistsAndLoadBean(t, &Issue{ID: 1}).(*Issue)
|
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1}).(*issues_model.Issue)
|
||||||
|
|
||||||
assert.NoError(t, CreateOrUpdateIssueNotifications(issue.ID, 0, 2, 0))
|
assert.NoError(t, CreateOrUpdateIssueNotifications(issue.ID, 0, 2, 0))
|
||||||
|
|
||||||
// User 9 is inactive, thus notifications for user 1 and 4 are created
|
// User 9 is inactive, thus notifications for user 1 and 4 are created
|
||||||
notf := unittest.AssertExistsAndLoadBean(t, &Notification{UserID: 1, IssueID: issue.ID}).(*Notification)
|
notf := unittest.AssertExistsAndLoadBean(t, &Notification{UserID: 1, IssueID: issue.ID}).(*Notification)
|
||||||
assert.Equal(t, NotificationStatusUnread, notf.Status)
|
assert.Equal(t, NotificationStatusUnread, notf.Status)
|
||||||
unittest.CheckConsistencyFor(t, &Issue{ID: issue.ID})
|
unittest.CheckConsistencyFor(t, &issues_model.Issue{ID: issue.ID})
|
||||||
|
|
||||||
notf = unittest.AssertExistsAndLoadBean(t, &Notification{UserID: 4, IssueID: issue.ID}).(*Notification)
|
notf = unittest.AssertExistsAndLoadBean(t, &Notification{UserID: 4, IssueID: issue.ID}).(*Notification)
|
||||||
assert.Equal(t, NotificationStatusUnread, notf.Status)
|
assert.Equal(t, NotificationStatusUnread, notf.Status)
|
||||||
|
|
|
@ -13,6 +13,7 @@ import (
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
git_model "code.gitea.io/gitea/models/git"
|
git_model "code.gitea.io/gitea/models/git"
|
||||||
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
"code.gitea.io/gitea/models/organization"
|
"code.gitea.io/gitea/models/organization"
|
||||||
access_model "code.gitea.io/gitea/models/perm/access"
|
access_model "code.gitea.io/gitea/models/perm/access"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
|
@ -153,7 +154,7 @@ func removeAllRepositories(ctx context.Context, t *organization.Team) (err error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove all IssueWatches a user has subscribed to in the repositories
|
// Remove all IssueWatches a user has subscribed to in the repositories
|
||||||
if err = removeIssueWatchersByRepoID(ctx, user.ID, repo.ID); err != nil {
|
if err = issues_model.RemoveIssueWatchersByRepoID(ctx, user.ID, repo.ID); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -216,7 +217,7 @@ func removeRepository(ctx context.Context, t *organization.Team, repo *repo_mode
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove all IssueWatches a user has subscribed to in the repositories
|
// Remove all IssueWatches a user has subscribed to in the repositories
|
||||||
if err := removeIssueWatchersByRepoID(ctx, teamUser.UID, repo.ID); err != nil {
|
if err := issues_model.RemoveIssueWatchersByRepoID(ctx, teamUser.UID, repo.ID); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -281,7 +281,7 @@ func DeleteRepository(doer *user_model.User, uid, repoID int64) error {
|
||||||
&access_model.Access{RepoID: repo.ID},
|
&access_model.Access{RepoID: repo.ID},
|
||||||
&Action{RepoID: repo.ID},
|
&Action{RepoID: repo.ID},
|
||||||
&repo_model.Collaboration{RepoID: repoID},
|
&repo_model.Collaboration{RepoID: repoID},
|
||||||
&Comment{RefRepoID: repoID},
|
&issues_model.Comment{RefRepoID: repoID},
|
||||||
&git_model.CommitStatus{RepoID: repoID},
|
&git_model.CommitStatus{RepoID: repoID},
|
||||||
&git_model.DeletedBranch{RepoID: repoID},
|
&git_model.DeletedBranch{RepoID: repoID},
|
||||||
&webhook.HookTask{RepoID: repoID},
|
&webhook.HookTask{RepoID: repoID},
|
||||||
|
@ -306,18 +306,18 @@ func DeleteRepository(doer *user_model.User, uid, repoID int64) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete Labels and related objects
|
// Delete Labels and related objects
|
||||||
if err := deleteLabelsByRepoID(ctx, repoID); err != nil {
|
if err := issues_model.DeleteLabelsByRepoID(ctx, repoID); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete Pulls and related objects
|
// Delete Pulls and related objects
|
||||||
if err := deletePullsByBaseRepoID(ctx, repoID); err != nil {
|
if err := issues_model.DeletePullsByBaseRepoID(ctx, repoID); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete Issues and related objects
|
// Delete Issues and related objects
|
||||||
var attachmentPaths []string
|
var attachmentPaths []string
|
||||||
if attachmentPaths, err = deleteIssuesByRepoID(ctx, repoID); err != nil {
|
if attachmentPaths, err = issues_model.DeleteIssuesByRepoID(ctx, repoID); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -576,16 +576,11 @@ func repoStatsCorrectNum(ctx context.Context, id int64, isPull bool, field strin
|
||||||
}
|
}
|
||||||
|
|
||||||
func repoStatsCorrectNumClosedIssues(ctx context.Context, id int64) error {
|
func repoStatsCorrectNumClosedIssues(ctx context.Context, id int64) error {
|
||||||
return repoStatsCorrectNumClosed(ctx, id, false, "num_closed_issues")
|
return repo_model.StatsCorrectNumClosed(ctx, id, false, "num_closed_issues")
|
||||||
}
|
}
|
||||||
|
|
||||||
func repoStatsCorrectNumClosedPulls(ctx context.Context, id int64) error {
|
func repoStatsCorrectNumClosedPulls(ctx context.Context, id int64) error {
|
||||||
return repoStatsCorrectNumClosed(ctx, id, true, "num_closed_pulls")
|
return repo_model.StatsCorrectNumClosed(ctx, id, true, "num_closed_pulls")
|
||||||
}
|
|
||||||
|
|
||||||
func repoStatsCorrectNumClosed(ctx context.Context, id int64, isPull bool, field string) error {
|
|
||||||
_, err := db.GetEngine(ctx).Exec("UPDATE `repository` SET "+field+"=(SELECT COUNT(*) FROM `issue` WHERE repo_id=? AND is_closed=? AND is_pull=?) WHERE id=?", id, true, isPull, id)
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func statsQuery(args ...interface{}) func(context.Context) ([]map[string][]byte, error) {
|
func statsQuery(args ...interface{}) func(context.Context) ([]map[string][]byte, error) {
|
||||||
|
@ -687,12 +682,11 @@ func CheckRepoStats(ctx context.Context) error {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
rawResult, err := e.Query("SELECT COUNT(*) FROM `repository` WHERE fork_id=?", repo.ID)
|
_, err = e.SQL("SELECT COUNT(*) FROM `repository` WHERE fork_id=?", repo.ID).Get(&repo.NumForks)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Select count of forks[%d]: %v", repo.ID, err)
|
log.Error("Select count of forks[%d]: %v", repo.ID, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
repo.NumForks = int(parseCountResult(rawResult))
|
|
||||||
|
|
||||||
if _, err = e.ID(repo.ID).Cols("num_forks").Update(repo); err != nil {
|
if _, err = e.ID(repo.ID).Cols("num_forks").Update(repo); err != nil {
|
||||||
log.Error("UpdateRepository[%d]: %v", id, err)
|
log.Error("UpdateRepository[%d]: %v", id, err)
|
||||||
|
|
|
@ -25,6 +25,22 @@ import (
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ErrUserDoesNotHaveAccessToRepo represets an error where the user doesn't has access to a given repo.
|
||||||
|
type ErrUserDoesNotHaveAccessToRepo struct {
|
||||||
|
UserID int64
|
||||||
|
RepoName string
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsErrUserDoesNotHaveAccessToRepo checks if an error is a ErrRepoFileAlreadyExists.
|
||||||
|
func IsErrUserDoesNotHaveAccessToRepo(err error) bool {
|
||||||
|
_, ok := err.(ErrUserDoesNotHaveAccessToRepo)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err ErrUserDoesNotHaveAccessToRepo) Error() string {
|
||||||
|
return fmt.Sprintf("user doesn't have access to repo [user_id: %d, repo_name: %s]", err.UserID, err.RepoName)
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
reservedRepoNames = []string{".", "..", "-"}
|
reservedRepoNames = []string{".", "..", "-"}
|
||||||
reservedRepoPatterns = []string{"*.git", "*.wiki", "*.rss", "*.atom"}
|
reservedRepoPatterns = []string{"*.git", "*.wiki", "*.rss", "*.atom"}
|
||||||
|
@ -743,3 +759,34 @@ func CountRepositories(ctx context.Context, opts CountRepositoryOptions) (int64,
|
||||||
}
|
}
|
||||||
return count, nil
|
return count, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StatsCorrectNumClosed update repository's issue related numbers
|
||||||
|
func StatsCorrectNumClosed(ctx context.Context, id int64, isPull bool, field string) error {
|
||||||
|
_, err := db.Exec(ctx, "UPDATE `repository` SET "+field+"=(SELECT COUNT(*) FROM `issue` WHERE repo_id=? AND is_closed=? AND is_pull=?) WHERE id=?", id, true, isPull, id)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateRepoIssueNumbers update repository issue numbers
|
||||||
|
func UpdateRepoIssueNumbers(ctx context.Context, repoID int64, isPull, isClosed bool) error {
|
||||||
|
e := db.GetEngine(ctx)
|
||||||
|
if isPull {
|
||||||
|
if _, err := e.ID(repoID).Decr("num_pulls").Update(new(Repository)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if isClosed {
|
||||||
|
if _, err := e.ID(repoID).Decr("num_closed_pulls").Update(new(Repository)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if _, err := e.ID(repoID).Decr("num_issues").Update(new(Repository)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if isClosed {
|
||||||
|
if _, err := e.ID(repoID).Decr("num_closed_issues").Update(new(Repository)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
|
@ -29,15 +30,15 @@ type ActivityAuthorData struct {
|
||||||
|
|
||||||
// ActivityStats represets issue and pull request information.
|
// ActivityStats represets issue and pull request information.
|
||||||
type ActivityStats struct {
|
type ActivityStats struct {
|
||||||
OpenedPRs PullRequestList
|
OpenedPRs issues_model.PullRequestList
|
||||||
OpenedPRAuthorCount int64
|
OpenedPRAuthorCount int64
|
||||||
MergedPRs PullRequestList
|
MergedPRs issues_model.PullRequestList
|
||||||
MergedPRAuthorCount int64
|
MergedPRAuthorCount int64
|
||||||
OpenedIssues IssueList
|
OpenedIssues issues_model.IssueList
|
||||||
OpenedIssueAuthorCount int64
|
OpenedIssueAuthorCount int64
|
||||||
ClosedIssues IssueList
|
ClosedIssues issues_model.IssueList
|
||||||
ClosedIssueAuthorCount int64
|
ClosedIssueAuthorCount int64
|
||||||
UnresolvedIssues IssueList
|
UnresolvedIssues issues_model.IssueList
|
||||||
PublishedReleases []*Release
|
PublishedReleases []*Release
|
||||||
PublishedReleaseAuthorCount int64
|
PublishedReleaseAuthorCount int64
|
||||||
Code *git.CodeActivityStats
|
Code *git.CodeActivityStats
|
||||||
|
@ -212,7 +213,7 @@ func (stats *ActivityStats) FillPullRequests(repoID int64, fromTime time.Time) e
|
||||||
// Merged pull requests
|
// Merged pull requests
|
||||||
sess := pullRequestsForActivityStatement(repoID, fromTime, true)
|
sess := pullRequestsForActivityStatement(repoID, fromTime, true)
|
||||||
sess.OrderBy("pull_request.merged_unix DESC")
|
sess.OrderBy("pull_request.merged_unix DESC")
|
||||||
stats.MergedPRs = make(PullRequestList, 0)
|
stats.MergedPRs = make(issues_model.PullRequestList, 0)
|
||||||
if err = sess.Find(&stats.MergedPRs); err != nil {
|
if err = sess.Find(&stats.MergedPRs); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -230,7 +231,7 @@ func (stats *ActivityStats) FillPullRequests(repoID int64, fromTime time.Time) e
|
||||||
// Opened pull requests
|
// Opened pull requests
|
||||||
sess = pullRequestsForActivityStatement(repoID, fromTime, false)
|
sess = pullRequestsForActivityStatement(repoID, fromTime, false)
|
||||||
sess.OrderBy("issue.created_unix ASC")
|
sess.OrderBy("issue.created_unix ASC")
|
||||||
stats.OpenedPRs = make(PullRequestList, 0)
|
stats.OpenedPRs = make(issues_model.PullRequestList, 0)
|
||||||
if err = sess.Find(&stats.OpenedPRs); err != nil {
|
if err = sess.Find(&stats.OpenedPRs); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -271,7 +272,7 @@ func (stats *ActivityStats) FillIssues(repoID int64, fromTime time.Time) error {
|
||||||
// Closed issues
|
// Closed issues
|
||||||
sess := issuesForActivityStatement(repoID, fromTime, true, false)
|
sess := issuesForActivityStatement(repoID, fromTime, true, false)
|
||||||
sess.OrderBy("issue.closed_unix DESC")
|
sess.OrderBy("issue.closed_unix DESC")
|
||||||
stats.ClosedIssues = make(IssueList, 0)
|
stats.ClosedIssues = make(issues_model.IssueList, 0)
|
||||||
if err = sess.Find(&stats.ClosedIssues); err != nil {
|
if err = sess.Find(&stats.ClosedIssues); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -286,7 +287,7 @@ func (stats *ActivityStats) FillIssues(repoID int64, fromTime time.Time) error {
|
||||||
// New issues
|
// New issues
|
||||||
sess = issuesForActivityStatement(repoID, fromTime, false, false)
|
sess = issuesForActivityStatement(repoID, fromTime, false, false)
|
||||||
sess.OrderBy("issue.created_unix ASC")
|
sess.OrderBy("issue.created_unix ASC")
|
||||||
stats.OpenedIssues = make(IssueList, 0)
|
stats.OpenedIssues = make(issues_model.IssueList, 0)
|
||||||
if err = sess.Find(&stats.OpenedIssues); err != nil {
|
if err = sess.Find(&stats.OpenedIssues); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -312,7 +313,7 @@ func (stats *ActivityStats) FillUnresolvedIssues(repoID int64, fromTime time.Tim
|
||||||
sess.And("issue.is_pull = ?", prs)
|
sess.And("issue.is_pull = ?", prs)
|
||||||
}
|
}
|
||||||
sess.OrderBy("issue.updated_unix DESC")
|
sess.OrderBy("issue.updated_unix DESC")
|
||||||
stats.UnresolvedIssues = make(IssueList, 0)
|
stats.UnresolvedIssues = make(issues_model.IssueList, 0)
|
||||||
return sess.Find(&stats.UnresolvedIssues)
|
return sess.Find(&stats.UnresolvedIssues)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
"code.gitea.io/gitea/models/perm"
|
"code.gitea.io/gitea/models/perm"
|
||||||
access_model "code.gitea.io/gitea/models/perm/access"
|
access_model "code.gitea.io/gitea/models/perm/access"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
|
@ -101,7 +102,7 @@ func reconsiderRepoIssuesAssignee(ctx context.Context, repo *repo_model.Reposito
|
||||||
|
|
||||||
if _, err := db.GetEngine(ctx).Where(builder.Eq{"assignee_id": uid}).
|
if _, err := db.GetEngine(ctx).Where(builder.Eq{"assignee_id": uid}).
|
||||||
In("issue_id", builder.Select("id").From("issue").Where(builder.Eq{"repo_id": repo.ID})).
|
In("issue_id", builder.Select("id").From("issue").Where(builder.Eq{"repo_id": repo.ID})).
|
||||||
Delete(&IssueAssignees{}); err != nil {
|
Delete(&issues_model.IssueAssignees{}); err != nil {
|
||||||
return fmt.Errorf("Could not delete assignee[%d] %v", uid, err)
|
return fmt.Errorf("Could not delete assignee[%d] %v", uid, err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -116,5 +117,5 @@ func reconsiderWatches(ctx context.Context, repo *repo_model.Repository, uid int
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove all IssueWatches a user has subscribed to in the repository
|
// Remove all IssueWatches a user has subscribed to in the repository
|
||||||
return removeIssueWatchersByRepoID(ctx, uid, repo.ID)
|
return issues_model.RemoveIssueWatchersByRepoID(ctx, uid, repo.ID)
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
"code.gitea.io/gitea/models/organization"
|
"code.gitea.io/gitea/models/organization"
|
||||||
access_model "code.gitea.io/gitea/models/perm/access"
|
access_model "code.gitea.io/gitea/models/perm/access"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
|
@ -376,7 +377,7 @@ func TransferOwnership(doer *user_model.User, newOwnerName string, repo *repo_mo
|
||||||
INNER JOIN issue ON issue.id = com.issue_id
|
INNER JOIN issue ON issue.id = com.issue_id
|
||||||
WHERE
|
WHERE
|
||||||
com.type = ? AND issue.repo_id = ? AND ((label.org_id = 0 AND issue.repo_id != label.repo_id) OR (label.repo_id = 0 AND label.org_id != ?))
|
com.type = ? AND issue.repo_id = ? AND ((label.org_id = 0 AND issue.repo_id != label.repo_id) OR (label.repo_id = 0 AND label.org_id != ?))
|
||||||
) AS il_too)`, CommentTypeLabel, repo.ID, newOwner.ID); err != nil {
|
) AS il_too)`, issues_model.CommentTypeLabel, repo.ID, newOwner.ID); err != nil {
|
||||||
return fmt.Errorf("Unable to remove old org label comments: %v", err)
|
return fmt.Errorf("Unable to remove old org label comments: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,7 +97,7 @@ func GetStatistic() (stats Statistic) {
|
||||||
|
|
||||||
stats.Counter.Issue = stats.Counter.IssueClosed + stats.Counter.IssueOpen
|
stats.Counter.Issue = stats.Counter.IssueClosed + stats.Counter.IssueOpen
|
||||||
|
|
||||||
stats.Counter.Comment, _ = e.Count(new(Comment))
|
stats.Counter.Comment, _ = e.Count(new(issues_model.Comment))
|
||||||
stats.Counter.Oauth = 0
|
stats.Counter.Oauth = 0
|
||||||
stats.Counter.Follow, _ = e.Count(new(user_model.Follow))
|
stats.Counter.Follow, _ = e.Count(new(user_model.Follow))
|
||||||
stats.Counter.Mirror, _ = e.Count(new(repo_model.Mirror))
|
stats.Counter.Mirror, _ = e.Count(new(repo_model.Mirror))
|
||||||
|
@ -105,7 +105,7 @@ func GetStatistic() (stats Statistic) {
|
||||||
stats.Counter.AuthSource = auth.CountSources()
|
stats.Counter.AuthSource = auth.CountSources()
|
||||||
stats.Counter.Webhook, _ = e.Count(new(webhook.Webhook))
|
stats.Counter.Webhook, _ = e.Count(new(webhook.Webhook))
|
||||||
stats.Counter.Milestone, _ = e.Count(new(issues_model.Milestone))
|
stats.Counter.Milestone, _ = e.Count(new(issues_model.Milestone))
|
||||||
stats.Counter.Label, _ = e.Count(new(Label))
|
stats.Counter.Label, _ = e.Count(new(issues_model.Label))
|
||||||
stats.Counter.HookTask, _ = e.Count(new(webhook.HookTask))
|
stats.Counter.HookTask, _ = e.Count(new(webhook.HookTask))
|
||||||
stats.Counter.Team, _ = e.Count(new(organization.Team))
|
stats.Counter.Team, _ = e.Count(new(organization.Team))
|
||||||
stats.Counter.Attachment, _ = e.Count(new(repo_model.Attachment))
|
stats.Counter.Attachment, _ = e.Count(new(repo_model.Attachment))
|
||||||
|
|
|
@ -16,7 +16,7 @@ import (
|
||||||
auth_model "code.gitea.io/gitea/models/auth"
|
auth_model "code.gitea.io/gitea/models/auth"
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
git_model "code.gitea.io/gitea/models/git"
|
git_model "code.gitea.io/gitea/models/git"
|
||||||
"code.gitea.io/gitea/models/issues"
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
"code.gitea.io/gitea/models/organization"
|
"code.gitea.io/gitea/models/organization"
|
||||||
access_model "code.gitea.io/gitea/models/perm/access"
|
access_model "code.gitea.io/gitea/models/perm/access"
|
||||||
pull_model "code.gitea.io/gitea/models/pull"
|
pull_model "code.gitea.io/gitea/models/pull"
|
||||||
|
@ -78,12 +78,12 @@ func DeleteUser(ctx context.Context, u *user_model.User) (err error) {
|
||||||
&user_model.Follow{UserID: u.ID},
|
&user_model.Follow{UserID: u.ID},
|
||||||
&user_model.Follow{FollowID: u.ID},
|
&user_model.Follow{FollowID: u.ID},
|
||||||
&Action{UserID: u.ID},
|
&Action{UserID: u.ID},
|
||||||
&IssueUser{UID: u.ID},
|
&issues_model.IssueUser{UID: u.ID},
|
||||||
&user_model.EmailAddress{UID: u.ID},
|
&user_model.EmailAddress{UID: u.ID},
|
||||||
&user_model.UserOpenID{UID: u.ID},
|
&user_model.UserOpenID{UID: u.ID},
|
||||||
&issues.Reaction{UserID: u.ID},
|
&issues_model.Reaction{UserID: u.ID},
|
||||||
&organization.TeamUser{UID: u.ID},
|
&organization.TeamUser{UID: u.ID},
|
||||||
&Stopwatch{UserID: u.ID},
|
&issues_model.Stopwatch{UserID: u.ID},
|
||||||
&user_model.Setting{UserID: u.ID},
|
&user_model.Setting{UserID: u.ID},
|
||||||
&pull_model.AutoMerge{DoerID: u.ID},
|
&pull_model.AutoMerge{DoerID: u.ID},
|
||||||
&pull_model.ReviewState{UserID: u.ID},
|
&pull_model.ReviewState{UserID: u.ID},
|
||||||
|
@ -101,8 +101,8 @@ func DeleteUser(ctx context.Context, u *user_model.User) (err error) {
|
||||||
// Delete Comments
|
// Delete Comments
|
||||||
const batchSize = 50
|
const batchSize = 50
|
||||||
for start := 0; ; start += batchSize {
|
for start := 0; ; start += batchSize {
|
||||||
comments := make([]*Comment, 0, batchSize)
|
comments := make([]*issues_model.Comment, 0, batchSize)
|
||||||
if err = e.Where("type=? AND poster_id=?", CommentTypeComment, u.ID).Limit(batchSize, start).Find(&comments); err != nil {
|
if err = e.Where("type=? AND poster_id=?", issues_model.CommentTypeComment, u.ID).Limit(batchSize, start).Find(&comments); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if len(comments) == 0 {
|
if len(comments) == 0 {
|
||||||
|
@ -110,14 +110,14 @@ func DeleteUser(ctx context.Context, u *user_model.User) (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, comment := range comments {
|
for _, comment := range comments {
|
||||||
if err = deleteComment(ctx, comment); err != nil {
|
if err = issues_model.DeleteComment(ctx, comment); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete Reactions
|
// Delete Reactions
|
||||||
if err = issues.DeleteReaction(ctx, &issues.ReactionOptions{DoerID: u.ID}); err != nil {
|
if err = issues_model.DeleteReaction(ctx, &issues_model.ReactionOptions{DoerID: u.ID}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -189,7 +189,7 @@ func DeleteUser(ctx context.Context, u *user_model.User) (err error) {
|
||||||
// ***** END: GPGPublicKey *****
|
// ***** END: GPGPublicKey *****
|
||||||
|
|
||||||
// Clear assignee.
|
// Clear assignee.
|
||||||
if _, err = db.DeleteByBean(ctx, &IssueAssignees{AssigneeID: u.ID}); err != nil {
|
if _, err = db.DeleteByBean(ctx, &issues_model.IssueAssignees{AssigneeID: u.ID}); err != nil {
|
||||||
return fmt.Errorf("clear assignee: %v", err)
|
return fmt.Errorf("clear assignee: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@ import (
|
||||||
"code.gitea.io/gitea/models"
|
"code.gitea.io/gitea/models"
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
git_model "code.gitea.io/gitea/models/git"
|
git_model "code.gitea.io/gitea/models/git"
|
||||||
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
access_model "code.gitea.io/gitea/models/perm/access"
|
access_model "code.gitea.io/gitea/models/perm/access"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
unit_model "code.gitea.io/gitea/models/unit"
|
unit_model "code.gitea.io/gitea/models/unit"
|
||||||
|
@ -83,7 +84,7 @@ type Repository struct {
|
||||||
|
|
||||||
// CanWriteToBranch checks if the branch is writable by the user
|
// CanWriteToBranch checks if the branch is writable by the user
|
||||||
func (r *Repository) CanWriteToBranch(user *user_model.User, branch string) bool {
|
func (r *Repository) CanWriteToBranch(user *user_model.User, branch string) bool {
|
||||||
return models.CanMaintainerWriteToBranch(r.Permission, branch, user)
|
return issues_model.CanMaintainerWriteToBranch(r.Permission, branch, user)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CanEnableEditor returns true if repository is editable and user has proper access level.
|
// CanEnableEditor returns true if repository is editable and user has proper access level.
|
||||||
|
@ -158,11 +159,11 @@ func (r *Repository) CanCommitToBranch(ctx context.Context, doer *user_model.Use
|
||||||
}
|
}
|
||||||
|
|
||||||
// CanUseTimetracker returns whether or not a user can use the timetracker.
|
// CanUseTimetracker returns whether or not a user can use the timetracker.
|
||||||
func (r *Repository) CanUseTimetracker(issue *models.Issue, user *user_model.User) bool {
|
func (r *Repository) CanUseTimetracker(issue *issues_model.Issue, user *user_model.User) bool {
|
||||||
// Checking for following:
|
// Checking for following:
|
||||||
// 1. Is timetracker enabled
|
// 1. Is timetracker enabled
|
||||||
// 2. Is the user a contributor, admin, poster or assignee and do the repository policies require this?
|
// 2. Is the user a contributor, admin, poster or assignee and do the repository policies require this?
|
||||||
isAssigned, _ := models.IsUserAssignedToIssue(db.DefaultContext, issue, user)
|
isAssigned, _ := issues_model.IsUserAssignedToIssue(db.DefaultContext, issue, user)
|
||||||
return r.Repository.IsTimetrackerEnabled() && (!r.Repository.AllowOnlyContributorsToTrackTime() ||
|
return r.Repository.IsTimetrackerEnabled() && (!r.Repository.AllowOnlyContributorsToTrackTime() ||
|
||||||
r.Permission.CanWriteIssuesOrPulls(issue.IsPull) || issue.IsPoster(user.ID) || isAssigned)
|
r.Permission.CanWriteIssuesOrPulls(issue.IsPull) || issue.IsPoster(user.ID) || isAssigned)
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,11 +11,11 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
|
||||||
asymkey_model "code.gitea.io/gitea/models/asymkey"
|
asymkey_model "code.gitea.io/gitea/models/asymkey"
|
||||||
"code.gitea.io/gitea/models/auth"
|
"code.gitea.io/gitea/models/auth"
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
git_model "code.gitea.io/gitea/models/git"
|
git_model "code.gitea.io/gitea/models/git"
|
||||||
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
"code.gitea.io/gitea/models/organization"
|
"code.gitea.io/gitea/models/organization"
|
||||||
"code.gitea.io/gitea/models/perm"
|
"code.gitea.io/gitea/models/perm"
|
||||||
access_model "code.gitea.io/gitea/models/perm/access"
|
access_model "code.gitea.io/gitea/models/perm/access"
|
||||||
|
@ -55,7 +55,7 @@ func ToBranch(repo *repo_model.Repository, b *git.Branch, c *git.Commit, bp *git
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
canPush = models.CanMaintainerWriteToBranch(perms, b.Name, user)
|
canPush = issues_model.CanMaintainerWriteToBranch(perms, b.Name, user)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &api.Branch{
|
return &api.Branch{
|
||||||
|
|
|
@ -9,7 +9,6 @@ import (
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
issues_model "code.gitea.io/gitea/models/issues"
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
|
@ -23,7 +22,7 @@ import (
|
||||||
// it assumes some fields assigned with values:
|
// it assumes some fields assigned with values:
|
||||||
// Required - Poster, Labels,
|
// Required - Poster, Labels,
|
||||||
// Optional - Milestone, Assignee, PullRequest
|
// Optional - Milestone, Assignee, PullRequest
|
||||||
func ToAPIIssue(issue *models.Issue) *api.Issue {
|
func ToAPIIssue(issue *issues_model.Issue) *api.Issue {
|
||||||
if err := issue.LoadLabels(db.DefaultContext); err != nil {
|
if err := issue.LoadLabels(db.DefaultContext); err != nil {
|
||||||
return &api.Issue{}
|
return &api.Issue{}
|
||||||
}
|
}
|
||||||
|
@ -100,7 +99,7 @@ func ToAPIIssue(issue *models.Issue) *api.Issue {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToAPIIssueList converts an IssueList to API format
|
// ToAPIIssueList converts an IssueList to API format
|
||||||
func ToAPIIssueList(il models.IssueList) []*api.Issue {
|
func ToAPIIssueList(il issues_model.IssueList) []*api.Issue {
|
||||||
result := make([]*api.Issue, len(il))
|
result := make([]*api.Issue, len(il))
|
||||||
for i := range il {
|
for i := range il {
|
||||||
result[i] = ToAPIIssue(il[i])
|
result[i] = ToAPIIssue(il[i])
|
||||||
|
@ -109,7 +108,7 @@ func ToAPIIssueList(il models.IssueList) []*api.Issue {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToTrackedTime converts TrackedTime to API format
|
// ToTrackedTime converts TrackedTime to API format
|
||||||
func ToTrackedTime(t *models.TrackedTime) (apiT *api.TrackedTime) {
|
func ToTrackedTime(t *issues_model.TrackedTime) (apiT *api.TrackedTime) {
|
||||||
apiT = &api.TrackedTime{
|
apiT = &api.TrackedTime{
|
||||||
ID: t.ID,
|
ID: t.ID,
|
||||||
IssueID: t.IssueID,
|
IssueID: t.IssueID,
|
||||||
|
@ -128,13 +127,13 @@ func ToTrackedTime(t *models.TrackedTime) (apiT *api.TrackedTime) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToStopWatches convert Stopwatch list to api.StopWatches
|
// ToStopWatches convert Stopwatch list to api.StopWatches
|
||||||
func ToStopWatches(sws []*models.Stopwatch) (api.StopWatches, error) {
|
func ToStopWatches(sws []*issues_model.Stopwatch) (api.StopWatches, error) {
|
||||||
result := api.StopWatches(make([]api.StopWatch, 0, len(sws)))
|
result := api.StopWatches(make([]api.StopWatch, 0, len(sws)))
|
||||||
|
|
||||||
issueCache := make(map[int64]*models.Issue)
|
issueCache := make(map[int64]*issues_model.Issue)
|
||||||
repoCache := make(map[int64]*repo_model.Repository)
|
repoCache := make(map[int64]*repo_model.Repository)
|
||||||
var (
|
var (
|
||||||
issue *models.Issue
|
issue *issues_model.Issue
|
||||||
repo *repo_model.Repository
|
repo *repo_model.Repository
|
||||||
ok bool
|
ok bool
|
||||||
err error
|
err error
|
||||||
|
@ -143,7 +142,7 @@ func ToStopWatches(sws []*models.Stopwatch) (api.StopWatches, error) {
|
||||||
for _, sw := range sws {
|
for _, sw := range sws {
|
||||||
issue, ok = issueCache[sw.IssueID]
|
issue, ok = issueCache[sw.IssueID]
|
||||||
if !ok {
|
if !ok {
|
||||||
issue, err = models.GetIssueByID(sw.IssueID)
|
issue, err = issues_model.GetIssueByID(db.DefaultContext, sw.IssueID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -170,7 +169,7 @@ func ToStopWatches(sws []*models.Stopwatch) (api.StopWatches, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToTrackedTimeList converts TrackedTimeList to API format
|
// ToTrackedTimeList converts TrackedTimeList to API format
|
||||||
func ToTrackedTimeList(tl models.TrackedTimeList) api.TrackedTimeList {
|
func ToTrackedTimeList(tl issues_model.TrackedTimeList) api.TrackedTimeList {
|
||||||
result := make([]*api.TrackedTime, 0, len(tl))
|
result := make([]*api.TrackedTime, 0, len(tl))
|
||||||
for _, t := range tl {
|
for _, t := range tl {
|
||||||
result = append(result, ToTrackedTime(t))
|
result = append(result, ToTrackedTime(t))
|
||||||
|
@ -179,7 +178,7 @@ func ToTrackedTimeList(tl models.TrackedTimeList) api.TrackedTimeList {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToLabel converts Label to API format
|
// ToLabel converts Label to API format
|
||||||
func ToLabel(label *models.Label, repo *repo_model.Repository, org *user_model.User) *api.Label {
|
func ToLabel(label *issues_model.Label, repo *repo_model.Repository, org *user_model.User) *api.Label {
|
||||||
result := &api.Label{
|
result := &api.Label{
|
||||||
ID: label.ID,
|
ID: label.ID,
|
||||||
Name: label.Name,
|
Name: label.Name,
|
||||||
|
@ -206,7 +205,7 @@ func ToLabel(label *models.Label, repo *repo_model.Repository, org *user_model.U
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToLabelList converts list of Label to API format
|
// ToLabelList converts list of Label to API format
|
||||||
func ToLabelList(labels []*models.Label, repo *repo_model.Repository, org *user_model.User) []*api.Label {
|
func ToLabelList(labels []*issues_model.Label, repo *repo_model.Repository, org *user_model.User) []*api.Label {
|
||||||
result := make([]*api.Label, len(labels))
|
result := make([]*api.Label, len(labels))
|
||||||
for i := range labels {
|
for i := range labels {
|
||||||
result[i] = ToLabel(labels[i], repo, org)
|
result[i] = ToLabel(labels[i], repo, org)
|
||||||
|
|
|
@ -5,16 +5,16 @@
|
||||||
package convert
|
package convert
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"code.gitea.io/gitea/models"
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ToComment converts a models.Comment to the api.Comment format
|
// ToComment converts a issues_model.Comment to the api.Comment format
|
||||||
func ToComment(c *models.Comment) *api.Comment {
|
func ToComment(c *issues_model.Comment) *api.Comment {
|
||||||
return &api.Comment{
|
return &api.Comment{
|
||||||
ID: c.ID,
|
ID: c.ID,
|
||||||
Poster: ToUser(c.Poster, nil),
|
Poster: ToUser(c.Poster, nil),
|
||||||
|
@ -27,8 +27,8 @@ func ToComment(c *models.Comment) *api.Comment {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToTimelineComment converts a models.Comment to the api.TimelineComment format
|
// ToTimelineComment converts a issues_model.Comment to the api.TimelineComment format
|
||||||
func ToTimelineComment(c *models.Comment, doer *user_model.User) *api.TimelineComment {
|
func ToTimelineComment(c *issues_model.Comment, doer *user_model.User) *api.TimelineComment {
|
||||||
err := c.LoadMilestone()
|
err := c.LoadMilestone()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("LoadMilestone: %v", err)
|
log.Error("LoadMilestone: %v", err)
|
||||||
|
@ -105,7 +105,7 @@ func ToTimelineComment(c *models.Comment, doer *user_model.User) *api.TimelineCo
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.RefIssueID != 0 {
|
if c.RefIssueID != 0 {
|
||||||
issue, err := models.GetIssueByID(c.RefIssueID)
|
issue, err := issues_model.GetIssueByID(db.DefaultContext, c.RefIssueID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("GetIssueByID(%d): %v", c.RefIssueID, err)
|
log.Error("GetIssueByID(%d): %v", c.RefIssueID, err)
|
||||||
return nil
|
return nil
|
||||||
|
@ -114,7 +114,7 @@ func ToTimelineComment(c *models.Comment, doer *user_model.User) *api.TimelineCo
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.RefCommentID != 0 {
|
if c.RefCommentID != 0 {
|
||||||
com, err := models.GetCommentByID(db.DefaultContext, c.RefCommentID)
|
com, err := issues_model.GetCommentByID(db.DefaultContext, c.RefCommentID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("GetCommentByID(%d): %v", c.RefCommentID, err)
|
log.Error("GetCommentByID(%d): %v", c.RefCommentID, err)
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -9,7 +9,6 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
|
||||||
issues_model "code.gitea.io/gitea/models/issues"
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
|
@ -22,7 +21,7 @@ import (
|
||||||
|
|
||||||
func TestLabel_ToLabel(t *testing.T) {
|
func TestLabel_ToLabel(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
label := unittest.AssertExistsAndLoadBean(t, &models.Label{ID: 1}).(*models.Label)
|
label := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 1}).(*issues_model.Label)
|
||||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: label.RepoID}).(*repo_model.Repository)
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: label.RepoID}).(*repo_model.Repository)
|
||||||
assert.Equal(t, &api.Label{
|
assert.Equal(t, &api.Label{
|
||||||
ID: label.ID,
|
ID: label.ID,
|
||||||
|
|
|
@ -8,7 +8,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
"code.gitea.io/gitea/models/perm"
|
"code.gitea.io/gitea/models/perm"
|
||||||
access_model "code.gitea.io/gitea/models/perm/access"
|
access_model "code.gitea.io/gitea/models/perm/access"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
@ -20,7 +20,7 @@ import (
|
||||||
// ToAPIPullRequest assumes following fields have been assigned with valid values:
|
// ToAPIPullRequest assumes following fields have been assigned with valid values:
|
||||||
// Required - Issue
|
// Required - Issue
|
||||||
// Optional - Merger
|
// Optional - Merger
|
||||||
func ToAPIPullRequest(ctx context.Context, pr *models.PullRequest, doer *user_model.User) *api.PullRequest {
|
func ToAPIPullRequest(ctx context.Context, pr *issues_model.PullRequest, doer *user_model.User) *api.PullRequest {
|
||||||
var (
|
var (
|
||||||
baseBranch *git.Branch
|
baseBranch *git.Branch
|
||||||
headBranch *git.Branch
|
headBranch *git.Branch
|
||||||
|
@ -114,7 +114,7 @@ func ToAPIPullRequest(ctx context.Context, pr *models.PullRequest, doer *user_mo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if pr.Flow == models.PullRequestFlowAGit {
|
if pr.Flow == issues_model.PullRequestFlowAGit {
|
||||||
gitRepo, err := git.OpenRepository(ctx, pr.BaseRepo.RepoPath())
|
gitRepo, err := git.OpenRepository(ctx, pr.BaseRepo.RepoPath())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("OpenRepository[%s]: %v", pr.GetGitRefName(), err)
|
log.Error("OpenRepository[%s]: %v", pr.GetGitRefName(), err)
|
||||||
|
@ -132,7 +132,7 @@ func ToAPIPullRequest(ctx context.Context, pr *models.PullRequest, doer *user_mo
|
||||||
apiPullRequest.Head.Name = ""
|
apiPullRequest.Head.Name = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
if pr.HeadRepo != nil && pr.Flow == models.PullRequestFlowGithub {
|
if pr.HeadRepo != nil && pr.Flow == issues_model.PullRequestFlowGithub {
|
||||||
p, err := access_model.GetUserRepoPermission(ctx, pr.HeadRepo, doer)
|
p, err := access_model.GetUserRepoPermission(ctx, pr.HeadRepo, doer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("GetUserRepoPermission[%d]: %v", pr.HeadRepoID, err)
|
log.Error("GetUserRepoPermission[%d]: %v", pr.HeadRepoID, err)
|
||||||
|
|
|
@ -8,13 +8,13 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ToPullReview convert a review to api format
|
// ToPullReview convert a review to api format
|
||||||
func ToPullReview(ctx context.Context, r *models.Review, doer *user_model.User) (*api.PullReview, error) {
|
func ToPullReview(ctx context.Context, r *issues_model.Review, doer *user_model.User) (*api.PullReview, error) {
|
||||||
if err := r.LoadAttributes(ctx); err != nil {
|
if err := r.LoadAttributes(ctx); err != nil {
|
||||||
if !user_model.IsErrUserNotExist(err) {
|
if !user_model.IsErrUserNotExist(err) {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -44,15 +44,15 @@ func ToPullReview(ctx context.Context, r *models.Review, doer *user_model.User)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch r.Type {
|
switch r.Type {
|
||||||
case models.ReviewTypeApprove:
|
case issues_model.ReviewTypeApprove:
|
||||||
result.State = api.ReviewStateApproved
|
result.State = api.ReviewStateApproved
|
||||||
case models.ReviewTypeReject:
|
case issues_model.ReviewTypeReject:
|
||||||
result.State = api.ReviewStateRequestChanges
|
result.State = api.ReviewStateRequestChanges
|
||||||
case models.ReviewTypeComment:
|
case issues_model.ReviewTypeComment:
|
||||||
result.State = api.ReviewStateComment
|
result.State = api.ReviewStateComment
|
||||||
case models.ReviewTypePending:
|
case issues_model.ReviewTypePending:
|
||||||
result.State = api.ReviewStatePending
|
result.State = api.ReviewStatePending
|
||||||
case models.ReviewTypeRequest:
|
case issues_model.ReviewTypeRequest:
|
||||||
result.State = api.ReviewStateRequestReview
|
result.State = api.ReviewStateRequestReview
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,11 +60,11 @@ func ToPullReview(ctx context.Context, r *models.Review, doer *user_model.User)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToPullReviewList convert a list of review to it's api format
|
// ToPullReviewList convert a list of review to it's api format
|
||||||
func ToPullReviewList(ctx context.Context, rl []*models.Review, doer *user_model.User) ([]*api.PullReview, error) {
|
func ToPullReviewList(ctx context.Context, rl []*issues_model.Review, doer *user_model.User) ([]*api.PullReview, error) {
|
||||||
result := make([]*api.PullReview, 0, len(rl))
|
result := make([]*api.PullReview, 0, len(rl))
|
||||||
for i := range rl {
|
for i := range rl {
|
||||||
// show pending reviews only for the user who created them
|
// show pending reviews only for the user who created them
|
||||||
if rl[i].Type == models.ReviewTypePending && !(doer.IsAdmin || doer.ID == rl[i].ReviewerID) {
|
if rl[i].Type == issues_model.ReviewTypePending && !(doer.IsAdmin || doer.ID == rl[i].ReviewerID) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
r, err := ToPullReview(ctx, rl[i], doer)
|
r, err := ToPullReview(ctx, rl[i], doer)
|
||||||
|
@ -77,7 +77,7 @@ func ToPullReviewList(ctx context.Context, rl []*models.Review, doer *user_model
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToPullReviewCommentList convert the CodeComments of an review to it's api format
|
// ToPullReviewCommentList convert the CodeComments of an review to it's api format
|
||||||
func ToPullReviewCommentList(ctx context.Context, review *models.Review, doer *user_model.User) ([]*api.PullReviewComment, error) {
|
func ToPullReviewCommentList(ctx context.Context, review *issues_model.Review, doer *user_model.User) ([]*api.PullReviewComment, error) {
|
||||||
if err := review.LoadAttributes(ctx); err != nil {
|
if err := review.LoadAttributes(ctx); err != nil {
|
||||||
if !user_model.IsErrUserNotExist(err) {
|
if !user_model.IsErrUserNotExist(err) {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -7,7 +7,7 @@ package convert
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
"code.gitea.io/gitea/models/perm"
|
"code.gitea.io/gitea/models/perm"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
|
@ -21,7 +21,7 @@ func TestPullRequest_APIFormat(t *testing.T) {
|
||||||
// with HeadRepo
|
// with HeadRepo
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
headRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository)
|
headRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository)
|
||||||
pr := unittest.AssertExistsAndLoadBean(t, &models.PullRequest{ID: 1}).(*models.PullRequest)
|
pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 1}).(*issues_model.PullRequest)
|
||||||
assert.NoError(t, pr.LoadAttributes())
|
assert.NoError(t, pr.LoadAttributes())
|
||||||
assert.NoError(t, pr.LoadIssue())
|
assert.NoError(t, pr.LoadIssue())
|
||||||
apiPullRequest := ToAPIPullRequest(git.DefaultContext, pr, nil)
|
apiPullRequest := ToAPIPullRequest(git.DefaultContext, pr, nil)
|
||||||
|
@ -35,7 +35,7 @@ func TestPullRequest_APIFormat(t *testing.T) {
|
||||||
}, apiPullRequest.Head)
|
}, apiPullRequest.Head)
|
||||||
|
|
||||||
// withOut HeadRepo
|
// withOut HeadRepo
|
||||||
pr = unittest.AssertExistsAndLoadBean(t, &models.PullRequest{ID: 1}).(*models.PullRequest)
|
pr = unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 1}).(*issues_model.PullRequest)
|
||||||
assert.NoError(t, pr.LoadIssue())
|
assert.NoError(t, pr.LoadIssue())
|
||||||
assert.NoError(t, pr.LoadAttributes())
|
assert.NoError(t, pr.LoadAttributes())
|
||||||
// simulate fork deletion
|
// simulate fork deletion
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
"code.gitea.io/gitea/models"
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
"code.gitea.io/gitea/models/migrations"
|
"code.gitea.io/gitea/models/migrations"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
@ -64,10 +65,10 @@ func genericOrphanCheck(name, subject, refobject, joincond string) consistencyCh
|
||||||
return consistencyCheck{
|
return consistencyCheck{
|
||||||
Name: name,
|
Name: name,
|
||||||
Counter: func() (int64, error) {
|
Counter: func() (int64, error) {
|
||||||
return models.CountOrphanedObjects(subject, refobject, joincond)
|
return db.CountOrphanedObjects(subject, refobject, joincond)
|
||||||
},
|
},
|
||||||
Fixer: func() (int64, error) {
|
Fixer: func() (int64, error) {
|
||||||
err := models.DeleteOrphanedObjects(subject, refobject, joincond)
|
err := db.DeleteOrphanedObjects(subject, refobject, joincond)
|
||||||
return -1, err
|
return -1, err
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -84,20 +85,20 @@ func checkDBConsistency(ctx context.Context, logger log.Logger, autofix bool) er
|
||||||
{
|
{
|
||||||
// find labels without existing repo or org
|
// find labels without existing repo or org
|
||||||
Name: "Orphaned Labels without existing repository or organisation",
|
Name: "Orphaned Labels without existing repository or organisation",
|
||||||
Counter: models.CountOrphanedLabels,
|
Counter: issues_model.CountOrphanedLabels,
|
||||||
Fixer: asFixer(models.DeleteOrphanedLabels),
|
Fixer: asFixer(issues_model.DeleteOrphanedLabels),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// find IssueLabels without existing label
|
// find IssueLabels without existing label
|
||||||
Name: "Orphaned Issue Labels without existing label",
|
Name: "Orphaned Issue Labels without existing label",
|
||||||
Counter: models.CountOrphanedIssueLabels,
|
Counter: issues_model.CountOrphanedIssueLabels,
|
||||||
Fixer: asFixer(models.DeleteOrphanedIssueLabels),
|
Fixer: asFixer(issues_model.DeleteOrphanedIssueLabels),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// find issues without existing repository
|
// find issues without existing repository
|
||||||
Name: "Orphaned Issues without existing repository",
|
Name: "Orphaned Issues without existing repository",
|
||||||
Counter: models.CountOrphanedIssues,
|
Counter: issues_model.CountOrphanedIssues,
|
||||||
Fixer: asFixer(models.DeleteOrphanedIssues),
|
Fixer: asFixer(issues_model.DeleteOrphanedIssues),
|
||||||
},
|
},
|
||||||
// find releases without existing repository
|
// find releases without existing repository
|
||||||
genericOrphanCheck("Orphaned Releases without existing repository",
|
genericOrphanCheck("Orphaned Releases without existing repository",
|
||||||
|
@ -127,22 +128,22 @@ func checkDBConsistency(ctx context.Context, logger log.Logger, autofix bool) er
|
||||||
// find label comments with empty labels
|
// find label comments with empty labels
|
||||||
{
|
{
|
||||||
Name: "Label comments with empty labels",
|
Name: "Label comments with empty labels",
|
||||||
Counter: models.CountCommentTypeLabelWithEmptyLabel,
|
Counter: issues_model.CountCommentTypeLabelWithEmptyLabel,
|
||||||
Fixer: models.FixCommentTypeLabelWithEmptyLabel,
|
Fixer: issues_model.FixCommentTypeLabelWithEmptyLabel,
|
||||||
FixedMessage: "Fixed",
|
FixedMessage: "Fixed",
|
||||||
},
|
},
|
||||||
// find label comments with labels from outside the repository
|
// find label comments with labels from outside the repository
|
||||||
{
|
{
|
||||||
Name: "Label comments with labels from outside the repository",
|
Name: "Label comments with labels from outside the repository",
|
||||||
Counter: models.CountCommentTypeLabelWithOutsideLabels,
|
Counter: issues_model.CountCommentTypeLabelWithOutsideLabels,
|
||||||
Fixer: models.FixCommentTypeLabelWithOutsideLabels,
|
Fixer: issues_model.FixCommentTypeLabelWithOutsideLabels,
|
||||||
FixedMessage: "Removed",
|
FixedMessage: "Removed",
|
||||||
},
|
},
|
||||||
// find issue_label with labels from outside the repository
|
// find issue_label with labels from outside the repository
|
||||||
{
|
{
|
||||||
Name: "IssueLabels with Labels from outside the repository",
|
Name: "IssueLabels with Labels from outside the repository",
|
||||||
Counter: models.CountIssueLabelWithOutsideLabels,
|
Counter: issues_model.CountIssueLabelWithOutsideLabels,
|
||||||
Fixer: models.FixIssueLabelWithOutsideLabels,
|
Fixer: issues_model.FixIssueLabelWithOutsideLabels,
|
||||||
FixedMessage: "Removed",
|
FixedMessage: "Removed",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -9,8 +9,8 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
@ -18,13 +18,13 @@ import (
|
||||||
"xorm.io/builder"
|
"xorm.io/builder"
|
||||||
)
|
)
|
||||||
|
|
||||||
func iteratePRs(ctx context.Context, repo *repo_model.Repository, each func(*repo_model.Repository, *models.PullRequest) error) error {
|
func iteratePRs(ctx context.Context, repo *repo_model.Repository, each func(*repo_model.Repository, *issues_model.PullRequest) error) error {
|
||||||
return db.Iterate(
|
return db.Iterate(
|
||||||
ctx,
|
ctx,
|
||||||
new(models.PullRequest),
|
new(issues_model.PullRequest),
|
||||||
builder.Eq{"base_repo_id": repo.ID},
|
builder.Eq{"base_repo_id": repo.ID},
|
||||||
func(idx int, bean interface{}) error {
|
func(idx int, bean interface{}) error {
|
||||||
return each(repo, bean.(*models.PullRequest))
|
return each(repo, bean.(*issues_model.PullRequest))
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,7 @@ func checkPRMergeBase(ctx context.Context, logger log.Logger, autofix bool) erro
|
||||||
numPRsUpdated := 0
|
numPRsUpdated := 0
|
||||||
err := iterateRepositories(ctx, func(repo *repo_model.Repository) error {
|
err := iterateRepositories(ctx, func(repo *repo_model.Repository) error {
|
||||||
numRepos++
|
numRepos++
|
||||||
return iteratePRs(ctx, repo, func(repo *repo_model.Repository, pr *models.PullRequest) error {
|
return iteratePRs(ctx, repo, func(repo *repo_model.Repository, pr *issues_model.PullRequest) error {
|
||||||
numPRs++
|
numPRs++
|
||||||
pr.BaseRepo = repo
|
pr.BaseRepo = repo
|
||||||
repoPath := repo.RepoPath()
|
repoPath := repo.RepoPath()
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
"code.gitea.io/gitea/models"
|
||||||
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
"code.gitea.io/gitea/modules/convert"
|
"code.gitea.io/gitea/modules/convert"
|
||||||
"code.gitea.io/gitea/modules/graceful"
|
"code.gitea.io/gitea/modules/graceful"
|
||||||
"code.gitea.io/gitea/modules/json"
|
"code.gitea.io/gitea/modules/json"
|
||||||
|
@ -84,7 +85,7 @@ loop:
|
||||||
then = now
|
then = now
|
||||||
|
|
||||||
if setting.Service.EnableTimetracking {
|
if setting.Service.EnableTimetracking {
|
||||||
usersStopwatches, err := models.GetUIDsAndStopwatch()
|
usersStopwatches, err := issues_model.GetUIDsAndStopwatch()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Unable to get GetUIDsAndStopwatch: %v", err)
|
log.Error("Unable to get GetUIDsAndStopwatch: %v", err)
|
||||||
return
|
return
|
||||||
|
|
|
@ -7,8 +7,8 @@ package issues
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DBIndexer implements Indexer interface to use database's like search
|
// DBIndexer implements Indexer interface to use database's like search
|
||||||
|
@ -44,7 +44,7 @@ func (i *DBIndexer) Close() {
|
||||||
|
|
||||||
// Search dummy function
|
// Search dummy function
|
||||||
func (i *DBIndexer) Search(ctx context.Context, kw string, repoIDs []int64, limit, start int) (*SearchResult, error) {
|
func (i *DBIndexer) Search(ctx context.Context, kw string, repoIDs []int64, limit, start int) (*SearchResult, error) {
|
||||||
total, ids, err := models.SearchIssueIDsByKeyword(ctx, kw, repoIDs, limit, start)
|
total, ids, err := issues_model.SearchIssueIDsByKeyword(ctx, kw, repoIDs, limit, start)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,8 +12,8 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
"code.gitea.io/gitea/modules/graceful"
|
"code.gitea.io/gitea/modules/graceful"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
@ -320,7 +320,7 @@ func populateIssueIndexer(ctx context.Context) {
|
||||||
|
|
||||||
// UpdateRepoIndexer add/update all issues of the repositories
|
// UpdateRepoIndexer add/update all issues of the repositories
|
||||||
func UpdateRepoIndexer(repo *repo_model.Repository) {
|
func UpdateRepoIndexer(repo *repo_model.Repository) {
|
||||||
is, err := models.Issues(&models.IssuesOptions{
|
is, err := issues_model.Issues(&issues_model.IssuesOptions{
|
||||||
RepoID: repo.ID,
|
RepoID: repo.ID,
|
||||||
IsClosed: util.OptionalBoolNone,
|
IsClosed: util.OptionalBoolNone,
|
||||||
IsPull: util.OptionalBoolNone,
|
IsPull: util.OptionalBoolNone,
|
||||||
|
@ -329,7 +329,7 @@ func UpdateRepoIndexer(repo *repo_model.Repository) {
|
||||||
log.Error("Issues: %v", err)
|
log.Error("Issues: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err = models.IssueList(is).LoadDiscussComments(); err != nil {
|
if err = issues_model.IssueList(is).LoadDiscussComments(); err != nil {
|
||||||
log.Error("LoadComments: %v", err)
|
log.Error("LoadComments: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -339,10 +339,10 @@ func UpdateRepoIndexer(repo *repo_model.Repository) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateIssueIndexer add/update an issue to the issue indexer
|
// UpdateIssueIndexer add/update an issue to the issue indexer
|
||||||
func UpdateIssueIndexer(issue *models.Issue) {
|
func UpdateIssueIndexer(issue *issues_model.Issue) {
|
||||||
var comments []string
|
var comments []string
|
||||||
for _, comment := range issue.Comments {
|
for _, comment := range issue.Comments {
|
||||||
if comment.Type == models.CommentTypeComment {
|
if comment.Type == issues_model.CommentTypeComment {
|
||||||
comments = append(comments, comment.Content)
|
comments = append(comments, comment.Content)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -362,7 +362,7 @@ func UpdateIssueIndexer(issue *models.Issue) {
|
||||||
// DeleteRepoIssueIndexer deletes repo's all issues indexes
|
// DeleteRepoIssueIndexer deletes repo's all issues indexes
|
||||||
func DeleteRepoIssueIndexer(repo *repo_model.Repository) {
|
func DeleteRepoIssueIndexer(repo *repo_model.Repository) {
|
||||||
var ids []int64
|
var ids []int64
|
||||||
ids, err := models.GetIssueIDsByRepoID(db.DefaultContext, repo.ID)
|
ids, err := issues_model.GetIssueIDsByRepoID(db.DefaultContext, repo.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("getIssueIDsByRepoID failed: %v", err)
|
log.Error("getIssueIDsByRepoID failed: %v", err)
|
||||||
return
|
return
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
"code.gitea.io/gitea/models"
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/graceful"
|
"code.gitea.io/gitea/modules/graceful"
|
||||||
|
@ -33,7 +34,7 @@ func NewNotifier() base.Notifier {
|
||||||
return &actionNotifier{}
|
return &actionNotifier{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *actionNotifier) NotifyNewIssue(issue *models.Issue, mentions []*user_model.User) {
|
func (a *actionNotifier) NotifyNewIssue(issue *issues_model.Issue, mentions []*user_model.User) {
|
||||||
if err := issue.LoadPoster(); err != nil {
|
if err := issue.LoadPoster(); err != nil {
|
||||||
log.Error("issue.LoadPoster: %v", err)
|
log.Error("issue.LoadPoster: %v", err)
|
||||||
return
|
return
|
||||||
|
@ -58,7 +59,7 @@ func (a *actionNotifier) NotifyNewIssue(issue *models.Issue, mentions []*user_mo
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyIssueChangeStatus notifies close or reopen issue to notifiers
|
// NotifyIssueChangeStatus notifies close or reopen issue to notifiers
|
||||||
func (a *actionNotifier) NotifyIssueChangeStatus(doer *user_model.User, issue *models.Issue, actionComment *models.Comment, closeOrReopen bool) {
|
func (a *actionNotifier) NotifyIssueChangeStatus(doer *user_model.User, 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 := &models.Action{
|
act := &models.Action{
|
||||||
|
@ -92,7 +93,7 @@ func (a *actionNotifier) NotifyIssueChangeStatus(doer *user_model.User, issue *m
|
||||||
|
|
||||||
// NotifyCreateIssueComment notifies comment on an issue to notifiers
|
// NotifyCreateIssueComment notifies comment on an issue to notifiers
|
||||||
func (a *actionNotifier) NotifyCreateIssueComment(doer *user_model.User, repo *repo_model.Repository,
|
func (a *actionNotifier) NotifyCreateIssueComment(doer *user_model.User, repo *repo_model.Repository,
|
||||||
issue *models.Issue, comment *models.Comment, mentions []*user_model.User,
|
issue *issues_model.Issue, comment *issues_model.Comment, mentions []*user_model.User,
|
||||||
) {
|
) {
|
||||||
act := &models.Action{
|
act := &models.Action{
|
||||||
ActUserID: doer.ID,
|
ActUserID: doer.ID,
|
||||||
|
@ -126,7 +127,7 @@ func (a *actionNotifier) NotifyCreateIssueComment(doer *user_model.User, repo *r
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *actionNotifier) NotifyNewPullRequest(pull *models.PullRequest, mentions []*user_model.User) {
|
func (a *actionNotifier) NotifyNewPullRequest(pull *issues_model.PullRequest, mentions []*user_model.User) {
|
||||||
if err := pull.LoadIssue(); err != nil {
|
if err := pull.LoadIssue(); err != nil {
|
||||||
log.Error("pull.LoadIssue: %v", err)
|
log.Error("pull.LoadIssue: %v", err)
|
||||||
return
|
return
|
||||||
|
@ -207,7 +208,7 @@ func (a *actionNotifier) NotifyForkRepository(doer *user_model.User, oldRepo, re
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *actionNotifier) NotifyPullRequestReview(pr *models.PullRequest, review *models.Review, comment *models.Comment, mentions []*user_model.User) {
|
func (a *actionNotifier) NotifyPullRequestReview(pr *issues_model.PullRequest, review *issues_model.Review, comment *issues_model.Comment, mentions []*user_model.User) {
|
||||||
ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("actionNotifier.NotifyPullRequestReview Pull[%d] #%d in [%d]", pr.ID, pr.Index, pr.BaseRepoID))
|
ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("actionNotifier.NotifyPullRequestReview Pull[%d] #%d in [%d]", pr.ID, pr.Index, pr.BaseRepoID))
|
||||||
defer finished()
|
defer finished()
|
||||||
|
|
||||||
|
@ -239,7 +240,7 @@ func (a *actionNotifier) NotifyPullRequestReview(pr *models.PullRequest, review
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if review.Type != models.ReviewTypeComment || strings.TrimSpace(comment.Content) != "" {
|
if review.Type != issues_model.ReviewTypeComment || strings.TrimSpace(comment.Content) != "" {
|
||||||
action := &models.Action{
|
action := &models.Action{
|
||||||
ActUserID: review.Reviewer.ID,
|
ActUserID: review.Reviewer.ID,
|
||||||
ActUser: review.Reviewer,
|
ActUser: review.Reviewer,
|
||||||
|
@ -252,9 +253,9 @@ func (a *actionNotifier) NotifyPullRequestReview(pr *models.PullRequest, review
|
||||||
}
|
}
|
||||||
|
|
||||||
switch review.Type {
|
switch review.Type {
|
||||||
case models.ReviewTypeApprove:
|
case issues_model.ReviewTypeApprove:
|
||||||
action.OpType = models.ActionApprovePullRequest
|
action.OpType = models.ActionApprovePullRequest
|
||||||
case models.ReviewTypeReject:
|
case issues_model.ReviewTypeReject:
|
||||||
action.OpType = models.ActionRejectPullRequest
|
action.OpType = models.ActionRejectPullRequest
|
||||||
default:
|
default:
|
||||||
action.OpType = models.ActionCommentPull
|
action.OpType = models.ActionCommentPull
|
||||||
|
@ -268,7 +269,7 @@ func (a *actionNotifier) NotifyPullRequestReview(pr *models.PullRequest, review
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*actionNotifier) NotifyMergePullRequest(pr *models.PullRequest, doer *user_model.User) {
|
func (*actionNotifier) NotifyMergePullRequest(pr *issues_model.PullRequest, doer *user_model.User) {
|
||||||
if err := models.NotifyWatchers(&models.Action{
|
if err := models.NotifyWatchers(&models.Action{
|
||||||
ActUserID: doer.ID,
|
ActUserID: doer.ID,
|
||||||
ActUser: doer,
|
ActUser: doer,
|
||||||
|
@ -282,7 +283,7 @@ func (*actionNotifier) NotifyMergePullRequest(pr *models.PullRequest, doer *user
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*actionNotifier) NotifyPullRevieweDismiss(doer *user_model.User, review *models.Review, comment *models.Comment) {
|
func (*actionNotifier) NotifyPullRevieweDismiss(doer *user_model.User, review *issues_model.Review, comment *issues_model.Comment) {
|
||||||
reviewerName := review.Reviewer.Name
|
reviewerName := review.Reviewer.Name
|
||||||
if len(review.OriginalAuthor) > 0 {
|
if len(review.OriginalAuthor) > 0 {
|
||||||
reviewerName = review.OriginalAuthor
|
reviewerName = review.OriginalAuthor
|
||||||
|
|
|
@ -6,6 +6,7 @@ package base
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"code.gitea.io/gitea/models"
|
"code.gitea.io/gitea/models"
|
||||||
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
packages_model "code.gitea.io/gitea/models/packages"
|
packages_model "code.gitea.io/gitea/models/packages"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
@ -21,30 +22,30 @@ type Notifier interface {
|
||||||
NotifyForkRepository(doer *user_model.User, oldRepo, repo *repo_model.Repository)
|
NotifyForkRepository(doer *user_model.User, oldRepo, repo *repo_model.Repository)
|
||||||
NotifyRenameRepository(doer *user_model.User, repo *repo_model.Repository, oldRepoName string)
|
NotifyRenameRepository(doer *user_model.User, repo *repo_model.Repository, oldRepoName string)
|
||||||
NotifyTransferRepository(doer *user_model.User, repo *repo_model.Repository, oldOwnerName string)
|
NotifyTransferRepository(doer *user_model.User, repo *repo_model.Repository, oldOwnerName string)
|
||||||
NotifyNewIssue(issue *models.Issue, mentions []*user_model.User)
|
NotifyNewIssue(issue *issues_model.Issue, mentions []*user_model.User)
|
||||||
NotifyIssueChangeStatus(*user_model.User, *models.Issue, *models.Comment, bool)
|
NotifyIssueChangeStatus(*user_model.User, *issues_model.Issue, *issues_model.Comment, bool)
|
||||||
NotifyDeleteIssue(*user_model.User, *models.Issue)
|
NotifyDeleteIssue(*user_model.User, *issues_model.Issue)
|
||||||
NotifyIssueChangeMilestone(doer *user_model.User, issue *models.Issue, oldMilestoneID int64)
|
NotifyIssueChangeMilestone(doer *user_model.User, issue *issues_model.Issue, oldMilestoneID int64)
|
||||||
NotifyIssueChangeAssignee(doer *user_model.User, issue *models.Issue, assignee *user_model.User, removed bool, comment *models.Comment)
|
NotifyIssueChangeAssignee(doer *user_model.User, issue *issues_model.Issue, assignee *user_model.User, removed bool, comment *issues_model.Comment)
|
||||||
NotifyPullReviewRequest(doer *user_model.User, issue *models.Issue, reviewer *user_model.User, isRequest bool, comment *models.Comment)
|
NotifyPullReviewRequest(doer *user_model.User, issue *issues_model.Issue, reviewer *user_model.User, isRequest bool, comment *issues_model.Comment)
|
||||||
NotifyIssueChangeContent(doer *user_model.User, issue *models.Issue, oldContent string)
|
NotifyIssueChangeContent(doer *user_model.User, issue *issues_model.Issue, oldContent string)
|
||||||
NotifyIssueClearLabels(doer *user_model.User, issue *models.Issue)
|
NotifyIssueClearLabels(doer *user_model.User, issue *issues_model.Issue)
|
||||||
NotifyIssueChangeTitle(doer *user_model.User, issue *models.Issue, oldTitle string)
|
NotifyIssueChangeTitle(doer *user_model.User, issue *issues_model.Issue, oldTitle string)
|
||||||
NotifyIssueChangeRef(doer *user_model.User, issue *models.Issue, oldRef string)
|
NotifyIssueChangeRef(doer *user_model.User, issue *issues_model.Issue, oldRef string)
|
||||||
NotifyIssueChangeLabels(doer *user_model.User, issue *models.Issue,
|
NotifyIssueChangeLabels(doer *user_model.User, issue *issues_model.Issue,
|
||||||
addedLabels, removedLabels []*models.Label)
|
addedLabels, removedLabels []*issues_model.Label)
|
||||||
NotifyNewPullRequest(pr *models.PullRequest, mentions []*user_model.User)
|
NotifyNewPullRequest(pr *issues_model.PullRequest, mentions []*user_model.User)
|
||||||
NotifyMergePullRequest(*models.PullRequest, *user_model.User)
|
NotifyMergePullRequest(*issues_model.PullRequest, *user_model.User)
|
||||||
NotifyPullRequestSynchronized(doer *user_model.User, pr *models.PullRequest)
|
NotifyPullRequestSynchronized(doer *user_model.User, pr *issues_model.PullRequest)
|
||||||
NotifyPullRequestReview(pr *models.PullRequest, review *models.Review, comment *models.Comment, mentions []*user_model.User)
|
NotifyPullRequestReview(pr *issues_model.PullRequest, review *issues_model.Review, comment *issues_model.Comment, mentions []*user_model.User)
|
||||||
NotifyPullRequestCodeComment(pr *models.PullRequest, comment *models.Comment, mentions []*user_model.User)
|
NotifyPullRequestCodeComment(pr *issues_model.PullRequest, comment *issues_model.Comment, mentions []*user_model.User)
|
||||||
NotifyPullRequestChangeTargetBranch(doer *user_model.User, pr *models.PullRequest, oldBranch string)
|
NotifyPullRequestChangeTargetBranch(doer *user_model.User, pr *issues_model.PullRequest, oldBranch string)
|
||||||
NotifyPullRequestPushCommits(doer *user_model.User, pr *models.PullRequest, comment *models.Comment)
|
NotifyPullRequestPushCommits(doer *user_model.User, pr *issues_model.PullRequest, comment *issues_model.Comment)
|
||||||
NotifyPullRevieweDismiss(doer *user_model.User, review *models.Review, comment *models.Comment)
|
NotifyPullRevieweDismiss(doer *user_model.User, review *issues_model.Review, comment *issues_model.Comment)
|
||||||
NotifyCreateIssueComment(doer *user_model.User, repo *repo_model.Repository,
|
NotifyCreateIssueComment(doer *user_model.User, repo *repo_model.Repository,
|
||||||
issue *models.Issue, comment *models.Comment, mentions []*user_model.User)
|
issue *issues_model.Issue, comment *issues_model.Comment, mentions []*user_model.User)
|
||||||
NotifyUpdateComment(*user_model.User, *models.Comment, string)
|
NotifyUpdateComment(*user_model.User, *issues_model.Comment, string)
|
||||||
NotifyDeleteComment(*user_model.User, *models.Comment)
|
NotifyDeleteComment(*user_model.User, *issues_model.Comment)
|
||||||
NotifyNewRelease(rel *models.Release)
|
NotifyNewRelease(rel *models.Release)
|
||||||
NotifyUpdateRelease(doer *user_model.User, rel *models.Release)
|
NotifyUpdateRelease(doer *user_model.User, rel *models.Release)
|
||||||
NotifyDeleteRelease(doer *user_model.User, rel *models.Release)
|
NotifyDeleteRelease(doer *user_model.User, rel *models.Release)
|
||||||
|
|
|
@ -6,6 +6,7 @@ package base
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"code.gitea.io/gitea/models"
|
"code.gitea.io/gitea/models"
|
||||||
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
packages_model "code.gitea.io/gitea/models/packages"
|
packages_model "code.gitea.io/gitea/models/packages"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
@ -23,59 +24,59 @@ func (*NullNotifier) Run() {
|
||||||
|
|
||||||
// NotifyCreateIssueComment places a place holder function
|
// NotifyCreateIssueComment places a place holder function
|
||||||
func (*NullNotifier) NotifyCreateIssueComment(doer *user_model.User, repo *repo_model.Repository,
|
func (*NullNotifier) NotifyCreateIssueComment(doer *user_model.User, repo *repo_model.Repository,
|
||||||
issue *models.Issue, comment *models.Comment, mentions []*user_model.User) {
|
issue *issues_model.Issue, comment *issues_model.Comment, mentions []*user_model.User) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyNewIssue places a place holder function
|
// NotifyNewIssue places a place holder function
|
||||||
func (*NullNotifier) NotifyNewIssue(issue *models.Issue, mentions []*user_model.User) {
|
func (*NullNotifier) NotifyNewIssue(issue *issues_model.Issue, mentions []*user_model.User) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyIssueChangeStatus places a place holder function
|
// NotifyIssueChangeStatus places a place holder function
|
||||||
func (*NullNotifier) NotifyIssueChangeStatus(doer *user_model.User, issue *models.Issue, actionComment *models.Comment, isClosed bool) {
|
func (*NullNotifier) NotifyIssueChangeStatus(doer *user_model.User, issue *issues_model.Issue, actionComment *issues_model.Comment, isClosed bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyDeleteIssue notify when some issue deleted
|
// NotifyDeleteIssue notify when some issue deleted
|
||||||
func (*NullNotifier) NotifyDeleteIssue(doer *user_model.User, issue *models.Issue) {
|
func (*NullNotifier) NotifyDeleteIssue(doer *user_model.User, issue *issues_model.Issue) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyNewPullRequest places a place holder function
|
// NotifyNewPullRequest places a place holder function
|
||||||
func (*NullNotifier) NotifyNewPullRequest(pr *models.PullRequest, mentions []*user_model.User) {
|
func (*NullNotifier) NotifyNewPullRequest(pr *issues_model.PullRequest, mentions []*user_model.User) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyPullRequestReview places a place holder function
|
// NotifyPullRequestReview places a place holder function
|
||||||
func (*NullNotifier) NotifyPullRequestReview(pr *models.PullRequest, r *models.Review, comment *models.Comment, mentions []*user_model.User) {
|
func (*NullNotifier) NotifyPullRequestReview(pr *issues_model.PullRequest, r *issues_model.Review, comment *issues_model.Comment, mentions []*user_model.User) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyPullRequestCodeComment places a place holder function
|
// NotifyPullRequestCodeComment places a place holder function
|
||||||
func (*NullNotifier) NotifyPullRequestCodeComment(pr *models.PullRequest, comment *models.Comment, mentions []*user_model.User) {
|
func (*NullNotifier) NotifyPullRequestCodeComment(pr *issues_model.PullRequest, comment *issues_model.Comment, mentions []*user_model.User) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyMergePullRequest places a place holder function
|
// NotifyMergePullRequest places a place holder function
|
||||||
func (*NullNotifier) NotifyMergePullRequest(pr *models.PullRequest, doer *user_model.User) {
|
func (*NullNotifier) NotifyMergePullRequest(pr *issues_model.PullRequest, doer *user_model.User) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyPullRequestSynchronized places a place holder function
|
// NotifyPullRequestSynchronized places a place holder function
|
||||||
func (*NullNotifier) NotifyPullRequestSynchronized(doer *user_model.User, pr *models.PullRequest) {
|
func (*NullNotifier) NotifyPullRequestSynchronized(doer *user_model.User, pr *issues_model.PullRequest) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyPullRequestChangeTargetBranch places a place holder function
|
// NotifyPullRequestChangeTargetBranch places a place holder function
|
||||||
func (*NullNotifier) NotifyPullRequestChangeTargetBranch(doer *user_model.User, pr *models.PullRequest, oldBranch string) {
|
func (*NullNotifier) NotifyPullRequestChangeTargetBranch(doer *user_model.User, pr *issues_model.PullRequest, oldBranch string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyPullRequestPushCommits notifies when push commits to pull request's head branch
|
// NotifyPullRequestPushCommits notifies when push commits to pull request's head branch
|
||||||
func (*NullNotifier) NotifyPullRequestPushCommits(doer *user_model.User, pr *models.PullRequest, comment *models.Comment) {
|
func (*NullNotifier) NotifyPullRequestPushCommits(doer *user_model.User, pr *issues_model.PullRequest, comment *issues_model.Comment) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyPullRevieweDismiss notifies when a review was dismissed by repo admin
|
// NotifyPullRevieweDismiss notifies when a review was dismissed by repo admin
|
||||||
func (*NullNotifier) NotifyPullRevieweDismiss(doer *user_model.User, review *models.Review, comment *models.Comment) {
|
func (*NullNotifier) NotifyPullRevieweDismiss(doer *user_model.User, review *issues_model.Review, comment *issues_model.Comment) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyUpdateComment places a place holder function
|
// NotifyUpdateComment places a place holder function
|
||||||
func (*NullNotifier) NotifyUpdateComment(doer *user_model.User, c *models.Comment, oldContent string) {
|
func (*NullNotifier) NotifyUpdateComment(doer *user_model.User, c *issues_model.Comment, oldContent string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyDeleteComment places a place holder function
|
// NotifyDeleteComment places a place holder function
|
||||||
func (*NullNotifier) NotifyDeleteComment(doer *user_model.User, c *models.Comment) {
|
func (*NullNotifier) NotifyDeleteComment(doer *user_model.User, c *issues_model.Comment) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyNewRelease places a place holder function
|
// NotifyNewRelease places a place holder function
|
||||||
|
@ -91,36 +92,36 @@ func (*NullNotifier) NotifyDeleteRelease(doer *user_model.User, rel *models.Rele
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyIssueChangeMilestone places a place holder function
|
// NotifyIssueChangeMilestone places a place holder function
|
||||||
func (*NullNotifier) NotifyIssueChangeMilestone(doer *user_model.User, issue *models.Issue, oldMilestoneID int64) {
|
func (*NullNotifier) NotifyIssueChangeMilestone(doer *user_model.User, issue *issues_model.Issue, oldMilestoneID int64) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyIssueChangeContent places a place holder function
|
// NotifyIssueChangeContent places a place holder function
|
||||||
func (*NullNotifier) NotifyIssueChangeContent(doer *user_model.User, issue *models.Issue, oldContent string) {
|
func (*NullNotifier) NotifyIssueChangeContent(doer *user_model.User, issue *issues_model.Issue, oldContent string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyIssueChangeAssignee places a place holder function
|
// NotifyIssueChangeAssignee places a place holder function
|
||||||
func (*NullNotifier) NotifyIssueChangeAssignee(doer *user_model.User, issue *models.Issue, assignee *user_model.User, removed bool, comment *models.Comment) {
|
func (*NullNotifier) NotifyIssueChangeAssignee(doer *user_model.User, issue *issues_model.Issue, assignee *user_model.User, removed bool, comment *issues_model.Comment) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyPullReviewRequest places a place holder function
|
// NotifyPullReviewRequest places a place holder function
|
||||||
func (*NullNotifier) NotifyPullReviewRequest(doer *user_model.User, issue *models.Issue, reviewer *user_model.User, isRequest bool, comment *models.Comment) {
|
func (*NullNotifier) NotifyPullReviewRequest(doer *user_model.User, issue *issues_model.Issue, reviewer *user_model.User, isRequest bool, comment *issues_model.Comment) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyIssueClearLabels places a place holder function
|
// NotifyIssueClearLabels places a place holder function
|
||||||
func (*NullNotifier) NotifyIssueClearLabels(doer *user_model.User, issue *models.Issue) {
|
func (*NullNotifier) NotifyIssueClearLabels(doer *user_model.User, issue *issues_model.Issue) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyIssueChangeTitle places a place holder function
|
// NotifyIssueChangeTitle places a place holder function
|
||||||
func (*NullNotifier) NotifyIssueChangeTitle(doer *user_model.User, issue *models.Issue, oldTitle string) {
|
func (*NullNotifier) NotifyIssueChangeTitle(doer *user_model.User, issue *issues_model.Issue, oldTitle string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyIssueChangeRef places a place holder function
|
// NotifyIssueChangeRef places a place holder function
|
||||||
func (*NullNotifier) NotifyIssueChangeRef(doer *user_model.User, issue *models.Issue, oldTitle string) {
|
func (*NullNotifier) NotifyIssueChangeRef(doer *user_model.User, issue *issues_model.Issue, oldTitle string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyIssueChangeLabels places a place holder function
|
// NotifyIssueChangeLabels places a place holder function
|
||||||
func (*NullNotifier) NotifyIssueChangeLabels(doer *user_model.User, issue *models.Issue,
|
func (*NullNotifier) NotifyIssueChangeLabels(doer *user_model.User, issue *issues_model.Issue,
|
||||||
addedLabels, removedLabels []*models.Label) {
|
addedLabels, removedLabels []*issues_model.Label) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyCreateRepository places a place holder function
|
// NotifyCreateRepository places a place holder function
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
package indexer
|
package indexer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"code.gitea.io/gitea/models"
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
|
@ -30,9 +30,9 @@ func NewNotifier() base.Notifier {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *indexerNotifier) NotifyCreateIssueComment(doer *user_model.User, repo *repo_model.Repository,
|
func (r *indexerNotifier) NotifyCreateIssueComment(doer *user_model.User, repo *repo_model.Repository,
|
||||||
issue *models.Issue, comment *models.Comment, mentions []*user_model.User,
|
issue *issues_model.Issue, comment *issues_model.Comment, mentions []*user_model.User,
|
||||||
) {
|
) {
|
||||||
if comment.Type == models.CommentTypeComment {
|
if comment.Type == issues_model.CommentTypeComment {
|
||||||
if issue.Comments == nil {
|
if issue.Comments == nil {
|
||||||
if err := issue.LoadDiscussComments(); err != nil {
|
if err := issue.LoadDiscussComments(); err != nil {
|
||||||
log.Error("LoadComments failed: %v", err)
|
log.Error("LoadComments failed: %v", err)
|
||||||
|
@ -46,16 +46,16 @@ func (r *indexerNotifier) NotifyCreateIssueComment(doer *user_model.User, repo *
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *indexerNotifier) NotifyNewIssue(issue *models.Issue, mentions []*user_model.User) {
|
func (r *indexerNotifier) NotifyNewIssue(issue *issues_model.Issue, mentions []*user_model.User) {
|
||||||
issue_indexer.UpdateIssueIndexer(issue)
|
issue_indexer.UpdateIssueIndexer(issue)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *indexerNotifier) NotifyNewPullRequest(pr *models.PullRequest, mentions []*user_model.User) {
|
func (r *indexerNotifier) NotifyNewPullRequest(pr *issues_model.PullRequest, mentions []*user_model.User) {
|
||||||
issue_indexer.UpdateIssueIndexer(pr.Issue)
|
issue_indexer.UpdateIssueIndexer(pr.Issue)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *indexerNotifier) NotifyUpdateComment(doer *user_model.User, c *models.Comment, oldContent string) {
|
func (r *indexerNotifier) NotifyUpdateComment(doer *user_model.User, c *issues_model.Comment, oldContent string) {
|
||||||
if c.Type == models.CommentTypeComment {
|
if c.Type == issues_model.CommentTypeComment {
|
||||||
var found bool
|
var found bool
|
||||||
if c.Issue.Comments != nil {
|
if c.Issue.Comments != nil {
|
||||||
for i := 0; i < len(c.Issue.Comments); i++ {
|
for i := 0; i < len(c.Issue.Comments); i++ {
|
||||||
|
@ -78,8 +78,8 @@ func (r *indexerNotifier) NotifyUpdateComment(doer *user_model.User, c *models.C
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *indexerNotifier) NotifyDeleteComment(doer *user_model.User, comment *models.Comment) {
|
func (r *indexerNotifier) NotifyDeleteComment(doer *user_model.User, comment *issues_model.Comment) {
|
||||||
if comment.Type == models.CommentTypeComment {
|
if comment.Type == issues_model.CommentTypeComment {
|
||||||
if err := comment.LoadIssue(); err != nil {
|
if err := comment.LoadIssue(); err != nil {
|
||||||
log.Error("LoadIssue: %v", err)
|
log.Error("LoadIssue: %v", err)
|
||||||
return
|
return
|
||||||
|
@ -142,14 +142,14 @@ func (r *indexerNotifier) NotifySyncPushCommits(pusher *user_model.User, repo *r
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *indexerNotifier) NotifyIssueChangeContent(doer *user_model.User, issue *models.Issue, oldContent string) {
|
func (r *indexerNotifier) NotifyIssueChangeContent(doer *user_model.User, issue *issues_model.Issue, oldContent string) {
|
||||||
issue_indexer.UpdateIssueIndexer(issue)
|
issue_indexer.UpdateIssueIndexer(issue)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *indexerNotifier) NotifyIssueChangeTitle(doer *user_model.User, issue *models.Issue, oldTitle string) {
|
func (r *indexerNotifier) NotifyIssueChangeTitle(doer *user_model.User, issue *issues_model.Issue, oldTitle string) {
|
||||||
issue_indexer.UpdateIssueIndexer(issue)
|
issue_indexer.UpdateIssueIndexer(issue)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *indexerNotifier) NotifyIssueChangeRef(doer *user_model.User, issue *models.Issue, oldRef string) {
|
func (r *indexerNotifier) NotifyIssueChangeRef(doer *user_model.User, issue *issues_model.Issue, oldRef string) {
|
||||||
issue_indexer.UpdateIssueIndexer(issue)
|
issue_indexer.UpdateIssueIndexer(issue)
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
"code.gitea.io/gitea/models"
|
||||||
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/graceful"
|
"code.gitea.io/gitea/modules/graceful"
|
||||||
|
@ -29,21 +30,21 @@ func NewNotifier() base.Notifier {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mailNotifier) NotifyCreateIssueComment(doer *user_model.User, repo *repo_model.Repository,
|
func (m *mailNotifier) NotifyCreateIssueComment(doer *user_model.User, repo *repo_model.Repository,
|
||||||
issue *models.Issue, comment *models.Comment, mentions []*user_model.User,
|
issue *issues_model.Issue, comment *issues_model.Comment, mentions []*user_model.User,
|
||||||
) {
|
) {
|
||||||
ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("mailNotifier.NotifyCreateIssueComment Issue[%d] #%d in [%d]", issue.ID, issue.Index, issue.RepoID))
|
ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("mailNotifier.NotifyCreateIssueComment Issue[%d] #%d in [%d]", issue.ID, issue.Index, issue.RepoID))
|
||||||
defer finished()
|
defer finished()
|
||||||
|
|
||||||
var act models.ActionType
|
var act models.ActionType
|
||||||
if comment.Type == models.CommentTypeClose {
|
if comment.Type == issues_model.CommentTypeClose {
|
||||||
act = models.ActionCloseIssue
|
act = models.ActionCloseIssue
|
||||||
} else if comment.Type == models.CommentTypeReopen {
|
} else if comment.Type == issues_model.CommentTypeReopen {
|
||||||
act = models.ActionReopenIssue
|
act = models.ActionReopenIssue
|
||||||
} else if comment.Type == models.CommentTypeComment {
|
} else if comment.Type == issues_model.CommentTypeComment {
|
||||||
act = models.ActionCommentIssue
|
act = models.ActionCommentIssue
|
||||||
} else if comment.Type == models.CommentTypeCode {
|
} else if comment.Type == issues_model.CommentTypeCode {
|
||||||
act = models.ActionCommentIssue
|
act = models.ActionCommentIssue
|
||||||
} else if comment.Type == models.CommentTypePullRequestPush {
|
} else if comment.Type == issues_model.CommentTypePullRequestPush {
|
||||||
act = 0
|
act = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,13 +53,13 @@ func (m *mailNotifier) NotifyCreateIssueComment(doer *user_model.User, repo *rep
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mailNotifier) NotifyNewIssue(issue *models.Issue, mentions []*user_model.User) {
|
func (m *mailNotifier) NotifyNewIssue(issue *issues_model.Issue, mentions []*user_model.User) {
|
||||||
if err := mailer.MailParticipants(issue, issue.Poster, models.ActionCreateIssue, mentions); err != nil {
|
if err := mailer.MailParticipants(issue, issue.Poster, models.ActionCreateIssue, mentions); err != nil {
|
||||||
log.Error("MailParticipants: %v", err)
|
log.Error("MailParticipants: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mailNotifier) NotifyIssueChangeStatus(doer *user_model.User, issue *models.Issue, actionComment *models.Comment, isClosed bool) {
|
func (m *mailNotifier) NotifyIssueChangeStatus(doer *user_model.User, issue *issues_model.Issue, actionComment *issues_model.Comment, isClosed bool) {
|
||||||
var actionType models.ActionType
|
var actionType models.ActionType
|
||||||
if issue.IsPull {
|
if issue.IsPull {
|
||||||
if isClosed {
|
if isClosed {
|
||||||
|
@ -79,34 +80,34 @@ func (m *mailNotifier) NotifyIssueChangeStatus(doer *user_model.User, issue *mod
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mailNotifier) NotifyIssueChangeTitle(doer *user_model.User, issue *models.Issue, oldTitle string) {
|
func (m *mailNotifier) NotifyIssueChangeTitle(doer *user_model.User, issue *issues_model.Issue, oldTitle string) {
|
||||||
if err := issue.LoadPullRequest(); err != nil {
|
if err := issue.LoadPullRequest(); err != nil {
|
||||||
log.Error("issue.LoadPullRequest: %v", err)
|
log.Error("issue.LoadPullRequest: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if issue.IsPull && models.HasWorkInProgressPrefix(oldTitle) && !issue.PullRequest.IsWorkInProgress() {
|
if issue.IsPull && issues_model.HasWorkInProgressPrefix(oldTitle) && !issue.PullRequest.IsWorkInProgress() {
|
||||||
if err := mailer.MailParticipants(issue, doer, models.ActionPullRequestReadyForReview, nil); err != nil {
|
if err := mailer.MailParticipants(issue, doer, models.ActionPullRequestReadyForReview, nil); err != nil {
|
||||||
log.Error("MailParticipants: %v", err)
|
log.Error("MailParticipants: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mailNotifier) NotifyNewPullRequest(pr *models.PullRequest, mentions []*user_model.User) {
|
func (m *mailNotifier) NotifyNewPullRequest(pr *issues_model.PullRequest, mentions []*user_model.User) {
|
||||||
if err := mailer.MailParticipants(pr.Issue, pr.Issue.Poster, models.ActionCreatePullRequest, mentions); err != nil {
|
if err := mailer.MailParticipants(pr.Issue, pr.Issue.Poster, models.ActionCreatePullRequest, mentions); err != nil {
|
||||||
log.Error("MailParticipants: %v", err)
|
log.Error("MailParticipants: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mailNotifier) NotifyPullRequestReview(pr *models.PullRequest, r *models.Review, comment *models.Comment, mentions []*user_model.User) {
|
func (m *mailNotifier) NotifyPullRequestReview(pr *issues_model.PullRequest, r *issues_model.Review, comment *issues_model.Comment, mentions []*user_model.User) {
|
||||||
ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("mailNotifier.NotifyPullRequestReview Pull[%d] #%d in [%d]", pr.ID, pr.Index, pr.BaseRepoID))
|
ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("mailNotifier.NotifyPullRequestReview Pull[%d] #%d in [%d]", pr.ID, pr.Index, pr.BaseRepoID))
|
||||||
defer finished()
|
defer finished()
|
||||||
|
|
||||||
var act models.ActionType
|
var act models.ActionType
|
||||||
if comment.Type == models.CommentTypeClose {
|
if comment.Type == issues_model.CommentTypeClose {
|
||||||
act = models.ActionCloseIssue
|
act = models.ActionCloseIssue
|
||||||
} else if comment.Type == models.CommentTypeReopen {
|
} else if comment.Type == issues_model.CommentTypeReopen {
|
||||||
act = models.ActionReopenIssue
|
act = models.ActionReopenIssue
|
||||||
} else if comment.Type == models.CommentTypeComment {
|
} else if comment.Type == issues_model.CommentTypeComment {
|
||||||
act = models.ActionCommentPull
|
act = models.ActionCommentPull
|
||||||
}
|
}
|
||||||
if err := mailer.MailParticipantsComment(ctx, comment, act, pr.Issue, mentions); err != nil {
|
if err := mailer.MailParticipantsComment(ctx, comment, act, pr.Issue, mentions); err != nil {
|
||||||
|
@ -114,7 +115,7 @@ func (m *mailNotifier) NotifyPullRequestReview(pr *models.PullRequest, r *models
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mailNotifier) NotifyPullRequestCodeComment(pr *models.PullRequest, comment *models.Comment, mentions []*user_model.User) {
|
func (m *mailNotifier) NotifyPullRequestCodeComment(pr *issues_model.PullRequest, comment *issues_model.Comment, mentions []*user_model.User) {
|
||||||
ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("mailNotifier.NotifyPullRequestCodeComment Pull[%d] #%d in [%d]", pr.ID, pr.Index, pr.BaseRepoID))
|
ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("mailNotifier.NotifyPullRequestCodeComment Pull[%d] #%d in [%d]", pr.ID, pr.Index, pr.BaseRepoID))
|
||||||
defer finished()
|
defer finished()
|
||||||
|
|
||||||
|
@ -123,7 +124,7 @@ func (m *mailNotifier) NotifyPullRequestCodeComment(pr *models.PullRequest, comm
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mailNotifier) NotifyIssueChangeAssignee(doer *user_model.User, issue *models.Issue, assignee *user_model.User, removed bool, comment *models.Comment) {
|
func (m *mailNotifier) NotifyIssueChangeAssignee(doer *user_model.User, issue *issues_model.Issue, assignee *user_model.User, removed bool, comment *issues_model.Comment) {
|
||||||
// mail only sent to added assignees and not self-assignee
|
// mail only sent to added assignees and not self-assignee
|
||||||
if !removed && doer.ID != assignee.ID && (assignee.EmailNotifications() == user_model.EmailNotificationsEnabled || assignee.EmailNotifications() == user_model.EmailNotificationsOnMention) {
|
if !removed && doer.ID != assignee.ID && (assignee.EmailNotifications() == user_model.EmailNotificationsEnabled || assignee.EmailNotifications() == user_model.EmailNotificationsOnMention) {
|
||||||
ct := fmt.Sprintf("Assigned #%d.", issue.Index)
|
ct := fmt.Sprintf("Assigned #%d.", issue.Index)
|
||||||
|
@ -133,7 +134,7 @@ func (m *mailNotifier) NotifyIssueChangeAssignee(doer *user_model.User, issue *m
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mailNotifier) NotifyPullReviewRequest(doer *user_model.User, issue *models.Issue, reviewer *user_model.User, isRequest bool, comment *models.Comment) {
|
func (m *mailNotifier) NotifyPullReviewRequest(doer *user_model.User, issue *issues_model.Issue, reviewer *user_model.User, isRequest bool, comment *issues_model.Comment) {
|
||||||
if isRequest && doer.ID != reviewer.ID && (reviewer.EmailNotifications() == user_model.EmailNotificationsEnabled || reviewer.EmailNotifications() == user_model.EmailNotificationsOnMention) {
|
if isRequest && doer.ID != reviewer.ID && (reviewer.EmailNotifications() == user_model.EmailNotificationsEnabled || reviewer.EmailNotifications() == user_model.EmailNotificationsOnMention) {
|
||||||
ct := fmt.Sprintf("Requested to review %s.", issue.HTMLURL())
|
ct := fmt.Sprintf("Requested to review %s.", issue.HTMLURL())
|
||||||
if err := mailer.SendIssueAssignedMail(issue, doer, ct, comment, []*user_model.User{reviewer}); err != nil {
|
if err := mailer.SendIssueAssignedMail(issue, doer, ct, comment, []*user_model.User{reviewer}); err != nil {
|
||||||
|
@ -142,7 +143,7 @@ func (m *mailNotifier) NotifyPullReviewRequest(doer *user_model.User, issue *mod
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mailNotifier) NotifyMergePullRequest(pr *models.PullRequest, doer *user_model.User) {
|
func (m *mailNotifier) NotifyMergePullRequest(pr *issues_model.PullRequest, doer *user_model.User) {
|
||||||
if err := pr.LoadIssue(); err != nil {
|
if err := pr.LoadIssue(); err != nil {
|
||||||
log.Error("pr.LoadIssue: %v", err)
|
log.Error("pr.LoadIssue: %v", err)
|
||||||
return
|
return
|
||||||
|
@ -152,7 +153,7 @@ func (m *mailNotifier) NotifyMergePullRequest(pr *models.PullRequest, doer *user
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mailNotifier) NotifyPullRequestPushCommits(doer *user_model.User, pr *models.PullRequest, comment *models.Comment) {
|
func (m *mailNotifier) NotifyPullRequestPushCommits(doer *user_model.User, pr *issues_model.PullRequest, comment *issues_model.Comment) {
|
||||||
ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("mailNotifier.NotifyPullRequestPushCommits Pull[%d] #%d in [%d]", pr.ID, pr.Index, pr.BaseRepoID))
|
ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("mailNotifier.NotifyPullRequestPushCommits Pull[%d] #%d in [%d]", pr.ID, pr.Index, pr.BaseRepoID))
|
||||||
defer finished()
|
defer finished()
|
||||||
|
|
||||||
|
@ -179,7 +180,7 @@ func (m *mailNotifier) NotifyPullRequestPushCommits(doer *user_model.User, pr *m
|
||||||
m.NotifyCreateIssueComment(doer, comment.Issue.Repo, comment.Issue, comment, nil)
|
m.NotifyCreateIssueComment(doer, comment.Issue.Repo, comment.Issue, comment, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mailNotifier) NotifyPullRevieweDismiss(doer *user_model.User, review *models.Review, comment *models.Comment) {
|
func (m *mailNotifier) NotifyPullRevieweDismiss(doer *user_model.User, review *issues_model.Review, comment *issues_model.Comment) {
|
||||||
ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("mailNotifier.NotifyPullRevieweDismiss Review[%d] in Issue[%d]", review.ID, review.IssueID))
|
ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("mailNotifier.NotifyPullRevieweDismiss Review[%d] in Issue[%d]", review.ID, review.IssueID))
|
||||||
defer finished()
|
defer finished()
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ package notification
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"code.gitea.io/gitea/models"
|
"code.gitea.io/gitea/models"
|
||||||
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
packages_model "code.gitea.io/gitea/models/packages"
|
packages_model "code.gitea.io/gitea/models/packages"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
@ -40,7 +41,7 @@ func NewContext() {
|
||||||
|
|
||||||
// NotifyCreateIssueComment notifies issue comment related message to notifiers
|
// NotifyCreateIssueComment notifies issue comment related message to notifiers
|
||||||
func NotifyCreateIssueComment(doer *user_model.User, repo *repo_model.Repository,
|
func NotifyCreateIssueComment(doer *user_model.User, repo *repo_model.Repository,
|
||||||
issue *models.Issue, comment *models.Comment, mentions []*user_model.User,
|
issue *issues_model.Issue, comment *issues_model.Comment, mentions []*user_model.User,
|
||||||
) {
|
) {
|
||||||
for _, notifier := range notifiers {
|
for _, notifier := range notifiers {
|
||||||
notifier.NotifyCreateIssueComment(doer, repo, issue, comment, mentions)
|
notifier.NotifyCreateIssueComment(doer, repo, issue, comment, mentions)
|
||||||
|
@ -48,91 +49,91 @@ func NotifyCreateIssueComment(doer *user_model.User, repo *repo_model.Repository
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyNewIssue notifies new issue to notifiers
|
// NotifyNewIssue notifies new issue to notifiers
|
||||||
func NotifyNewIssue(issue *models.Issue, mentions []*user_model.User) {
|
func NotifyNewIssue(issue *issues_model.Issue, mentions []*user_model.User) {
|
||||||
for _, notifier := range notifiers {
|
for _, notifier := range notifiers {
|
||||||
notifier.NotifyNewIssue(issue, mentions)
|
notifier.NotifyNewIssue(issue, mentions)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyIssueChangeStatus notifies close or reopen issue to notifiers
|
// NotifyIssueChangeStatus notifies close or reopen issue to notifiers
|
||||||
func NotifyIssueChangeStatus(doer *user_model.User, issue *models.Issue, actionComment *models.Comment, closeOrReopen bool) {
|
func NotifyIssueChangeStatus(doer *user_model.User, issue *issues_model.Issue, actionComment *issues_model.Comment, closeOrReopen bool) {
|
||||||
for _, notifier := range notifiers {
|
for _, notifier := range notifiers {
|
||||||
notifier.NotifyIssueChangeStatus(doer, issue, actionComment, closeOrReopen)
|
notifier.NotifyIssueChangeStatus(doer, issue, actionComment, closeOrReopen)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyDeleteIssue notify when some issue deleted
|
// NotifyDeleteIssue notify when some issue deleted
|
||||||
func NotifyDeleteIssue(doer *user_model.User, issue *models.Issue) {
|
func NotifyDeleteIssue(doer *user_model.User, issue *issues_model.Issue) {
|
||||||
for _, notifier := range notifiers {
|
for _, notifier := range notifiers {
|
||||||
notifier.NotifyDeleteIssue(doer, issue)
|
notifier.NotifyDeleteIssue(doer, issue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyMergePullRequest notifies merge pull request to notifiers
|
// NotifyMergePullRequest notifies merge pull request to notifiers
|
||||||
func NotifyMergePullRequest(pr *models.PullRequest, doer *user_model.User) {
|
func NotifyMergePullRequest(pr *issues_model.PullRequest, doer *user_model.User) {
|
||||||
for _, notifier := range notifiers {
|
for _, notifier := range notifiers {
|
||||||
notifier.NotifyMergePullRequest(pr, doer)
|
notifier.NotifyMergePullRequest(pr, doer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyNewPullRequest notifies new pull request to notifiers
|
// NotifyNewPullRequest notifies new pull request to notifiers
|
||||||
func NotifyNewPullRequest(pr *models.PullRequest, mentions []*user_model.User) {
|
func NotifyNewPullRequest(pr *issues_model.PullRequest, mentions []*user_model.User) {
|
||||||
for _, notifier := range notifiers {
|
for _, notifier := range notifiers {
|
||||||
notifier.NotifyNewPullRequest(pr, mentions)
|
notifier.NotifyNewPullRequest(pr, mentions)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyPullRequestSynchronized notifies Synchronized pull request
|
// NotifyPullRequestSynchronized notifies Synchronized pull request
|
||||||
func NotifyPullRequestSynchronized(doer *user_model.User, pr *models.PullRequest) {
|
func NotifyPullRequestSynchronized(doer *user_model.User, pr *issues_model.PullRequest) {
|
||||||
for _, notifier := range notifiers {
|
for _, notifier := range notifiers {
|
||||||
notifier.NotifyPullRequestSynchronized(doer, pr)
|
notifier.NotifyPullRequestSynchronized(doer, pr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyPullRequestReview notifies new pull request review
|
// NotifyPullRequestReview notifies new pull request review
|
||||||
func NotifyPullRequestReview(pr *models.PullRequest, review *models.Review, comment *models.Comment, mentions []*user_model.User) {
|
func NotifyPullRequestReview(pr *issues_model.PullRequest, review *issues_model.Review, comment *issues_model.Comment, mentions []*user_model.User) {
|
||||||
for _, notifier := range notifiers {
|
for _, notifier := range notifiers {
|
||||||
notifier.NotifyPullRequestReview(pr, review, comment, mentions)
|
notifier.NotifyPullRequestReview(pr, review, comment, mentions)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyPullRequestCodeComment notifies new pull request code comment
|
// NotifyPullRequestCodeComment notifies new pull request code comment
|
||||||
func NotifyPullRequestCodeComment(pr *models.PullRequest, comment *models.Comment, mentions []*user_model.User) {
|
func NotifyPullRequestCodeComment(pr *issues_model.PullRequest, comment *issues_model.Comment, mentions []*user_model.User) {
|
||||||
for _, notifier := range notifiers {
|
for _, notifier := range notifiers {
|
||||||
notifier.NotifyPullRequestCodeComment(pr, comment, mentions)
|
notifier.NotifyPullRequestCodeComment(pr, comment, mentions)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyPullRequestChangeTargetBranch notifies when a pull request's target branch was changed
|
// NotifyPullRequestChangeTargetBranch notifies when a pull request's target branch was changed
|
||||||
func NotifyPullRequestChangeTargetBranch(doer *user_model.User, pr *models.PullRequest, oldBranch string) {
|
func NotifyPullRequestChangeTargetBranch(doer *user_model.User, pr *issues_model.PullRequest, oldBranch string) {
|
||||||
for _, notifier := range notifiers {
|
for _, notifier := range notifiers {
|
||||||
notifier.NotifyPullRequestChangeTargetBranch(doer, pr, oldBranch)
|
notifier.NotifyPullRequestChangeTargetBranch(doer, pr, oldBranch)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyPullRequestPushCommits notifies when push commits to pull request's head branch
|
// NotifyPullRequestPushCommits notifies when push commits to pull request's head branch
|
||||||
func NotifyPullRequestPushCommits(doer *user_model.User, pr *models.PullRequest, comment *models.Comment) {
|
func NotifyPullRequestPushCommits(doer *user_model.User, pr *issues_model.PullRequest, comment *issues_model.Comment) {
|
||||||
for _, notifier := range notifiers {
|
for _, notifier := range notifiers {
|
||||||
notifier.NotifyPullRequestPushCommits(doer, pr, comment)
|
notifier.NotifyPullRequestPushCommits(doer, pr, comment)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyPullRevieweDismiss notifies when a review was dismissed by repo admin
|
// NotifyPullRevieweDismiss notifies when a review was dismissed by repo admin
|
||||||
func NotifyPullRevieweDismiss(doer *user_model.User, review *models.Review, comment *models.Comment) {
|
func NotifyPullRevieweDismiss(doer *user_model.User, review *issues_model.Review, comment *issues_model.Comment) {
|
||||||
for _, notifier := range notifiers {
|
for _, notifier := range notifiers {
|
||||||
notifier.NotifyPullRevieweDismiss(doer, review, comment)
|
notifier.NotifyPullRevieweDismiss(doer, review, comment)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyUpdateComment notifies update comment to notifiers
|
// NotifyUpdateComment notifies update comment to notifiers
|
||||||
func NotifyUpdateComment(doer *user_model.User, c *models.Comment, oldContent string) {
|
func NotifyUpdateComment(doer *user_model.User, c *issues_model.Comment, oldContent string) {
|
||||||
for _, notifier := range notifiers {
|
for _, notifier := range notifiers {
|
||||||
notifier.NotifyUpdateComment(doer, c, oldContent)
|
notifier.NotifyUpdateComment(doer, c, oldContent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyDeleteComment notifies delete comment to notifiers
|
// NotifyDeleteComment notifies delete comment to notifiers
|
||||||
func NotifyDeleteComment(doer *user_model.User, c *models.Comment) {
|
func NotifyDeleteComment(doer *user_model.User, c *issues_model.Comment) {
|
||||||
for _, notifier := range notifiers {
|
for _, notifier := range notifiers {
|
||||||
notifier.NotifyDeleteComment(doer, c)
|
notifier.NotifyDeleteComment(doer, c)
|
||||||
}
|
}
|
||||||
|
@ -160,57 +161,57 @@ func NotifyDeleteRelease(doer *user_model.User, rel *models.Release) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyIssueChangeMilestone notifies change milestone to notifiers
|
// NotifyIssueChangeMilestone notifies change milestone to notifiers
|
||||||
func NotifyIssueChangeMilestone(doer *user_model.User, issue *models.Issue, oldMilestoneID int64) {
|
func NotifyIssueChangeMilestone(doer *user_model.User, issue *issues_model.Issue, oldMilestoneID int64) {
|
||||||
for _, notifier := range notifiers {
|
for _, notifier := range notifiers {
|
||||||
notifier.NotifyIssueChangeMilestone(doer, issue, oldMilestoneID)
|
notifier.NotifyIssueChangeMilestone(doer, issue, oldMilestoneID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyIssueChangeContent notifies change content to notifiers
|
// NotifyIssueChangeContent notifies change content to notifiers
|
||||||
func NotifyIssueChangeContent(doer *user_model.User, issue *models.Issue, oldContent string) {
|
func NotifyIssueChangeContent(doer *user_model.User, issue *issues_model.Issue, oldContent string) {
|
||||||
for _, notifier := range notifiers {
|
for _, notifier := range notifiers {
|
||||||
notifier.NotifyIssueChangeContent(doer, issue, oldContent)
|
notifier.NotifyIssueChangeContent(doer, issue, oldContent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyIssueChangeAssignee notifies change content to notifiers
|
// NotifyIssueChangeAssignee notifies change content to notifiers
|
||||||
func NotifyIssueChangeAssignee(doer *user_model.User, issue *models.Issue, assignee *user_model.User, removed bool, comment *models.Comment) {
|
func NotifyIssueChangeAssignee(doer *user_model.User, issue *issues_model.Issue, assignee *user_model.User, removed bool, comment *issues_model.Comment) {
|
||||||
for _, notifier := range notifiers {
|
for _, notifier := range notifiers {
|
||||||
notifier.NotifyIssueChangeAssignee(doer, issue, assignee, removed, comment)
|
notifier.NotifyIssueChangeAssignee(doer, issue, assignee, removed, comment)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyPullReviewRequest notifies Request Review change
|
// NotifyPullReviewRequest notifies Request Review change
|
||||||
func NotifyPullReviewRequest(doer *user_model.User, issue *models.Issue, reviewer *user_model.User, isRequest bool, comment *models.Comment) {
|
func NotifyPullReviewRequest(doer *user_model.User, issue *issues_model.Issue, reviewer *user_model.User, isRequest bool, comment *issues_model.Comment) {
|
||||||
for _, notifier := range notifiers {
|
for _, notifier := range notifiers {
|
||||||
notifier.NotifyPullReviewRequest(doer, issue, reviewer, isRequest, comment)
|
notifier.NotifyPullReviewRequest(doer, issue, reviewer, isRequest, comment)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyIssueClearLabels notifies clear labels to notifiers
|
// NotifyIssueClearLabels notifies clear labels to notifiers
|
||||||
func NotifyIssueClearLabels(doer *user_model.User, issue *models.Issue) {
|
func NotifyIssueClearLabels(doer *user_model.User, issue *issues_model.Issue) {
|
||||||
for _, notifier := range notifiers {
|
for _, notifier := range notifiers {
|
||||||
notifier.NotifyIssueClearLabels(doer, issue)
|
notifier.NotifyIssueClearLabels(doer, issue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyIssueChangeTitle notifies change title to notifiers
|
// NotifyIssueChangeTitle notifies change title to notifiers
|
||||||
func NotifyIssueChangeTitle(doer *user_model.User, issue *models.Issue, oldTitle string) {
|
func NotifyIssueChangeTitle(doer *user_model.User, issue *issues_model.Issue, oldTitle string) {
|
||||||
for _, notifier := range notifiers {
|
for _, notifier := range notifiers {
|
||||||
notifier.NotifyIssueChangeTitle(doer, issue, oldTitle)
|
notifier.NotifyIssueChangeTitle(doer, issue, oldTitle)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyIssueChangeRef notifies change reference to notifiers
|
// NotifyIssueChangeRef notifies change reference to notifiers
|
||||||
func NotifyIssueChangeRef(doer *user_model.User, issue *models.Issue, oldRef string) {
|
func NotifyIssueChangeRef(doer *user_model.User, issue *issues_model.Issue, oldRef string) {
|
||||||
for _, notifier := range notifiers {
|
for _, notifier := range notifiers {
|
||||||
notifier.NotifyIssueChangeRef(doer, issue, oldRef)
|
notifier.NotifyIssueChangeRef(doer, issue, oldRef)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyIssueChangeLabels notifies change labels to notifiers
|
// NotifyIssueChangeLabels notifies change labels to notifiers
|
||||||
func NotifyIssueChangeLabels(doer *user_model.User, issue *models.Issue,
|
func NotifyIssueChangeLabels(doer *user_model.User, issue *issues_model.Issue,
|
||||||
addedLabels, removedLabels []*models.Label,
|
addedLabels, removedLabels []*issues_model.Label,
|
||||||
) {
|
) {
|
||||||
for _, notifier := range notifiers {
|
for _, notifier := range notifiers {
|
||||||
notifier.NotifyIssueChangeLabels(doer, issue, addedLabels, removedLabels)
|
notifier.NotifyIssueChangeLabels(doer, issue, addedLabels, removedLabels)
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Reference in a new issue