pepr 0.52.2 → 0.52.3-nightly.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.
Files changed (73) hide show
  1. package/dist/cli/{build.helpers.d.ts → build/build.helpers.d.ts} +4 -4
  2. package/dist/cli/build/build.helpers.d.ts.map +1 -0
  3. package/dist/cli/build/buildModule.d.ts +12 -0
  4. package/dist/cli/build/buildModule.d.ts.map +1 -0
  5. package/dist/cli/build/index.d.ts +3 -0
  6. package/dist/cli/build/index.d.ts.map +1 -0
  7. package/dist/cli/build/loadModule.d.ts +11 -0
  8. package/dist/cli/build/loadModule.d.ts.map +1 -0
  9. package/dist/cli/crd/generate/generators.d.ts +1 -28
  10. package/dist/cli/crd/generate/generators.d.ts.map +1 -1
  11. package/dist/cli/deploy.d.ts +2 -2
  12. package/dist/cli/deploy.d.ts.map +1 -1
  13. package/dist/cli/dev.d.ts.map +1 -1
  14. package/dist/cli/init/templates.d.ts +0 -1
  15. package/dist/cli/init/templates.d.ts.map +1 -1
  16. package/dist/cli/monitor.d.ts +3 -0
  17. package/dist/cli/monitor.d.ts.map +1 -1
  18. package/dist/cli/types.d.ts +14 -0
  19. package/dist/cli/types.d.ts.map +1 -1
  20. package/dist/cli/uuid.d.ts.map +1 -1
  21. package/dist/cli.js +999 -984
  22. package/dist/controller.js +24 -11
  23. package/dist/lib/assets/assets.d.ts.map +1 -1
  24. package/dist/lib/assets/environment.d.ts +1 -0
  25. package/dist/lib/assets/environment.d.ts.map +1 -1
  26. package/dist/lib/assets/loader.d.ts.map +1 -1
  27. package/dist/lib/assets/webhooks.d.ts.map +1 -1
  28. package/dist/lib/assets/yaml/generateAllYaml.d.ts +1 -2
  29. package/dist/lib/assets/yaml/generateAllYaml.d.ts.map +1 -1
  30. package/dist/lib/core/storage.d.ts +2 -1
  31. package/dist/lib/core/storage.d.ts.map +1 -1
  32. package/dist/lib/filter/adjudicators/binding.d.ts +2 -1
  33. package/dist/lib/filter/adjudicators/binding.d.ts.map +1 -1
  34. package/dist/lib/filter/adjudicators/kubernetesObject.d.ts +0 -1
  35. package/dist/lib/filter/adjudicators/kubernetesObject.d.ts.map +1 -1
  36. package/dist/lib/processors/mutate-processor.d.ts +2 -1
  37. package/dist/lib/processors/mutate-processor.d.ts.map +1 -1
  38. package/dist/lib/types.d.ts +0 -4
  39. package/dist/lib/types.d.ts.map +1 -1
  40. package/dist/lib.js +7 -7
  41. package/dist/lib.js.map +2 -2
  42. package/dist/runtime/controller.d.ts +1 -1
  43. package/dist/runtime/controller.d.ts.map +1 -1
  44. package/package.json +10 -11
  45. package/src/cli/{build.helpers.ts → build/build.helpers.ts} +12 -12
  46. package/src/cli/build/buildModule.ts +160 -0
  47. package/src/cli/build/index.ts +150 -0
  48. package/src/cli/build/loadModule.ts +54 -0
  49. package/src/cli/crd/generate/generators.ts +6 -6
  50. package/src/cli/deploy.ts +5 -4
  51. package/src/cli/dev.ts +4 -3
  52. package/src/cli/monitor.ts +2 -2
  53. package/src/cli/types.ts +26 -0
  54. package/src/cli/uuid.ts +5 -6
  55. package/src/lib/assets/assets.ts +5 -1
  56. package/src/lib/assets/deploy.ts +1 -1
  57. package/src/lib/assets/environment.ts +8 -1
  58. package/src/lib/assets/loader.ts +0 -6
  59. package/src/lib/assets/webhooks.ts +5 -8
  60. package/src/lib/assets/yaml/generateAllYaml.ts +1 -1
  61. package/src/lib/controller/index.ts +3 -3
  62. package/src/lib/controller/store.ts +1 -1
  63. package/src/lib/core/capability.ts +3 -3
  64. package/src/lib/core/storage.ts +1 -1
  65. package/src/lib/filter/adjudicators/binding.ts +2 -1
  66. package/src/lib/filter/adjudicators/kubernetesObject.ts +1 -1
  67. package/src/lib/processors/mutate-processor.ts +1 -1
  68. package/src/lib/types.ts +0 -4
  69. package/src/runtime/controller.ts +8 -14
  70. package/dist/cli/build.d.ts +0 -34
  71. package/dist/cli/build.d.ts.map +0 -1
  72. package/dist/cli/build.helpers.d.ts.map +0 -1
  73. package/src/cli/build.ts +0 -375
@@ -100,7 +100,7 @@ export async function deployWebhook(
100
100
  // Create the validating webhook configuration if it is needed
101
101
  await handleWebhookConfiguration(assets, WebhookType.VALIDATE, webhookTimeout, force);
102
102
 
103
- Log.info("Applying the Pepr Store CRD if it doesn't exist");
103
+ Log.debug("Applying the Pepr Store CRD if it doesn't exist");
104
104
  await K8s(kind.CustomResourceDefinition).Apply(peprStoreCRD, { force });
105
105
 
106
106
  if (assets.host) return; // Skip resource deployment if a host is already specified
@@ -1,6 +1,13 @@
1
1
  import { V1EnvVar } from "@kubernetes/client-node";
2
2
  import { ModuleConfig } from "../types";
3
3
 
4
+ export function getLogLevel(config: ModuleConfig): string {
5
+ const fromEnv = process.env.LOG_LEVEL;
6
+ if (fromEnv) {
7
+ return fromEnv;
8
+ }
9
+ return config.logLevel || "info";
10
+ }
4
11
  export function genEnv(
5
12
  config: ModuleConfig,
6
13
  watchMode = false,
@@ -8,7 +15,7 @@ export function genEnv(
8
15
  ): V1EnvVar[] {
9
16
  const noWatchDef = {
10
17
  PEPR_PRETTY_LOG: "false",
11
- LOG_LEVEL: config.logLevel || "info",
18
+ LOG_LEVEL: getLogLevel(config),
12
19
  };
13
20
 
14
21
  const def = {
@@ -26,12 +26,6 @@ export function loadCapabilities(path: string): Promise<CapabilityExport[]> {
26
26
  program.on("message", message => {
27
27
  // Cast the message to the ModuleCapabilities type
28
28
  const capabilities = message.valueOf() as CapabilityExport[];
29
-
30
- // Iterate through the capabilities and generate the rules
31
- for (const capability of capabilities) {
32
- console.info(`Registered Pepr Capability "${capability.name}"`);
33
- }
34
-
35
29
  resolve(capabilities);
36
30
  });
37
31
 
@@ -12,7 +12,6 @@ import { resolveIgnoreNamespaces } from "./ignoredNamespaces";
12
12
  import { Assets } from "./assets";
13
13
  import { Event, WebhookType } from "../enums";
14
14
  import { Binding } from "../types";
15
- import Log from "../telemetry/logger";
16
15
 
17
16
  export const peprIgnoreNamespaces: string[] = ["kube-system", "pepr-system"];
18
17
 
@@ -47,15 +46,13 @@ export async function generateWebhookRules(
47
46
  assets: Assets,
48
47
  isMutateWebhook: boolean,
49
48
  ): Promise<V1RuleWithOperations[]> {
50
- const { config, capabilities } = assets;
49
+ const { capabilities } = assets;
51
50
 
52
- const rules = capabilities.flatMap(capability => {
53
- Log.info(`Module ${config.uuid} has capability: ${capability.name}`);
54
-
55
- return capability.bindings
51
+ const rules = capabilities.flatMap(capability =>
52
+ capability.bindings
56
53
  .map(binding => validateRule(binding, isMutateWebhook))
57
- .filter((rule): rule is V1RuleWithOperations => !!rule);
58
- });
54
+ .filter((rule): rule is V1RuleWithOperations => !!rule),
55
+ );
59
56
 
60
57
  return uniqWith(equals, rules);
61
58
  }
@@ -23,7 +23,7 @@ type services = {
23
23
  watch: V1Service | null;
24
24
  };
25
25
 
26
- export function pushControllerManifests(
26
+ function pushControllerManifests(
27
27
  resources: KubernetesObject[],
28
28
  deployments: deployments,
29
29
  services: services,
@@ -57,10 +57,10 @@ export class Controller {
57
57
  if (typeof onReady === "function") {
58
58
  onReady();
59
59
  }
60
- Log.info("Controller startup complete");
60
+ Log.debug("Controller startup complete");
61
61
  // Initialize the schedule store for each capability
62
62
  new StoreController(capabilities, `pepr-${config.uuid}-schedule`, () => {
63
- Log.info("Scheduling processed");
63
+ Log.debug("Scheduling processed");
64
64
  });
65
65
  });
66
66
 
@@ -112,7 +112,7 @@ export class Controller {
112
112
 
113
113
  // Handle server listening event
114
114
  server.on("listening", () => {
115
- Log.info(`Server listening on port ${port}`);
115
+ Log.debug(`Server listening on port ${port}`);
116
116
  // Track that the server is running
117
117
  this.#running = true;
118
118
  });
@@ -138,7 +138,7 @@ export class StoreController {
138
138
  };
139
139
 
140
140
  #createStoreResource = async (e: unknown): Promise<void> => {
141
- Log.info(`Pepr store not found, creating...`);
141
+ Log.debug(`Pepr store not found, creating...`);
142
142
  Log.debug(e);
143
143
 
144
144
  try {
@@ -133,7 +133,7 @@ export class Capability implements CapabilityExport {
133
133
  this.#namespaces = cfg.namespaces;
134
134
  this.hasSchedule = false;
135
135
 
136
- Log.info(`Capability ${this.#name} registered`);
136
+ Log.debug(`Capability ${this.#name} registered`);
137
137
  Log.debug(cfg);
138
138
  }
139
139
 
@@ -141,7 +141,7 @@ export class Capability implements CapabilityExport {
141
141
  * Register the store with the capability. This is called automatically by the Pepr controller.
142
142
  */
143
143
  registerScheduleStore = (): Storage => {
144
- Log.info(`Registering schedule store for ${this.#name}`);
144
+ Log.debug(`Registering schedule store for ${this.#name}`);
145
145
 
146
146
  if (this.#scheduleRegistered) {
147
147
  throw new Error(`Schedule store already registered for ${this.#name}`);
@@ -159,7 +159,7 @@ export class Capability implements CapabilityExport {
159
159
  * @param store
160
160
  */
161
161
  registerStore = (): Storage => {
162
- Log.info(`Registering store for ${this.#name}`);
162
+ Log.debug(`Registering store for ${this.#name}`);
163
163
 
164
164
  if (this.#registered) {
165
165
  throw new Error(`Store already registered for ${this.#name}`);
@@ -6,7 +6,7 @@ import pointer from "json-pointer";
6
6
  export type DataOp = "add" | "remove";
7
7
  export type DataStore = Record<string, string>;
8
8
  export type DataSender = (op: DataOp, keys: string[], value?: string) => void;
9
- export type DataReceiver = (data: DataStore) => void;
9
+ type DataReceiver = (data: DataStore) => void;
10
10
  export type Unsubscribe = () => void;
11
11
 
12
12
  const MAX_WAIT_TIME = 15000;
@@ -74,7 +74,8 @@ export const definedCategory = (binding: Partial<Binding>): string => {
74
74
 
75
75
  return Object.keys(categories).find(key => categories[key]) || "";
76
76
  };
77
- export type DefinedCallbackReturnType =
77
+
78
+ type DefinedCallbackReturnType =
78
79
  | FinalizeAction<GenericClass, InstanceType<GenericClass>>
79
80
  | WatchLogAction<GenericClass, InstanceType<GenericClass>>
80
81
  | MutateAction<GenericClass, InstanceType<GenericClass>>
@@ -4,7 +4,7 @@
4
4
  import { __, allPass, complement, defaultTo, equals, length, gt, not, nthArg, pipe } from "ramda";
5
5
  import { KubernetesObject } from "kubernetes-fluent-client";
6
6
 
7
- export const carriesDeletionTimestamp = pipe(
7
+ const carriesDeletionTimestamp = pipe(
8
8
  kubernetesObject => !!kubernetesObject.metadata?.deletionTimestamp,
9
9
  defaultTo(false),
10
10
  );
@@ -30,7 +30,7 @@ export interface Bindable {
30
30
  actMeta: Record<string, string>;
31
31
  }
32
32
 
33
- export interface Result {
33
+ interface Result {
34
34
  wrapped: PeprMutateRequest<KubernetesObject>;
35
35
  response: MutateResponse;
36
36
  }
package/src/lib/types.ts CHANGED
@@ -68,10 +68,6 @@ export type WhenSelector<T extends GenericClass> = {
68
68
  /** Register an action to be executed when a Kubernetes resource is deleted. */
69
69
  IsDeleted: () => BindingAll<T>;
70
70
  };
71
- export interface RegExpFilter {
72
- obj: RegExp;
73
- source: string;
74
- }
75
71
 
76
72
  export type Filters = {
77
73
  annotations: Record<string, string>;
@@ -18,16 +18,12 @@ function runModule(expectedHash: string): void {
18
18
  const gzPath = `/app/load/module-${expectedHash}.js.gz`;
19
19
  const jsPath = `/app/module-${expectedHash}.js`;
20
20
 
21
- // Set the log level
22
- Log.level = "info";
23
-
24
21
  // Check if the path is a valid file
25
22
  if (!fs.existsSync(gzPath)) {
26
23
  throw new Error(`File not found: ${gzPath}`);
27
24
  }
28
-
29
25
  try {
30
- Log.info(`Loading module ${gzPath}`);
26
+ Log.debug(`Loading module ${gzPath}`);
31
27
 
32
28
  // Extract the code from the file
33
29
  const codeGZ = fs.readFileSync(gzPath);
@@ -42,8 +38,7 @@ function runModule(expectedHash: string): void {
42
38
  if (!crypto.timingSafeEqual(Buffer.from(expectedHash, "hex"), Buffer.from(actualHash, "hex"))) {
43
39
  throw new Error(`File hash does not match, expected ${expectedHash} but got ${actualHash}`);
44
40
  }
45
-
46
- Log.info(`File hash matches, running module`);
41
+ Log.debug(`File hash matches, running module`);
47
42
 
48
43
  // Write the code to a file
49
44
  fs.writeFileSync(jsPath, code);
@@ -55,13 +50,10 @@ function runModule(expectedHash: string): void {
55
50
  }
56
51
  }
57
52
 
58
- Log.info(`Pepr Controller (v${version})`);
59
-
60
- const hash = process.argv[2];
61
-
62
- const startup = async (): Promise<void> => {
53
+ export const startup = async (hash: string): Promise<void> => {
63
54
  try {
64
- Log.info("Applying the Pepr Store CRD if it doesn't exist");
55
+ Log.debug(`Pepr Controller (v${version})`);
56
+ Log.debug("Applying the Pepr Store CRD if it doesn't exist");
65
57
  await K8s(kind.CustomResourceDefinition).Apply(peprStoreCRD, { force: true });
66
58
 
67
59
  validateHash(hash);
@@ -72,4 +64,6 @@ const startup = async (): Promise<void> => {
72
64
  }
73
65
  };
74
66
 
75
- startup().catch(err => Log.error(err, `Error starting Pepr Controller`));
67
+ // Start the controller
68
+ const hash = process.argv[2];
69
+ startup(hash).catch(err => Log.error(err, `Error starting Pepr Controller`));
@@ -1,34 +0,0 @@
1
- import { BuildContext, BuildOptions, BuildResult } from "esbuild";
2
- import { Command } from "commander";
3
- import { ModuleConfig } from "../lib/types";
4
- export type Reloader = (opts: BuildResult<BuildOptions>) => void | Promise<void>;
5
- export type PeprNestedFields = Pick<ModuleConfig, "uuid" | "onError" | "webhookTimeout" | "customLabels" | "alwaysIgnore" | "env" | "rbac" | "rbacMode"> & {
6
- peprVersion: string;
7
- };
8
- export type PeprConfig = Omit<ModuleConfig, keyof PeprNestedFields> & {
9
- pepr: PeprNestedFields & {
10
- includedFiles: string[];
11
- };
12
- description: string;
13
- version: string;
14
- };
15
- type LoadModuleReturn = {
16
- cfg: PeprConfig;
17
- entryPointPath: string;
18
- modulePath: string;
19
- name: string;
20
- path: string;
21
- uuid: string;
22
- };
23
- type BuildModuleReturn = {
24
- ctx: BuildContext<BuildOptions>;
25
- path: string;
26
- cfg: PeprConfig;
27
- uuid: string;
28
- };
29
- export default function (program: Command): void;
30
- export declare function loadModule(entryPoint?: string): Promise<LoadModuleReturn>;
31
- export declare function buildModule(reloader?: Reloader, entryPoint?: string, embed?: boolean): Promise<BuildModuleReturn | void>;
32
- export declare function checkFormat(): Promise<void>;
33
- export {};
34
- //# sourceMappingURL=build.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/cli/build.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,WAAW,EAAmB,MAAM,SAAS,CAAC;AAKnF,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAc5C,MAAM,MAAM,QAAQ,GAAG,CAAC,IAAI,EAAE,WAAW,CAAC,YAAY,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AACjF,MAAM,MAAM,gBAAgB,GAAG,IAAI,CACjC,YAAY,EACV,MAAM,GACN,SAAS,GACT,gBAAgB,GAChB,cAAc,GACd,cAAc,GACd,KAAK,GACL,MAAM,GACN,UAAU,CACb,GAAG;IACF,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG,IAAI,CAAC,YAAY,EAAE,MAAM,gBAAgB,CAAC,GAAG;IACpE,IAAI,EAAE,gBAAgB,GAAG;QACvB,aAAa,EAAE,MAAM,EAAE,CAAC;KACzB,CAAC;IACF,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,KAAK,gBAAgB,GAAG;IACtB,GAAG,EAAE,UAAU,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,KAAK,iBAAiB,GAAG;IACvB,GAAG,EAAE,YAAY,CAAC,YAAY,CAAC,CAAC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,UAAU,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,CAAC,OAAO,WAAW,OAAO,EAAE,OAAO,GAAG,IAAI,CA8H/C;AAWD,wBAAsB,UAAU,CAAC,UAAU,SAAS,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAuC/E;AAED,wBAAsB,WAAW,CAC/B,QAAQ,CAAC,EAAE,QAAQ,EACnB,UAAU,SAAS,EACnB,KAAK,UAAO,GACX,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAwEnC;AA6CD,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CASjD"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"build.helpers.d.ts","sourceRoot":"","sources":["../../src/cli/build.helpers.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAEhD,OAAO,EAAE,YAAY,EAAE,WAAW,EAAW,YAAY,EAAE,MAAM,SAAS,CAAC;AAC3E,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAc9C,UAAU,YAAY;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AACD;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,YAAY,EAAE,YAAY,GAAG,MAAM,CAe9D;AAED,MAAM,MAAM,QAAQ,GAAG,CAAC,IAAI,EAAE,WAAW,CAAC,YAAY,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AACjF;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,EAC3B,GAAG,EAAE;IAAE,IAAI,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GACnC,MAAM,CAaR;AAED;;;;GAIG;AAEH,wBAAsB,qBAAqB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAS9E;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAI/F;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAStE;AAED;;;;;;GAMG;AACH,wBAAsB,sBAAsB,CAC1C,aAAa,EAAE,MAAM,EAAE,EACvB,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,IAAI,CAAC,CAQf;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,YAAY,EAAE,gBAAgB,EAAE,GAAG,IAAI,CAQjF;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CACnC,MAAM,EAAE,YAAY,EACpB,QAAQ,EAAE,QAAQ,GAAG,SAAS,GAC7B,OAAO,CAAC,YAAY,CAAC,YAAY,CAAC,CAAC,CAarC;AAED,wBAAsB,0BAA0B,CAAC,GAAG,EAAE;IACpD,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd,GAAG,OAAO,CAAC,IAAI,CAAC,CAiChB"}
package/src/cli/build.ts DELETED
@@ -1,375 +0,0 @@
1
- // SPDX-License-Identifier: Apache-2.0
2
- // SPDX-FileCopyrightText: 2023-Present The Pepr Authors
3
-
4
- import { execFileSync } from "child_process";
5
- import { BuildContext, BuildOptions, BuildResult, analyzeMetafile } from "esbuild";
6
- import { promises as fs } from "fs";
7
- import { basename, dirname, extname, resolve } from "path";
8
- import { Assets } from "../lib/assets/assets";
9
- import { dependencies, version } from "./init/templates";
10
- import { Command } from "commander";
11
- import { Option } from "commander";
12
- import { parseTimeout } from "../lib/helpers";
13
- import { peprFormat } from "./format";
14
- import { ModuleConfig } from "../lib/types";
15
- import {
16
- watchForChanges,
17
- determineRbacMode,
18
- assignImage,
19
- createOutputDirectory,
20
- handleValidCapabilityNames,
21
- handleCustomImageBuild,
22
- validImagePullSecret,
23
- generateYamlAndWriteToDisk,
24
- } from "./build.helpers";
25
-
26
- const peprTS = "pepr.ts";
27
- let outputDir: string = "dist";
28
- export type Reloader = (opts: BuildResult<BuildOptions>) => void | Promise<void>;
29
- export type PeprNestedFields = Pick<
30
- ModuleConfig,
31
- | "uuid"
32
- | "onError"
33
- | "webhookTimeout"
34
- | "customLabels"
35
- | "alwaysIgnore"
36
- | "env"
37
- | "rbac"
38
- | "rbacMode"
39
- > & {
40
- peprVersion: string;
41
- };
42
-
43
- export type PeprConfig = Omit<ModuleConfig, keyof PeprNestedFields> & {
44
- pepr: PeprNestedFields & {
45
- includedFiles: string[];
46
- };
47
- description: string;
48
- version: string;
49
- };
50
-
51
- type LoadModuleReturn = {
52
- cfg: PeprConfig;
53
- entryPointPath: string;
54
- modulePath: string;
55
- name: string;
56
- path: string;
57
- uuid: string;
58
- };
59
-
60
- type BuildModuleReturn = {
61
- ctx: BuildContext<BuildOptions>;
62
- path: string;
63
- cfg: PeprConfig;
64
- uuid: string;
65
- };
66
-
67
- export default function (program: Command): void {
68
- program
69
- .command("build")
70
- .description("Build a Pepr Module for deployment")
71
- .addOption(
72
- new Option("-M, --rbac-mode <mode>", "Override module config and set RBAC mode.").choices([
73
- "admin",
74
- "scoped",
75
- ]),
76
- )
77
- .addOption(
78
- new Option(
79
- "-I, --registry-info <registry/username>",
80
- "Provide the image registry and username for building and pushing a custom WASM container. Requires authentication. Conflicts with --custom-image and --registry. Builds and pushes `'<registry/username>/custom-pepr-controller:<current-version>'`.",
81
- ).conflicts(["customImage", "registry"]),
82
- )
83
- .option("-P, --with-pull-secret <name>", "Use image pull secret for controller Deployment.", "")
84
- .addOption(
85
- new Option(
86
- "-c, --custom-name <name>",
87
- "Set name for zarf component and service monitors in helm charts.",
88
- ),
89
- )
90
- .option("-e, --entry-point <file>", "Specify the entry point file to build with.", peprTS)
91
- .addOption(
92
- new Option(
93
- "-i, --custom-image <image>",
94
- "Specify a custom image with version for deployments. Conflicts with --registry-info and --registry. Example: 'docker.io/username/custom-pepr-controller:v1.0.0'",
95
- ).conflicts(["registryInfo", "registry"]),
96
- )
97
- .option(
98
- "-n, --no-embed",
99
- "Disable embedding of deployment files into output module. Useful when creating library modules intended solely for reuse/distribution via NPM.",
100
- )
101
- .option("-o, --output <directory>", "Set output directory.", "dist")
102
- .addOption(
103
- new Option(
104
- "-r, --registry <GitHub|Iron Bank>",
105
- "Container registry: Choose container registry for deployment manifests. Conflicts with --custom-image and --registry-info.",
106
- )
107
- .conflicts(["customImage", "registryInfo"])
108
- .choices(["GitHub", "Iron Bank"]),
109
- )
110
- .option(
111
- "-t, --timeout <seconds>",
112
- "How long the API server should wait for a webhook to respond before treating the call as a failure.",
113
- parseTimeout,
114
- )
115
- .addOption(
116
- new Option("-z, --zarf <manifest|chart>", "Set Zarf package type")
117
- .choices(["manifest", "chart"])
118
- .default("manifest"),
119
- )
120
- .action(async opts => {
121
- outputDir = await createOutputDirectory(opts.output);
122
-
123
- // Build the module
124
- const buildModuleResult = await buildModule(undefined, opts.entryPoint, opts.embed);
125
-
126
- const { cfg, path } = buildModuleResult!;
127
- // override the name if provided
128
- if (opts.customName) {
129
- process.env.PEPR_CUSTOM_BUILD_NAME = opts.customName;
130
- }
131
-
132
- const image = assignImage({
133
- customImage: opts.customImage,
134
- registryInfo: opts.registryInfo,
135
- peprVersion: cfg.pepr.peprVersion,
136
- registry: opts.registry,
137
- });
138
-
139
- // Check if there is a custom timeout defined
140
- if (opts.timeout !== undefined) {
141
- cfg.pepr.webhookTimeout = opts.timeout;
142
- }
143
-
144
- if (opts.registryInfo !== undefined) {
145
- console.info(`Including ${cfg.pepr.includedFiles.length} files in controller image.`);
146
- // for journey test to make sure the image is built
147
-
148
- // only actually build/push if there are files to include
149
- await handleCustomImageBuild(
150
- cfg.pepr.includedFiles,
151
- cfg.pepr.peprVersion,
152
- cfg.description,
153
- image,
154
- );
155
- }
156
-
157
- // If building without embedding, exit after building
158
- if (!opts.embed) {
159
- console.info(`Module built successfully at ${path}`);
160
- return;
161
- }
162
-
163
- // Generate a secret for the module
164
- const assets = new Assets(
165
- {
166
- ...cfg.pepr,
167
- appVersion: cfg.version,
168
- description: cfg.description,
169
- alwaysIgnore: {
170
- namespaces: cfg.pepr.alwaysIgnore?.namespaces,
171
- },
172
- // Can override the rbacMode with the CLI option
173
- rbacMode: determineRbacMode(opts, cfg),
174
- },
175
- path,
176
- opts.withPullSecret === "" ? [] : [opts.withPullSecret],
177
- );
178
-
179
- if (image !== "") assets.image = image;
180
-
181
- // Ensure imagePullSecret is valid
182
- validImagePullSecret(opts.withPullSecret);
183
-
184
- handleValidCapabilityNames(assets.capabilities);
185
- await generateYamlAndWriteToDisk({
186
- uuid: cfg.pepr.uuid,
187
- outputDir,
188
- imagePullSecret: opts.withPullSecret,
189
- zarf: opts.zarf,
190
- assets,
191
- });
192
- });
193
- }
194
-
195
- // Create a list of external libraries to exclude from the bundle, these are already stored in the container
196
- const externalLibs = Object.keys(dependencies);
197
-
198
- // Add the pepr library to the list of external libraries
199
- externalLibs.push("pepr");
200
-
201
- // Add the kubernetes client to the list of external libraries as it is pulled in by kubernetes-fluent-client
202
- externalLibs.push("@kubernetes/client-node");
203
-
204
- export async function loadModule(entryPoint = peprTS): Promise<LoadModuleReturn> {
205
- // Resolve path to the module / files
206
- const entryPointPath = resolve(".", entryPoint);
207
- const modulePath = dirname(entryPointPath);
208
- const cfgPath = resolve(modulePath, "package.json");
209
-
210
- // Ensure the module's package.json and entrypoint files exist
211
- try {
212
- await fs.access(cfgPath);
213
- await fs.access(entryPointPath);
214
- } catch {
215
- console.error(
216
- `Could not find ${cfgPath} or ${entryPointPath} in the current directory. Please run this command from the root of your module's directory.`,
217
- );
218
- process.exit(1);
219
- }
220
-
221
- // Read the module's UUID from the package.json file
222
- const moduleText = await fs.readFile(cfgPath, { encoding: "utf-8" });
223
- const cfg = JSON.parse(moduleText);
224
- const { uuid } = cfg.pepr;
225
- const name = `pepr-${uuid}.js`;
226
-
227
- // Set the Pepr version from the current running version
228
- cfg.pepr.peprVersion = version;
229
-
230
- // Exit if the module's UUID could not be found
231
- if (!uuid) {
232
- throw new Error("Could not load the uuid in package.json");
233
- }
234
-
235
- return {
236
- cfg,
237
- entryPointPath,
238
- modulePath,
239
- name,
240
- path: resolve(outputDir, name),
241
- uuid,
242
- };
243
- }
244
-
245
- export async function buildModule(
246
- reloader?: Reloader,
247
- entryPoint = peprTS,
248
- embed = true,
249
- ): Promise<BuildModuleReturn | void> {
250
- try {
251
- const { cfg, modulePath, path, uuid } = await loadModule(entryPoint);
252
-
253
- await checkFormat();
254
- // Resolve node_modules folder (in support of npm workspaces!)
255
- const npmRoot = execFileSync("npm", ["root"]).toString().trim();
256
-
257
- // Run `tsc` to validate the module's types & output sourcemaps
258
- const args = ["--project", `${modulePath}/tsconfig.json`, "--outdir", outputDir];
259
- execFileSync(`${npmRoot}/.bin/tsc`, args);
260
-
261
- // Common build options for all builds
262
- const ctxCfg: BuildOptions = {
263
- bundle: true,
264
- entryPoints: [entryPoint],
265
- external: externalLibs,
266
- format: "cjs",
267
- keepNames: true,
268
- legalComments: "external",
269
- metafile: true,
270
- minify: true,
271
- outfile: path,
272
- plugins: [
273
- {
274
- name: "reload-server",
275
- setup(build): void | Promise<void> {
276
- build.onEnd(async r => {
277
- // Print the build size analysis
278
- if (r?.metafile) {
279
- console.info(await analyzeMetafile(r.metafile));
280
- }
281
-
282
- // If we're in dev mode, call the reloader function
283
- if (reloader) {
284
- await reloader(r);
285
- }
286
- });
287
- },
288
- },
289
- ],
290
- platform: "node",
291
- sourcemap: true,
292
- treeShaking: true,
293
- };
294
-
295
- if (reloader) {
296
- // Only minify the code if we're not in dev mode
297
- ctxCfg.minify = false;
298
- }
299
-
300
- // If not embedding (i.e. making a library module to be distro'd via NPM)
301
- if (!embed) {
302
- // Don't minify
303
- ctxCfg.minify = false;
304
-
305
- // Preserve the original file name
306
- ctxCfg.outfile = resolve(outputDir, basename(entryPoint, extname(entryPoint))) + ".js";
307
-
308
- // Don't bundle
309
- ctxCfg.packages = "external";
310
-
311
- // Don't tree shake
312
- ctxCfg.treeShaking = false;
313
- }
314
-
315
- const ctx = await watchForChanges(ctxCfg, reloader);
316
-
317
- return { ctx, path, cfg, uuid };
318
- } catch (e) {
319
- handleModuleBuildError(e);
320
- }
321
- }
322
-
323
- interface BuildModuleResult {
324
- stdout?: Buffer;
325
- stderr: Buffer;
326
- }
327
-
328
- function handleModuleBuildError(e: BuildModuleResult): void {
329
- console.error(`Error building module:`, e);
330
-
331
- if (!e.stdout) process.exit(1); // Exit with a non-zero exit code on any other error
332
-
333
- const out = e.stdout.toString() as string;
334
- const err = e.stderr.toString();
335
-
336
- console.info(out);
337
- console.error(err);
338
-
339
- // Check for version conflicts
340
- if (out.includes("Types have separate declarations of a private property '_name'.")) {
341
- // Try to find the conflicting package
342
- const pgkErrMatch = /error TS2322: .*? 'import\("\/.*?\/node_modules\/(.*?)\/node_modules/g;
343
- out.matchAll(pgkErrMatch);
344
-
345
- // Look for package conflict errors
346
- const conflicts = [...out.matchAll(pgkErrMatch)];
347
-
348
- // If the regex didn't match, leave a generic error
349
- if (conflicts.length < 1) {
350
- console.info(
351
- `\n\tOne or more imported Pepr Capabilities seem to be using an incompatible version of Pepr.\n\tTry updating your Pepr Capabilities to their latest versions.`,
352
- "Version Conflict",
353
- );
354
- }
355
-
356
- // Otherwise, loop through each conflicting package and print an error
357
- conflicts.forEach(match => {
358
- console.info(
359
- `\n\tPackage '${match[1]}' seems to be incompatible with your current version of Pepr.\n\tTry updating to the latest version.`,
360
- "Version Conflict",
361
- );
362
- });
363
- }
364
- }
365
-
366
- export async function checkFormat(): Promise<void> {
367
- const validFormat = await peprFormat(true);
368
-
369
- if (!validFormat) {
370
- console.info(
371
- "\x1b[33m%s\x1b[0m",
372
- "Formatting errors were found. The build will continue, but you may want to run `npx pepr format` to address any issues.",
373
- );
374
- }
375
- }