This commit is contained in:
AlexanderBeyn 2018-07-20 09:28:16 +00:00 committed by GitHub
commit 774abff779
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 118 additions and 20 deletions

View File

@ -527,10 +527,13 @@ func (repo *Repository) ComposeMetas() map[string]string {
"format": unit.ExternalTrackerConfig().ExternalTrackerFormat,
"user": repo.MustOwner().Name,
"repo": repo.Name,
"regexp": unit.ExternalTrackerConfig().ExternalTrackerRegexpPattern,
}
switch unit.ExternalTrackerConfig().ExternalTrackerStyle {
case markup.IssueNameStyleAlphanumeric:
repo.ExternalMetas["style"] = markup.IssueNameStyleAlphanumeric
case markup.IssueNameStyleRegexp:
repo.ExternalMetas["style"] = markup.IssueNameStyleRegexp
default:
repo.ExternalMetas["style"] = markup.IssueNameStyleNumeric
}

View File

@ -46,6 +46,9 @@ func TestRepo(t *testing.T) {
externalTracker.ExternalTrackerConfig().ExternalTrackerStyle = markup.IssueNameStyleNumeric
testSuccess(markup.IssueNameStyleNumeric)
externalTracker.ExternalTrackerConfig().ExternalTrackerStyle = markup.IssueNameStyleRegexp
testSuccess(markup.IssueNameStyleRegexp)
}
func TestGetRepositoryCount(t *testing.T) {

View File

@ -54,9 +54,10 @@ func (cfg *ExternalWikiConfig) ToDB() ([]byte, error) {
// ExternalTrackerConfig describes external tracker config
type ExternalTrackerConfig struct {
ExternalTrackerURL string
ExternalTrackerFormat string
ExternalTrackerStyle string
ExternalTrackerURL string
ExternalTrackerFormat string
ExternalTrackerStyle string
ExternalTrackerRegexpPattern string
}
// FromDB fills up a ExternalTrackerConfig from serialized format.

View File

@ -106,6 +106,7 @@ type RepoSettingForm struct {
ExternalTrackerURL string
TrackerURLFormat string
TrackerIssueStyle string
ExternalTrackerRegexpPattern string
EnablePulls bool
PullsIgnoreWhitespace bool
PullsAllowMerge bool

View File

@ -25,6 +25,7 @@ import (
const (
IssueNameStyleNumeric = "numeric"
IssueNameStyleAlphanumeric = "alphanumeric"
IssueNameStyleRegexp = "regexp"
)
var (
@ -543,28 +544,52 @@ func issueIndexPatternProcessor(ctx *postProcessCtx, node *html.Node) {
// default to numeric pattern, unless alphanumeric is requested.
pattern := issueNumericPattern
if ctx.metas["style"] == IssueNameStyleAlphanumeric {
switch ctx.metas["style"] {
case IssueNameStyleAlphanumeric:
pattern = issueAlphanumericPattern
case IssueNameStyleRegexp:
var err error
pattern, err = regexp.Compile(ctx.metas["regexp"])
if err != nil {
return
}
}
match := pattern.FindStringSubmatchIndex(node.Data)
if match == nil {
if match == nil || len(match) < 4 {
return
}
id := node.Data[match[2]:match[3]]
var index string
var content string
var start int
var end int
switch ctx.metas["style"] {
case IssueNameStyleAlphanumeric:
content = node.Data[match[2]:match[3]]
index = content
start = match[2]
end = match[3]
case IssueNameStyleRegexp:
index = node.Data[match[2]:match[3]]
content = node.Data[match[0]:match[1]]
start = match[0]
end = match[1]
default:
content = node.Data[match[2]:match[3]]
index = content[1:]
start = match[2]
end = match[3]
}
var link *html.Node
if ctx.metas == nil {
link = createLink(util.URLJoin(prefix, "issues", id[1:]), id)
link = createLink(util.URLJoin(prefix, "issues", index), content)
} else {
// Support for external issue tracker
if ctx.metas["style"] == IssueNameStyleAlphanumeric {
ctx.metas["index"] = id
} else {
ctx.metas["index"] = id[1:]
}
link = createLink(com.Expand(ctx.metas["format"], ctx.metas), id)
ctx.metas["index"] = index
link = createLink(com.Expand(ctx.metas["format"], ctx.metas), content)
}
replaceContent(node, match[2], match[3], link)
replaceContent(node, start, end, link)
}
func crossReferenceIssueIndexPatternProcessor(ctx *postProcessCtx, node *html.Node) {

View File

@ -53,6 +53,13 @@ var alphanumericMetas = map[string]string{
"style": IssueNameStyleAlphanumeric,
}
var regexpMetas = map[string]string{
"format": "https://someurl.com/{user}/{repo}/{index}",
"user": "someUser",
"repo": "someRepo",
"style": IssueNameStyleRegexp,
}
func TestRender_IssueIndexPattern(t *testing.T) {
// numeric: render inputs without valid mentions
test := func(s string) {
@ -160,6 +167,40 @@ func TestRender_IssueIndexPattern4(t *testing.T) {
test("test issue ABCDEFGHIJ-1234567890", "test issue %s", "ABCDEFGHIJ-1234567890")
}
func TestRender_IssueIndexPattern5(t *testing.T) {
test := func(s, expectedFmt string, pattern string, ids []string, names []string) {
metas := regexpMetas
metas["regexp"] = pattern
links := make([]interface{}, len(ids))
for i, id := range ids {
links[i] = link(util.URLJoin("https://someurl.com/someUser/someRepo/", id), names[i])
}
expected := fmt.Sprintf(expectedFmt, links...)
testRenderIssueIndexPattern(t, s, expected, &postProcessCtx{metas: metas})
}
test("abc ISSUE-123 def", "abc %s def", "ISSUE-(\\d+)",
[]string{"123"},
[]string{"ISSUE-123"},
)
test("abc (ISSUE 123) def", "abc %s def",
"\\(ISSUE (\\d+)\\)",
[]string{"123"},
[]string{"(ISSUE 123)"},
)
test("abc (ISSUE 123) def (TASK 456) ghi", "abc %s def %s ghi", "\\((?:ISSUE|TASK) (\\d+)\\)",
[]string{"123", "456"},
[]string{"(ISSUE 123)", "(TASK 456)"},
)
metas := regexpMetas
metas["regexp"] = "no matches"
testRenderIssueIndexPattern(t, "will not match", "will not match", &postProcessCtx{metas: metas})
}
func testRenderIssueIndexPattern(t *testing.T, input, expected string, ctx *postProcessCtx) {
if ctx == nil {
ctx = new(postProcessCtx)

View File

@ -974,6 +974,9 @@ settings.tracker_url_format = External Issue Tracker URL Format
settings.tracker_issue_style = External Issue Tracker Number Format
settings.tracker_issue_style.numeric = Numeric
settings.tracker_issue_style.alphanumeric = Alphanumeric
settings.tracker_issue_style.regexp = Regular Expression
settings.tracker_issue_style.regexp_pattern = Regular Expression Pattern
settings.tracker_issue_style.regexp_pattern_desc = The first captured group will be used in place of <code>{index}</code>.
settings.tracker_url_format_desc = Use the placeholders <code>{user}</code>, <code>{repo}</code> and <code>{index}</code> for the username, repository name and issue index.
settings.enable_timetracker = Enable Time Tracking
settings.allow_only_contributors_to_track_time = Let Only Contributors Track Time

View File

@ -501,6 +501,15 @@ function initRepository() {
if (typeof $(this).data('context') !== 'undefined') $($(this).data('context')).addClass('disabled');
}
});
$('.enable-system-pick').change(function () {
if ($(this).data('context') && $(this).data('target')) {
if ($(this).data('context') === this.value) {
$($(this).data('target')).removeClass('disabled')
} else {
$($(this).data('target')).addClass('disabled')
}
}
})
}
// Labels

View File

@ -190,9 +190,10 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) {
RepoID: repo.ID,
Type: models.UnitTypeExternalTracker,
Config: &models.ExternalTrackerConfig{
ExternalTrackerURL: form.ExternalTrackerURL,
ExternalTrackerFormat: form.TrackerURLFormat,
ExternalTrackerStyle: form.TrackerIssueStyle,
ExternalTrackerURL: form.ExternalTrackerURL,
ExternalTrackerFormat: form.TrackerURLFormat,
ExternalTrackerStyle: form.TrackerIssueStyle,
ExternalTrackerRegexpPattern: form.ExternalTrackerRegexpPattern,
},
})
} else {

View File

@ -183,16 +183,27 @@
<div class="ui radio checkbox">
{{$externalTracker := (.Repository.MustGetUnit $.UnitTypeExternalTracker)}}
{{$externalTrackerStyle := $externalTracker.ExternalTrackerConfig.ExternalTrackerStyle}}
<input class="hidden" tabindex="0" name="tracker_issue_style" type="radio" value="numeric" {{if $externalTrackerStyle}}{{if eq $externalTrackerStyle "numeric"}}checked=""{{end}}{{end}}/>
<input class="hidden enable-system-pick" tabindex="0" name="tracker_issue_style" type="radio" value="numeric" data-context="regexp" data-target="#tracker_regexp_pattern_box" {{if $externalTrackerStyle}}{{if eq $externalTrackerStyle "numeric"}}checked=""{{end}}{{end}}/>
<label>{{.i18n.Tr "repo.settings.tracker_issue_style.numeric"}} <span class="ui light grey text">(#1234)</span></label>
</div>
</div>
<div class="field">
<div class="ui radio checkbox">
<input class="hidden" tabindex="0" name="tracker_issue_style" type="radio" value="alphanumeric" {{if $externalTrackerStyle}}{{if eq $externalTracker.ExternalTrackerConfig.ExternalTrackerStyle "alphanumeric"}}checked=""{{end}}{{end}} />
<input class="hidden enable-system-pick" tabindex="0" name="tracker_issue_style" type="radio" value="alphanumeric" data-context="regexp" data-target="#tracker_regexp_pattern_box" {{if $externalTrackerStyle}}{{if eq $externalTracker.ExternalTrackerConfig.ExternalTrackerStyle "alphanumeric"}}checked=""{{end}}{{end}} />
<label>{{.i18n.Tr "repo.settings.tracker_issue_style.alphanumeric"}} <span class="ui light grey text">(ABC-123, DEFG-234)</span></label>
</div>
</div>
<div class="field">
<div class="ui radio checkbox">
<input class="hidden enable-system-pick" tabindex="0" name="tracker_issue_style" type="radio" value="regexp" data-context="regexp" data-target="#tracker_regexp_pattern_box" {{if $externalTrackerStyle}}{{if eq $externalTracker.ExternalTrackerConfig.ExternalTrackerStyle "regexp"}}checked=""{{end}}{{end}} />
<label>{{.i18n.Tr "repo.settings.tracker_issue_style.regexp"}} <span class="ui light grey text">((?:TASK|ISSUE) (\d+))</span></label>
</div>
</div>
</div>
<div class="field {{if ne $externalTracker.ExternalTrackerConfig.ExternalTrackerStyle "regexp"}}disabled{{end}}" id="tracker_regexp_pattern_box">
<label for="external_tracker_regexp_pattern">{{.i18n.Tr "repo.settings.tracker_issue_style.regexp_pattern"}}</label>
<input id="external_tracker_regexp_pattern" name="external_tracker_regexp_pattern" value="{{(.Repository.MustGetUnit $.UnitTypeExternalTracker).ExternalTrackerConfig.ExternalTrackerRegexpPattern}}">
<p class="help">{{.i18n.Tr "repo.settings.tracker_issue_style.regexp_pattern_desc" | Str2html}}</p>
</div>
</div>
</div>