pepr 0.35.0 → 0.37.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 (107) hide show
  1. package/dist/cli/init/index.d.ts.map +1 -1
  2. package/dist/cli/init/templates.d.ts +3 -1
  3. package/dist/cli/init/templates.d.ts.map +1 -1
  4. package/dist/cli/init/utils.d.ts.map +1 -1
  5. package/dist/cli/init/walkthrough.d.ts +10 -3
  6. package/dist/cli/init/walkthrough.d.ts.map +1 -1
  7. package/dist/cli.js +253 -31
  8. package/dist/controller.js +138 -1
  9. package/dist/lib/adjudicators.d.ts +63 -0
  10. package/dist/lib/adjudicators.d.ts.map +1 -0
  11. package/dist/lib/adjudicators.test.d.ts +2 -0
  12. package/dist/lib/adjudicators.test.d.ts.map +1 -0
  13. package/dist/lib/assets/loader.d.ts.map +1 -1
  14. package/dist/lib/assets/pods.d.ts +1 -0
  15. package/dist/lib/assets/pods.d.ts.map +1 -1
  16. package/dist/lib/capability.d.ts +1 -0
  17. package/dist/lib/capability.d.ts.map +1 -1
  18. package/dist/lib/capability.test.d.ts +2 -0
  19. package/dist/lib/capability.test.d.ts.map +1 -0
  20. package/dist/lib/controller/index.d.ts.map +1 -1
  21. package/dist/lib/controller/store.d.ts +4 -0
  22. package/dist/lib/controller/store.d.ts.map +1 -1
  23. package/dist/lib/controller/store.test.d.ts +2 -0
  24. package/dist/lib/controller/store.test.d.ts.map +1 -0
  25. package/dist/lib/filter.d.ts +2 -3
  26. package/dist/lib/filter.d.ts.map +1 -1
  27. package/dist/lib/filter.test.d.ts +2 -1
  28. package/dist/lib/filter.test.d.ts.map +1 -1
  29. package/dist/lib/finalizer.d.ts +6 -0
  30. package/dist/lib/finalizer.d.ts.map +1 -0
  31. package/dist/lib/finalizer.test.d.ts +2 -0
  32. package/dist/lib/finalizer.test.d.ts.map +1 -0
  33. package/dist/lib/helpers.d.ts +2 -2
  34. package/dist/lib/helpers.d.ts.map +1 -1
  35. package/dist/lib/helpers.test.d.ts +1 -1
  36. package/dist/lib/helpers.test.d.ts.map +1 -1
  37. package/dist/lib/k8s.d.ts.map +1 -1
  38. package/dist/lib/logger.d.ts +1 -1
  39. package/dist/lib/logger.d.ts.map +1 -1
  40. package/dist/lib/module.d.ts +2 -1
  41. package/dist/lib/module.d.ts.map +1 -1
  42. package/dist/lib/mutate-processor.d.ts +2 -1
  43. package/dist/lib/mutate-processor.d.ts.map +1 -1
  44. package/dist/lib/mutate-request.d.ts +1 -2
  45. package/dist/lib/mutate-request.d.ts.map +1 -1
  46. package/dist/lib/queue.d.ts +19 -3
  47. package/dist/lib/queue.d.ts.map +1 -1
  48. package/dist/lib/schedule.d.ts +1 -2
  49. package/dist/lib/schedule.d.ts.map +1 -1
  50. package/dist/lib/storage.d.ts.map +1 -1
  51. package/dist/lib/types.d.ts +118 -6
  52. package/dist/lib/types.d.ts.map +1 -1
  53. package/dist/lib/validate-processor.d.ts +4 -2
  54. package/dist/lib/validate-processor.d.ts.map +1 -1
  55. package/dist/lib/validate-request.d.ts +1 -1
  56. package/dist/lib/validate-request.d.ts.map +1 -1
  57. package/dist/lib/watch-processor.d.ts +8 -6
  58. package/dist/lib/watch-processor.d.ts.map +1 -1
  59. package/dist/lib.js +467 -233
  60. package/dist/lib.js.map +4 -4
  61. package/dist/sdk/sdk.d.ts +5 -3
  62. package/dist/sdk/sdk.d.ts.map +1 -1
  63. package/package.json +13 -11
  64. package/src/cli/build.ts +3 -3
  65. package/src/cli/init/index.ts +20 -11
  66. package/src/cli/init/templates.ts +1 -1
  67. package/src/cli/init/utils.test.ts +11 -20
  68. package/src/cli/init/utils.ts +5 -0
  69. package/src/cli/init/walkthrough.test.ts +92 -11
  70. package/src/cli/init/walkthrough.ts +71 -16
  71. package/src/cli/monitor.ts +1 -1
  72. package/src/cli.ts +4 -2
  73. package/src/fixtures/data/create-pod.json +1 -1
  74. package/src/fixtures/data/delete-pod.json +1 -1
  75. package/src/lib/adjudicators.test.ts +1232 -0
  76. package/src/lib/adjudicators.ts +235 -0
  77. package/src/lib/assets/index.ts +1 -1
  78. package/src/lib/assets/loader.ts +1 -0
  79. package/src/lib/assets/webhooks.ts +1 -1
  80. package/src/lib/capability.test.ts +655 -0
  81. package/src/lib/capability.ts +112 -11
  82. package/src/lib/controller/index.ts +7 -4
  83. package/src/lib/controller/store.test.ts +131 -0
  84. package/src/lib/controller/store.ts +43 -5
  85. package/src/lib/filter.test.ts +279 -9
  86. package/src/lib/filter.ts +46 -98
  87. package/src/lib/finalizer.test.ts +236 -0
  88. package/src/lib/finalizer.ts +63 -0
  89. package/src/lib/helpers.test.ts +359 -65
  90. package/src/lib/helpers.ts +141 -95
  91. package/src/lib/k8s.ts +4 -0
  92. package/src/lib/module.ts +3 -3
  93. package/src/lib/mutate-processor.ts +5 -4
  94. package/src/lib/mutate-request.test.ts +1 -2
  95. package/src/lib/mutate-request.ts +1 -3
  96. package/src/lib/queue.test.ts +138 -44
  97. package/src/lib/queue.ts +48 -13
  98. package/src/lib/schedule.ts +1 -1
  99. package/src/lib/storage.ts +5 -6
  100. package/src/lib/types.ts +154 -5
  101. package/src/lib/validate-processor.ts +5 -2
  102. package/src/lib/validate-request.test.ts +1 -4
  103. package/src/lib/validate-request.ts +1 -1
  104. package/src/lib/watch-processor.test.ts +89 -124
  105. package/src/lib/watch-processor.ts +52 -35
  106. package/src/sdk/sdk.test.ts +46 -13
  107. package/src/sdk/sdk.ts +15 -6
package/dist/sdk/sdk.d.ts CHANGED
@@ -24,10 +24,12 @@ export declare function containers(request: PeprValidateRequest<a.Pod> | PeprMut
24
24
  export declare function writeEvent(cr: GenericKind, event: Partial<kind.CoreEvent>, eventType: string, eventReason: string, reportingComponent: string, reportingInstance: string): Promise<void>;
25
25
  /**
26
26
  * Get the owner reference for a custom resource
27
- * @param cr the custom resource to get the owner reference for
28
- * @returns the owner reference for the custom resource
27
+ * @param customResource the custom resource to get the owner reference for
28
+ * @param blockOwnerDeletion if true, AND if the owner has the "foregroundDeletion" finalizer, then the owner cannot be deleted from the key-value store until this reference is removed.
29
+ * @param controller if true, this reference points to the managing controller.
30
+ * @returns the owner reference array for the custom resource
29
31
  */
30
- export declare function getOwnerRefFrom(cr: GenericKind): V1OwnerReference[];
32
+ export declare function getOwnerRefFrom(customResource: GenericKind, blockOwnerDeletion?: boolean, controller?: boolean): V1OwnerReference[];
31
33
  /**
32
34
  * Sanitize a resource name to make it a valid Kubernetes resource name.
33
35
  *
@@ -1 +1 @@
1
- {"version":3,"file":"sdk.d.ts","sourceRoot":"","sources":["../../src/sdk/sdk.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,CAAC,EAAE,MAAM,QAAQ,CAAC;AAC3B,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAO,IAAI,EAAE,MAAM,0BAA0B,CAAC;AAGrD;;;;;GAKG;AACH,wBAAgB,UAAU,CACxB,OAAO,EAAE,mBAAmB,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,iBAAiB,CAAC,CAAC,CAAC,GAAG,CAAC,EAC9D,aAAa,CAAC,EAAE,YAAY,GAAG,gBAAgB,GAAG,qBAAqB,mDAgBxE;AAED;;;;;;;;;GASG;AACH,wBAAsB,UAAU,CAC9B,EAAE,EAAE,WAAW,EACf,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,EAC9B,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,EACnB,kBAAkB,EAAE,MAAM,EAC1B,iBAAiB,EAAE,MAAM,iBAwB1B;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,EAAE,EAAE,WAAW,GAAG,gBAAgB,EAAE,CAWnE;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,UAYhD"}
1
+ {"version":3,"file":"sdk.d.ts","sourceRoot":"","sources":["../../src/sdk/sdk.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,CAAC,EAAE,MAAM,QAAQ,CAAC;AAC3B,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAO,IAAI,EAAE,MAAM,0BAA0B,CAAC;AAGrD;;;;;GAKG;AACH,wBAAgB,UAAU,CACxB,OAAO,EAAE,mBAAmB,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,iBAAiB,CAAC,CAAC,CAAC,GAAG,CAAC,EAC9D,aAAa,CAAC,EAAE,YAAY,GAAG,gBAAgB,GAAG,qBAAqB,mDAgBxE;AAED;;;;;;;;;GASG;AACH,wBAAsB,UAAU,CAC9B,EAAE,EAAE,WAAW,EACf,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,EAC9B,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,EACnB,kBAAkB,EAAE,MAAM,EAC1B,iBAAiB,EAAE,MAAM,iBAwB1B;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,cAAc,EAAE,WAAW,EAC3B,kBAAkB,CAAC,EAAE,OAAO,EAC5B,UAAU,CAAC,EAAE,OAAO,GACnB,gBAAgB,EAAE,CAcpB;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,UAYhD"}
package/package.json CHANGED
@@ -13,7 +13,7 @@
13
13
  "/dist",
14
14
  "/src"
15
15
  ],
16
- "version": "0.35.0",
16
+ "version": "0.37.0",
17
17
  "main": "dist/lib.js",
18
18
  "types": "dist/lib.d.ts",
19
19
  "scripts": {
@@ -22,7 +22,7 @@
22
22
  "prebuild": "rm -fr dist/* && npm run gen-data-json",
23
23
  "version": "node scripts/set-version.js",
24
24
  "build": "tsc && node build.mjs",
25
- "build:image": "npm run build && docker buildx build --tag pepr:dev .",
25
+ "build:image": "npm run build && docker buildx build --output type=docker --tag pepr:dev .",
26
26
  "test": "npm run test:unit && npm run test:journey",
27
27
  "test:unit": "npm run gen-data-json && jest src --coverage --detectOpenHandles --coverageDirectory=./coverage",
28
28
  "test:journey": "npm run test:journey:k3d && npm run test:journey:build && npm run test:journey:image && npm run test:journey:run",
@@ -30,31 +30,32 @@
30
30
  "test:journey-wasm": "npm run test:journey:k3d && npm run test:journey:build && npm run test:journey:image && npm run test:journey:run-wasm",
31
31
  "test:journey:k3d": "k3d cluster delete pepr-dev && k3d cluster create pepr-dev --k3s-arg '--debug@server:0' --wait && kubectl rollout status deployment -n kube-system",
32
32
  "test:journey:build": "npm run build && npm pack",
33
- "test:journey:image": "docker buildx build --tag pepr:dev . && k3d image import pepr:dev -c pepr-dev",
33
+ "test:journey:image": "docker buildx build --output type=docker --tag pepr:dev . && k3d image import pepr:dev -c pepr-dev",
34
34
  "test:journey:run": "jest --detectOpenHandles journey/entrypoint.test.ts && npm run test:journey:prep && npm run test:journey:upgrade",
35
35
  "test:journey:run-wasm": "jest --detectOpenHandles journey/entrypoint-wasm.test.ts",
36
36
  "test:journey:upgrade": "npm run test:journey:k3d && npm run test:journey:image && jest --detectOpenHandles journey/pepr-upgrade.test.ts",
37
37
  "format:check": "eslint src && prettier src --check",
38
- "format:fix": "eslint src --fix && prettier src --write"
38
+ "format:fix": "eslint src --fix && prettier src --write",
39
+ "prepare": "if [ \"$NODE_ENV\" != 'production' ]; then husky; fi"
39
40
  },
40
41
  "dependencies": {
41
42
  "@types/ramda": "0.30.2",
42
- "express": "4.19.2",
43
+ "express": "4.21.0",
43
44
  "fast-json-patch": "3.1.1",
44
45
  "json-pointer": "^0.6.2",
45
- "kubernetes-fluent-client": "3.0.2",
46
- "pino": "9.3.2",
46
+ "kubernetes-fluent-client": "3.0.4",
47
+ "pino": "9.4.0",
47
48
  "pino-pretty": "11.2.2",
48
49
  "prom-client": "15.1.3",
49
50
  "ramda": "0.30.1"
50
51
  },
51
52
  "devDependencies": {
52
- "@commitlint/cli": "19.4.1",
53
- "@commitlint/config-conventional": "19.4.1",
53
+ "@commitlint/cli": "19.5.0",
54
+ "@commitlint/config-conventional": "19.5.0",
54
55
  "@fast-check/jest": "^2.0.1",
55
56
  "@jest/globals": "29.7.0",
56
57
  "@types/eslint": "9.6.1",
57
- "@types/express": "4.17.21",
58
+ "@types/express": "5.0.0",
58
59
  "@types/json-pointer": "^1.0.34",
59
60
  "@types/node": "22.x.x",
60
61
  "@types/node-forge": "1.3.11",
@@ -64,7 +65,8 @@
64
65
  "jest": "29.7.0",
65
66
  "js-yaml": "^4.1.0",
66
67
  "nock": "^13.5.4",
67
- "ts-jest": "29.2.5"
68
+ "ts-jest": "29.2.5",
69
+ "husky": "^9.1.6"
68
70
  },
69
71
  "peerDependencies": {
70
72
  "@typescript-eslint/eslint-plugin": "7.18.0",
package/src/cli/build.ts CHANGED
@@ -139,7 +139,7 @@ export default function (program: RootCmd) {
139
139
 
140
140
  // If registry is set to Iron Bank, use Iron Bank image
141
141
  if (opts?.registry == "Iron Bank") {
142
- console.warn(
142
+ console.info(
143
143
  `\n\tThis command assumes the latest release. Pepr's Iron Bank image release cycle is dictated by renovate and is typically released a few days after the GitHub release.\n\tAs an alternative you may consider custom --custom-image to target a specific image and version.`,
144
144
  );
145
145
  image = `registry1.dso.mil/ironbank/opensource/defenseunicorns/pepr/controller:v${cfg.pepr.peprVersion}`;
@@ -348,7 +348,7 @@ export async function buildModule(reloader?: Reloader, entryPoint = peprTS, embe
348
348
 
349
349
  // If the regex didn't match, leave a generic error
350
350
  if (conflicts.length < 1) {
351
- console.warn(
351
+ console.info(
352
352
  `\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.`,
353
353
  "Version Conflict",
354
354
  );
@@ -356,7 +356,7 @@ export async function buildModule(reloader?: Reloader, entryPoint = peprTS, embe
356
356
 
357
357
  // Otherwise, loop through each conflicting package and print an error
358
358
  conflicts.forEach(match => {
359
- console.warn(
359
+ console.info(
360
360
  `\n\tPackage '${match[1]}' seems to be incompatible with your current version of Pepr.\n\tTry updating to the latest version.`,
361
361
  "Version Conflict",
362
362
  );
@@ -20,29 +20,38 @@ import {
20
20
  tsConfig,
21
21
  } from "./templates";
22
22
  import { createDir, sanitizeName, write } from "./utils";
23
- import { confirm, walkthrough } from "./walkthrough";
23
+ import { confirm, PromptOptions, walkthrough } from "./walkthrough";
24
+ import { ErrorList, Errors } from "../../lib/errors";
24
25
 
25
26
  export default function (program: RootCmd) {
27
+ let response = {} as PromptOptions;
28
+ let pkgOverride = "";
26
29
  program
27
30
  .command("init")
28
31
  .description("Initialize a new Pepr Module")
29
- // skip auto npm install and git init
30
- .option("--skip-post-init", "Skip npm install, git init and VSCode launch")
31
- .action(async opts => {
32
- let pkgOverride = "";
33
-
34
- // Overrides for testing. @todo: don't be so gross with Node CLI testing
32
+ .option("--confirm", "Skip verification prompt when creating a new module.")
33
+ .option("--description <string>", "Explain the purpose of the new module.")
34
+ .option("--name <string>", "Set the name of the new module.")
35
+ .option("--skip-post-init", "Skip npm install, git init, and VSCode launch.")
36
+ .option(`--errorBehavior <${ErrorList.join("|")}>`, "Set a errorBehavior.", Errors.reject)
37
+ .hook("preAction", async thisCommand => {
38
+ // TODO: Overrides for testing. Don't be so gross with Node CLI testing
39
+ // TODO: See pepr/#1140
35
40
  if (process.env.TEST_MODE === "true") {
36
41
  prompts.inject(["pepr-test-module", "A test module for Pepr", "ignore", "y"]);
37
42
  pkgOverride = "file:../pepr-0.0.0-development.tgz";
43
+ response = await walkthrough();
44
+ } else {
45
+ response = await walkthrough(thisCommand.opts());
46
+ Object.entries(response).map(([key, value]) => thisCommand.setOptionValue(key, value));
38
47
  }
39
-
40
- const response = await walkthrough();
48
+ })
49
+ .action(async opts => {
41
50
  const dirName = sanitizeName(response.name);
42
51
  const packageJSON = genPkgJSON(response, pkgOverride);
43
52
  const peprTS = genPeprTS();
44
53
 
45
- const confirmed = await confirm(dirName, packageJSON, peprTS.path);
54
+ const confirmed = await confirm(dirName, packageJSON, peprTS.path, opts.confirm);
46
55
 
47
56
  if (confirmed) {
48
57
  console.log("Creating new Pepr module...");
@@ -72,7 +81,7 @@ export default function (program: RootCmd) {
72
81
  });
73
82
 
74
83
  // setup git
75
- execSync("git init", {
84
+ execSync("git init --initial-branch=main", {
76
85
  stdio: "inherit",
77
86
  });
78
87
 
@@ -13,7 +13,7 @@ import peprSnippetsJSON from "../../templates/pepr.code-snippets.json";
13
13
  import settingsJSON from "../../templates/settings.json";
14
14
  import tsConfigJSON from "../../templates/tsconfig.module.json";
15
15
  import { sanitizeName } from "./utils";
16
- import { InitOptions } from "./walkthrough";
16
+ import { InitOptions } from "../../lib/types";
17
17
 
18
18
  export const { dependencies, devDependencies, peerDependencies, scripts, version } = packageJSON;
19
19
 
@@ -1,28 +1,19 @@
1
1
  // SPDX-License-Identifier: Apache-2.0
2
2
  // SPDX-FileCopyrightText: 2023-Present The Pepr Authors
3
3
 
4
- import { expect, test } from "@jest/globals";
4
+ import { expect, it } from "@jest/globals";
5
5
 
6
6
  import { sanitizeName } from "./utils";
7
7
 
8
- test("sanitizeName() sanitizes names correctly", () => {
9
- const cases = [
10
- {
11
- input: "My Test Module",
12
- expected: "my-test-module",
13
- },
14
- {
15
- input: "!! 123 @@ Module",
16
- expected: "123-module",
17
- },
18
- {
19
- input: "---Test-Module---",
20
- expected: "test-module",
21
- },
22
- ];
8
+ it.each([
9
+ //Test sanitizeName() with ["$BAD_INPUT", "$SANITIZED_INPUT"]
10
+ ["My Test Module", "my-test-module"],
11
+ ["!! 123 @@ Module", "123-module"],
12
+ ["---Test-Module---", "test-module"],
13
+ ])("sanitizeName() sanitizes '%s' correctly", (input: string, expected: string) => {
14
+ expect(sanitizeName(input)).toBe(expected);
15
+ });
23
16
 
24
- for (const { input, expected } of cases) {
25
- const result = sanitizeName(input);
26
- expect(result).toBe(expected);
27
- }
17
+ it("sanitizeName() should throw TypeError when given a non-string", () => {
18
+ expect(() => sanitizeName({ input: 0 } as unknown as string)).toThrow(TypeError);
28
19
  });
@@ -10,6 +10,11 @@ import { promises as fs } from "fs";
10
10
  * @returns the sanitized name
11
11
  */
12
12
  export function sanitizeName(name: string) {
13
+ if (typeof name !== "string") {
14
+ throw TypeError(
15
+ `sanitizeName() was called with a non-string value. The value is: ${name} of type ${typeof name}`,
16
+ );
17
+ }
13
18
  // Replace any characters outside of [^a-z0-9-] with "-"
14
19
  let sanitized = name.toLowerCase().replace(/[^a-z0-9-]+/gi, "-");
15
20
 
@@ -1,21 +1,102 @@
1
1
  // SPDX-License-Identifier: Apache-2.0
2
2
  // SPDX-FileCopyrightText: 2023-Present The Pepr Authors
3
3
 
4
- import { expect, test } from "@jest/globals";
4
+ import { describe, expect, it } from "@jest/globals";
5
5
  import prompts from "prompts";
6
+ import {
7
+ walkthrough,
8
+ confirm,
9
+ PromptOptions,
10
+ PartialPromptOptions,
11
+ setName,
12
+ setErrorBehavior,
13
+ } from "./walkthrough";
6
14
 
7
- import { walkthrough } from "./walkthrough";
15
+ describe("when processing input", () => {
16
+ describe("walkthough() returns expected results", () => {
17
+ it.each([
18
+ //Test flag combinations with [["$FLAG", ...]]
19
+ [["description", "errorBehavior"]],
20
+ [["description"]],
21
+ [["errorBehavior"]],
22
+ [["name", "description", "errorBehavior"]],
23
+ [["name", "description"]],
24
+ [["name", "errorBehavior"]],
25
+ [["name"]],
26
+ [undefined],
27
+ ])(`when the set flags are: %s`, async (flagInput: string[] | undefined) => {
28
+ const expected: PromptOptions = {
29
+ name: "My Test Module",
30
+ description: "A test module for Pepr",
31
+ errorBehavior: "reject",
32
+ };
8
33
 
9
- test("walkthrough() returns expected results", async () => {
10
- // Inject predefined answers for the prompts
11
- prompts.inject(["My Test Module", "A test module for Pepr", 0]);
34
+ // Set values for the flag(s) under test by making a subset of (expected)
35
+ type SupportedFlagNames = keyof typeof expected;
36
+ type PartialTestInput = { [key in SupportedFlagNames]?: string };
37
+ const setFlags =
38
+ flagInput?.reduce((acc: PartialTestInput, key: string) => {
39
+ if (key in expected) {
40
+ acc[key as SupportedFlagNames] = expected[key as SupportedFlagNames];
41
+ }
42
+ return acc;
43
+ }, {} as PartialTestInput) || {};
12
44
 
13
- const result = await walkthrough();
45
+ // Simulate user-input for unset flags by making a subset of (expected - setFlags)
46
+ const promptInput = flagInput
47
+ ? Object.entries(expected)
48
+ .filter(([key]) => !flagInput.includes(key))
49
+ .map(([, value]) => value)
50
+ : Object.values(expected);
51
+ prompts.inject(Object.values(promptInput));
14
52
 
15
- // Check the returned object
16
- expect(result).toEqual({
17
- name: "My Test Module",
18
- description: "A test module for Pepr",
19
- errorBehavior: 0,
53
+ const result = await walkthrough(setFlags as PartialPromptOptions);
54
+
55
+ expect(result).toEqual(expected);
56
+ });
57
+
58
+ it("should prompt for input when given invalid input", async () => {
59
+ const expected = { name: "aaa" };
60
+ prompts.inject(["aaa"]);
61
+ const result = await setName("aa");
62
+ expect(result).toStrictEqual(expected);
63
+ });
64
+
65
+ it("should prompt for errorBehavior when given invalid input", async () => {
66
+ const expected = { errorBehavior: "audit" };
67
+ prompts.inject(["audit"]);
68
+ const result = await setErrorBehavior("not-valid" as "reject"); // Type-Coercion forces invalid input
69
+ expect(result).toStrictEqual(expected);
70
+ });
71
+ });
72
+
73
+ describe("confirm() handles input", () => {
74
+ it.each([
75
+ ["n", false],
76
+ ["no", false],
77
+ ["y", true],
78
+ ["yes", true],
79
+ ])("when prompt input is '%s'", async (userInput: string, expected: boolean) => {
80
+ prompts.inject([userInput]);
81
+ const result = await confirm(
82
+ "some string",
83
+ { path: "some path", print: "some print" },
84
+ "some Pepr TS path",
85
+ );
86
+ expect(result).toBe(expected);
87
+ });
88
+
89
+ it.each([[true], [false]])(
90
+ "when flag '--confirm' is %s",
91
+ async (confirmFlag: boolean | undefined) => {
92
+ const result = await confirm(
93
+ "some string",
94
+ { path: "some path", print: "some print" },
95
+ "some Pepr TS path",
96
+ confirmFlag,
97
+ );
98
+ expect(result).toBe(confirmFlag);
99
+ },
100
+ );
20
101
  });
21
102
  });
@@ -4,19 +4,34 @@
4
4
  import { promises as fs } from "fs";
5
5
  import prompt, { Answers, PromptObject } from "prompts";
6
6
 
7
- import { Errors } from "../../lib/errors";
7
+ import { ErrorList, Errors } from "../../lib/errors";
8
8
  import { eslint, gitignore, prettier, readme, tsConfig } from "./templates";
9
9
  import { sanitizeName } from "./utils";
10
10
 
11
- export type InitOptions = Answers<"name" | "description" | "errorBehavior">;
11
+ export type PromptOptions = {
12
+ name: string;
13
+ description: string;
14
+ errorBehavior: "audit" | "ignore" | "reject";
15
+ };
12
16
 
13
- export function walkthrough(): Promise<InitOptions> {
17
+ export type PartialPromptOptions = Partial<PromptOptions>;
18
+
19
+ export async function walkthrough(opts?: PartialPromptOptions): Promise<PromptOptions> {
20
+ const result = {
21
+ ...(await setName(opts?.name)),
22
+ ...(await setDescription(opts?.description)),
23
+ ...(await setErrorBehavior(opts?.errorBehavior)),
24
+ };
25
+ return result as PromptOptions;
26
+ }
27
+
28
+ export async function setName(name?: string): Promise<Answers<string>> {
14
29
  const askName: PromptObject = {
15
30
  type: "text",
16
31
  name: "name",
17
32
  message:
18
33
  "Enter a name for the new Pepr module. This will create a new directory based on the name.\n",
19
- validate: async val => {
34
+ validate: async (val: string) => {
20
35
  try {
21
36
  const name = sanitizeName(val);
22
37
  await fs.access(name, fs.constants.F_OK);
@@ -28,12 +43,36 @@ export function walkthrough(): Promise<InitOptions> {
28
43
  },
29
44
  };
30
45
 
46
+ if (name !== undefined) {
47
+ if (name.length < 3) {
48
+ console.error(`Module name must be at least 3 characters long. Received '${name}'`);
49
+ const response = prompt([askName]);
50
+ return response;
51
+ } else {
52
+ return { name };
53
+ }
54
+ }
55
+
56
+ return prompt([askName]);
57
+ }
58
+
59
+ async function setDescription(description?: string): Promise<Answers<string>> {
31
60
  const askDescription: PromptObject = {
32
61
  type: "text",
33
62
  name: "description",
34
63
  message: "(Recommended) Enter a description for the new Pepr module.\n",
35
64
  };
36
65
 
66
+ if (description !== undefined) {
67
+ return { description };
68
+ }
69
+
70
+ return prompt([askDescription]);
71
+ }
72
+
73
+ export async function setErrorBehavior(
74
+ errorBehavior?: "audit" | "ignore" | "reject",
75
+ ): Promise<Answers<string>> {
37
76
  const askErrorBehavior: PromptObject = {
38
77
  type: "select",
39
78
  name: "errorBehavior",
@@ -61,16 +100,28 @@ export function walkthrough(): Promise<InitOptions> {
61
100
  ],
62
101
  };
63
102
 
64
- return prompt([askName, askDescription, askErrorBehavior]) as Promise<InitOptions>;
103
+ if (errorBehavior !== undefined) {
104
+ if (!ErrorList.includes(errorBehavior)) {
105
+ return prompt([askErrorBehavior]);
106
+ }
107
+ return { errorBehavior };
108
+ }
109
+
110
+ return prompt([askErrorBehavior]);
65
111
  }
66
112
 
67
113
  export async function confirm(
68
114
  dirName: string,
69
115
  packageJSON: { path: string; print: string },
70
116
  peprTSPath: string,
71
- ) {
72
- console.log(`
73
- To be generated:
117
+ skipPrompt?: boolean,
118
+ ): Promise<boolean> {
119
+ const confirmationPrompt: PromptObject = {
120
+ type: "confirm",
121
+ name: "confirm",
122
+ message: "Create the new Pepr module?",
123
+ };
124
+ const confirmationMessage = `To be generated:
74
125
 
75
126
  \x1b[1m${dirName}\x1b[0m
76
127
  ├── \x1b[1m${eslint.path}\x1b[0m
@@ -84,13 +135,17 @@ ${packageJSON.print.replace(/^/gm, " │ ")}
84
135
  ├── \x1b[1m${peprTSPath}\x1b[0m
85
136
  ├── \x1b[1m${readme.path}\x1b[0m
86
137
  └── \x1b[1m${tsConfig.path}\x1b[0m
87
- `);
88
-
89
- const confirm = await prompt({
90
- type: "confirm",
91
- name: "confirm",
92
- message: "Create the new Pepr module?",
93
- });
138
+ `;
94
139
 
95
- return confirm.confirm;
140
+ if (skipPrompt !== undefined) {
141
+ return skipPrompt;
142
+ } else {
143
+ console.log(confirmationMessage);
144
+ const confirm = await prompt([confirmationPrompt]);
145
+ const shouldCreateModule =
146
+ confirm.confirm === "y" || confirm.confirm === "yes" || confirm.confirm === true
147
+ ? true
148
+ : false;
149
+ return shouldCreateModule;
150
+ }
96
151
  }
@@ -84,7 +84,7 @@ export default function (program: RootCmd) {
84
84
  }
85
85
  }
86
86
  } catch {
87
- console.warn(`\nIGNORED - Unable to parse line: ${line}.`);
87
+ // Do nothing
88
88
  }
89
89
  }
90
90
  }
package/src/cli.ts CHANGED
@@ -17,11 +17,13 @@ import update from "./cli/update";
17
17
  import kfc from "./cli/kfc";
18
18
 
19
19
  if (process.env.npm_lifecycle_event !== "npx") {
20
- console.warn("Pepr should be run via `npx pepr <command>` instead of `pepr <command>`.");
20
+ console.info("Pepr should be run via `npx pepr <command>` instead of `pepr <command>`.");
21
21
  }
22
22
 
23
23
  const program = new RootCmd();
24
-
24
+ if (!process.env.PEPR_NODE_WARNINGS) {
25
+ process.removeAllListeners("warning");
26
+ }
25
27
  program
26
28
  .version(version)
27
29
  .description(`Pepr (v${version}) - Type safe K8s middleware for humans`)
@@ -13,7 +13,7 @@
13
13
  "subResource": "",
14
14
  "name": "podinfo",
15
15
  "namespace": "default",
16
- "operation": "Create",
16
+ "operation": "CREATE",
17
17
  "userInfo": {
18
18
  "username": "system:serviceaccount:kube-system:replicaset-controller",
19
19
  "uid": "95c8f0ca-d31a-4d3f-9f27-9a2a2661ab3c",
@@ -13,7 +13,7 @@
13
13
  "subResource": "",
14
14
  "name": "podinfo",
15
15
  "namespace": "default",
16
- "operation": "Delete",
16
+ "operation": "DELETE",
17
17
  "userInfo": {
18
18
  "username": "system:serviceaccount:kube-system:replicaset-controller",
19
19
  "uid": "95c8f0ca-d31a-4d3f-9f27-9a2a2661ab3c",