From ecb943b24ad1b60b1c5873de2c7748ce81346047 Mon Sep 17 00:00:00 2001 From: Andrew Thornton Date: Sat, 27 Mar 2021 20:56:34 +0000 Subject: [PATCH] Provide mechanism for configuring submodule aliases Sometimes Gitea users would like submodules when displayed on the website to have a different alias than what is normally inferred by gitea. This PR provides a mechanism to configure this. Fix #15178 Signed-off-by: Andrew Thornton --- custom/conf/app.example.ini | 7 ++ .../doc/advanced/config-cheat-sheet.en-us.md | 7 ++ modules/git/git.go | 2 + modules/git/submodule.go | 39 +++++++++++ modules/git/submodule_test.go | 69 ++++++++++++------- modules/setting/git.go | 19 +++++ 6 files changed, 120 insertions(+), 23 deletions(-) diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index fe4fec7e92f6c..509ac18922ae5 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -1145,6 +1145,13 @@ CLONE = 300 PULL = 300 GC = 60 +; Submodule aliase +; [git.submodule] +; MAP_NAME_1 = git@127.0.0.1 +; MAP_VALUE_1 = https://example.com +; MAP_NAME_2 = git@github.com/go-gitea/gitea +; MAP_VALUE_2 = https://gitea.com/gitea/gitea + [mirror] ; Default interval as a duration between each check DEFAULT_INTERVAL = 8h diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index e32112f025913..9e3dec2cfb424 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -782,6 +782,7 @@ NB: You must have `DISABLE_ROUTER_LOG` set to `false` for this option to take ef - `VERBOSE_PUSH_DELAY`: **5s**: Only print verbose information if push takes longer than this delay. ## Git - Timeout settings (`git.timeout`) + - `DEFAUlT`: **360**: Git operations default timeout seconds. - `MIGRATE`: **600**: Migrate external repositories timeout seconds. - `MIRROR`: **300**: Mirror external repositories timeout seconds. @@ -789,6 +790,12 @@ NB: You must have `DISABLE_ROUTER_LOG` set to `false` for this option to take ef - `PULL`: **300**: Git pull from internal repositories timeout seconds. - `GC`: **60**: Git repository GC timeout seconds. +## Git - Submodule alias settings (`git.submodule`) + +- List of `MAP_NAME_` and `MAP_VALUE_` pairs that map submodule urls or partial urls to web paths. For example: + - `MAP_NAME_1 = git@127.0.0.1` & `MAP_VALUE_1 = https://external` would convert any submodules referring to `git@127.0.0.1` to `https://external` + - `MAP_NAME_A = git@127.0.0.1:owner/repo` & `MAP_VALUE_A = https://external/externalowner/externalrepo` + ## Metrics (`metrics`) - `ENABLED`: **false**: Enables /metrics endpoint for prometheus. diff --git a/modules/git/git.go b/modules/git/git.go index 6b15138a5c748..70a009e545803 100644 --- a/modules/git/git.go +++ b/modules/git/git.go @@ -39,6 +39,8 @@ var ( // will be checked on Init goVersionLessThan115 = true + + SubModuleMap = map[string]string{} ) func log(format string, args ...interface{}) { diff --git a/modules/git/submodule.go b/modules/git/submodule.go index 231827f1e989a..1c2d3970467ea 100644 --- a/modules/git/submodule.go +++ b/modules/git/submodule.go @@ -44,8 +44,16 @@ func getRefURL(refURL, urlPrefix, repoFullName, sshDomain string) string { return "" } + if alias, ok := SubModuleMap[refURL]; ok { + return alias + } + refURI := strings.TrimSuffix(refURL, ".git") + if alias, ok := SubModuleMap[refURI]; ok { + return alias + } + prefixURL, _ := url.Parse(urlPrefix) urlPrefixHostname, _, err := net.SplitHostPort(prefixURL.Host) if err != nil { @@ -76,6 +84,10 @@ func getRefURL(refURL, urlPrefix, repoFullName, sshDomain string) string { pth = "/" + pth } + if alias, ok := SubModuleMap[m[1]+refHostname]; ok { + return alias + pth + } + if urlPrefixHostname == refHostname || refHostname == sshDomain { return urlPrefix + path.Clean(path.Join("/", pth)) } @@ -95,6 +107,33 @@ func getRefURL(refURL, urlPrefix, repoFullName, sshDomain string) string { supportedSchemes := []string{"http", "https", "git", "ssh", "git+ssh"} + if len(SubModuleMap) > 0 && ref.Scheme != "" { + if ref.Scheme == "ssh" { + if len(ref.User.Username()) > 0 { + if alias, ok := SubModuleMap[fmt.Sprintf("%v@%s:%s", ref.User, ref.Host, ref.Path[1:])]; ok { + return alias + } + if alias, ok := SubModuleMap[fmt.Sprintf("%v@%s", ref.User, ref.Host)]; ok { + return alias + ref.Path + } + } else if alias, ok := SubModuleMap[ref.Host+":"+ref.Path[1:]]; ok { + return alias + } else if alias, ok := SubModuleMap[ref.Host]; ok { + return alias + ref.Path + } + } + left := refURI + right := "" + for idx := strings.LastIndex(left, "/"); idx > len(ref.Scheme)+3; { + right = left[idx:] + right + left = left[:idx] + if alias, ok := SubModuleMap[left]; ok { + return alias + right + } + idx = strings.LastIndex(left, "/") + } + } + for _, scheme := range supportedSchemes { if ref.Scheme == scheme { if ref.Scheme == "http" || ref.Scheme == "https" { diff --git a/modules/git/submodule_test.go b/modules/git/submodule_test.go index ff8dc579f6d51..f0e6f30f7d643 100644 --- a/modules/git/submodule_test.go +++ b/modules/git/submodule_test.go @@ -12,32 +12,55 @@ import ( func TestGetRefURL(t *testing.T) { var kases = []struct { - refURL string - prefixURL string - parentPath string - SSHDomain string - expect string + refURL string + prefixURL string + parentPath string + SSHDomain string + expect string + subModuleMap map[string]string }{ - {"git://github.com/user1/repo1", "/", "user1/repo2", "", "http://github.com/user1/repo1"}, - {"https://localhost/user1/repo1.git", "/", "user1/repo2", "", "https://localhost/user1/repo1"}, - {"http://localhost/user1/repo1.git", "/", "owner/reponame", "", "http://localhost/user1/repo1"}, - {"git@github.com:user1/repo1.git", "/", "owner/reponame", "", "http://github.com/user1/repo1"}, - {"ssh://git@git.zefie.net:2222/zefie/lge_g6_kernel_scripts.git", "/", "zefie/lge_g6_kernel", "", "http://git.zefie.net/zefie/lge_g6_kernel_scripts"}, - {"git@git.zefie.net:2222/zefie/lge_g6_kernel_scripts.git", "/", "zefie/lge_g6_kernel", "", "http://git.zefie.net/2222/zefie/lge_g6_kernel_scripts"}, - {"git@try.gitea.io:go-gitea/gitea", "https://try.gitea.io/", "go-gitea/sdk", "", "https://try.gitea.io/go-gitea/gitea"}, - {"ssh://git@try.gitea.io:9999/go-gitea/gitea", "https://try.gitea.io/", "go-gitea/sdk", "", "https://try.gitea.io/go-gitea/gitea"}, - {"git://git@try.gitea.io:9999/go-gitea/gitea", "https://try.gitea.io/", "go-gitea/sdk", "", "https://try.gitea.io/go-gitea/gitea"}, - {"ssh://git@127.0.0.1:9999/go-gitea/gitea", "https://127.0.0.1:3000/", "go-gitea/sdk", "", "https://127.0.0.1:3000/go-gitea/gitea"}, - {"https://gitea.com:3000/user1/repo1.git", "https://127.0.0.1:3000/", "user/repo2", "", "https://gitea.com:3000/user1/repo1"}, - {"https://example.gitea.com/gitea/user1/repo1.git", "https://example.gitea.com/gitea/", "", "user/repo2", "https://example.gitea.com/gitea/user1/repo1"}, - {"https://username:password@github.com/username/repository.git", "/", "username/repository2", "", "https://username:password@github.com/username/repository"}, - {"somethingbad", "https://127.0.0.1:3000/go-gitea/gitea", "/", "", ""}, - {"git@localhost:user/repo", "https://localhost/", "user2/repo1", "", "https://localhost/user/repo"}, - {"../path/to/repo.git/", "https://localhost/", "user/repo2", "", "https://localhost/user/path/to/repo.git"}, - {"ssh://git@ssh.gitea.io:2222/go-gitea/gitea", "https://try.gitea.io/", "go-gitea/sdk", "ssh.gitea.io", "https://try.gitea.io/go-gitea/gitea"}, + {"git://github.com/user1/repo1", "/", "user1/repo2", "", "http://github.com/user1/repo1", map[string]string{}}, + {"https://localhost/user1/repo1.git", "/", "user1/repo2", "", "https://localhost/user1/repo1", map[string]string{}}, + {"http://localhost/user1/repo1.git", "/", "owner/reponame", "", "http://localhost/user1/repo1", map[string]string{}}, + {"git@github.com:user1/repo1.git", "/", "owner/reponame", "", "http://github.com/user1/repo1", map[string]string{}}, + {"ssh://git@git.zefie.net:2222/zefie/lge_g6_kernel_scripts.git", "/", "zefie/lge_g6_kernel", "", "http://git.zefie.net/zefie/lge_g6_kernel_scripts", map[string]string{}}, + {"git@git.zefie.net:2222/zefie/lge_g6_kernel_scripts.git", "/", "zefie/lge_g6_kernel", "", "http://git.zefie.net/2222/zefie/lge_g6_kernel_scripts", map[string]string{}}, + {"git@try.gitea.io:go-gitea/gitea", "https://try.gitea.io/", "go-gitea/sdk", "", "https://try.gitea.io/go-gitea/gitea", map[string]string{}}, + {"ssh://git@try.gitea.io:9999/go-gitea/gitea", "https://try.gitea.io/", "go-gitea/sdk", "", "https://try.gitea.io/go-gitea/gitea", map[string]string{}}, + {"git://git@try.gitea.io:9999/go-gitea/gitea", "https://try.gitea.io/", "go-gitea/sdk", "", "https://try.gitea.io/go-gitea/gitea", map[string]string{}}, + {"ssh://git@127.0.0.1:9999/go-gitea/gitea", "https://127.0.0.1:3000/", "go-gitea/sdk", "", "https://127.0.0.1:3000/go-gitea/gitea", map[string]string{}}, + {"https://gitea.com:3000/user1/repo1.git", "https://127.0.0.1:3000/", "user/repo2", "", "https://gitea.com:3000/user1/repo1", map[string]string{}}, + {"https://example.gitea.com/gitea/user1/repo1.git", "https://example.gitea.com/gitea/", "", "user/repo2", "https://example.gitea.com/gitea/user1/repo1", map[string]string{}}, + {"https://username:password@github.com/username/repository.git", "/", "username/repository2", "", "https://username:password@github.com/username/repository", map[string]string{}}, + {"somethingbad", "https://127.0.0.1:3000/go-gitea/gitea", "/", "", "", map[string]string{}}, + {"git@localhost:user/repo", "https://localhost/", "user2/repo1", "", "https://localhost/user/repo", map[string]string{}}, + {"../path/to/repo.git/", "https://localhost/", "user/repo2", "", "https://localhost/user/path/to/repo.git", map[string]string{}}, + {"ssh://git@ssh.gitea.io:2222/go-gitea/gitea", "https://try.gitea.io/", "go-gitea/sdk", "ssh.gitea.io", "https://try.gitea.io/go-gitea/gitea", map[string]string{}}, + {"ssh://git@ssh.gitea.io:2222/go-gitea/gitea", "https://try.gitea.io/", "go-gitea/sdk", "try.gitea.io", "https://try.gitea.io/go-gitea/gitea", map[string]string{ + "ssh://git@ssh.gitea.io:2222": "https://try.gitea.io", + }}, + {"git@ssh.gitea.io:go-gitea/gitea", "https://try.gitea.io/", "go-gitea/sdk", "try.gitea.io", "https://try.gitea.io/go-gitea/gitea", map[string]string{ + "git@ssh.gitea.io": "https://try.gitea.io", + "ssh://git@ssh.gitea.io:2222": "Wrong", + }}, + {"ssh://git@ssh.gitea.io/go-gitea/gitea", "https://try.gitea.io/", "go-gitea/sdk", "try.gitea.io", "https://try.gitea.io/go-gitea/gitea", map[string]string{ + "ssh://git@ssh.gitea.io": "https://try.gitea.io", + "ssh://git@ssh.gitea.io:2222": "Wrong", + }}, + {"ssh://git@ssh.gitea.io/go-gitea/gitea", "https://try.gitea.io/", "go-gitea/sdk", "try.gitea.io", "https://try.gitea.io/go-gitea/gitea", map[string]string{ + "git@ssh.gitea.io": "https://try.gitea.io", + }}, + {"ssh://git@ssh.gitea.io/go-gitea/gitea", "https://try.gitea.io/", "go-gitea/sdk", "try.gitea.io", "https://try.gitea.io/go-gitea/gitea", map[string]string{ + "git@ssh.gitea.io": "https://try.gitea.io", + }}, + {"ssh://git@ssh.gitea.io/go-gitea/gitea", "https://try.gitea.io/", "go-gitea/sdk", "try.gitea.io", "https://try.gitea.io/go-gitea/gitea", map[string]string{ + "git@ssh.gitea.io:go-gitea/gitea": "https://try.gitea.io/go-gitea/gitea", + }}, } - + orig := SubModuleMap for _, kase := range kases { + SubModuleMap = kase.subModuleMap assert.EqualValues(t, kase.expect, getRefURL(kase.refURL, kase.prefixURL, kase.parentPath, kase.SSHDomain)) } + SubModuleMap = orig } diff --git a/modules/setting/git.go b/modules/setting/git.go index 308d94894ba72..d96b5f1c81143 100644 --- a/modules/setting/git.go +++ b/modules/setting/git.go @@ -5,6 +5,7 @@ package setting import ( + "strings" "time" "code.gitea.io/gitea/modules/git" @@ -99,4 +100,22 @@ func newGit() { git.BranchesRangeSize = Git.BranchesRangeSize log.Info(format, args...) + + submoduleSection := Cfg.Section("git.submodule") + for key, nameValue := range submoduleSection.KeysHash() { + if !strings.HasPrefix(key, "MAP_NAME_") { + continue + } + if nameValue == "" { + continue + } + if !submoduleSection.HasKey("MAP_VALUE_" + key[9:]) { + log.Error("Missing value for submodule map: %s", key) + continue + } + valueValue := submoduleSection.Key("MAP_VALUE_" + key[9:]).MustString("") + if valueValue != "" { + git.SubModuleMap[nameValue] = valueValue + } + } }