Skip to content

Commit

Permalink
Allow using the --from to get template from a github release
Browse files Browse the repository at this point in the history
Currently, `clusterctl generate cluster`'s `--from` flag only support
yaml files from github code. Trying to get template from a rlease tag is
failing.

This PR adds the option to use the `--form` also for release assets.

Signed-off-by: Nahshon Unna-Tsameret <nunnatsa@redhat.com>
  • Loading branch information
nunnatsa committed Oct 25, 2022
1 parent 9d35266 commit b90b1fa
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 8 deletions.
59 changes: 51 additions & 8 deletions cmd/clusterctl/client/cluster/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package cluster
import (
"context"
"encoding/base64"
"fmt"
"io"
"net/http"
"net/url"
Expand Down Expand Up @@ -181,35 +182,77 @@ func (t *templateClient) getGitHubFileContent(rURL *url.URL) ([]byte, error) {

// Extract all the info from url split.
owner := urlSplit[0]
repository := urlSplit[1]
repo := urlSplit[1]
linkType := urlSplit[2]
branch := urlSplit[3]
path := strings.Join(urlSplit[4:], "/")

// gets the GitHub client
client, err := t.gitHubClientFactory(t.configClient.Variables())
ghClient, err := t.gitHubClientFactory(t.configClient.Variables())
if err != nil {
return nil, err
}

// gets the file from GiHub
fileContent, _, _, err := client.Repositories.GetContents(context.TODO(), owner, repository, path, &github.RepositoryContentGetOptions{Ref: branch})
switch linkType {
case "blob": // get file from a code in a github repo
return getGithubFileContentFromCode(ghClient, rURL.Path, owner, repo, path, branch)

case "releases": // get a github release asset
tag := urlSplit[4]
assetName := urlSplit[5]

return getGithubAssetFromRelease(rURL.Path, ghClient, owner, repo, tag, assetName)

default:
return nil, fmt.Errorf("unknown github URL: %v", rURL)
}
}

func getGithubFileContentFromCode(ghClient *github.Client, fullPath string, owner string, repo string, path string, branch string) ([]byte, error) {
fileContent, _, _, err := ghClient.Repositories.GetContents(ctx, owner, repo, path, &github.RepositoryContentGetOptions{Ref: branch})
if err != nil {
return nil, handleGithubErr(err, "failed to get %q", rURL.Path)
return nil, handleGithubErr(err, "failed to get %q", fullPath)
}
if fileContent == nil {
return nil, errors.Errorf("%q does not return a valid file content", rURL.Path)
return nil, errors.Errorf("%q does not return a valid file content", fullPath)
}
if fileContent.Encoding == nil || *fileContent.Encoding != "base64" {
return nil, errors.Errorf("invalid encoding detected for %q. Only base64 encoding supported", rURL.Path)
return nil, errors.Errorf("invalid encoding detected for %q. Only base64 encoding supported", fullPath)
}

content, err := base64.StdEncoding.DecodeString(*fileContent.Content)
if err != nil {
return nil, errors.Wrapf(err, "failed to decode file %q", rURL.Path)
return nil, errors.Wrapf(err, "failed to decode file %q", fullPath)
}
return content, nil
}

func getGithubAssetFromRelease(path string, ghClient *github.Client, owner string, repo string, tag string, assetName string) ([]byte, error) {
release, _, err := ghClient.Repositories.GetReleaseByTag(ctx, owner, repo, tag)
if err != nil {
return nil, handleGithubErr(err, "failed to get release '%s' from %s%s repository", tag, owner, repo)
}

var rc io.ReadCloser
for _, asset := range release.Assets {
if asset.Name != nil && *asset.Name == assetName {
rc, _, err = ghClient.Repositories.DownloadReleaseAsset(ctx, owner, repo, asset.GetID(), ghClient.Client())
if err != nil {
return nil, errors.Wrapf(err, "failed to download file %q", path)
}
break
}
}

if rc == nil {
return nil, fmt.Errorf("failed to download the file %q", path)
}

defer func() { _ = rc.Close() }()

return io.ReadAll(rc)
}

func getGitHubClient(configVariablesClient config.VariablesClient) (*github.Client, error) {
var authenticatingHTTPClient *http.Client
if token, err := configVariablesClient.Get(config.GitHubTokenVariable); err == nil {
Expand Down
29 changes: 29 additions & 0 deletions cmd/clusterctl/client/cluster/template_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,25 @@ func Test_templateClient_GetFromURL(t *testing.T) {
}`)
})

mux.HandleFunc("/repos/some-owner/some-repo/releases/tags/v1.0.0", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, `{
"tag_name": "v1.0.0",
"name": "v1.0.0",
"id": 12345678,
"url": "https://api.github.com/repos/some-owner/some-repo/releases/12345678",
"assets": [
{
"id": 87654321,
"name": "cluster-template.yaml"
}
]
}`)
})

mux.HandleFunc("/repos/some-owner/some-repo/releases/assets/87654321", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, template)
})

path := filepath.Join(tmpDir, "cluster-template.yaml")
g.Expect(os.WriteFile(path, []byte(template), 0600)).To(Succeed())

Expand Down Expand Up @@ -344,6 +363,16 @@ func Test_templateClient_GetFromURL(t *testing.T) {
want: template,
wantErr: false,
},
{
name: "Get asset from GitHub release",
args: args{
templateURL: "https://github.com/some-owner/some-repo/releases/download/v1.0.0/cluster-template.yaml",
targetNamespace: "",
skipTemplateProcess: false,
},
want: template,
wantErr: false,
},
{
name: "Get from stdin",
args: args{
Expand Down

0 comments on commit b90b1fa

Please sign in to comment.