Skip to content

Commit 64112b1

Browse files
committed
test: address Helm lifecycle review feedback
1 parent fb46e32 commit 64112b1

7 files changed

Lines changed: 90 additions & 66 deletions

File tree

examples/helm/atmos.yaml

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,16 @@ commands:
4242
- atmos validate stacks
4343
# Dependency acquisition is explicit: the opt-in flag fetches the missing
4444
# file:// library and updates the local chart before the first render.
45-
- atmos helm template demo -s dev --dependency-update --output=/tmp/atmos-helm-template.yaml
4645
# Template output includes weighted hooks and leaves Helm `tpl` expressions
4746
# in values for the chart to evaluate with its native .Values context.
4847
- command: >-
49-
test "$(grep -c '^ name: demo-hook-order$' /tmp/atmos-helm-template.yaml)" -eq 2 &&
50-
grep -q 'helm.sh/hook-weight: "-2"' /tmp/atmos-helm-template.yaml &&
51-
grep -q 'helm.sh/hook-weight: "-1"' /tmp/atmos-helm-template.yaml &&
52-
grep -q 'rendered: from-stack' /tmp/atmos-helm-template.yaml
48+
artifact=$(mktemp ./atmos-helm-template.XXXXXX.yaml);
49+
trap 'rm -f "$artifact"' EXIT;
50+
atmos helm template demo -s dev --dependency-update --output="$artifact" &&
51+
test "$(grep -c '^ name: demo-hook-order$' "$artifact")" -eq 2 &&
52+
grep -q 'helm.sh/hook-weight: "-2"' "$artifact" &&
53+
grep -q 'helm.sh/hook-weight: "-1"' "$artifact" &&
54+
grep -q 'rendered: from-stack' "$artifact"
5355
- command: atmos emulator up kubernetes -s dev
5456
retry:
5557
max_attempts: 2

internal/exec/describe_affected_components_test.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -645,6 +645,34 @@ func TestProcessHelmComponentsIndexed_ValuesFileChangedOutsideComponentBasePath(
645645
assert.Contains(t, affected[0].AffectedAll, affectedReasonStackValuesFile)
646646
}
647647

648+
func TestProcessHelmComponentsIndexed_AbsoluteValuesFileChanged(t *testing.T) {
649+
tempDir := t.TempDir()
650+
atmosConfig := helmAtmosConfig()
651+
atmosConfig.BasePath = tempDir
652+
653+
valuesFile := filepath.Join(tempDir, "config", "helm", "app-values.yaml")
654+
identical := map[string]any{
655+
cfg.ComponentSectionName: "shared-chart",
656+
sectionNameChart: ".",
657+
sectionNameValuesF: []any{valuesFile},
658+
}
659+
helmSection := map[string]any{helmTestComponent: identical}
660+
remoteStacks := helmRemoteStacksWith(identical)
661+
filesIndex := newChangedFilesIndex(atmosConfig, []string{valuesFile}, tempDir)
662+
663+
affected, err := processHelmComponentsIndexed(
664+
helmTestStack, helmSection, &remoteStacks, &remoteStacks,
665+
atmosConfig, filesIndex, newComponentPathPatternCache(),
666+
false, false, false,
667+
)
668+
require.NoError(t, err)
669+
670+
require.Len(t, affected, 1)
671+
assert.Equal(t, helmTestComponent, affected[0].Component)
672+
assert.Equal(t, cfg.HelmComponentType, affected[0].ComponentType)
673+
assert.Contains(t, affected[0].AffectedAll, affectedReasonStackValuesFile)
674+
}
675+
648676
func TestProcessHelmComponentsIndexed_UnrelatedFileDoesNotAffectValuesFile(t *testing.T) {
649677
tempDir := t.TempDir()
650678
atmosConfig := helmAtmosConfig()

pkg/ci/plugins/helm/plugin_test.go

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -264,8 +264,9 @@ func TestTemplateRendering(t *testing.T) {
264264
"history": map[string]any{"max": 10},
265265
},
266266
contains: []string{
267-
"Helm Apply Summary", "bitnami/nginx", "Deployment", "Release lifecycle",
268-
"| Wait strategy | `watcher` |",
267+
"Helm Apply Summary", "bitnami/nginx", "Deployment", "\n### Release lifecycle\n",
268+
"\n| Operation | `upgrade` |\n",
269+
"\n| Wait strategy | `watcher` |\n",
269270
"| Timeout | `30m0s` |",
270271
"| Chart hooks enabled | `true` |",
271272
"| Wait for Jobs | `true` |",
@@ -286,8 +287,8 @@ func TestTemplateRendering(t *testing.T) {
286287
"crds": "create",
287288
},
288289
contains: []string{
289-
"Helm Apply Summary", "Release lifecycle",
290-
"| Operation | `install` |",
290+
"Helm Apply Summary", "\n### Release lifecycle\n",
291+
"\n| Operation | `install` |\n",
291292
"| Wait strategy | `hookOnly` |",
292293
"| Timeout | `5m0s` |",
293294
"| Chart hooks enabled | `true` |",
@@ -305,7 +306,8 @@ func TestTemplateRendering(t *testing.T) {
305306
},
306307
contains: []string{
307308
"Helm Apply Summary",
308-
"| Applied | `false` |",
309+
"\n### Release lifecycle\n",
310+
"\n| Applied | `false` |\n",
309311
"| Target kind | `git` |",
310312
"| Reason | `external_target` |",
311313
},
@@ -321,8 +323,8 @@ func TestTemplateRendering(t *testing.T) {
321323
"chart_hooks": false,
322324
},
323325
contains: []string{
324-
"Helm Delete Summary", "Release lifecycle",
325-
"| Operation | `delete` |",
326+
"Helm Delete Summary", "\n### Release lifecycle\n",
327+
"\n| Operation | `delete` |\n",
326328
"| Wait strategy | `legacy` |",
327329
"| Timeout | `10m0s` |",
328330
"| Chart hooks enabled | `false` |",
@@ -336,7 +338,8 @@ func TestTemplateRendering(t *testing.T) {
336338
},
337339
contains: []string{
338340
"Helm Delete Summary",
339-
"| Deleted | `false` |",
341+
"\n### Release lifecycle\n",
342+
"\n| Deleted | `false` |\n",
340343
"| Target kind | `git` |",
341344
"| Reason | `external_target` |",
342345
},

pkg/ci/plugins/helm/templates/apply.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,19 @@
1414
| Objects | `{{ .ObjectCount }}` |
1515
| Manifest bytes | `{{ .ManifestBytes }}` |
1616

17-
{{- with .Lifecycle }}
17+
{{ with .Lifecycle }}
1818

1919
### Release lifecycle
2020

21-
{{- if eq (index . "reason") "external_target" }}
21+
{{ if eq (index . "reason") "external_target" }}
2222

2323
| Field | Value |
2424
| --- | --- |
2525
| Applied | `false` |
2626
| Target kind | `{{ index . "target_kind" }}` |
2727
| Reason | `external_target` |
2828

29-
{{- else }}
29+
{{ else }}
3030

3131
| Field | Value |
3232
| --- | --- |
@@ -37,20 +37,20 @@
3737
| Wait for Jobs | `{{ index (index . "wait") "jobs" }}` |
3838
| On failure | `{{ index . "on_failure" }}` |
3939

40-
{{- if eq (index . "operation") "install" }}
40+
{{ if eq (index . "operation") "install" }}
4141
| Install CRDs | `{{ index . "crds" }}` |
4242

43-
{{- end }}
43+
{{ end }}
4444

45-
{{- if eq (index . "operation") "upgrade" }}
45+
{{ if eq (index . "operation") "upgrade" }}
4646
| Cleanup on failure | `{{ index . "cleanup_on_failure" }}` |
4747
| Maximum history | `{{ index (index . "history") "max" }}` |
4848

49-
{{- end }}
49+
{{ end }}
5050

51-
{{- end }}
51+
{{ end }}
5252

53-
{{- end }}
53+
{{ end }}
5454

5555
To reproduce locally:
5656

pkg/ci/plugins/helm/templates/delete.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,19 @@
1010
| Release | `{{ .ReleaseName }}` |
1111
| Namespace | `{{ .Namespace }}` |
1212

13-
{{- with .Lifecycle }}
13+
{{ with .Lifecycle }}
1414

1515
### Release lifecycle
1616

17-
{{- if eq (index . "reason") "external_target" }}
17+
{{ if eq (index . "reason") "external_target" }}
1818

1919
| Field | Value |
2020
| --- | --- |
2121
| Deleted | `false` |
2222
| Target kind | `{{ index . "target_kind" }}` |
2323
| Reason | `external_target` |
2424

25-
{{- else }}
25+
{{ else }}
2626

2727
| Field | Value |
2828
| --- | --- |
@@ -31,9 +31,9 @@
3131
| Timeout | `{{ index . "timeout" }}` |
3232
| Chart hooks enabled | `{{ index . "chart_hooks" }}` |
3333

34-
{{- end }}
34+
{{ end }}
3535

36-
{{- end }}
36+
{{ end }}
3737

3838
To reproduce locally:
3939

pkg/component/helm/lifecycle_test.go

Lines changed: 29 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -111,46 +111,37 @@ func TestResolveReleaseLifecycleDerivedWaitStrategy(t *testing.T) {
111111
}
112112
}
113113

114-
func TestResolveReleaseLifecycleWithFlagsReportsDerivedWaitStrategy(t *testing.T) {
115-
input, err := decodeReleasePolicy(map[string]any{
116-
cfg.HelmReleaseSectionName: map[string]any{
117-
cfg.HelmWaitSectionName: map[string]any{
118-
cfg.HelmWaitStrategySectionName: "hookOnly",
119-
},
120-
cfg.HelmUpgradeSectionName: map[string]any{
121-
cfg.HelmOnFailureSectionName: "rollback",
122-
cfg.HelmWaitSectionName: map[string]any{
123-
cfg.HelmWaitJobsSectionName: true,
114+
func TestResolveReleaseLifecycleWithFlagsDerivesWaitStrategyAfterFlagOverlay(t *testing.T) {
115+
for _, tt := range []struct {
116+
name string
117+
configuredFailure string
118+
flags map[string]any
119+
wantStrategy kube.WaitStrategy
120+
wantDerived bool
121+
}{
122+
{name: "configured rollback", configuredFailure: "rollback", wantStrategy: kube.StatusWatcherStrategy, wantDerived: true},
123+
{name: "flag rollback", flags: map[string]any{cfg.HelmOnFailureSectionName: "rollback"}, wantStrategy: kube.StatusWatcherStrategy, wantDerived: true},
124+
{name: "flag keep disables configured rollback", configuredFailure: "rollback", flags: map[string]any{cfg.HelmOnFailureSectionName: "keep"}, wantStrategy: kube.HookOnlyStrategy},
125+
} {
126+
t.Run(tt.name, func(t *testing.T) {
127+
upgrade := map[string]any{}
128+
if tt.configuredFailure != "" {
129+
upgrade[cfg.HelmOnFailureSectionName] = tt.configuredFailure
130+
}
131+
input, err := decodeReleasePolicy(map[string]any{
132+
cfg.HelmReleaseSectionName: map[string]any{
133+
cfg.HelmWaitSectionName: map[string]any{cfg.HelmWaitStrategySectionName: "hookOnly"},
134+
cfg.HelmUpgradeSectionName: upgrade,
124135
},
125-
},
126-
},
127-
})
128-
require.NoError(t, err)
129-
130-
resolution, err := resolveReleaseLifecycleWithFlags(input, releaseOperationUpgrade, nil)
131-
require.NoError(t, err)
132-
assert.Equal(t, kube.StatusWatcherStrategy, resolution.Policy.WaitStrategy)
133-
assert.True(t, resolution.Policy.WaitForJobs)
134-
assert.True(t, hasLifecycleWarning(resolution.Warnings, warningWaitDerived))
135-
}
136-
137-
func TestResolveReleaseLifecycleWithFlagsCanDisableDerivedWaitStrategy(t *testing.T) {
138-
input, err := decodeReleasePolicy(map[string]any{
139-
cfg.HelmReleaseSectionName: map[string]any{
140-
cfg.HelmWaitSectionName: map[string]any{cfg.HelmWaitStrategySectionName: "hookOnly"},
141-
cfg.HelmUpgradeSectionName: map[string]any{
142-
cfg.HelmOnFailureSectionName: "rollback",
143-
},
144-
},
145-
})
146-
require.NoError(t, err)
136+
})
137+
require.NoError(t, err)
147138

148-
resolution, err := resolveReleaseLifecycleWithFlags(input, releaseOperationUpgrade, map[string]any{
149-
cfg.HelmOnFailureSectionName: "keep",
150-
})
151-
require.NoError(t, err)
152-
assert.Equal(t, kube.HookOnlyStrategy, resolution.Policy.WaitStrategy)
153-
assert.False(t, hasLifecycleWarning(resolution.Warnings, warningWaitDerived))
139+
resolution, err := resolveReleaseLifecycleWithFlags(input, releaseOperationUpgrade, tt.flags)
140+
require.NoError(t, err)
141+
assert.Equal(t, tt.wantStrategy, resolution.Policy.WaitStrategy)
142+
assert.Equal(t, tt.wantDerived, hasLifecycleWarning(resolution.Warnings, warningWaitDerived))
143+
})
144+
}
154145
}
155146

156147
func TestResolveReleaseLifecycleWithFlagsHighestPrecedence(t *testing.T) {

website/docs/cli/commands/helm/helm-apply.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ Install or upgrade the release in the cluster:
2626
atmos helm apply monitoring -s plat-ue2-dev
2727
```
2828

29-
Apply an explicit production readiness and recovery policy:
29+
Upgrade an existing release with an explicit production readiness and recovery policy:
3030

3131
```shell
3232
atmos helm apply monitoring -s plat-ue2-dev \

0 commit comments

Comments
 (0)