Skip to content

Commit 05ecddc

Browse files
committed
add url parser and test for git remote url parser
1 parent c1882be commit 05ecddc

File tree

4 files changed

+86
-34
lines changed

4 files changed

+86
-34
lines changed

internal/command/scan/handler.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ func (h *Handler) Execute(ctx context.Context) (constant.ExitCode, error) {
6767
h.stopLoadingMessage()
6868

6969
if !h.Args.Quiet {
70-
fmt.Fprintf(w, "Project name: %s\nGit provider: %s\n", repoMetadata.Name, repoMetadata.Provider)
70+
fmt.Fprintf(w, "Project name: %s\nGit provider: %s\n", repoMetadata.RepoName, repoMetadata.Provider)
7171
if h.Args.Format == "" || h.Args.Format == FormatPretty {
7272
fmt.Fprintf(w, "Format: %s (default)\n", FormatPretty)
7373
} else {
@@ -88,15 +88,15 @@ func (h *Handler) Execute(ctx context.Context) (constant.ExitCode, error) {
8888
}
8989

9090
// pass the list of the tracked files and compress it into zip file.
91-
h.displayCompressingMessage(repoMetadata.Name)
92-
projectZipBuf, err := h.Archiver.OutputZipToIOReader(repoMetadata.Path, filepaths)
91+
h.displayCompressingMessage(repoMetadata.RepoName)
92+
projectZipBuf, err := h.Archiver.OutputZipToIOReader(repoMetadata.DirPath, filepaths)
9393
if err != nil {
9494
return constant.ErrorExitCode, err
9595
}
9696
h.stopLoadingMessage()
9797

9898
// create presigned url for uploading the compressed file
99-
projectZipName := fmt.Sprintf("%s_%s.tar.gz", repoMetadata.Name, repoMetadata.CommitHash)
99+
projectZipName := fmt.Sprintf("%s_%s.tar.gz", repoMetadata.RepoName, repoMetadata.CommitHash)
100100
createUploadURLReq := &grclient.CreateUploadURLReq{
101101
File: projectZipName,
102102
}
@@ -119,7 +119,7 @@ func (h *Handler) Execute(ctx context.Context) (constant.ExitCode, error) {
119119

120120
// call GuardRails trigger scan API
121121
triggerScanReq := &grclient.TriggerScanReq{
122-
Repository: repoMetadata.Name,
122+
Repository: repoMetadata.RepoName,
123123
SHA: repoMetadata.CommitHash,
124124
Branch: repoMetadata.Branch,
125125
FileName: projectZipName,
@@ -129,7 +129,7 @@ func (h *Handler) Execute(ctx context.Context) (constant.ExitCode, error) {
129129
return constant.ErrorExitCode, err
130130
}
131131

132-
h.displayRetrievingScanResultMessage(repoMetadata.Name)
132+
h.displayRetrievingScanResultMessage(repoMetadata.RepoName)
133133
bo := backoff.NewConstantBackOff(h.Config.HttpClient.PollingInterval)
134134
backoffCtx, backoffCtxCancel := context.WithTimeout(ctx, h.Config.HttpClient.RetryTimeout)
135135
defer backoffCtxCancel()

internal/command/scan/handler_test.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,10 @@ func TestScanCommandExecuteSuccess(t *testing.T) {
5151
commitHash := fmt.Sprintf("%x", encrypted)
5252

5353
repoMetadata := &repository.Metadata{
54-
Path: args.Path,
54+
DirPath: args.Path,
5555
Protocol: "https",
5656
Provider: "github",
57-
Name: gofakeit.AppName(),
57+
RepoName: gofakeit.AppName(),
5858
Branch: gofakeit.Word(),
5959
CommitHash: commitHash,
6060
}
@@ -92,7 +92,7 @@ func TestScanCommandExecuteSuccess(t *testing.T) {
9292
"internal/tools/spinner/spinner.go",
9393
"main.go",
9494
}
95-
fileZipName := fmt.Sprintf("%s_%s.tar.gz", repoMetadata.Name, repoMetadata.CommitHash)
95+
fileZipName := fmt.Sprintf("%s_%s.tar.gz", repoMetadata.RepoName, repoMetadata.CommitHash)
9696
fileZipByte := bytes.NewReader([]byte{})
9797
createUploadURLReq := &grclient.CreateUploadURLReq{
9898
File: fileZipName,
@@ -105,7 +105,7 @@ func TestScanCommandExecuteSuccess(t *testing.T) {
105105
File: fileZipByte,
106106
}
107107
triggerScanReq := &grclient.TriggerScanReq{
108-
Repository: repoMetadata.Name,
108+
Repository: repoMetadata.RepoName,
109109
SHA: repoMetadata.CommitHash,
110110
Branch: repoMetadata.Branch,
111111
FileName: fileZipName,
@@ -129,7 +129,7 @@ func TestScanCommandExecuteSuccess(t *testing.T) {
129129
gomock.InOrder(
130130
mockRepo.EXPECT().GetMetadataFromRemoteURL().Return(repoMetadata, nil),
131131
mockRepo.EXPECT().ListFiles().Return(listOfFiles, nil),
132-
mockArc.EXPECT().OutputZipToIOReader(repoMetadata.Path, listOfFiles).Return(fileZipByte, nil),
132+
mockArc.EXPECT().OutputZipToIOReader(repoMetadata.DirPath, listOfFiles).Return(fileZipByte, nil),
133133
mockGrClient.EXPECT().CreateUploadURL(ctx, createUploadURLReq).Return(createUploadURLResp, nil),
134134
mockGrClient.EXPECT().UploadProject(ctx, uploadProjectReq).Return(nil),
135135
mockGrClient.EXPECT().TriggerScan(ctx, triggerScanReq).Return(triggerScanResp, nil),

internal/repository/repository.go

Lines changed: 41 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"fmt"
66
"io"
77
"regexp"
8+
"strings"
89

910
"github.com/go-git/go-git/v5"
1011
"github.com/go-git/go-git/v5/plumbing/object"
@@ -40,12 +41,14 @@ type repository struct {
4041

4142
// Metadata contains repository metadata.
4243
type Metadata struct {
43-
Path string
44-
Protocol string
45-
Provider string
46-
Name string
47-
Branch string
48-
CommitHash string
44+
DirPath string
45+
Protocol string
46+
Provider string
47+
UserAccount string
48+
RemoteURL string
49+
RepoName string
50+
Branch string
51+
CommitHash string
4952
}
5053

5154
// New instantiates new repository.
@@ -59,7 +62,7 @@ func New(projectPath string) (Repository, error) {
5962
return nil, err
6063
}
6164

62-
return &repository{client: client, Metadata: &Metadata{Path: projectPath}}, nil
65+
return &repository{client: client, Metadata: &Metadata{DirPath: projectPath}}, nil
6366
}
6467

6568
// GetMetadataFromRemoteURL implements repository.Repository interface.
@@ -75,19 +78,8 @@ func (r *repository) GetMetadataFromRemoteURL() (*Metadata, error) {
7578
return nil, ErrGitRemoteURLNotFound
7679
}
7780

78-
remoteURL := remoteURLs[0]
79-
80-
re := regexp.MustCompile(`(?P<Protocol>git@|http(s)?:\/\/)(.+@)*(?P<Provider>[\w\d\.-]+)(:[\d]+){0,1}(\/scm)?\/*(?P<Name>.*)`)
81-
matches := re.FindStringSubmatch(remoteURL)
82-
83-
protocolRe := regexp.MustCompile(`[^\w]`)
84-
protocol := protocolRe.ReplaceAllString(matches[re.SubexpIndex("Protocol")], "")
85-
86-
providerRe := regexp.MustCompile(`^([\w\d-]+)([\.\w\d]*)`)
87-
provider := providerRe.FindStringSubmatch(matches[re.SubexpIndex("Provider")])
88-
89-
nameRe := regexp.MustCompile(`\/(.*)\.git$`)
90-
name := nameRe.FindStringSubmatch(matches[re.SubexpIndex("Name")])
81+
// retrieves all possible information from git remote url.
82+
getMetadataFromRemoteURL(r.Metadata, remoteURLs[0])
9183

9284
ref, err := r.client.Head()
9385
if err != nil {
@@ -97,15 +89,41 @@ func (r *repository) GetMetadataFromRemoteURL() (*Metadata, error) {
9789
branchRe := regexp.MustCompile(`([^\/]+$)`)
9890
branch := branchRe.FindString(ref.Name().String())
9991

100-
r.Metadata.Protocol = protocol
101-
r.Metadata.Provider = provider[1]
102-
r.Metadata.Name = name[1]
92+
r.Metadata.RemoteURL = remoteURLs[0]
10393
r.Metadata.Branch = branch
10494
r.Metadata.CommitHash = ref.Hash().String()
10595

10696
return r.Metadata, nil
10797
}
10898

99+
func getMetadataFromRemoteURL(metadata *Metadata, gitRemoteURL string) {
100+
re := regexp.MustCompile(`(?P<Protocol>git@|http(s)?:\/\/)(.+@)*(?P<Provider>[\w\d\.-]+)(:[\d]+){0,1}(\/scm)?\/*(?P<Name>.*)`)
101+
matches := re.FindStringSubmatch(gitRemoteURL)
102+
103+
protocolRe := regexp.MustCompile(`[^\w]`)
104+
protocol := protocolRe.ReplaceAllString(matches[re.SubexpIndex("Protocol")], "")
105+
106+
providerRe := regexp.MustCompile(`^([\w\d-]+)([\.\w\d]*)`)
107+
provider := providerRe.FindStringSubmatch(matches[re.SubexpIndex("Provider")])
108+
109+
// use url parser to extract username and repository name by extracting the last 2 parts of the url
110+
urlParts := strings.Split(gitRemoteURL, "/")
111+
112+
userAccount := urlParts[len(urlParts)-2]
113+
// remove the "[email protected]:" from user account part if exists
114+
userAccountParts := strings.Split(userAccount, ":")
115+
if len(userAccountParts) > 1 {
116+
userAccount = userAccountParts[1]
117+
}
118+
119+
repoName := strings.TrimSuffix(urlParts[len(urlParts)-1], ".git")
120+
121+
metadata.Protocol = protocol
122+
metadata.Provider = provider[1]
123+
metadata.UserAccount = userAccount
124+
metadata.RepoName = repoName
125+
}
126+
109127
// ListFiles implements repository.Repository interface.
110128
func (r *repository) ListFiles() ([]string, error) {
111129
filepaths := make([]string, 0)
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package repository
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
7+
"github.com/brianvoe/gofakeit/v6"
8+
"github.com/stretchr/testify/assert"
9+
)
10+
11+
func TestParseGitRemoteURLToMetadataSuccess(t *testing.T) {
12+
userAccount := gofakeit.Username()
13+
repoName := fmt.Sprintf("%s-%s", gofakeit.LoremIpsumWord(), gofakeit.LoremIpsumWord())
14+
15+
urls := []string{
16+
fmt.Sprintf("[email protected]:%s/%s.git", userAccount, repoName),
17+
fmt.Sprintf("http://github.com/%s/%s.git", userAccount, repoName),
18+
fmt.Sprintf("https://github.com/%s/%s.git", userAccount, repoName),
19+
fmt.Sprintf("http://username:password@bitbucket-server:7990/scm/%s/%s.git", userAccount, repoName),
20+
fmt.Sprintf("https://gitlab-on-premise.com/%s/%s.git", userAccount, repoName),
21+
fmt.Sprintf("http://username:password@gitlab-ee/scm/%s/%s.git", userAccount, repoName),
22+
fmt.Sprintf("https://username:[email protected]/prefix1/prefix2/prefix3/%s/%s.git", userAccount, repoName),
23+
}
24+
25+
metadata := new(Metadata)
26+
27+
for _, url := range urls {
28+
getMetadataFromRemoteURL(metadata, url)
29+
assert.NotEmpty(t, metadata.Protocol)
30+
assert.NotEmpty(t, metadata.Provider)
31+
assert.Equal(t, metadata.UserAccount, userAccount)
32+
assert.Equal(t, metadata.RepoName, repoName)
33+
}
34+
}

0 commit comments

Comments
 (0)