1
0
mirror of https://github.com/helm/helm.git synced 2025-02-06 10:24:22 +00:00

Merge 80ae32622b3a31215b7be60505308e434ab1abee into 32530594381efc783e17f6fdd3a4a936548bfd04

This commit is contained in:
Itai Spiegel 2025-02-06 08:36:31 +02:00 committed by GitHub
commit 95bf507887
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 292 additions and 0 deletions

View File

@ -45,6 +45,7 @@ func newRepoCmd(out io.Writer) *cobra.Command {
cmd.AddCommand(newRepoRemoveCmd(out))
cmd.AddCommand(newRepoIndexCmd(out))
cmd.AddCommand(newRepoUpdateCmd(out))
cmd.AddCommand(newRepoImportCmd(out))
return cmd
}

98
cmd/helm/repo_import.go Normal file
View File

@ -0,0 +1,98 @@
/*
Copyright The Helm Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"io"
"os"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/util/yaml"
"helm.sh/helm/v3/cmd/helm/require"
"helm.sh/helm/v3/pkg/repo"
)
type repoImportOptions struct {
importedFilePath string
repoFile string
repoCache string
}
func newRepoImportCmd(out io.Writer) *cobra.Command {
o := &repoImportOptions{}
cmd := &cobra.Command{
Use: "import [PATH]",
Short: "import chart repositories",
Args: require.ExactArgs(1),
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
if len(args) == 0 {
// Allow file completion when completing the argument for the directory
return nil, cobra.ShellCompDirectiveDefault
}
// No more completions, so disable file completion
return nil, cobra.ShellCompDirectiveNoFileComp
},
RunE: func(cmd *cobra.Command, args []string) error {
o.importedFilePath = args[0]
o.repoFile = settings.RepositoryConfig
o.repoCache = settings.RepositoryCache
return o.run(out)
},
}
f := cmd.Flags()
f.StringVar(&o.importedFilePath, "file", "", "path to the file to import")
return cmd
}
func (o *repoImportOptions) run(out io.Writer) error {
var helmRepoEntries []repo.Entry
fileContent, err := os.ReadFile(o.importedFilePath)
if err != nil {
return err
}
err = yaml.UnmarshalStrict(fileContent, &helmRepoEntries)
if err != nil {
return errors.Errorf("%s is an invalid YAML file", o.importedFilePath)
}
for i := range helmRepoEntries {
helmRepoEntry := helmRepoEntries[i]
info := repoAddOptions{
name: helmRepoEntry.Name,
url: helmRepoEntry.URL,
username: helmRepoEntry.Username,
password: helmRepoEntry.Password,
passCredentialsAll: helmRepoEntry.PassCredentialsAll,
certFile: helmRepoEntry.CertFile,
keyFile: helmRepoEntry.KeyFile,
caFile: helmRepoEntry.CAFile,
insecureSkipTLSverify: helmRepoEntry.InsecureSkipTLSverify,
repoFile: o.repoFile,
repoCache: o.repoCache}
err = info.run(out)
if err != nil {
return err
}
}
return nil
}

View File

@ -0,0 +1,189 @@
/*
Copyright The Helm Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"fmt"
"io"
"os"
"path/filepath"
"testing"
"io/fs"
"helm.sh/helm/v3/pkg/repo/repotest"
"sigs.k8s.io/yaml"
)
func TestRepoImportCmd(t *testing.T) {
srv, err := repotest.NewTempServerWithCleanup(t, "testdata/testserver/*.*")
if err != nil {
t.Fatal(err)
}
defer srv.Stop()
// A second test server is setup to verify URL changing
srv2, err := repotest.NewTempServerWithCleanup(t, "testdata/testserver/*.*")
if err != nil {
t.Fatal(err)
}
defer srv2.Stop()
tmpdir := filepath.Join(t.TempDir(), "path-component.yaml/data")
err = os.MkdirAll(tmpdir, 0777)
if err != nil {
t.Fatal(err)
}
repoFile := filepath.Join(tmpdir, "repositories.yaml")
repoImportFile := filepath.Join(tmpdir, "repositories-import.yaml")
var repositories = []repositoryElement{
{Name: "repo1", URL: srv.URL()},
{Name: "repo2", URL: srv2.URL()},
}
data, err := yaml.Marshal(&repositories)
if err != nil {
t.Fatal(err)
}
err = os.WriteFile(repoImportFile, data, fs.FileMode(0644))
if err != nil {
t.Fatal(err)
}
tests := []cmdTestCase{
{
name: "import repositories",
cmd: fmt.Sprintf("repo import %s --repository-config %s --repository-cache %s", repoImportFile, repoFile, tmpdir),
golden: "output/repo-import.txt",
},
{
name: "import repositories second time",
cmd: fmt.Sprintf("repo import %s --repository-config %s --repository-cache %s", repoImportFile, repoFile, tmpdir),
golden: "output/repo-import2.txt",
},
}
runTestCmd(t, tests)
}
func TestRepoImportFileCompletion(t *testing.T) {
checkFileCompletion(t, "repo import", true)
checkFileCompletion(t, "repo import file", false)
}
func TestRepoImportOnNonExistingFile(t *testing.T) {
ts, err := repotest.NewTempServerWithCleanup(t, "testdata/testserver/*.*")
if err != nil {
t.Fatal(err)
}
defer ts.Stop()
tmpdir := filepath.Join(t.TempDir(), "path-component.yaml/data")
err = os.MkdirAll(tmpdir, 0777)
if err != nil {
t.Fatal(err)
}
repoFile := filepath.Join(tmpdir, "repositories.yaml")
nonExistingFileName := "non-existing-file"
o := &repoImportOptions{
importedFilePath: nonExistingFileName,
repoFile: repoFile,
repoCache: tmpdir,
}
wantErrorMsg := fmt.Sprintf("open %s: no such file or directory", nonExistingFileName)
if err := o.run(io.Discard); err != nil {
if wantErrorMsg != err.Error() {
t.Fatalf("Actual error %s, not equal to expected error %s", err, wantErrorMsg)
}
} else {
t.Fatalf("expect reported an error.")
}
}
func TestRepoImportOnNonYamlFile(t *testing.T) {
ts, err := repotest.NewTempServerWithCleanup(t, "testdata/testserver/*.*")
if err != nil {
t.Fatal(err)
}
defer ts.Stop()
tmpdir := filepath.Join(t.TempDir(), "path-component.yaml/data")
err = os.MkdirAll(tmpdir, 0777)
if err != nil {
t.Fatal(err)
}
repoFile := filepath.Join(tmpdir, "repositories.yaml")
repoImportFile := filepath.Join(tmpdir, "repositories-import.txt")
err = os.WriteFile(repoImportFile, []byte("This is not a yaml file"), fs.FileMode(0644))
if err != nil {
t.Fatal(err)
}
o := &repoImportOptions{
importedFilePath: repoImportFile,
repoFile: repoFile,
repoCache: tmpdir,
}
wantErrorMsg := fmt.Sprintf("%s is an invalid YAML file", repoImportFile)
if err := o.run(io.Discard); err != nil {
if wantErrorMsg != err.Error() {
t.Fatalf("Actual error %s, not equal to expected error %s", err, wantErrorMsg)
}
} else {
t.Fatalf("expect reported an error.")
}
}
func TestRepoImportOnYamlFileWithInvalidStructure(t *testing.T) {
ts, err := repotest.NewTempServerWithCleanup(t, "testdata/testserver/*.*")
if err != nil {
t.Fatal(err)
}
defer ts.Stop()
tmpdir := filepath.Join(t.TempDir(), "path-component.yaml/data")
err = os.MkdirAll(tmpdir, 0777)
if err != nil {
t.Fatal(err)
}
repoFile := filepath.Join(tmpdir, "repositories.yaml")
repoImportFile := filepath.Join(tmpdir, "repositories-import.txt")
err = os.WriteFile(repoImportFile, []byte("- firstKey: firstValue\n secondKey: secondValue"), fs.FileMode(0644))
if err != nil {
t.Fatal(err)
}
o := &repoImportOptions{
importedFilePath: repoImportFile,
repoFile: repoFile,
repoCache: tmpdir,
}
wantErrorMsg := fmt.Sprintf("%s is an invalid YAML file", repoImportFile)
if err := o.run(io.Discard); err != nil {
if wantErrorMsg != err.Error() {
t.Fatalf("Actual error %s, not equal to expected error %s", err, wantErrorMsg)
}
} else {
t.Fatalf("expect reported an error.")
}
}

View File

@ -0,0 +1,2 @@
"repo1" has been added to your repositories
"repo2" has been added to your repositories

View File

@ -0,0 +1,2 @@
"repo1" already exists with the same configuration, skipping
"repo2" already exists with the same configuration, skipping