Skip to content

Commit

Permalink
Ability to push directly to repo URL (#3)
Browse files Browse the repository at this point in the history
  • Loading branch information
jdolitsky committed Jul 16, 2018
1 parent 4987731 commit 57a5f8a
Show file tree
Hide file tree
Showing 7 changed files with 123 additions and 3 deletions.
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Installed plugin: push
```

## Usage
You must start by adding a ChartMuseum-backed repo via Helm CLI (if not already added)
Start by adding a ChartMuseum-backed repo via Helm CLI (if not already added)
```
$ helm repo add chartmuseum http://localhost:8080
```
Expand Down Expand Up @@ -57,6 +57,14 @@ Pushing mychart-0.3.2.tgz to chartmuseum...
Done.
```

### Pushing directly to URL
If the second argument provided resembles a URL, you are not required to add the repo prior to push:
```
$ helm push mychart-0.3.2.tgz http://localhost:8080
Pushing mychart-0.3.2.tgz to http://localhost:8080...
Done.
```

## Authentication
### Basic Auth
If you have added your repo with the `--username`/`--password` flags (Helm 2.9+), or have added your repo with the basic auth username/password in the URL (e.g. `https://myuser:mypass@my.chart.repo.com`), no further setup is required.
Expand Down
32 changes: 32 additions & 0 deletions acceptance_tests/chartmuseum.robot
Original file line number Diff line number Diff line change
Expand Up @@ -9,33 +9,65 @@ Suite Teardown Suite Teardown

*** Test Cases ***
Chart directory can be pushed to ChartMuseum
# Repo name
push chart directory
HelmPush.return code should be 0
package exists in chartmuseum storage
ChartMuseum.return code should be 0
clear chartmuseum storage

# Repo URL
push chart directory to url
HelmPush.return code should be 0
package exists in chartmuseum storage
ChartMuseum.return code should be 0
clear chartmuseum storage

Chart directory can be pushed to ChartMuseum with custom version
# Repo name
push chart directory latest
HelmPush.return code should be 0
package exists in chartmuseum storage latest
ChartMuseum.return code should be 0
clear chartmuseum storage

# Repo URL
push chart directory to url latest
HelmPush.return code should be 0
package exists in chartmuseum storage latest
ChartMuseum.return code should be 0
clear chartmuseum storage

Chart package can be pushed to ChartMuseum
# Repo name
push chart package
HelmPush.return code should be 0
package exists in chartmuseum storage
ChartMuseum.return code should be 0
clear chartmuseum storage

# Repo URL
push chart package to url
HelmPush.return code should be 0
package exists in chartmuseum storage
ChartMuseum.return code should be 0
clear chartmuseum storage

Chart package can be pushed to ChartMuseum with custom version
# Repo name
push chart package latest
HelmPush.return code should be 0
package exists in chartmuseum storage latest
ChartMuseum.return code should be 0
clear chartmuseum storage

# Repo URL
push chart package to url latest
HelmPush.return code should be 0
package exists in chartmuseum storage latest
ChartMuseum.return code should be 0
clear chartmuseum storage

*** Keywords ***
Suite Setup
remove chartmuseum logs
Expand Down
12 changes: 12 additions & 0 deletions acceptance_tests/lib/HelmPush.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,20 @@ def push_chart_directory(self, version=''):
cmd += " --version=\"%s\"" % version
self.run_command(cmd)

def push_chart_directory_to_url(self, version=''):
cmd = 'helmpush %s/mychart %s' % (common.TESTCHARTS_DIR, common.HELM_REPO_URL)
if version:
cmd += " --version=\"%s\"" % version
self.run_command(cmd)

def push_chart_package(self, version=''):
cmd = 'helmpush %s/mychart/*.tgz %s' % (common.TESTCHARTS_DIR, common.HELM_REPO_NAME)
if version:
cmd += " --version=\"%s\"" % version
self.run_command(cmd)

def push_chart_package_to_url(self, version=''):
cmd = 'helmpush %s/mychart %s' % (common.TESTCHARTS_DIR, common.HELM_REPO_URL)
if version:
cmd += " --version=\"%s\"" % version
self.run_command(cmd)
17 changes: 15 additions & 2 deletions cmd/helmpush/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"os/user"
"path"
"path/filepath"
"regexp"
"strconv"
"strings"
)
Expand Down Expand Up @@ -51,6 +52,7 @@ Examples:
$ helm push mychart-0.1.0.tgz chartmuseum # push .tgz from "helm package"
$ helm push . chartmuseum # package and push chart directory
$ helm push . --version="7c4d121" chartmuseum # override version in Chart.yaml
$ helm push . https://my.chart.repo.com # push directly to chart repo URL
`
)

Expand All @@ -70,7 +72,7 @@ func newPushCmd(args []string) *cobra.Command {
}

if len(args) != 2 {
return errors.New("This command needs 2 arguments: name of chart, name of chart repository")
return errors.New("This command needs 2 arguments: name of chart, name of chart repository (or repo URL)")
}
p.chartName = args[0]
p.repoName = args[1]
Expand Down Expand Up @@ -140,7 +142,18 @@ func (p *pushCmd) setAccessTokenFromConfigFile() {
}

func (p *pushCmd) push() error {
repo, err := helm.GetRepoByName(p.repoName)
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.repoName) {
repo, err = helm.TempRepoFromURL(p.repoName)
p.repoName = repo.URL
} else {
repo, err = helm.GetRepoByName(p.repoName)
}

if err != nil {
return err
}
Expand Down
8 changes: 8 additions & 0 deletions cmd/helmpush/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,14 @@ func TestPushCmd(t *testing.T) {
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)
if err != nil {
t.Error("unexpecting error uploading tarball, using repo URL", err)
}

// Trigger 409
statusCode = 409
body = "{\"error\": \"package already exists\"}"
Expand Down
21 changes: 21 additions & 0 deletions pkg/helm/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import (
"k8s.io/helm/pkg/helm/helmpath"
"k8s.io/helm/pkg/repo"
"os"
"strings"
urllib "net/url"
)

type (
Expand All @@ -28,6 +30,25 @@ func GetRepoByName(name string) (*Repo, error) {
return &Repo{entry}, nil
}

// TempRepoFromURL builds a temporary Repo from a given URL
func TempRepoFromURL(url string) (*Repo, error) {
u, err := urllib.Parse(url)
if err != nil {
return nil, err
}
entry := &repo.Entry{}
if u.User != nil {
// remove the username/password section from URL
pass, _ := u.User.Password()
entry.URL = strings.Split(url, "://")[0] + "://" + strings.Split(url, fmt.Sprintf("%s@", pass))[1]
entry.Username = u.User.Username()
entry.Password = pass
} else {
entry.URL = url
}
return &Repo{entry}, nil
}

func repoFile() (*repo.RepoFile, error) {
home := helmHome()
return repo.LoadRepositoriesFile(home.RepositoryFile())
Expand Down
26 changes: 26 additions & 0 deletions pkg/helm/repo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,29 @@ func TestGetRepoByName(t *testing.T) {
}

}

func TestTempRepoFromURL(t *testing.T) {
url := "https://my.chart.repo.com"
repo, err := TempRepoFromURL(url)
if err != nil {
t.Error("unexpected error getting temp repo from URL", err)
}
if repo.URL != url {
t.Error("expecting repo URL to match what was provided")
}

url = "https://user:p@ss@my.chart.repo.com/a/b/c/"
repo, err = TempRepoFromURL(url)
if err != nil {
t.Error("unexpected error getting temp repo from URL, with basic auth", err)
}
if repo.URL != "https://my.chart.repo.com/a/b/c/" {
t.Error("expecting repo URL to have basic auth removed")
}
if repo.Username != "user" {
t.Error("expecting repo username to be extracted from URL")
}
if repo.Password != "p@ss" {
t.Error("expecting repo password to be extracted from URL")
}
}

0 comments on commit 57a5f8a

Please sign in to comment.