Skip to content

Commit

Permalink
return error if gh client returns 404 to bubble up the workaround
Browse files Browse the repository at this point in the history
  • Loading branch information
chrischdi committed Mar 9, 2023
1 parent a8841fb commit 42e0607
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 3 deletions.
13 changes: 12 additions & 1 deletion cmd/clusterctl/client/repository/repository_github.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ const (
)

var (
errNotFound = errors.New("404 Not Found")

// Caches used to limit the number of GitHub API calls.

cacheVersions = map[string][]string{}
Expand Down Expand Up @@ -226,7 +228,7 @@ func NewGitHubRepository(providerConfig config.Provider, configVariablesClient c
if defaultVersion == githubLatestReleaseLabel {
repo.defaultVersion, err = latestContractRelease(repo, clusterv1.GroupVersion.Version)
if err != nil {
return nil, errors.Wrap(err, "failed to get GitHub latest version")
return nil, errors.Wrap(err, "failed to get latest release")
}
}

Expand Down Expand Up @@ -332,6 +334,10 @@ func (g *gitHubRepository) getReleaseByTag(tag string) (*github.RepositoryReleas
release, _, getReleasesErr = client.Repositories.GetReleaseByTag(context.TODO(), g.owner, g.repository, tag)
if getReleasesErr != nil {
retryError = g.handleGithubErr(getReleasesErr, "failed to read release %q", tag)
// return immediately if not found
if errors.Is(retryError, errNotFound) {
return false, retryError
}
// return immediately if we are rate limited
if _, ok := getReleasesErr.(*github.RateLimitError); ok {
return false, retryError
Expand Down Expand Up @@ -418,5 +424,10 @@ func (g *gitHubRepository) handleGithubErr(err error, message string, args ...in
if _, ok := err.(*github.RateLimitError); ok {
return errors.New("rate limit for github api has been reached. Please wait one hour or get a personal API token and assign it to the GITHUB_TOKEN environment variable")
}
if ghErr, ok := err.(*github.ErrorResponse); ok {
if ghErr.Response.StatusCode == http.StatusNotFound {
return errNotFound
}
}
return errors.Wrapf(err, message, args...)
}
23 changes: 23 additions & 0 deletions cmd/clusterctl/client/repository/repository_github_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,15 @@ func Test_gitHubRepository_getLatestContractRelease(t *testing.T) {
fmt.Fprint(w, "v0.3.1\n")
})

// setup an handler for returning 4 fake releases but no actual tagged release
muxGoproxy.HandleFunc("/github.com/o/r2/@v/list", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
fmt.Fprint(w, "v0.5.0\n")
fmt.Fprint(w, "v0.4.0\n")
fmt.Fprint(w, "v0.3.2\n")
fmt.Fprint(w, "v0.3.1\n")
})

configVariablesClient := test.NewFakeVariableClient()

type field struct {
Expand Down Expand Up @@ -460,6 +469,15 @@ func Test_gitHubRepository_getLatestContractRelease(t *testing.T) {
contract: "foo",
wantErr: false,
},
{
name: "Return 404 if there is no release for the tag",
field: field{
providerConfig: config.NewProvider("test", "https://github.com/o/r2/releases/v0.99.0/path", clusterctlv1.CoreProviderType),
},
want: "0.99.0",
contract: "v1alpha4",
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down Expand Up @@ -494,6 +512,11 @@ func Test_gitHubRepository_getLatestRelease(t *testing.T) {
fmt.Fprint(w, "v0.4.3-alpha\n") // prerelease
fmt.Fprint(w, "foo\n") // no semantic version tag
})
// And also expose a release for them
muxGoproxy.HandleFunc("/api.github.com/repos/o/r1/releases/tags/v0.4.2", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
fmt.Fprint(w, "{}\n")
})

// setup an handler for returning no releases
muxGoproxy.HandleFunc("/github.com/o/r2/@v/list", func(w http.ResponseWriter, r *http.Request) {
Expand Down
9 changes: 7 additions & 2 deletions cmd/clusterctl/client/repository/repository_versions.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,16 @@ func latestContractRelease(repo Repository, contract string) (string, error) {
}
// Attempt to check if the latest release satisfies the API Contract
// This is a best-effort attempt to find the latest release for an older API contract if it's not the latest release.
// If an error occurs, we just return the latest release.
file, err := repo.GetFile(latest, metadataFile)
// If an error occurs, we just return the latest release.
if err != nil {
if errors.Is(err, errNotFound) {
// If it was ErrNotFound, then there is no release yet for the resolved tag.
// Ref: https://github.com/kubernetes-sigs/cluster-api/issues/7889
return "", errors.Wrap(err, "release does not exist yet, consider setting \"GOPROXY=off\" as workaround")
}
// if we can't get the metadata file from the release, we return latest.
return latest, nil //nolint:nilerr
return latest, nil
}
latestMetadata := &clusterctlv1.Metadata{}
codecFactory := serializer.NewCodecFactory(scheme.Scheme)
Expand Down

0 comments on commit 42e0607

Please sign in to comment.