Merge pull request #79 from Sajfer/preapply

Add preapply hook
This commit is contained in:
yxxhero 2022-09-19 10:58:04 +08:00 committed by GitHub
commit 24810a45ae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 712 additions and 11 deletions

View File

@ -1183,6 +1183,7 @@ Once `events` are triggered, associated `hooks` are executed, by running the `co
Currently supported `events` are:
- `prepare`
- `preapply`
- `presync`
- `preuninstall`
- `postuninstall`
@ -1192,9 +1193,12 @@ Currently supported `events` are:
Hooks associated to `prepare` events are triggered after each release in your helmfile is loaded from YAML, before execution.
`prepare` hooks are triggered on the release as long as it is not excluded by the helmfile selector(e.g. `helmfile -l key=value`).
Hooks associated to `presync` events are triggered before each release is applied to the remote cluster.
Hooks associated to `presync` events are triggered before each release is installed or upgraded on the remote cluster.
This is the ideal event to execute any commands that may mutate the cluster state as it will not be run for read-only operations like `lint`, `diff` or `template`.
`preapply` hooks are triggered before a release is uninstalled, installed, or upgraded as part of `helmfile apply`.
This is the ideal event to hook into when you are going to use `helmfile apply` for every kind of change, and you want the hook to be called only when any kind of change is being made.
`preuninstall` hooks are triggered immediately before a release is uninstalled as part of `helmfile apply`, `helmfile sync`, `helmfile delete`, and `helmfile destroy`.
`postuninstall` hooks are triggered immediately after successful uninstall of a release while running `helmfile apply`, `helmfile sync`, `helmfile delete`, `helmfile destroy`.

3
go.mod
View File

@ -29,12 +29,14 @@ require (
github.com/variantdev/vals v0.18.0
go.uber.org/multierr v1.6.0
go.uber.org/zap v1.23.0
golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211
gopkg.in/yaml.v2 v2.4.0
gotest.tools v2.2.0+incompatible
helm.sh/helm/v3 v3.8.1
k8s.io/apimachinery v0.24.4
k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9
)
require (
@ -194,7 +196,6 @@ require (
k8s.io/client-go v0.23.4 // indirect
k8s.io/klog/v2 v2.60.1 // indirect
k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42 // indirect
k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 // indirect
oras.land/oras-go v1.1.0 // indirect
sigs.k8s.io/kustomize/api v0.10.1 // indirect
sigs.k8s.io/kustomize/kyaml v0.13.0 // indirect

2
go.sum
View File

@ -1373,6 +1373,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561 h1:MDc5xs78ZrZr3HMQugiXOAkSZtfTpbJLDr/lwfgO53E=
golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=

View File

@ -790,7 +790,7 @@ func (a *App) visitStates(fileOrDir string, defOpts LoadOpts, converge func(*sta
go func() {
sig := <-sigs
errs := []error{fmt.Errorf("Received [%s] to shutdown ", sig)}
errs := []error{fmt.Errorf("received [%s] to shutdown ", sig)}
_ = context{app: a, st: st, retainValues: defOpts.RetainValuesFiles}.clean(errs)
// See http://tldp.org/LDP/abs/html/exitcodes.html
switch sig {
@ -1342,7 +1342,7 @@ Do you really want to apply?
a.Logger.Debug(*infoMsg)
}
applyErrs := []error{}
var applyErrs []error
affectedReleases := state.AffectedReleases{}
@ -1355,15 +1355,27 @@ Do you really want to apply?
// We deleted releases by traversing the DAG in reverse order
if len(releasesToBeDeleted) > 0 {
_, deletionErrs := withDAG(st, helm, a.Logger, state.PlanOptions{Reverse: true, SelectedReleases: toDelete, SkipNeeds: true}, a.WrapWithoutSelector(func(subst *state.HelmState, helm helmexec.Interface) []error {
var rs []state.ReleaseSpec
var (
rs []state.ReleaseSpec
preapplyErrors []error
)
for _, r := range subst.Releases {
release := r
if r2, ok := releasesToBeDeleted[state.ReleaseToID(&release)]; ok {
if _, err := st.TriggerPreapplyEvent(&r2, "apply"); err != nil {
preapplyErrors = append(applyErrs, err)
continue
}
rs = append(rs, r2)
}
}
if len(preapplyErrors) > 0 {
return preapplyErrors
}
subst.Releases = rs
return subst.DeleteReleasesForSync(&affectedReleases, helm, c.Concurrency())
@ -1377,15 +1389,27 @@ Do you really want to apply?
// We upgrade releases by traversing the DAG
if len(releasesToBeUpdated) > 0 {
_, updateErrs := withDAG(st, helm, a.Logger, state.PlanOptions{SelectedReleases: toUpdate, Reverse: false, SkipNeeds: true, IncludeTransitiveNeeds: c.IncludeTransitiveNeeds()}, a.WrapWithoutSelector(func(subst *state.HelmState, helm helmexec.Interface) []error {
var rs []state.ReleaseSpec
var (
rs []state.ReleaseSpec
preapplyErrors []error
)
for _, r := range subst.Releases {
release := r
if r2, ok := releasesToBeUpdated[state.ReleaseToID(&release)]; ok {
if _, err := st.TriggerPreapplyEvent(&r2, "apply"); err != nil {
preapplyErrors = append(applyErrs, err)
continue
}
rs = append(rs, r2)
}
}
if len(preapplyErrors) > 0 {
return preapplyErrors
}
subst.Releases = rs
syncOpts := state.SyncOpts{

View File

@ -0,0 +1,485 @@
package app
import (
"bufio"
"bytes"
"io"
"sync"
"testing"
"github.com/google/go-cmp/cmp"
"github.com/variantdev/vals"
"github.com/helmfile/helmfile/pkg/exectest"
"github.com/helmfile/helmfile/pkg/helmexec"
"github.com/helmfile/helmfile/pkg/testhelper"
)
func TestApply_hooks(t *testing.T) {
type fields struct {
skipNeeds bool
includeNeeds bool
includeTransitiveNeeds bool
}
type testcase struct {
fields fields
ns string
concurrency int
skipDiffOnInstall bool
error string
files map[string]string
selectors []string
lists map[exectest.ListKey]string
diffs map[exectest.DiffKey]error
upgraded []exectest.Release
deleted []exectest.Release
log string
logLevel string
}
check := func(t *testing.T, tc testcase) {
t.Helper()
wantUpgrades := tc.upgraded
wantDeletes := tc.deleted
var helm = &exectest.Helm{
FailOnUnexpectedList: true,
FailOnUnexpectedDiff: true,
Lists: tc.lists,
Diffs: tc.diffs,
DiffMutex: &sync.Mutex{},
ChartsMutex: &sync.Mutex{},
ReleasesMutex: &sync.Mutex{},
}
bs := &bytes.Buffer{}
func() {
t.Helper()
logReader, logWriter := io.Pipe()
logFlushed := &sync.WaitGroup{}
// Ensure all the log is consumed into `bs` by calling `logWriter.Close()` followed by `logFlushed.Wait()`
logFlushed.Add(1)
go func() {
scanner := bufio.NewScanner(logReader)
for scanner.Scan() {
bs.Write(scanner.Bytes())
bs.WriteString("\n")
}
logFlushed.Done()
}()
defer func() {
// This is here to avoid data-trace on bytes buffer `bs` to capture logs
if err := logWriter.Close(); err != nil {
panic(err)
}
logFlushed.Wait()
}()
logger := helmexec.NewLogger(logWriter, tc.logLevel)
valsRuntime, err := vals.New(vals.Options{CacheSize: 32})
if err != nil {
t.Errorf("unexpected error creating vals runtime: %v", err)
}
app := appWithFs(&App{
OverrideHelmBinary: DefaultHelmBinary,
OverrideKubeContext: "default",
Env: "default",
Logger: logger,
helms: map[helmKey]helmexec.Interface{
createHelmKey("helm", "default"): helm,
},
valsRuntime: valsRuntime,
}, tc.files)
if tc.ns != "" {
app.Namespace = tc.ns
}
if tc.selectors != nil {
app.Selectors = tc.selectors
}
syncErr := app.Apply(applyConfig{
// if we check log output, concurrency must be 1. otherwise the test becomes non-deterministic.
concurrency: tc.concurrency,
logger: logger,
skipDiffOnInstall: tc.skipDiffOnInstall,
skipNeeds: tc.fields.skipNeeds,
includeNeeds: tc.fields.includeNeeds,
includeTransitiveNeeds: tc.fields.includeTransitiveNeeds,
})
var gotErr string
if syncErr != nil {
gotErr = syncErr.Error()
}
if d := cmp.Diff(tc.error, gotErr); d != "" {
t.Fatalf("unexpected error: want (-), got (+): %s", d)
}
if len(wantUpgrades) > len(helm.Releases) {
t.Fatalf("insufficient number of upgrades: got %d, want %d", len(helm.Releases), len(wantUpgrades))
}
for relIdx := range wantUpgrades {
if wantUpgrades[relIdx].Name != helm.Releases[relIdx].Name {
t.Errorf("releases[%d].name: got %q, want %q", relIdx, helm.Releases[relIdx].Name, wantUpgrades[relIdx].Name)
}
for flagIdx := range wantUpgrades[relIdx].Flags {
if wantUpgrades[relIdx].Flags[flagIdx] != helm.Releases[relIdx].Flags[flagIdx] {
t.Errorf("releases[%d].flags[%d]: got %v, want %v", relIdx, flagIdx, helm.Releases[relIdx].Flags[flagIdx], wantUpgrades[relIdx].Flags[flagIdx])
}
}
}
if len(wantDeletes) > len(helm.Deleted) {
t.Fatalf("insufficient number of deletes: got %d, want %d", len(helm.Deleted), len(wantDeletes))
}
for relIdx := range wantDeletes {
if wantDeletes[relIdx].Name != helm.Deleted[relIdx].Name {
t.Errorf("releases[%d].name: got %q, want %q", relIdx, helm.Deleted[relIdx].Name, wantDeletes[relIdx].Name)
}
for flagIdx := range wantDeletes[relIdx].Flags {
if wantDeletes[relIdx].Flags[flagIdx] != helm.Deleted[relIdx].Flags[flagIdx] {
t.Errorf("releaes[%d].flags[%d]: got %v, want %v", relIdx, flagIdx, helm.Deleted[relIdx].Flags[flagIdx], wantDeletes[relIdx].Flags[flagIdx])
}
}
}
}()
if tc.log != "" {
actual := bs.String()
diff, exists := testhelper.Diff(tc.log, actual, 3)
if exists {
t.Errorf("unexpected log:\nDIFF\n%s\nEOD", diff)
}
} else {
assertEqualsToSnapshot(t, "log", bs.String())
}
}
t.Run("apply release with preapply hook", func(t *testing.T) {
check(t, testcase{
files: map[string]string{
"/path/to/helmfile.yaml": `
releases:
- name: foo
chart: incubator/raw
namespace: default
labels:
app: test
hooks:
- events: ["preapply"]
command: echo
showlogs: true
args: ["foo"]
`,
},
selectors: []string{"name=foo"},
upgraded: []exectest.Release{
{Name: "foo"},
},
diffs: map[exectest.DiffKey]error{
{Name: "foo", Chart: "incubator/raw", Flags: "--kube-contextdefault--namespacedefault--detailed-exitcode"}: helmexec.ExitError{Code: 2},
},
error: "",
// as we check for log output, set concurrency to 1 to avoid non-deterministic test result
concurrency: 1,
logLevel: "info",
})
})
t.Run("apply release with preapply hook", func(t *testing.T) {
check(t, testcase{
files: map[string]string{
"/path/to/helmfile.yaml": `
releases:
- name: foo
chart: incubator/raw
namespace: default
labels:
app: test
hooks:
- events: ["prepare", "preapply", "presync"]
command: echo
showlogs: true
args: ["foo"]
`,
},
selectors: []string{"name=foo"},
upgraded: []exectest.Release{
{Name: "foo"},
},
diffs: map[exectest.DiffKey]error{
{Name: "foo", Chart: "incubator/raw", Flags: "--kube-contextdefault--namespacedefault--detailed-exitcode"}: helmexec.ExitError{Code: 2},
},
error: "",
// as we check for log output, set concurrency to 1 to avoid non-deterministic test result
concurrency: 1,
logLevel: "info",
})
})
t.Run("apply release with preapply hook", func(t *testing.T) {
check(t, testcase{
files: map[string]string{
"/path/to/helmfile.yaml": `
releases:
- name: foo
chart: incubator/raw
namespace: default
labels:
app: test
hooks:
- events: ["presync"]
command: echo
showlogs: true
args: ["foo"]
`,
},
selectors: []string{"name=foo"},
upgraded: []exectest.Release{
{Name: "foo"},
},
diffs: map[exectest.DiffKey]error{
{Name: "foo", Chart: "incubator/raw", Flags: "--kube-contextdefault--namespacedefault--detailed-exitcode"}: helmexec.ExitError{Code: 2},
},
error: "",
// as we check for log output, set concurrency to 1 to avoid non-deterministic test result
concurrency: 1,
logLevel: "info",
})
})
t.Run("hooks for no-diff release", func(t *testing.T) {
check(t, testcase{
files: map[string]string{
"/path/to/helmfile.yaml": `
releases:
- name: foo
chart: incubator/raw
namespace: default
labels:
app: test
hooks:
# only prepare and cleanup are run
- events: ["prepare", "preapply", "presync", "cleanup"]
command: echo
showlogs: true
args: ["foo"]
`,
},
selectors: []string{"app=test"},
diffs: map[exectest.DiffKey]error{
{Name: "foo", Chart: "incubator/raw", Flags: "--kube-contextdefault--namespacedefault--detailed-exitcode"}: nil,
},
error: "",
// as we check for log output, set concurrency to 1 to avoid non-deterministic test result
concurrency: 1,
logLevel: "info",
})
})
t.Run("hooks are run on enabled release", func(t *testing.T) {
check(t, testcase{
files: map[string]string{
"/path/to/helmfile.yaml": `
values:
- bar:
enabled: true
releases:
- name: foo
chart: incubator/raw
namespace: default
labels:
app: test
hooks:
- events: ["prepare", "preapply", "presync"]
command: echo
showlogs: true
args: ["foo"]
- name: bar
condition: bar.enabled
chart: incubator/raw
namespace: default
labels:
app: test
hooks:
- events: ["prepare", "preapply", "presync"]
command: echo
showlogs: true
args: ["bar"]
`,
},
selectors: []string{"app=test"},
upgraded: []exectest.Release{
{Name: "foo"},
{Name: "bar"},
},
diffs: map[exectest.DiffKey]error{
{Name: "foo", Chart: "incubator/raw", Flags: "--kube-contextdefault--namespacedefault--detailed-exitcode"}: helmexec.ExitError{Code: 2},
{Name: "bar", Chart: "incubator/raw", Flags: "--kube-contextdefault--namespacedefault--detailed-exitcode"}: helmexec.ExitError{Code: 2},
},
error: "",
// as we check for log output, set concurrency to 1 to avoid non-deterministic test result
concurrency: 1,
logLevel: "info",
})
})
t.Run("hooks are not run on disabled release", func(t *testing.T) {
check(t, testcase{
files: map[string]string{
"/path/to/helmfile.yaml": `
values:
- bar:
enabled: false
releases:
- name: foo
chart: incubator/raw
namespace: default
labels:
app: test
hooks:
- events: ["prepare", "preapply", "presync"]
command: echo
showlogs: true
args: ["foo"]
- name: bar
condition: bar.enabled
chart: incubator/raw
namespace: default
labels:
app: test
hooks:
- events: ["prepare", "preapply", "presync"]
command: echo
showlogs: true
args: ["bar"]
`,
},
selectors: []string{"app=test"},
upgraded: []exectest.Release{
{Name: "foo"},
},
diffs: map[exectest.DiffKey]error{
{Name: "foo", Chart: "incubator/raw", Flags: "--kube-contextdefault--namespacedefault--detailed-exitcode"}: helmexec.ExitError{Code: 2},
},
error: "",
// as we check for log output, set concurrency to 1 to avoid non-deterministic test result
concurrency: 1,
logLevel: "info",
})
})
t.Run("hooks are run on to-be-uninstalled release", func(t *testing.T) {
check(t, testcase{
files: map[string]string{
"/path/to/helmfile.yaml": `
releases:
- name: foo
chart: incubator/raw
namespace: default
labels:
app: test
hooks:
- events: ["prepare", "preapply", "presync"]
command: echo
showlogs: true
args: ["foo"]
- name: bar
installed: false
chart: incubator/raw
namespace: default
labels:
app: test
hooks:
- events: ["prepare", "preapply", "presync"]
command: echo
showlogs: true
args: ["bar"]
`,
},
selectors: []string{"app=test"},
lists: map[exectest.ListKey]string{
{Filter: "^foo$", Flags: helmV2ListFlags}: `NAME REVISION UPDATED STATUS CHART APP VERSION NAMESPACE
foo 4 Fri Nov 1 08:40:07 2019 DEPLOYED raw-3.1.0 3.1.0 default
`,
{Filter: "^bar$", Flags: helmV2ListFlags}: `NAME REVISION UPDATED STATUS CHART APP VERSION NAMESPACE
bar 4 Fri Nov 1 08:40:07 2019 DEPLOYED raw-3.1.0 3.1.0 default
`,
},
upgraded: []exectest.Release{
{Name: "foo"},
},
diffs: map[exectest.DiffKey]error{
{Name: "foo", Chart: "incubator/raw", Flags: "--kube-contextdefault--namespacedefault--detailed-exitcode"}: helmexec.ExitError{Code: 2},
},
error: "",
// as we check for log output, set concurrency to 1 to avoid non-deterministic test result
concurrency: 1,
logLevel: "info",
})
})
t.Run("hooks are not run on alreadyd uninstalled release", func(t *testing.T) {
check(t, testcase{
files: map[string]string{
"/path/to/helmfile.yaml": `
releases:
- name: foo
chart: incubator/raw
namespace: default
labels:
app: test
hooks:
- events: ["prepare", "preapply", "presync"]
command: echo
showlogs: true
args: ["foo"]
- name: bar
installed: false
chart: incubator/raw
namespace: default
labels:
app: test
hooks:
- events: ["prepare", "preapply", "presync"]
command: echo
showlogs: true
args: ["bar"]
`,
},
selectors: []string{"app=test"},
lists: map[exectest.ListKey]string{
{Filter: "^foo$", Flags: helmV2ListFlags}: `NAME REVISION UPDATED STATUS CHART APP VERSION NAMESPACE
foo 4 Fri Nov 1 08:40:07 2019 DEPLOYED raw-3.1.0 3.1.0 default
`,
{Filter: "^bar$", Flags: helmV2ListFlags}: ``,
},
upgraded: []exectest.Release{
{Name: "foo"},
},
diffs: map[exectest.DiffKey]error{
{Name: "foo", Chart: "incubator/raw", Flags: "--kube-contextdefault--namespacedefault--detailed-exitcode"}: helmexec.ExitError{Code: 2},
},
error: "",
// as we check for log output, set concurrency to 1 to avoid non-deterministic test result
concurrency: 1,
logLevel: "info",
})
})
}

View File

@ -137,7 +137,7 @@ func TestApply_2(t *testing.T) {
}
for flagIdx := range wantUpgrades[relIdx].Flags {
if wantUpgrades[relIdx].Flags[flagIdx] != helm.Releases[relIdx].Flags[flagIdx] {
t.Errorf("releaes[%d].flags[%d]: got %v, want %v", relIdx, flagIdx, helm.Releases[relIdx].Flags[flagIdx], wantUpgrades[relIdx].Flags[flagIdx])
t.Errorf("releases[%d].flags[%d]: got %v, want %v", relIdx, flagIdx, helm.Releases[relIdx].Flags[flagIdx], wantUpgrades[relIdx].Flags[flagIdx])
}
}
}

View File

@ -47,10 +47,10 @@ GROUP RELEASES
2 default//foo
processing releases in group 1/2: default//baz, default//bar
getting deployed release version failed:unexpected list key: listkey(filter=^baz$,flags=--kube-contextdefault--deleting--deployed--failed--pending) in
getting deployed release version failed:unexpected list key: listkey(filter=^bar$,flags=--kube-contextdefault--deleting--deployed--failed--pending) in
getting deployed release version failed:unexpected list key: listkey(filter=^baz$,flags=--kube-contextdefault--deleting--deployed--failed--pending) not found in
getting deployed release version failed:unexpected list key: listkey(filter=^bar$,flags=--kube-contextdefault--deleting--deployed--failed--pending) not found in
processing releases in group 2/2: default//foo
getting deployed release version failed:unexpected list key: listkey(filter=^foo$,flags=--kube-contextdefault--deleting--deployed--failed--pending) in
getting deployed release version failed:unexpected list key: listkey(filter=^foo$,flags=--kube-contextdefault--deleting--deployed--failed--pending) not found in
UPDATED RELEASES:
NAME CHART VERSION

View File

@ -0,0 +1,68 @@
processing file "helmfile.yaml" in directory "."
first-pass rendering starting for "helmfile.yaml.part.0": inherited=&{default map[] map[]}, overrode=<nil>
first-pass uses: &{default map[] map[]}
first-pass rendering output of "helmfile.yaml.part.0":
0:
1: releases:
2: - name: foo
3: chart: incubator/raw
4: namespace: default
5: labels:
6: app: test
7: hooks:
8: - events: ["preapply"]
9: command: echo
10: showlogs: true
11: args: ["foo"]
12:
first-pass produced: &{default map[] map[]}
first-pass rendering result of "helmfile.yaml.part.0": {default map[] map[]}
vals:
map[]
defaultVals:[]
second-pass rendering result of "helmfile.yaml.part.0":
0:
1: releases:
2: - name: foo
3: chart: incubator/raw
4: namespace: default
5: labels:
6: app: test
7: hooks:
8: - events: ["preapply"]
9: command: echo
10: showlogs: true
11: args: ["foo"]
12:
merged environment: &{default map[] map[]}
1 release(s) matching name=foo found in helmfile.yaml
Affected releases are:
foo (incubator/raw) UPDATED
Releases with preapply hooks:
foo (incubator/raw)
Running preapply hook for foo:
hook[echo]: stateFilePath=helmfile.yaml, basePath=.
hook[echo]: triggered by event "preapply"
echo:XlBWj> foo
hook[echo]: foo
hook[preapply] logs | foo
hook[preapply] logs |
processing 1 groups of releases in this order:
GROUP RELEASES
1 default/default/foo
processing releases in group 1/1: default/default/foo
getting deployed release version failed:unexpected list key: {^foo$ --kube-contextdefault--deleting--deployed--failed--pending}
UPDATED RELEASES:
NAME CHART VERSION
foo incubator/raw

View File

@ -0,0 +1,14 @@
hook[prepare] logs | foo
hook[prepare] logs |
hook[preapply] logs | foo
hook[preapply] logs |
hook[presync] logs | foo
hook[presync] logs |
UPDATED RELEASES:
NAME CHART VERSION
foo incubator/raw

View File

@ -0,0 +1,8 @@
hook[presync] logs | foo
hook[presync] logs |
UPDATED RELEASES:
NAME CHART VERSION
foo incubator/raw

View File

@ -0,0 +1,8 @@
hook[preapply] logs | foo
hook[preapply] logs |
UPDATED RELEASES:
NAME CHART VERSION
foo incubator/raw

View File

@ -0,0 +1,14 @@
hook[prepare] logs | foo
hook[prepare] logs |
hook[preapply] logs | foo
hook[preapply] logs |
hook[presync] logs | foo
hook[presync] logs |
UPDATED RELEASES:
NAME CHART VERSION
foo incubator/raw 3.1.0

View File

@ -0,0 +1,14 @@
hook[prepare] logs | foo
hook[prepare] logs |
hook[preapply] logs | foo
hook[preapply] logs |
hook[presync] logs | foo
hook[presync] logs |
UPDATED RELEASES:
NAME CHART VERSION
foo incubator/raw

View File

@ -0,0 +1,24 @@
hook[prepare] logs | foo
hook[prepare] logs |
hook[prepare] logs | bar
hook[prepare] logs |
hook[preapply] logs | foo
hook[preapply] logs |
hook[preapply] logs | bar
hook[preapply] logs |
hook[presync] logs | foo
hook[presync] logs |
hook[presync] logs | bar
hook[presync] logs |
UPDATED RELEASES:
NAME CHART VERSION
foo incubator/raw
bar incubator/raw

View File

@ -0,0 +1,24 @@
hook[prepare] logs | foo
hook[prepare] logs |
hook[preapply] logs | bar
hook[preapply] logs |
hook[presync] logs | bar
hook[presync] logs |
hook[preapply] logs | foo
hook[preapply] logs |
hook[presync] logs | foo
hook[presync] logs |
UPDATED RELEASES:
NAME CHART VERSION
foo incubator/raw 3.1.0
DELETED RELEASES:
NAME
bar

View File

@ -0,0 +1,6 @@
hook[prepare] logs | foo
hook[prepare] logs |
hook[cleanup] logs | foo
hook[cleanup] logs |

View File

@ -161,7 +161,7 @@ func (helm *Helm) List(context helmexec.HelmContext, filter string, flags ...str
for k := range helm.Lists {
keys = append(keys, k.String())
}
return "", fmt.Errorf("unexpected list key: %v in %v", key, strings.Join(keys, ", "))
return "", fmt.Errorf("unexpected list key: %v not found in %v", key, strings.Join(keys, ", "))
}
return res, nil
}

View File

@ -2251,6 +2251,10 @@ func (st *HelmState) triggerPostsyncEvent(r *ReleaseSpec, evtErr error, helmfile
return st.triggerReleaseEvent("postsync", evtErr, r, helmfileCommand)
}
func (st *HelmState) TriggerPreapplyEvent(r *ReleaseSpec, helmfileCommand string) (bool, error) {
return st.triggerReleaseEvent("preapply", nil, r, helmfileCommand)
}
func (st *HelmState) triggerReleaseEvent(evt string, evtErr error, r *ReleaseSpec, helmfileCmd string) (bool, error) {
bus := &event.Bus{
Hooks: r.Hooks,
@ -2268,6 +2272,7 @@ func (st *HelmState) triggerReleaseEvent(evt string, evtErr error, r *ReleaseSpe
"Release": r,
"HelmfileCommand": helmfileCmd,
}
return bus.Trigger(evt, evtErr, data)
}