Optimize regex compilations

Compile them only once at startup. I didn't measure if this makes a difference,
but it's easy to do, and now that we potentially need to check them more often,
it might be worth it.
This commit is contained in:
Stefan Haller 2026-05-08 13:21:40 +02:00
parent eba1df11a8
commit 692f56a61b
2 changed files with 23 additions and 23 deletions

View file

@ -1,10 +1,12 @@
package hosting_service
import "regexp"
// if you want to make a custom regex for a given service feel free to test it out
// at https://regex101.com using the flavor Golang
var defaultUrlRegexStrings = []string{
`^(?:https?|ssh)://[^/]+/(?P<owner>.*)/(?P<repo>.*?)(?:\.git)?$`,
`^(.*?@)?.*:/*(?P<owner>.*)/(?P<repo>.*?)(?:\.git)?$`,
var defaultUrlRegexps = []*regexp.Regexp{
regexp.MustCompile(`^(?:https?|ssh)://[^/]+/(?P<owner>.*)/(?P<repo>.*?)(?:\.git)?$`),
regexp.MustCompile(`^(.*?@)?.*:/*(?P<owner>.*)/(?P<repo>.*?)(?:\.git)?$`),
}
var (
@ -19,7 +21,7 @@ var githubServiceDef = ServiceDefinition{
pullRequestURLIntoDefaultBranch: "/compare/{{.From}}?expand=1",
pullRequestURLIntoTargetBranch: "/compare/{{.To}}...{{.From}}?expand=1",
commitURL: "/commit/{{.CommitHash}}",
regexStrings: defaultUrlRegexStrings,
urlRegexps: defaultUrlRegexps,
repoURLTemplate: defaultRepoURLTemplate,
repoNameTemplate: defaultRepoNameTemplate,
}
@ -29,9 +31,9 @@ var bitbucketServiceDef = ServiceDefinition{
pullRequestURLIntoDefaultBranch: "/pull-requests/new?source={{.From}}&t=1",
pullRequestURLIntoTargetBranch: "/pull-requests/new?source={{.From}}&dest={{.To}}&t=1",
commitURL: "/commits/{{.CommitHash}}",
regexStrings: []string{
`^(?:https?|ssh)://.*/(?P<owner>.*)/(?P<repo>.*?)(?:\.git)?$`,
`^.*@.*:/*(?P<owner>.*)/(?P<repo>.*?)(?:\.git)?$`,
urlRegexps: []*regexp.Regexp{
regexp.MustCompile(`^(?:https?|ssh)://.*/(?P<owner>.*)/(?P<repo>.*?)(?:\.git)?$`),
regexp.MustCompile(`^.*@.*:/*(?P<owner>.*)/(?P<repo>.*?)(?:\.git)?$`),
},
repoURLTemplate: defaultRepoURLTemplate,
repoNameTemplate: defaultRepoNameTemplate,
@ -42,7 +44,7 @@ var gitLabServiceDef = ServiceDefinition{
pullRequestURLIntoDefaultBranch: "/-/merge_requests/new?merge_request%5Bsource_branch%5D={{.From}}",
pullRequestURLIntoTargetBranch: "/-/merge_requests/new?merge_request%5Bsource_branch%5D={{.From}}&merge_request%5Btarget_branch%5D={{.To}}",
commitURL: "/-/commit/{{.CommitHash}}",
regexStrings: defaultUrlRegexStrings,
urlRegexps: defaultUrlRegexps,
repoURLTemplate: defaultRepoURLTemplate,
repoNameTemplate: defaultRepoNameTemplate,
}
@ -52,11 +54,11 @@ var azdoServiceDef = ServiceDefinition{
pullRequestURLIntoDefaultBranch: "/pullrequestcreate?sourceRef={{.From}}",
pullRequestURLIntoTargetBranch: "/pullrequestcreate?sourceRef={{.From}}&targetRef={{.To}}",
commitURL: "/commit/{{.CommitHash}}",
regexStrings: []string{
`^.+@vs-ssh\.visualstudio\.com[:/](?:v3/)?(?P<org>[^/]+)/(?P<project>[^/]+)/(?P<repo>[^/]+?)(?:\.git)?$`,
`^git@ssh.dev.azure.com.*/(?P<org>.*)/(?P<project>.*)/(?P<repo>.*?)(?:\.git)?$`,
`^https://.*@dev.azure.com/(?P<org>.*?)/(?P<project>.*?)/_git/(?P<repo>.*?)(?:\.git)?$`,
`^https://.*/(?P<org>.*?)/(?P<project>.*?)/_git/(?P<repo>.*?)(?:\.git)?$`,
urlRegexps: []*regexp.Regexp{
regexp.MustCompile(`^.+@vs-ssh\.visualstudio\.com[:/](?:v3/)?(?P<org>[^/]+)/(?P<project>[^/]+)/(?P<repo>[^/]+?)(?:\.git)?$`),
regexp.MustCompile(`^git@ssh.dev.azure.com.*/(?P<org>.*)/(?P<project>.*)/(?P<repo>.*?)(?:\.git)?$`),
regexp.MustCompile(`^https://.*@dev.azure.com/(?P<org>.*?)/(?P<project>.*?)/_git/(?P<repo>.*?)(?:\.git)?$`),
regexp.MustCompile(`^https://.*/(?P<org>.*?)/(?P<project>.*?)/_git/(?P<repo>.*?)(?:\.git)?$`),
},
repoURLTemplate: "https://{{.webDomain}}/{{.org}}/{{.project}}/_git/{{.repo}}",
repoNameTemplate: "{{.org}}/{{.project}}/{{.repo}}",
@ -67,9 +69,9 @@ var bitbucketServerServiceDef = ServiceDefinition{
pullRequestURLIntoDefaultBranch: "/pull-requests?create&sourceBranch={{.From}}",
pullRequestURLIntoTargetBranch: "/pull-requests?create&targetBranch={{.To}}&sourceBranch={{.From}}",
commitURL: "/commits/{{.CommitHash}}",
regexStrings: []string{
`^ssh://git@.*/(?P<project>.*)/(?P<repo>.*?)(?:\.git)?$`,
`^https://.*/scm/(?P<project>.*)/(?P<repo>.*?)(?:\.git)?$`,
urlRegexps: []*regexp.Regexp{
regexp.MustCompile(`^ssh://git@.*/(?P<project>.*)/(?P<repo>.*?)(?:\.git)?$`),
regexp.MustCompile(`^https://.*/scm/(?P<project>.*)/(?P<repo>.*?)(?:\.git)?$`),
},
repoURLTemplate: "https://{{.webDomain}}/projects/{{.project}}/repos/{{.repo}}",
repoNameTemplate: "{{.project}}/{{.repo}}",
@ -80,7 +82,7 @@ var giteaServiceDef = ServiceDefinition{
pullRequestURLIntoDefaultBranch: "/compare/{{.From}}",
pullRequestURLIntoTargetBranch: "/compare/{{.To}}...{{.From}}",
commitURL: "/commit/{{.CommitHash}}",
regexStrings: defaultUrlRegexStrings,
urlRegexps: defaultUrlRegexps,
repoURLTemplate: defaultRepoURLTemplate,
}
@ -89,7 +91,7 @@ var codebergServiceDef = ServiceDefinition{
pullRequestURLIntoDefaultBranch: "/compare/{{.From}}",
pullRequestURLIntoTargetBranch: "/compare/{{.To}}...{{.From}}",
commitURL: "/commit/{{.CommitHash}}",
regexStrings: defaultUrlRegexStrings,
urlRegexps: defaultUrlRegexps,
repoURLTemplate: defaultRepoURLTemplate,
}

View file

@ -195,7 +195,7 @@ type ServiceDefinition struct {
pullRequestURLIntoDefaultBranch string
pullRequestURLIntoTargetBranch string
commitURL string
regexStrings []string
urlRegexps []*regexp.Regexp
// can expect 'webdomain' to be passed in. Otherwise, you get to pick what we match in the regex
repoURLTemplate string
@ -222,8 +222,7 @@ func (self ServiceDefinition) getRepoNameFromRemoteURL(url string) (string, erro
}
func (self ServiceDefinition) parseRemoteUrl(url string) (map[string]string, error) {
for _, regexStr := range self.regexStrings {
re := regexp.MustCompile(regexStr)
for _, re := range self.urlRegexps {
matches := utils.FindNamedMatches(re, url)
if matches != nil {
return matches, nil
@ -242,8 +241,7 @@ type RepoInformation struct {
// GetRepoInfoFromURL parses a remote URL (SSH or HTTPS) and extracts the
// owner and repository name using the default URL regex patterns.
func GetRepoInfoFromURL(url string) (RepoInformation, error) {
for _, regexStr := range defaultUrlRegexStrings {
re := regexp.MustCompile(regexStr)
for _, re := range defaultUrlRegexps {
matches := utils.FindNamedMatches(re, url)
if matches != nil {
return RepoInformation{