diff --git a/cmd/clusterctl/client/repository/repository_github.go b/cmd/clusterctl/client/repository/repository_github.go index 38f4b12cdcb8..ea8999946f18 100644 --- a/cmd/clusterctl/client/repository/repository_github.go +++ b/cmd/clusterctl/client/repository/repository_github.go @@ -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{} @@ -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") } } @@ -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 @@ -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...) } diff --git a/cmd/clusterctl/client/repository/repository_versions.go b/cmd/clusterctl/client/repository/repository_versions.go index f4b710408d47..bd5ab56121c3 100644 --- a/cmd/clusterctl/client/repository/repository_versions.go +++ b/cmd/clusterctl/client/repository/repository_versions.go @@ -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)