Skip to content

Commit d915dc2

Browse files
Add TypeScript chart rendering support
Signed-off-by: Dmitry Bochkarev <dimabochkarev@gmail.com>
1 parent dcb818b commit d915dc2

21 files changed

Lines changed: 3836 additions & 3 deletions

cmd/nelm/chart.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ func newChartCommand(ctx context.Context, afterAllCommandsBuiltFuncs map[*cobra.
1818
cli.GroupCommandOptions{},
1919
)
2020

21+
cmd.AddCommand(newChartInitCommand(ctx, afterAllCommandsBuiltFuncs))
2122
cmd.AddCommand(newChartRenderCommand(ctx, afterAllCommandsBuiltFuncs))
2223
cmd.AddCommand(newChartDependencyCommand(ctx, afterAllCommandsBuiltFuncs))
2324
cmd.AddCommand(newChartDownloadCommand(ctx, afterAllCommandsBuiltFuncs))

cmd/nelm/chart_init.go

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
package main
2+
3+
import (
4+
"cmp"
5+
"context"
6+
"fmt"
7+
8+
"github.com/spf13/cobra"
9+
10+
"github.com/werf/common-go/pkg/cli"
11+
"github.com/werf/nelm/pkg/action"
12+
"github.com/werf/nelm/pkg/common"
13+
"github.com/werf/nelm/pkg/log"
14+
)
15+
16+
type chartInitConfig struct {
17+
action.ChartInitOptions
18+
19+
LogColorMode string
20+
LogLevel string
21+
}
22+
23+
func newChartInitCommand(ctx context.Context, afterAllCommandsBuiltFuncs map[*cobra.Command]func(cmd *cobra.Command) error) *cobra.Command {
24+
cfg := &chartInitConfig{}
25+
26+
cmd := cli.NewSubCommand(
27+
ctx,
28+
"init [PATH]",
29+
"Initialize a new chart.",
30+
"Initialize a new chart in the specified directory. If PATH is not specified, uses the current directory.",
31+
10, // priority for ordering in help
32+
chartCmdGroup,
33+
cli.SubCommandOptions{
34+
Args: cobra.MaximumNArgs(1),
35+
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
36+
return nil, cobra.ShellCompDirectiveFilterDirs
37+
},
38+
},
39+
func(cmd *cobra.Command, args []string) error {
40+
ctx = log.SetupLogging(ctx, cmp.Or(log.Level(cfg.LogLevel), log.InfoLevel), log.SetupLoggingOptions{
41+
ColorMode: cfg.LogColorMode,
42+
})
43+
44+
if len(args) > 0 {
45+
cfg.ChartDirPath = args[0]
46+
}
47+
48+
if err := action.ChartInit(ctx, cfg.ChartInitOptions); err != nil {
49+
return fmt.Errorf("chart init: %w", err)
50+
}
51+
52+
return nil
53+
},
54+
)
55+
56+
afterAllCommandsBuiltFuncs[cmd] = func(cmd *cobra.Command) error {
57+
if err := cli.AddFlag(cmd, &cfg.TS, "ts", false, "Initialize TypeScript chart", cli.AddFlagOptions{
58+
Group: mainFlagGroup,
59+
}); err != nil {
60+
return fmt.Errorf("add flag: %w", err)
61+
}
62+
63+
if err := cli.AddFlag(cmd, &cfg.TempDirPath, "temp-dir", "", "The directory for temporary files. By default, create a new directory in the default system directory for temporary files", cli.AddFlagOptions{
64+
GetEnvVarRegexesFunc: cli.GetFlagGlobalEnvVarRegexes,
65+
Group: miscFlagGroup,
66+
Type: cli.FlagTypeDir,
67+
}); err != nil {
68+
return fmt.Errorf("add flag: %w", err)
69+
}
70+
71+
if err := cli.AddFlag(cmd, &cfg.LogColorMode, "color-mode", common.DefaultLogColorMode, "Color mode for logs. "+allowedLogColorModesHelp(), cli.AddFlagOptions{
72+
GetEnvVarRegexesFunc: cli.GetFlagGlobalAndLocalEnvVarRegexes,
73+
Group: miscFlagGroup,
74+
}); err != nil {
75+
return fmt.Errorf("add flag: %w", err)
76+
}
77+
78+
if err := cli.AddFlag(cmd, &cfg.LogLevel, "log-level", string(log.InfoLevel), "Set log level. "+allowedLogLevelsHelp(), cli.AddFlagOptions{
79+
GetEnvVarRegexesFunc: cli.GetFlagGlobalAndLocalEnvVarRegexes,
80+
Group: miscFlagGroup,
81+
}); err != nil {
82+
return fmt.Errorf("add flag: %w", err)
83+
}
84+
85+
return nil
86+
}
87+
88+
return cmd
89+
}

cmd/nelm/chart_pack.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package main
22

33
import (
44
"context"
5+
"fmt"
56
"strings"
67

78
"github.com/samber/lo"
@@ -10,6 +11,8 @@ import (
1011
helm_v3 "github.com/werf/3p-helm/cmd/helm"
1112
"github.com/werf/3p-helm/pkg/chart/loader"
1213
"github.com/werf/common-go/pkg/cli"
14+
"github.com/werf/nelm/internal/tschart"
15+
"github.com/werf/nelm/pkg/featgate"
1316
"github.com/werf/nelm/pkg/log"
1417
)
1518

@@ -33,6 +36,15 @@ func newChartPackCommand(ctx context.Context, afterAllCommandsBuiltFuncs map[*co
3336

3437
loader.NoChartLockWarning = ""
3538

39+
if featgate.FeatGateTypescript.Enabled() {
40+
transformer := tschart.NewTransformer()
41+
for _, chartPath := range args {
42+
if err := transformer.TransformChartDir(ctx, chartPath); err != nil {
43+
return fmt.Errorf("transform TypeScript in %q: %w", chartPath, err)
44+
}
45+
}
46+
}
47+
3648
if err := originalRunE(cmd, args); err != nil {
3749
return err
3850
}

go.mod

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@ require (
1313
github.com/docker/cli v25.0.5+incompatible
1414
github.com/docker/docker v25.0.5+incompatible
1515
github.com/dominikbraun/graph v0.23.0
16+
github.com/dop251/goja v0.0.0-20251121114222-56b1242a5f86
17+
github.com/dop251/goja_nodejs v0.0.0-20251015164255-5e94316bedaf
1618
github.com/evanphx/json-patch v5.8.0+incompatible
19+
github.com/evanw/esbuild v0.27.0
1720
github.com/fluxcd/flagger v1.36.1
1821
github.com/goccy/go-yaml v1.15.23
1922
github.com/google/go-cmp v0.6.0
@@ -94,6 +97,7 @@ require (
9497
github.com/go-openapi/jsonpointer v0.21.0 // indirect
9598
github.com/go-openapi/jsonreference v0.21.0 // indirect
9699
github.com/go-openapi/swag v0.23.0 // indirect
100+
github.com/go-sourcemap/sourcemap v2.1.4+incompatible // indirect
97101
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
98102
github.com/gobwas/glob v0.2.3 // indirect
99103
github.com/gofrs/flock v0.8.1 // indirect

go.sum

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,10 +111,16 @@ github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 h1:UhxFibDNY/bfvqU
111111
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE=
112112
github.com/dominikbraun/graph v0.23.0 h1:TdZB4pPqCLFxYhdyMFb1TBdFxp8XLcJfTTBQucVPgCo=
113113
github.com/dominikbraun/graph v0.23.0/go.mod h1:yOjYyogZLY1LSG9E33JWZJiq5k83Qy2C6POAuiViluc=
114+
github.com/dop251/goja v0.0.0-20251121114222-56b1242a5f86 h1:iY/kk+Fw7k49PRM4cS2wz9CVxO0jB61+h//XN9bbAS4=
115+
github.com/dop251/goja v0.0.0-20251121114222-56b1242a5f86/go.mod h1:MxLav0peU43GgvwVgNbLAj1s/bSGboKkhuULvq/7hx4=
116+
github.com/dop251/goja_nodejs v0.0.0-20251015164255-5e94316bedaf h1:gbmvliZnCut4NjaPSNOQlfqBoZ9C5Dpf72mHMMYhgVE=
117+
github.com/dop251/goja_nodejs v0.0.0-20251015164255-5e94316bedaf/go.mod h1:Tb7Xxye4LX7cT3i8YLvmPMGCV92IOi4CDZvm/V8ylc0=
114118
github.com/emicklei/go-restful/v3 v3.11.2 h1:1onLa9DcsMYO9P+CXaL0dStDqQ2EHHXLiz+BtnqkLAU=
115119
github.com/emicklei/go-restful/v3 v3.11.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
116120
github.com/evanphx/json-patch v5.8.0+incompatible h1:1Av9pn2FyxPdvrWNQszj1g6D6YthSmvCfcN6SYclTJg=
117121
github.com/evanphx/json-patch v5.8.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
122+
github.com/evanw/esbuild v0.27.0 h1:1fbrgepqU1rZeu4VPcQRZJpvIfQpbrYqRr1wJdeMkfM=
123+
github.com/evanw/esbuild v0.27.0/go.mod h1:D2vIQZqV/vIf/VRHtViaUtViZmG7o+kKmlBfVQuRi48=
118124
github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f h1:Wl78ApPPB2Wvf/TIe2xdyJxTlb6obmF18d8QdkxNDu4=
119125
github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f/go.mod h1:OSYXu++VVOHnXeitef/D8n/6y4QV8uLHSFXX4NeXMGc=
120126
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
@@ -148,6 +154,8 @@ github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF
148154
github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4=
149155
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
150156
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
157+
github.com/go-sourcemap/sourcemap v2.1.4+incompatible h1:a+iTbH5auLKxaNwQFg0B+TCYl6lbukKPc7b5x0n1s6Q=
158+
github.com/go-sourcemap/sourcemap v2.1.4+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg=
151159
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
152160
github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=
153161
github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=

internal/chart/chart_render.go

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"bytes"
55
"context"
66
"fmt"
7+
"maps"
78
"os"
89
"path"
910
"path/filepath"
@@ -16,7 +17,7 @@ import (
1617
"sigs.k8s.io/yaml"
1718

1819
"github.com/werf/3p-helm/pkg/action"
19-
"github.com/werf/3p-helm/pkg/chart"
20+
helmchart "github.com/werf/3p-helm/pkg/chart"
2021
"github.com/werf/3p-helm/pkg/chart/loader"
2122
"github.com/werf/3p-helm/pkg/chartutil"
2223
"github.com/werf/3p-helm/pkg/cli"
@@ -31,7 +32,9 @@ import (
3132
"github.com/werf/3p-helm/pkg/werf/helmopts"
3233
"github.com/werf/nelm/internal/kube"
3334
"github.com/werf/nelm/internal/resource/spec"
35+
"github.com/werf/nelm/internal/tschart"
3436
"github.com/werf/nelm/pkg/common"
37+
"github.com/werf/nelm/pkg/featgate"
3538
"github.com/werf/nelm/pkg/log"
3639
)
3740

@@ -53,7 +56,7 @@ type RenderChartOptions struct {
5356
}
5457

5558
type RenderChartResult struct {
56-
Chart *chart.Chart
59+
Chart *helmchart.Chart
5760
Notes string
5861
ReleaseConfig map[string]interface{}
5962
ResourceSpecs []*spec.ResourceSpec
@@ -147,6 +150,7 @@ func RenderChart(ctx context.Context, chartPath, releaseName, releaseNamespace s
147150
log.Default.TraceStruct(ctx, runtime, "Runtime:")
148151

149152
var isUpgrade bool
153+
150154
switch deployType {
151155
case common.DeployTypeUpgrade, common.DeployTypeRollback:
152156
isUpgrade = true
@@ -204,6 +208,17 @@ func RenderChart(ctx context.Context, chartPath, releaseName, releaseNamespace s
204208
return nil, fmt.Errorf("render resources for chart %q: %w", chart.Name(), err)
205209
}
206210

211+
if featgate.FeatGateTypescript.Enabled() {
212+
jsRenderedTemplates, err := renderJSTemplates(ctx, chartPath, chart, renderedValues)
213+
if err != nil {
214+
return nil, fmt.Errorf("render ts chart templates for chart %q: %w", chart.Name(), err)
215+
}
216+
217+
if len(jsRenderedTemplates) > 0 {
218+
maps.Copy(renderedTemplates, jsRenderedTemplates)
219+
}
220+
}
221+
207222
log.Default.TraceStruct(ctx, renderedTemplates, "Rendered contents of templates/:")
208223

209224
if r, err := renderedTemplatesToResourceSpecs(renderedTemplates, releaseNamespace, opts); err != nil {
@@ -229,7 +244,25 @@ func RenderChart(ctx context.Context, chartPath, releaseName, releaseNamespace s
229244
}, nil
230245
}
231246

232-
func validateChart(ctx context.Context, chart *chart.Chart) error {
247+
func renderJSTemplates(
248+
ctx context.Context,
249+
chartPath string,
250+
chart *helmchart.Chart,
251+
renderedValues chartutil.Values,
252+
) (map[string]string, error) {
253+
log.Default.Debug(ctx, "Rendering TypeScript resources for chart %q and its dependencies", chart.Name())
254+
255+
jsEngine := tschart.NewEngine()
256+
257+
jsRenderedTemplates, err := jsEngine.RenderChartWithDependencies(ctx, chartPath, chart, renderedValues)
258+
if err != nil {
259+
return nil, err
260+
}
261+
262+
return jsRenderedTemplates, nil
263+
}
264+
265+
func validateChart(ctx context.Context, chart *helmchart.Chart) error {
233266
if chart == nil {
234267
return fmt.Errorf("load chart: %w", action.ErrMissingChart())
235268
}
@@ -253,6 +286,7 @@ func validateChart(ctx context.Context, chart *chart.Chart) error {
253286

254287
func renderedTemplatesToResourceSpecs(renderedTemplates map[string]string, releaseNamespace string, opts RenderChartOptions) ([]*spec.ResourceSpec, error) {
255288
var resources []*spec.ResourceSpec
289+
256290
for filePath, fileContent := range renderedTemplates {
257291
if strings.HasPrefix(path.Base(filePath), "_") ||
258292
strings.HasSuffix(filePath, action.NotesFileSuffix) ||

internal/tschart/console.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package tschart
2+
3+
import (
4+
"github.com/dop251/goja"
5+
"github.com/dop251/goja_nodejs/console"
6+
"github.com/dop251/goja_nodejs/require"
7+
)
8+
9+
func SetupConsoleGlobal(runtime *goja.Runtime) {
10+
registry := require.NewRegistry()
11+
registry.Enable(runtime)
12+
13+
console.Enable(runtime)
14+
}

0 commit comments

Comments
 (0)