feat(cmd): Allow to specify which repos to update

This is a port to helm v3 of #5182.
A little more flexible than the v2 version, it allows to specify a list
of repositories that should be updated.

Signed-off-by: Marc Khouzam <marc.khouzam@montreal.ca>
pull/9934/head
Marc Khouzam 3 years ago committed by Marc Khouzam
parent 21251378b4
commit 6951cd5076

@ -32,6 +32,10 @@ import (
const updateDesc = `
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'.
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")
@ -40,21 +44,25 @@ type repoUpdateOptions struct {
update func([]*repo.ChartRepository, io.Writer)
repoFile string
repoCache string
names []string
}
func newRepoUpdateCmd(out io.Writer) *cobra.Command {
o := &repoUpdateOptions{update: updateCharts}
cmd := &cobra.Command{
Use: "update",
Aliases: []string{"up"},
Short: "update information of available charts locally from chart repositories",
Long: updateDesc,
Args: require.NoArgs,
ValidArgsFunction: noCompletions,
Use: "update [REPO1 [REPO2 ...]]",
Aliases: []string{"up"},
Short: "update information of available charts locally from chart repositories",
Long: updateDesc,
Args: require.MinimumNArgs(0),
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 {
o.repoFile = settings.RepositoryConfig
o.repoCache = settings.RepositoryCache
o.names = args
return o.run(out)
},
}
@ -73,15 +81,26 @@ func (o *repoUpdateOptions) run(out io.Writer) error {
}
var repos []*repo.ChartRepository
for _, cfg := range f.Repositories {
r, err := repo.NewChartRepository(cfg, getter.All(settings))
if err != nil {
updateAllRepos := len(o.names) == 0
if !updateAllRepos {
// Fail early if the user specified an invalid repo to update
if err := checkRequestedRepos(o.names, f.Repositories); err != nil {
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)
@ -105,3 +124,28 @@ func updateCharts(repos []*repo.ChartRepository, out io.Writer) {
wg.Wait()
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)
}
if got := out.String(); !strings.Contains(got, "charts") {
t.Errorf("Expected 'charts' got %q", got)
if got := out.String(); !strings.Contains(got, "charts") ||
!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) {
checkFileCompletion(t, "repo update", false)
checkFileCompletion(t, "repo update repo1", false)
}

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

Loading…
Cancel
Save