Skip to content

Commit 568e1c5

Browse files
committed
Fix #69: Support nested groups and subgroups in GitLab urls
1 parent c918de1 commit 568e1c5

File tree

5 files changed

+60
-52
lines changed

5 files changed

+60
-52
lines changed

internal/server/app_apis.go

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -722,12 +722,23 @@ func (s *Server) getStageApp(ctx context.Context, tx types.Transaction, appEntry
722722
return stageAppEntry, nil
723723
}
724724

725-
func parseGithubUrl(sourceUrl string, usingSSH bool) (repo, folder string, err error) {
725+
const REPO_FOLDER_SEPERATOR = "//"
726+
727+
func parseGitUrl(sourceUrl string, usingSSH bool) (repo, folder string, err error) {
726728
if !strings.HasSuffix(sourceUrl, "/") {
727729
sourceUrl = sourceUrl + "/"
728730
}
729731

732+
// GitLab supports groups and subgroups, like gitlab.com/g16004341/g2/pr1/app1
733+
// OpenRun requires such urls to be specified with // separator for the folder path
734+
// like gitlab.com/g16004341/g2/pr1//app1
735+
730736
if strings.HasPrefix(sourceUrl, "git@") {
737+
if strings.Contains(sourceUrl, REPO_FOLDER_SEPERATOR) {
738+
repo, folder, _ := strings.Cut(sourceUrl, REPO_FOLDER_SEPERATOR)
739+
return repo, folder, nil
740+
}
741+
731742
// Using git url format
732743
split := strings.SplitN(sourceUrl, "/", 3)
733744
if len(split) != 3 {
@@ -746,6 +757,17 @@ func parseGithubUrl(sourceUrl string, usingSSH bool) (repo, folder string, err e
746757
return "", "", err
747758
}
748759

760+
if strings.Contains(url.Path, REPO_FOLDER_SEPERATOR) {
761+
repo, folder, _ := strings.Cut(url.Path, REPO_FOLDER_SEPERATOR)
762+
if usingSSH {
763+
repo = strings.TrimPrefix(repo, "/")
764+
// Use git url like git@github.com:openrundev/openrun.git
765+
gitUrl := fmt.Sprintf("git@%s:%s.git", url.Host, repo)
766+
return gitUrl, folder, nil
767+
}
768+
return fmt.Sprintf("%s://%s%s", url.Scheme, url.Host, repo), folder, nil
769+
}
770+
749771
split := strings.SplitN(url.Path, "/", 4)
750772
if len(split) == 4 {
751773
if usingSSH {

internal/server/openrun_plugin.go

Lines changed: 6 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -188,37 +188,15 @@ func getSourceUrl(sourceUrl, branch string) string {
188188
if branch == "" {
189189
return ""
190190
}
191-
url := sourceUrl
192-
if strings.HasPrefix(sourceUrl, "http://") {
193-
url = strings.TrimPrefix(sourceUrl, "http://")
194-
} else if strings.HasPrefix(sourceUrl, "https://") {
195-
url = strings.TrimPrefix(sourceUrl, "https://")
196-
}
197-
198-
isGitUrl := false
199-
if strings.HasPrefix(url, "github.com/") {
200-
url = strings.TrimPrefix(url, "github.com/")
201-
} else if strings.HasPrefix(url, "git@github.com:") {
202-
url = strings.TrimPrefix(url, "git@github.com:")
203-
isGitUrl = true
204-
} else {
205-
return "" // cannot get full url
206-
}
207-
208-
splitPath := strings.Split(url, "/")
209-
if len(splitPath) < 2 {
210-
return "" // cannot get full url
191+
if !system.IsGit(sourceUrl) || strings.HasPrefix(sourceUrl, "git@") {
192+
return ""
211193
}
212-
folder := ""
213-
if len(splitPath) > 2 {
214-
folder = strings.Join(splitPath[2:], "/")
194+
repo, folder, err := parseGitUrl(sourceUrl, false)
195+
if err != nil {
196+
return ""
215197
}
216198

217-
repo := splitPath[1]
218-
if isGitUrl {
219-
repo = strings.TrimSuffix(splitPath[1], ".git")
220-
}
221-
return fmt.Sprintf("https://github.com/%s/%s/tree/%s/%s", splitPath[0], repo, branch, folder)
199+
return fmt.Sprintf("%s/tree/%s/%s", repo, branch, folder)
222200
}
223201

224202
func (c *openrunPlugin) ListAuditEvents(thread *starlark.Thread, builtin *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {

internal/server/openrun_plugin_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,17 @@ func TestGetSourceUrl(t *testing.T) {
1818
{
1919
url: "github.com/openrundev/openrun/myapp",
2020
branch: "main",
21-
want: "https://github.com/openrundev/openrun/tree/main/myapp",
21+
want: "https://github.com/openrundev/openrun/tree/main/myapp/",
2222
},
2323
{
2424
url: "https://github.com/openrundev/openrun/myapp",
2525
branch: "main",
26-
want: "https://github.com/openrundev/openrun/tree/main/myapp",
26+
want: "https://github.com/openrundev/openrun/tree/main/myapp/",
2727
},
2828
{
2929
url: "https://github.com/openrundev/openrun/myapp",
3030
branch: "main",
31-
want: "https://github.com/openrundev/openrun/tree/main/myapp",
31+
want: "https://github.com/openrundev/openrun/tree/main/myapp/",
3232
},
3333
{
3434
url: "/openrundev/openrun/myapp",
@@ -43,7 +43,7 @@ func TestGetSourceUrl(t *testing.T) {
4343
{
4444
url: "git@github.com:openrundev/openrun.git/myapp/t1/t2",
4545
branch: "develop",
46-
want: "https://github.com/openrundev/openrun/tree/develop/myapp/t1/t2",
46+
want: "",
4747
},
4848
{
4949
url: "github.com/openrundev",

internal/server/repo_cache.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ func (r *RepoCache) GetSha(sourceUrl, branch, gitAuth string) (string, error) {
6060
}
6161

6262
// Figure on which repo to clone
63-
repo, _, err := parseGithubUrl(sourceUrl, authEntry.usingSSH)
63+
repo, _, err := parseGitUrl(sourceUrl, authEntry.usingSSH)
6464
if err != nil {
6565
return "", err
6666
}
@@ -137,7 +137,7 @@ func (r *RepoCache) CheckoutRepo(sourceUrl, branch, commit, gitAuth string, isDe
137137
}
138138

139139
// Figure on which repo to clone
140-
repo, folder, err := parseGithubUrl(sourceUrl, authEntry.usingSSH)
140+
repo, folder, err := parseGitUrl(sourceUrl, authEntry.usingSSH)
141141
if err != nil {
142142
return "", "", "", "", err
143143
}

internal/server/server_test.go

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import (
1010
"github.com/openrundev/openrun/internal/testutil"
1111
)
1212

13-
func TestParseGithub(t *testing.T) {
13+
func TestParseGitUrl(t *testing.T) {
1414
tests := map[string]struct {
1515
url string
1616
wantRepo string
@@ -21,16 +21,22 @@ func TestParseGithub(t *testing.T) {
2121
"org and repo only": {url: "github.com/orgName/repoName", wantRepo: "https://github.com/orgName/repoName", wantFolder: "", wantError: nil},
2222
"org, repo and folder": {url: "http://github.com/orgName/repoName/folderName", wantRepo: "http://github.com/orgName/repoName", wantFolder: "folderName/", wantError: nil},
2323
"org, repo and subfolders": {url: "https://github.com/orgName/repoName/folderName/sub", wantRepo: "https://github.com/orgName/repoName", wantFolder: "folderName/sub/", wantError: nil},
24-
"giturl": {url: "git@github.com:user/repo.git", wantRepo: "git@github.com:user/repo.git", wantFolder: "", wantError: nil},
25-
"giturl and folder": {url: "git@github.com:user/repo.git/folderName", wantRepo: "git@github.com:user/repo.git", wantFolder: "folderName/", wantError: nil},
26-
"giturl and subfolders": {url: "git@github.com:user/repo.git/folderName/sub", wantRepo: "git@github.com:user/repo.git", wantFolder: "folderName/sub/", wantError: nil},
27-
"invalid giturl": {url: "git@github.com:user", wantRepo: "", wantFolder: "", wantError: fmt.Errorf("invalid github url: git@github.com:user/, expected git@github.com:orgName/repoName or git@github.com:orgName/repoName/folder")},
28-
"invalid url": {url: "/orgName", wantRepo: "", wantFolder: "", wantError: fmt.Errorf("invalid github url: https:///orgName/, expected github.com/orgName/repoName or github.com/orgName/repoName/folder")},
24+
"gitlab group and subgroup and subfolders": {url: "gitlab.com/g16004341/g2/pr1//app1", wantRepo: "https://gitlab.com/g16004341/g2/pr1", wantFolder: "app1/", wantError: nil},
25+
"gitlab group and subgroup and subfolders2": {url: "gitlab.com/g16004341/pr1//app1", wantRepo: "https://gitlab.com/g16004341/pr1", wantFolder: "app1/", wantError: nil},
26+
"gitlab group and subgroup and subfolders3": {url: "gitlab.com/g16004341/g2/pr1//", wantRepo: "https://gitlab.com/g16004341/g2/pr1", wantFolder: "", wantError: nil},
27+
"giturl": {url: "git@github.com:user/repo.git", wantRepo: "git@github.com:user/repo.git", wantFolder: "", wantError: nil},
28+
"giturl and folder": {url: "git@github.com:user/repo.git/folderName", wantRepo: "git@github.com:user/repo.git", wantFolder: "folderName/", wantError: nil},
29+
"giturl and subfolders": {url: "git@github.com:user/repo.git/folderName/sub", wantRepo: "git@github.com:user/repo.git", wantFolder: "folderName/sub/", wantError: nil},
30+
"gitlab with subfolders": {url: "git@github.com:user/g1/g2/repo.git//folderName/sub", wantRepo: "git@github.com:user/g1/g2/repo.git", wantFolder: "folderName/sub/", wantError: nil},
31+
"gitlab with subfolders2": {url: "git@github.com:user/repo.git//sub", wantRepo: "git@github.com:user/repo.git", wantFolder: "sub/", wantError: nil},
32+
"gitlab with subfolders3": {url: "git@github.com:user/g1/repo.git//", wantRepo: "git@github.com:user/g1/repo.git", wantFolder: "", wantError: nil},
33+
"invalid giturl": {url: "git@github.com:user", wantRepo: "", wantFolder: "", wantError: fmt.Errorf("invalid github url: git@github.com:user/, expected git@github.com:orgName/repoName or git@github.com:orgName/repoName/folder")},
34+
"invalid url": {url: "/orgName", wantRepo: "", wantFolder: "", wantError: fmt.Errorf("invalid github url: https:///orgName/, expected github.com/orgName/repoName or github.com/orgName/repoName/folder")},
2935
}
3036

3137
for name, tc := range tests {
3238
t.Run(name, func(t *testing.T) {
33-
gotRepo, gotFolder, gotError := parseGithubUrl(tc.url, false)
39+
gotRepo, gotFolder, gotError := parseGitUrl(tc.url, false)
3440
testutil.AssertEqualsString(t, "repo", gotRepo, tc.wantRepo)
3541
testutil.AssertEqualsString(t, "folder", gotFolder, tc.wantFolder)
3642
testutil.AssertEqualsError(t, "error", gotError, tc.wantError)
@@ -45,20 +51,22 @@ func TestParseGithubAuth(t *testing.T) {
4551
wantFolder string
4652
wantError error
4753
}{
48-
"blank": {url: "", wantRepo: "", wantFolder: "", wantError: fmt.Errorf("invalid github url: https:///, expected github.com/orgName/repoName or github.com/orgName/repoName/folder")},
49-
"org and repo only": {url: "github.com/orgName/repoName", wantRepo: "git@github.com:orgName/repoName.git", wantFolder: "", wantError: nil},
50-
"org, repo and folder": {url: "http://github.com/orgName/repoName/folderName", wantRepo: "git@github.com:orgName/repoName.git", wantFolder: "folderName/", wantError: nil},
51-
"org, repo and subfolders": {url: "https://github.com/orgName/repoName/folderName/sub", wantRepo: "git@github.com:orgName/repoName.git", wantFolder: "folderName/sub/", wantError: nil},
52-
"giturl": {url: "git@github.com:user/repo.git", wantRepo: "git@github.com:user/repo.git", wantFolder: "", wantError: nil},
53-
"giturl and folder": {url: "git@github.com:user/repo.git/folderName", wantRepo: "git@github.com:user/repo.git", wantFolder: "folderName/", wantError: nil},
54-
"giturl and subfolders": {url: "git@github.com:user/repo.git/folderName/sub", wantRepo: "git@github.com:user/repo.git", wantFolder: "folderName/sub/", wantError: nil},
55-
"invalid giturl": {url: "git@github.com:user", wantRepo: "", wantFolder: "", wantError: fmt.Errorf("invalid github url: git@github.com:user/, expected git@github.com:orgName/repoName or git@github.com:orgName/repoName/folder")},
56-
"invalid url": {url: "/orgName", wantRepo: "", wantFolder: "", wantError: fmt.Errorf("invalid github url: https:///orgName/, expected github.com/orgName/repoName or github.com/orgName/repoName/folder")},
54+
"blank": {url: "", wantRepo: "", wantFolder: "", wantError: fmt.Errorf("invalid github url: https:///, expected github.com/orgName/repoName or github.com/orgName/repoName/folder")},
55+
"org and repo only": {url: "github.com/orgName/repoName", wantRepo: "git@github.com:orgName/repoName.git", wantFolder: "", wantError: nil},
56+
"org, repo and folder": {url: "http://github.com/orgName/repoName/folderName", wantRepo: "git@github.com:orgName/repoName.git", wantFolder: "folderName/", wantError: nil},
57+
"org, repo and subfolders": {url: "https://github.com/orgName/repoName/folderName/sub", wantRepo: "git@github.com:orgName/repoName.git", wantFolder: "folderName/sub/", wantError: nil},
58+
"gitlab http with subfolders": {url: "https://github.com/orgName/g1/repoName//folderName/sub", wantRepo: "git@github.com:orgName/g1/repoName.git", wantFolder: "folderName/sub/", wantError: nil},
59+
"giturl": {url: "git@github.com:user/repo.git", wantRepo: "git@github.com:user/repo.git", wantFolder: "", wantError: nil},
60+
"giturl and folder": {url: "git@github.com:user/repo.git/folderName", wantRepo: "git@github.com:user/repo.git", wantFolder: "folderName/", wantError: nil},
61+
"giturl and subfolders": {url: "git@github.com:user/repo.git/folderName/sub", wantRepo: "git@github.com:user/repo.git", wantFolder: "folderName/sub/", wantError: nil},
62+
"gitlab with subfolders": {url: "git@github.com:user/g1/repo.git//folderName/sub", wantRepo: "git@github.com:user/g1/repo.git", wantFolder: "folderName/sub/", wantError: nil},
63+
"invalid giturl": {url: "git@github.com:user", wantRepo: "", wantFolder: "", wantError: fmt.Errorf("invalid github url: git@github.com:user/, expected git@github.com:orgName/repoName or git@github.com:orgName/repoName/folder")},
64+
"invalid url": {url: "/orgName", wantRepo: "", wantFolder: "", wantError: fmt.Errorf("invalid github url: https:///orgName/, expected github.com/orgName/repoName or github.com/orgName/repoName/folder")},
5765
}
5866

5967
for name, tc := range tests {
6068
t.Run(name, func(t *testing.T) {
61-
gotRepo, gotFolder, gotError := parseGithubUrl(tc.url, true)
69+
gotRepo, gotFolder, gotError := parseGitUrl(tc.url, true)
6270
testutil.AssertEqualsString(t, "repo", gotRepo, tc.wantRepo)
6371
testutil.AssertEqualsString(t, "folder", gotFolder, tc.wantFolder)
6472
testutil.AssertEqualsError(t, "error", gotError, tc.wantError)

0 commit comments

Comments
 (0)