Skip to content

Commit 79d9013

Browse files
authored
feat(api): implement Distribution template function (#3061)
* feat(api): implement Distribution and NodeCount template functions * f * f * f
1 parent fadf159 commit 79d9013

File tree

6 files changed

+61
-21
lines changed

6 files changed

+61
-21
lines changed

api/pkg/template/engine.go

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -23,24 +23,26 @@ const (
2323
)
2424

2525
type Engine struct {
26-
mode Mode
27-
config *kotsv1beta1.Config
28-
license *kotsv1beta1.License
29-
releaseData *release.ReleaseData
26+
mode Mode
27+
config *kotsv1beta1.Config
28+
license *kotsv1beta1.License
29+
releaseData *release.ReleaseData
30+
privateCACertConfigMapName string // ConfigMap name for private CA certificates, empty string if not available
31+
isAirgapInstallation bool // Whether the installation is an airgap installation
32+
33+
// ExecOptions
34+
proxySpec *ecv1beta1.ProxySpec // Proxy spec for the proxy template functions, if applicable
35+
registrySettings *types.RegistrySettings // Registry settings for registry template functions, if applicable
3036

3137
// Internal state
32-
configValues types.AppConfigValues
33-
prevConfigValues types.AppConfigValues
34-
tmpl *template.Template
35-
funcMap template.FuncMap
36-
cache map[string]resolvedConfigItem
37-
depsTree map[string][]string
38-
stack []string
39-
proxySpec *ecv1beta1.ProxySpec // Proxy spec for the proxy template functions, if applicable
40-
registrySettings *types.RegistrySettings // Registry settings for registry template functions, if applicable
41-
privateCACertConfigMapName string // ConfigMap name for private CA certificates, empty string if not available
42-
isAirgapInstallation bool // Whether the installation is an airgap installation
43-
mtx sync.Mutex
38+
configValues types.AppConfigValues
39+
prevConfigValues types.AppConfigValues
40+
tmpl *template.Template
41+
funcMap template.FuncMap
42+
cache map[string]resolvedConfigItem
43+
depsTree map[string][]string
44+
stack []string
45+
mtx sync.Mutex
4446
}
4547

4648
type EngineOption func(*Engine)

api/pkg/template/execute.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ func (e *Engine) getFuncMap() template.FuncMap {
174174
"ParseUint": e.parseUint,
175175
"HumanSize": e.humanSize,
176176
"YamlEscape": e.yamlEscape,
177+
"Distribution": e.distribution,
177178

178179
// Registry template functions
179180
"HasLocalRegistry": e.hasLocalRegistry,
@@ -183,7 +184,7 @@ func (e *Engine) getFuncMap() template.FuncMap {
183184
"ImagePullSecretName": e.imagePullSecretName,
184185
"LocalRegistryImagePullSecret": e.localRegistryImagePullSecret,
185186

186-
// Release template functions
187+
// Airgap template functions
187188
"IsAirgap": e.isAirgap,
188189
}
189190
}

api/pkg/template/static.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,10 @@ func (e *Engine) yamlEscape(plain string) string {
285285
return indented
286286
}
287287

288+
func (e *Engine) distribution() string {
289+
return "embedded-cluster"
290+
}
291+
288292
// copied from sprig
289293
func indent(spaces int, v string) string {
290294
pad := strings.Repeat(" ", spaces)

api/pkg/template/static_test.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -893,3 +893,19 @@ func TestEngine_YamlEscape(t *testing.T) {
893893
})
894894
}
895895
}
896+
897+
func TestEngine_Distribution(t *testing.T) {
898+
config := &kotsv1beta1.Config{
899+
Spec: kotsv1beta1.ConfigSpec{
900+
Groups: []kotsv1beta1.ConfigGroup{},
901+
},
902+
}
903+
904+
engine := NewEngine(config)
905+
906+
err := engine.Parse("{{repl Distribution }}")
907+
require.NoError(t, err)
908+
result, err := engine.Execute(nil, WithProxySpec(&ecv1beta1.ProxySpec{}))
909+
require.NoError(t, err)
910+
assert.Equal(t, "embedded-cluster", result)
911+
}

e2e/kots-release-install-v3/config.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -633,3 +633,11 @@ spec:
633633
---
634634
635635
{{repl if IsAirgap }}Yes{{repl else }}No{{repl end }}
636+
637+
- name: template_function_distribution
638+
type: label
639+
title: |
640+
## Distribution
641+
---
642+
643+
{{repl Distribution }}

web/src/components/wizard/tests/ConfigurationStep.test.tsx

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { setupServer } from "msw/node";
55
import { renderWithProviders } from "../../../test/setup.tsx";
66
import ConfigurationStep from "../config/ConfigurationStep.tsx";
77
import { AppConfig, AppConfigGroup, AppConfigItem, AppConfigValues } from "../../../types";
8+
import '@testing-library/jest-dom/vitest';
89

910
// Mock the debounced fetch to remove timing issues in tests
1011
vi.mock("../../../utils/debouncedFetch", () => ({
@@ -1771,12 +1772,13 @@ describe.each([
17711772
// Mock FileReader for new file upload
17721773
const mockFileReader = {
17731774
readAsDataURL: vi.fn().mockImplementation(() => {
1775+
// Use setTimeout with a small delay to simulate async file reading
17741776
setTimeout(() => {
17751777
if (mockFileReader.onload) {
17761778
// eslint-disable-next-line @typescript-eslint/no-explicit-any
17771779
mockFileReader.onload({ target: { result: 'data:text/plain;base64,bmV3IGNvbnRlbnQ=' } } as any);
17781780
}
1779-
}, 0);
1781+
}, 10);
17801782
}),
17811783
result: 'data:text/plain;base64,bmV3IGNvbnRlbnQ=',
17821784
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -1791,11 +1793,14 @@ describe.each([
17911793
// Upload new file
17921794
fireEvent.change(configFileInput, { target: { files: [newFile] } });
17931795

1794-
// Wait for the new filename to appear
1796+
// Wait for the new filename to appear and file processing to complete
17951797
await waitFor(() => {
17961798
expect(screen.getByText("new-config.yml")).toBeInTheDocument();
17971799
});
17981800

1801+
// Wait a bit more to ensure the file processing is fully complete
1802+
await new Promise(resolve => setTimeout(resolve, 20));
1803+
17991804
// Verify the old filename is no longer displayed
18001805
expect(screen.queryByText("config.yaml")).not.toBeInTheDocument();
18011806

@@ -1883,12 +1888,13 @@ describe.each([
18831888
// Mock FileReader
18841889
const mockFileReader = {
18851890
readAsDataURL: vi.fn().mockImplementation(() => {
1891+
// Use setTimeout with a small delay to simulate async file reading
18861892
setTimeout(() => {
18871893
if (mockFileReader.onload) {
18881894
// eslint-disable-next-line @typescript-eslint/no-explicit-any
18891895
mockFileReader.onload({ target: { result: 'data:text/plain;base64,Y29udGVudA==' } } as any);
18901896
}
1891-
}, 0);
1897+
}, 10);
18921898
}),
18931899
result: 'data:text/plain;base64,Y29udGVudA==',
18941900
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -1903,11 +1909,14 @@ describe.each([
19031909
// Upload file
19041910
fireEvent.change(fileInput, { target: { files: [newFile] } });
19051911

1906-
// Wait for the filename to appear
1912+
// Wait for the filename to appear and file processing to complete
19071913
await waitFor(() => {
19081914
expect(screen.getByTestId("file-input-no_filename_file-filename")).toBeInTheDocument();
19091915
});
19101916

1917+
// Wait a bit more to ensure the file processing is fully complete
1918+
await new Promise(resolve => setTimeout(resolve, 20));
1919+
19111920
expect(screen.getByText("uploaded-file.txt")).toBeInTheDocument();
19121921
});
19131922
});

0 commit comments

Comments
 (0)