Configurable close and reopen keywords for PRs (#8120)
* Add settings for CloseKeywords and ReopenKeywords * Fix and improve tests * Use sync.Once() for initialization * Fix unintended exported function
This commit is contained in:
@ -69,6 +69,10 @@ MAX_FILES = 5
|
||||
[repository.pull-request]
|
||||
; List of prefixes used in Pull Request title to mark them as Work In Progress
|
||||
WORK_IN_PROGRESS_PREFIXES=WIP:,[WIP]
|
||||
; List of keywords used in Pull Request comments to automatically close a related issue
|
||||
CLOSE_KEYWORDS=close,closes,closed,fix,fixes,fixed,resolve,resolves,resolved
|
||||
; List of keywords used in Pull Request comments to automatically reopen a related issue
|
||||
REOPEN_KEYWORDS=reopen,reopens,reopened
|
||||
|
||||
[repository.issue]
|
||||
; List of reasons why a Pull Request or Issue can be locked
|
||||
|
@ -71,6 +71,10 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`.
|
||||
|
||||
- `WORK_IN_PROGRESS_PREFIXES`: **WIP:,\[WIP\]**: List of prefixes used in Pull Request
|
||||
title to mark them as Work In Progress
|
||||
- `CLOSE_KEYWORDS`: **close**, **closes**, **closed**, **fix**, **fixes**, **fixed**, **resolve**, **resolves**, **resolved**: List of
|
||||
keywords used in Pull Request comments to automatically close a related issue
|
||||
- `REOPEN_KEYWORDS`: **reopen**, **reopens**, **reopened**: List of keywords used in Pull Request comments to automatically reopen
|
||||
a related issue
|
||||
|
||||
### Repository - Issue (`repository.issue`)
|
||||
|
||||
|
@ -11,6 +11,7 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/markup/mdstripper"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
)
|
||||
@ -35,12 +36,8 @@ var (
|
||||
// e.g. gogits/gogs#12345
|
||||
crossReferenceIssueNumericPattern = regexp.MustCompile(`(?:\s|^|\(|\[)([0-9a-zA-Z-_\.]+/[0-9a-zA-Z-_\.]+#[0-9]+)(?:\s|$|\)|\]|\.(\s|$))`)
|
||||
|
||||
// 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"}
|
||||
issueReopenKeywords = []string{"reopen", "reopens", "reopened"}
|
||||
|
||||
issueCloseKeywordsPat, issueReopenKeywordsPat *regexp.Regexp
|
||||
issueKeywordsOnce sync.Once
|
||||
|
||||
giteaHostInit sync.Once
|
||||
giteaHost string
|
||||
@ -107,13 +104,40 @@ type RefSpan struct {
|
||||
End int
|
||||
}
|
||||
|
||||
func makeKeywordsPat(keywords []string) *regexp.Regexp {
|
||||
return regexp.MustCompile(`(?i)(?:\s|^|\(|\[)(` + strings.Join(keywords, `|`) + `):? $`)
|
||||
func makeKeywordsPat(words []string) *regexp.Regexp {
|
||||
acceptedWords := parseKeywords(words)
|
||||
if len(acceptedWords) == 0 {
|
||||
// Never match
|
||||
return nil
|
||||
}
|
||||
return regexp.MustCompile(`(?i)(?:\s|^|\(|\[)(` + strings.Join(acceptedWords, `|`) + `):? $`)
|
||||
}
|
||||
|
||||
func init() {
|
||||
issueCloseKeywordsPat = makeKeywordsPat(issueCloseKeywords)
|
||||
issueReopenKeywordsPat = makeKeywordsPat(issueReopenKeywords)
|
||||
func parseKeywords(words []string) []string {
|
||||
acceptedWords := make([]string, 0, 5)
|
||||
wordPat := regexp.MustCompile(`^[\pL]+$`)
|
||||
for _, word := range words {
|
||||
word = strings.ToLower(strings.TrimSpace(word))
|
||||
// Accept Unicode letter class runes (a-z, á, à, ä, )
|
||||
if wordPat.MatchString(word) {
|
||||
acceptedWords = append(acceptedWords, word)
|
||||
} else {
|
||||
log.Info("Invalid keyword: %s", word)
|
||||
}
|
||||
}
|
||||
return acceptedWords
|
||||
}
|
||||
|
||||
func newKeywords() {
|
||||
issueKeywordsOnce.Do(func() {
|
||||
// Delay initialization until after the settings module is initialized
|
||||
doNewKeywords(setting.Repository.PullRequest.CloseKeywords, setting.Repository.PullRequest.ReopenKeywords)
|
||||
})
|
||||
}
|
||||
|
||||
func doNewKeywords(close []string, reopen []string) {
|
||||
issueCloseKeywordsPat = makeKeywordsPat(close)
|
||||
issueReopenKeywordsPat = makeKeywordsPat(reopen)
|
||||
}
|
||||
|
||||
// getGiteaHostName returns a normalized string with the local host name, with no scheme or port information
|
||||
@ -310,13 +334,19 @@ func getCrossReference(content []byte, start, end int, fromLink bool) *rawRefere
|
||||
}
|
||||
|
||||
func findActionKeywords(content []byte, start int) (XRefAction, *RefSpan) {
|
||||
m := issueCloseKeywordsPat.FindSubmatchIndex(content[:start])
|
||||
if m != nil {
|
||||
return XRefActionCloses, &RefSpan{Start: m[2], End: m[3]}
|
||||
newKeywords()
|
||||
var m []int
|
||||
if issueCloseKeywordsPat != nil {
|
||||
m = issueCloseKeywordsPat.FindSubmatchIndex(content[:start])
|
||||
if m != nil {
|
||||
return XRefActionCloses, &RefSpan{Start: m[2], End: m[3]}
|
||||
}
|
||||
}
|
||||
m = issueReopenKeywordsPat.FindSubmatchIndex(content[:start])
|
||||
if m != nil {
|
||||
return XRefActionReopens, &RefSpan{Start: m[2], End: m[3]}
|
||||
if issueReopenKeywordsPat != nil {
|
||||
m = issueReopenKeywordsPat.FindSubmatchIndex(content[:start])
|
||||
if m != nil {
|
||||
return XRefActionReopens, &RefSpan{Start: m[2], End: m[3]}
|
||||
}
|
||||
}
|
||||
return XRefActionNone, nil
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -59,6 +59,8 @@ var (
|
||||
// Pull request settings
|
||||
PullRequest struct {
|
||||
WorkInProgressPrefixes []string
|
||||
CloseKeywords []string
|
||||
ReopenKeywords []string
|
||||
} `ini:"repository.pull-request"`
|
||||
|
||||
// Issue Setting
|
||||
@ -122,8 +124,14 @@ var (
|
||||
// Pull request settings
|
||||
PullRequest: struct {
|
||||
WorkInProgressPrefixes []string
|
||||
CloseKeywords []string
|
||||
ReopenKeywords []string
|
||||
}{
|
||||
WorkInProgressPrefixes: []string{"WIP:", "[WIP]"},
|
||||
// Same as GitHub. See
|
||||
// https://help.github.com/articles/closing-issues-via-commit-messages
|
||||
CloseKeywords: strings.Split("close,closes,closed,fix,fixes,fixed,resolve,resolves,resolved", ","),
|
||||
ReopenKeywords: strings.Split("reopen,reopens,reopened", ","),
|
||||
},
|
||||
|
||||
// Issue settings
|
||||
|
Reference in New Issue
Block a user