Skip to content

Commit b0a9d5c

Browse files
authored
GetRepositoryInfo for Azure Repos (#116)
1 parent 7ea0065 commit b0a9d5c

15 files changed

+177
-298
lines changed

vcsclient/azurerepos.go

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"github.com/jfrog/froggit-go/vcsutils"
1010
"github.com/jfrog/gofrog/datastructures"
1111
"github.com/microsoft/azure-devops-go-api/azuredevops"
12+
"github.com/microsoft/azure-devops-go-api/azuredevops/core"
1213
"github.com/microsoft/azure-devops-go-api/azuredevops/git"
1314
"io"
1415
"net/http"
@@ -114,16 +115,16 @@ func (client *AzureReposClient) DownloadRepository(ctx context.Context, owner, r
114115
return err
115116
}
116117
client.logger.Info(successfulRepoExtraction)
118+
repoInfo, err := client.GetRepositoryInfo(ctx, owner, repository)
119+
if err != nil {
120+
return err
121+
}
122+
httpsCloneUrl := repoInfo.CloneInfo.HTTP
117123
// Generate .git folder with remote details
118124
return vcsutils.CreateDotGitFolderWithRemote(
119125
localPath,
120126
vcsutils.RemoteName,
121-
client.GetGitRemoteURL(owner, repository))
122-
}
123-
124-
// GetGitRemoteURL on Azure Repos
125-
func (client *AzureReposClient) GetGitRemoteURL(owner, repository string) string {
126-
return fmt.Sprintf("https://%s@%s/%s/_git/%s", owner, strings.TrimPrefix(client.connectionDetails.BaseUrl, "https://"), client.vcsInfo.Project, repository)
127+
httpsCloneUrl)
127128
}
128129

129130
func (client *AzureReposClient) sendDownloadRepoRequest(ctx context.Context, repository string, branch string) (res *http.Response, err error) {
@@ -405,7 +406,33 @@ func (client *AzureReposClient) AddSshKeyToRepository(ctx context.Context, owner
405406

406407
// GetRepositoryInfo on Azure Repos
407408
func (client *AzureReposClient) GetRepositoryInfo(ctx context.Context, owner, repository string) (RepositoryInfo, error) {
408-
return RepositoryInfo{}, getUnsupportedInAzureError("get repository info")
409+
azureReposGitClient, err := client.buildAzureReposClient(ctx)
410+
if err != nil {
411+
return RepositoryInfo{}, err
412+
}
413+
response, err := azureReposGitClient.GetRepository(ctx, git.GetRepositoryArgs{
414+
RepositoryId: &repository,
415+
Project: &client.vcsInfo.Project,
416+
})
417+
if err != nil {
418+
return RepositoryInfo{}, fmt.Errorf("an error occured while retrieving <%s/%s/%s> repository info:\n%s", owner, client.vcsInfo.Project, repository, err.Error())
419+
}
420+
if response == nil {
421+
return RepositoryInfo{}, fmt.Errorf("failed to retreive <%s/%s/%s> repository info, received empty response", owner, client.vcsInfo.Project, repository)
422+
}
423+
if response.Project == nil {
424+
return RepositoryInfo{}, fmt.Errorf("failed to retreive <%s/%s/%s> repository info, received empty project info", owner, client.vcsInfo.Project, repository)
425+
}
426+
427+
visibility := Private
428+
visibilityFromResponse := *response.Project.Visibility
429+
if visibilityFromResponse == core.ProjectVisibilityValues.Public {
430+
visibility = Public
431+
}
432+
return RepositoryInfo{
433+
CloneInfo: CloneInfo{HTTP: *response.RemoteUrl, SSH: *response.SshUrl},
434+
RepositoryVisibility: visibility,
435+
}, nil
409436
}
410437

411438
// GetCommitBySha on Azure Repos

vcsclient/azurerepos_test.go

Lines changed: 49 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ func TestAzureRepos_ListRepositories(t *testing.T) {
3939
jsonRes, err := json.Marshal(res)
4040
assert.NoError(t, err)
4141
ctx := context.Background()
42-
client, cleanUp := createServerAndClient(t, vcsutils.AzureRepos, true, jsonRes, "listRepositories", createAzureReposHandler)
42+
client, cleanUp := createServerAndClient(t, vcsutils.AzureRepos, true, jsonRes, "getRepository", createAzureReposHandler)
4343
defer cleanUp()
4444
reposMap, err := client.ListRepositories(ctx)
4545
assert.NoError(t, err)
@@ -92,7 +92,7 @@ func TestAzureRepos_TestDownloadRepository(t *testing.T) {
9292
repo1,
9393
branch1)
9494
client, cleanUp := createServerAndClient(t, vcsutils.AzureRepos, true,
95-
repoFile, downloadURL, createAzureReposHandler)
95+
repoFile, downloadURL, createGetRepositoryAzureReposHandler)
9696
defer cleanUp()
9797
err = client.DownloadRepository(ctx, "", repo1, branch1, dir)
9898
assert.NoError(t, err)
@@ -449,11 +449,11 @@ func TestAzureReposClient_CreateLabel(t *testing.T) {
449449
assert.Error(t, client.CreateLabel(ctx, owner, repo1, LabelInfo{}))
450450
}
451451

452-
func TestAzureReposClient_GetRepositoryInfo(t *testing.T) {
452+
func TestAzureReposClient_GetRepositoryEnvironmentInfo(t *testing.T) {
453453
ctx := context.Background()
454454
client, cleanUp := createServerAndClient(t, vcsutils.AzureRepos, true, "", "unsupportedTest", createAzureReposHandler)
455455
defer cleanUp()
456-
_, err := client.GetRepositoryInfo(ctx, owner, repo1)
456+
_, err := client.GetRepositoryEnvironmentInfo(ctx, owner, repo1, "")
457457
assert.Error(t, err)
458458
}
459459

@@ -547,19 +547,22 @@ func TestAzureReposClient_SetCommitStatus(t *testing.T) {
547547
assert.Error(t, err)
548548
}
549549

550-
func TestAzureReposClient_GetLabel(t *testing.T) {
550+
func TestAzureReposClient_GetRepositoryInfo(t *testing.T) {
551551
ctx := context.Background()
552-
client, cleanUp := createServerAndClient(t, vcsutils.AzureRepos, true, "", "unsupportedTest", createAzureReposHandler)
552+
client, cleanUp := createServerAndClient(t, vcsutils.AzureRepos, true, "", "/_apis/ResourceAreas/getRepository", createGetRepositoryAzureReposHandler)
553553
defer cleanUp()
554-
_, err := client.GetLabel(ctx, owner, repo1, "")
555-
assert.Error(t, err)
554+
repositoryInfo, err := client.GetRepositoryInfo(ctx, "jfrog", "froggit-go")
555+
assert.NoError(t, err)
556+
assert.Equal(t, "https://jfrog@dev.azure.com/jfrog/froggit-go/_git/froggit-go", repositoryInfo.CloneInfo.HTTP)
557+
assert.Equal(t, "git@ssh.dev.azure.com:v3/jfrog/froggit-go/froggit-go", repositoryInfo.CloneInfo.SSH)
558+
assert.Equal(t, repositoryInfo.RepositoryVisibility, Public)
556559
}
557560

558-
func TestAzureReposClient_GetRepositoryEnvironmentInfo(t *testing.T) {
561+
func TestAzureReposClient_GetLabel(t *testing.T) {
559562
ctx := context.Background()
560563
client, cleanUp := createServerAndClient(t, vcsutils.AzureRepos, true, "", "unsupportedTest", createAzureReposHandler)
561564
defer cleanUp()
562-
_, err := client.GetRepositoryEnvironmentInfo(ctx, owner, repo1, envName)
565+
_, err := client.GetLabel(ctx, owner, repo1, "")
563566
assert.Error(t, err)
564567
}
565568

@@ -695,13 +698,14 @@ func createAzureReposHandler(t *testing.T, expectedURI string, response []byte,
695698
return func(w http.ResponseWriter, r *http.Request) {
696699
base64Token := base64.StdEncoding.EncodeToString([]byte(":" + token))
697700
assert.Equal(t, "Basic "+base64Token, r.Header.Get("Authorization"))
698-
if r.RequestURI == "/_apis" {
701+
switch r.RequestURI {
702+
case "/_apis":
699703
jsonVal, err := os.ReadFile(filepath.Join("./", "testdata", "azurerepos", "resourcesResponse.json"))
700704
assert.NoError(t, err)
701705
_, err = w.Write(jsonVal)
702706
assert.NoError(t, err)
703707
return
704-
} else if r.RequestURI == "/_apis/ResourceAreas" {
708+
case "/_apis/ResourceAreas":
705709
jsonVal := `{"value": [],"count": 0}`
706710
_, err := w.Write([]byte(jsonVal))
707711
assert.NoError(t, err)
@@ -719,6 +723,39 @@ func createAzureReposHandler(t *testing.T, expectedURI string, response []byte,
719723
}
720724
}
721725

726+
func createGetRepositoryAzureReposHandler(t *testing.T, expectedURI string, response []byte, expectedStatusCode int) http.HandlerFunc {
727+
return func(w http.ResponseWriter, r *http.Request) {
728+
base64Token := base64.StdEncoding.EncodeToString([]byte(":" + token))
729+
assert.Equal(t, "Basic "+base64Token, r.Header.Get("Authorization"))
730+
switch r.RequestURI {
731+
case "/_apis":
732+
jsonVal, err := os.ReadFile(filepath.Join("./", "testdata", "azurerepos", "resourcesResponse.json"))
733+
assert.NoError(t, err)
734+
_, err = w.Write(jsonVal)
735+
assert.NoError(t, err)
736+
return
737+
case "/_apis/ResourceAreas":
738+
jsonVal := `{"value": [],"count": 0}`
739+
_, err := w.Write([]byte(jsonVal))
740+
assert.NoError(t, err)
741+
return
742+
case "/_apis/ResourceAreas/getRepository":
743+
jsonVal := `{"id":"23d122fb-c6c1-4f03-8117-a10a08f8b0d6","name":"froggit-go","url":"https://dev.azure.com/jfrog/638e3921-f5e3-46e6-a11f-a139cb9bd511/_apis/git/repositories/23d122fb-c6c1-4f03-8117-a10a08f8b0d6","project":{"id":"638e3921-f5e3-46e6-a11f-a139cb9bd511","name":"froggit-go","visibility":"public"},"defaultBranch":"refs/heads/main","remoteUrl":"https://jfrog@dev.azure.com/jfrog/froggit-go/_git/froggit-go","sshUrl":"git@ssh.dev.azure.com:v3/jfrog/froggit-go/froggit-go","isDisabled":false,"isInMaintenance":false}`
744+
_, err := w.Write([]byte(jsonVal))
745+
assert.NoError(t, err)
746+
return
747+
}
748+
749+
if !strings.Contains(expectedURI, "bad^endpoint") {
750+
assert.Contains(t, r.RequestURI, expectedURI)
751+
w.WriteHeader(expectedStatusCode)
752+
_, err := w.Write(response)
753+
assert.NoError(t, err)
754+
return
755+
}
756+
w.WriteHeader(http.StatusNotFound)
757+
}
758+
}
722759
func createBadAzureReposClient(t *testing.T, response []byte) (VcsClient, func()) {
723760
client, cleanUp := createServerAndClient(
724761
t,
@@ -732,23 +769,3 @@ func createBadAzureReposClient(t *testing.T, response []byte) (VcsClient, func()
732769
createAzureReposHandler)
733770
return client, cleanUp
734771
}
735-
736-
func TestAzureReposClient_GetGitRemoteUrl(t *testing.T) {
737-
testCase := struct {
738-
name string
739-
apiEndpoint string
740-
owner string
741-
repo string
742-
expectedResult string
743-
}{
744-
name: "Azure Repos Cloud",
745-
apiEndpoint: "https://dev.azure.com/my-org",
746-
owner: "my-org",
747-
repo: "my-repo",
748-
expectedResult: "https://my-org@dev.azure.com/my-org/project/_git/my-repo",
749-
}
750-
info := VcsInfo{APIEndpoint: testCase.apiEndpoint, Project: "project"}
751-
client, err := NewAzureReposClient(info, nil)
752-
assert.NoError(t, err)
753-
assert.Equal(t, testCase.expectedResult, client.GetGitRemoteURL(testCase.owner, testCase.repo))
754-
}

vcsclient/bitbucketcloud.go

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -274,14 +274,12 @@ func (client *BitbucketCloudClient) DownloadRepository(ctx context.Context, owne
274274
return err
275275
}
276276
client.logger.Info(successfulRepoExtraction)
277+
repositoryInfo, err := client.GetRepositoryInfo(ctx, owner, repository)
278+
if err != nil {
279+
return err
280+
}
277281
// Generate .git folder with remote details
278-
return vcsutils.CreateDotGitFolderWithRemote(localPath, "origin",
279-
client.GetGitRemoteURL(owner, repository))
280-
}
281-
282-
// GetGitRemoteURL on Bitbucket Cloud
283-
func (client *BitbucketCloudClient) GetGitRemoteURL(owner, repository string) string {
284-
return vcsutils.GetGenericGitRemoteUrl(client.vcsInfo.APIEndpoint, owner, repository)
282+
return vcsutils.CreateDotGitFolderWithRemote(localPath, "origin", repositoryInfo.CloneInfo.HTTP)
285283
}
286284

287285
// CreatePullRequest on Bitbucket cloud

vcsclient/bitbucketcloud_test.go

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -151,26 +151,6 @@ func TestBitbucketCloud_CreatePullRequest(t *testing.T) {
151151
assert.NoError(t, err)
152152
}
153153

154-
func TestBitbucketCloudClient_GetGitRemoteUrl(t *testing.T) {
155-
testCase := struct {
156-
name string
157-
apiEndpoint string
158-
owner string
159-
repo string
160-
expectedResult string
161-
}{
162-
name: "Bitbucket Cloud",
163-
apiEndpoint: "https://bitbucket.org",
164-
owner: "my-org",
165-
repo: "my-repo",
166-
expectedResult: "https://bitbucket.org/my-org/my-repo.git",
167-
}
168-
info := VcsInfo{APIEndpoint: testCase.apiEndpoint}
169-
client, err := NewBitbucketCloudClient(info, nil)
170-
assert.NoError(t, err)
171-
assert.Equal(t, testCase.expectedResult, client.GetGitRemoteURL(testCase.owner, testCase.repo))
172-
}
173-
174154
func TestBitbucketCloudClient_UpdatePullRequest(t *testing.T) {
175155
ctx := context.Background()
176156
prId := 3

vcsclient/bitbucketserver.go

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -266,16 +266,15 @@ func (client *BitbucketServerClient) DownloadRepository(ctx context.Context, own
266266
return err
267267
}
268268
client.logger.Info(successfulRepoExtraction)
269+
repositoryInfo, err := client.GetRepositoryInfo(ctx, owner, repository)
270+
if err != nil {
271+
return err
272+
}
269273
// Generate .git folder with remote details
270274
return vcsutils.CreateDotGitFolderWithRemote(
271275
localPath,
272276
vcsutils.RemoteName,
273-
client.GetGitRemoteURL(owner, repository))
274-
}
275-
276-
// GetGitRemoteURL on Bitbucket Server
277-
func (client *BitbucketServerClient) GetGitRemoteURL(owner, repository string) string {
278-
return vcsutils.GetGenericGitRemoteUrl(fmt.Sprintf("%s/scm", strings.TrimSuffix(client.vcsInfo.APIEndpoint, "/rest")), owner, repository)
277+
repositoryInfo.CloneInfo.HTTP)
279278
}
280279

281280
// CreatePullRequest on Bitbucket server

vcsclient/bitbucketserver_test.go

Lines changed: 17 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ func TestBitbucketServer_DownloadRepository(t *testing.T) {
158158
assert.NoError(t, err)
159159

160160
client, cleanUp := createServerAndClient(t, vcsutils.BitbucketServer, false, repoFile,
161-
fmt.Sprintf("/rest/api/1.0/projects/%s/repos/%s/archive?format=tgz", owner, repo1), createBitbucketServerHandler)
161+
fmt.Sprintf("/rest/api/1.0/projects/%s/repos/%s/archive?format=tgz", owner, repo1), createBitbucketServerDownloadRepositoryHandler)
162162
defer cleanUp()
163163
err = client.DownloadRepository(ctx, owner, repo1, "", dir)
164164
assert.NoError(t, err)
@@ -718,6 +718,22 @@ func createBitbucketServerHandler(t *testing.T, expectedURI string, response []b
718718
}
719719
}
720720

721+
func createBitbucketServerDownloadRepositoryHandler(t *testing.T, expectedURI string, response []byte, expectedStatusCode int) http.HandlerFunc {
722+
return func(w http.ResponseWriter, r *http.Request) {
723+
if r.RequestURI == "/rest/api/1.0/projects/jfrog/repos/repo-1" {
724+
repositoryResponse, err := os.ReadFile(filepath.Join("testdata", "bitbucketserver", "repository_response.json"))
725+
assert.NoError(t, err)
726+
_, err = w.Write(repositoryResponse)
727+
assert.NoError(t, err)
728+
}
729+
w.WriteHeader(expectedStatusCode)
730+
_, err := w.Write(response)
731+
assert.NoError(t, err)
732+
assert.Contains(t, expectedURI, r.RequestURI)
733+
assert.Equal(t, "Bearer "+token, r.Header.Get("Authorization"))
734+
}
735+
}
736+
721737
func createBitbucketServerListRepositoriesHandler(t *testing.T, _ string, _ []byte, expectedStatusCode int) http.HandlerFunc {
722738
return func(w http.ResponseWriter, r *http.Request) {
723739
var responseObj interface{}
@@ -834,24 +850,3 @@ func createBadBitbucketServerClient(t *testing.T) VcsClient {
834850
assert.NoError(t, err)
835851
return client
836852
}
837-
838-
func TestBitbucketServerClient_GetGitRemoteUrl(t *testing.T) {
839-
testCase := struct {
840-
name string
841-
apiEndpoint string
842-
owner string
843-
repo string
844-
expectedResult string
845-
}{
846-
name: "Bitbucket On-Premises",
847-
apiEndpoint: "https://git.example.com",
848-
owner: "my-org",
849-
repo: "my-repo",
850-
expectedResult: "https://git.example.com/scm/my-org/my-repo.git",
851-
}
852-
info := VcsInfo{APIEndpoint: testCase.apiEndpoint}
853-
client, err := NewBitbucketServerClient(info, nil)
854-
assert.NoError(t, err)
855-
assert.Equal(t, testCase.expectedResult, client.GetGitRemoteURL(testCase.owner, testCase.repo))
856-
857-
}

vcsclient/github.go

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,6 @@ import (
2020
"golang.org/x/oauth2"
2121
)
2222

23-
const (
24-
GitHubApiVersion = "/api/v3"
25-
GitHubCloudBaseUrl = "https://github.com"
26-
)
27-
2823
// GitHubClient API version 3
2924
type GitHubClient struct {
3025
vcsInfo VcsInfo
@@ -251,17 +246,15 @@ func (client *GitHubClient) DownloadRepository(ctx context.Context, owner, repos
251246
return
252247
}
253248

249+
repositoryInfo, err := client.GetRepositoryInfo(ctx, owner, repository)
250+
if err != nil {
251+
return err
252+
}
254253
client.logger.Info(successfulRepoExtraction)
255-
err = vcsutils.CreateDotGitFolderWithRemote(localPath, vcsutils.RemoteName, client.GetGitRemoteURL(owner, repository))
254+
err = vcsutils.CreateDotGitFolderWithRemote(localPath, vcsutils.RemoteName, repositoryInfo.CloneInfo.HTTP)
256255
return
257256
}
258257

259-
// GetGitRemoteURL on GitHub
260-
func (client *GitHubClient) GetGitRemoteURL(owner, repository string) string {
261-
baseUrl := vcsutils.GetBaseURLFromApiEndpoint(client.vcsInfo.APIEndpoint, GitHubCloudBaseUrl, GitHubApiVersion)
262-
return vcsutils.GetGenericGitRemoteUrl(baseUrl, owner, repository)
263-
}
264-
265258
// CreatePullRequest on GitHub
266259
func (client *GitHubClient) CreatePullRequest(ctx context.Context, owner, repository, sourceBranch, targetBranch,
267260
title, description string) error {

0 commit comments

Comments
 (0)