Merge pull request #346 from stek29/list-noprepare
feat: dont prepare on list
This commit is contained in:
commit
700d708b29
|
|
@ -32,6 +32,7 @@ func NewListCmd(globalCfg *config.GlobalImpl) *cobra.Command {
|
||||||
|
|
||||||
f := cmd.Flags()
|
f := cmd.Flags()
|
||||||
f.BoolVar(&listOptions.KeepTempDir, "keep-temp-dir", false, "Keep temporary directory")
|
f.BoolVar(&listOptions.KeepTempDir, "keep-temp-dir", false, "Keep temporary directory")
|
||||||
|
f.BoolVar(&listOptions.SkipCharts, "skip-charts", false, "don't prepare charts when listing releases")
|
||||||
f.StringVar(&listOptions.Output, "output", "", "output releases list as a json string")
|
f.StringVar(&listOptions.Output, "output", "", "output releases list as a json string")
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
|
|
|
||||||
100
pkg/app/app.go
100
pkg/app/app.go
|
|
@ -547,55 +547,31 @@ func (a *App) ListReleases(c ListConfigProvider) error {
|
||||||
var releases []*HelmRelease
|
var releases []*HelmRelease
|
||||||
|
|
||||||
err := a.ForEachState(func(run *Run) (_ bool, errs []error) {
|
err := a.ForEachState(func(run *Run) (_ bool, errs []error) {
|
||||||
err := run.withPreparedCharts("list", state.ChartPrepareOptions{
|
var stateReleases []*HelmRelease
|
||||||
SkipRepos: true,
|
var err error
|
||||||
SkipDeps: true,
|
|
||||||
Concurrency: 2,
|
|
||||||
}, func() {
|
|
||||||
// var releases m
|
|
||||||
for _, r := range run.state.Releases {
|
|
||||||
labels := ""
|
|
||||||
if r.Labels == nil {
|
|
||||||
r.Labels = map[string]string{}
|
|
||||||
}
|
|
||||||
for k, v := range run.state.CommonLabels {
|
|
||||||
r.Labels[k] = v
|
|
||||||
}
|
|
||||||
|
|
||||||
var keys []string
|
if !c.SkipCharts() {
|
||||||
for k := range r.Labels {
|
err = run.withPreparedCharts("list", state.ChartPrepareOptions{
|
||||||
keys = append(keys, k)
|
SkipRepos: true,
|
||||||
}
|
SkipDeps: true,
|
||||||
sort.Strings(keys)
|
Concurrency: 2,
|
||||||
|
}, func() {
|
||||||
for _, k := range keys {
|
rel, err := a.list(run)
|
||||||
v := r.Labels[k]
|
|
||||||
labels = fmt.Sprintf("%s,%s:%s", labels, k, v)
|
|
||||||
}
|
|
||||||
labels = strings.Trim(labels, ",")
|
|
||||||
|
|
||||||
enabled, err := state.ConditionEnabled(r, run.state.Values())
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
stateReleases = rel
|
||||||
installed := r.Installed == nil || *r.Installed
|
})
|
||||||
releases = append(releases, &HelmRelease{
|
} else {
|
||||||
Name: r.Name,
|
stateReleases, err = a.list(run)
|
||||||
Namespace: r.Namespace,
|
}
|
||||||
Installed: installed,
|
|
||||||
Enabled: enabled,
|
|
||||||
Labels: labels,
|
|
||||||
Chart: r.Chart,
|
|
||||||
Version: r.Version,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs = append(errs, err)
|
errs = append(errs, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
releases = append(releases, stateReleases...)
|
||||||
|
|
||||||
return
|
return
|
||||||
}, false, SetFilter(true))
|
}, false, SetFilter(true))
|
||||||
|
|
||||||
|
|
@ -612,6 +588,50 @@ func (a *App) ListReleases(c ListConfigProvider) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *App) list(run *Run) ([]*HelmRelease, error) {
|
||||||
|
var releases []*HelmRelease
|
||||||
|
|
||||||
|
for _, r := range run.state.Releases {
|
||||||
|
labels := ""
|
||||||
|
if r.Labels == nil {
|
||||||
|
r.Labels = map[string]string{}
|
||||||
|
}
|
||||||
|
for k, v := range run.state.CommonLabels {
|
||||||
|
r.Labels[k] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
var keys []string
|
||||||
|
for k := range r.Labels {
|
||||||
|
keys = append(keys, k)
|
||||||
|
}
|
||||||
|
sort.Strings(keys)
|
||||||
|
|
||||||
|
for _, k := range keys {
|
||||||
|
v := r.Labels[k]
|
||||||
|
labels = fmt.Sprintf("%s,%s:%s", labels, k, v)
|
||||||
|
}
|
||||||
|
labels = strings.Trim(labels, ",")
|
||||||
|
|
||||||
|
enabled, err := state.ConditionEnabled(r, run.state.Values())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
installed := r.Installed == nil || *r.Installed
|
||||||
|
releases = append(releases, &HelmRelease{
|
||||||
|
Name: r.Name,
|
||||||
|
Namespace: r.Namespace,
|
||||||
|
Installed: installed,
|
||||||
|
Enabled: enabled,
|
||||||
|
Labels: labels,
|
||||||
|
Chart: r.Chart,
|
||||||
|
Version: r.Version,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return releases, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (a *App) within(dir string, do func() error) error {
|
func (a *App) within(dir string, do func() error) error {
|
||||||
if dir == "." {
|
if dir == "." {
|
||||||
return do()
|
return do()
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
"io"
|
"io"
|
||||||
|
"os"
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
|
@ -17,7 +18,7 @@ import (
|
||||||
"github.com/helmfile/helmfile/pkg/testutil"
|
"github.com/helmfile/helmfile/pkg/testutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestListWithEnvironment(t *testing.T) {
|
func testListWithEnvironment(t *testing.T, cfg configImpl) {
|
||||||
type testcase struct {
|
type testcase struct {
|
||||||
environment string
|
environment string
|
||||||
ns string
|
ns string
|
||||||
|
|
@ -26,7 +27,7 @@ func TestListWithEnvironment(t *testing.T) {
|
||||||
expected string
|
expected string
|
||||||
}
|
}
|
||||||
|
|
||||||
check := func(t *testing.T, tc testcase) {
|
check := func(t *testing.T, tc testcase, cfg configImpl) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
bs := &bytes.Buffer{}
|
bs := &bytes.Buffer{}
|
||||||
|
|
@ -164,7 +165,7 @@ releases:
|
||||||
|
|
||||||
var listErr error
|
var listErr error
|
||||||
out := testutil.CaptureStdout(func() {
|
out := testutil.CaptureStdout(func() {
|
||||||
listErr = app.ListReleases(configImpl{})
|
listErr = app.ListReleases(cfg)
|
||||||
})
|
})
|
||||||
|
|
||||||
var gotErr string
|
var gotErr string
|
||||||
|
|
@ -197,14 +198,14 @@ cache my-app true true app:test bitnami/redis
|
||||||
database my-app true true bitnami/postgres 11.6.22
|
database my-app true true bitnami/postgres 11.6.22
|
||||||
global kube-system true true incubator/raw
|
global kube-system true true incubator/raw
|
||||||
`,
|
`,
|
||||||
})
|
}, cfg)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("fail on unknown environment", func(t *testing.T) {
|
t.Run("fail on unknown environment", func(t *testing.T) {
|
||||||
check(t, testcase{
|
check(t, testcase{
|
||||||
environment: "staging",
|
environment: "staging",
|
||||||
error: `err: no releases found that matches specified selector() and environment(staging), in any helmfile`,
|
error: `err: no releases found that matches specified selector() and environment(staging), in any helmfile`,
|
||||||
})
|
}, cfg)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("list releases matching selector and environment", func(t *testing.T) {
|
t.Run("list releases matching selector and environment", func(t *testing.T) {
|
||||||
|
|
@ -215,7 +216,7 @@ global kube-system true true incubator/raw
|
||||||
external-secrets default true true app:test,chart:raw,name:external-secrets,namespace:default incubator/raw
|
external-secrets default true true app:test,chart:raw,name:external-secrets,namespace:default incubator/raw
|
||||||
my-release default true true app:test,chart:raw,name:my-release,namespace:default incubator/raw
|
my-release default true true app:test,chart:raw,name:my-release,namespace:default incubator/raw
|
||||||
`,
|
`,
|
||||||
})
|
}, cfg)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("filters releases for environment used in one file only", func(t *testing.T) {
|
t.Run("filters releases for environment used in one file only", func(t *testing.T) {
|
||||||
|
|
@ -225,7 +226,7 @@ my-release default true true app:test,chart:raw,name:my-release,
|
||||||
cache my-app true true app:test bitnami/redis 17.0.7
|
cache my-app true true app:test bitnami/redis 17.0.7
|
||||||
database my-app true true bitnami/postgres 11.6.22
|
database my-app true true bitnami/postgres 11.6.22
|
||||||
`,
|
`,
|
||||||
})
|
}, cfg)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("filters releases for environment used in multiple files", func(t *testing.T) {
|
t.Run("filters releases for environment used in multiple files", func(t *testing.T) {
|
||||||
|
|
@ -243,6 +244,82 @@ test3 true true incubator/raw
|
||||||
cache my-app true true app:test bitnami/redis 17.0.7
|
cache my-app true true app:test bitnami/redis 17.0.7
|
||||||
database my-app true true bitnami/postgres 11.6.22
|
database my-app true true bitnami/postgres 11.6.22
|
||||||
`,
|
`,
|
||||||
})
|
}, cfg)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestListWithEnvironment(t *testing.T) {
|
||||||
|
t.Run("with skipCharts=false", func(t *testing.T) {
|
||||||
|
testListWithEnvironment(t, configImpl{skipCharts: false})
|
||||||
|
})
|
||||||
|
t.Run("with skipCharts=true", func(t *testing.T) {
|
||||||
|
testListWithEnvironment(t, configImpl{skipCharts: true})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func testListWithJSONOutput(t *testing.T, cfg configImpl) {
|
||||||
|
cfg.output = "json"
|
||||||
|
|
||||||
|
files := map[string]string{
|
||||||
|
"/path/to/helmfile.d/first.yaml": `
|
||||||
|
environments:
|
||||||
|
default:
|
||||||
|
values:
|
||||||
|
- myrelease2:
|
||||||
|
enabled: false
|
||||||
|
releases:
|
||||||
|
- name: myrelease1
|
||||||
|
chart: mychart1
|
||||||
|
installed: no
|
||||||
|
labels:
|
||||||
|
id: myrelease1
|
||||||
|
- name: myrelease2
|
||||||
|
chart: mychart1
|
||||||
|
condition: myrelease2.enabled
|
||||||
|
`,
|
||||||
|
"/path/to/helmfile.d/second.yaml": `
|
||||||
|
releases:
|
||||||
|
- name: myrelease3
|
||||||
|
chart: mychart1
|
||||||
|
installed: yes
|
||||||
|
- name: myrelease4
|
||||||
|
chart: mychart1
|
||||||
|
labels:
|
||||||
|
id: myrelease1
|
||||||
|
`,
|
||||||
|
}
|
||||||
|
stdout := os.Stdout
|
||||||
|
defer func() { os.Stdout = stdout }()
|
||||||
|
|
||||||
|
var buffer bytes.Buffer
|
||||||
|
logger := helmexec.NewLogger(&buffer, "debug")
|
||||||
|
|
||||||
|
app := appWithFs(&App{
|
||||||
|
OverrideHelmBinary: DefaultHelmBinary,
|
||||||
|
fs: ffs.DefaultFileSystem(),
|
||||||
|
OverrideKubeContext: "default",
|
||||||
|
Env: "default",
|
||||||
|
Logger: logger,
|
||||||
|
Namespace: "testNamespace",
|
||||||
|
}, files)
|
||||||
|
|
||||||
|
expectNoCallsToHelm(app)
|
||||||
|
|
||||||
|
out := testutil.CaptureStdout(func() {
|
||||||
|
err := app.ListReleases(cfg)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
})
|
||||||
|
|
||||||
|
expected := `[{"name":"myrelease1","namespace":"","enabled":true,"installed":false,"labels":"id:myrelease1","chart":"mychart1","version":""},{"name":"myrelease2","namespace":"","enabled":false,"installed":true,"labels":"","chart":"mychart1","version":""},{"name":"myrelease3","namespace":"","enabled":true,"installed":true,"labels":"","chart":"mychart1","version":""},{"name":"myrelease4","namespace":"","enabled":true,"installed":true,"labels":"id:myrelease1","chart":"mychart1","version":""}]
|
||||||
|
`
|
||||||
|
assert.Equal(t, expected, out)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestListWithJSONOutput(t *testing.T) {
|
||||||
|
t.Run("with skipCharts=false", func(t *testing.T) {
|
||||||
|
testListWithJSONOutput(t, configImpl{skipCharts: false})
|
||||||
|
})
|
||||||
|
t.Run("with skipCharts=true", func(t *testing.T) {
|
||||||
|
testListWithJSONOutput(t, configImpl{skipCharts: true})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2220,6 +2220,7 @@ type configImpl struct {
|
||||||
skipNeeds bool
|
skipNeeds bool
|
||||||
includeNeeds bool
|
includeNeeds bool
|
||||||
includeTransitiveNeeds bool
|
includeTransitiveNeeds bool
|
||||||
|
skipCharts bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c configImpl) Selectors() []string {
|
func (c configImpl) Selectors() []string {
|
||||||
|
|
@ -2294,6 +2295,10 @@ func (c configImpl) Output() string {
|
||||||
return c.output
|
return c.output
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c configImpl) SkipCharts() bool {
|
||||||
|
return c.skipCharts
|
||||||
|
}
|
||||||
|
|
||||||
type applyConfig struct {
|
type applyConfig struct {
|
||||||
args string
|
args string
|
||||||
values []string
|
values []string
|
||||||
|
|
@ -4622,64 +4627,6 @@ myrelease4 true true id:myrelease1 mychart1
|
||||||
assert.Equal(t, expected, out)
|
assert.Equal(t, expected, out)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestListWithJsonOutput(t *testing.T) {
|
|
||||||
files := map[string]string{
|
|
||||||
"/path/to/helmfile.d/first.yaml": `
|
|
||||||
environments:
|
|
||||||
default:
|
|
||||||
values:
|
|
||||||
- myrelease2:
|
|
||||||
enabled: false
|
|
||||||
releases:
|
|
||||||
- name: myrelease1
|
|
||||||
chart: mychart1
|
|
||||||
installed: no
|
|
||||||
labels:
|
|
||||||
id: myrelease1
|
|
||||||
- name: myrelease2
|
|
||||||
chart: mychart1
|
|
||||||
condition: myrelease2.enabled
|
|
||||||
`,
|
|
||||||
"/path/to/helmfile.d/second.yaml": `
|
|
||||||
releases:
|
|
||||||
- name: myrelease3
|
|
||||||
chart: mychart1
|
|
||||||
installed: yes
|
|
||||||
- name: myrelease4
|
|
||||||
chart: mychart1
|
|
||||||
labels:
|
|
||||||
id: myrelease1
|
|
||||||
`,
|
|
||||||
}
|
|
||||||
stdout := os.Stdout
|
|
||||||
defer func() { os.Stdout = stdout }()
|
|
||||||
|
|
||||||
var buffer bytes.Buffer
|
|
||||||
logger := helmexec.NewLogger(&buffer, "debug")
|
|
||||||
|
|
||||||
app := appWithFs(&App{
|
|
||||||
OverrideHelmBinary: DefaultHelmBinary,
|
|
||||||
fs: ffs.DefaultFileSystem(),
|
|
||||||
OverrideKubeContext: "default",
|
|
||||||
Env: "default",
|
|
||||||
Logger: logger,
|
|
||||||
Namespace: "testNamespace",
|
|
||||||
}, files)
|
|
||||||
|
|
||||||
expectNoCallsToHelm(app)
|
|
||||||
|
|
||||||
out := testutil.CaptureStdout(func() {
|
|
||||||
err := app.ListReleases(configImpl{
|
|
||||||
output: "json",
|
|
||||||
})
|
|
||||||
assert.Nil(t, err)
|
|
||||||
})
|
|
||||||
|
|
||||||
expected := `[{"name":"myrelease1","namespace":"","enabled":true,"installed":false,"labels":"id:myrelease1","chart":"mychart1","version":""},{"name":"myrelease2","namespace":"","enabled":false,"installed":true,"labels":"","chart":"mychart1","version":""},{"name":"myrelease3","namespace":"","enabled":true,"installed":true,"labels":"","chart":"mychart1","version":""},{"name":"myrelease4","namespace":"","enabled":true,"installed":true,"labels":"id:myrelease1","chart":"mychart1","version":""}]
|
|
||||||
`
|
|
||||||
assert.Equal(t, expected, out)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSetValuesTemplate(t *testing.T) {
|
func TestSetValuesTemplate(t *testing.T) {
|
||||||
files := map[string]string{
|
files := map[string]string{
|
||||||
"/path/to/helmfile.yaml": `
|
"/path/to/helmfile.yaml": `
|
||||||
|
|
|
||||||
|
|
@ -236,6 +236,7 @@ type interactive interface {
|
||||||
|
|
||||||
type ListConfigProvider interface {
|
type ListConfigProvider interface {
|
||||||
Output() string
|
Output() string
|
||||||
|
SkipCharts() bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type CacheConfigProvider interface{}
|
type CacheConfigProvider interface{}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,8 @@ type ListOptions struct {
|
||||||
Output string
|
Output string
|
||||||
// KeepTempDir is the keep temp dir flag
|
// KeepTempDir is the keep temp dir flag
|
||||||
KeepTempDir bool
|
KeepTempDir bool
|
||||||
|
// SkipCharts makes List skip `withPreparedCharts`
|
||||||
|
SkipCharts bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewListOptions creates a new Apply
|
// NewListOptions creates a new Apply
|
||||||
|
|
@ -36,3 +38,8 @@ func (c *ListImpl) Args() string {
|
||||||
func (c *ListImpl) Output() string {
|
func (c *ListImpl) Output() string {
|
||||||
return c.ListOptions.Output
|
return c.ListOptions.Output
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SkipCharts returns skipCharts flag
|
||||||
|
func (c *ListImpl) SkipCharts() bool {
|
||||||
|
return c.ListOptions.SkipCharts
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue