models/action.go: add action reopen for #462

- models/issue.go: format comment type names
This commit is contained in:
Unknwon 2015-02-06 20:47:21 -05:00
parent afccd0a3ee
commit 5a99e9a37b
3 changed files with 84 additions and 45 deletions

View file

@ -41,13 +41,20 @@ var (
var (
// Same as Github. See https://help.github.com/articles/closing-issues-via-commit-messages
IssueCloseKeywords = []string{"close", "closes", "closed", "fix", "fixes", "fixed", "resolve", "resolves", "resolved"}
IssueCloseKeywordsPat *regexp.Regexp
IssueReferenceKeywordsPat *regexp.Regexp
IssueCloseKeywords = []string{"close", "closes", "closed", "fix", "fixes", "fixed", "resolve", "resolves", "resolved"}
IssueReopenKeywords = []string{"reopen", "reopens", "reopened"}
IssueCloseKeywordsPat, IssueReopenKeywordsPat *regexp.Regexp
IssueReferenceKeywordsPat *regexp.Regexp
)
func assembleKeywordsPattern(words []string) string {
return fmt.Sprintf(`(?i)(?:%s) \S+`, strings.Join(words, "|"))
}
func init() {
IssueCloseKeywordsPat = regexp.MustCompile(fmt.Sprintf(`(?i)(?:%s) \S+`, strings.Join(IssueCloseKeywords, "|")))
IssueCloseKeywordsPat = regexp.MustCompile(assembleKeywordsPattern(IssueCloseKeywords))
IssueReopenKeywordsPat = regexp.MustCompile(assembleKeywordsPattern(IssueReopenKeywords))
IssueReferenceKeywordsPat = regexp.MustCompile(`(?i)(?:)(^| )\S+`)
}
@ -112,11 +119,9 @@ func (a Action) GetIssueInfos() []string {
func updateIssuesCommit(userId, repoId int64, repoUserName, repoName string, commits []*base.PushCommit) error {
for _, c := range commits {
references := IssueReferenceKeywordsPat.FindAllString(c.Message, -1)
// FIXME: should not be a reference when it comes with action.
// e.g. fixes #1 will not have duplicated reference message.
for _, ref := range references {
for _, ref := range IssueReferenceKeywordsPat.FindAllString(c.Message, -1) {
ref := ref[strings.IndexByte(ref, byte(' '))+1:]
ref = strings.TrimRightFunc(ref, func(c rune) bool {
return !unicode.IsDigit(c)
@ -137,22 +142,18 @@ func updateIssuesCommit(userId, repoId int64, repoUserName, repoName string, com
}
issue, err := GetIssueByRef(ref)
if err != nil {
return err
}
url := fmt.Sprintf("%s/%s/%s/commit/%s", setting.AppSubUrl, repoUserName, repoName, c.Sha1)
message := fmt.Sprintf(`<a href="%s">%s</a>`, url, c.Message)
if _, err = CreateComment(userId, issue.RepoId, issue.Id, 0, 0, COMMIT, message, nil); err != nil {
if _, err = CreateComment(userId, issue.RepoId, issue.Id, 0, 0, COMMENT_TYPE_COMMIT, message, nil); err != nil {
return err
}
}
closes := IssueCloseKeywordsPat.FindAllString(c.Message, -1)
for _, ref := range closes {
for _, ref := range IssueCloseKeywordsPat.FindAllString(c.Message, -1) {
ref := ref[strings.IndexByte(ref, byte(' '))+1:]
ref = strings.TrimRightFunc(ref, func(c rune) bool {
return !unicode.IsDigit(c)
@ -173,7 +174,6 @@ func updateIssuesCommit(userId, repoId int64, repoUserName, repoName string, com
}
issue, err := GetIssueByRef(ref)
if err != nil {
return err
}
@ -182,7 +182,6 @@ func updateIssuesCommit(userId, repoId int64, repoUserName, repoName string, com
if issue.IsClosed {
continue
}
issue.IsClosed = true
if err = UpdateIssue(issue); err != nil {
@ -196,14 +195,60 @@ func updateIssuesCommit(userId, repoId int64, repoUserName, repoName string, com
}
// If commit happened in the referenced repository, it means the issue can be closed.
if _, err = CreateComment(userId, repoId, issue.Id, 0, 0, CLOSE, "", nil); err != nil {
if _, err = CreateComment(userId, repoId, issue.Id, 0, 0, COMMENT_TYPE_CLOSE, "", nil); err != nil {
return err
}
}
}
}
for _, ref := range IssueReopenKeywordsPat.FindAllString(c.Message, -1) {
ref := ref[strings.IndexByte(ref, byte(' '))+1:]
ref = strings.TrimRightFunc(ref, func(c rune) bool {
return !unicode.IsDigit(c)
})
if len(ref) == 0 {
continue
}
// Add repo name if missing
if ref[0] == '#' {
ref = fmt.Sprintf("%s/%s%s", repoUserName, repoName, ref)
} else if strings.Contains(ref, "/") == false {
// We don't support User#ID syntax yet
// return ErrNotImplemented
continue
}
issue, err := GetIssueByRef(ref)
if err != nil {
return err
}
if issue.RepoId == repoId {
if !issue.IsClosed {
continue
}
issue.IsClosed = false
if err = UpdateIssue(issue); err != nil {
return err
} else if err = UpdateIssueUserPairsByStatus(issue.Id, issue.IsClosed); err != nil {
return err
}
if err = ChangeMilestoneIssueStats(issue); err != nil {
return err
}
// If commit happened in the referenced repository, it means the issue can be closed.
if _, err = CreateComment(userId, repoId, issue.Id, 0, 0, COMMENT_TYPE_REOPEN, "", nil); err != nil {
return err
}
}
}
}
return nil
}

View file

@ -859,22 +859,16 @@ type CommentType int
const (
// Plain comment, can be associated with a commit (CommitId > 0) and a line (Line > 0)
COMMENT CommentType = iota
// Reopen action
REOPEN
// Close action
CLOSE
// Reference from another issue
ISSUE
COMMENT_TYPE_COMMENT CommentType = iota
COMMENT_TYPE_REOPEN
COMMENT_TYPE_CLOSE
// References.
COMMENT_TYPE_ISSUE
// Reference from some commit (not part of a pull request)
COMMIT
COMMENT_TYPE_COMMIT
// Reference from some pull request
PULL
COMMENT_TYPE_PULL
)
// Comment represents a comment in commit and issue page.
@ -908,7 +902,7 @@ func CreateComment(userId, repoId, issueId, commitId, line int64, cmtType Commen
// Check comment type.
switch cmtType {
case COMMENT:
case COMMENT_TYPE_COMMENT:
rawSql := "UPDATE `issue` SET num_comments = num_comments + 1 WHERE id = ?"
if _, err := sess.Exec(rawSql, issueId); err != nil {
sess.Rollback()
@ -929,13 +923,13 @@ func CreateComment(userId, repoId, issueId, commitId, line int64, cmtType Commen
return nil, err
}
}
case REOPEN:
case COMMENT_TYPE_REOPEN:
rawSql := "UPDATE `repository` SET num_closed_issues = num_closed_issues - 1 WHERE id = ?"
if _, err := sess.Exec(rawSql, repoId); err != nil {
sess.Rollback()
return nil, err
}
case CLOSE:
case COMMENT_TYPE_CLOSE:
rawSql := "UPDATE `repository` SET num_closed_issues = num_closed_issues + 1 WHERE id = ?"
if _, err := sess.Exec(rawSql, repoId); err != nil {
sess.Rollback()

View file

@ -424,7 +424,7 @@ func ViewIssue(ctx *middleware.Context) {
}
comments[i].Poster = u
if comments[i].Type == models.COMMENT {
if comments[i].Type == models.COMMENT_TYPE_COMMENT {
comments[i].Content = string(base.RenderMarkdown([]byte(comments[i].Content), ctx.Repo.RepoLink))
}
}
@ -774,9 +774,9 @@ func Comment(ctx *middleware.Context) {
}
}
cmtType := models.CLOSE
cmtType := models.COMMENT_TYPE_CLOSE
if !issue.IsClosed {
cmtType = models.REOPEN
cmtType = models.COMMENT_TYPE_REOPEN
}
if _, err = models.CreateComment(ctx.User.Id, ctx.Repo.Repository.Id, issue.Id, 0, 0, cmtType, "", nil); err != nil {
@ -795,7 +795,7 @@ func Comment(ctx *middleware.Context) {
if len(content) > 0 || len(ctx.Req.MultipartForm.File["attachments"]) > 0 {
switch ctx.Params(":action") {
case "new":
if comment, err = models.CreateComment(ctx.User.Id, ctx.Repo.Repository.Id, issue.Id, 0, 0, models.COMMENT, content, nil); err != nil {
if comment, err = models.CreateComment(ctx.User.Id, ctx.Repo.Repository.Id, issue.Id, 0, 0, models.COMMENT_TYPE_COMMENT, content, nil); err != nil {
send(500, nil, err)
return
}
@ -1122,18 +1122,18 @@ func IssueGetAttachment(ctx *middleware.Context) {
// testing route handler for new issue ui page
// todo : move to Issue() function
func Issues2(ctx *middleware.Context){
ctx.HTML(200,"repo/issue2/list")
func Issues2(ctx *middleware.Context) {
ctx.HTML(200, "repo/issue2/list")
}
func PullRequest2(ctx *middleware.Context){
ctx.HTML(200,"repo/pr2/list")
func PullRequest2(ctx *middleware.Context) {
ctx.HTML(200, "repo/pr2/list")
}
func Labels2(ctx *middleware.Context){
ctx.HTML(200,"repo/issue2/labels")
func Labels2(ctx *middleware.Context) {
ctx.HTML(200, "repo/issue2/labels")
}
func Milestones2(ctx *middleware.Context){
ctx.HTML(200,"repo/milestone2/list")
func Milestones2(ctx *middleware.Context) {
ctx.HTML(200, "repo/milestone2/list")
}