pepr 0.48.1 → 0.49.0

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.
package/package.json CHANGED
@@ -16,7 +16,7 @@
16
16
  "!src/fixtures/**",
17
17
  "!dist/**/*.test.d.ts*"
18
18
  ],
19
- "version": "0.48.1",
19
+ "version": "0.49.0",
20
20
  "main": "dist/lib.js",
21
21
  "types": "dist/lib.d.ts",
22
22
  "scripts": {
@@ -54,12 +54,13 @@
54
54
  "heredoc": "^1.3.1",
55
55
  "http-status-codes": "^2.3.0",
56
56
  "json-pointer": "^0.6.2",
57
- "kubernetes-fluent-client": "3.4.10",
57
+ "kubernetes-fluent-client": "3.5.1",
58
58
  "pino": "9.6.0",
59
59
  "pino-pretty": "13.0.0",
60
60
  "prom-client": "15.1.3",
61
61
  "ramda": "0.30.1",
62
- "sigstore": "3.1.0"
62
+ "sigstore": "3.1.0",
63
+ "ts-morph": "^25.0.1"
63
64
  },
64
65
  "devDependencies": {
65
66
  "@commitlint/cli": "19.8.0",
@@ -78,7 +79,7 @@
78
79
  "jest": "29.7.0",
79
80
  "js-yaml": "^4.1.0",
80
81
  "shellcheck": "^3.0.0",
81
- "ts-jest": "29.3.1",
82
+ "ts-jest": "29.3.2",
82
83
  "undici": "^7.0.1"
83
84
  },
84
85
  "overrides": {
@@ -192,18 +192,23 @@ export async function generateYamlAndWriteToDisk(obj: {
192
192
  const yamlFile = `pepr-module-${uuid}.yaml`;
193
193
  const chartPath = `${uuid}-chart`;
194
194
  const yamlPath = resolve(outputDir, yamlFile);
195
- const yaml = await assets.allYaml(generateAllYaml, getDeployment, getWatcher, imagePullSecret);
196
- const zarfPath = resolve(outputDir, "zarf.yaml");
195
+ try {
196
+ const yaml = await assets.allYaml(generateAllYaml, getDeployment, getWatcher, imagePullSecret);
197
+ const zarfPath = resolve(outputDir, "zarf.yaml");
198
+
199
+ let localZarf = "";
200
+ if (zarf === "chart") {
201
+ localZarf = assets.zarfYamlChart(generateZarfYamlGeneric, chartPath);
202
+ } else {
203
+ localZarf = assets.zarfYaml(generateZarfYamlGeneric, yamlFile);
204
+ }
205
+ await fs.writeFile(yamlPath, yaml);
206
+ await fs.writeFile(zarfPath, localZarf);
197
207
 
198
- let localZarf = "";
199
- if (zarf === "chart") {
200
- localZarf = assets.zarfYamlChart(generateZarfYamlGeneric, chartPath);
201
- } else {
202
- localZarf = assets.zarfYaml(generateZarfYamlGeneric, yamlFile);
208
+ await assets.generateHelmChart(webhookConfigGenerator, getWatcher, getModuleSecret, outputDir);
209
+ console.info(`✅ K8s resource for the module saved to ${yamlPath}`);
210
+ } catch (error) {
211
+ console.error(`Error generating YAML: ${error}`);
212
+ process.exit(1);
203
213
  }
204
- await fs.writeFile(yamlPath, yaml);
205
- await fs.writeFile(zarfPath, localZarf);
206
-
207
- await assets.generateHelmChart(webhookConfigGenerator, getWatcher, getModuleSecret, outputDir);
208
- console.info(`✅ K8s resource for the module saved to ${yamlPath}`);
209
214
  }
package/src/cli/build.ts CHANGED
@@ -120,6 +120,12 @@ export default function (program: RootCmd): void {
120
120
  ["admin", "scoped"],
121
121
  ),
122
122
  )
123
+ .addOption(
124
+ new Option(
125
+ "--custom-name [name]",
126
+ "Specify a custom name for zarf component and service monitors in helm charts.",
127
+ ),
128
+ )
123
129
  .action(async opts => {
124
130
  // assign custom output directory if provided
125
131
  outputDir = await handleCustomOutputDir(opts.outputDir);
@@ -127,7 +133,12 @@ export default function (program: RootCmd): void {
127
133
  // Build the module
128
134
  const buildModuleResult = await buildModule(undefined, opts.entryPoint, opts.embed);
129
135
 
130
- const { cfg, path, uuid } = buildModuleResult!;
136
+ const { cfg, path } = buildModuleResult!;
137
+ // override the name if provided
138
+ if (opts.customName) {
139
+ process.env.PEPR_CUSTOM_BUILD_NAME = opts.customName;
140
+ }
141
+
131
142
  const image = assignImage({
132
143
  customImage: opts.customImage,
133
144
  registryInfo: opts.registryInfo,
@@ -182,7 +193,7 @@ export default function (program: RootCmd): void {
182
193
 
183
194
  handleValidCapabilityNames(assets.capabilities);
184
195
  await generateYamlAndWriteToDisk({
185
- uuid,
196
+ uuid: cfg.pepr.uuid,
186
197
  outputDir,
187
198
  imagePullSecret: opts.withPullSecret,
188
199
  zarf: opts.zarf,
@@ -0,0 +1,134 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // SPDX-FileCopyrightText: 2023-Present The Pepr Authors
3
+
4
+ import { Command } from "commander";
5
+ import { createDirectoryIfNotExists } from "../../lib/filesystemService";
6
+ import { promises as fs } from "fs";
7
+ import path from "path";
8
+
9
+ // Scaffolds a new CRD TypeScript definition
10
+ const create = new Command("create")
11
+ .description("Create a new CRD TypeScript definition")
12
+ .requiredOption("--group <group>", "API group (e.g. cache)")
13
+ .requiredOption("--version <version>", "API version (e.g. v1alpha1)")
14
+ .requiredOption("--kind <kind>", "Kind name (e.g. Memcached)")
15
+ .option("--domain <domain>", "Optional domain (e.g. pepr.dev)", "pepr.dev")
16
+ .option(
17
+ "--scope <Namespaced | Cluster>",
18
+ "Whether the resulting custom resource is cluster- or namespace-scoped",
19
+ validateScope,
20
+ "Namespaced",
21
+ )
22
+ .option("--plural <plural>", "Plural name (e.g. memcacheds)", "")
23
+ .option("--shortName <shortName>", "Short name (e.g. mc)", "")
24
+ .action(async ({ group, version, kind, domain, scope, plural, shortName }) => {
25
+ console.log("This feature is currently in alpha.\n");
26
+ const outputDir = path.resolve(`./api/${version}`);
27
+ await createDirectoryIfNotExists(outputDir);
28
+
29
+ // create file in directory with kind
30
+ await fs.writeFile(
31
+ `./api/${version}/${kind.toLowerCase()}_types.ts`,
32
+ generateCRDScaffold(group, version, kind, { domain, scope, plural, shortName }),
33
+ );
34
+ console.log(`✔ Created ${kind} TypeScript definition in ${outputDir}`);
35
+ });
36
+
37
+ export default create;
38
+
39
+ export const generateCRDScaffold = (
40
+ group: string,
41
+ version: string,
42
+ kind: string,
43
+ data: {
44
+ domain: string;
45
+ plural: string;
46
+ scope: string;
47
+ shortName: string;
48
+ },
49
+ ): string => {
50
+ return `// Auto-generated CRD TypeScript definition
51
+ // Kind: ${kind}
52
+ // Group: ${group}
53
+ // Version: ${version}
54
+ // Domain: ${data.domain}
55
+
56
+ export interface ${kind}Spec {
57
+ // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
58
+ // Important: Run "npx pepr crd generate" to regenerate code after modifying this file
59
+
60
+ /**
61
+ * Size defines the number of Memcache instances
62
+ */
63
+ Size?: number[];
64
+
65
+ /**
66
+ * Port defines the port that will be used to init the container with the image
67
+ */
68
+ ContainerPort: number;
69
+
70
+ /**
71
+ * Application specific configuration
72
+ */
73
+ Config?: {
74
+ language: string[];
75
+ timezone: number;
76
+ zone: {
77
+ state: string;
78
+ areaCode: string[];
79
+ };
80
+ };
81
+ }
82
+
83
+ export interface ${kind}Status {
84
+ conditions: ${kind}StatusCondition[];
85
+ }
86
+
87
+ export const details = {
88
+ plural: "${data.plural}",
89
+ scope: "${data.scope}",
90
+ shortName: "${data.shortName}",
91
+ };
92
+
93
+ type ${kind}StatusCondition = {
94
+ /**
95
+ * lastTransitionTime is the last time the condition transitioned from one status to another. This is not guaranteed to be set in happensBefore order across different conditions for a given object. It may be unset in some circumstances.
96
+ */
97
+ lastTransitionTime: Date;
98
+ /**
99
+ * message is a human readable message indicating details about the transition. This may be an empty string.
100
+ */
101
+ message: string;
102
+ /**
103
+ * observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance.
104
+ */
105
+ observedGeneration?: number;
106
+ /**
107
+ * reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty.
108
+ */
109
+ reason: string;
110
+ /**
111
+ * status of the condition, one of True, False, Unknown.
112
+ */
113
+ status: string;
114
+ /**
115
+ * VM location.
116
+ */
117
+ vm: {
118
+ name: string;
119
+ region: string;
120
+ status: string;
121
+ message: string;
122
+ }
123
+ };
124
+
125
+
126
+ `;
127
+ };
128
+
129
+ export function validateScope(value: string): "Cluster" | "Namespaced" {
130
+ if (value !== "Cluster" && value !== "Namespaced") {
131
+ throw new Error("Scope must be either 'Cluster' or 'Namespaced'");
132
+ }
133
+ return value;
134
+ }
@@ -0,0 +1,317 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // SPDX-FileCopyrightText: 2023-Present The Pepr Authors
3
+
4
+ import { Command } from "commander";
5
+ import fs from "fs";
6
+ import path from "path";
7
+ import { stringify as toYAML } from "yaml";
8
+ import {
9
+ Project,
10
+ InterfaceDeclaration,
11
+ TypeAliasDeclaration,
12
+ SyntaxKind,
13
+ Node,
14
+ SourceFile,
15
+ Type,
16
+ } from "ts-morph";
17
+ import { createDirectoryIfNotExists } from "../../lib/filesystemService";
18
+ import { kind as k } from "kubernetes-fluent-client";
19
+ import { V1JSONSchemaProps } from "@kubernetes/client-node";
20
+
21
+ export default new Command("generate")
22
+ .description("Generate CRD manifests from TypeScript definitions")
23
+ .option("--output <output>", "Output directory for generated CRDs", "./crds")
24
+ .action(generateCRDs);
25
+
26
+ export function extractCRDDetails(
27
+ content: string,
28
+ sourceFile: SourceFile,
29
+ ): {
30
+ kind: string | undefined;
31
+ fqdn: string;
32
+ scope: "Cluster" | "Namespaced";
33
+ plural: string;
34
+ shortNames?: string[];
35
+ } {
36
+ const kind = extractSingleLineComment(content, "Kind");
37
+ const group = extractSingleLineComment(content, "Group") ?? "example";
38
+ const domain = extractSingleLineComment(content, "Domain") ?? "pepr.dev";
39
+ const details = extractDetails(sourceFile);
40
+
41
+ const fqdn = `${group}.${domain}`;
42
+
43
+ const { plural, scope } = details;
44
+
45
+ const shortNames = details.shortName ? [details.shortName] : undefined;
46
+ return { kind, plural, scope, shortNames, fqdn };
47
+ }
48
+
49
+ export async function generateCRDs(options: { output: string }): Promise<void> {
50
+ console.log("This feature is currently in alpha.\n");
51
+ const outputDir = path.resolve(options.output);
52
+ await createDirectoryIfNotExists(outputDir);
53
+
54
+ const project = new Project();
55
+ const apiRoot = path.resolve("api");
56
+ const versions = getAPIVersions(apiRoot);
57
+
58
+ for (const version of versions) {
59
+ const sourceFiles = loadVersionFiles(project, path.join(apiRoot, version));
60
+ for (const sourceFile of sourceFiles) {
61
+ processSourceFile(sourceFile, version, outputDir);
62
+ }
63
+ }
64
+ }
65
+
66
+ export function getAPIVersions(apiRoot: string): string[] {
67
+ return fs.readdirSync(apiRoot).filter(v => fs.statSync(path.join(apiRoot, v)).isDirectory());
68
+ }
69
+
70
+ export function loadVersionFiles(project: Project, versionDir: string): SourceFile[] {
71
+ const files = fs.readdirSync(versionDir).filter(f => f.endsWith(".ts"));
72
+ const filePaths = files.map(f => path.join(versionDir, f));
73
+ return project.addSourceFilesAtPaths(filePaths);
74
+ }
75
+
76
+ export function processSourceFile(
77
+ sourceFile: SourceFile,
78
+ version: string,
79
+ outputDir: string,
80
+ ): void {
81
+ const content = sourceFile.getFullText();
82
+ const { kind, fqdn, scope, plural, shortNames } = extractCRDDetails(content, sourceFile);
83
+
84
+ if (!kind) {
85
+ console.warn(`Skipping ${sourceFile.getBaseName()}: missing '// Kind: <KindName>' comment`);
86
+ return;
87
+ }
88
+
89
+ const spec = sourceFile.getInterface(`${kind}Spec`);
90
+ if (!spec) {
91
+ console.warn(`Skipping ${sourceFile.getBaseName()}: missing interface ${kind}Spec`);
92
+ return;
93
+ }
94
+
95
+ const condition = sourceFile.getTypeAlias(`${kind}StatusCondition`);
96
+ const specSchema = getSchemaFromType(spec);
97
+ const conditionSchema = condition ? getSchemaFromType(condition) : emptySchema();
98
+
99
+ const crd = buildCRD({
100
+ kind,
101
+ fqdn,
102
+ version,
103
+ plural,
104
+ scope,
105
+ shortNames,
106
+ specSchema,
107
+ conditionSchema,
108
+ });
109
+
110
+ const outPath = path.join(outputDir, `${kind.toLowerCase()}.yaml`);
111
+ fs.writeFileSync(outPath, toYAML(crd), "utf8");
112
+ console.log(`✔ Created ${outPath}`);
113
+ }
114
+
115
+ // Extracts a comment from the content of a file based on a label.
116
+ export function extractSingleLineComment(content: string, label: string): string | undefined {
117
+ // https://regex101.com/r/oLFaHP/1
118
+ const match = content.match(new RegExp(`//\\s+${label}:\\s+(.*)`));
119
+ return match?.[1].trim();
120
+ }
121
+
122
+ export function extractDetails(sourceFile: SourceFile): {
123
+ plural: string;
124
+ scope: "Cluster" | "Namespaced";
125
+ shortName: string;
126
+ } {
127
+ const decl = sourceFile.getVariableDeclaration("details");
128
+ if (!decl) {
129
+ throw new Error(`Missing 'details' variable declaration.`);
130
+ }
131
+
132
+ const init = decl.getInitializerIfKindOrThrow(SyntaxKind.ObjectLiteralExpression);
133
+
134
+ const getStr = (key: string): string => {
135
+ const prop = init.getProperty(key);
136
+ const value = prop?.getFirstChildByKind(SyntaxKind.StringLiteral)?.getLiteralText();
137
+ if (!value) {
138
+ throw new Error(`Missing or invalid value for required key: '${key}'`);
139
+ }
140
+ return value;
141
+ };
142
+
143
+ const scope = getStr("scope");
144
+ if (scope === "Cluster" || scope === "Namespaced") {
145
+ return {
146
+ plural: getStr("plural"),
147
+ scope,
148
+ shortName: getStr("shortName"),
149
+ };
150
+ }
151
+
152
+ throw new Error(`'scope' must be either "Cluster" or "Namespaced", got "${scope}"`);
153
+ }
154
+
155
+ export function getJsDocDescription(node: Node): string {
156
+ if (!Node.isPropertySignature(node) && !Node.isPropertyDeclaration(node)) return "";
157
+ return node
158
+ .getJsDocs()
159
+ .map(doc => doc.getComment())
160
+ .filter(Boolean)
161
+ .join(" ")
162
+ .trim();
163
+ }
164
+
165
+ export function getSchemaFromType(decl: InterfaceDeclaration | TypeAliasDeclaration): {
166
+ properties: Record<string, V1JSONSchemaProps>;
167
+ required: string[];
168
+ } {
169
+ const type = decl.getType();
170
+ const properties: Record<string, V1JSONSchemaProps> = {};
171
+ const required: string[] = [];
172
+
173
+ for (const prop of type.getProperties()) {
174
+ const name = uncapitalize(prop.getName());
175
+ const declarations = prop.getDeclarations();
176
+ if (!declarations.length) continue;
177
+
178
+ const declaration = declarations[0];
179
+ const description = getJsDocDescription(declaration);
180
+ const valueType = declaration.getType();
181
+
182
+ properties[name] = {
183
+ ...mapTypeToSchema(valueType),
184
+ ...(description ? { description } : {}),
185
+ };
186
+
187
+ if (!prop.isOptional()) required.push(name);
188
+ }
189
+
190
+ return { properties, required };
191
+ }
192
+
193
+ export function mapTypeToSchema(type: Type): V1JSONSchemaProps {
194
+ if (type.getText() === "Date") return { type: "string", format: "date-time" };
195
+ if (type.isString()) return { type: "string" };
196
+ if (type.isNumber()) return { type: "number" };
197
+ if (type.isBoolean()) return { type: "boolean" };
198
+ if (type.isArray()) {
199
+ return {
200
+ type: "array",
201
+ items: mapTypeToSchema(type.getArrayElementTypeOrThrow()),
202
+ };
203
+ }
204
+
205
+ if (type.isObject()) return buildObjectSchema(type);
206
+ return { type: "string" };
207
+ }
208
+
209
+ export function buildObjectSchema(type: Type): V1JSONSchemaProps {
210
+ const props: Record<string, V1JSONSchemaProps> = {};
211
+ const required: string[] = [];
212
+
213
+ for (const prop of type.getProperties()) {
214
+ const name = uncapitalize(prop.getName());
215
+ const declarations = prop.getDeclarations();
216
+ if (!declarations.length) continue;
217
+
218
+ const decl = declarations[0];
219
+ const description = getJsDocDescription(decl);
220
+ const subType = decl.getType();
221
+
222
+ props[name] = {
223
+ ...mapTypeToSchema(subType),
224
+ ...(description ? { description } : {}),
225
+ };
226
+
227
+ if (!prop.isOptional()) required.push(name);
228
+ }
229
+
230
+ return {
231
+ type: "object",
232
+ properties: props,
233
+ ...(required.length > 0 ? { required } : {}),
234
+ };
235
+ }
236
+
237
+ export function uncapitalize(str: string): string {
238
+ return str.charAt(0).toLowerCase() + str.slice(1);
239
+ }
240
+
241
+ export function emptySchema(): {
242
+ properties: Record<string, V1JSONSchemaProps>;
243
+ required: string[];
244
+ } {
245
+ return { properties: {}, required: [] };
246
+ }
247
+
248
+ interface CRDConfig {
249
+ kind: string;
250
+ fqdn: string;
251
+ version: string;
252
+ plural: string;
253
+ scope: "Cluster" | "Namespaced";
254
+ shortNames?: string[];
255
+ specSchema: ReturnType<typeof getSchemaFromType>;
256
+ conditionSchema: ReturnType<typeof getSchemaFromType>;
257
+ }
258
+
259
+ export function buildCRD(config: CRDConfig): k.CustomResourceDefinition {
260
+ return {
261
+ apiVersion: "apiextensions.k8s.io/v1",
262
+ kind: "CustomResourceDefinition",
263
+ metadata: {
264
+ name: `${config.plural}.${config.fqdn}`,
265
+ },
266
+ spec: {
267
+ group: config.fqdn,
268
+ names: {
269
+ kind: config.kind,
270
+ plural: config.plural,
271
+ singular: config.kind.toLowerCase(),
272
+ ...(config.shortNames ? { shortNames: config.shortNames } : {}),
273
+ },
274
+ scope: config.scope,
275
+ versions: [
276
+ {
277
+ name: config.version,
278
+ served: true,
279
+ storage: true,
280
+ schema: {
281
+ openAPIV3Schema: {
282
+ type: "object",
283
+ properties: {
284
+ spec: {
285
+ type: "object",
286
+ description: `${config.kind}Spec defines the desired state of ${config.kind}`,
287
+ properties: config.specSchema.properties,
288
+ required: config.specSchema.required,
289
+ },
290
+ status: {
291
+ type: "object",
292
+ description: `${config.kind}Status defines the observed state of ${config.kind}`,
293
+ properties: {
294
+ conditions: {
295
+ type: "array",
296
+ description: "Conditions describing the current state",
297
+ items: {
298
+ type: "object",
299
+ description:
300
+ "Condition contains details for one aspect of the current state of this API Resource.",
301
+ properties: config.conditionSchema.properties,
302
+ required: config.conditionSchema.required,
303
+ },
304
+ },
305
+ },
306
+ },
307
+ },
308
+ },
309
+ },
310
+ subresources: {
311
+ status: {},
312
+ },
313
+ },
314
+ ],
315
+ },
316
+ };
317
+ }
@@ -0,0 +1,15 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // SPDX-FileCopyrightText: 2023-Present The Pepr Authors
3
+
4
+ import { RootCmd } from "../root";
5
+ import createCmd from "./create";
6
+ import generateCmd from "./generate";
7
+
8
+ export default function (program: RootCmd): void {
9
+ const crd = program
10
+ .command("crd")
11
+ .description("Scaffold and generate Kubernetes CRDs from structured TypeScript definitions");
12
+
13
+ crd.addCommand(createCmd);
14
+ crd.addCommand(generateCmd);
15
+ }
package/src/cli.ts CHANGED
@@ -15,6 +15,7 @@ import { version } from "./cli/init/templates";
15
15
  import { RootCmd } from "./cli/root";
16
16
  import update from "./cli/update";
17
17
  import kfc from "./cli/kfc";
18
+ import crd from "./cli/crd";
18
19
 
19
20
  if (process.env.npm_lifecycle_event !== "npx") {
20
21
  console.info("Pepr should be run via `npx pepr <command>` instead of `pepr <command>`.");
@@ -25,6 +26,7 @@ if (!process.env.PEPR_NODE_WARNINGS) {
25
26
  process.removeAllListeners("warning");
26
27
  }
27
28
  program
29
+ .enablePositionalOptions()
28
30
  .version(version)
29
31
  .description(`Pepr (v${version}) - Type safe K8s middleware for humans`)
30
32
  .action(() => {
@@ -47,4 +49,5 @@ format(program);
47
49
  monitor(program);
48
50
  uuid(program);
49
51
  kfc(program);
52
+ crd(program);
50
53
  program.parse();
@@ -128,7 +128,14 @@ export class Assets {
128
128
  );
129
129
  await fs.writeFile(
130
130
  helm.files.admissionServiceMonitorYaml,
131
- dedent(serviceMonitorTemplate("admission")),
131
+ dedent(
132
+ serviceMonitorTemplate(
133
+ process.env.PEPR_CUSTOM_BUILD_NAME
134
+ ? `admission-${process.env.PEPR_CUSTOM_BUILD_NAME}`
135
+ : "admission",
136
+ `admission`,
137
+ ),
138
+ ),
132
139
  );
133
140
  }
134
141
 
@@ -232,7 +239,14 @@ export class Assets {
232
239
  );
233
240
  await fs.writeFile(
234
241
  helm.files.watcherServiceMonitorYaml,
235
- dedent(serviceMonitorTemplate("watcher")),
242
+ dedent(
243
+ serviceMonitorTemplate(
244
+ process.env.PEPR_CUSTOM_BUILD_NAME
245
+ ? `watcher-${process.env.PEPR_CUSTOM_BUILD_NAME}`
246
+ : "watcher",
247
+ `watcher`,
248
+ ),
249
+ ),
236
250
  );
237
251
  }
238
252
  } catch (err) {
@@ -245,22 +245,23 @@ export function admissionDeployTemplate(buildTimestamp: string): string {
245
245
  {{- end }}
246
246
  `;
247
247
  }
248
-
249
- export function serviceMonitorTemplate(name: string): string {
248
+ type ControllerType = "admission" | "watcher";
249
+ export function serviceMonitorTemplate(name: string, type: ControllerType): string {
250
250
  return `
251
- {{- if .Values.${name}.serviceMonitor.enabled }}
251
+ {{- if .Values.${type}.serviceMonitor.enabled }}
252
252
  apiVersion: monitoring.coreos.com/v1
253
253
  kind: ServiceMonitor
254
254
  metadata:
255
255
  name: ${name}
256
+ namespace: pepr-system
256
257
  annotations:
257
- {{- toYaml .Values.${name}.serviceMonitor.annotations | nindent 4 }}
258
+ {{- toYaml .Values.${type}.serviceMonitor.annotations | nindent 4 }}
258
259
  labels:
259
- {{- toYaml .Values.${name}.serviceMonitor.labels | nindent 4 }}
260
+ {{- toYaml .Values.${type}.serviceMonitor.labels | nindent 4 }}
260
261
  spec:
261
262
  selector:
262
263
  matchLabels:
263
- pepr.dev/controller: ${name}
264
+ pepr.dev/controller: ${type}
264
265
  namespaceSelector:
265
266
  matchNames:
266
267
  - pepr-system
@@ -348,8 +348,7 @@ export function getModuleSecret(name: string, data: Buffer, hash: string): kind.
348
348
  const compressedData = compressed.toString("base64");
349
349
  if (secretOverLimit(compressedData)) {
350
350
  const error = new Error(`Module secret for ${name} is over the 1MB limit`);
351
- console.error("Uncaught Exception:", error);
352
- process.exit(1);
351
+ throw error;
353
352
  } else {
354
353
  return {
355
354
  apiVersion: "v1",
@@ -4,20 +4,21 @@ import { Assets } from "../assets";
4
4
  type ConfigType = "manifests" | "charts";
5
5
 
6
6
  export function generateZarfYamlGeneric(assets: Assets, path: string, type: ConfigType): string {
7
+ const zarfComponentName = process.env.PEPR_CUSTOM_BUILD_NAME ?? "module";
7
8
  const manifestSettings = {
8
- name: "module",
9
+ name: zarfComponentName,
9
10
  namespace: "pepr-system",
10
11
  files: [path],
11
12
  };
12
13
  const chartSettings = {
13
- name: "module",
14
+ name: zarfComponentName,
14
15
  namespace: "pepr-system",
15
16
  version: `${assets.config.appVersion || "0.0.1"}`,
16
17
  localPath: path,
17
18
  };
18
19
 
19
20
  const component = {
20
- name: "module",
21
+ name: zarfComponentName,
21
22
  required: true,
22
23
  images: [assets.image],
23
24
  [type]: [type === "manifests" ? manifestSettings : chartSettings],