From 6dfccc5d93e8e2e0d1a9ffdac55d2586d8c350f6 Mon Sep 17 00:00:00 2001 From: Miguel Santiago Date: Mon, 21 Jan 2019 19:35:30 +0000 Subject: [PATCH] Feature/support repos from helm settings (#2) * support repos added through CLI * Fix readme --- Makefile | 2 +- README.md | 85 +++++++++++++++++++++++++++++++++++-------- cmd/push/main.go | 38 +++++++++++++++++-- cmd/push/main_test.go | 70 ++++++++++++++++++++++++++++++++--- plugin.yaml | 2 +- 5 files changed, 171 insertions(+), 26 deletions(-) diff --git a/Makefile b/Makefile index 9052728..4af60e9 100644 --- a/Makefile +++ b/Makefile @@ -46,7 +46,7 @@ endif @dep ensure -v -vendor-only .PHONY: dist -dist: clean +dist: clean build-cross dist: ( \ cd _dist && \ diff --git a/README.md b/README.md index ae475e9..d47a0c7 100644 --- a/README.md +++ b/README.md @@ -11,8 +11,8 @@ Based on the version in `plugin.yaml`, release binary will be downloaded from Gi ``` $ helm plugin install https://github.com/belitre/helm-push-artifactory-plugin -Downloading and installing helm-push-artifactory v0.1.0 ... -https://github.com/belitre/helm-push-artifactory-plugin/releases/download/v0.1.0/helm-push-artifactory_v0.1.0_darwin_amd64.tar.gz +Downloading and installing helm-push-artifactory v0.2.0 ... +https://github.com/belitre/helm-push-artifactory-plugin/releases/download/v0.2.0/helm-push-artifactory_v0.2.0_darwin_amd64.tar.gz Installed plugin: push-artifactory ``` @@ -23,27 +23,80 @@ helm plugin remove push-artifactory Removed plugin: push-artifactory ``` +## Local and virtual repositories + +Artifactory has two types of repositories: local and virtual. Local repositories are the ones where you push the charts, but to get a chart you'll need to use a virtual repository! + +__This plugin works with local repositories__, you can add them through the Helm CLI like a virtual repository and use it later instead of the URL. But remember: __you won't be able to get charts from a local repository__ + +Example: + +* We can add our local repository with helm CLI: + + ```bash + $ helm repo add --username myuser --password mypass my-local-repo https://artifactoryhost/my-local-repo + "my-local-repo" has been added to your repositories + ``` + +* We can use this repository later to push charts: + + ```bash + $ helm push-artifactory mychart-0.3.2.tgz my-local-repo + Pushing mychart-0.3.2.tgz to https://artifactoryhost/my-local-repo/mychart/mychart-0.3.2.tgz... + Done. + Reindex helm repository my-local-repo... + Reindex of helm repo my-local-repo was scheduled to run. + ``` + +* __We can't get the helm chart from a local repo:__ + + ```bash + $ helm fetch my-local-repo/mychart + Error: Get local://mychart/mychart-0.3.2.tgz: unsupported protocol scheme "local" + ``` + +* We can add the virtual repo and get the chart: + + ```bash + $ helm repo add --username myuser --password mypass my-virtual-repo https://artifactoryhost/my-virtual-repo + "my-virtual-repo" has been added to your repositories + $ helm repo update + Hang tight while we grab the latest from your chart repositories... + ...Skip local chart repository + ...Successfully got an update from the "my-local-repo" chart repository + ...Successfully got an update from the "my-virtual-repo" chart repository + Update Complete. ⎈ Happy Helming!⎈ + $ helm fetch my-virtual-repo/mychart + $ ls + mychart-0.3.2.tgz + ``` + ## Usage -__This plugin doesn't use repositories added through Helm CLI, in Artifactory those are virtual repositories. To push a chart we need to use a local repository URL__ -Example -``` +Example using URL: + +```bash $ helm push-artifactory /my/chart/folder https://my-artifactory/my-local-repo --username username --password password ``` -For all available plugin options, please run +Example using helm repo added through CLI: +```bash +$ helm push-artifactory /my/chart/folder my-local-repo ``` + +For all available plugin options, please run: +```bash $ helm push-artifactory --help ``` ### Pushing a directory Point to a directory containing a valid `Chart.yaml` and the chart will be packaged and uploaded: -``` +```bash $ cat mychart/Chart.yaml name: mychart version: 0.3.2 ``` -``` +```bash $ helm push-artifactory mychart/ https://my-artifactory/my-local-repo Pushing mychart-0.3.2.tgz to https://my-artifactory/my-local-repo/mychart/mychart-0.3.2.tgz... Done. @@ -55,7 +108,7 @@ Reindex of helm repo my-local-repo was scheduled to run. The `--version` flag can be provided, which will push the package with a custom version. Here is an example using the last git commit id as the version: -``` +```bash $ helm push-artifactory mychart/ --version="$(git log -1 --pretty=format:%h)" https://my-artifactory/my-local-repo Pushing mychart-5abbbf28.tgz to https://my-artifactory/my-local-repo/mychart/mychart-5abbbf28.tgz... Done. @@ -65,8 +118,8 @@ Reindex of helm repo my-local-repo was scheduled to run. ### Push .tgz package This workflow does not require the use of `helm package`, but pushing .tgz is still supported: -``` -$ helm push mychart-0.3.2.tgz https://my-artifactory/my-local-repo +```bash +$ helm push-artifactory mychart-0.3.2.tgz https://my-artifactory/my-local-repo Pushing mychart-0.3.2.tgz to https://my-artifactory/my-local-repo/mychart/mychart-0.3.2.tgz... Done. Reindex helm repository my-local-repo... @@ -75,7 +128,7 @@ Reindex of helm repo my-local-repo was scheduled to run. ### Push with path You can set a path to push your chart in your Artifactory local repository: -``` +```bash $ helm push-artifactory mychart/ https://my-artifactory/my-local-repo --path organization Pushing mychart-0.3.2.tgz to https://my-artifactory/my-local-repo/organization/mychart/mychart-0.3.2.tgz... Done. @@ -85,7 +138,7 @@ Reindex of helm repo my-local-repo was scheduled to run. ### Skip repository reindex You can skip triggering the repository reindex: -``` +```bash $ helm push-artifactory mychart/ https://my-artifactory/my-local-repo --skip-reindex Pushing mychart-0.3.2.tgz to https://my-artifactory/my-local-repo/mychart/mychart-0.3.2.tgz... Done. @@ -96,14 +149,14 @@ Done. __The plugin will not use the auth info located in `~/.helm/repository/repositories.yaml` in order to authenticate.__ You can provide username and password through commmand line with `--username username --password password` or use the following environment variables for basic auth on push operations: -``` +```bash $ export HELM_REPO_USERNAME="myuser" $ export HELM_REPO_PASSWORD="mypass" ``` ### Access Token You can provide an access token through command line with `--access-token my-token` or use the following env var: -``` +```bash $ export HELM_REPO_ACCESS_TOKEN="" ``` @@ -116,7 +169,7 @@ If a username is supplied with an access token, the plugin will use basic authen ### Api Key You can provide an api key through command line with `--api-key my-key` or use the following env var: -``` +```bash $ export HELM_REPO_API_KEY="" ``` diff --git a/cmd/push/main.go b/cmd/push/main.go index ea7be6a..5820504 100644 --- a/cmd/push/main.go +++ b/cmd/push/main.go @@ -8,6 +8,7 @@ import ( "net/http" "net/url" "os" + "regexp" "strconv" "strings" @@ -44,6 +45,7 @@ Examples: $ helm push-artifactory mychart-0.1.0.tgz https://artifactory/repo # push mychart-0.1.0.tgz from "helm package" $ helm push-artifactory . https://artifactory/repo # package and push chart directory $ helm push-artifactory . --version="7c4d121" https://artifactory/repo # override version in Chart.yaml + $ helm push-artifactory mychart-0.1.0.tgz my-helm-repo # push mychart-0.1.0.tgz to a "my-helm-repo" repository ` ) @@ -119,13 +121,24 @@ func (p *pushCmd) setFieldsFromEnv() { } func (p *pushCmd) push() error { - chart, err := helm.GetChartByName(p.chartName) + var repo *helm.Repo + var err error + + // If the argument looks like a URL, just create a temp repo object + // instead of looking for the entry in the local repository list + if regexp.MustCompile(`^https?://`).MatchString(p.repository) { + // Check valid URL + _, err = url.ParseRequestURI(p.repository) + } else { + repo, err = helm.GetRepoByName(p.repository) + } + if err != nil { return err } - // Check valid URL - if _, err = url.ParseRequestURI(p.repository); err != nil { + chart, err := helm.GetChartByName(p.chartName) + if err != nil { return err } @@ -134,6 +147,25 @@ func (p *pushCmd) push() error { chart.SetVersion(p.chartVersion) } + if repo != nil { + p.repository = repo.URL + if p.username == "" { + p.username = repo.Username + } + if p.password == "" { + p.password = repo.Password + } + if p.caFile == "" { + p.caFile = repo.CAFile + } + if p.certFile == "" { + p.certFile = repo.CertFile + } + if p.keyFile == "" { + p.keyFile = repo.KeyFile + } + } + client, err := artifactory.NewClient( artifactory.URL(p.repository), artifactory.Path(p.path), diff --git a/cmd/push/main_test.go b/cmd/push/main_test.go index ebb6660..cbf5d1c 100644 --- a/cmd/push/main_test.go +++ b/cmd/push/main_test.go @@ -3,6 +3,7 @@ package main import ( "crypto/rand" "crypto/tls" + "io/ioutil" "net/http" "net/http/httptest" "os" @@ -10,7 +11,10 @@ import ( "github.com/stretchr/testify/assert" + "k8s.io/helm/pkg/getter" helm_env "k8s.io/helm/pkg/helm/environment" + "k8s.io/helm/pkg/helm/helmpath" + "k8s.io/helm/pkg/repo" "k8s.io/helm/pkg/tlsutil" ) @@ -42,34 +46,66 @@ func TestPushCmd(t *testing.T) { })) defer ts.Close() + // Create new Helm home w/ test repo + tmp, err := ioutil.TempDir("", "helm-push-test") + if err != nil { + t.Error("unexpected error creating temp test dir", err) + } + defer os.RemoveAll(tmp) + + home := helmpath.Home(tmp) + f := repo.NewRepoFile() + + entry := repo.Entry{} + entry.Name = "helm-push-test" + entry.URL = ts.URL + + _, err = repo.NewChartRepository(&entry, getter.All(settings)) + if err != nil { + t.Error("unexpected error created test repository", err) + } + + f.Update(&entry) + os.MkdirAll(home.Repository(), 0777) + f.WriteFile(home.RepositoryFile(), 0644) + + os.Setenv("HELM_HOME", home.String()) os.Setenv("HELM_REPO_USERNAME", "myuser") os.Setenv("HELM_REPO_PASSWORD", "mypass") // Not enough args args := []string{} cmd := newPushCmd(args) - err := cmd.RunE(cmd, args) + err = cmd.RunE(cmd, args) if err == nil { t.Error("expecting error with missing args, instead got nil") } // Bad chart path - args = []string{"/this/this/not/a/chart", ts.URL} + args = []string{"/this/this/not/a/chart", "helm-push-test"} cmd = newPushCmd(args) err = cmd.RunE(cmd, args) if err == nil { t.Error("expecting error with bad chart path, instead got nil") } - // Bad repo URL + // Bad repo name args = []string{testTarballPath, "wkerjbnkwejrnkj"} cmd = newPushCmd(args) err = cmd.RunE(cmd, args) if err == nil { - t.Error("expecting error with bad repo URL, instead got nil") + t.Error("expecting error with bad repo name, instead got nil") } // Happy path + args = []string{testTarballPath, "helm-push-test"} + cmd = newPushCmd(args) + err = cmd.RunE(cmd, args) + if err != nil { + t.Error("unexpecting error uploading tarball", err) + } + + // Happy path by repo URL args = []string{testTarballPath, ts.URL} cmd = newPushCmd(args) err = cmd.RunE(cmd, args) @@ -145,11 +181,35 @@ func TestPushCmdWithTlsEnabledServer(t *testing.T) { ts.StartTLS() defer ts.Close() + // Create new Helm home w/ test repo + tmp, err := ioutil.TempDir("", "helm-push-test") + if err != nil { + t.Error("unexpected error creating temp test dir", err) + } + defer os.RemoveAll(tmp) + + home := helmpath.Home(tmp) + f := repo.NewRepoFile() + + entry := repo.Entry{} + entry.Name = "helm-push-test" + entry.URL = ts.URL + + _, err = repo.NewChartRepository(&entry, getter.All(settings)) + if err != nil { + t.Error("unexpected error created test repository", err) + } + + f.Update(&entry) + os.MkdirAll(home.Repository(), 0777) + f.WriteFile(home.RepositoryFile(), 0644) + + os.Setenv("HELM_HOME", home.String()) os.Setenv("HELM_REPO_USERNAME", "myuser") os.Setenv("HELM_REPO_PASSWORD", "mypass") //no certificate options - args := []string{testTarballPath, ts.URL} + args := []string{testTarballPath, "helm-push-test"} cmd := newPushCmd(args) err = cmd.RunE(cmd, args) if err == nil { diff --git a/plugin.yaml b/plugin.yaml index 8cf3fa6..5b967ec 100644 --- a/plugin.yaml +++ b/plugin.yaml @@ -1,5 +1,5 @@ name: "push-artifactory" -version: "0.1.0" +version: "0.2.0" usage: "Please see https://github.com/belitre/helm-push-artifactory-plugin for usage" description: "Push helm charts to artifactory" ignoreFlags: false