From d94f15c2fd921722796a4cfdbbf266dd3017525c Mon Sep 17 00:00:00 2001
From: Andrew Imeson <andrew@andrewimeson.com>
Date: Fri, 7 Oct 2022 08:49:30 -0400
Subject: [PATCH] Make external issue tracker regexp configurable via API
 (#21338)

Fixes #21336

Signed-off-by: Andrew Imeson <andrew@andrewimeson.com>
---
 modules/convert/repository.go           |  7 ++++---
 modules/structs/repo.go                 |  4 +++-
 routers/api/v1/repo/repo.go             |  7 ++++---
 templates/swagger/v1_json.tmpl          |  7 ++++++-
 tests/integration/api_repo_edit_test.go | 18 +++++++++++++++---
 5 files changed, 32 insertions(+), 11 deletions(-)

diff --git a/modules/convert/repository.go b/modules/convert/repository.go
index f85316384..09b84afa6 100644
--- a/modules/convert/repository.go
+++ b/modules/convert/repository.go
@@ -56,9 +56,10 @@ func innerToRepo(repo *repo_model.Repository, mode perm.AccessMode, isParent boo
 		config := unit.ExternalTrackerConfig()
 		hasIssues = true
 		externalTracker = &api.ExternalTracker{
-			ExternalTrackerURL:    config.ExternalTrackerURL,
-			ExternalTrackerFormat: config.ExternalTrackerFormat,
-			ExternalTrackerStyle:  config.ExternalTrackerStyle,
+			ExternalTrackerURL:           config.ExternalTrackerURL,
+			ExternalTrackerFormat:        config.ExternalTrackerFormat,
+			ExternalTrackerStyle:         config.ExternalTrackerStyle,
+			ExternalTrackerRegexpPattern: config.ExternalTrackerRegexpPattern,
 		}
 	}
 	hasWiki := false
diff --git a/modules/structs/repo.go b/modules/structs/repo.go
index 27e7f4618..cf6601704 100644
--- a/modules/structs/repo.go
+++ b/modules/structs/repo.go
@@ -34,8 +34,10 @@ type ExternalTracker struct {
 	ExternalTrackerURL string `json:"external_tracker_url"`
 	// External Issue Tracker URL Format. Use the placeholders {user}, {repo} and {index} for the username, repository name and issue index.
 	ExternalTrackerFormat string `json:"external_tracker_format"`
-	// External Issue Tracker Number Format, either `numeric` or `alphanumeric`
+	// External Issue Tracker Number Format, either `numeric`, `alphanumeric`, or `regexp`
 	ExternalTrackerStyle string `json:"external_tracker_style"`
+	// External Issue Tracker issue regular expression
+	ExternalTrackerRegexpPattern string `json:"external_tracker_regexp_pattern"`
 }
 
 // ExternalWiki represents setting for external wiki
diff --git a/routers/api/v1/repo/repo.go b/routers/api/v1/repo/repo.go
index 319c4c781..de8a4d186 100644
--- a/routers/api/v1/repo/repo.go
+++ b/routers/api/v1/repo/repo.go
@@ -755,9 +755,10 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error {
 				RepoID: repo.ID,
 				Type:   unit_model.TypeExternalTracker,
 				Config: &repo_model.ExternalTrackerConfig{
-					ExternalTrackerURL:    opts.ExternalTracker.ExternalTrackerURL,
-					ExternalTrackerFormat: opts.ExternalTracker.ExternalTrackerFormat,
-					ExternalTrackerStyle:  opts.ExternalTracker.ExternalTrackerStyle,
+					ExternalTrackerURL:           opts.ExternalTracker.ExternalTrackerURL,
+					ExternalTrackerFormat:        opts.ExternalTracker.ExternalTrackerFormat,
+					ExternalTrackerStyle:         opts.ExternalTracker.ExternalTrackerStyle,
+					ExternalTrackerRegexpPattern: opts.ExternalTracker.ExternalTrackerRegexpPattern,
 				},
 			})
 			deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeIssues)
diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl
index 5ca379471..728e88b73 100644
--- a/templates/swagger/v1_json.tmpl
+++ b/templates/swagger/v1_json.tmpl
@@ -16015,8 +16015,13 @@
           "type": "string",
           "x-go-name": "ExternalTrackerFormat"
         },
+        "external_tracker_regexp_pattern": {
+          "description": "External Issue Tracker issue regular expression",
+          "type": "string",
+          "x-go-name": "ExternalTrackerRegexpPattern"
+        },
         "external_tracker_style": {
-          "description": "External Issue Tracker Number Format, either `numeric` or `alphanumeric`",
+          "description": "External Issue Tracker Number Format, either `numeric`, `alphanumeric`, or `regexp`",
           "type": "string",
           "x-go-name": "ExternalTrackerStyle"
         },
diff --git a/tests/integration/api_repo_edit_test.go b/tests/integration/api_repo_edit_test.go
index 5ef92bf47..4dfae97e4 100644
--- a/tests/integration/api_repo_edit_test.go
+++ b/tests/integration/api_repo_edit_test.go
@@ -40,9 +40,10 @@ func getRepoEditOptionFromRepo(repo *repo_model.Repository) *api.EditRepoOption
 		config := unit.ExternalTrackerConfig()
 		hasIssues = true
 		externalTracker = &api.ExternalTracker{
-			ExternalTrackerURL:    config.ExternalTrackerURL,
-			ExternalTrackerFormat: config.ExternalTrackerFormat,
-			ExternalTrackerStyle:  config.ExternalTrackerStyle,
+			ExternalTrackerURL:           config.ExternalTrackerURL,
+			ExternalTrackerFormat:        config.ExternalTrackerFormat,
+			ExternalTrackerStyle:         config.ExternalTrackerStyle,
+			ExternalTrackerRegexpPattern: config.ExternalTrackerRegexpPattern,
 		}
 	}
 	hasWiki := false
@@ -220,6 +221,17 @@ func TestAPIRepoEdit(t *testing.T) {
 		assert.Equal(t, *repo1editedOption.HasWiki, true)
 		assert.Equal(t, *repo1editedOption.ExternalWiki, *repoEditOption.ExternalWiki)
 
+		repoEditOption.ExternalTracker.ExternalTrackerStyle = "regexp"
+		repoEditOption.ExternalTracker.ExternalTrackerRegexpPattern = `(\d+)`
+		req = NewRequestWithJSON(t, "PATCH", url, &repoEditOption)
+		resp = session.MakeRequest(t, req, http.StatusOK)
+		DecodeJSON(t, resp, &repo)
+		assert.NotNil(t, repo)
+		repo1edited = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
+		repo1editedOption = getRepoEditOptionFromRepo(repo1edited)
+		assert.Equal(t, *repo1editedOption.HasIssues, true)
+		assert.Equal(t, *repo1editedOption.ExternalTracker, *repoEditOption.ExternalTracker)
+
 		// Do some tests with invalid URL for external tracker and wiki
 		repoEditOption.ExternalTracker.ExternalTrackerURL = "htp://www.somewebsite.com"
 		req = NewRequestWithJSON(t, "PATCH", url, &repoEditOption)