-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: new repo resolver logic to fetch info from a gcbrepov2 (#9283)
* feat: new repo resolver logic to fetch info from a gcbrepov2 * test: add unit test for repo_resolver * fix: add 2024 as valid date for boilerplate check * fix: solve comments
- Loading branch information
1 parent
e4f1975
commit db98603
Showing
264 changed files
with
28,952 additions
and
13,932 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
/* | ||
Copyright 2024 The Skaffold Authors | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
package gcbreposv2 | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"net/url" | ||
|
||
cloudbuild "cloud.google.com/go/cloudbuild/apiv2" | ||
cloudbuildpb "cloud.google.com/go/cloudbuild/apiv2/cloudbuildpb" | ||
"github.com/googleapis/gax-go/v2" | ||
) | ||
|
||
type cloudBuildRepoClient interface { | ||
GetRepository(ctx context.Context, req *cloudbuildpb.GetRepositoryRequest, opts ...gax.CallOption) (*cloudbuildpb.Repository, error) | ||
FetchReadToken(ctx context.Context, req *cloudbuildpb.FetchReadTokenRequest, opts ...gax.CallOption) (*cloudbuildpb.FetchReadTokenResponse, error) | ||
Close() error | ||
} | ||
|
||
type Repo struct { | ||
// Original repo URI. | ||
URI string | ||
|
||
// URI with oauth2 format. | ||
CloneURI string | ||
} | ||
|
||
var RepositoryManagerClient = repositoryManagerClient | ||
|
||
func GetRepoInfo(ctx context.Context, gcpProject, gcpRegion, gcpConnectionName, gcpRepoName string) (Repo, error) { | ||
cbRepoRef := fmt.Sprintf("projects/%v/locations/%v/connections/%v/repositories/%v", gcpProject, gcpRegion, gcpConnectionName, gcpRepoName) | ||
cbClient, err := RepositoryManagerClient(ctx) | ||
if err != nil { | ||
return Repo{}, fmt.Errorf("failed to create repository manager client: %w", err) | ||
} | ||
defer cbClient.Close() | ||
|
||
repoURI, err := getRepoURI(ctx, cbClient, cbRepoRef) | ||
if err != nil { | ||
return Repo{}, fmt.Errorf("failed to get remote URI for repository %v: %w", gcpRepoName, err) | ||
} | ||
|
||
readAccessToken, err := getRepoReadAccessToken(ctx, cbClient, cbRepoRef) | ||
if err != nil { | ||
return Repo{}, fmt.Errorf("failed to get repository read access token for repo %v: %w", gcpRepoName, err) | ||
} | ||
|
||
repoCloneURI, err := buildRepoURIWithToken(repoURI, readAccessToken) | ||
if err != nil { | ||
return Repo{}, fmt.Errorf("failed to clone repo %s: trouble building repo URI with token: %w", repoURI, err) | ||
} | ||
|
||
return Repo{ | ||
URI: repoURI, | ||
CloneURI: repoCloneURI, | ||
}, nil | ||
} | ||
|
||
func repositoryManagerClient(ctx context.Context) (cloudBuildRepoClient, error) { | ||
return cloudbuild.NewRepositoryManagerClient(ctx) | ||
} | ||
|
||
func getRepoURI(ctx context.Context, cbClient cloudBuildRepoClient, cbRepoRef string) (string, error) { | ||
req := &cloudbuildpb.GetRepositoryRequest{ | ||
Name: cbRepoRef, | ||
} | ||
repoInfo, err := cbClient.GetRepository(ctx, req) | ||
if err != nil { | ||
return "", err | ||
} | ||
return repoInfo.GetRemoteUri(), nil | ||
} | ||
|
||
func getRepoReadAccessToken(ctx context.Context, cbClient cloudBuildRepoClient, cbRepoRef string) (string, error) { | ||
req := &cloudbuildpb.FetchReadTokenRequest{ | ||
Repository: cbRepoRef, | ||
} | ||
resp, err := cbClient.FetchReadToken(ctx, req) | ||
if err != nil { | ||
return "", err | ||
} | ||
return resp.GetToken(), nil | ||
} | ||
|
||
func buildRepoURIWithToken(repoURI, readAccessToken string) (string, error) { | ||
parsed, err := url.Parse(repoURI) | ||
if err != nil { | ||
return "", err | ||
} | ||
|
||
parsed.Host = fmt.Sprintf("oauth2:%v@%v", readAccessToken, parsed.Host) | ||
return url.PathUnescape(parsed.String()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
/* | ||
Copyright 2024 The Skaffold Authors | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
package gcbreposv2 | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"testing" | ||
|
||
"cloud.google.com/go/cloudbuild/apiv2/cloudbuildpb" | ||
"github.com/googleapis/gax-go/v2" | ||
|
||
"github.com/GoogleContainerTools/skaffold/v2/testutil" | ||
) | ||
|
||
type GCBReposClientMock struct { | ||
GitRepo string | ||
ReadToken string | ||
ErrorGetRepo bool | ||
ErrorGetToken bool | ||
} | ||
|
||
const ( | ||
gcpProject = "my-project" | ||
gcpRegion = "us-central1" | ||
gcbConnection = "gcb-repo-connection" | ||
gcbRepo = "repo-1" | ||
) | ||
|
||
func (c GCBReposClientMock) GetRepository(ctx context.Context, req *cloudbuildpb.GetRepositoryRequest, opts ...gax.CallOption) (*cloudbuildpb.Repository, error) { | ||
if c.ErrorGetRepo { | ||
return nil, fmt.Errorf("failed to get repo") | ||
} | ||
|
||
validRepoIdentifier := fmt.Sprintf("projects/%v/locations/%v/connections/%v/repositories/%v", gcpProject, gcpRegion, gcbConnection, gcbRepo) | ||
if req.Name != validRepoIdentifier { | ||
return nil, fmt.Errorf("invalid request, expecting %v, got %v", validRepoIdentifier, req.Name) | ||
} | ||
|
||
return &cloudbuildpb.Repository{ | ||
RemoteUri: c.GitRepo, | ||
}, nil | ||
} | ||
|
||
func (c GCBReposClientMock) FetchReadToken(ctx context.Context, req *cloudbuildpb.FetchReadTokenRequest, opts ...gax.CallOption) (*cloudbuildpb.FetchReadTokenResponse, error) { | ||
if c.ErrorGetToken { | ||
return nil, fmt.Errorf("failed to get token") | ||
} | ||
|
||
validRepoIdentifier := fmt.Sprintf("projects/%v/locations/%v/connections/%v/repositories/%v", gcpProject, gcpRegion, gcbConnection, gcbRepo) | ||
if req.Repository != validRepoIdentifier { | ||
return nil, fmt.Errorf("invalid request, expecting %v, got %v", validRepoIdentifier, req.Repository) | ||
} | ||
|
||
return &cloudbuildpb.FetchReadTokenResponse{ | ||
Token: c.ReadToken, | ||
}, nil | ||
} | ||
|
||
func (c GCBReposClientMock) Close() error { return nil } | ||
|
||
func TestGetRepoInfo(t *testing.T) { | ||
tests := []struct { | ||
description string | ||
expectedRepoInfo Repo | ||
gcbMockClient GCBReposClientMock | ||
shouldError bool | ||
errorMsg string | ||
}{ | ||
{ | ||
description: "repo info correct", | ||
expectedRepoInfo: Repo{ | ||
URI: "https://github.com/GoogleContainerTools/skaffold", | ||
CloneURI: "https://oauth2:token123@github.com/GoogleContainerTools/skaffold", | ||
}, | ||
gcbMockClient: GCBReposClientMock{ | ||
GitRepo: "https://github.com/GoogleContainerTools/skaffold", | ||
ReadToken: "token123", | ||
}, | ||
}, | ||
{ | ||
description: "failed getting GCB repo info", | ||
expectedRepoInfo: Repo{}, | ||
shouldError: true, | ||
errorMsg: fmt.Sprintf("failed to get remote URI for repository %v", gcbRepo), | ||
gcbMockClient: GCBReposClientMock{ | ||
ErrorGetRepo: true, | ||
}, | ||
}, | ||
{ | ||
description: "failed getting GCB repo read token", | ||
expectedRepoInfo: Repo{}, | ||
shouldError: true, | ||
errorMsg: fmt.Sprintf("failed to get repository read access token for repo %v", gcbRepo), | ||
gcbMockClient: GCBReposClientMock{ | ||
ErrorGetToken: true, | ||
}, | ||
}, | ||
{ | ||
description: "failed to build clone repo URI", | ||
expectedRepoInfo: Repo{}, | ||
shouldError: true, | ||
errorMsg: "failed to clone repo :not-valid: trouble building repo URI with token", | ||
gcbMockClient: GCBReposClientMock{ | ||
GitRepo: ":not-valid", | ||
ReadToken: "token123", | ||
}, | ||
}, | ||
} | ||
|
||
for _, test := range tests { | ||
testutil.Run(t, test.description, func(t *testutil.T) { | ||
ctx := context.Background() | ||
t.Override(&RepositoryManagerClient, func(ctx context.Context) (cloudBuildRepoClient, error) { | ||
return test.gcbMockClient, nil | ||
}) | ||
|
||
repoInfo, err := GetRepoInfo(ctx, gcpProject, gcpRegion, gcbConnection, gcbRepo) | ||
|
||
t.CheckError(test.shouldError, err) | ||
if test.shouldError { | ||
t.CheckErrorContains(test.errorMsg, err) | ||
} | ||
t.CheckDeepEqual(test.expectedRepoInfo, repoInfo) | ||
}) | ||
} | ||
} |
19 changes: 10 additions & 9 deletions
19
vendor/cloud.google.com/go/.release-please-manifest-individual.json
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Oops, something went wrong.