Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions pkg/action/chart_ts_init.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@ import (
)

type ChartTSInitOptions struct {
ChartDirPath string
ChartName string
TempDirPath string
ChartDirPath string
ChartName string
RenderContextType string
TempDirPath string
}

func ChartTSInit(ctx context.Context, opts ChartTSInitOptions) error {
Expand Down Expand Up @@ -47,7 +48,9 @@ func ChartTSInit(ctx context.Context, opts ChartTSInitOptions) error {
return fmt.Errorf("init chart structure: %w", err)
}

if err := ts.InitTSBoilerplate(ctx, absPath, chartName); err != nil {
if err := ts.InitTSBoilerplate(ctx, absPath, chartName, ts.InitTSBoilerplateOptions{
RenderContextType: opts.RenderContextType,
}); err != nil {
return fmt.Errorf("init TypeScript boilerplate: %w", err)
}

Expand Down
5 changes: 5 additions & 0 deletions pkg/common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,11 @@ const (
StageStartSuffix = "start"
StubReleaseName = "stub-release"
StubReleaseNamespace = "stub-namespace"
TSDefaultRenderContextType = TSGenericRenderContextType
// TSGenericRenderContextType is the TypeScript render context type name for nelm charts.
TSGenericRenderContextType = "RenderContext"
// TSWerfRenderContextType is the TypeScript render context type name for werf charts.
TSWerfRenderContextType = "WerfRenderContext"
)

var (
Expand Down
65 changes: 53 additions & 12 deletions pkg/ts/init.go
Original file line number Diff line number Diff line change
@@ -1,18 +1,30 @@
package ts

import (
"bytes"
"context"
"fmt"
"os"
"path/filepath"
"strings"
"text/template"

"github.com/werf/nelm/pkg/common"
"github.com/werf/nelm/pkg/log"
)

const denoBuildScript = "deno bundle --output=dist/bundle.js src/index.ts"

type InitTSBoilerplateOptions struct {
RenderContextType string
}

type initTmplData struct {
BuildScript string
ChartName string
RenderContextType string
}

// EnsureGitignore adds TypeScript entries to .gitignore, creating if needed.
func EnsureGitignore(chartPath string) error {
entries := []string{
Expand Down Expand Up @@ -53,8 +65,7 @@ func InitChartStructure(ctx context.Context, chartPath, chartName string) error
return nil
}

// InitTSBoilerplate creates TypeScript boilerplate files in ts/ directory.
func InitTSBoilerplate(ctx context.Context, chartPath, chartName string) error {
func InitTSBoilerplate(ctx context.Context, chartPath, chartName string, opts InitTSBoilerplateOptions) error {
tsDir := filepath.Join(chartPath, common.ChartTSSourceDir)
srcDir := filepath.Join(tsDir, "src")

Expand All @@ -64,25 +75,41 @@ func InitTSBoilerplate(ctx context.Context, chartPath, chartName string) error {
return fmt.Errorf("stat %s: %w", tsDir, err)
}

ctxType := common.TSDefaultRenderContextType
if opts.RenderContextType != "" {
ctxType = opts.RenderContextType
}

data := initTmplData{
BuildScript: denoBuildScript,
ChartName: chartName,
RenderContextType: ctxType,
}

files := []struct {
content string
path string
tmpl string
path string
}{
{content: indexTSContent, path: filepath.Join(srcDir, "index.ts")},
{content: helpersTSContent, path: filepath.Join(srcDir, "helpers.ts")},
{content: deploymentTSContent, path: filepath.Join(srcDir, "deployment.ts")},
{content: serviceTSContent, path: filepath.Join(srcDir, "service.ts")},
{content: tsconfigContent, path: filepath.Join(tsDir, "tsconfig.json")},
{content: fmt.Sprintf(denoJSONTmpl, denoBuildScript), path: filepath.Join(tsDir, "deno.json")},
{content: fmt.Sprintf(inputExampleContent, chartName), path: filepath.Join(tsDir, "input.example.yaml")},
{tmpl: indexTSTmpl, path: filepath.Join(srcDir, "index.ts")},
{tmpl: helpersTSTmpl, path: filepath.Join(srcDir, "helpers.ts")},
{tmpl: deploymentTSTmpl, path: filepath.Join(srcDir, "deployment.ts")},
{tmpl: serviceTSTmpl, path: filepath.Join(srcDir, "service.ts")},
{tmpl: tsconfigContent, path: filepath.Join(tsDir, "tsconfig.json")},
{tmpl: denoJSONTmpl, path: filepath.Join(tsDir, "deno.json")},
{tmpl: inputExampleTmpl, path: filepath.Join(tsDir, "input.example.yaml")},
}

if err := os.MkdirAll(srcDir, 0o755); err != nil {
return fmt.Errorf("create directory %s: %w", srcDir, err)
}

for _, f := range files {
if err := os.WriteFile(f.path, []byte(f.content), 0o644); err != nil {
content, err := renderTemplate(f.tmpl, data)
if err != nil {
return fmt.Errorf("render template for %s: %w", f.path, err)
}

if err := os.WriteFile(f.path, []byte(content), 0o644); err != nil {
return fmt.Errorf("write %s: %w", f.path, err)
}

Expand Down Expand Up @@ -181,3 +208,17 @@ func fileExists(path string) (bool, error) {

return false, fmt.Errorf("stat %s: %w", path, err)
}

func renderTemplate(tmplStr string, data initTmplData) (string, error) {
t, err := template.New("").Parse(tmplStr)
if err != nil {
return "", fmt.Errorf("parse template: %w", err)
}

var buf bytes.Buffer
if err := t.Execute(&buf, data); err != nil {
return "", fmt.Errorf("execute template: %w", err)
}

return buf.String(), nil
}
44 changes: 22 additions & 22 deletions pkg/ts/init_templates.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,17 @@ package ts
const (
denoJSONTmpl = `{
"tasks": {
"build": "%s"
"build": "{{ .BuildScript }}"
},
"imports": {
"@nelm/chart-ts-sdk": "npm:@nelm/chart-ts-sdk@^0.1.3"
"@nelm/chart-ts-sdk": "npm:@nelm/chart-ts-sdk@^0.1.4"
}
}
`
deploymentTSContent = `import type { RenderContext } from '@nelm/chart-ts-sdk';
deploymentTSTmpl = `import type { {{ .RenderContextType }} } from '@nelm/chart-ts-sdk';
import { getFullname, getLabels, getSelectorLabels } from './helpers.ts';

export function newDeployment($: RenderContext): object {
export function newDeployment($: {{ .RenderContextType }}): object {
const name = getFullname($);

return {
Expand Down Expand Up @@ -59,7 +59,7 @@ export function newDeployment($: RenderContext): object {
ts/vendor/
ts/node_modules/
`
helpersTSContent = `import type { RenderContext } from '@nelm/chart-ts-sdk';
helpersTSTmpl = `import type { {{ .RenderContextType }} } from '@nelm/chart-ts-sdk';

/**
* Truncate string to max length, removing trailing hyphens.
Expand All @@ -73,7 +73,7 @@ export function trunc(str: string, max: number): string {
* Get the fully qualified app name.
* Truncated at 63 chars (DNS naming spec limit).
*/
export function getFullname($: RenderContext): string {
export function getFullname($: {{ .RenderContextType }}): string {
if ($.Values.fullnameOverride) {
return trunc($.Values.fullnameOverride, 63);
}
Expand All @@ -87,25 +87,25 @@ export function getFullname($: RenderContext): string {
return trunc(` + "`${$.Release.Name}-${chartName}`" + `, 63);
}

export function getLabels($: RenderContext): Record<string, string> {
export function getLabels($: {{ .RenderContextType }}): Record<string, string> {
return {
'app.kubernetes.io/name': $.Chart.Name,
'app.kubernetes.io/instance': $.Release.Name,
};
}

export function getSelectorLabels($: RenderContext): Record<string, string> {
export function getSelectorLabels($: {{ .RenderContextType }}): Record<string, string> {
return {
'app.kubernetes.io/name': $.Chart.Name,
'app.kubernetes.io/instance': $.Release.Name,
};
}
`
indexTSContent = `import { RenderContext, RenderResult, runRender } from '@nelm/chart-ts-sdk';
indexTSTmpl = `import { {{ .RenderContextType }}, RenderResult, render } from '@nelm/chart-ts-sdk';
import { newDeployment } from './deployment.ts';
import { newService } from './service.ts';

function render($: RenderContext): RenderResult {
function generate($: {{ .RenderContextType }}): RenderResult {
const manifests: object[] = [];

manifests.push(newDeployment($));
Expand All @@ -117,9 +117,9 @@ function render($: RenderContext): RenderResult {
return { manifests };
}

await runRender(render);
await render(generate);
`
inputExampleContent = `Capabilities:
inputExampleTmpl = `Capabilities:
APIVersions:
- v1
HelmVersion:
Expand All @@ -134,29 +134,29 @@ Chart:
Annotations:
anno: value
AppVersion: 1.0.0
Condition: %[1]s.enabled
Description: %[1]s description
Condition: {{ .ChartName }}.enabled
Description: {{ .ChartName }} description
Home: https://example.org/home
Icon: https://example.org/icon
Keywords:
- %[1]s
- {{ .ChartName }}
Maintainers:
- Email: john@example.com
Name: john
URL: https://example.com/john
Name: %[1]s
Name: {{ .ChartName }}
Sources:
- https://example.org/%[1]s
Tags: %[1]s
- https://example.org/{{ .ChartName }}
Tags: {{ .ChartName }}
Type: application
Version: 0.1.0
Files:
myfile: "content"
Release:
IsInstall: false
IsUpgrade: true
Name: %[1]s
Namespace: %[1]s
Name: {{ .ChartName }}
Namespace: {{ .ChartName }}
Revision: 2
Service: Helm
Values:
Expand All @@ -169,10 +169,10 @@ Values:
port: 80
type: ClusterIP
`
serviceTSContent = `import type { RenderContext } from '@nelm/chart-ts-sdk';
serviceTSTmpl = `import type { {{ .RenderContextType }} } from '@nelm/chart-ts-sdk';
import { getFullname, getLabels, getSelectorLabels } from './helpers.ts';

export function newService($: RenderContext): object {
export function newService($: {{ .RenderContextType }}): object {
return {
apiVersion: 'v1',
kind: 'Service',
Expand Down
Loading
Loading