@intentius/chant-lexicon-helm 0.0.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. package/README.md +22 -0
  2. package/dist/integrity.json +36 -0
  3. package/dist/manifest.json +37 -0
  4. package/dist/meta.json +208 -0
  5. package/dist/rules/chart-metadata.ts +64 -0
  6. package/dist/rules/helm-helpers.ts +64 -0
  7. package/dist/rules/no-hardcoded-image.ts +62 -0
  8. package/dist/rules/values-no-secrets.ts +82 -0
  9. package/dist/rules/whm101.ts +46 -0
  10. package/dist/rules/whm102.ts +33 -0
  11. package/dist/rules/whm103.ts +59 -0
  12. package/dist/rules/whm104.ts +35 -0
  13. package/dist/rules/whm105.ts +30 -0
  14. package/dist/rules/whm201.ts +36 -0
  15. package/dist/rules/whm202.ts +50 -0
  16. package/dist/rules/whm203.ts +39 -0
  17. package/dist/rules/whm204.ts +60 -0
  18. package/dist/rules/whm301.ts +41 -0
  19. package/dist/rules/whm302.ts +40 -0
  20. package/dist/rules/whm401.ts +57 -0
  21. package/dist/rules/whm402.ts +45 -0
  22. package/dist/rules/whm403.ts +45 -0
  23. package/dist/rules/whm404.ts +36 -0
  24. package/dist/rules/whm405.ts +53 -0
  25. package/dist/rules/whm406.ts +34 -0
  26. package/dist/rules/whm407.ts +83 -0
  27. package/dist/rules/whm501.ts +103 -0
  28. package/dist/rules/whm502.ts +94 -0
  29. package/dist/skills/chant-helm-chart-patterns.md +229 -0
  30. package/dist/skills/chant-helm-chart-security-patterns.md +192 -0
  31. package/dist/skills/chant-helm-create-chart.md +211 -0
  32. package/dist/types/index.d.ts +132 -0
  33. package/package.json +34 -0
  34. package/src/codegen/docs-cli.ts +4 -0
  35. package/src/codegen/docs.ts +483 -0
  36. package/src/codegen/generate-cli.ts +28 -0
  37. package/src/codegen/generate.ts +249 -0
  38. package/src/codegen/naming.ts +38 -0
  39. package/src/codegen/package.ts +64 -0
  40. package/src/composites/composites.test.ts +1050 -0
  41. package/src/composites/helm-batch-job.ts +209 -0
  42. package/src/composites/helm-crd-lifecycle.ts +184 -0
  43. package/src/composites/helm-cron-job.ts +177 -0
  44. package/src/composites/helm-daemon-set.ts +169 -0
  45. package/src/composites/helm-external-secret.ts +93 -0
  46. package/src/composites/helm-library.ts +51 -0
  47. package/src/composites/helm-microservice.ts +331 -0
  48. package/src/composites/helm-monitored-service.ts +252 -0
  49. package/src/composites/helm-namespace-env.ts +154 -0
  50. package/src/composites/helm-secure-ingress.ts +114 -0
  51. package/src/composites/helm-stateful-service.ts +213 -0
  52. package/src/composites/helm-web-app.ts +264 -0
  53. package/src/composites/helm-worker.ts +207 -0
  54. package/src/composites/index.ts +38 -0
  55. package/src/coverage.test.ts +21 -0
  56. package/src/coverage.ts +50 -0
  57. package/src/generated/index.d.ts +132 -0
  58. package/src/generated/index.ts +13 -0
  59. package/src/generated/lexicon-helm.json +208 -0
  60. package/src/helpers.test.ts +51 -0
  61. package/src/helpers.ts +100 -0
  62. package/src/import/generator.ts +285 -0
  63. package/src/import/import.test.ts +224 -0
  64. package/src/import/parser.ts +160 -0
  65. package/src/import/template-stripper.ts +123 -0
  66. package/src/index.ts +108 -0
  67. package/src/intrinsics.test.ts +380 -0
  68. package/src/intrinsics.ts +484 -0
  69. package/src/lint/post-synth/helm-helpers.ts +64 -0
  70. package/src/lint/post-synth/post-synth.test.ts +504 -0
  71. package/src/lint/post-synth/whm101.ts +46 -0
  72. package/src/lint/post-synth/whm102.ts +33 -0
  73. package/src/lint/post-synth/whm103.ts +59 -0
  74. package/src/lint/post-synth/whm104.ts +35 -0
  75. package/src/lint/post-synth/whm105.ts +30 -0
  76. package/src/lint/post-synth/whm201.ts +36 -0
  77. package/src/lint/post-synth/whm202.ts +50 -0
  78. package/src/lint/post-synth/whm203.ts +39 -0
  79. package/src/lint/post-synth/whm204.ts +60 -0
  80. package/src/lint/post-synth/whm301.ts +41 -0
  81. package/src/lint/post-synth/whm302.ts +40 -0
  82. package/src/lint/post-synth/whm401.ts +57 -0
  83. package/src/lint/post-synth/whm402.ts +45 -0
  84. package/src/lint/post-synth/whm403.ts +45 -0
  85. package/src/lint/post-synth/whm404.ts +36 -0
  86. package/src/lint/post-synth/whm405.ts +53 -0
  87. package/src/lint/post-synth/whm406.ts +34 -0
  88. package/src/lint/post-synth/whm407.ts +83 -0
  89. package/src/lint/post-synth/whm501.ts +103 -0
  90. package/src/lint/post-synth/whm502.ts +94 -0
  91. package/src/lint/rules/chart-metadata.ts +64 -0
  92. package/src/lint/rules/lint-rules.test.ts +97 -0
  93. package/src/lint/rules/no-hardcoded-image.ts +62 -0
  94. package/src/lint/rules/values-no-secrets.ts +82 -0
  95. package/src/lsp/completions.test.ts +72 -0
  96. package/src/lsp/completions.ts +20 -0
  97. package/src/lsp/hover.test.ts +46 -0
  98. package/src/lsp/hover.ts +46 -0
  99. package/src/package-cli.ts +28 -0
  100. package/src/plugin.test.ts +71 -0
  101. package/src/plugin.ts +206 -0
  102. package/src/resources.ts +77 -0
  103. package/src/serializer.test.ts +930 -0
  104. package/src/serializer.ts +835 -0
  105. package/src/skills/chart-patterns.md +229 -0
  106. package/src/skills/chart-security-patterns.md +192 -0
  107. package/src/skills/create-chart.md +211 -0
  108. package/src/validate-cli.ts +21 -0
  109. package/src/validate.test.ts +37 -0
  110. package/src/validate.ts +36 -0
@@ -0,0 +1,209 @@
1
+ /**
2
+ * HelmBatchJob composite — Job + optional ServiceAccount + RBAC.
3
+ *
4
+ * One-shot batch job pattern with optional RBAC for jobs that need
5
+ * Kubernetes API access (e.g., data migrations, cluster operations).
6
+ */
7
+
8
+ import { values, include, printf, toYaml, If, With } from "../intrinsics";
9
+
10
+ export interface HelmBatchJobProps {
11
+ /** Chart and release name. */
12
+ name: string;
13
+ /** Default container image repository. */
14
+ imageRepository?: string;
15
+ /** Default container image tag. */
16
+ imageTag?: string;
17
+ /** Backoff limit for retries. */
18
+ backoffLimit?: number;
19
+ /** Number of completions required. */
20
+ completions?: number;
21
+ /** Parallelism level. */
22
+ parallelism?: number;
23
+ /** Default restart policy. */
24
+ restartPolicy?: string;
25
+ /** TTL seconds after job finishes. */
26
+ ttlSecondsAfterFinished?: number;
27
+ /** Include ServiceAccount. Default: true. */
28
+ serviceAccount?: boolean;
29
+ /** Include RBAC (Role + RoleBinding). Default: false. */
30
+ rbac?: boolean;
31
+ /** Pod-level security context defaults. */
32
+ podSecurityContext?: Record<string, unknown>;
33
+ /** Container-level security context defaults. */
34
+ securityContext?: Record<string, unknown>;
35
+ /** Node selector defaults. */
36
+ nodeSelector?: Record<string, string>;
37
+ /** Tolerations defaults. */
38
+ tolerations?: Array<Record<string, unknown>>;
39
+ /** Chart appVersion. */
40
+ appVersion?: string;
41
+ }
42
+
43
+ export interface HelmBatchJobResult {
44
+ chart: Record<string, unknown>;
45
+ values: Record<string, unknown>;
46
+ job: Record<string, unknown>;
47
+ serviceAccount?: Record<string, unknown>;
48
+ role?: Record<string, unknown>;
49
+ roleBinding?: Record<string, unknown>;
50
+ }
51
+
52
+ export function HelmBatchJob(props: HelmBatchJobProps): HelmBatchJobResult {
53
+ const {
54
+ name,
55
+ imageRepository = "busybox",
56
+ imageTag = "latest",
57
+ backoffLimit = 6,
58
+ completions = 1,
59
+ parallelism = 1,
60
+ restartPolicy = "OnFailure",
61
+ serviceAccount = true,
62
+ rbac = false,
63
+ appVersion = "1.0.0",
64
+ } = props;
65
+
66
+ const chart = {
67
+ apiVersion: "v2",
68
+ name,
69
+ version: "0.1.0",
70
+ appVersion,
71
+ type: "application",
72
+ description: `A Helm chart for ${name} batch job`,
73
+ };
74
+
75
+ const valuesObj: Record<string, unknown> = {
76
+ image: {
77
+ repository: imageRepository,
78
+ tag: imageTag,
79
+ pullPolicy: "IfNotPresent",
80
+ },
81
+ job: {
82
+ backoffLimit,
83
+ completions,
84
+ parallelism,
85
+ },
86
+ restartPolicy,
87
+ command: [],
88
+ args: [],
89
+ resources: {},
90
+ };
91
+
92
+ if (props.ttlSecondsAfterFinished !== undefined) {
93
+ (valuesObj.job as Record<string, unknown>).ttlSecondsAfterFinished = props.ttlSecondsAfterFinished;
94
+ }
95
+
96
+ if (props.podSecurityContext) valuesObj.podSecurityContext = props.podSecurityContext;
97
+ if (props.securityContext) valuesObj.securityContext = props.securityContext;
98
+ if (props.nodeSelector) valuesObj.nodeSelector = props.nodeSelector;
99
+ if (props.tolerations) valuesObj.tolerations = props.tolerations;
100
+
101
+ if (serviceAccount) {
102
+ valuesObj.serviceAccount = {
103
+ create: true,
104
+ name: "",
105
+ annotations: {},
106
+ };
107
+ }
108
+
109
+ if (rbac) {
110
+ valuesObj.rbac = {
111
+ create: true,
112
+ rules: [],
113
+ };
114
+ }
115
+
116
+ const containerSpec: Record<string, unknown> = {
117
+ name,
118
+ image: printf("%s:%s", values.image.repository, values.image.tag),
119
+ imagePullPolicy: values.image.pullPolicy,
120
+ command: values.command,
121
+ args: values.args,
122
+ resources: toYaml(values.resources),
123
+ };
124
+
125
+ if (props.securityContext) containerSpec.securityContext = toYaml(values.securityContext);
126
+
127
+ const podSpec: Record<string, unknown> = {
128
+ restartPolicy: values.restartPolicy,
129
+ containers: [containerSpec],
130
+ };
131
+
132
+ if (props.podSecurityContext) podSpec.securityContext = toYaml(values.podSecurityContext);
133
+ if (props.nodeSelector) podSpec.nodeSelector = With(values.nodeSelector, toYaml(values.nodeSelector));
134
+ if (props.tolerations) podSpec.tolerations = With(values.tolerations, toYaml(values.tolerations));
135
+ if (serviceAccount) podSpec.serviceAccountName = include(`${name}.serviceAccountName`);
136
+
137
+ const jobSpec: Record<string, unknown> = {
138
+ backoffLimit: values.job.backoffLimit,
139
+ completions: values.job.completions,
140
+ parallelism: values.job.parallelism,
141
+ template: {
142
+ metadata: {
143
+ labels: include(`${name}.selectorLabels`),
144
+ },
145
+ spec: podSpec,
146
+ },
147
+ };
148
+
149
+ if (props.ttlSecondsAfterFinished !== undefined) {
150
+ jobSpec.ttlSecondsAfterFinished = values.job.ttlSecondsAfterFinished;
151
+ }
152
+
153
+ const job = {
154
+ apiVersion: "batch/v1",
155
+ kind: "Job",
156
+ metadata: {
157
+ name: include(`${name}.fullname`),
158
+ labels: include(`${name}.labels`),
159
+ },
160
+ spec: jobSpec,
161
+ };
162
+
163
+ const result: HelmBatchJobResult = { chart, values: valuesObj, job };
164
+
165
+ if (serviceAccount) {
166
+ result.serviceAccount = {
167
+ apiVersion: "v1",
168
+ kind: "ServiceAccount",
169
+ metadata: {
170
+ name: include(`${name}.serviceAccountName`),
171
+ labels: include(`${name}.labels`),
172
+ annotations: toYaml(values.serviceAccount.annotations),
173
+ },
174
+ };
175
+ }
176
+
177
+ if (rbac) {
178
+ result.role = {
179
+ apiVersion: "rbac.authorization.k8s.io/v1",
180
+ kind: "Role",
181
+ metadata: {
182
+ name: include(`${name}.fullname`),
183
+ labels: include(`${name}.labels`),
184
+ },
185
+ rules: toYaml(values.rbac.rules),
186
+ };
187
+
188
+ result.roleBinding = {
189
+ apiVersion: "rbac.authorization.k8s.io/v1",
190
+ kind: "RoleBinding",
191
+ metadata: {
192
+ name: include(`${name}.fullname`),
193
+ labels: include(`${name}.labels`),
194
+ },
195
+ roleRef: {
196
+ apiGroup: "rbac.authorization.k8s.io",
197
+ kind: "Role",
198
+ name: include(`${name}.fullname`),
199
+ },
200
+ subjects: [{
201
+ kind: "ServiceAccount",
202
+ name: include(`${name}.serviceAccountName`),
203
+ namespace: values.namespace ?? undefined,
204
+ }],
205
+ };
206
+ }
207
+
208
+ return result;
209
+ }
@@ -0,0 +1,184 @@
1
+ /**
2
+ * HelmCRDLifecycle composite — managed CRD lifecycle via Helm hooks.
3
+ *
4
+ * Produces a Job-based CRD installer that runs as a pre-install/pre-upgrade
5
+ * hook, solving the Helm limitation that CRDs in crds/ are never upgraded
6
+ * or deleted.
7
+ */
8
+
9
+ import { values, include, printf } from "../intrinsics";
10
+
11
+ export interface HelmCRDLifecycleProps {
12
+ /** Chart and release name. */
13
+ name: string;
14
+ /** Raw CRD YAML content. */
15
+ crdContent: string;
16
+ /** kubectl image. Default: "bitnami/kubectl" */
17
+ kubectlImage?: string;
18
+ /** kubectl image tag. Default: "latest" */
19
+ kubectlTag?: string;
20
+ /** ServiceAccount name for RBAC. */
21
+ serviceAccountName?: string;
22
+ }
23
+
24
+ export interface HelmCRDLifecycleResult {
25
+ chart: Record<string, unknown>;
26
+ values: Record<string, unknown>;
27
+ crdInstallJob: Record<string, unknown>;
28
+ crdConfigMap: Record<string, unknown>;
29
+ serviceAccount: Record<string, unknown>;
30
+ clusterRole: Record<string, unknown>;
31
+ clusterRoleBinding: Record<string, unknown>;
32
+ }
33
+
34
+ export function HelmCRDLifecycle(props: HelmCRDLifecycleProps): HelmCRDLifecycleResult {
35
+ const {
36
+ name,
37
+ crdContent,
38
+ kubectlImage = "bitnami/kubectl",
39
+ kubectlTag = "latest",
40
+ serviceAccountName,
41
+ } = props;
42
+
43
+ const saName = serviceAccountName ?? `${name}-crd-installer`;
44
+
45
+ const chart = {
46
+ apiVersion: "v2",
47
+ name,
48
+ version: "0.1.0",
49
+ type: "application",
50
+ description: `CRD lifecycle management for ${name}`,
51
+ };
52
+
53
+ const valuesObj = {
54
+ crdLifecycle: {
55
+ enabled: true,
56
+ kubectl: {
57
+ image: kubectlImage,
58
+ tag: kubectlTag,
59
+ },
60
+ serviceAccount: {
61
+ name: saName,
62
+ },
63
+ },
64
+ };
65
+
66
+ const hookAnnotations = {
67
+ "helm.sh/hook": "pre-install,pre-upgrade",
68
+ "helm.sh/hook-weight": "-5",
69
+ "helm.sh/hook-delete-policy": "before-hook-creation",
70
+ };
71
+
72
+ const crdConfigMap = {
73
+ apiVersion: "v1",
74
+ kind: "ConfigMap",
75
+ metadata: {
76
+ name: printf("%s-crd-content", include(`${name}.fullname`)),
77
+ labels: include(`${name}.labels`),
78
+ annotations: hookAnnotations,
79
+ },
80
+ data: {
81
+ "crds.yaml": crdContent,
82
+ },
83
+ };
84
+
85
+ const serviceAccount = {
86
+ apiVersion: "v1",
87
+ kind: "ServiceAccount",
88
+ metadata: {
89
+ name: values.crdLifecycle.serviceAccount.name,
90
+ labels: include(`${name}.labels`),
91
+ annotations: hookAnnotations,
92
+ },
93
+ };
94
+
95
+ const clusterRole = {
96
+ apiVersion: "rbac.authorization.k8s.io/v1",
97
+ kind: "ClusterRole",
98
+ metadata: {
99
+ name: printf("%s-crd-installer", include(`${name}.fullname`)),
100
+ labels: include(`${name}.labels`),
101
+ annotations: hookAnnotations,
102
+ },
103
+ rules: [{
104
+ apiGroups: ["apiextensions.k8s.io"],
105
+ resources: ["customresourcedefinitions"],
106
+ verbs: ["get", "list", "create", "update", "patch"],
107
+ }],
108
+ };
109
+
110
+ const clusterRoleBinding = {
111
+ apiVersion: "rbac.authorization.k8s.io/v1",
112
+ kind: "ClusterRoleBinding",
113
+ metadata: {
114
+ name: printf("%s-crd-installer", include(`${name}.fullname`)),
115
+ labels: include(`${name}.labels`),
116
+ annotations: hookAnnotations,
117
+ },
118
+ roleRef: {
119
+ apiGroup: "rbac.authorization.k8s.io",
120
+ kind: "ClusterRole",
121
+ name: printf("%s-crd-installer", include(`${name}.fullname`)),
122
+ },
123
+ subjects: [{
124
+ kind: "ServiceAccount",
125
+ name: values.crdLifecycle.serviceAccount.name,
126
+ namespace: "{{ .Release.Namespace }}",
127
+ }],
128
+ };
129
+
130
+ const crdInstallJob = {
131
+ apiVersion: "batch/v1",
132
+ kind: "Job",
133
+ metadata: {
134
+ name: printf("%s-crd-install", include(`${name}.fullname`)),
135
+ labels: include(`${name}.labels`),
136
+ annotations: hookAnnotations,
137
+ },
138
+ spec: {
139
+ template: {
140
+ metadata: {
141
+ labels: include(`${name}.selectorLabels`),
142
+ },
143
+ spec: {
144
+ serviceAccountName: values.crdLifecycle.serviceAccount.name,
145
+ restartPolicy: "Never",
146
+ securityContext: {
147
+ runAsNonRoot: true,
148
+ runAsUser: 1000,
149
+ },
150
+ containers: [{
151
+ name: "crd-installer",
152
+ image: printf("%s:%s", values.crdLifecycle.kubectl.image, values.crdLifecycle.kubectl.tag),
153
+ command: ["kubectl", "apply", "-f", "/crds/"],
154
+ securityContext: {
155
+ readOnlyRootFilesystem: true,
156
+ allowPrivilegeEscalation: false,
157
+ },
158
+ volumeMounts: [{
159
+ name: "crd-content",
160
+ mountPath: "/crds",
161
+ readOnly: true,
162
+ }],
163
+ }],
164
+ volumes: [{
165
+ name: "crd-content",
166
+ configMap: {
167
+ name: printf("%s-crd-content", include(`${name}.fullname`)),
168
+ },
169
+ }],
170
+ },
171
+ },
172
+ },
173
+ };
174
+
175
+ return {
176
+ chart,
177
+ values: valuesObj,
178
+ crdInstallJob,
179
+ crdConfigMap,
180
+ serviceAccount,
181
+ clusterRole,
182
+ clusterRoleBinding,
183
+ };
184
+ }
@@ -0,0 +1,177 @@
1
+ /**
2
+ * HelmCronJob composite — CronJob chart.
3
+ *
4
+ * Produces a Helm chart for scheduled batch workloads.
5
+ */
6
+
7
+ import { values, include, printf, toYaml, With } from "../intrinsics";
8
+
9
+ export interface HelmCronJobProps {
10
+ /** Chart and release name. */
11
+ name: string;
12
+ /** Default container image repository. */
13
+ imageRepository?: string;
14
+ /** Default container image tag. */
15
+ imageTag?: string;
16
+ /** Default cron schedule. */
17
+ schedule?: string;
18
+ /** Default restart policy. */
19
+ restartPolicy?: string;
20
+ /** Chart appVersion. */
21
+ appVersion?: string;
22
+ /** Pod-level security context defaults. */
23
+ podSecurityContext?: Record<string, unknown>;
24
+ /** Container-level security context defaults. */
25
+ securityContext?: Record<string, unknown>;
26
+ /** Node selector defaults. */
27
+ nodeSelector?: Record<string, string>;
28
+ /** Tolerations defaults. */
29
+ tolerations?: Array<Record<string, unknown>>;
30
+ /** Affinity defaults. */
31
+ affinity?: Record<string, unknown>;
32
+ /** Pod annotations defaults. */
33
+ podAnnotations?: Record<string, string>;
34
+ /** Concurrency policy. */
35
+ concurrencyPolicy?: string;
36
+ /** Number of successful job completions to retain. */
37
+ successfulJobsHistoryLimit?: number;
38
+ /** Number of failed job completions to retain. */
39
+ failedJobsHistoryLimit?: number;
40
+ /** Backoff limit for job retries. */
41
+ backoffLimit?: number;
42
+ /** Include ServiceAccount. Default: false. */
43
+ serviceAccount?: boolean;
44
+ }
45
+
46
+ export interface HelmCronJobResult {
47
+ chart: Record<string, unknown>;
48
+ values: Record<string, unknown>;
49
+ cronJob: Record<string, unknown>;
50
+ serviceAccount?: Record<string, unknown>;
51
+ }
52
+
53
+ export function HelmCronJob(props: HelmCronJobProps): HelmCronJobResult {
54
+ const {
55
+ name,
56
+ imageRepository = "busybox",
57
+ imageTag = "latest",
58
+ schedule = "0 * * * *",
59
+ restartPolicy = "OnFailure",
60
+ appVersion = "1.0.0",
61
+ serviceAccount = false,
62
+ } = props;
63
+
64
+ const chart = {
65
+ apiVersion: "v2",
66
+ name,
67
+ version: "0.1.0",
68
+ appVersion,
69
+ type: "application",
70
+ description: `A Helm chart for ${name} (cron job)`,
71
+ };
72
+
73
+ const valuesObj: Record<string, unknown> = {
74
+ image: {
75
+ repository: imageRepository,
76
+ tag: imageTag,
77
+ pullPolicy: "IfNotPresent",
78
+ },
79
+ schedule,
80
+ restartPolicy,
81
+ command: [],
82
+ args: [],
83
+ resources: {},
84
+ };
85
+
86
+ if (props.podSecurityContext) valuesObj.podSecurityContext = props.podSecurityContext;
87
+ if (props.securityContext) valuesObj.securityContext = props.securityContext;
88
+ if (props.nodeSelector) valuesObj.nodeSelector = props.nodeSelector;
89
+ if (props.tolerations) valuesObj.tolerations = props.tolerations;
90
+ if (props.affinity) valuesObj.affinity = props.affinity;
91
+ if (props.podAnnotations) valuesObj.podAnnotations = props.podAnnotations;
92
+ if (props.concurrencyPolicy) valuesObj.concurrencyPolicy = props.concurrencyPolicy;
93
+ if (props.successfulJobsHistoryLimit !== undefined) valuesObj.successfulJobsHistoryLimit = props.successfulJobsHistoryLimit;
94
+ if (props.failedJobsHistoryLimit !== undefined) valuesObj.failedJobsHistoryLimit = props.failedJobsHistoryLimit;
95
+ if (props.backoffLimit !== undefined) valuesObj.backoffLimit = props.backoffLimit;
96
+
97
+ if (serviceAccount) {
98
+ valuesObj.serviceAccount = {
99
+ create: true,
100
+ name: "",
101
+ annotations: {},
102
+ };
103
+ }
104
+
105
+ const containerSpec: Record<string, unknown> = {
106
+ name,
107
+ image: printf("%s:%s", values.image.repository, values.image.tag),
108
+ imagePullPolicy: values.image.pullPolicy,
109
+ command: values.command,
110
+ args: values.args,
111
+ resources: toYaml(values.resources),
112
+ };
113
+
114
+ if (props.securityContext) containerSpec.securityContext = toYaml(values.securityContext);
115
+
116
+ const podSpec: Record<string, unknown> = {
117
+ restartPolicy: values.restartPolicy,
118
+ containers: [containerSpec],
119
+ };
120
+
121
+ if (props.podSecurityContext) podSpec.securityContext = toYaml(values.podSecurityContext);
122
+ if (props.nodeSelector) podSpec.nodeSelector = With(values.nodeSelector, toYaml(values.nodeSelector));
123
+ if (props.tolerations) podSpec.tolerations = With(values.tolerations, toYaml(values.tolerations));
124
+ if (props.affinity) podSpec.affinity = With(values.affinity, toYaml(values.affinity));
125
+ if (serviceAccount) podSpec.serviceAccountName = include(`${name}.serviceAccountName`);
126
+
127
+ const templateMetadata: Record<string, unknown> = {
128
+ labels: include(`${name}.selectorLabels`),
129
+ };
130
+ if (props.podAnnotations) templateMetadata.annotations = toYaml(values.podAnnotations);
131
+
132
+ const jobSpec: Record<string, unknown> = {
133
+ template: {
134
+ metadata: templateMetadata,
135
+ spec: podSpec,
136
+ },
137
+ };
138
+
139
+ if (props.backoffLimit !== undefined) jobSpec.backoffLimit = values.backoffLimit;
140
+
141
+ const cronJobSpec: Record<string, unknown> = {
142
+ schedule: values.schedule,
143
+ jobTemplate: {
144
+ spec: jobSpec,
145
+ },
146
+ };
147
+
148
+ if (props.concurrencyPolicy) cronJobSpec.concurrencyPolicy = values.concurrencyPolicy;
149
+ if (props.successfulJobsHistoryLimit !== undefined) cronJobSpec.successfulJobsHistoryLimit = values.successfulJobsHistoryLimit;
150
+ if (props.failedJobsHistoryLimit !== undefined) cronJobSpec.failedJobsHistoryLimit = values.failedJobsHistoryLimit;
151
+
152
+ const cronJob = {
153
+ apiVersion: "batch/v1",
154
+ kind: "CronJob",
155
+ metadata: {
156
+ name: include(`${name}.fullname`),
157
+ labels: include(`${name}.labels`),
158
+ },
159
+ spec: cronJobSpec,
160
+ };
161
+
162
+ const result: HelmCronJobResult = { chart, values: valuesObj, cronJob };
163
+
164
+ if (serviceAccount) {
165
+ result.serviceAccount = {
166
+ apiVersion: "v1",
167
+ kind: "ServiceAccount",
168
+ metadata: {
169
+ name: include(`${name}.serviceAccountName`),
170
+ labels: include(`${name}.labels`),
171
+ annotations: toYaml(values.serviceAccount.annotations),
172
+ },
173
+ };
174
+ }
175
+
176
+ return result;
177
+ }