Merge branch 'main' of github.com:helm/helm into hip-6

Signed-off-by: Josh Dolitsky <josh@dolit.ski>
pull/9782/head
Josh Dolitsky 4 years ago
commit d296ddf026
No known key found for this signature in database
GPG Key ID: B2B93673243A65FB

@ -0,0 +1,29 @@
name: build-pr
on:
pull_request:
branches:
- main
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout source code
uses: actions/checkout@v2
- name: Setup Go
uses: actions/setup-go@v2
with:
go-version: '1.16'
- name: Install golangci-lint
run: |
curl -sSLO https://github.com/golangci/golangci-lint/releases/download/v$GOLANGCI_LINT_VERSION/golangci-lint-$GOLANGCI_LINT_VERSION-linux-amd64.tar.gz
shasum -a 256 golangci-lint-$GOLANGCI_LINT_VERSION-linux-amd64.tar.gz | grep "^$GOLANGCI_LINT_SHA256 " > /dev/null
tar -xf golangci-lint-$GOLANGCI_LINT_VERSION-linux-amd64.tar.gz
sudo mv golangci-lint-$GOLANGCI_LINT_VERSION-linux-amd64/golangci-lint /usr/local/bin/golangci-lint
rm -rf golangci-lint-$GOLANGCI_LINT_VERSION-linux-amd64*
env:
GOLANGCI_LINT_VERSION: '1.36.0'
GOLANGCI_LINT_SHA256: '9b8856b3a1c9bfbcf3a06b78e94611763b79abd9751c245246787cd3bf0e78a5'
- name: Test style
run: make test-style
- name: Run unit tests
run: make test-coverage

@ -17,7 +17,6 @@ package main
import ( import (
"fmt" "fmt"
"io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
@ -191,7 +190,7 @@ func TestDependencyUpdateCmd_DoNotDeleteOldChartsOnError(t *testing.T) {
} }
// Make sure charts dir still has dependencies // Make sure charts dir still has dependencies
files, err := ioutil.ReadDir(filepath.Join(dir(chartname), "charts")) files, err := os.ReadDir(filepath.Join(dir(chartname), "charts"))
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }

@ -32,6 +32,10 @@ import (
const updateDesc = ` const updateDesc = `
Update gets the latest information about charts from the respective chart repositories. Update gets the latest information about charts from the respective chart repositories.
Information is cached locally, where it is used by commands like 'helm search'. Information is cached locally, where it is used by commands like 'helm search'.
You can optionally specify a list of repositories you want to update.
$ helm repo update <repo_name> ...
To update all the repositories, use 'helm repo update'.
` `
var errNoRepositories = errors.New("no repositories found. You must add one before updating") var errNoRepositories = errors.New("no repositories found. You must add one before updating")
@ -40,21 +44,25 @@ type repoUpdateOptions struct {
update func([]*repo.ChartRepository, io.Writer) update func([]*repo.ChartRepository, io.Writer)
repoFile string repoFile string
repoCache string repoCache string
names []string
} }
func newRepoUpdateCmd(out io.Writer) *cobra.Command { func newRepoUpdateCmd(out io.Writer) *cobra.Command {
o := &repoUpdateOptions{update: updateCharts} o := &repoUpdateOptions{update: updateCharts}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "update", Use: "update [REPO1 [REPO2 ...]]",
Aliases: []string{"up"}, Aliases: []string{"up"},
Short: "update information of available charts locally from chart repositories", Short: "update information of available charts locally from chart repositories",
Long: updateDesc, Long: updateDesc,
Args: require.NoArgs, Args: require.MinimumNArgs(0),
ValidArgsFunction: noCompletions, ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return compListRepos(toComplete, args), cobra.ShellCompDirectiveNoFileComp
},
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
o.repoFile = settings.RepositoryConfig o.repoFile = settings.RepositoryConfig
o.repoCache = settings.RepositoryCache o.repoCache = settings.RepositoryCache
o.names = args
return o.run(out) return o.run(out)
}, },
} }
@ -73,15 +81,26 @@ func (o *repoUpdateOptions) run(out io.Writer) error {
} }
var repos []*repo.ChartRepository var repos []*repo.ChartRepository
for _, cfg := range f.Repositories { updateAllRepos := len(o.names) == 0
r, err := repo.NewChartRepository(cfg, getter.All(settings))
if err != nil { if !updateAllRepos {
// Fail early if the user specified an invalid repo to update
if err := checkRequestedRepos(o.names, f.Repositories); err != nil {
return err return err
} }
if o.repoCache != "" { }
r.CachePath = o.repoCache
for _, cfg := range f.Repositories {
if updateAllRepos || isRepoRequested(cfg.Name, o.names) {
r, err := repo.NewChartRepository(cfg, getter.All(settings))
if err != nil {
return err
}
if o.repoCache != "" {
r.CachePath = o.repoCache
}
repos = append(repos, r)
} }
repos = append(repos, r)
} }
o.update(repos, out) o.update(repos, out)
@ -105,3 +124,28 @@ func updateCharts(repos []*repo.ChartRepository, out io.Writer) {
wg.Wait() wg.Wait()
fmt.Fprintln(out, "Update Complete. ⎈Happy Helming!⎈") fmt.Fprintln(out, "Update Complete. ⎈Happy Helming!⎈")
} }
func checkRequestedRepos(requestedRepos []string, validRepos []*repo.Entry) error {
for _, requestedRepo := range requestedRepos {
found := false
for _, repo := range validRepos {
if requestedRepo == repo.Name {
found = true
break
}
}
if !found {
return errors.Errorf("no repositories found matching '%s'. Nothing will be updated", requestedRepo)
}
}
return nil
}
func isRepoRequested(repoName string, requestedRepos []string) bool {
for _, requestedRepo := range requestedRepos {
if repoName == requestedRepo {
return true
}
}
return false
}

@ -48,8 +48,54 @@ func TestUpdateCmd(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
if got := out.String(); !strings.Contains(got, "charts") { if got := out.String(); !strings.Contains(got, "charts") ||
t.Errorf("Expected 'charts' got %q", got) !strings.Contains(got, "firstexample") ||
!strings.Contains(got, "secondexample") {
t.Errorf("Expected 'charts', 'firstexample' and 'secondexample' but got %q", got)
}
}
func TestUpdateCmdMultiple(t *testing.T) {
var out bytes.Buffer
// Instead of using the HTTP updater, we provide our own for this test.
// The TestUpdateCharts test verifies the HTTP behavior independently.
updater := func(repos []*repo.ChartRepository, out io.Writer) {
for _, re := range repos {
fmt.Fprintln(out, re.Config.Name)
}
}
o := &repoUpdateOptions{
update: updater,
repoFile: "testdata/repositories.yaml",
names: []string{"firstexample", "charts"},
}
if err := o.run(&out); err != nil {
t.Fatal(err)
}
if got := out.String(); !strings.Contains(got, "charts") ||
!strings.Contains(got, "firstexample") ||
strings.Contains(got, "secondexample") {
t.Errorf("Expected 'charts' and 'firstexample' but not 'secondexample' but got %q", got)
}
}
func TestUpdateCmdInvalid(t *testing.T) {
var out bytes.Buffer
// Instead of using the HTTP updater, we provide our own for this test.
// The TestUpdateCharts test verifies the HTTP behavior independently.
updater := func(repos []*repo.ChartRepository, out io.Writer) {
for _, re := range repos {
fmt.Fprintln(out, re.Config.Name)
}
}
o := &repoUpdateOptions{
update: updater,
repoFile: "testdata/repositories.yaml",
names: []string{"firstexample", "invalid"},
}
if err := o.run(&out); err == nil {
t.Fatal("expected error but did not get one")
} }
} }
@ -111,4 +157,5 @@ func TestUpdateCharts(t *testing.T) {
func TestRepoUpdateFileCompletion(t *testing.T) { func TestRepoUpdateFileCompletion(t *testing.T) {
checkFileCompletion(t, "repo update", false) checkFileCompletion(t, "repo update", false)
checkFileCompletion(t, "repo update repo1", false)
} }

@ -22,6 +22,7 @@ import (
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
"os"
"path/filepath" "path/filepath"
"strings" "strings"
@ -340,7 +341,7 @@ func compListCharts(toComplete string, includeFiles bool) ([]string, cobra.Shell
// listing the entire content of the current directory which will // listing the entire content of the current directory which will
// be too many choices for the user to find the real repos) // be too many choices for the user to find the real repos)
if includeFiles && len(completions) > 0 && len(toComplete) > 0 { if includeFiles && len(completions) > 0 && len(toComplete) > 0 {
if files, err := ioutil.ReadDir("."); err == nil { if files, err := os.ReadDir("."); err == nil {
for _, file := range files { for _, file := range files {
if strings.HasPrefix(file.Name(), toComplete) { if strings.HasPrefix(file.Name(), toComplete) {
// We are completing a file prefix // We are completing a file prefix

@ -2,3 +2,8 @@ apiVersion: v1
repositories: repositories:
- name: charts - name: charts
url: "https://charts.helm.sh/stable" url: "https://charts.helm.sh/stable"
- name: firstexample
url: "http://firstexample.com"
- name: secondexample
url: "http://secondexample.com"

@ -33,7 +33,6 @@ package fs
import ( import (
"io" "io"
"io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
"runtime" "runtime"
@ -119,7 +118,7 @@ func CopyDir(src, dst string) error {
return errors.Wrapf(err, "cannot mkdir %s", dst) return errors.Wrapf(err, "cannot mkdir %s", dst)
} }
entries, err := ioutil.ReadDir(src) entries, err := os.ReadDir(src)
if err != nil { if err != nil {
return errors.Wrapf(err, "cannot read directory %s", dst) return errors.Wrapf(err, "cannot read directory %s", dst)
} }

@ -96,7 +96,7 @@ func lintChart(path string, vals map[string]interface{}, namespace string, stric
return linter, errors.Wrap(err, "unable to extract tarball") return linter, errors.Wrap(err, "unable to extract tarball")
} }
files, err := ioutil.ReadDir(tempDir) files, err := os.ReadDir(tempDir)
if err != nil { if err != nil {
return linter, errors.Wrapf(err, "unable to read temporary output directory %s", tempDir) return linter, errors.Wrapf(err, "unable to read temporary output directory %s", tempDir)
} }

@ -878,7 +878,7 @@ func tarFromLocalDir(chartpath, name, repo, version string) (string, error) {
// move files from tmppath to destpath // move files from tmppath to destpath
func move(tmpPath, destPath string) error { func move(tmpPath, destPath string) error {
files, _ := ioutil.ReadDir(tmpPath) files, _ := os.ReadDir(tmpPath)
for _, file := range files { for _, file := range files {
filename := file.Name() filename := file.Name()
tmpfile := filepath.Join(tmpPath, filename) tmpfile := filepath.Join(tmpPath, filename)

@ -286,7 +286,8 @@ func FindChartInAuthAndTLSAndPassRepoURL(repoURL, username, password, chartName,
// ResolveReferenceURL resolves refURL relative to baseURL. // ResolveReferenceURL resolves refURL relative to baseURL.
// If refURL is absolute, it simply returns refURL. // If refURL is absolute, it simply returns refURL.
func ResolveReferenceURL(baseURL, refURL string) (string, error) { func ResolveReferenceURL(baseURL, refURL string) (string, error) {
parsedBaseURL, err := url.Parse(baseURL) // We need a trailing slash for ResolveReference to work, but make sure there isn't already one
parsedBaseURL, err := url.Parse(strings.TrimSuffix(baseURL, "/") + "/")
if err != nil { if err != nil {
return "", errors.Wrapf(err, "failed to parse %s as URL", baseURL) return "", errors.Wrapf(err, "failed to parse %s as URL", baseURL)
} }
@ -296,8 +297,6 @@ func ResolveReferenceURL(baseURL, refURL string) (string, error) {
return "", errors.Wrapf(err, "failed to parse %s as URL", refURL) return "", errors.Wrapf(err, "failed to parse %s as URL", refURL)
} }
// We need a trailing slash for ResolveReference to work, but make sure there isn't already one
parsedBaseURL.Path = strings.TrimSuffix(parsedBaseURL.Path, "/") + "/"
return parsedBaseURL.ResolveReference(parsedRefURL).String(), nil return parsedBaseURL.ResolveReference(parsedRefURL).String(), nil
} }

@ -400,4 +400,12 @@ func TestResolveReferenceURL(t *testing.T) {
if chartURL != "https://charts.helm.sh/stable/nginx-0.2.0.tgz" { if chartURL != "https://charts.helm.sh/stable/nginx-0.2.0.tgz" {
t.Errorf("%s", chartURL) t.Errorf("%s", chartURL)
} }
chartURL, err = ResolveReferenceURL("http://localhost:8123/charts%2fwith%2fescaped%2fslash", "nginx-0.2.0.tgz")
if err != nil {
t.Errorf("%s", err)
}
if chartURL != "http://localhost:8123/charts%2fwith%2fescaped%2fslash/nginx-0.2.0.tgz" {
t.Errorf("%s", chartURL)
}
} }

Loading…
Cancel
Save