From 5593109129847f6a861d66ff5de8a96026e3457e Mon Sep 17 00:00:00 2001 From: Barrett LaFrance Date: Thu, 9 Jan 2025 10:45:43 -0600 Subject: [PATCH 01/51] wip: initial --- .eslintrc.json | 2 +- integration/cli/build.test.ts | 8 ++++++++ package.json | 1 + tsconfig.eslint.json | 4 ++++ 4 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 integration/cli/build.test.ts create mode 100644 tsconfig.eslint.json diff --git a/.eslintrc.json b/.eslintrc.json index f3831d9a6..04da5c9c5 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -6,7 +6,7 @@ "extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"], "parser": "@typescript-eslint/parser", "parserOptions": { - "project": ["tsconfig.json"], + "project": ["tsconfig.eslint.json"], "ecmaVersion": 2022 }, "rules": { diff --git a/integration/cli/build.test.ts b/integration/cli/build.test.ts new file mode 100644 index 000000000..4d51179f4 --- /dev/null +++ b/integration/cli/build.test.ts @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2023-Present The Pepr Authors + +import { expect, it } from "@jest/globals"; + +it("does", () => { + expect(true).toBe(true); +}); diff --git a/package.json b/package.json index e2495604c..93eccc970 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "build:image": "npm run build && docker buildx build --output type=docker --tag pepr:dev .", "test": "npm run test:unit && npm run test:journey", "test:unit": "npm run gen-data-json && jest src --coverage --detectOpenHandles --coverageDirectory=./coverage --testPathIgnorePatterns='cosign.e2e.test.ts'", + "test:int": "jest integration", "test:journey": "npm run test:journey:k3d && npm run build && npm run test:journey:image && npm run test:journey:run", "test:journey:prep": "if [ ! -d ./pepr-upgrade-test ]; then git clone https://github.com/defenseunicorns/pepr-upgrade-test.git ; fi", "test:journey-wasm": "npm run test:journey:k3d && npm run build && npm run test:journey:image && npm run test:journey:run-wasm", diff --git a/tsconfig.eslint.json b/tsconfig.eslint.json new file mode 100644 index 000000000..8497fd3df --- /dev/null +++ b/tsconfig.eslint.json @@ -0,0 +1,4 @@ +{ + "extends": "./tsconfig.json", + "include": ["integration/**/*.ts"] +} From d40f43eac105e0e794193bd3944795f0cf419433 Mon Sep 17 00:00:00 2001 From: Barrett LaFrance Date: Thu, 9 Jan 2025 10:58:04 -0600 Subject: [PATCH 02/51] wip: update eslint config --- tsconfig.eslint.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tsconfig.eslint.json b/tsconfig.eslint.json index 8497fd3df..8e41fae78 100644 --- a/tsconfig.eslint.json +++ b/tsconfig.eslint.json @@ -1,4 +1,4 @@ { "extends": "./tsconfig.json", - "include": ["integration/**/*.ts"] + "include": ["src/**/*.ts", "integration/**/*.ts"] } From d775061583a258565534586e0f6280082e85b6a2 Mon Sep 17 00:00:00 2001 From: Barrett LaFrance Date: Thu, 9 Jan 2025 11:01:18 -0600 Subject: [PATCH 03/51] wip: saving progress --- .github/workflows/node.js.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index f22aced21..df5fa2654 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -44,6 +44,25 @@ jobs: uses: codecov/codecov-action@1e68e06f1dbfde0e4cefc87efeba9e4643565303 # v5.1.2 env: CODECOV_TOKEN: ${{ secrets.CODECOV_ORG_TOKEN }} + + integration: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - name: Use Node.js 22 + uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0 + with: + node-version: 22 + cache: "npm" + - name: Setup Helm + uses: azure/setup-helm@fe7b79cd5ee1e45176fcad797de68ecaf3ca4814 # v4.2.0 + with: + version: v3.3.4 + + - run: npm ci + - run: npm run test:int + journey: runs-on: ubuntu-latest steps: From 7a9577d1a6621440f3f03ce1818d7ab0e7366eab Mon Sep 17 00:00:00 2001 From: Barrett LaFrance Date: Thu, 9 Jan 2025 18:19:52 -0600 Subject: [PATCH 04/51] wip: saving progress --- integration/.gitignore | 1 + integration/cli/build.test.ts | 8 -- integration/cli/init.test.ts | 31 +++++++ integration/helpers/cmd.test.ts | 56 ++++++++++++ integration/helpers/cmd.ts | 74 ++++++++++++++++ integration/helpers/pepr.test.ts | 56 ++++++++++++ integration/helpers/pepr.ts | 34 ++++++++ integration/helpers/time.test.ts | 64 ++++++++++++++ integration/helpers/time.ts | 108 +++++++++++++++++++++++ integration/helpers/workdir.test.ts | 127 ++++++++++++++++++++++++++++ integration/helpers/workdir.ts | 48 +++++++++++ package.json | 4 +- 12 files changed, 602 insertions(+), 9 deletions(-) create mode 100644 integration/.gitignore delete mode 100644 integration/cli/build.test.ts create mode 100644 integration/cli/init.test.ts create mode 100644 integration/helpers/cmd.test.ts create mode 100644 integration/helpers/cmd.ts create mode 100644 integration/helpers/pepr.test.ts create mode 100644 integration/helpers/pepr.ts create mode 100644 integration/helpers/time.test.ts create mode 100644 integration/helpers/time.ts create mode 100644 integration/helpers/workdir.test.ts create mode 100644 integration/helpers/workdir.ts diff --git a/integration/.gitignore b/integration/.gitignore new file mode 100644 index 000000000..4f574e404 --- /dev/null +++ b/integration/.gitignore @@ -0,0 +1 @@ +workroot/ diff --git a/integration/cli/build.test.ts b/integration/cli/build.test.ts deleted file mode 100644 index 4d51179f4..000000000 --- a/integration/cli/build.test.ts +++ /dev/null @@ -1,8 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2023-Present The Pepr Authors - -import { expect, it } from "@jest/globals"; - -it("does", () => { - expect(true).toBe(true); -}); diff --git a/integration/cli/init.test.ts b/integration/cli/init.test.ts new file mode 100644 index 000000000..529cd77d3 --- /dev/null +++ b/integration/cli/init.test.ts @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2023-Present The Pepr Authors + +import { beforeAll, describe, expect, it } from "@jest/globals"; +import * as path from "node:path"; +import { Workdir } from "../helpers/workdir"; +import * as time from "../helpers/time"; +import * as pepr from "../helpers/pepr"; + +const FILE = path.basename(__filename); +const HERE = __dirname; + +describe("init", () => { + const workdir = new Workdir(`${FILE}`, `${HERE}/../workroot/cli`); + + beforeAll(async () => { + await workdir.recreate(); + await pepr.prepWorkdir(workdir.path()); + }); + + it( + "init --help", + async () => { + const res = await pepr.cli(workdir.path(), { cmd: "pepr init --help" }); + expect(res.exitcode).toBe(0); + expect(res.stderr.join("").trim()).toBe(""); + expect(res.stdout.at(0)).toMatch("Usage: pepr init"); + }, + time.toMs("2m"), + ); +}); diff --git a/integration/helpers/cmd.test.ts b/integration/helpers/cmd.test.ts new file mode 100644 index 000000000..64077251a --- /dev/null +++ b/integration/helpers/cmd.test.ts @@ -0,0 +1,56 @@ +import { describe, expect, it } from "@jest/globals"; +import { Cmd } from "./cmd"; + +describe("runRaw()", () => { + it("returns stdout", async () => { + const expected = "pong"; + const { stdout } = await new Cmd({ cmd: `echo "${expected}"` }).runRaw(); + expect(stdout.join("")).toBe(expected); + }); + + it("returns exit code", async () => { + const expected = 83; + const { exitcode } = await new Cmd({ cmd: `exit ${expected}` }).runRaw(); + expect(exitcode).toBe(expected); + }); + + it("returns stderr", async () => { + const expected = "oof"; + const { stderr } = await new Cmd({ cmd: `>&2 echo "${expected}" ` }).runRaw(); + expect(stderr.join("")).toBe(expected); + }); + + it("caches last result", async () => { + const cmd = new Cmd({ cmd: `echo "whatever"` }); + const result = await cmd.runRaw(); + expect(result).toBe(cmd.result); + }); + + it("accepts working directory", async () => { + const expected = "/tmp"; + const { stdout } = await new Cmd({ cwd: expected, cmd: `pwd` }).runRaw(); + expect(stdout.join("")).toBe(expected); + }); + + it("accepts env var overrides", async () => { + const [key, val] = ["TESTVAR", "testcontent"]; + const { stdout } = await new Cmd({ env: { [key]: val }, cmd: `echo $${key}` }).runRaw(); + expect(stdout.join("")).toBe(val); + }); +}); + +describe("run()", () => { + it("on success, returns result", async () => { + const expected = "pong"; + const result = await new Cmd({ cmd: `echo "${expected}"` }).run(); + expect(result.stdout.join("")).toBe(expected); + expect(result.stderr.join("")).toBe(""); + expect(result.exitcode).toBe(0); + }); + + it("on failure, throws result", async () => { + const expected = { exitcode: 1, stderr: [], stdout: [] }; + const promise = new Cmd({ cmd: `exit ${expected.exitcode}` }).run(); + expect(promise).rejects.toEqual(expected); + }); +}); diff --git a/integration/helpers/cmd.ts b/integration/helpers/cmd.ts new file mode 100644 index 000000000..2443ef066 --- /dev/null +++ b/integration/helpers/cmd.ts @@ -0,0 +1,74 @@ +import { spawn } from "child_process"; + +export interface Spec { + cmd: string; + stdin?: string[]; + cwd?: string; + env?: object; // object containing key-value pairs +} + +export interface Result { + stdout: string[]; + stderr: string[]; + exitcode: number; +} + +export class Cmd { + result?: Result; + cmd: string; + stdin: string[]; + cwd: string; + env: object; + + constructor(spec: Spec) { + this.cmd = spec.cmd; + this.stdin = spec.stdin || []; + this.cwd = spec.cwd || process.cwd(); + this.env = spec.env ? { ...process.env, ...spec.env } : process.env; + } + + runRaw(): Promise { + return new Promise((resolve, reject) => { + const proc = spawn(this.cmd, [], { + shell: true, + cwd: this.cwd, + env: this.env as NodeJS.ProcessEnv, + }); + + this.stdin.forEach(line => proc.stdin.write(`${line}\n`)); + proc.stdin.end(); + + let bufout: Buffer = Buffer.from(""); + proc.stdout.on("data", buf => { + bufout = Buffer.concat([bufout, buf]); + }); + + let buferr: Buffer = Buffer.from(""); + proc.stderr.on("data", buf => { + buferr = Buffer.concat([buferr, buf]); + }); + + proc.on("close", exitcode => { + const stdout = bufout.toString("utf8") === "" ? [] : bufout.toString("utf8").split(/[\r\n]+/); + + const stderr = buferr.toString("utf8") === "" ? [] : buferr.toString("utf8").split(/[\r\n]+/); + + this.result = { stdout, stderr, exitcode: exitcode || 0 }; + resolve(this.result); + }); + + proc.on("error", err => { + reject(err); + }); + }); + } + + run(): Promise { + return this.runRaw().then(result => { + if (result.exitcode > 0) { + throw result; + } + return result; + }); + } +} diff --git a/integration/helpers/pepr.test.ts b/integration/helpers/pepr.test.ts new file mode 100644 index 000000000..3cc811594 --- /dev/null +++ b/integration/helpers/pepr.test.ts @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2023-Present The Pepr Authors + +import { beforeAll, describe, expect, it } from "@jest/globals"; +import * as fs from "node:fs/promises"; +import * as path from "node:path"; +import { Workdir } from "./workdir"; +import * as time from "./time"; +import * as sut from "./pepr"; + +const FILE = path.basename(__filename); +const HERE = __dirname; + +describe("pepr", () => { + describe("projectRoot", () => { + it("returns pepr project root directory", async () => { + const expected = path.resolve(HERE, "../.."); + const actual = await sut.projectRoot(); + expect(actual).toBe(expected); + }); + }); + + describe("prepWorkdir", () => { + const workdir = new Workdir(`${FILE}-prepWorkdir`, `${HERE}/../workroot/helpers`); + + beforeAll(async () => await workdir.recreate()); + + it("builds pepr package and drops .tgz into given directory", async () => { + await sut.prepWorkdir(workdir.path()); + const files = await fs.readdir(workdir.path()); + + expect(files).toHaveLength(1); + expect(files).toContain("pepr-0.0.0-development.tgz"); + }); + }); + + describe("cli", () => { + const workdir = new Workdir(`${FILE}-cli`, `${HERE}/../workroot/helpers`); + + beforeAll(async () => { + await workdir.recreate(); + await sut.prepWorkdir(workdir.path()); + }); + + it( + "invokes pepr command via .tgz", + async () => { + const res = await sut.cli(workdir.path(), { cmd: "pepr --version" }); + expect(res.exitcode).toBe(0); + expect(res.stderr.join("").trim()).toBe(""); + expect(res.stdout.join("").trim()).toBe("0.0.0-development"); + }, + time.toMs("2m"), + ); + }); +}); diff --git a/integration/helpers/pepr.ts b/integration/helpers/pepr.ts new file mode 100644 index 000000000..bc42825d0 --- /dev/null +++ b/integration/helpers/pepr.ts @@ -0,0 +1,34 @@ +import { resolve, join } from "node:path"; +import { copyFile } from "node:fs/promises"; +import { Spec, Cmd, Result } from "./cmd"; +import { clone } from "ramda"; + +const HERE = __dirname; + +export async function projectRoot(): Promise { + const cmd = new Cmd({ cmd: `npm root`, cwd: HERE }); + const res = await cmd.run(); + const npmroot = res.stdout.join("").trim(); + return resolve(npmroot, ".."); +} + +export async function prepWorkdir(workdir: string): Promise { + const rootdir = await projectRoot(); + const tgz = "pepr-0.0.0-development.tgz"; + const src = join(rootdir, tgz); + const dst = join(workdir, tgz); + await copyFile(src, dst); +} + +export async function cli(workdir: string, spec: Spec): Promise { + const tgz = "pepr-0.0.0-development.tgz"; + + const _spec = clone(spec); + _spec.cwd = workdir; + + const _cmd = _spec.cmd.trim().replace(/^pepr /, `npx --yes file://./${tgz} `); + _spec.cmd = _cmd; + + const cmd = new Cmd(_spec); + return await cmd.runRaw(); +} diff --git a/integration/helpers/time.test.ts b/integration/helpers/time.test.ts new file mode 100644 index 000000000..ccbe8866b --- /dev/null +++ b/integration/helpers/time.test.ts @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2023-Present The Pepr Authors + +import { describe, it, expect } from "@jest/globals"; +import * as sut from "./time"; + +describe("toHuman()", () => { + it.each([ + // simple + [1, "1ms"], + [1000, "1s"], + [60000, "1m"], + [3600000, "1h"], + [86400000, "1d"], + [604800000, "1w"], + [2592000000, "1mo"], + [31536000000, "1y"], + + // combined + [34822861001, "1y1mo1w1d1h1m1s1ms"], + ])("given ms '%s', returns '%s' duration", (ms, human) => { + const result = sut.toHuman(ms); + expect(result).toBe(human); + }); +}); + +describe("toMs()", () => { + it.each([ + // simple + ["1ms", 1], + ["1s", 1000], + ["60s", 60000], + ["1m", 60000], + ["60m", 3600000], + ["1h", 3600000], + ["24h", 86400000], + ["1d", 86400000], + ["7d", 604800000], + ["1w", 604800000], + ["30d", 2592000000], + ["1mo", 2592000000], + ["365d", 31536000000], + ["1y", 31536000000], + + // weird + ["0001s", 1000], + ["1 s ", 1000], + + // combined + ["1y1mo1w1d1h1m1s1ms", 34822861001], + ["1ms1s1m1h1d1w1mo1y", 34822861001], + ])("given duration '%s', returns '%s' ms", (human, ms) => { + const result = sut.toMs(human); + expect(result).toBe(ms); + }); + + it.each([ + // bad + ["h1m1s", /Unrecognized number .* while parsing/], + ["1z", /Unrecognized unit .* while parsing/], + ])("given duration '%s', throws error matching '%s'", (human, err) => { + expect(() => sut.toMs(human)).toThrow(err); + }); +}); diff --git a/integration/helpers/time.ts b/integration/helpers/time.ts new file mode 100644 index 000000000..4e23ec8f5 --- /dev/null +++ b/integration/helpers/time.ts @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2023-Present The Pepr Authors + +export function toMs(human: string) { + const UNITS: Record = {}; + UNITS.ms = 1; + UNITS.s = UNITS.ms * 1000; + UNITS.m = UNITS.s * 60; + UNITS.h = UNITS.m * 60; + UNITS.d = UNITS.h * 24; + UNITS.w = UNITS.d * 7; + UNITS.mo = UNITS.d * 30; + UNITS.y = UNITS.d * 365; + + const splits = human.split("").map(m => m.trim()); + + const groups: string[] = []; + splits.forEach(next => { + const tail = groups.at(-1) as string; + const sameKind = (tail: string, next: string) => /\d+/.test(tail) === /\d+/.test(next); + sameKind(tail, next) ? groups.splice(-1, 1, `${tail}${next}`) : groups.push(next); + }); + + const pairs = groups.reduce<[string, string][]>( + (acc, cur, idx, arr) => (idx % 2 === 0 ? [...acc, [arr[idx], arr[idx + 1]]] : acc), + [], + ); + + const parsed = pairs.map<[number, string]>(([num, unit]) => { + const parsedNum = parseInt(num); + if (isNaN(parsedNum)) { + throw `Unrecognized number "${num}" seen while parsing "${human}"`; + } + + const validUnits = Object.keys(UNITS); + if (!validUnits.includes(unit)) { + throw `Unrecognized unit "${unit}" seen while parsing "${human}"`; + } + + return [parsedNum, unit]; + }); + + const milliseconds = parsed.reduce((acc, [num, unit]) => acc + num * UNITS[unit], 0); + + return milliseconds; +} + +export function toHuman(ms: number) { + const UNITS: Record = {}; + UNITS.ms = 1; + UNITS.s = UNITS.ms * 1000; + UNITS.m = UNITS.s * 60; + UNITS.h = UNITS.m * 60; + UNITS.d = UNITS.h * 24; + UNITS.w = UNITS.d * 7; + UNITS.mo = UNITS.d * 30; + UNITS.y = UNITS.d * 365; + + let y = 0; + let mo = 0; + let w = 0; + let d = 0; + let h = 0; + let m = 0; + let s = 0; + let remain = ms; + + while (remain >= UNITS.y) { + remain -= UNITS.y; + y += 1; + } + while (remain >= UNITS.mo) { + remain -= UNITS.mo; + mo += 1; + } + while (remain >= UNITS.w) { + remain -= UNITS.w; + w += 1; + } + while (remain >= UNITS.d) { + remain -= UNITS.d; + d += 1; + } + while (remain >= UNITS.h) { + remain -= UNITS.h; + h += 1; + } + while (remain >= UNITS.m) { + remain -= UNITS.m; + m += 1; + } + while (remain >= UNITS.s) { + remain -= UNITS.s; + s += 1; + } + + let result = ""; + result = y > 0 ? `${result}${y}y` : result; + result = mo > 0 ? `${result}${mo}mo` : result; + result = w > 0 ? `${result}${w}w` : result; + result = d > 0 ? `${result}${d}d` : result; + result = h > 0 ? `${result}${h}h` : result; + result = m > 0 ? `${result}${m}m` : result; + result = s > 0 ? `${result}${s}s` : result; + result = remain > 0 ? `${result}${remain}ms` : result; + + return result; +} diff --git a/integration/helpers/workdir.test.ts b/integration/helpers/workdir.test.ts new file mode 100644 index 000000000..21dbb36ff --- /dev/null +++ b/integration/helpers/workdir.test.ts @@ -0,0 +1,127 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2023-Present The Pepr Authors + +import { beforeEach, describe, expect, it } from "@jest/globals"; +import * as fs from "node:fs/promises"; +import * as path from "node:path"; +import { Workdir } from "../helpers/workdir"; + +describe("Workdir", () => { + const ROOT_DEFAULT = new Workdir("").root; + + describe("path", () => { + it.each([ + ["a", `/tmp`, `/tmp/a`], + ["b", `/tmp/c`, `/tmp/c/b`], + ["d", undefined, `${ROOT_DEFAULT}/d`], + ["e/f", undefined, `${ROOT_DEFAULT}/e/f`], + ])(`leaf "%s" and root "%s" gives "%s"`, async (leaf, root, expected) => { + const sut = new Workdir(leaf, root); + expect(sut.path()).toBe(expected); + }); + }); + + describe("create", () => { + const sut = new Workdir("create"); + + beforeEach(async () => { + await fs.rm(sut.path(), { recursive: true, force: true }); + }); + + it("creating a non-existant workdir succeeds", async () => { + const path = await sut.create(); + + expect(path).toBe(sut.path()); + await fs.access(path); + }); + + it("creating a pre-existing workdir also succeeds (idempotency, yay!)", async () => { + await sut.create(); + const path = await sut.create(); + + expect(path).toBe(sut.path()); + await fs.access(path); + }); + }); + + describe("exists", () => { + const sut = new Workdir("exists"); + + beforeEach(async () => { + await fs.rm(sut.path(), { recursive: true, force: true }); + }); + + it("returns false when workdir doesn't exist", async () => { + const exists = await sut.exists(); + expect(exists).toBe(false); + }); + + it("returns true when workdir does exist", async () => { + await sut.create(); + const exists = await sut.exists(); + expect(exists).toBe(true); + }); + }); + + describe("delete", () => { + const sut = new Workdir("delete"); + + beforeEach(async () => { + await fs.rm(sut.path(), { recursive: true, force: true }); + }); + + it("deleting a pre-existing workdir succeeds", async () => { + await sut.create(); + await sut.delete(); + expect(await sut.exists()).toBe(false); + }); + + it("deleting a non-existant workdir also succeeds (idempotency, yay!)", async () => { + await sut.delete(); + expect(await sut.exists()).toBe(false); + }); + }); + + describe("isEmpty", () => { + const sut = new Workdir("isEmpty"); + + beforeEach(async () => { + await fs.rm(sut.path(), { recursive: true, force: true }); + }); + + it("returns true when workdir is empty", async () => { + await sut.create(); + expect(await sut.isEmpty()).toBe(true); + }); + + it("returns false when workdir has content", async () => { + await sut.create(); + await fs.writeFile(path.join(sut.path(), "file.txt"), "exists"); + expect(await sut.isEmpty()).toBe(false); + }); + }); + + describe("recreate", () => { + const sut = new Workdir("recreate"); + + beforeEach(async () => { + await fs.rm(sut.path(), { recursive: true, force: true }); + }); + + it("recreating a pre-existing workdir succeeds", async () => { + const path = await sut.create(); + const stat = await fs.stat(path, { bigint: true }); + + const repath = await sut.recreate(); + const restat = await fs.stat(path, { bigint: true }); + + expect(path).toBe(repath); + expect(stat.birthtimeNs).toBeLessThan(restat.birthtimeNs); + }); + + it("recreating a non-existant workdir also succeeds (idempotency, yay!)", async () => { + await sut.recreate(); + expect(await sut.exists()).toBe(true); + }); + }); +}); diff --git a/integration/helpers/workdir.ts b/integration/helpers/workdir.ts new file mode 100644 index 000000000..84f5b7f41 --- /dev/null +++ b/integration/helpers/workdir.ts @@ -0,0 +1,48 @@ +import * as os from "node:os"; +import * as path from "node:path"; +import * as fs from "node:fs/promises"; + +export class Workdir { + root: string; + leaf: string; + + constructor(leaf: string, root: string = os.tmpdir()) { + this.leaf = leaf; + this.root = path.resolve(root); + } + + path() { + return path.join(this.root, this.leaf); + } + + async create(): Promise { + await fs.mkdir(this.path(), { recursive: true }); + return this.path(); + } + + async exists() { + try { + await fs.access(this.path()); + return true; + } catch (e) { + if (e.message.includes("no such file or directory")) { + return false; + } + throw e; + } + } + + async isEmpty() { + const contents = await fs.readdir(this.path()); + return contents.length > 0 ? false : true; + } + + async delete(): Promise { + await fs.rm(this.path(), { recursive: true, force: true }); + } + + async recreate(): Promise { + await this.delete(); + return await this.create(); + } +} diff --git a/package.json b/package.json index 93eccc970..08107e3a2 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,9 @@ "build:image": "npm run build && docker buildx build --output type=docker --tag pepr:dev .", "test": "npm run test:unit && npm run test:journey", "test:unit": "npm run gen-data-json && jest src --coverage --detectOpenHandles --coverageDirectory=./coverage --testPathIgnorePatterns='cosign.e2e.test.ts'", - "test:int": "jest integration", + "test:int": "npm run test:int:prep && npm run test:int:run", + "test:int:prep": "npm run build && npx --yes file://./pepr-0.0.0-development.tgz", + "test:int:run": "jest integration", "test:journey": "npm run test:journey:k3d && npm run build && npm run test:journey:image && npm run test:journey:run", "test:journey:prep": "if [ ! -d ./pepr-upgrade-test ]; then git clone https://github.com/defenseunicorns/pepr-upgrade-test.git ; fi", "test:journey-wasm": "npm run test:journey:k3d && npm run build && npm run test:journey:image && npm run test:journey:run-wasm", From 106d4f077fba35f4f9ce9f92c70d6dca9d2eb054 Mon Sep 17 00:00:00 2001 From: Barrett LaFrance Date: Thu, 9 Jan 2025 18:26:00 -0600 Subject: [PATCH 05/51] wip: saving progress --- integration/helpers/time.ts | 4 ++++ integration/helpers/workdir.ts | 2 ++ 2 files changed, 6 insertions(+) diff --git a/integration/helpers/time.ts b/integration/helpers/time.ts index 4e23ec8f5..f51c3ae7a 100644 --- a/integration/helpers/time.ts +++ b/integration/helpers/time.ts @@ -1,6 +1,10 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-FileCopyrightText: 2023-Present The Pepr Authors +export function nap(ms: number) { + new Promise(resolve => setTimeout(resolve, ms)); +} + export function toMs(human: string) { const UNITS: Record = {}; UNITS.ms = 1; diff --git a/integration/helpers/workdir.ts b/integration/helpers/workdir.ts index 84f5b7f41..5f59e852e 100644 --- a/integration/helpers/workdir.ts +++ b/integration/helpers/workdir.ts @@ -1,6 +1,7 @@ import * as os from "node:os"; import * as path from "node:path"; import * as fs from "node:fs/promises"; +import * as time from "./time"; export class Workdir { root: string; @@ -43,6 +44,7 @@ export class Workdir { async recreate(): Promise { await this.delete(); + await time.nap(1); return await this.create(); } } From bbc0a4f9c38b1292ef9ff50cd015c5dd2dd998ba Mon Sep 17 00:00:00 2001 From: Barrett LaFrance Date: Thu, 9 Jan 2025 18:28:07 -0600 Subject: [PATCH 06/51] wip: saving progress --- integration/helpers/workdir.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration/helpers/workdir.ts b/integration/helpers/workdir.ts index 5f59e852e..60e5b74cd 100644 --- a/integration/helpers/workdir.ts +++ b/integration/helpers/workdir.ts @@ -44,7 +44,7 @@ export class Workdir { async recreate(): Promise { await this.delete(); - await time.nap(1); + await time.nap(100); return await this.create(); } } From 5ac83796b9f2e005a5b88917a3eb86b52e06b0e0 Mon Sep 17 00:00:00 2001 From: Barrett LaFrance Date: Fri, 10 Jan 2025 10:12:03 -0600 Subject: [PATCH 07/51] wip: refactor f/ eslint warnings --- integration/helpers/cmd.test.ts | 2 +- integration/helpers/time.ts | 87 ++++++++++++--------------------- 2 files changed, 31 insertions(+), 58 deletions(-) diff --git a/integration/helpers/cmd.test.ts b/integration/helpers/cmd.test.ts index 64077251a..7d080321a 100644 --- a/integration/helpers/cmd.test.ts +++ b/integration/helpers/cmd.test.ts @@ -51,6 +51,6 @@ describe("run()", () => { it("on failure, throws result", async () => { const expected = { exitcode: 1, stderr: [], stdout: [] }; const promise = new Cmd({ cmd: `exit ${expected.exitcode}` }).run(); - expect(promise).rejects.toEqual(expected); + return expect(promise).rejects.toEqual(expected); }); }); diff --git a/integration/helpers/time.ts b/integration/helpers/time.ts index f51c3ae7a..691991012 100644 --- a/integration/helpers/time.ts +++ b/integration/helpers/time.ts @@ -1,21 +1,21 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-FileCopyrightText: 2023-Present The Pepr Authors -export function nap(ms: number) { - new Promise(resolve => setTimeout(resolve, ms)); +const UNITS: Record = {}; +UNITS.ms = 1; +UNITS.s = UNITS.ms * 1000; +UNITS.m = UNITS.s * 60; +UNITS.h = UNITS.m * 60; +UNITS.d = UNITS.h * 24; +UNITS.w = UNITS.d * 7; +UNITS.mo = UNITS.d * 30; +UNITS.y = UNITS.d * 365; + +export async function nap(ms: number): Promise { + return new Promise(resolve => setTimeout(resolve, ms)); } export function toMs(human: string) { - const UNITS: Record = {}; - UNITS.ms = 1; - UNITS.s = UNITS.ms * 1000; - UNITS.m = UNITS.s * 60; - UNITS.h = UNITS.m * 60; - UNITS.d = UNITS.h * 24; - UNITS.w = UNITS.d * 7; - UNITS.mo = UNITS.d * 30; - UNITS.y = UNITS.d * 365; - const splits = human.split("").map(m => m.trim()); const groups: string[] = []; @@ -49,54 +49,27 @@ export function toMs(human: string) { return milliseconds; } -export function toHuman(ms: number) { - const UNITS: Record = {}; - UNITS.ms = 1; - UNITS.s = UNITS.ms * 1000; - UNITS.m = UNITS.s * 60; - UNITS.h = UNITS.m * 60; - UNITS.d = UNITS.h * 24; - UNITS.w = UNITS.d * 7; - UNITS.mo = UNITS.d * 30; - UNITS.y = UNITS.d * 365; +function reduceBy(unit: number, ms: number): [number, number] { + let remain = ms; + let result = 0; + while (remain >= unit) { + remain -= unit; + result += 1; + } + return [result, remain]; +} - let y = 0; - let mo = 0; - let w = 0; - let d = 0; - let h = 0; - let m = 0; - let s = 0; +export function toHuman(ms: number) { + let [y, mo, w, d, h, m, s] = Array(7).fill(0); let remain = ms; - while (remain >= UNITS.y) { - remain -= UNITS.y; - y += 1; - } - while (remain >= UNITS.mo) { - remain -= UNITS.mo; - mo += 1; - } - while (remain >= UNITS.w) { - remain -= UNITS.w; - w += 1; - } - while (remain >= UNITS.d) { - remain -= UNITS.d; - d += 1; - } - while (remain >= UNITS.h) { - remain -= UNITS.h; - h += 1; - } - while (remain >= UNITS.m) { - remain -= UNITS.m; - m += 1; - } - while (remain >= UNITS.s) { - remain -= UNITS.s; - s += 1; - } + [y, remain] = reduceBy(UNITS.y, remain); + [mo, remain] = reduceBy(UNITS.mo, remain); + [w, remain] = reduceBy(UNITS.w, remain); + [d, remain] = reduceBy(UNITS.d, remain); + [h, remain] = reduceBy(UNITS.h, remain); + [m, remain] = reduceBy(UNITS.m, remain); + [s, remain] = reduceBy(UNITS.s, remain); let result = ""; result = y > 0 ? `${result}${y}y` : result; From ff7df21bebd76d1407167dcd545f4d5528698786 Mon Sep 17 00:00:00 2001 From: Barrett LaFrance Date: Fri, 10 Jan 2025 11:15:09 -0600 Subject: [PATCH 08/51] wip: saving progress --- integration/.gitignore | 2 +- integration/cli/init.test.ts | 36 +++++++++++++++++++++++++++++--- integration/helpers/pepr.test.ts | 4 ++-- 3 files changed, 36 insertions(+), 6 deletions(-) diff --git a/integration/.gitignore b/integration/.gitignore index 4f574e404..9943f1187 100644 --- a/integration/.gitignore +++ b/integration/.gitignore @@ -1 +1 @@ -workroot/ +testroot/ diff --git a/integration/cli/init.test.ts b/integration/cli/init.test.ts index 529cd77d3..a662d2f21 100644 --- a/integration/cli/init.test.ts +++ b/integration/cli/init.test.ts @@ -3,6 +3,7 @@ import { beforeAll, describe, expect, it } from "@jest/globals"; import * as path from "node:path"; +import * as fs from "node:fs/promises"; import { Workdir } from "../helpers/workdir"; import * as time from "../helpers/time"; import * as pepr from "../helpers/pepr"; @@ -11,7 +12,7 @@ const FILE = path.basename(__filename); const HERE = __dirname; describe("init", () => { - const workdir = new Workdir(`${FILE}`, `${HERE}/../workroot/cli`); + const workdir = new Workdir(`${FILE}`, `${HERE}/../testroot/cli`); beforeAll(async () => { await workdir.recreate(); @@ -19,13 +20,42 @@ describe("init", () => { }); it( - "init --help", + "gives command line help", async () => { - const res = await pepr.cli(workdir.path(), { cmd: "pepr init --help" }); + const argz = "--help"; + const res = await pepr.cli(workdir.path(), { cmd: `pepr init ${argz}` }); expect(res.exitcode).toBe(0); expect(res.stderr.join("").trim()).toBe(""); expect(res.stdout.at(0)).toMatch("Usage: pepr init"); }, time.toMs("2m"), ); + + it( + "creates new module using input args", + async () => { + const name = "flags-name"; + const desc = "flags-desc"; + const errb = "reject"; + const argz = [ + `--name ${name}`, + `--description ${desc}`, + `--errorBehavior ${errb}`, + "--confirm", + "--skip-post-init", + ].join(" "); + const res = await pepr.cli(workdir.path(), { cmd: `pepr init ${argz}` }); + expect(res.exitcode).toBe(0); + expect(res.stderr.join("").trim()).toBe(""); + expect(res.stdout.join("").trim()).toContain("New Pepr module created"); + + const packageJson = JSON.parse( + await fs.readFile(`${workdir.path()}/${name}/package.json`, { encoding: "utf8" }), + ); + expect(packageJson.name).toBe(name); + expect(packageJson.description).toBe(desc); + expect(packageJson.pepr.onError).toBe(errb); + }, + time.toMs("2m"), + ); }); diff --git a/integration/helpers/pepr.test.ts b/integration/helpers/pepr.test.ts index 3cc811594..b4d1f2a06 100644 --- a/integration/helpers/pepr.test.ts +++ b/integration/helpers/pepr.test.ts @@ -21,7 +21,7 @@ describe("pepr", () => { }); describe("prepWorkdir", () => { - const workdir = new Workdir(`${FILE}-prepWorkdir`, `${HERE}/../workroot/helpers`); + const workdir = new Workdir(`${FILE}-prepWorkdir`, `${HERE}/../testroot/helpers`); beforeAll(async () => await workdir.recreate()); @@ -35,7 +35,7 @@ describe("pepr", () => { }); describe("cli", () => { - const workdir = new Workdir(`${FILE}-cli`, `${HERE}/../workroot/helpers`); + const workdir = new Workdir(`${FILE}-cli`, `${HERE}/../testroot/helpers`); beforeAll(async () => { await workdir.recreate(); From cb674cbf8131bd585f602c9bdc7f356873718fe6 Mon Sep 17 00:00:00 2001 From: Barrett LaFrance Date: Fri, 10 Jan 2025 15:23:51 -0600 Subject: [PATCH 09/51] wip: somethings changing root package.json, ugh, so I'm changing approach --- integration/cli/build.test.ts | 74 ++++++++++++++++++++++++++++++++ integration/helpers/pepr.test.ts | 43 ++++++++++++++++++- integration/helpers/pepr.ts | 38 +++++++++++++++- 3 files changed, 152 insertions(+), 3 deletions(-) create mode 100644 integration/cli/build.test.ts diff --git a/integration/cli/build.test.ts b/integration/cli/build.test.ts new file mode 100644 index 000000000..f9b70a552 --- /dev/null +++ b/integration/cli/build.test.ts @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2023-Present The Pepr Authors + +import { beforeAll, beforeEach, describe, expect, it } from "@jest/globals"; +import * as path from "node:path"; +import * as fs from "node:fs/promises"; +import { Workdir } from "../helpers/workdir"; +import * as time from "../helpers/time"; +import * as pepr from "../helpers/pepr"; + +const FILE = path.basename(__filename); +const HERE = __dirname; + +describe("build", () => { + const workdir = new Workdir(`${FILE}`, `${HERE}/../testroot/cli`); + + beforeAll(async () => { + await workdir.recreate(); + await pepr.prepWorkdir(workdir.path()); + }); + + it( + "gives command line help", + async () => { + const argz = "--help"; + const res = await pepr.cli(workdir.path(), { cmd: `pepr build ${argz}` }); + expect(res.exitcode).toBe(0); + expect(res.stderr.join("").trim()).toBe(""); + expect(res.stdout.at(0)).toMatch("Usage: pepr build"); + }, + time.toMs("2m"), + ); + + describe("builds a module successfully", () => { + const NAME = "module"; + const moduleDir = `${workdir.path()}/${NAME}`; + + beforeEach(async () => { + await fs.rm(moduleDir, { recursive: true, force: true }); + const argz = [ + `--name ${NAME}`, + `--description description`, + `--errorBehavior reject`, + "--confirm", + "--skip-post-init", + ].join(" "); + await pepr.cli(workdir.path(), { cmd: `pepr init ${argz}` }); + await pepr.tgzifyModule(moduleDir); + await pepr.cli(moduleDir, { cmd: `npm install` }); + }, time.toMs("2m")); + + it( + "using default options", + async () => { + const build = await pepr.cli(moduleDir, { cmd: `pepr build` }); + expect(build.exitcode).toBe(0); + expect(build.stderr.join("").trim()).toBe(""); + expect(build.stdout.join("").trim()).toContain("K8s resource for the module saved"); + }, + time.toMs("2m"), + ); + + // it( + // "using build-time override options", + // async () => { + // const build = await pepr.cli(moduleDir, { cmd: `pepr build` }); + // expect(build.exitcode).toBe(0); + // expect(build.stderr.join("").trim()).toBe(""); + // expect(build.stdout.join("").trim()).toContain("K8s resource for the module saved"); + // }, + // time.toMs("2m"), + // ); + }); +}); diff --git a/integration/helpers/pepr.test.ts b/integration/helpers/pepr.test.ts index b4d1f2a06..6a2d06367 100644 --- a/integration/helpers/pepr.test.ts +++ b/integration/helpers/pepr.test.ts @@ -34,6 +34,32 @@ describe("pepr", () => { }); }); + describe("tgzifyModule", () => { + const workdir = new Workdir(`${FILE}-tgzifyModule`, `${HERE}/../testroot/helpers`); + + beforeAll(async () => await workdir.recreate()); + + it("converts module source to install pepr from a .tgz", async () => { + await sut.prepWorkdir(workdir.path()); + let packageJson = { + dependencies: { + pepr: "0.0.0-development", + }, + }; + const modulePath = `${workdir.path()}/module`; + const packagePath = `${modulePath}/package.json`; + await fs.mkdir(modulePath, { recursive: true }); + await fs.writeFile(packagePath, JSON.stringify(packageJson, null, 2)); + + await sut.tgzifyModule(modulePath); + + packageJson = JSON.parse(await fs.readFile(packagePath, { encoding: "utf8" })); + expect(packageJson.dependencies.pepr).toBe( + `file://${modulePath}/../pepr-0.0.0-development.tgz`, + ); + }); + }); + describe("cli", () => { const workdir = new Workdir(`${FILE}-cli`, `${HERE}/../testroot/helpers`); @@ -43,7 +69,7 @@ describe("pepr", () => { }); it( - "invokes pepr command via .tgz", + "can invoke pepr command via .tgz in current dir", async () => { const res = await sut.cli(workdir.path(), { cmd: "pepr --version" }); expect(res.exitcode).toBe(0); @@ -52,5 +78,20 @@ describe("pepr", () => { }, time.toMs("2m"), ); + + it( + "can invoke pepr command via .tgz in parent dir", + async () => { + const modulePath = `${workdir.path()}/module`; + await fs.mkdir(modulePath, { recursive: true }); + + const res = await sut.cli(modulePath, { cmd: "pepr --version" }); + + expect(res.exitcode).toBe(0); + expect(res.stderr.join("").trim()).toBe(""); + expect(res.stdout.join("").trim()).toBe("0.0.0-development"); + }, + time.toMs("2m"), + ); }); }); diff --git a/integration/helpers/pepr.ts b/integration/helpers/pepr.ts index bc42825d0..451897226 100644 --- a/integration/helpers/pepr.ts +++ b/integration/helpers/pepr.ts @@ -1,5 +1,5 @@ import { resolve, join } from "node:path"; -import { copyFile } from "node:fs/promises"; +import { access, copyFile, readFile, writeFile } from "node:fs/promises"; import { Spec, Cmd, Result } from "./cmd"; import { clone } from "ramda"; @@ -20,15 +20,49 @@ export async function prepWorkdir(workdir: string): Promise { await copyFile(src, dst); } +export async function tgzifyModule(modulePath: string): Promise { + const packagePath = `${modulePath}/package.json`; + const packageJson = JSON.parse(await readFile(packagePath, { encoding: "utf8" })); + packageJson.dependencies.pepr = `file://${modulePath}/../pepr-0.0.0-development.tgz`; + await writeFile(packagePath, JSON.stringify(packageJson, null, 2)); +} + export async function cli(workdir: string, spec: Spec): Promise { const tgz = "pepr-0.0.0-development.tgz"; const _spec = clone(spec); _spec.cwd = workdir; - const _cmd = _spec.cmd.trim().replace(/^pepr /, `npx --yes file://./${tgz} `); + let tgzRef = ""; + + // if .tgz exists in workdir, use that (e.g. when `pepr init`-ing) + try { + await access(`${workdir}/${tgz}`); + tgzRef = `file://${workdir}/${tgz}`; + } catch { + /* do nothing */ + } + + // if .tgz exists one level above workdir, use that (e.g. when `pepr build`-ing) + try { + await access(`${workdir}/../${tgz}`); + tgzRef = `file://${workdir}/../${tgz}`; + } catch { + /* do nothing */ + } + + // else bomb out + if (tgzRef === "") { + throw "can't find pepr .tgz"; + } + + const _cmd = _spec.cmd.trim().replace(/^pepr /, `npx --yes ${tgzRef} `); _spec.cmd = _cmd; + // install .tgz before calling so stdout doesn't spew install text on first run + const inst = new Cmd({ ..._spec, cmd: `npm install ${tgzRef}` }); + await inst.run(); + const cmd = new Cmd(_spec); return await cmd.runRaw(); } From d573a8563fc0731b3d18adf538390ed5c6b02f40 Mon Sep 17 00:00:00 2001 From: Barrett LaFrance Date: Fri, 10 Jan 2025 17:29:46 -0600 Subject: [PATCH 10/51] wip: new approach (with NPM_CONFIG_CACHE) working much better --- integration/.gitignore | 1 + integration/cli/build.test.ts | 1 - integration/cli/init.test.ts | 1 - integration/helpers/pepr.test.ts | 44 ++++------------------------ integration/helpers/pepr.ts | 49 ++++++-------------------------- integration/prep.sh | 10 +++++++ package.json | 2 +- 7 files changed, 27 insertions(+), 81 deletions(-) create mode 100755 integration/prep.sh diff --git a/integration/.gitignore b/integration/.gitignore index 9943f1187..66dd4c91a 100644 --- a/integration/.gitignore +++ b/integration/.gitignore @@ -1 +1,2 @@ testroot/ +.npm/ \ No newline at end of file diff --git a/integration/cli/build.test.ts b/integration/cli/build.test.ts index f9b70a552..c3f63d14a 100644 --- a/integration/cli/build.test.ts +++ b/integration/cli/build.test.ts @@ -16,7 +16,6 @@ describe("build", () => { beforeAll(async () => { await workdir.recreate(); - await pepr.prepWorkdir(workdir.path()); }); it( diff --git a/integration/cli/init.test.ts b/integration/cli/init.test.ts index a662d2f21..bff0491dd 100644 --- a/integration/cli/init.test.ts +++ b/integration/cli/init.test.ts @@ -16,7 +16,6 @@ describe("init", () => { beforeAll(async () => { await workdir.recreate(); - await pepr.prepWorkdir(workdir.path()); }); it( diff --git a/integration/helpers/pepr.test.ts b/integration/helpers/pepr.test.ts index 6a2d06367..901165d35 100644 --- a/integration/helpers/pepr.test.ts +++ b/integration/helpers/pepr.test.ts @@ -20,43 +20,27 @@ describe("pepr", () => { }); }); - describe("prepWorkdir", () => { - const workdir = new Workdir(`${FILE}-prepWorkdir`, `${HERE}/../testroot/helpers`); - - beforeAll(async () => await workdir.recreate()); - - it("builds pepr package and drops .tgz into given directory", async () => { - await sut.prepWorkdir(workdir.path()); - const files = await fs.readdir(workdir.path()); - - expect(files).toHaveLength(1); - expect(files).toContain("pepr-0.0.0-development.tgz"); - }); - }); - describe("tgzifyModule", () => { const workdir = new Workdir(`${FILE}-tgzifyModule`, `${HERE}/../testroot/helpers`); beforeAll(async () => await workdir.recreate()); - it("converts module source to install pepr from a .tgz", async () => { - await sut.prepWorkdir(workdir.path()); + it("converts module source to install pepr from .tgz", async () => { + const modulePath = `${workdir.path()}/module`; + const packagePath = `${modulePath}/package.json`; let packageJson = { dependencies: { pepr: "0.0.0-development", }, }; - const modulePath = `${workdir.path()}/module`; - const packagePath = `${modulePath}/package.json`; await fs.mkdir(modulePath, { recursive: true }); await fs.writeFile(packagePath, JSON.stringify(packageJson, null, 2)); await sut.tgzifyModule(modulePath); packageJson = JSON.parse(await fs.readFile(packagePath, { encoding: "utf8" })); - expect(packageJson.dependencies.pepr).toBe( - `file://${modulePath}/../pepr-0.0.0-development.tgz`, - ); + const root = await sut.projectRoot(); + expect(packageJson.dependencies.pepr).toBe(`file://${root}/pepr-0.0.0-development.tgz`); }); }); @@ -65,11 +49,10 @@ describe("pepr", () => { beforeAll(async () => { await workdir.recreate(); - await sut.prepWorkdir(workdir.path()); }); it( - "can invoke pepr command via .tgz in current dir", + "can invoke pepr command via .tgz", async () => { const res = await sut.cli(workdir.path(), { cmd: "pepr --version" }); expect(res.exitcode).toBe(0); @@ -78,20 +61,5 @@ describe("pepr", () => { }, time.toMs("2m"), ); - - it( - "can invoke pepr command via .tgz in parent dir", - async () => { - const modulePath = `${workdir.path()}/module`; - await fs.mkdir(modulePath, { recursive: true }); - - const res = await sut.cli(modulePath, { cmd: "pepr --version" }); - - expect(res.exitcode).toBe(0); - expect(res.stderr.join("").trim()).toBe(""); - expect(res.stdout.join("").trim()).toBe("0.0.0-development"); - }, - time.toMs("2m"), - ); }); }); diff --git a/integration/helpers/pepr.ts b/integration/helpers/pepr.ts index 451897226..3d57b3acc 100644 --- a/integration/helpers/pepr.ts +++ b/integration/helpers/pepr.ts @@ -1,5 +1,5 @@ -import { resolve, join } from "node:path"; -import { access, copyFile, readFile, writeFile } from "node:fs/promises"; +import { resolve } from "node:path"; +import { readFile, writeFile } from "node:fs/promises"; import { Spec, Cmd, Result } from "./cmd"; import { clone } from "ramda"; @@ -12,56 +12,25 @@ export async function projectRoot(): Promise { return resolve(npmroot, ".."); } -export async function prepWorkdir(workdir: string): Promise { - const rootdir = await projectRoot(); - const tgz = "pepr-0.0.0-development.tgz"; - const src = join(rootdir, tgz); - const dst = join(workdir, tgz); - await copyFile(src, dst); -} - export async function tgzifyModule(modulePath: string): Promise { const packagePath = `${modulePath}/package.json`; const packageJson = JSON.parse(await readFile(packagePath, { encoding: "utf8" })); - packageJson.dependencies.pepr = `file://${modulePath}/../pepr-0.0.0-development.tgz`; + + const root = await projectRoot(); + packageJson.dependencies.pepr = `file://${root}/pepr-0.0.0-development.tgz`; await writeFile(packagePath, JSON.stringify(packageJson, null, 2)); } export async function cli(workdir: string, spec: Spec): Promise { - const tgz = "pepr-0.0.0-development.tgz"; + const root = await projectRoot(); + const tgz = `file://${root}/pepr-0.0.0-development.tgz`; const _spec = clone(spec); _spec.cwd = workdir; - let tgzRef = ""; - - // if .tgz exists in workdir, use that (e.g. when `pepr init`-ing) - try { - await access(`${workdir}/${tgz}`); - tgzRef = `file://${workdir}/${tgz}`; - } catch { - /* do nothing */ - } - - // if .tgz exists one level above workdir, use that (e.g. when `pepr build`-ing) - try { - await access(`${workdir}/../${tgz}`); - tgzRef = `file://${workdir}/../${tgz}`; - } catch { - /* do nothing */ - } - - // else bomb out - if (tgzRef === "") { - throw "can't find pepr .tgz"; - } - - const _cmd = _spec.cmd.trim().replace(/^pepr /, `npx --yes ${tgzRef} `); + const _cmd = _spec.cmd.trim().replace(/^pepr /, `npx --yes ${tgz} `); _spec.cmd = _cmd; - - // install .tgz before calling so stdout doesn't spew install text on first run - const inst = new Cmd({ ..._spec, cmd: `npm install ${tgzRef}` }); - await inst.run(); + _spec.env = { ..._spec.env, NPM_CONFIG_CACHE: `${root}/integration/testroot/.npm` }; const cmd = new Cmd(_spec); return await cmd.runRaw(); diff --git a/integration/prep.sh b/integration/prep.sh new file mode 100755 index 000000000..8de83daa6 --- /dev/null +++ b/integration/prep.sh @@ -0,0 +1,10 @@ +#!/bin/sh +ME="$(readlink -f "$0")" +HERE="$(dirname "$ME")" +ROOT="$(dirname "$HERE")" + +export NPM_CONFIG_CACHE="${HERE}/testroot/.npm" +mkdir --parents "$NPM_CONFIG_CACHE" + +npm run build +npx --yes file://${ROOT}/pepr-0.0.0-development.tgz \ No newline at end of file diff --git a/package.json b/package.json index 08107e3a2..86c3e12f8 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "test": "npm run test:unit && npm run test:journey", "test:unit": "npm run gen-data-json && jest src --coverage --detectOpenHandles --coverageDirectory=./coverage --testPathIgnorePatterns='cosign.e2e.test.ts'", "test:int": "npm run test:int:prep && npm run test:int:run", - "test:int:prep": "npm run build && npx --yes file://./pepr-0.0.0-development.tgz", + "test:int:prep": "./integration/prep.sh", "test:int:run": "jest integration", "test:journey": "npm run test:journey:k3d && npm run build && npm run test:journey:image && npm run test:journey:run", "test:journey:prep": "if [ ! -d ./pepr-upgrade-test ]; then git clone https://github.com/defenseunicorns/pepr-upgrade-test.git ; fi", From 191fe0a39417c0ebe4924e16241aa163fa69e585 Mon Sep 17 00:00:00 2001 From: Barrett LaFrance Date: Fri, 10 Jan 2025 23:56:09 -0600 Subject: [PATCH 11/51] wip: saving proress --- .eslintrc.json | 3 +- integration/cli/build.test.ts | 131 ++++++++++++++++++++++++++----- integration/helpers/pepr.test.ts | 24 ++++++ integration/helpers/pepr.ts | 15 +++- 4 files changed, 150 insertions(+), 23 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index 04da5c9c5..9034f067b 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -30,7 +30,8 @@ "pepr-test-module", "build.mjs", "journey", - "__mocks__" + "__mocks__", + "integration/testroot" ], "root": true } diff --git a/integration/cli/build.test.ts b/integration/cli/build.test.ts index c3f63d14a..060b8e4c4 100644 --- a/integration/cli/build.test.ts +++ b/integration/cli/build.test.ts @@ -1,16 +1,65 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-FileCopyrightText: 2023-Present The Pepr Authors -import { beforeAll, beforeEach, describe, expect, it } from "@jest/globals"; +import { beforeAll, describe, expect, it } from "@jest/globals"; import * as path from "node:path"; import * as fs from "node:fs/promises"; import { Workdir } from "../helpers/workdir"; import * as time from "../helpers/time"; import * as pepr from "../helpers/pepr"; +import yaml from "yaml"; const FILE = path.basename(__filename); const HERE = __dirname; +/* eslint-disable-next-line @typescript-eslint/no-explicit-any */ +async function oneFromFile(path: string): Promise { + const ext = path.split(".").at(-1); + + let ret: object; + switch (ext) { + case "json": { + const all = JSON.parse(await fs.readFile(path, { encoding: "utf8" })); + ret = Array.isArray(all) ? all.at(0) : all; + break; + } + + case "yaml": + ret = yaml.parseDocument(await fs.readFile(path, { encoding: "utf8" })).contents!.toJSON(); + break; + + default: + throw `oops: don't recognize file of type ".${ext}"`; + } + + return ret; +} + +/* eslint-disable-next-line @typescript-eslint/no-explicit-any */ +async function manyFromFile(path: string): Promise { + const ext = path.split(".").at(-1); + + let ret: object[]; + switch (ext) { + case "json": { + const all = JSON.parse(await fs.readFile(path, { encoding: "utf8" })); + ret = Array.isArray(all) ? all : [all]; + break; + } + + case "yaml": + ret = yaml + .parseAllDocuments(await fs.readFile(path, { encoding: "utf8" })) + .map(m => m.contents!.toJSON()); + break; + + default: + throw `oops: don't recognize file of type ".${ext}"`; + } + + return ret; +} + describe("build", () => { const workdir = new Workdir(`${FILE}`, `${HERE}/../testroot/cli`); @@ -31,43 +80,83 @@ describe("build", () => { ); describe("builds a module successfully", () => { - const NAME = "module"; - const moduleDir = `${workdir.path()}/${NAME}`; + const moduleSrc = `${workdir.path()}/module`; - beforeEach(async () => { - await fs.rm(moduleDir, { recursive: true, force: true }); + beforeAll(async () => { + await fs.rm(moduleSrc, { recursive: true, force: true }); const argz = [ - `--name ${NAME}`, + `--name module`, `--description description`, `--errorBehavior reject`, "--confirm", "--skip-post-init", ].join(" "); await pepr.cli(workdir.path(), { cmd: `pepr init ${argz}` }); - await pepr.tgzifyModule(moduleDir); - await pepr.cli(moduleDir, { cmd: `npm install` }); + await pepr.tgzifyModule(moduleSrc); }, time.toMs("2m")); it( - "using default options", + "using default build options", async () => { - const build = await pepr.cli(moduleDir, { cmd: `pepr build` }); + const moduleDst = `${workdir.path()}/defaults`; + await pepr.copyModule(moduleSrc, moduleDst); + await pepr.cli(moduleDst, { cmd: `npm install` }); + + const build = await pepr.cli(moduleDst, { cmd: `pepr build` }); expect(build.exitcode).toBe(0); expect(build.stderr.join("").trim()).toBe(""); expect(build.stdout.join("").trim()).toContain("K8s resource for the module saved"); }, - time.toMs("2m"), + time.toMs("1m"), ); - // it( - // "using build-time override options", - // async () => { - // const build = await pepr.cli(moduleDir, { cmd: `pepr build` }); - // expect(build.exitcode).toBe(0); - // expect(build.stderr.join("").trim()).toBe(""); - // expect(build.stdout.join("").trim()).toContain("K8s resource for the module saved"); - // }, - // time.toMs("2m"), - // ); + it( + "using build override options", + async () => { + const moduleDst = `${workdir.path()}/overrides`; + await pepr.copyModule(moduleSrc, moduleDst); + await pepr.cli(moduleDst, { cmd: `npm install` }); + + const entrypoint = "pepr2.ts"; + await fs.rename(`${moduleDst}/pepr.ts`, `${moduleDst}/${entrypoint}`); + + const argz = [`--entry-point ${entrypoint}`, `--custom-image pepr:overrides`].join(" "); + const build = await pepr.cli(moduleDst, { cmd: `pepr build ${argz}` }); + expect(build.exitcode).toBe(0); + expect(build.stderr.join("").trim()).toBe(""); + expect(build.stdout.join("").trim()).toContain("K8s resource for the module saved"); + + const packageJson = JSON.parse( + await fs.readFile(`${moduleDst}/package.json`, { encoding: "utf8" }), + ); + + // --entrypoint (will fail build if given --entrypoint doesn't exist) + // --custom-image + const moduleYaml = `${moduleDst}/dist/pepr-module-${packageJson.pepr.uuid}.yaml`; + console.log(moduleYaml); + + // const zarfYaml = `${moduleDst}/dist/zarf.yaml`; + // const valuesYaml = `${moduleDst}/dist/${packageJson.pepr.uuid}-chart/values.yaml`; + }, + time.toMs("1m"), + ); }); }); + +it.only("does", async () => { + const moduleDst = `/home/barrett/workspace/defuni/pepr/integration/testroot/cli/build.test.ts/overrides`; + + const packageJson = await oneFromFile(`${moduleDst}/package.json`); + const zarfYaml = await manyFromFile(`${moduleDst}/dist/zarf.yaml`); + const moduleYaml = await manyFromFile( + `${moduleDst}/dist/pepr-module-${packageJson.pepr.uuid}.yaml`, + ); + const valuesYaml = await manyFromFile( + `${moduleDst}/dist/${packageJson.pepr.uuid}-chart/values.yaml`, + ); + + console.log(packageJson); + console.log(zarfYaml); + console.log(moduleYaml); + console.log(valuesYaml); +}); diff --git a/integration/helpers/pepr.test.ts b/integration/helpers/pepr.test.ts index 901165d35..81a8c58ec 100644 --- a/integration/helpers/pepr.test.ts +++ b/integration/helpers/pepr.test.ts @@ -44,6 +44,30 @@ describe("pepr", () => { }); }); + describe("copyModule", () => { + const workdir = new Workdir(`${FILE}-copyModule`, `${HERE}/../testroot/helpers`); + + beforeAll(async () => await workdir.recreate()); + + it("copies & configs pepr module", async () => { + const srcPath = `${workdir.path()}/src`; + const dstPath = `${workdir.path()}/dst`; + + const packageSrc = `${srcPath}/package.json`; + let packageJson = { + name: "src", + }; + await fs.mkdir(srcPath, { recursive: true }); + await fs.writeFile(packageSrc, JSON.stringify(packageJson, null, 2)); + + await sut.copyModule(srcPath, dstPath); + + const packageDst = `${dstPath}/package.json`; + packageJson = JSON.parse(await fs.readFile(packageDst, { encoding: "utf8" })); + expect(packageJson.name).toBe("dst"); + }); + }); + describe("cli", () => { const workdir = new Workdir(`${FILE}-cli`, `${HERE}/../testroot/helpers`); diff --git a/integration/helpers/pepr.ts b/integration/helpers/pepr.ts index 3d57b3acc..3d27dc56c 100644 --- a/integration/helpers/pepr.ts +++ b/integration/helpers/pepr.ts @@ -1,5 +1,6 @@ import { resolve } from "node:path"; -import { readFile, writeFile } from "node:fs/promises"; +import { cp, readFile, writeFile } from "node:fs/promises"; +import { basename } from "node:path"; import { Spec, Cmd, Result } from "./cmd"; import { clone } from "ramda"; @@ -21,6 +22,18 @@ export async function tgzifyModule(modulePath: string): Promise { await writeFile(packagePath, JSON.stringify(packageJson, null, 2)); } +export async function copyModule(src: string, dst: string): Promise { + await cp(src, dst, { recursive: true }); + + // jest fails to run if given a file hierarchy that includes more than one + // module with the same name -- this copies-then-rename is to avoid that + const packagePath = `${dst}/package.json`; + const packageJson = JSON.parse(await readFile(packagePath, { encoding: "utf8" })); + packageJson.name = basename(dst); + + await writeFile(packagePath, JSON.stringify(packageJson, null, 2)); +} + export async function cli(workdir: string, spec: Spec): Promise { const root = await projectRoot(); const tgz = `file://${root}/pepr-0.0.0-development.tgz`; From 8c9ca067a98b4e8720ba8eb48355b9670e8c21a4 Mon Sep 17 00:00:00 2001 From: Barrett LaFrance Date: Sat, 11 Jan 2025 11:03:46 -0600 Subject: [PATCH 12/51] wip: saving proress --- integration/cli/build.test.ts | 50 +++++++++++++++++++++++++---------- 1 file changed, 36 insertions(+), 14 deletions(-) diff --git a/integration/cli/build.test.ts b/integration/cli/build.test.ts index 060b8e4c4..d79265e4e 100644 --- a/integration/cli/build.test.ts +++ b/integration/cli/build.test.ts @@ -8,6 +8,7 @@ import { Workdir } from "../helpers/workdir"; import * as time from "../helpers/time"; import * as pepr from "../helpers/pepr"; import yaml from "yaml"; +import { kind } from "kubernetes-fluent-client"; const FILE = path.basename(__filename); const HERE = __dirname; @@ -117,10 +118,11 @@ describe("build", () => { await pepr.copyModule(moduleSrc, moduleDst); await pepr.cli(moduleDst, { cmd: `npm install` }); - const entrypoint = "pepr2.ts"; - await fs.rename(`${moduleDst}/pepr.ts`, `${moduleDst}/${entrypoint}`); + const entryPoint = "pepr2.ts"; + await fs.rename(`${moduleDst}/pepr.ts`, `${moduleDst}/${entryPoint}`); + const customImage = "pepr:overrides"; - const argz = [`--entry-point ${entrypoint}`, `--custom-image pepr:overrides`].join(" "); + const argz = [`--entry-point ${entryPoint}`, `--custom-image ${customImage}"`].join(" "); const build = await pepr.cli(moduleDst, { cmd: `pepr build ${argz}` }); expect(build.exitcode).toBe(0); expect(build.stderr.join("").trim()).toBe(""); @@ -145,18 +147,38 @@ describe("build", () => { it.only("does", async () => { const moduleDst = `/home/barrett/workspace/defuni/pepr/integration/testroot/cli/build.test.ts/overrides`; + const customImage = "pepr:overrides"; const packageJson = await oneFromFile(`${moduleDst}/package.json`); - const zarfYaml = await manyFromFile(`${moduleDst}/dist/zarf.yaml`); - const moduleYaml = await manyFromFile( - `${moduleDst}/dist/pepr-module-${packageJson.pepr.uuid}.yaml`, - ); - const valuesYaml = await manyFromFile( - `${moduleDst}/dist/${packageJson.pepr.uuid}-chart/values.yaml`, - ); + const uuid = packageJson.pepr.uuid; + + const moduleYaml = await manyFromFile(`${moduleDst}/dist/pepr-module-${uuid}.yaml`); + { + const admissionController = moduleYaml + .filter(f => f.kind === "Deployment") + .filter(f => f.metadata.name === `pepr-${uuid}`) + .at(0) as kind.Deployment; + const admissionImage = admissionController! + .spec!.template!.spec!.containers.filter(f => f.name === "server") + .at(0)!.image; + expect(admissionImage).toBe(customImage); + + const watchController = moduleYaml + .filter(f => f.kind === "Deployment") + .filter(f => f.metadata.name === `pepr-${uuid}-watcher`) + .at(0) as kind.Deployment; + const watchImage = watchController! + .spec!.template!.spec!.containers.filter(f => f.name === "watcher") + .at(0)!.image; + expect(watchImage).toBe(customImage); + } + + // const zarfYaml = await manyFromFile(`${moduleDst}/dist/zarf.yaml`); + // const valuesYaml = await manyFromFile( + // `${moduleDst}/dist/${packageJson.pepr.uuid}-chart/values.yaml`, + // ); - console.log(packageJson); - console.log(zarfYaml); - console.log(moduleYaml); - console.log(valuesYaml); + // console.log(packageJson); + // console.log(zarfYaml); + // console.log(valuesYaml); }); From ddebf486499e967960b7391028192682f6d7ac76 Mon Sep 17 00:00:00 2001 From: Barrett LaFrance Date: Sat, 11 Jan 2025 14:48:41 -0600 Subject: [PATCH 13/51] wip: saving progress --- integration/cli/build.test.ts | 66 ++------------ integration/helpers/resource.test.ts | 126 +++++++++++++++++++++++++++ integration/helpers/resource.ts | 86 ++++++++++++++++++ 3 files changed, 218 insertions(+), 60 deletions(-) create mode 100644 integration/helpers/resource.test.ts create mode 100644 integration/helpers/resource.ts diff --git a/integration/cli/build.test.ts b/integration/cli/build.test.ts index d79265e4e..72df09fc4 100644 --- a/integration/cli/build.test.ts +++ b/integration/cli/build.test.ts @@ -4,63 +4,15 @@ import { beforeAll, describe, expect, it } from "@jest/globals"; import * as path from "node:path"; import * as fs from "node:fs/promises"; +import { kind } from "kubernetes-fluent-client"; import { Workdir } from "../helpers/workdir"; import * as time from "../helpers/time"; import * as pepr from "../helpers/pepr"; -import yaml from "yaml"; -import { kind } from "kubernetes-fluent-client"; +import * as resource from "../helpers/resource"; const FILE = path.basename(__filename); const HERE = __dirname; -/* eslint-disable-next-line @typescript-eslint/no-explicit-any */ -async function oneFromFile(path: string): Promise { - const ext = path.split(".").at(-1); - - let ret: object; - switch (ext) { - case "json": { - const all = JSON.parse(await fs.readFile(path, { encoding: "utf8" })); - ret = Array.isArray(all) ? all.at(0) : all; - break; - } - - case "yaml": - ret = yaml.parseDocument(await fs.readFile(path, { encoding: "utf8" })).contents!.toJSON(); - break; - - default: - throw `oops: don't recognize file of type ".${ext}"`; - } - - return ret; -} - -/* eslint-disable-next-line @typescript-eslint/no-explicit-any */ -async function manyFromFile(path: string): Promise { - const ext = path.split(".").at(-1); - - let ret: object[]; - switch (ext) { - case "json": { - const all = JSON.parse(await fs.readFile(path, { encoding: "utf8" })); - ret = Array.isArray(all) ? all : [all]; - break; - } - - case "yaml": - ret = yaml - .parseAllDocuments(await fs.readFile(path, { encoding: "utf8" })) - .map(m => m.contents!.toJSON()); - break; - - default: - throw `oops: don't recognize file of type ".${ext}"`; - } - - return ret; -} - describe("build", () => { const workdir = new Workdir(`${FILE}`, `${HERE}/../testroot/cli`); @@ -149,24 +101,18 @@ it.only("does", async () => { const moduleDst = `/home/barrett/workspace/defuni/pepr/integration/testroot/cli/build.test.ts/overrides`; const customImage = "pepr:overrides"; - const packageJson = await oneFromFile(`${moduleDst}/package.json`); + const packageJson = await resource.oneFromFile(`${moduleDst}/package.json`); const uuid = packageJson.pepr.uuid; - const moduleYaml = await manyFromFile(`${moduleDst}/dist/pepr-module-${uuid}.yaml`); + const moduleYaml = await resource.manyFromFile(`${moduleDst}/dist/pepr-module-${uuid}.yaml`); { - const admissionController = moduleYaml - .filter(f => f.kind === "Deployment") - .filter(f => f.metadata.name === `pepr-${uuid}`) - .at(0) as kind.Deployment; + const admissionController = resource.select(moduleYaml, kind.Deployment, `pepr-${uuid}`); const admissionImage = admissionController! .spec!.template!.spec!.containers.filter(f => f.name === "server") .at(0)!.image; expect(admissionImage).toBe(customImage); - const watchController = moduleYaml - .filter(f => f.kind === "Deployment") - .filter(f => f.metadata.name === `pepr-${uuid}-watcher`) - .at(0) as kind.Deployment; + const watchController = resource.select(moduleYaml, kind.Deployment, `pepr-${uuid}-watcher`); const watchImage = watchController! .spec!.template!.spec!.containers.filter(f => f.name === "watcher") .at(0)!.image; diff --git a/integration/helpers/resource.test.ts b/integration/helpers/resource.test.ts new file mode 100644 index 000000000..a7b100b95 --- /dev/null +++ b/integration/helpers/resource.test.ts @@ -0,0 +1,126 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2023-Present The Pepr Authors + +import { beforeAll, describe, expect, it } from "@jest/globals"; +import * as path from "node:path"; +import * as fs from "node:fs/promises"; +import { Workdir } from "../helpers/workdir"; +import { heredoc } from "../../src/sdk/heredoc"; +import * as sut from "./resource"; +import { kind } from "kubernetes-fluent-client"; + +const FILE = path.basename(__filename); +const HERE = __dirname; +const workdir = new Workdir(`${FILE}`, `${HERE}/../testroot/helpers`); + +beforeAll(async () => { + await workdir.recreate(); +}); + +describe("oneFromFile", () => { + it("can load one resource from .json file", async () => { + const oneJson = `${workdir.path()}/one.json`; + await fs.writeFile( + oneJson, + heredoc` + { + "one": "json" + } + `, + ); + const res = await sut.oneFromFile(oneJson); + expect(res.one).toBe("json"); + }); + + it("can load one resource from .yaml file", async () => { + const oneYaml = `${workdir.path()}/one.yaml`; + await fs.writeFile( + oneYaml, + heredoc` + --- + one: yaml + `, + ); + const res = await sut.oneFromFile(oneYaml); + expect(res.one).toBe("yaml"); + }); +}); + +describe("manyFromFile", () => { + it("can load many resources from .json file", async () => { + const manyJson = `${workdir.path()}/many.json`; + await fs.writeFile( + manyJson, + heredoc` + [ + { + "one": "json" + }, + { + "two": "json" + }, + { + "three": "json" + } + ] + `, + ); + const res = await sut.manyFromFile(manyJson); + expect(res.at(0).one).toBe("json"); + expect(res.at(1).two).toBe("json"); + expect(res.at(2).three).toBe("json"); + }); + + it("can load many resources from .yaml file", async () => { + const manyYaml = `${workdir.path()}/many.yaml`; + await fs.writeFile( + manyYaml, + heredoc` + --- + one: yaml + --- + two: yaml + --- + three: yaml + `, + ); + const res = await sut.manyFromFile(manyYaml); + expect(res.at(0).one).toBe("yaml"); + expect(res.at(1).two).toBe("yaml"); + expect(res.at(2).three).toBe("yaml"); + }); +}); + +describe("select", () => { + it("returns typed resources, selected from list by name", async () => { + const manyYaml = `${workdir.path()}/select.yaml`; + await fs.writeFile( + manyYaml, + heredoc` + --- + apiVersion: v1 + kind: Secret + metadata: + name: sec + namespace: select + stringData: + top: secret + --- + apiVersion: v1 + kind: ConfigMap + metadata: + name: cm + namespace: select + data: + fake: news + `, + ); + const many = await sut.manyFromFile(manyYaml); + + const sec = sut.select(many, kind.Secret, "sec"); + const cm = sut.select(many, kind.ConfigMap, "cm"); + + expect(sec.stringData!.top).toBe("secret"); + expect(cm.data!.fake).toBe("news"); + }); +}); diff --git a/integration/helpers/resource.ts b/integration/helpers/resource.ts new file mode 100644 index 000000000..03acc6b4f --- /dev/null +++ b/integration/helpers/resource.ts @@ -0,0 +1,86 @@ +import { readFile } from "node:fs/promises"; +import { kind, KubernetesObject } from "kubernetes-fluent-client"; +import { parseDocument, parseAllDocuments } from "yaml"; + +/** + * Read one resource from file, rehydrated as a JS object + * + * @param path Path to file holding one JSON (*.json) object / YAML (*.yaml) document + * @returns JS object + */ +/* eslint-disable-next-line @typescript-eslint/no-explicit-any */ +export async function oneFromFile(path: string): Promise { + const ext = path.split(".").at(-1); + + let ret: object; + switch (ext) { + case "json": { + const all = JSON.parse(await readFile(path, { encoding: "utf8" })); + ret = Array.isArray(all) ? all.at(0) : all; + break; + } + + case "yaml": + ret = parseDocument(await readFile(path, { encoding: "utf8" })).contents!.toJSON(); + break; + + default: + throw `oops: don't recognize file of type ".${ext}"`; + } + + return ret; +} + +/** + * Read many resources from file, rehydrated as an array of JS objects + * + * @param path Path to file holding an array of JSON (*.json) objects / multiple concatinated YAML (*.yaml) documents + * @returns Array of JS objects + */ +/* eslint-disable-next-line @typescript-eslint/no-explicit-any */ +export async function manyFromFile(path: string): Promise { + const ext = path.split(".").at(-1); + + let ret: object[]; + switch (ext) { + case "json": { + const all = JSON.parse(await readFile(path, { encoding: "utf8" })); + ret = Array.isArray(all) ? all : [all]; + break; + } + + case "yaml": + ret = parseAllDocuments(await readFile(path, { encoding: "utf8" })).map(m => + m.contents!.toJSON(), + ); + break; + + default: + throw `oops: don't recognize file of type ".${ext}"`; + } + + return ret; +} + +/** + * Select & strongly-type resource from array of JS objects + * + * @param list Array of JS objects + * @param asKind Type of object to select (from kubernetes-fluent-client, e.g. kind.Secret) + * @param name Object.metadata.name to select + * @returns Strong-typed resource object + */ +export function select InstanceType>( + list: T[], + asKind: U, + name: string, +): InstanceType { + const kynd = Object.entries(kind) + .filter(f => f[1] === asKind) + .at(0)! + .at(0); + return list + .filter(f => f.kind === kynd) + .filter(f => f!.metadata!.name === name) + .at(0) as InstanceType; +} From f4ecb210a9cf89be46650c978105da578894e3dc Mon Sep 17 00:00:00 2001 From: Barrett LaFrance Date: Sat, 11 Jan 2025 16:10:54 -0600 Subject: [PATCH 14/51] wip: saving progress --- integration/cli/build.test.ts | 77 +++++++++++++++++------------------ 1 file changed, 37 insertions(+), 40 deletions(-) diff --git a/integration/cli/build.test.ts b/integration/cli/build.test.ts index 72df09fc4..e30c4474b 100644 --- a/integration/cli/build.test.ts +++ b/integration/cli/build.test.ts @@ -74,57 +74,54 @@ describe("build", () => { await fs.rename(`${moduleDst}/pepr.ts`, `${moduleDst}/${entryPoint}`); const customImage = "pepr:overrides"; - const argz = [`--entry-point ${entryPoint}`, `--custom-image ${customImage}"`].join(" "); + const argz = [`--entry-point ${entryPoint}`, `--custom-image ${customImage}`].join(" "); const build = await pepr.cli(moduleDst, { cmd: `pepr build ${argz}` }); + expect(build.exitcode).toBe(0); expect(build.stderr.join("").trim()).toBe(""); expect(build.stdout.join("").trim()).toContain("K8s resource for the module saved"); - const packageJson = JSON.parse( - await fs.readFile(`${moduleDst}/package.json`, { encoding: "utf8" }), - ); + const packageJson = await resource.oneFromFile(`${moduleDst}/package.json`); // --entrypoint (will fail build if given --entrypoint doesn't exist) // --custom-image - const moduleYaml = `${moduleDst}/dist/pepr-module-${packageJson.pepr.uuid}.yaml`; - console.log(moduleYaml); + const uuid = packageJson.pepr.uuid; + const moduleYaml = await resource.manyFromFile( + `${moduleDst}/dist/pepr-module-${uuid}.yaml`, + ); + { + const getDepConImg = (deploy: kind.Deployment, container: string): string => { + return deploy!.spec!.template!.spec!.containers.filter(f => f.name === container).at(0)! + .image!; + }; + + const admission = resource.select(moduleYaml, kind.Deployment, `pepr-${uuid}`); + const admissionImage = getDepConImg(admission, "server"); + expect(admissionImage).toBe(customImage); + + const watcher = resource.select(moduleYaml, kind.Deployment, `pepr-${uuid}-watcher`); + const watcherImage = getDepConImg(watcher, "watcher"); + expect(watcherImage).toBe(customImage); + } + + const zarfYaml = await resource.oneFromFile(`${moduleDst}/dist/zarf.yaml`); + { + const componentImage = zarfYaml.components.at(0).images.at(0); + expect(componentImage).toBe(customImage); + } + + const valuesYaml = await resource.oneFromFile( + `${moduleDst}/dist/${uuid}-chart/values.yaml`, + ); + { + const admissionImage = valuesYaml.admission.image; + expect(admissionImage).toBe(customImage); - // const zarfYaml = `${moduleDst}/dist/zarf.yaml`; - // const valuesYaml = `${moduleDst}/dist/${packageJson.pepr.uuid}-chart/values.yaml`; + const watcherImage = valuesYaml.watcher.image; + expect(watcherImage).toBe(customImage); + } }, time.toMs("1m"), ); }); }); - -it.only("does", async () => { - const moduleDst = `/home/barrett/workspace/defuni/pepr/integration/testroot/cli/build.test.ts/overrides`; - const customImage = "pepr:overrides"; - - const packageJson = await resource.oneFromFile(`${moduleDst}/package.json`); - const uuid = packageJson.pepr.uuid; - - const moduleYaml = await resource.manyFromFile(`${moduleDst}/dist/pepr-module-${uuid}.yaml`); - { - const admissionController = resource.select(moduleYaml, kind.Deployment, `pepr-${uuid}`); - const admissionImage = admissionController! - .spec!.template!.spec!.containers.filter(f => f.name === "server") - .at(0)!.image; - expect(admissionImage).toBe(customImage); - - const watchController = resource.select(moduleYaml, kind.Deployment, `pepr-${uuid}-watcher`); - const watchImage = watchController! - .spec!.template!.spec!.containers.filter(f => f.name === "watcher") - .at(0)!.image; - expect(watchImage).toBe(customImage); - } - - // const zarfYaml = await manyFromFile(`${moduleDst}/dist/zarf.yaml`); - // const valuesYaml = await manyFromFile( - // `${moduleDst}/dist/${packageJson.pepr.uuid}-chart/values.yaml`, - // ); - - // console.log(packageJson); - // console.log(zarfYaml); - // console.log(valuesYaml); -}); From 99c3623d70a4857a33af45aa04519db4f0f38161 Mon Sep 17 00:00:00 2001 From: Barrett LaFrance Date: Sat, 11 Jan 2025 16:19:47 -0600 Subject: [PATCH 15/51] wip: saving progress --- integration/cli/build.test.ts | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/integration/cli/build.test.ts b/integration/cli/build.test.ts index e30c4474b..05d8bf8c5 100644 --- a/integration/cli/build.test.ts +++ b/integration/cli/build.test.ts @@ -66,14 +66,23 @@ describe("build", () => { it( "using build override options", async () => { + // + // prepare module + // const moduleDst = `${workdir.path()}/overrides`; await pepr.copyModule(moduleSrc, moduleDst); await pepr.cli(moduleDst, { cmd: `npm install` }); + // + // establish override-support conditions + // const entryPoint = "pepr2.ts"; await fs.rename(`${moduleDst}/pepr.ts`, `${moduleDst}/${entryPoint}`); const customImage = "pepr:overrides"; + // + // build using with overrides + // const argz = [`--entry-point ${entryPoint}`, `--custom-image ${customImage}`].join(" "); const build = await pepr.cli(moduleDst, { cmd: `pepr build ${argz}` }); @@ -81,11 +90,16 @@ describe("build", () => { expect(build.stderr.join("").trim()).toBe(""); expect(build.stdout.join("").trim()).toContain("K8s resource for the module saved"); + // + // assert on consequences + // const packageJson = await resource.oneFromFile(`${moduleDst}/package.json`); - - // --entrypoint (will fail build if given --entrypoint doesn't exist) - // --custom-image const uuid = packageJson.pepr.uuid; + + /* --entrypoint (will fail build if given --entrypoint doesn't exist) */ + // noop + + /* --custom-image */ const moduleYaml = await resource.manyFromFile( `${moduleDst}/dist/pepr-module-${uuid}.yaml`, ); From d4ef9143d2a8514d2554950efd2630c9581666c6 Mon Sep 17 00:00:00 2001 From: Barrett LaFrance Date: Sat, 11 Jan 2025 16:52:24 -0600 Subject: [PATCH 16/51] wip: saving progress --- integration/cli/build.test.ts | 89 +++++++++++++++++++---------------- 1 file changed, 49 insertions(+), 40 deletions(-) diff --git a/integration/cli/build.test.ts b/integration/cli/build.test.ts index 05d8bf8c5..cb2f648af 100644 --- a/integration/cli/build.test.ts +++ b/integration/cli/build.test.ts @@ -32,7 +32,7 @@ describe("build", () => { time.toMs("2m"), ); - describe("builds a module successfully", () => { + describe("builds a module", () => { const moduleSrc = `${workdir.path()}/module`; beforeAll(async () => { @@ -48,58 +48,68 @@ describe("build", () => { await pepr.tgzifyModule(moduleSrc); }, time.toMs("2m")); - it( - "using default build options", - async () => { - const moduleDst = `${workdir.path()}/defaults`; - await pepr.copyModule(moduleSrc, moduleDst); - await pepr.cli(moduleDst, { cmd: `npm install` }); - - const build = await pepr.cli(moduleDst, { cmd: `pepr build` }); - expect(build.exitcode).toBe(0); - expect(build.stderr.join("").trim()).toBe(""); - expect(build.stdout.join("").trim()).toContain("K8s resource for the module saved"); - }, - time.toMs("1m"), - ); + describe("using default build options", () => { + it( + "succeeds", + async () => { + const moduleDst = `${workdir.path()}/defaults`; + await pepr.copyModule(moduleSrc, moduleDst); + await pepr.cli(moduleDst, { cmd: `npm install` }); + + const build = await pepr.cli(moduleDst, { cmd: `pepr build` }); + expect(build.exitcode).toBe(0); + expect(build.stderr.join("").trim()).toBe(""); + expect(build.stdout.join("").trim()).toContain("K8s resource for the module saved"); + }, + time.toMs("1m"), + ); + }); + + describe("using build override options", () => { + let moduleDst: string; + let packageJson; + let uuid: string; + const overrides = { + entryPoint: "pepr2.ts", + customImage: "pepr:override", + }; + + beforeAll(async () => { + moduleDst = `${workdir.path()}/overrides`; - it( - "using build override options", - async () => { // // prepare module // - const moduleDst = `${workdir.path()}/overrides`; await pepr.copyModule(moduleSrc, moduleDst); await pepr.cli(moduleDst, { cmd: `npm install` }); // // establish override-support conditions // - const entryPoint = "pepr2.ts"; - await fs.rename(`${moduleDst}/pepr.ts`, `${moduleDst}/${entryPoint}`); - const customImage = "pepr:overrides"; + await fs.rename(`${moduleDst}/pepr.ts`, `${moduleDst}/${overrides.entryPoint}`); // - // build using with overrides + // use overrides // - const argz = [`--entry-point ${entryPoint}`, `--custom-image ${customImage}`].join(" "); + const argz = [ + `--entry-point ${overrides.entryPoint}`, + `--custom-image ${overrides.customImage}`, + ].join(" "); const build = await pepr.cli(moduleDst, { cmd: `pepr build ${argz}` }); expect(build.exitcode).toBe(0); expect(build.stderr.join("").trim()).toBe(""); expect(build.stdout.join("").trim()).toContain("K8s resource for the module saved"); - // - // assert on consequences - // - const packageJson = await resource.oneFromFile(`${moduleDst}/package.json`); - const uuid = packageJson.pepr.uuid; + packageJson = await resource.oneFromFile(`${moduleDst}/package.json`); + uuid = packageJson.pepr.uuid; + }, time.toMs("1m")); - /* --entrypoint (will fail build if given --entrypoint doesn't exist) */ - // noop + it("--entry-point, works", async () => { + // build would fail if given entrypoint didn't exist, so... no-op, right? + }); - /* --custom-image */ + it("--custom-image, works", async () => { const moduleYaml = await resource.manyFromFile( `${moduleDst}/dist/pepr-module-${uuid}.yaml`, ); @@ -111,17 +121,17 @@ describe("build", () => { const admission = resource.select(moduleYaml, kind.Deployment, `pepr-${uuid}`); const admissionImage = getDepConImg(admission, "server"); - expect(admissionImage).toBe(customImage); + expect(admissionImage).toBe(overrides.customImage); const watcher = resource.select(moduleYaml, kind.Deployment, `pepr-${uuid}-watcher`); const watcherImage = getDepConImg(watcher, "watcher"); - expect(watcherImage).toBe(customImage); + expect(watcherImage).toBe(overrides.customImage); } const zarfYaml = await resource.oneFromFile(`${moduleDst}/dist/zarf.yaml`); { const componentImage = zarfYaml.components.at(0).images.at(0); - expect(componentImage).toBe(customImage); + expect(componentImage).toBe(overrides.customImage); } const valuesYaml = await resource.oneFromFile( @@ -129,13 +139,12 @@ describe("build", () => { ); { const admissionImage = valuesYaml.admission.image; - expect(admissionImage).toBe(customImage); + expect(admissionImage).toBe(overrides.customImage); const watcherImage = valuesYaml.watcher.image; - expect(watcherImage).toBe(customImage); + expect(watcherImage).toBe(overrides.customImage); } - }, - time.toMs("1m"), - ); + }); + }); }); }); From f9dd5f6433042ce8df7f8eed39426e7b29b1271a Mon Sep 17 00:00:00 2001 From: Barrett LaFrance Date: Mon, 13 Jan 2025 09:53:16 -0600 Subject: [PATCH 17/51] wip: saving progress --- integration/cli/build.test.ts | 126 ++++++++++++++++++++++++++++++++++ 1 file changed, 126 insertions(+) diff --git a/integration/cli/build.test.ts b/integration/cli/build.test.ts index cb2f648af..2845bcb4c 100644 --- a/integration/cli/build.test.ts +++ b/integration/cli/build.test.ts @@ -65,6 +65,132 @@ describe("build", () => { ); }); + describe("for use as a library", () => { + it( + "--no-embed, works", + async () => { + // overwrites --custom-image..? + + const moduleDst = `${workdir.path()}/noembed`; + await pepr.copyModule(moduleSrc, moduleDst); + await pepr.cli(moduleDst, { cmd: `npm install` }); + + const argz = [`--no-embed`].join(" "); + const build = await pepr.cli(moduleDst, { cmd: `pepr build ${argz}` }); + expect(build.exitcode).toBe(0); + + // TODO: team talk + // Should this be writing to stderr? Even with a 0 exit code..? + expect(build.stderr.join("").trim()).toContain("Error: Cannot find module"); + // TODO: end + + expect(build.stdout.join("").trim()).toContain(""); + + const packageJson = await resource.oneFromFile(`${moduleDst}/package.json`); + const uuid = packageJson.pepr.uuid; + + // deployable module files + { + const files = [ + `${moduleDst}/dist/pepr-${uuid}.js`, + `${moduleDst}/dist/pepr-${uuid}.js.map`, + `${moduleDst}/dist/pepr-${uuid}.js.LEGAL.txt`, + `${moduleDst}/dist/pepr-module-${uuid}.yaml`, + ]; + for (const file of files) { + await expect(fs.access(file)).rejects.toThrowError("no such file or directory"); + } + } + + // zarf manifest + { + const file = `${moduleDst}/dist/zarf.yaml`; + await expect(fs.access(file)).rejects.toThrowError("no such file or directory"); + } + + // helm chart + { + const file = `${moduleDst}/dist/${uuid}-chart/`; + await expect(fs.access(file)).rejects.toThrowError("no such file or directory"); + } + + // importable module files + { + const files = [ + `${moduleDst}/dist/pepr.js`, + `${moduleDst}/dist/pepr.js.map`, + `${moduleDst}/dist/pepr.js.LEGAL.txt`, + ]; + for (const file of files) { + await expect(fs.access(file)).resolves.toBe(undefined); + } + } + }, + time.toMs("2m"), + ); + }); + + describe("that uses a custom registry", () => { + it( + "--registry-info, works", + async () => { + // overwrites --custom-image..? + + const moduleDst = `${workdir.path()}/reginfo`; + await pepr.copyModule(moduleSrc, moduleDst); + await pepr.cli(moduleDst, { cmd: `npm install` }); + + const registryInfo = "registry.io/username"; + const argz = [`--registry-info ${registryInfo}`].join(" "); + const build = await pepr.cli(moduleDst, { cmd: `pepr build ${argz}` }); + expect(build.exitcode).toBe(0); + expect(build.stderr.join("").trim()).toBe(""); + expect(build.stdout.join("").trim()).toContain("K8s resource for the module saved"); + + const packageJson = await resource.oneFromFile(`${moduleDst}/package.json`); + const uuid = packageJson.pepr.uuid; + const image = `${registryInfo}/custom-pepr-controller:0.0.0-development`; + + const moduleYaml = await resource.manyFromFile( + `${moduleDst}/dist/pepr-module-${uuid}.yaml`, + ); + { + const getDepConImg = (deploy: kind.Deployment, container: string): string => { + return deploy! + .spec!.template!.spec!.containers.filter(f => f.name === container) + .at(0)!.image!; + }; + + const admission = resource.select(moduleYaml, kind.Deployment, `pepr-${uuid}`); + const admissionImage = getDepConImg(admission, "server"); + expect(admissionImage).toBe(image); + + const watcher = resource.select(moduleYaml, kind.Deployment, `pepr-${uuid}-watcher`); + const watcherImage = getDepConImg(watcher, "watcher"); + expect(watcherImage).toBe(image); + } + + const zarfYaml = await resource.oneFromFile(`${moduleDst}/dist/zarf.yaml`); + { + const componentImage = zarfYaml.components.at(0).images.at(0); + expect(componentImage).toBe(image); + } + + const valuesYaml = await resource.oneFromFile( + `${moduleDst}/dist/${uuid}-chart/values.yaml`, + ); + { + const admissionImage = valuesYaml.admission.image; + expect(admissionImage).toBe(image); + + const watcherImage = valuesYaml.watcher.image; + expect(watcherImage).toBe(image); + } + }, + time.toMs("2m"), + ); + }); + describe("using build override options", () => { let moduleDst: string; let packageJson; From f00f448f7aa321db61ee0f64ae817d9ba00a90ac Mon Sep 17 00:00:00 2001 From: Barrett LaFrance Date: Mon, 13 Jan 2025 10:09:29 -0600 Subject: [PATCH 18/51] wip: saving progress --- integration/cli/build.test.ts | 116 ++++++++++++++++------------------ 1 file changed, 55 insertions(+), 61 deletions(-) diff --git a/integration/cli/build.test.ts b/integration/cli/build.test.ts index 2845bcb4c..ac23edbd3 100644 --- a/integration/cli/build.test.ts +++ b/integration/cli/build.test.ts @@ -13,6 +13,10 @@ import * as resource from "../helpers/resource"; const FILE = path.basename(__filename); const HERE = __dirname; +const getDepConImg = (deploy: kind.Deployment, container: string): string => { + return deploy!.spec!.template!.spec!.containers.filter(f => f.name === container).at(0)!.image!; +}; + describe("build", () => { const workdir = new Workdir(`${FILE}`, `${HERE}/../testroot/cli`); @@ -66,68 +70,69 @@ describe("build", () => { }); describe("for use as a library", () => { - it( - "--no-embed, works", - async () => { - // overwrites --custom-image..? + const moduleDst = `${workdir.path()}/noembed`; + let packageJson; + let uuid: string; - const moduleDst = `${workdir.path()}/noembed`; - await pepr.copyModule(moduleSrc, moduleDst); - await pepr.cli(moduleDst, { cmd: `npm install` }); + beforeAll(async () => { + await pepr.copyModule(moduleSrc, moduleDst); + await pepr.cli(moduleDst, { cmd: `npm install` }); - const argz = [`--no-embed`].join(" "); - const build = await pepr.cli(moduleDst, { cmd: `pepr build ${argz}` }); - expect(build.exitcode).toBe(0); + const argz = [`--no-embed`].join(" "); + const build = await pepr.cli(moduleDst, { cmd: `pepr build ${argz}` }); + expect(build.exitcode).toBe(0); - // TODO: team talk - // Should this be writing to stderr? Even with a 0 exit code..? - expect(build.stderr.join("").trim()).toContain("Error: Cannot find module"); - // TODO: end + // TODO: team talk + // Should this be writing to stderr? Even with a 0 exit code..? + expect(build.stderr.join("").trim()).toContain("Error: Cannot find module"); + // TODO: end - expect(build.stdout.join("").trim()).toContain(""); + expect(build.stdout.join("").trim()).toContain(""); - const packageJson = await resource.oneFromFile(`${moduleDst}/package.json`); - const uuid = packageJson.pepr.uuid; + packageJson = await resource.oneFromFile(`${moduleDst}/package.json`); + uuid = packageJson.pepr.uuid; + }, time.toMs("1m")); - // deployable module files - { - const files = [ - `${moduleDst}/dist/pepr-${uuid}.js`, - `${moduleDst}/dist/pepr-${uuid}.js.map`, - `${moduleDst}/dist/pepr-${uuid}.js.LEGAL.txt`, - `${moduleDst}/dist/pepr-module-${uuid}.yaml`, - ]; - for (const file of files) { - await expect(fs.access(file)).rejects.toThrowError("no such file or directory"); - } - } + it.only("--no-embed, works", async () => { + // overwrites --custom-image..? - // zarf manifest - { - const file = `${moduleDst}/dist/zarf.yaml`; + // deployable module files + { + const files = [ + `${moduleDst}/dist/pepr-${uuid}.js`, + `${moduleDst}/dist/pepr-${uuid}.js.map`, + `${moduleDst}/dist/pepr-${uuid}.js.LEGAL.txt`, + `${moduleDst}/dist/pepr-module-${uuid}.yaml`, + ]; + for (const file of files) { await expect(fs.access(file)).rejects.toThrowError("no such file or directory"); } + } - // helm chart - { - const file = `${moduleDst}/dist/${uuid}-chart/`; - await expect(fs.access(file)).rejects.toThrowError("no such file or directory"); - } + // zarf manifest + { + const file = `${moduleDst}/dist/zarf.yaml`; + await expect(fs.access(file)).rejects.toThrowError("no such file or directory"); + } - // importable module files - { - const files = [ - `${moduleDst}/dist/pepr.js`, - `${moduleDst}/dist/pepr.js.map`, - `${moduleDst}/dist/pepr.js.LEGAL.txt`, - ]; - for (const file of files) { - await expect(fs.access(file)).resolves.toBe(undefined); - } + // helm chart + { + const file = `${moduleDst}/dist/${uuid}-chart/`; + await expect(fs.access(file)).rejects.toThrowError("no such file or directory"); + } + + // importable module files + { + const files = [ + `${moduleDst}/dist/pepr.js`, + `${moduleDst}/dist/pepr.js.map`, + `${moduleDst}/dist/pepr.js.LEGAL.txt`, + ]; + for (const file of files) { + await expect(fs.access(file)).resolves.toBe(undefined); } - }, - time.toMs("2m"), - ); + } + }); }); describe("that uses a custom registry", () => { @@ -155,12 +160,6 @@ describe("build", () => { `${moduleDst}/dist/pepr-module-${uuid}.yaml`, ); { - const getDepConImg = (deploy: kind.Deployment, container: string): string => { - return deploy! - .spec!.template!.spec!.containers.filter(f => f.name === container) - .at(0)!.image!; - }; - const admission = resource.select(moduleYaml, kind.Deployment, `pepr-${uuid}`); const admissionImage = getDepConImg(admission, "server"); expect(admissionImage).toBe(image); @@ -240,11 +239,6 @@ describe("build", () => { `${moduleDst}/dist/pepr-module-${uuid}.yaml`, ); { - const getDepConImg = (deploy: kind.Deployment, container: string): string => { - return deploy!.spec!.template!.spec!.containers.filter(f => f.name === container).at(0)! - .image!; - }; - const admission = resource.select(moduleYaml, kind.Deployment, `pepr-${uuid}`); const admissionImage = getDepConImg(admission, "server"); expect(admissionImage).toBe(overrides.customImage); From ea0c58955b7f0aa17f062958af4c80256979298f Mon Sep 17 00:00:00 2001 From: Barrett LaFrance Date: Mon, 13 Jan 2025 10:13:57 -0600 Subject: [PATCH 19/51] wip: saving progress --- integration/cli/build.test.ts | 95 +++++++++++++++++------------------ 1 file changed, 47 insertions(+), 48 deletions(-) diff --git a/integration/cli/build.test.ts b/integration/cli/build.test.ts index ac23edbd3..71d228a3d 100644 --- a/integration/cli/build.test.ts +++ b/integration/cli/build.test.ts @@ -93,9 +93,7 @@ describe("build", () => { uuid = packageJson.pepr.uuid; }, time.toMs("1m")); - it.only("--no-embed, works", async () => { - // overwrites --custom-image..? - + it("--no-embed, works", async () => { // deployable module files { const files = [ @@ -136,58 +134,59 @@ describe("build", () => { }); describe("that uses a custom registry", () => { - it( - "--registry-info, works", - async () => { - // overwrites --custom-image..? + const moduleDst = `${workdir.path()}/reginfo`; + let packageJson; + let uuid: string; + const registryInfo = "registry.io/username"; - const moduleDst = `${workdir.path()}/reginfo`; - await pepr.copyModule(moduleSrc, moduleDst); - await pepr.cli(moduleDst, { cmd: `npm install` }); + beforeAll(async () => { + await pepr.copyModule(moduleSrc, moduleDst); + await pepr.cli(moduleDst, { cmd: `npm install` }); - const registryInfo = "registry.io/username"; - const argz = [`--registry-info ${registryInfo}`].join(" "); - const build = await pepr.cli(moduleDst, { cmd: `pepr build ${argz}` }); - expect(build.exitcode).toBe(0); - expect(build.stderr.join("").trim()).toBe(""); - expect(build.stdout.join("").trim()).toContain("K8s resource for the module saved"); + const argz = [`--registry-info ${registryInfo}`].join(" "); + const build = await pepr.cli(moduleDst, { cmd: `pepr build ${argz}` }); + expect(build.exitcode).toBe(0); + expect(build.stderr.join("").trim()).toBe(""); + expect(build.stdout.join("").trim()).toContain("K8s resource for the module saved"); - const packageJson = await resource.oneFromFile(`${moduleDst}/package.json`); - const uuid = packageJson.pepr.uuid; - const image = `${registryInfo}/custom-pepr-controller:0.0.0-development`; + packageJson = await resource.oneFromFile(`${moduleDst}/package.json`); + uuid = packageJson.pepr.uuid; + }, time.toMs("1m")); - const moduleYaml = await resource.manyFromFile( - `${moduleDst}/dist/pepr-module-${uuid}.yaml`, - ); - { - const admission = resource.select(moduleYaml, kind.Deployment, `pepr-${uuid}`); - const admissionImage = getDepConImg(admission, "server"); - expect(admissionImage).toBe(image); - - const watcher = resource.select(moduleYaml, kind.Deployment, `pepr-${uuid}-watcher`); - const watcherImage = getDepConImg(watcher, "watcher"); - expect(watcherImage).toBe(image); - } + it("--registry-info, works", async () => { + // overwrites --custom-image..? + const image = `${registryInfo}/custom-pepr-controller:0.0.0-development`; - const zarfYaml = await resource.oneFromFile(`${moduleDst}/dist/zarf.yaml`); - { - const componentImage = zarfYaml.components.at(0).images.at(0); - expect(componentImage).toBe(image); - } + const moduleYaml = await resource.manyFromFile( + `${moduleDst}/dist/pepr-module-${uuid}.yaml`, + ); + { + const admission = resource.select(moduleYaml, kind.Deployment, `pepr-${uuid}`); + const admissionImage = getDepConImg(admission, "server"); + expect(admissionImage).toBe(image); - const valuesYaml = await resource.oneFromFile( - `${moduleDst}/dist/${uuid}-chart/values.yaml`, - ); - { - const admissionImage = valuesYaml.admission.image; - expect(admissionImage).toBe(image); + const watcher = resource.select(moduleYaml, kind.Deployment, `pepr-${uuid}-watcher`); + const watcherImage = getDepConImg(watcher, "watcher"); + expect(watcherImage).toBe(image); + } - const watcherImage = valuesYaml.watcher.image; - expect(watcherImage).toBe(image); - } - }, - time.toMs("2m"), - ); + const zarfYaml = await resource.oneFromFile(`${moduleDst}/dist/zarf.yaml`); + { + const componentImage = zarfYaml.components.at(0).images.at(0); + expect(componentImage).toBe(image); + } + + const valuesYaml = await resource.oneFromFile( + `${moduleDst}/dist/${uuid}-chart/values.yaml`, + ); + { + const admissionImage = valuesYaml.admission.image; + expect(admissionImage).toBe(image); + + const watcherImage = valuesYaml.watcher.image; + expect(watcherImage).toBe(image); + } + }); }); describe("using build override options", () => { From 7a162bd421237bdf904162d02df6fc20bbb49d43 Mon Sep 17 00:00:00 2001 From: Barrett LaFrance Date: Mon, 13 Jan 2025 11:17:32 -0600 Subject: [PATCH 20/51] wip: saving progress --- integration/cli/build.test.ts | 46 +++++++++++++++++++------------- integration/helpers/file.test.ts | 28 +++++++++++++++++++ integration/helpers/file.ts | 14 ++++++++++ 3 files changed, 70 insertions(+), 18 deletions(-) create mode 100644 integration/helpers/file.test.ts create mode 100644 integration/helpers/file.ts diff --git a/integration/cli/build.test.ts b/integration/cli/build.test.ts index 71d228a3d..6049f37cd 100644 --- a/integration/cli/build.test.ts +++ b/integration/cli/build.test.ts @@ -9,6 +9,7 @@ import { Workdir } from "../helpers/workdir"; import * as time from "../helpers/time"; import * as pepr from "../helpers/pepr"; import * as resource from "../helpers/resource"; +import * as file from "../helpers/file"; const FILE = path.basename(__filename); const HERE = __dirname; @@ -96,44 +97,45 @@ describe("build", () => { it("--no-embed, works", async () => { // deployable module files { - const files = [ + const paths = [ `${moduleDst}/dist/pepr-${uuid}.js`, `${moduleDst}/dist/pepr-${uuid}.js.map`, `${moduleDst}/dist/pepr-${uuid}.js.LEGAL.txt`, `${moduleDst}/dist/pepr-module-${uuid}.yaml`, ]; - for (const file of files) { - await expect(fs.access(file)).rejects.toThrowError("no such file or directory"); + for (const path of paths) { + // await expect(fs.access(path)).rejects.toThrowError("no such file or directory"); + expect(await file.exists(path)).toBe(false); } } // zarf manifest { - const file = `${moduleDst}/dist/zarf.yaml`; - await expect(fs.access(file)).rejects.toThrowError("no such file or directory"); + const path = `${moduleDst}/dist/zarf.yaml`; + expect(await file.exists(path)).toBe(false); } // helm chart { - const file = `${moduleDst}/dist/${uuid}-chart/`; - await expect(fs.access(file)).rejects.toThrowError("no such file or directory"); + const path = `${moduleDst}/dist/${uuid}-chart/`; + expect(await file.exists(path)).toBe(false); } // importable module files { - const files = [ + const paths = [ `${moduleDst}/dist/pepr.js`, `${moduleDst}/dist/pepr.js.map`, `${moduleDst}/dist/pepr.js.LEGAL.txt`, ]; - for (const file of files) { - await expect(fs.access(file)).resolves.toBe(undefined); + for (const path of paths) { + expect(await file.exists(path)).toBe(true); } } }); }); - describe("that uses a custom registry", () => { + describe("using a custom registry", () => { const moduleDst = `${workdir.path()}/reginfo`; let packageJson; let uuid: string; @@ -189,18 +191,17 @@ describe("build", () => { }); }); - describe("using build override options", () => { - let moduleDst: string; + describe("using non-conflicting build override options", () => { + const moduleDst = `${workdir.path()}/overrides`; let packageJson; let uuid: string; const overrides = { entryPoint: "pepr2.ts", customImage: "pepr:override", + outputDir: `${moduleDst}/out`, }; beforeAll(async () => { - moduleDst = `${workdir.path()}/overrides`; - // // prepare module // @@ -218,6 +219,7 @@ describe("build", () => { const argz = [ `--entry-point ${overrides.entryPoint}`, `--custom-image ${overrides.customImage}`, + `--output-dir ${overrides.outputDir}`, ].join(" "); const build = await pepr.cli(moduleDst, { cmd: `pepr build ${argz}` }); @@ -233,9 +235,17 @@ describe("build", () => { // build would fail if given entrypoint didn't exist, so... no-op, right? }); + it("--output-dir, works", async () => { + const dist = `${moduleDst}/dist`; + expect(await file.exists(dist)).toBe(false); + + const out = overrides.outputDir; + expect(await file.exists(out)).toBe(true); + }); + it("--custom-image, works", async () => { const moduleYaml = await resource.manyFromFile( - `${moduleDst}/dist/pepr-module-${uuid}.yaml`, + `${overrides.outputDir}/pepr-module-${uuid}.yaml`, ); { const admission = resource.select(moduleYaml, kind.Deployment, `pepr-${uuid}`); @@ -247,14 +257,14 @@ describe("build", () => { expect(watcherImage).toBe(overrides.customImage); } - const zarfYaml = await resource.oneFromFile(`${moduleDst}/dist/zarf.yaml`); + const zarfYaml = await resource.oneFromFile(`${overrides.outputDir}/zarf.yaml`); { const componentImage = zarfYaml.components.at(0).images.at(0); expect(componentImage).toBe(overrides.customImage); } const valuesYaml = await resource.oneFromFile( - `${moduleDst}/dist/${uuid}-chart/values.yaml`, + `${overrides.outputDir}/${uuid}-chart/values.yaml`, ); { const admissionImage = valuesYaml.admission.image; diff --git a/integration/helpers/file.test.ts b/integration/helpers/file.test.ts new file mode 100644 index 000000000..6597befae --- /dev/null +++ b/integration/helpers/file.test.ts @@ -0,0 +1,28 @@ +import { beforeAll, describe, expect, it } from "@jest/globals"; +import * as path from "node:path"; +import * as fs from "node:fs/promises"; +import { Workdir } from "../helpers/workdir"; +import * as sut from "./file"; + +const FILE = path.basename(__filename); +const HERE = __dirname; + +describe("exists", () => { + const workdir = new Workdir(`${FILE}-exists`, `${HERE}/../testroot/helpers`); + const real = `${workdir.path()}/exists.txt`; + + beforeAll(async () => { + await workdir.recreate(); + await fs.writeFile(real, "I exist!"); + }); + + it("returns true when exists", async () => { + const res = await sut.exists(real); + expect(res).toBe(true); + }); + + it("returns false when missing", async () => { + const res = await sut.exists(`${real}.nope`); + expect(res).toBe(false); + }); +}); diff --git a/integration/helpers/file.ts b/integration/helpers/file.ts new file mode 100644 index 000000000..7ce54b298 --- /dev/null +++ b/integration/helpers/file.ts @@ -0,0 +1,14 @@ +import { access } from "node:fs/promises"; + +export async function exists(path: string): Promise { + try { + await access(path); + return true; + } catch (e) { + if (e.code === "ENOENT") { + return false; + } else { + throw e; + } + } +} From 0a3fc9f1ac452e6c8696827658abae676d06752f Mon Sep 17 00:00:00 2001 From: Barrett LaFrance Date: Mon, 13 Jan 2025 11:38:22 -0600 Subject: [PATCH 21/51] wip: saving progress --- integration/cli/build.test.ts | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/integration/cli/build.test.ts b/integration/cli/build.test.ts index 6049f37cd..ea2427b60 100644 --- a/integration/cli/build.test.ts +++ b/integration/cli/build.test.ts @@ -199,6 +199,7 @@ describe("build", () => { entryPoint: "pepr2.ts", customImage: "pepr:override", outputDir: `${moduleDst}/out`, + timeout: 11, }; beforeAll(async () => { @@ -220,6 +221,7 @@ describe("build", () => { `--entry-point ${overrides.entryPoint}`, `--custom-image ${overrides.customImage}`, `--output-dir ${overrides.outputDir}`, + `--timeout ${overrides.timeout}`, ].join(" "); const build = await pepr.cli(moduleDst, { cmd: `pepr build ${argz}` }); @@ -274,6 +276,35 @@ describe("build", () => { expect(watcherImage).toBe(overrides.customImage); } }); + + it.only("--timeout, works", async () => { + const moduleYaml = await resource.manyFromFile( + `${overrides.outputDir}/pepr-module-${uuid}.yaml`, + ); + { + const mwc = resource.select( + moduleYaml, + kind.MutatingWebhookConfiguration, + `pepr-${uuid}`, + ); + const webhook = mwc.webhooks!.filter(f => f.name === `pepr-${uuid}.pepr.dev`).at(0)!; + expect(webhook.timeoutSeconds).toBe(overrides.timeout); + } + { + const mwc = resource.select( + moduleYaml, + kind.ValidatingWebhookConfiguration, + `pepr-${uuid}`, + ); + const webhook = mwc.webhooks!.filter(f => f.name === `pepr-${uuid}.pepr.dev`).at(0)!; + expect(webhook.timeoutSeconds).toBe(overrides.timeout); + } + + const valuesYaml = await resource.oneFromFile( + `${overrides.outputDir}/${uuid}-chart/values.yaml`, + ); + expect(valuesYaml.admission.webhookTimeout).toBe(overrides.timeout); + }); }); }); }); From eef5cd0c9e80d90718bbd94e9f1683780dbb2ad3 Mon Sep 17 00:00:00 2001 From: Barrett LaFrance Date: Mon, 13 Jan 2025 11:48:53 -0600 Subject: [PATCH 22/51] wip: saving progress --- .eslintrc.json | 8 ++++++++ integration/cli/build.test.ts | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/.eslintrc.json b/.eslintrc.json index 9034f067b..bfbd37b9b 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -21,6 +21,14 @@ "max-statements": ["warn", { "max": 20 }, { "ignoreTopLevelFunctions": true }], "no-invalid-this": "warn" }, + "overrides": [ + { + "files": ["*.test.ts"], + "rules": { + "max-nested-callbacks": ["warn", { "max": 10 }] + } + } + ], "plugins": ["@typescript-eslint"], "ignorePatterns": [ "src/templates", diff --git a/integration/cli/build.test.ts b/integration/cli/build.test.ts index ea2427b60..19360718f 100644 --- a/integration/cli/build.test.ts +++ b/integration/cli/build.test.ts @@ -277,7 +277,7 @@ describe("build", () => { } }); - it.only("--timeout, works", async () => { + it("--timeout, works", async () => { const moduleYaml = await resource.manyFromFile( `${overrides.outputDir}/pepr-module-${uuid}.yaml`, ); From 7b9d80aaf95124a3776aa93fcabd723cfee3db81 Mon Sep 17 00:00:00 2001 From: Barrett LaFrance Date: Mon, 13 Jan 2025 12:13:09 -0600 Subject: [PATCH 23/51] wip: saving progress --- integration/cli/build.test.ts | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/integration/cli/build.test.ts b/integration/cli/build.test.ts index 19360718f..8d64e9a2b 100644 --- a/integration/cli/build.test.ts +++ b/integration/cli/build.test.ts @@ -191,6 +191,28 @@ describe("build", () => { }); }); + describe("using a specified pepr version", () => { + const moduleDst = `${workdir.path()}/version`; + const version = "1.2.3"; + + beforeAll(async () => { + await pepr.copyModule(moduleSrc, moduleDst); + await pepr.cli(moduleDst, { cmd: `npm install` }); + + const argz = [`--version ${version}`].join(" "); + const build = await pepr.cli(moduleDst, { cmd: `pepr build ${argz}` }); + expect(build.exitcode).toBe(0); + expect(build.stderr.join("").trim()).toBe(""); + expect(build.stdout.join("").trim()).toContain("0.0.0-development"); + }, time.toMs("1m")); + + it("--version, is broken..?", async () => { + // looks like it's just giving back the `pepr --version` and exiting, + // rather than buidling/affecting the output files at all..? + expect(await file.exists(`${moduleDst}/dist`)).toBe(false); + }); + }); + describe("using non-conflicting build override options", () => { const moduleDst = `${workdir.path()}/overrides`; let packageJson; From dfa0eae930c422bf38e68277ddccc2f2cea2762a Mon Sep 17 00:00:00 2001 From: Barrett LaFrance Date: Mon, 13 Jan 2025 12:14:27 -0600 Subject: [PATCH 24/51] wip: saving progress --- integration/cli/build.test.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/integration/cli/build.test.ts b/integration/cli/build.test.ts index 8d64e9a2b..1f2ecca67 100644 --- a/integration/cli/build.test.ts +++ b/integration/cli/build.test.ts @@ -193,6 +193,7 @@ describe("build", () => { describe("using a specified pepr version", () => { const moduleDst = `${workdir.path()}/version`; + const cliVersion = "0.0.0-development"; const version = "1.2.3"; beforeAll(async () => { @@ -203,11 +204,11 @@ describe("build", () => { const build = await pepr.cli(moduleDst, { cmd: `pepr build ${argz}` }); expect(build.exitcode).toBe(0); expect(build.stderr.join("").trim()).toBe(""); - expect(build.stdout.join("").trim()).toContain("0.0.0-development"); + expect(build.stdout.join("").trim()).toContain(cliVersion); }, time.toMs("1m")); - it("--version, is broken..?", async () => { - // looks like it's just giving back the `pepr --version` and exiting, + it.only("--version, is broken..?", async () => { + // looks like it's just giving back the `pepr --version` then exiting, // rather than buidling/affecting the output files at all..? expect(await file.exists(`${moduleDst}/dist`)).toBe(false); }); From 738a09ce2401259a345eccdfa5fefccaad9a4e33 Mon Sep 17 00:00:00 2001 From: Barrett LaFrance Date: Mon, 13 Jan 2025 12:18:15 -0600 Subject: [PATCH 25/51] wip: saving progress --- integration/cli/build.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration/cli/build.test.ts b/integration/cli/build.test.ts index 1f2ecca67..f61be9fff 100644 --- a/integration/cli/build.test.ts +++ b/integration/cli/build.test.ts @@ -207,7 +207,7 @@ describe("build", () => { expect(build.stdout.join("").trim()).toContain(cliVersion); }, time.toMs("1m")); - it.only("--version, is broken..?", async () => { + it("--version, is broken..?", async () => { // looks like it's just giving back the `pepr --version` then exiting, // rather than buidling/affecting the output files at all..? expect(await file.exists(`${moduleDst}/dist`)).toBe(false); From 09d2ad5d42e38d46d25c4d7b124d9862d74a457a Mon Sep 17 00:00:00 2001 From: Barrett LaFrance Date: Mon, 13 Jan 2025 13:24:12 -0600 Subject: [PATCH 26/51] wip: saving progress --- integration/cli/build.test.ts | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/integration/cli/build.test.ts b/integration/cli/build.test.ts index f61be9fff..14fd7d8d1 100644 --- a/integration/cli/build.test.ts +++ b/integration/cli/build.test.ts @@ -18,6 +18,10 @@ const getDepConImg = (deploy: kind.Deployment, container: string): string => { return deploy!.spec!.template!.spec!.containers.filter(f => f.name === container).at(0)!.image!; }; +const getDepImgPull = (deploy: kind.Deployment): string[] => { + return deploy!.spec!.template!.spec!.imagePullSecrets!.map(m => m.name!); +}; + describe("build", () => { const workdir = new Workdir(`${FILE}`, `${HERE}/../testroot/cli`); @@ -208,9 +212,11 @@ describe("build", () => { }, time.toMs("1m")); it("--version, is broken..?", async () => { + // TODO: team talk // looks like it's just giving back the `pepr --version` then exiting, // rather than buidling/affecting the output files at all..? expect(await file.exists(`${moduleDst}/dist`)).toBe(false); + // TODO: end }); }); @@ -223,6 +229,7 @@ describe("build", () => { customImage: "pepr:override", outputDir: `${moduleDst}/out`, timeout: 11, + withPullSecret: "shhh", }; beforeAll(async () => { @@ -245,6 +252,7 @@ describe("build", () => { `--custom-image ${overrides.customImage}`, `--output-dir ${overrides.outputDir}`, `--timeout ${overrides.timeout}`, + `--withPullSecret ${overrides.withPullSecret}`, ].join(" "); const build = await pepr.cli(moduleDst, { cmd: `pepr build ${argz}` }); @@ -328,6 +336,24 @@ describe("build", () => { ); expect(valuesYaml.admission.webhookTimeout).toBe(overrides.timeout); }); + + it("--withPullSecret, works", async () => { + const moduleYaml = await resource.manyFromFile( + `${overrides.outputDir}/pepr-module-${uuid}.yaml`, + ); + { + const admission = resource.select(moduleYaml, kind.Deployment, `pepr-${uuid}`); + const admissionSecrets = getDepImgPull(admission); + expect(admissionSecrets).toEqual([overrides.withPullSecret]); + + const watcher = resource.select(moduleYaml, kind.Deployment, `pepr-${uuid}-watcher`); + const watcherSecrets = getDepImgPull(watcher); + expect(watcherSecrets).toEqual([overrides.withPullSecret]); + } + // TODO: team talk + // Image pull secrets don't seem to map into the Helm chart anywhere..? Should they? + // TODO: end + }); }); }); }); From 4d7990ee72f493504792ebeba947d98fc27cf0db Mon Sep 17 00:00:00 2001 From: Barrett LaFrance Date: Mon, 13 Jan 2025 13:54:30 -0600 Subject: [PATCH 27/51] wip: saving progress --- integration/cli/build.test.ts | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/integration/cli/build.test.ts b/integration/cli/build.test.ts index 14fd7d8d1..1441c1a19 100644 --- a/integration/cli/build.test.ts +++ b/integration/cli/build.test.ts @@ -42,12 +42,12 @@ describe("build", () => { ); describe("builds a module", () => { - const moduleSrc = `${workdir.path()}/module`; + const moduleSrc = `${workdir.path()}/build-base`; beforeAll(async () => { await fs.rm(moduleSrc, { recursive: true, force: true }); const argz = [ - `--name module`, + `--name build-base`, `--description description`, `--errorBehavior reject`, "--confirm", @@ -230,6 +230,7 @@ describe("build", () => { outputDir: `${moduleDst}/out`, timeout: 11, withPullSecret: "shhh", + zarf: "chart", }; beforeAll(async () => { @@ -253,6 +254,7 @@ describe("build", () => { `--output-dir ${overrides.outputDir}`, `--timeout ${overrides.timeout}`, `--withPullSecret ${overrides.withPullSecret}`, + `--zarf ${overrides.zarf}`, ].join(" "); const build = await pepr.cli(moduleDst, { cmd: `pepr build ${argz}` }); @@ -354,6 +356,21 @@ describe("build", () => { // Image pull secrets don't seem to map into the Helm chart anywhere..? Should they? // TODO: end }); + + it("--zarf, works", async () => { + const chart = { + name: "module", + namespace: "pepr-system", + version: "0.0.1", + localPath: `${uuid}-chart`, + }; + + const zarfYaml = await resource.oneFromFile(`${overrides.outputDir}/zarf.yaml`); + const component = zarfYaml.components + .filter((f: { name: string }) => f.name === "module") + .at(0); + expect(component.charts).toContainEqual(chart); + }); }); }); }); From cfd756d9ed8bd77c0098b89a639fcc202dfd4943 Mon Sep 17 00:00:00 2001 From: Barrett LaFrance Date: Mon, 13 Jan 2025 13:56:11 -0600 Subject: [PATCH 28/51] wip: saving progress --- integration/cli/build.test.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/integration/cli/build.test.ts b/integration/cli/build.test.ts index 1441c1a19..254865eaf 100644 --- a/integration/cli/build.test.ts +++ b/integration/cli/build.test.ts @@ -371,6 +371,10 @@ describe("build", () => { .at(0); expect(component.charts).toContainEqual(chart); }); + + // it("--rbac-mode, ...todo!", async () => { + // --rbac-mode scoped + // } }); }); }); From f80d3127a5641933d4d553f0914e207602c8a77b Mon Sep 17 00:00:00 2001 From: Barrett LaFrance Date: Mon, 13 Jan 2025 15:40:34 -0600 Subject: [PATCH 29/51] wip: saving progress --- .eslintrc.json | 2 +- .github/workflows/cli-tests.yml | 127 -------------------------------- integration/cli/build.test.ts | 26 +++---- 3 files changed, 12 insertions(+), 143 deletions(-) delete mode 100644 .github/workflows/cli-tests.yml diff --git a/.eslintrc.json b/.eslintrc.json index bfbd37b9b..0cb52d9a2 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -25,7 +25,7 @@ { "files": ["*.test.ts"], "rules": { - "max-nested-callbacks": ["warn", { "max": 10 }] + "max-nested-callbacks": ["warn", { "max": 8 }] } } ], diff --git a/.github/workflows/cli-tests.yml b/.github/workflows/cli-tests.yml deleted file mode 100644 index 15b89d15b..000000000 --- a/.github/workflows/cli-tests.yml +++ /dev/null @@ -1,127 +0,0 @@ -name: CLI tests - -permissions: read-all -on: - push: - branches: ["main"] - pull_request: - branches: ["main"] - merge_group: - paths-ignore: - - "**.md" - - "**.yml" - - "**.yaml" - - "**.toml" - - "docs/**" - - "hack/**" - - "journey/**" - - "LICENSE" - - "CODEOWNERS" - - "Dockerfile" - - "Dockerfile.controller" - - "Dockerfile.kfc" - -jobs: - pepr-build: - name: controller image - runs-on: ubuntu-latest - steps: - - name: Harden Runner - uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 - with: - egress-policy: audit - - - name: clone pepr - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - with: - repository: defenseunicorns/pepr - path: pepr - - - name: "set env: PEPR" - run: echo "PEPR=${GITHUB_WORKSPACE}/pepr" >> "$GITHUB_ENV" - - - name: setup node - uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0 - with: - node-version: 20 - cache-dependency-path: pepr - - - name: Prep for CLI tests - run: | - cd "$PEPR" - npm ci - - - name: pepr init - displays the help menu - run: | - cd "$PEPR" - npm run gen-data-json - npx ts-node src/cli.ts init --help > result.log - grep " \-\-name" result.log - grep " \-\-description" result.log - grep " \-\-errorBehavior" result.log - grep " \-\-confirm" result.log - - - name: pepr init - creates a module with input from flags - run: | - cd "$PEPR" - npm run gen-data-json - npx ts-node src/cli.ts init \ - --name my-flagged-module \ - --description "Set by flag" \ - --errorBehavior reject \ - --confirm \ - --skip-post-init - RESULT_FILE="my-flagged-module/package.json" - grep "my-flagged-module" $RESULT_FILE - grep "Set by flag" $RESULT_FILE - grep "reject" $RESULT_FILE - - - name: pepr init - creates a module with input from stdin - run: | - cd "$PEPR" - npm run gen-data-json - echo "stdin-module" | npx ts-node src/cli.ts init \ - --description "Set by flag" \ - --errorBehavior reject \ - --confirm \ - --skip-post-init - RESULT_FILE="stdin-module/package.json" - grep "stdin-module" $RESULT_FILE - grep "Set by flag" $RESULT_FILE - grep "reject" $RESULT_FILE - - - name: pepr build --custom-image - generates Kubernetes manifest with a custom image - run: | - cd "${GITHUB_WORKSPACE}" - npx pepr@latest init \ - --name=custom-image \ - --description="custom image test" \ - --errorBehavior=reject \ - --skip-post-init \ - --confirm - cd custom-image - npm i - npx ts-node ../pepr/src/cli.ts build --custom-image pepr:dev - UUID=$(cat package.json | jq -r .pepr.uuid) - count=$(cat dist/$UUID-chart/values.yaml | egrep "image: 'pepr:dev'" | wc -l) - if [ "$count" -eq 2 ]; then - echo "✅ Generated correct image for helm values." - else - echo "❌ Generated incorrect image for helm values." - exit 1 - fi - count=$(cat dist/pepr-module-$UUID.yaml | egrep "pepr:dev" | wc -l) - if [ "$count" -eq 2 ]; then - echo "✅ Generated correct image for Pepr manifest." - else - echo "❌ Generated incorrect image for Pepr manifest." - exit 1 - fi - count=$(cat dist/zarf.yaml | egrep "pepr:dev" | wc -l) - if [ "$count" -eq 1 ]; then - echo "✅ Generated correct image for Zarf manifest." - else - echo "❌ Generated incorrect image for Zarf manifest." - exit 1 - fi - diff --git a/integration/cli/build.test.ts b/integration/cli/build.test.ts index 254865eaf..911498a1f 100644 --- a/integration/cli/build.test.ts +++ b/integration/cli/build.test.ts @@ -18,10 +18,6 @@ const getDepConImg = (deploy: kind.Deployment, container: string): string => { return deploy!.spec!.template!.spec!.containers.filter(f => f.name === container).at(0)!.image!; }; -const getDepImgPull = (deploy: kind.Deployment): string[] => { - return deploy!.spec!.template!.spec!.imagePullSecrets!.map(m => m.name!); -}; - describe("build", () => { const workdir = new Workdir(`${FILE}`, `${HERE}/../testroot/cli`); @@ -29,17 +25,13 @@ describe("build", () => { await workdir.recreate(); }); - it( - "gives command line help", - async () => { - const argz = "--help"; - const res = await pepr.cli(workdir.path(), { cmd: `pepr build ${argz}` }); - expect(res.exitcode).toBe(0); - expect(res.stderr.join("").trim()).toBe(""); - expect(res.stdout.at(0)).toMatch("Usage: pepr build"); - }, - time.toMs("2m"), - ); + it("gives command line help", async () => { + const argz = "--help"; + const res = await pepr.cli(workdir.path(), { cmd: `pepr build ${argz}` }); + expect(res.exitcode).toBe(0); + expect(res.stderr.join("").trim()).toBe(""); + expect(res.stdout.at(0)).toMatch("Usage: pepr build"); + }); describe("builds a module", () => { const moduleSrc = `${workdir.path()}/build-base`; @@ -340,6 +332,10 @@ describe("build", () => { }); it("--withPullSecret, works", async () => { + const getDepImgPull = (deploy: kind.Deployment): string[] => { + return deploy!.spec!.template!.spec!.imagePullSecrets!.map(m => m.name!); + }; + const moduleYaml = await resource.manyFromFile( `${overrides.outputDir}/pepr-module-${uuid}.yaml`, ); From 704a3496b5b1162b58bd3b7eecc8c876ae335c29 Mon Sep 17 00:00:00 2001 From: Barrett LaFrance Date: Mon, 13 Jan 2025 18:22:39 -0600 Subject: [PATCH 30/51] wip: parallelize them tests! --- integration/cli/build.defaults.test.ts | 52 +++ integration/cli/build.help.test.ts | 31 ++ integration/cli/build.noembed.test.ts | 93 +++++ integration/cli/build.nonconflict.test.ts | 187 ++++++++++ integration/cli/build.registryinfo.test.ts | 97 ++++++ integration/cli/build.test.ts | 376 --------------------- integration/cli/build.version.test.ts | 68 ++++ package.json | 2 +- 8 files changed, 529 insertions(+), 377 deletions(-) create mode 100644 integration/cli/build.defaults.test.ts create mode 100644 integration/cli/build.help.test.ts create mode 100644 integration/cli/build.noembed.test.ts create mode 100644 integration/cli/build.nonconflict.test.ts create mode 100644 integration/cli/build.registryinfo.test.ts delete mode 100644 integration/cli/build.test.ts create mode 100644 integration/cli/build.version.test.ts diff --git a/integration/cli/build.defaults.test.ts b/integration/cli/build.defaults.test.ts new file mode 100644 index 000000000..dda7e734c --- /dev/null +++ b/integration/cli/build.defaults.test.ts @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2023-Present The Pepr Authors + +import { beforeAll, describe, expect, it } from "@jest/globals"; +import * as path from "node:path"; +import * as fs from "node:fs/promises"; +import { Workdir } from "../helpers/workdir"; +import * as time from "../helpers/time"; +import * as pepr from "../helpers/pepr"; + +const FILE = path.basename(__filename); +const HERE = __dirname; + +describe("build", () => { + const workdir = new Workdir(`${FILE}`, `${HERE}/../testroot/cli`); + + beforeAll(async () => { + await workdir.recreate(); + }); + + describe("builds a module", () => { + const id = FILE.split(".").at(1); + const mod = `${workdir.path()}/${id}`; + + beforeAll(async () => { + await fs.rm(mod, { recursive: true, force: true }); + const argz = [ + `--name ${id}`, + `--description ${id}`, + `--errorBehavior reject`, + "--confirm", + "--skip-post-init", + ].join(" "); + await pepr.cli(workdir.path(), { cmd: `pepr init ${argz}` }); + await pepr.tgzifyModule(mod); + await pepr.cli(mod, { cmd: `npm install` }); + }, time.toMs("2m")); + + describe("using default build options", () => { + it( + "builds", + async () => { + const build = await pepr.cli(mod, { cmd: `pepr build` }); + expect(build.exitcode).toBe(0); + expect(build.stderr.join("").trim()).toBe(""); + expect(build.stdout.join("").trim()).toContain("K8s resource for the module saved"); + }, + time.toMs("1m"), + ); + }); + }); +}); diff --git a/integration/cli/build.help.test.ts b/integration/cli/build.help.test.ts new file mode 100644 index 000000000..d69c349fb --- /dev/null +++ b/integration/cli/build.help.test.ts @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2023-Present The Pepr Authors + +import { beforeAll, describe, expect, it } from "@jest/globals"; +import * as path from "node:path"; +import { Workdir } from "../helpers/workdir"; +import * as pepr from "../helpers/pepr"; +import * as time from "../helpers/time"; + +const FILE = path.basename(__filename); +const HERE = __dirname; + +describe("build", () => { + const workdir = new Workdir(`${FILE}`, `${HERE}/../testroot/cli`); + + beforeAll(async () => { + await workdir.recreate(); + }); + + it( + "gives command line help", + async () => { + const argz = "--help"; + const res = await pepr.cli(workdir.path(), { cmd: `pepr build ${argz}` }); + expect(res.exitcode).toBe(0); + expect(res.stderr.join("").trim()).toBe(""); + expect(res.stdout.at(0)).toMatch("Usage: pepr build"); + }, + time.toMs("30s"), + ); +}); diff --git a/integration/cli/build.noembed.test.ts b/integration/cli/build.noembed.test.ts new file mode 100644 index 000000000..dba15af49 --- /dev/null +++ b/integration/cli/build.noembed.test.ts @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2023-Present The Pepr Authors + +import { beforeAll, describe, expect, it } from "@jest/globals"; +import * as path from "node:path"; +import * as fs from "node:fs/promises"; +import { Workdir } from "../helpers/workdir"; +import * as time from "../helpers/time"; +import * as pepr from "../helpers/pepr"; +import * as resource from "../helpers/resource"; +import * as file from "../helpers/file"; + +const FILE = path.basename(__filename); +const HERE = __dirname; + +describe("build", () => { + const workdir = new Workdir(`${FILE}`, `${HERE}/../testroot/cli`); + + beforeAll(async () => { + await workdir.recreate(); + }); + + describe("builds a module", () => { + const id = FILE.split(".").at(1); + const mod = `${workdir.path()}/${id}`; + + beforeAll(async () => { + await fs.rm(mod, { recursive: true, force: true }); + const argz = [ + `--name ${id}`, + `--description ${id}`, + `--errorBehavior reject`, + "--confirm", + "--skip-post-init", + ].join(" "); + await pepr.cli(workdir.path(), { cmd: `pepr init ${argz}` }); + await pepr.tgzifyModule(mod); + await pepr.cli(mod, { cmd: `npm install` }); + }, time.toMs("2m")); + + describe("for use as a library", () => { + let packageJson; + let uuid: string; + + it( + "builds", + async () => { + const argz = [`--no-embed`].join(" "); + const build = await pepr.cli(mod, { cmd: `pepr build ${argz}` }); + expect(build.exitcode).toBe(0); + + // TODO: team talk + // Should this be writing to stderr? Even with a 0 exit code..? + expect(build.stderr.join("").trim()).toContain("Error: Cannot find module"); + // TODO: end + + expect(build.stdout.join("").trim()).toContain(""); + + packageJson = await resource.oneFromFile(`${mod}/package.json`); + uuid = packageJson.pepr.uuid; + }, + time.toMs("1m"), + ); + + it( + "outputs appropriate configuration", + async () => { + const missing = [ + `${mod}/dist/pepr-${uuid}.js`, + `${mod}/dist/pepr-${uuid}.js.map`, + `${mod}/dist/pepr-${uuid}.js.LEGAL.txt`, + `${mod}/dist/pepr-module-${uuid}.yaml`, + `${mod}/dist/zarf.yaml`, + `${mod}/dist/${uuid}-chart/`, + ]; + for (const path of missing) { + expect(await file.exists(path)).toBe(false); + } + + const found = [ + `${mod}/dist/pepr.js`, + `${mod}/dist/pepr.js.map`, + `${mod}/dist/pepr.js.LEGAL.txt`, + ]; + for (const path of found) { + expect(await file.exists(path)).toBe(true); + } + }, + time.toMs("1m"), + ); + }); + }); +}); diff --git a/integration/cli/build.nonconflict.test.ts b/integration/cli/build.nonconflict.test.ts new file mode 100644 index 000000000..e3f36e081 --- /dev/null +++ b/integration/cli/build.nonconflict.test.ts @@ -0,0 +1,187 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2023-Present The Pepr Authors + +import { beforeAll, describe, expect, it } from "@jest/globals"; +import * as path from "node:path"; +import * as fs from "node:fs/promises"; +import { kind } from "kubernetes-fluent-client"; +import { Workdir } from "../helpers/workdir"; +import * as time from "../helpers/time"; +import * as pepr from "../helpers/pepr"; +import * as resource from "../helpers/resource"; +import * as file from "../helpers/file"; + +const FILE = path.basename(__filename); +const HERE = __dirname; + +describe("build", () => { + const workdir = new Workdir(`${FILE}`, `${HERE}/../testroot/cli`); + + beforeAll(async () => { + await workdir.recreate(); + }); + + describe("builds a module", () => { + const id = FILE.split(".").at(1); + const mod = `${workdir.path()}/${id}`; + + beforeAll(async () => { + await fs.rm(mod, { recursive: true, force: true }); + const argz = [ + `--name ${id}`, + `--description ${id}`, + `--errorBehavior reject`, + "--confirm", + "--skip-post-init", + ].join(" "); + await pepr.cli(workdir.path(), { cmd: `pepr init ${argz}` }); + await pepr.tgzifyModule(mod); + await pepr.cli(mod, { cmd: `npm install` }); + }, time.toMs("2m")); + + describe("using non-conflicting build override options", () => { + const entryPoint = "pepr2.ts"; + const customImage = "pepr:override"; + const outputDir = `${mod}/out`; + const timeout = 11; + const withPullSecret = "shhh"; + const zarf = "chart"; + + let packageJson; + let uuid: string; + + it( + "builds", + async () => { + await fs.rename(`${mod}/pepr.ts`, `${mod}/${entryPoint}`); + + const argz = [ + `--entry-point ${entryPoint}`, + `--custom-image ${customImage}`, + `--output-dir ${outputDir}`, + `--timeout ${timeout}`, + `--withPullSecret ${withPullSecret}`, + `--zarf ${zarf}`, + ].join(" "); + const build = await pepr.cli(mod, { cmd: `pepr build ${argz}` }); + + expect(build.exitcode).toBe(0); + expect(build.stderr.join("").trim()).toBe(""); + expect(build.stdout.join("").trim()).toContain("K8s resource for the module saved"); + + packageJson = await resource.oneFromFile(`${mod}/package.json`); + uuid = packageJson.pepr.uuid; + }, + time.toMs("1m"), + ); + + const getDepConImg = (deploy: kind.Deployment, container: string): string => { + return deploy!.spec!.template!.spec!.containers.filter(f => f.name === container).at(0)! + .image!; + }; + + it("--entry-point, works", async () => { + // build would fail if given entrypoint didn't exist, so... no-op test! + }); + + it("--output-dir, works", async () => { + const dist = `${mod}/dist`; + expect(await file.exists(dist)).toBe(false); + + const out = outputDir; + expect(await file.exists(out)).toBe(true); + }); + + it("--custom-image, works", async () => { + const moduleYaml = await resource.manyFromFile(`${outputDir}/pepr-module-${uuid}.yaml`); + { + const admission = resource.select(moduleYaml, kind.Deployment, `pepr-${uuid}`); + const admissionImage = getDepConImg(admission, "server"); + expect(admissionImage).toBe(customImage); + + const watcher = resource.select(moduleYaml, kind.Deployment, `pepr-${uuid}-watcher`); + const watcherImage = getDepConImg(watcher, "watcher"); + expect(watcherImage).toBe(customImage); + } + + const zarfYaml = await resource.oneFromFile(`${outputDir}/zarf.yaml`); + { + const componentImage = zarfYaml.components.at(0).images.at(0); + expect(componentImage).toBe(customImage); + } + + const valuesYaml = await resource.oneFromFile(`${outputDir}/${uuid}-chart/values.yaml`); + { + const admissionImage = valuesYaml.admission.image; + expect(admissionImage).toBe(customImage); + + const watcherImage = valuesYaml.watcher.image; + expect(watcherImage).toBe(customImage); + } + }); + + it("--timeout, works", async () => { + const moduleYaml = await resource.manyFromFile(`${outputDir}/pepr-module-${uuid}.yaml`); + { + const mwc = resource.select( + moduleYaml, + kind.MutatingWebhookConfiguration, + `pepr-${uuid}`, + ); + const webhook = mwc.webhooks!.filter(f => f.name === `pepr-${uuid}.pepr.dev`).at(0)!; + expect(webhook.timeoutSeconds).toBe(timeout); + } + { + const mwc = resource.select( + moduleYaml, + kind.ValidatingWebhookConfiguration, + `pepr-${uuid}`, + ); + const webhook = mwc.webhooks!.filter(f => f.name === `pepr-${uuid}.pepr.dev`).at(0)!; + expect(webhook.timeoutSeconds).toBe(timeout); + } + + const valuesYaml = await resource.oneFromFile(`${outputDir}/${uuid}-chart/values.yaml`); + expect(valuesYaml.admission.webhookTimeout).toBe(timeout); + }); + + it("--withPullSecret, works", async () => { + const getDepImgPull = (deploy: kind.Deployment): string[] => { + return deploy!.spec!.template!.spec!.imagePullSecrets!.map(m => m.name!); + }; + + const moduleYaml = await resource.manyFromFile(`${outputDir}/pepr-module-${uuid}.yaml`); + const admission = resource.select(moduleYaml, kind.Deployment, `pepr-${uuid}`); + const admissionSecrets = getDepImgPull(admission); + expect(admissionSecrets).toEqual([withPullSecret]); + + const watcher = resource.select(moduleYaml, kind.Deployment, `pepr-${uuid}-watcher`); + const watcherSecrets = getDepImgPull(watcher); + expect(watcherSecrets).toEqual([withPullSecret]); + + // TODO: team talk + // Image pull secrets don't seem to map into the Helm chart anywhere..? Should they? + // TODO: end + }); + + it("--zarf, works", async () => { + const chart = { + name: "module", + namespace: "pepr-system", + version: "0.0.1", + localPath: `${uuid}-chart`, + }; + + const zarfYaml = await resource.oneFromFile(`${outputDir}/zarf.yaml`); + const component = zarfYaml.components + .filter((f: { name: string }) => f.name === "module") + .at(0); + expect(component.charts).toContainEqual(chart); + }); + + // it("--rbac-mode, ...todo!", async () => { + // --rbac-mode scoped + // } + }); + }); +}); diff --git a/integration/cli/build.registryinfo.test.ts b/integration/cli/build.registryinfo.test.ts new file mode 100644 index 000000000..e49bc171c --- /dev/null +++ b/integration/cli/build.registryinfo.test.ts @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2023-Present The Pepr Authors + +import { beforeAll, describe, expect, it } from "@jest/globals"; +import * as path from "node:path"; +import * as fs from "node:fs/promises"; +import { kind } from "kubernetes-fluent-client"; +import { Workdir } from "../helpers/workdir"; +import * as time from "../helpers/time"; +import * as pepr from "../helpers/pepr"; +import * as resource from "../helpers/resource"; + +const FILE = path.basename(__filename); +const HERE = __dirname; + +describe("build", () => { + const workdir = new Workdir(`${FILE}`, `${HERE}/../testroot/cli`); + + beforeAll(async () => { + await workdir.recreate(); + }); + + describe("builds a module", () => { + const id = FILE.split(".").at(1); + const mod = `${workdir.path()}/${id}`; + + let packageJson; + let uuid: string; + + beforeAll(async () => { + await fs.rm(mod, { recursive: true, force: true }); + const argz = [ + `--name ${id}`, + `--description ${id}`, + `--errorBehavior reject`, + "--confirm", + "--skip-post-init", + ].join(" "); + await pepr.cli(workdir.path(), { cmd: `pepr init ${argz}` }); + await pepr.tgzifyModule(mod); + await pepr.cli(mod, { cmd: `npm install` }); + }, time.toMs("2m")); + + describe("using a custom registry", () => { + const registryInfo = "registry.io/username"; + + const getDepConImg = (deploy: kind.Deployment, container: string): string => { + return deploy!.spec!.template!.spec!.containers.filter(f => f.name === container).at(0)! + .image!; + }; + + it( + "builds", + async () => { + const argz = [`--registry-info ${registryInfo}`].join(" "); + const build = await pepr.cli(mod, { cmd: `pepr build ${argz}` }); + expect(build.exitcode).toBe(0); + expect(build.stderr.join("").trim()).toBe(""); + expect(build.stdout.join("").trim()).toContain("K8s resource for the module saved"); + + packageJson = await resource.oneFromFile(`${mod}/package.json`); + uuid = packageJson.pepr.uuid; + }, + time.toMs("1m"), + ); + + it("outputs appropriate configuration", async () => { + // overwrites --custom-image..? + const image = `${registryInfo}/custom-pepr-controller:0.0.0-development`; + + { + const moduleYaml = await resource.manyFromFile(`${mod}/dist/pepr-module-${uuid}.yaml`); + const admission = resource.select(moduleYaml, kind.Deployment, `pepr-${uuid}`); + const admissionImage = getDepConImg(admission, "server"); + expect(admissionImage).toBe(image); + + const watcher = resource.select(moduleYaml, kind.Deployment, `pepr-${uuid}-watcher`); + const watcherImage = getDepConImg(watcher, "watcher"); + expect(watcherImage).toBe(image); + } + { + const zarfYaml = await resource.oneFromFile(`${mod}/dist/zarf.yaml`); + const componentImage = zarfYaml.components.at(0).images.at(0); + expect(componentImage).toBe(image); + } + { + const valuesYaml = await resource.oneFromFile(`${mod}/dist/${uuid}-chart/values.yaml`); + const admissionImage = valuesYaml.admission.image; + expect(admissionImage).toBe(image); + + const watcherImage = valuesYaml.watcher.image; + expect(watcherImage).toBe(image); + } + }); + }); + }); +}); diff --git a/integration/cli/build.test.ts b/integration/cli/build.test.ts deleted file mode 100644 index 911498a1f..000000000 --- a/integration/cli/build.test.ts +++ /dev/null @@ -1,376 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2023-Present The Pepr Authors - -import { beforeAll, describe, expect, it } from "@jest/globals"; -import * as path from "node:path"; -import * as fs from "node:fs/promises"; -import { kind } from "kubernetes-fluent-client"; -import { Workdir } from "../helpers/workdir"; -import * as time from "../helpers/time"; -import * as pepr from "../helpers/pepr"; -import * as resource from "../helpers/resource"; -import * as file from "../helpers/file"; - -const FILE = path.basename(__filename); -const HERE = __dirname; - -const getDepConImg = (deploy: kind.Deployment, container: string): string => { - return deploy!.spec!.template!.spec!.containers.filter(f => f.name === container).at(0)!.image!; -}; - -describe("build", () => { - const workdir = new Workdir(`${FILE}`, `${HERE}/../testroot/cli`); - - beforeAll(async () => { - await workdir.recreate(); - }); - - it("gives command line help", async () => { - const argz = "--help"; - const res = await pepr.cli(workdir.path(), { cmd: `pepr build ${argz}` }); - expect(res.exitcode).toBe(0); - expect(res.stderr.join("").trim()).toBe(""); - expect(res.stdout.at(0)).toMatch("Usage: pepr build"); - }); - - describe("builds a module", () => { - const moduleSrc = `${workdir.path()}/build-base`; - - beforeAll(async () => { - await fs.rm(moduleSrc, { recursive: true, force: true }); - const argz = [ - `--name build-base`, - `--description description`, - `--errorBehavior reject`, - "--confirm", - "--skip-post-init", - ].join(" "); - await pepr.cli(workdir.path(), { cmd: `pepr init ${argz}` }); - await pepr.tgzifyModule(moduleSrc); - }, time.toMs("2m")); - - describe("using default build options", () => { - it( - "succeeds", - async () => { - const moduleDst = `${workdir.path()}/defaults`; - await pepr.copyModule(moduleSrc, moduleDst); - await pepr.cli(moduleDst, { cmd: `npm install` }); - - const build = await pepr.cli(moduleDst, { cmd: `pepr build` }); - expect(build.exitcode).toBe(0); - expect(build.stderr.join("").trim()).toBe(""); - expect(build.stdout.join("").trim()).toContain("K8s resource for the module saved"); - }, - time.toMs("1m"), - ); - }); - - describe("for use as a library", () => { - const moduleDst = `${workdir.path()}/noembed`; - let packageJson; - let uuid: string; - - beforeAll(async () => { - await pepr.copyModule(moduleSrc, moduleDst); - await pepr.cli(moduleDst, { cmd: `npm install` }); - - const argz = [`--no-embed`].join(" "); - const build = await pepr.cli(moduleDst, { cmd: `pepr build ${argz}` }); - expect(build.exitcode).toBe(0); - - // TODO: team talk - // Should this be writing to stderr? Even with a 0 exit code..? - expect(build.stderr.join("").trim()).toContain("Error: Cannot find module"); - // TODO: end - - expect(build.stdout.join("").trim()).toContain(""); - - packageJson = await resource.oneFromFile(`${moduleDst}/package.json`); - uuid = packageJson.pepr.uuid; - }, time.toMs("1m")); - - it("--no-embed, works", async () => { - // deployable module files - { - const paths = [ - `${moduleDst}/dist/pepr-${uuid}.js`, - `${moduleDst}/dist/pepr-${uuid}.js.map`, - `${moduleDst}/dist/pepr-${uuid}.js.LEGAL.txt`, - `${moduleDst}/dist/pepr-module-${uuid}.yaml`, - ]; - for (const path of paths) { - // await expect(fs.access(path)).rejects.toThrowError("no such file or directory"); - expect(await file.exists(path)).toBe(false); - } - } - - // zarf manifest - { - const path = `${moduleDst}/dist/zarf.yaml`; - expect(await file.exists(path)).toBe(false); - } - - // helm chart - { - const path = `${moduleDst}/dist/${uuid}-chart/`; - expect(await file.exists(path)).toBe(false); - } - - // importable module files - { - const paths = [ - `${moduleDst}/dist/pepr.js`, - `${moduleDst}/dist/pepr.js.map`, - `${moduleDst}/dist/pepr.js.LEGAL.txt`, - ]; - for (const path of paths) { - expect(await file.exists(path)).toBe(true); - } - } - }); - }); - - describe("using a custom registry", () => { - const moduleDst = `${workdir.path()}/reginfo`; - let packageJson; - let uuid: string; - const registryInfo = "registry.io/username"; - - beforeAll(async () => { - await pepr.copyModule(moduleSrc, moduleDst); - await pepr.cli(moduleDst, { cmd: `npm install` }); - - const argz = [`--registry-info ${registryInfo}`].join(" "); - const build = await pepr.cli(moduleDst, { cmd: `pepr build ${argz}` }); - expect(build.exitcode).toBe(0); - expect(build.stderr.join("").trim()).toBe(""); - expect(build.stdout.join("").trim()).toContain("K8s resource for the module saved"); - - packageJson = await resource.oneFromFile(`${moduleDst}/package.json`); - uuid = packageJson.pepr.uuid; - }, time.toMs("1m")); - - it("--registry-info, works", async () => { - // overwrites --custom-image..? - const image = `${registryInfo}/custom-pepr-controller:0.0.0-development`; - - const moduleYaml = await resource.manyFromFile( - `${moduleDst}/dist/pepr-module-${uuid}.yaml`, - ); - { - const admission = resource.select(moduleYaml, kind.Deployment, `pepr-${uuid}`); - const admissionImage = getDepConImg(admission, "server"); - expect(admissionImage).toBe(image); - - const watcher = resource.select(moduleYaml, kind.Deployment, `pepr-${uuid}-watcher`); - const watcherImage = getDepConImg(watcher, "watcher"); - expect(watcherImage).toBe(image); - } - - const zarfYaml = await resource.oneFromFile(`${moduleDst}/dist/zarf.yaml`); - { - const componentImage = zarfYaml.components.at(0).images.at(0); - expect(componentImage).toBe(image); - } - - const valuesYaml = await resource.oneFromFile( - `${moduleDst}/dist/${uuid}-chart/values.yaml`, - ); - { - const admissionImage = valuesYaml.admission.image; - expect(admissionImage).toBe(image); - - const watcherImage = valuesYaml.watcher.image; - expect(watcherImage).toBe(image); - } - }); - }); - - describe("using a specified pepr version", () => { - const moduleDst = `${workdir.path()}/version`; - const cliVersion = "0.0.0-development"; - const version = "1.2.3"; - - beforeAll(async () => { - await pepr.copyModule(moduleSrc, moduleDst); - await pepr.cli(moduleDst, { cmd: `npm install` }); - - const argz = [`--version ${version}`].join(" "); - const build = await pepr.cli(moduleDst, { cmd: `pepr build ${argz}` }); - expect(build.exitcode).toBe(0); - expect(build.stderr.join("").trim()).toBe(""); - expect(build.stdout.join("").trim()).toContain(cliVersion); - }, time.toMs("1m")); - - it("--version, is broken..?", async () => { - // TODO: team talk - // looks like it's just giving back the `pepr --version` then exiting, - // rather than buidling/affecting the output files at all..? - expect(await file.exists(`${moduleDst}/dist`)).toBe(false); - // TODO: end - }); - }); - - describe("using non-conflicting build override options", () => { - const moduleDst = `${workdir.path()}/overrides`; - let packageJson; - let uuid: string; - const overrides = { - entryPoint: "pepr2.ts", - customImage: "pepr:override", - outputDir: `${moduleDst}/out`, - timeout: 11, - withPullSecret: "shhh", - zarf: "chart", - }; - - beforeAll(async () => { - // - // prepare module - // - await pepr.copyModule(moduleSrc, moduleDst); - await pepr.cli(moduleDst, { cmd: `npm install` }); - - // - // establish override-support conditions - // - await fs.rename(`${moduleDst}/pepr.ts`, `${moduleDst}/${overrides.entryPoint}`); - - // - // use overrides - // - const argz = [ - `--entry-point ${overrides.entryPoint}`, - `--custom-image ${overrides.customImage}`, - `--output-dir ${overrides.outputDir}`, - `--timeout ${overrides.timeout}`, - `--withPullSecret ${overrides.withPullSecret}`, - `--zarf ${overrides.zarf}`, - ].join(" "); - const build = await pepr.cli(moduleDst, { cmd: `pepr build ${argz}` }); - - expect(build.exitcode).toBe(0); - expect(build.stderr.join("").trim()).toBe(""); - expect(build.stdout.join("").trim()).toContain("K8s resource for the module saved"); - - packageJson = await resource.oneFromFile(`${moduleDst}/package.json`); - uuid = packageJson.pepr.uuid; - }, time.toMs("1m")); - - it("--entry-point, works", async () => { - // build would fail if given entrypoint didn't exist, so... no-op, right? - }); - - it("--output-dir, works", async () => { - const dist = `${moduleDst}/dist`; - expect(await file.exists(dist)).toBe(false); - - const out = overrides.outputDir; - expect(await file.exists(out)).toBe(true); - }); - - it("--custom-image, works", async () => { - const moduleYaml = await resource.manyFromFile( - `${overrides.outputDir}/pepr-module-${uuid}.yaml`, - ); - { - const admission = resource.select(moduleYaml, kind.Deployment, `pepr-${uuid}`); - const admissionImage = getDepConImg(admission, "server"); - expect(admissionImage).toBe(overrides.customImage); - - const watcher = resource.select(moduleYaml, kind.Deployment, `pepr-${uuid}-watcher`); - const watcherImage = getDepConImg(watcher, "watcher"); - expect(watcherImage).toBe(overrides.customImage); - } - - const zarfYaml = await resource.oneFromFile(`${overrides.outputDir}/zarf.yaml`); - { - const componentImage = zarfYaml.components.at(0).images.at(0); - expect(componentImage).toBe(overrides.customImage); - } - - const valuesYaml = await resource.oneFromFile( - `${overrides.outputDir}/${uuid}-chart/values.yaml`, - ); - { - const admissionImage = valuesYaml.admission.image; - expect(admissionImage).toBe(overrides.customImage); - - const watcherImage = valuesYaml.watcher.image; - expect(watcherImage).toBe(overrides.customImage); - } - }); - - it("--timeout, works", async () => { - const moduleYaml = await resource.manyFromFile( - `${overrides.outputDir}/pepr-module-${uuid}.yaml`, - ); - { - const mwc = resource.select( - moduleYaml, - kind.MutatingWebhookConfiguration, - `pepr-${uuid}`, - ); - const webhook = mwc.webhooks!.filter(f => f.name === `pepr-${uuid}.pepr.dev`).at(0)!; - expect(webhook.timeoutSeconds).toBe(overrides.timeout); - } - { - const mwc = resource.select( - moduleYaml, - kind.ValidatingWebhookConfiguration, - `pepr-${uuid}`, - ); - const webhook = mwc.webhooks!.filter(f => f.name === `pepr-${uuid}.pepr.dev`).at(0)!; - expect(webhook.timeoutSeconds).toBe(overrides.timeout); - } - - const valuesYaml = await resource.oneFromFile( - `${overrides.outputDir}/${uuid}-chart/values.yaml`, - ); - expect(valuesYaml.admission.webhookTimeout).toBe(overrides.timeout); - }); - - it("--withPullSecret, works", async () => { - const getDepImgPull = (deploy: kind.Deployment): string[] => { - return deploy!.spec!.template!.spec!.imagePullSecrets!.map(m => m.name!); - }; - - const moduleYaml = await resource.manyFromFile( - `${overrides.outputDir}/pepr-module-${uuid}.yaml`, - ); - { - const admission = resource.select(moduleYaml, kind.Deployment, `pepr-${uuid}`); - const admissionSecrets = getDepImgPull(admission); - expect(admissionSecrets).toEqual([overrides.withPullSecret]); - - const watcher = resource.select(moduleYaml, kind.Deployment, `pepr-${uuid}-watcher`); - const watcherSecrets = getDepImgPull(watcher); - expect(watcherSecrets).toEqual([overrides.withPullSecret]); - } - // TODO: team talk - // Image pull secrets don't seem to map into the Helm chart anywhere..? Should they? - // TODO: end - }); - - it("--zarf, works", async () => { - const chart = { - name: "module", - namespace: "pepr-system", - version: "0.0.1", - localPath: `${uuid}-chart`, - }; - - const zarfYaml = await resource.oneFromFile(`${overrides.outputDir}/zarf.yaml`); - const component = zarfYaml.components - .filter((f: { name: string }) => f.name === "module") - .at(0); - expect(component.charts).toContainEqual(chart); - }); - - // it("--rbac-mode, ...todo!", async () => { - // --rbac-mode scoped - // } - }); - }); -}); diff --git a/integration/cli/build.version.test.ts b/integration/cli/build.version.test.ts new file mode 100644 index 000000000..ec174d8e8 --- /dev/null +++ b/integration/cli/build.version.test.ts @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2023-Present The Pepr Authors + +import { beforeAll, describe, expect, it } from "@jest/globals"; +import * as path from "node:path"; +import * as fs from "node:fs/promises"; +import { Workdir } from "../helpers/workdir"; +import * as time from "../helpers/time"; +import * as pepr from "../helpers/pepr"; +import * as file from "../helpers/file"; + +const FILE = path.basename(__filename); +const HERE = __dirname; + +describe("build", () => { + const workdir = new Workdir(`${FILE}`, `${HERE}/../testroot/cli`); + + beforeAll(async () => { + await workdir.recreate(); + }); + + describe("builds a module", () => { + const id = FILE.split(".").at(1); + const mod = `${workdir.path()}/${id}`; + + beforeAll(async () => { + await fs.rm(mod, { recursive: true, force: true }); + const argz = [ + `--name ${id}`, + `--description ${id}`, + `--errorBehavior reject`, + "--confirm", + "--skip-post-init", + ].join(" "); + await pepr.cli(workdir.path(), { cmd: `pepr init ${argz}` }); + await pepr.tgzifyModule(mod); + await pepr.cli(mod, { cmd: `npm install` }); + }, time.toMs("2m")); + + describe("using a specified pepr version", () => { + const cliVersion = "0.0.0-development"; + const version = "1.2.3"; + + it( + "builds", + async () => { + const argz = [`--version ${version}`].join(" "); + const build = await pepr.cli(mod, { cmd: `pepr build ${argz}` }); + expect(build.exitcode).toBe(0); + expect(build.stderr.join("").trim()).toBe(""); + expect(build.stdout.join("").trim()).toContain(cliVersion); + + // TODO: team talk + // looks like it's just giving back the `pepr --version` then exiting, + // rather than buidling/affecting the output files at all..? + expect(await file.exists(`${mod}/dist`)).toBe(false); + // TODO: end + }, + time.toMs("1m"), + ); + + // it( + // "outputs appropriate configuration", + // async () => { /* TOOD? */ } + // ); + }); + }); +}); diff --git a/package.json b/package.json index 86c3e12f8..56c5e73d5 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "test:unit": "npm run gen-data-json && jest src --coverage --detectOpenHandles --coverageDirectory=./coverage --testPathIgnorePatterns='cosign.e2e.test.ts'", "test:int": "npm run test:int:prep && npm run test:int:run", "test:int:prep": "./integration/prep.sh", - "test:int:run": "jest integration", + "test:int:run": "jest --maxWorkers=4 integration", "test:journey": "npm run test:journey:k3d && npm run build && npm run test:journey:image && npm run test:journey:run", "test:journey:prep": "if [ ! -d ./pepr-upgrade-test ]; then git clone https://github.com/defenseunicorns/pepr-upgrade-test.git ; fi", "test:journey-wasm": "npm run test:journey:k3d && npm run build && npm run test:journey:image && npm run test:journey:run-wasm", From 9709182d1c64add2e21f0725ee8cc9cf8c29f9a9 Mon Sep 17 00:00:00 2001 From: Barrett LaFrance Date: Tue, 14 Jan 2025 06:58:43 -0600 Subject: [PATCH 31/51] wip: rm redundant CI test file --- .github/workflows/cli-tests.yml | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 .github/workflows/cli-tests.yml diff --git a/.github/workflows/cli-tests.yml b/.github/workflows/cli-tests.yml deleted file mode 100644 index e69de29bb..000000000 From eab67ae7ba0278841dbe6fbdcbe6d553619e779e Mon Sep 17 00:00:00 2001 From: Barrett LaFrance Date: Tue, 14 Jan 2025 14:03:30 -0600 Subject: [PATCH 32/51] wip: PR feedback - swap 'testModule' for 'mod' --- integration/cli/build.defaults.test.ts | 10 ++++---- integration/cli/build.noembed.test.ts | 30 +++++++++++----------- integration/cli/build.nonconflict.test.ts | 18 ++++++------- integration/cli/build.registryinfo.test.ts | 22 +++++++++------- integration/cli/build.version.test.ts | 12 ++++----- 5 files changed, 48 insertions(+), 44 deletions(-) diff --git a/integration/cli/build.defaults.test.ts b/integration/cli/build.defaults.test.ts index dda7e734c..7d6175d2d 100644 --- a/integration/cli/build.defaults.test.ts +++ b/integration/cli/build.defaults.test.ts @@ -20,10 +20,10 @@ describe("build", () => { describe("builds a module", () => { const id = FILE.split(".").at(1); - const mod = `${workdir.path()}/${id}`; + const testModule = `${workdir.path()}/${id}`; beforeAll(async () => { - await fs.rm(mod, { recursive: true, force: true }); + await fs.rm(testModule, { recursive: true, force: true }); const argz = [ `--name ${id}`, `--description ${id}`, @@ -32,15 +32,15 @@ describe("build", () => { "--skip-post-init", ].join(" "); await pepr.cli(workdir.path(), { cmd: `pepr init ${argz}` }); - await pepr.tgzifyModule(mod); - await pepr.cli(mod, { cmd: `npm install` }); + await pepr.tgzifyModule(testModule); + await pepr.cli(testModule, { cmd: `npm install` }); }, time.toMs("2m")); describe("using default build options", () => { it( "builds", async () => { - const build = await pepr.cli(mod, { cmd: `pepr build` }); + const build = await pepr.cli(testModule, { cmd: `pepr build` }); expect(build.exitcode).toBe(0); expect(build.stderr.join("").trim()).toBe(""); expect(build.stdout.join("").trim()).toContain("K8s resource for the module saved"); diff --git a/integration/cli/build.noembed.test.ts b/integration/cli/build.noembed.test.ts index dba15af49..ef25184c4 100644 --- a/integration/cli/build.noembed.test.ts +++ b/integration/cli/build.noembed.test.ts @@ -22,10 +22,10 @@ describe("build", () => { describe("builds a module", () => { const id = FILE.split(".").at(1); - const mod = `${workdir.path()}/${id}`; + const testModule = `${workdir.path()}/${id}`; beforeAll(async () => { - await fs.rm(mod, { recursive: true, force: true }); + await fs.rm(testModule, { recursive: true, force: true }); const argz = [ `--name ${id}`, `--description ${id}`, @@ -34,8 +34,8 @@ describe("build", () => { "--skip-post-init", ].join(" "); await pepr.cli(workdir.path(), { cmd: `pepr init ${argz}` }); - await pepr.tgzifyModule(mod); - await pepr.cli(mod, { cmd: `npm install` }); + await pepr.tgzifyModule(testModule); + await pepr.cli(testModule, { cmd: `npm install` }); }, time.toMs("2m")); describe("for use as a library", () => { @@ -46,7 +46,7 @@ describe("build", () => { "builds", async () => { const argz = [`--no-embed`].join(" "); - const build = await pepr.cli(mod, { cmd: `pepr build ${argz}` }); + const build = await pepr.cli(testModule, { cmd: `pepr build ${argz}` }); expect(build.exitcode).toBe(0); // TODO: team talk @@ -56,7 +56,7 @@ describe("build", () => { expect(build.stdout.join("").trim()).toContain(""); - packageJson = await resource.oneFromFile(`${mod}/package.json`); + packageJson = await resource.oneFromFile(`${testModule}/package.json`); uuid = packageJson.pepr.uuid; }, time.toMs("1m"), @@ -66,21 +66,21 @@ describe("build", () => { "outputs appropriate configuration", async () => { const missing = [ - `${mod}/dist/pepr-${uuid}.js`, - `${mod}/dist/pepr-${uuid}.js.map`, - `${mod}/dist/pepr-${uuid}.js.LEGAL.txt`, - `${mod}/dist/pepr-module-${uuid}.yaml`, - `${mod}/dist/zarf.yaml`, - `${mod}/dist/${uuid}-chart/`, + `${testModule}/dist/pepr-${uuid}.js`, + `${testModule}/dist/pepr-${uuid}.js.map`, + `${testModule}/dist/pepr-${uuid}.js.LEGAL.txt`, + `${testModule}/dist/pepr-module-${uuid}.yaml`, + `${testModule}/dist/zarf.yaml`, + `${testModule}/dist/${uuid}-chart/`, ]; for (const path of missing) { expect(await file.exists(path)).toBe(false); } const found = [ - `${mod}/dist/pepr.js`, - `${mod}/dist/pepr.js.map`, - `${mod}/dist/pepr.js.LEGAL.txt`, + `${testModule}/dist/pepr.js`, + `${testModule}/dist/pepr.js.map`, + `${testModule}/dist/pepr.js.LEGAL.txt`, ]; for (const path of found) { expect(await file.exists(path)).toBe(true); diff --git a/integration/cli/build.nonconflict.test.ts b/integration/cli/build.nonconflict.test.ts index e3f36e081..59b0784f5 100644 --- a/integration/cli/build.nonconflict.test.ts +++ b/integration/cli/build.nonconflict.test.ts @@ -23,10 +23,10 @@ describe("build", () => { describe("builds a module", () => { const id = FILE.split(".").at(1); - const mod = `${workdir.path()}/${id}`; + const testModule = `${workdir.path()}/${id}`; beforeAll(async () => { - await fs.rm(mod, { recursive: true, force: true }); + await fs.rm(testModule, { recursive: true, force: true }); const argz = [ `--name ${id}`, `--description ${id}`, @@ -35,14 +35,14 @@ describe("build", () => { "--skip-post-init", ].join(" "); await pepr.cli(workdir.path(), { cmd: `pepr init ${argz}` }); - await pepr.tgzifyModule(mod); - await pepr.cli(mod, { cmd: `npm install` }); + await pepr.tgzifyModule(testModule); + await pepr.cli(testModule, { cmd: `npm install` }); }, time.toMs("2m")); describe("using non-conflicting build override options", () => { const entryPoint = "pepr2.ts"; const customImage = "pepr:override"; - const outputDir = `${mod}/out`; + const outputDir = `${testModule}/out`; const timeout = 11; const withPullSecret = "shhh"; const zarf = "chart"; @@ -53,7 +53,7 @@ describe("build", () => { it( "builds", async () => { - await fs.rename(`${mod}/pepr.ts`, `${mod}/${entryPoint}`); + await fs.rename(`${testModule}/pepr.ts`, `${testModule}/${entryPoint}`); const argz = [ `--entry-point ${entryPoint}`, @@ -63,13 +63,13 @@ describe("build", () => { `--withPullSecret ${withPullSecret}`, `--zarf ${zarf}`, ].join(" "); - const build = await pepr.cli(mod, { cmd: `pepr build ${argz}` }); + const build = await pepr.cli(testModule, { cmd: `pepr build ${argz}` }); expect(build.exitcode).toBe(0); expect(build.stderr.join("").trim()).toBe(""); expect(build.stdout.join("").trim()).toContain("K8s resource for the module saved"); - packageJson = await resource.oneFromFile(`${mod}/package.json`); + packageJson = await resource.oneFromFile(`${testModule}/package.json`); uuid = packageJson.pepr.uuid; }, time.toMs("1m"), @@ -85,7 +85,7 @@ describe("build", () => { }); it("--output-dir, works", async () => { - const dist = `${mod}/dist`; + const dist = `${testModule}/dist`; expect(await file.exists(dist)).toBe(false); const out = outputDir; diff --git a/integration/cli/build.registryinfo.test.ts b/integration/cli/build.registryinfo.test.ts index e49bc171c..f5a526523 100644 --- a/integration/cli/build.registryinfo.test.ts +++ b/integration/cli/build.registryinfo.test.ts @@ -22,13 +22,13 @@ describe("build", () => { describe("builds a module", () => { const id = FILE.split(".").at(1); - const mod = `${workdir.path()}/${id}`; + const testModule = `${workdir.path()}/${id}`; let packageJson; let uuid: string; beforeAll(async () => { - await fs.rm(mod, { recursive: true, force: true }); + await fs.rm(testModule, { recursive: true, force: true }); const argz = [ `--name ${id}`, `--description ${id}`, @@ -37,8 +37,8 @@ describe("build", () => { "--skip-post-init", ].join(" "); await pepr.cli(workdir.path(), { cmd: `pepr init ${argz}` }); - await pepr.tgzifyModule(mod); - await pepr.cli(mod, { cmd: `npm install` }); + await pepr.tgzifyModule(testModule); + await pepr.cli(testModule, { cmd: `npm install` }); }, time.toMs("2m")); describe("using a custom registry", () => { @@ -53,12 +53,12 @@ describe("build", () => { "builds", async () => { const argz = [`--registry-info ${registryInfo}`].join(" "); - const build = await pepr.cli(mod, { cmd: `pepr build ${argz}` }); + const build = await pepr.cli(testModule, { cmd: `pepr build ${argz}` }); expect(build.exitcode).toBe(0); expect(build.stderr.join("").trim()).toBe(""); expect(build.stdout.join("").trim()).toContain("K8s resource for the module saved"); - packageJson = await resource.oneFromFile(`${mod}/package.json`); + packageJson = await resource.oneFromFile(`${testModule}/package.json`); uuid = packageJson.pepr.uuid; }, time.toMs("1m"), @@ -69,7 +69,9 @@ describe("build", () => { const image = `${registryInfo}/custom-pepr-controller:0.0.0-development`; { - const moduleYaml = await resource.manyFromFile(`${mod}/dist/pepr-module-${uuid}.yaml`); + const moduleYaml = await resource.manyFromFile( + `${testModule}/dist/pepr-module-${uuid}.yaml`, + ); const admission = resource.select(moduleYaml, kind.Deployment, `pepr-${uuid}`); const admissionImage = getDepConImg(admission, "server"); expect(admissionImage).toBe(image); @@ -79,12 +81,14 @@ describe("build", () => { expect(watcherImage).toBe(image); } { - const zarfYaml = await resource.oneFromFile(`${mod}/dist/zarf.yaml`); + const zarfYaml = await resource.oneFromFile(`${testModule}/dist/zarf.yaml`); const componentImage = zarfYaml.components.at(0).images.at(0); expect(componentImage).toBe(image); } { - const valuesYaml = await resource.oneFromFile(`${mod}/dist/${uuid}-chart/values.yaml`); + const valuesYaml = await resource.oneFromFile( + `${testModule}/dist/${uuid}-chart/values.yaml`, + ); const admissionImage = valuesYaml.admission.image; expect(admissionImage).toBe(image); diff --git a/integration/cli/build.version.test.ts b/integration/cli/build.version.test.ts index ec174d8e8..ed7d74961 100644 --- a/integration/cli/build.version.test.ts +++ b/integration/cli/build.version.test.ts @@ -21,10 +21,10 @@ describe("build", () => { describe("builds a module", () => { const id = FILE.split(".").at(1); - const mod = `${workdir.path()}/${id}`; + const testModule = `${workdir.path()}/${id}`; beforeAll(async () => { - await fs.rm(mod, { recursive: true, force: true }); + await fs.rm(testModule, { recursive: true, force: true }); const argz = [ `--name ${id}`, `--description ${id}`, @@ -33,8 +33,8 @@ describe("build", () => { "--skip-post-init", ].join(" "); await pepr.cli(workdir.path(), { cmd: `pepr init ${argz}` }); - await pepr.tgzifyModule(mod); - await pepr.cli(mod, { cmd: `npm install` }); + await pepr.tgzifyModule(testModule); + await pepr.cli(testModule, { cmd: `npm install` }); }, time.toMs("2m")); describe("using a specified pepr version", () => { @@ -45,7 +45,7 @@ describe("build", () => { "builds", async () => { const argz = [`--version ${version}`].join(" "); - const build = await pepr.cli(mod, { cmd: `pepr build ${argz}` }); + const build = await pepr.cli(testModule, { cmd: `pepr build ${argz}` }); expect(build.exitcode).toBe(0); expect(build.stderr.join("").trim()).toBe(""); expect(build.stdout.join("").trim()).toContain(cliVersion); @@ -53,7 +53,7 @@ describe("build", () => { // TODO: team talk // looks like it's just giving back the `pepr --version` then exiting, // rather than buidling/affecting the output files at all..? - expect(await file.exists(`${mod}/dist`)).toBe(false); + expect(await file.exists(`${testModule}/dist`)).toBe(false); // TODO: end }, time.toMs("1m"), From 76d65101a4b198e84c867f3cab024d6a92faa879 Mon Sep 17 00:00:00 2001 From: Barrett LaFrance Date: Tue, 14 Jan 2025 14:05:54 -0600 Subject: [PATCH 33/51] wip: PR feedback - swap 'test:integration' for 'test:int' --- package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 56c5e73d5..2b5c7fc19 100644 --- a/package.json +++ b/package.json @@ -27,9 +27,9 @@ "build:image": "npm run build && docker buildx build --output type=docker --tag pepr:dev .", "test": "npm run test:unit && npm run test:journey", "test:unit": "npm run gen-data-json && jest src --coverage --detectOpenHandles --coverageDirectory=./coverage --testPathIgnorePatterns='cosign.e2e.test.ts'", - "test:int": "npm run test:int:prep && npm run test:int:run", - "test:int:prep": "./integration/prep.sh", - "test:int:run": "jest --maxWorkers=4 integration", + "test:integration": "npm run test:integration:prep && npm run test:integration:run", + "test:integration:prep": "./integration/prep.sh", + "test:integration:run": "jest --maxWorkers=4 integration", "test:journey": "npm run test:journey:k3d && npm run build && npm run test:journey:image && npm run test:journey:run", "test:journey:prep": "if [ ! -d ./pepr-upgrade-test ]; then git clone https://github.com/defenseunicorns/pepr-upgrade-test.git ; fi", "test:journey-wasm": "npm run test:journey:k3d && npm run build && npm run test:journey:image && npm run test:journey:run-wasm", From 8245518fa0571661302b54a1c1c9757602fce3ff Mon Sep 17 00:00:00 2001 From: Barrett LaFrance Date: Tue, 14 Jan 2025 14:06:40 -0600 Subject: [PATCH 34/51] wip: PR feedback - swap 'test:integration' for 'test:int' --- .github/workflows/node.js.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index df5fa2654..a1a4bb918 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -61,7 +61,7 @@ jobs: version: v3.3.4 - run: npm ci - - run: npm run test:int + - run: npm run test:integration journey: runs-on: ubuntu-latest From ff9ca16fa64d8c51b598c75fa888189b1a01629c Mon Sep 17 00:00:00 2001 From: Barrett LaFrance Date: Tue, 14 Jan 2025 14:13:27 -0600 Subject: [PATCH 35/51] wip: PR feedback - swap 'result' for 'res' --- integration/cli/build.help.test.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/integration/cli/build.help.test.ts b/integration/cli/build.help.test.ts index d69c349fb..2824e24c1 100644 --- a/integration/cli/build.help.test.ts +++ b/integration/cli/build.help.test.ts @@ -21,10 +21,10 @@ describe("build", () => { "gives command line help", async () => { const argz = "--help"; - const res = await pepr.cli(workdir.path(), { cmd: `pepr build ${argz}` }); - expect(res.exitcode).toBe(0); - expect(res.stderr.join("").trim()).toBe(""); - expect(res.stdout.at(0)).toMatch("Usage: pepr build"); + const result = await pepr.cli(workdir.path(), { cmd: `pepr build ${argz}` }); + expect(result.exitcode).toBe(0); + expect(result.stderr.join("").trim()).toBe(""); + expect(result.stdout.at(0)).toMatch("Usage: pepr build"); }, time.toMs("30s"), ); From a6abee2523895bfe78c30b328a9f1f943855dd0d Mon Sep 17 00:00:00 2001 From: Barrett LaFrance Date: Tue, 14 Jan 2025 14:14:55 -0600 Subject: [PATCH 36/51] wip: PR feedback - swap 'result' for 'res' --- integration/cli/init.test.ts | 16 ++++++++-------- integration/helpers/file.test.ts | 8 ++++---- integration/helpers/pepr.test.ts | 8 ++++---- integration/helpers/resource.test.ts | 24 ++++++++++++------------ 4 files changed, 28 insertions(+), 28 deletions(-) diff --git a/integration/cli/init.test.ts b/integration/cli/init.test.ts index bff0491dd..c8be64776 100644 --- a/integration/cli/init.test.ts +++ b/integration/cli/init.test.ts @@ -22,10 +22,10 @@ describe("init", () => { "gives command line help", async () => { const argz = "--help"; - const res = await pepr.cli(workdir.path(), { cmd: `pepr init ${argz}` }); - expect(res.exitcode).toBe(0); - expect(res.stderr.join("").trim()).toBe(""); - expect(res.stdout.at(0)).toMatch("Usage: pepr init"); + const result = await pepr.cli(workdir.path(), { cmd: `pepr init ${argz}` }); + expect(result.exitcode).toBe(0); + expect(result.stderr.join("").trim()).toBe(""); + expect(result.stdout.at(0)).toMatch("Usage: pepr init"); }, time.toMs("2m"), ); @@ -43,10 +43,10 @@ describe("init", () => { "--confirm", "--skip-post-init", ].join(" "); - const res = await pepr.cli(workdir.path(), { cmd: `pepr init ${argz}` }); - expect(res.exitcode).toBe(0); - expect(res.stderr.join("").trim()).toBe(""); - expect(res.stdout.join("").trim()).toContain("New Pepr module created"); + const result = await pepr.cli(workdir.path(), { cmd: `pepr init ${argz}` }); + expect(result.exitcode).toBe(0); + expect(result.stderr.join("").trim()).toBe(""); + expect(result.stdout.join("").trim()).toContain("New Pepr module created"); const packageJson = JSON.parse( await fs.readFile(`${workdir.path()}/${name}/package.json`, { encoding: "utf8" }), diff --git a/integration/helpers/file.test.ts b/integration/helpers/file.test.ts index 6597befae..ba872ca16 100644 --- a/integration/helpers/file.test.ts +++ b/integration/helpers/file.test.ts @@ -17,12 +17,12 @@ describe("exists", () => { }); it("returns true when exists", async () => { - const res = await sut.exists(real); - expect(res).toBe(true); + const result = await sut.exists(real); + expect(result).toBe(true); }); it("returns false when missing", async () => { - const res = await sut.exists(`${real}.nope`); - expect(res).toBe(false); + const result = await sut.exists(`${real}.nope`); + expect(result).toBe(false); }); }); diff --git a/integration/helpers/pepr.test.ts b/integration/helpers/pepr.test.ts index 81a8c58ec..8332d1ba2 100644 --- a/integration/helpers/pepr.test.ts +++ b/integration/helpers/pepr.test.ts @@ -78,10 +78,10 @@ describe("pepr", () => { it( "can invoke pepr command via .tgz", async () => { - const res = await sut.cli(workdir.path(), { cmd: "pepr --version" }); - expect(res.exitcode).toBe(0); - expect(res.stderr.join("").trim()).toBe(""); - expect(res.stdout.join("").trim()).toBe("0.0.0-development"); + const result = await sut.cli(workdir.path(), { cmd: "pepr --version" }); + expect(result.exitcode).toBe(0); + expect(result.stderr.join("").trim()).toBe(""); + expect(result.stdout.join("").trim()).toBe("0.0.0-development"); }, time.toMs("2m"), ); diff --git a/integration/helpers/resource.test.ts b/integration/helpers/resource.test.ts index a7b100b95..787737b7a 100644 --- a/integration/helpers/resource.test.ts +++ b/integration/helpers/resource.test.ts @@ -28,8 +28,8 @@ describe("oneFromFile", () => { } `, ); - const res = await sut.oneFromFile(oneJson); - expect(res.one).toBe("json"); + const result = await sut.oneFromFile(oneJson); + expect(result.one).toBe("json"); }); it("can load one resource from .yaml file", async () => { @@ -41,8 +41,8 @@ describe("oneFromFile", () => { one: yaml `, ); - const res = await sut.oneFromFile(oneYaml); - expect(res.one).toBe("yaml"); + const result = await sut.oneFromFile(oneYaml); + expect(result.one).toBe("yaml"); }); }); @@ -65,10 +65,10 @@ describe("manyFromFile", () => { ] `, ); - const res = await sut.manyFromFile(manyJson); - expect(res.at(0).one).toBe("json"); - expect(res.at(1).two).toBe("json"); - expect(res.at(2).three).toBe("json"); + const result = await sut.manyFromFile(manyJson); + expect(result.at(0).one).toBe("json"); + expect(result.at(1).two).toBe("json"); + expect(result.at(2).three).toBe("json"); }); it("can load many resources from .yaml file", async () => { @@ -84,10 +84,10 @@ describe("manyFromFile", () => { three: yaml `, ); - const res = await sut.manyFromFile(manyYaml); - expect(res.at(0).one).toBe("yaml"); - expect(res.at(1).two).toBe("yaml"); - expect(res.at(2).three).toBe("yaml"); + const result = await sut.manyFromFile(manyYaml); + expect(result.at(0).one).toBe("yaml"); + expect(result.at(1).two).toBe("yaml"); + expect(result.at(2).three).toBe("yaml"); }); }); From b8b84a64548910e3da769392ffdaf39928c55798 Mon Sep 17 00:00:00 2001 From: Barrett LaFrance Date: Tue, 14 Jan 2025 14:29:38 -0600 Subject: [PATCH 37/51] wip: PR feedback - remove 'TODO' comments --- integration/cli/build.noembed.test.ts | 5 ----- integration/cli/build.nonconflict.test.ts | 4 ---- integration/cli/build.version.test.ts | 9 --------- 3 files changed, 18 deletions(-) diff --git a/integration/cli/build.noembed.test.ts b/integration/cli/build.noembed.test.ts index ef25184c4..6b06c3f47 100644 --- a/integration/cli/build.noembed.test.ts +++ b/integration/cli/build.noembed.test.ts @@ -48,12 +48,7 @@ describe("build", () => { const argz = [`--no-embed`].join(" "); const build = await pepr.cli(testModule, { cmd: `pepr build ${argz}` }); expect(build.exitcode).toBe(0); - - // TODO: team talk - // Should this be writing to stderr? Even with a 0 exit code..? expect(build.stderr.join("").trim()).toContain("Error: Cannot find module"); - // TODO: end - expect(build.stdout.join("").trim()).toContain(""); packageJson = await resource.oneFromFile(`${testModule}/package.json`); diff --git a/integration/cli/build.nonconflict.test.ts b/integration/cli/build.nonconflict.test.ts index 59b0784f5..331f1dc9f 100644 --- a/integration/cli/build.nonconflict.test.ts +++ b/integration/cli/build.nonconflict.test.ts @@ -158,10 +158,6 @@ describe("build", () => { const watcher = resource.select(moduleYaml, kind.Deployment, `pepr-${uuid}-watcher`); const watcherSecrets = getDepImgPull(watcher); expect(watcherSecrets).toEqual([withPullSecret]); - - // TODO: team talk - // Image pull secrets don't seem to map into the Helm chart anywhere..? Should they? - // TODO: end }); it("--zarf, works", async () => { diff --git a/integration/cli/build.version.test.ts b/integration/cli/build.version.test.ts index ed7d74961..2b38f5ae7 100644 --- a/integration/cli/build.version.test.ts +++ b/integration/cli/build.version.test.ts @@ -50,19 +50,10 @@ describe("build", () => { expect(build.stderr.join("").trim()).toBe(""); expect(build.stdout.join("").trim()).toContain(cliVersion); - // TODO: team talk - // looks like it's just giving back the `pepr --version` then exiting, - // rather than buidling/affecting the output files at all..? expect(await file.exists(`${testModule}/dist`)).toBe(false); - // TODO: end }, time.toMs("1m"), ); - - // it( - // "outputs appropriate configuration", - // async () => { /* TOOD? */ } - // ); }); }); }); From a1995fe92888cc25f7f4c101ca545635930db374 Mon Sep 17 00:00:00 2001 From: Barrett LaFrance Date: Tue, 14 Jan 2025 14:42:33 -0600 Subject: [PATCH 38/51] wip: PR feedback - remove intermediate local var --- integration/cli/build.nonconflict.test.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/integration/cli/build.nonconflict.test.ts b/integration/cli/build.nonconflict.test.ts index 331f1dc9f..d5530b605 100644 --- a/integration/cli/build.nonconflict.test.ts +++ b/integration/cli/build.nonconflict.test.ts @@ -88,8 +88,7 @@ describe("build", () => { const dist = `${testModule}/dist`; expect(await file.exists(dist)).toBe(false); - const out = outputDir; - expect(await file.exists(out)).toBe(true); + expect(await file.exists(outputDir)).toBe(true); }); it("--custom-image, works", async () => { From 1dbaca5c023186b448b0a42e260384c91a3534cb Mon Sep 17 00:00:00 2001 From: Barrett LaFrance Date: Tue, 14 Jan 2025 14:58:54 -0600 Subject: [PATCH 39/51] wip: PR feedback - expand filter func args --- integration/cli/build.nonconflict.test.ts | 15 ++++++++++----- integration/cli/build.registryinfo.test.ts | 5 +++-- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/integration/cli/build.nonconflict.test.ts b/integration/cli/build.nonconflict.test.ts index d5530b605..0e7fcce9f 100644 --- a/integration/cli/build.nonconflict.test.ts +++ b/integration/cli/build.nonconflict.test.ts @@ -76,8 +76,9 @@ describe("build", () => { ); const getDepConImg = (deploy: kind.Deployment, container: string): string => { - return deploy!.spec!.template!.spec!.containers.filter(f => f.name === container).at(0)! - .image!; + return deploy! + .spec!.template!.spec!.containers.filter(cont => cont.name === container) + .at(0)!.image!; }; it("--entry-point, works", async () => { @@ -127,7 +128,9 @@ describe("build", () => { kind.MutatingWebhookConfiguration, `pepr-${uuid}`, ); - const webhook = mwc.webhooks!.filter(f => f.name === `pepr-${uuid}.pepr.dev`).at(0)!; + const webhook = mwc + .webhooks!.filter(hook => hook.name === `pepr-${uuid}.pepr.dev`) + .at(0)!; expect(webhook.timeoutSeconds).toBe(timeout); } { @@ -136,7 +139,9 @@ describe("build", () => { kind.ValidatingWebhookConfiguration, `pepr-${uuid}`, ); - const webhook = mwc.webhooks!.filter(f => f.name === `pepr-${uuid}.pepr.dev`).at(0)!; + const webhook = mwc + .webhooks!.filter(hook => hook.name === `pepr-${uuid}.pepr.dev`) + .at(0)!; expect(webhook.timeoutSeconds).toBe(timeout); } @@ -169,7 +174,7 @@ describe("build", () => { const zarfYaml = await resource.oneFromFile(`${outputDir}/zarf.yaml`); const component = zarfYaml.components - .filter((f: { name: string }) => f.name === "module") + .filter((component: { name: string }) => component.name === "module") .at(0); expect(component.charts).toContainEqual(chart); }); diff --git a/integration/cli/build.registryinfo.test.ts b/integration/cli/build.registryinfo.test.ts index f5a526523..2ce6c8343 100644 --- a/integration/cli/build.registryinfo.test.ts +++ b/integration/cli/build.registryinfo.test.ts @@ -45,8 +45,9 @@ describe("build", () => { const registryInfo = "registry.io/username"; const getDepConImg = (deploy: kind.Deployment, container: string): string => { - return deploy!.spec!.template!.spec!.containers.filter(f => f.name === container).at(0)! - .image!; + return deploy! + .spec!.template!.spec!.containers.filter(cont => cont.name === container) + .at(0)!.image!; }; it( From 544150a2bd428c326068063f640ba29f58189932 Mon Sep 17 00:00:00 2001 From: Barrett LaFrance Date: Tue, 14 Jan 2025 15:09:32 -0600 Subject: [PATCH 40/51] wip: PR feedback - expand map func args --- integration/cli/build.nonconflict.test.ts | 4 +++- integration/helpers/resource.ts | 4 ++-- integration/helpers/time.ts | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/integration/cli/build.nonconflict.test.ts b/integration/cli/build.nonconflict.test.ts index 0e7fcce9f..037c62f9a 100644 --- a/integration/cli/build.nonconflict.test.ts +++ b/integration/cli/build.nonconflict.test.ts @@ -151,7 +151,9 @@ describe("build", () => { it("--withPullSecret, works", async () => { const getDepImgPull = (deploy: kind.Deployment): string[] => { - return deploy!.spec!.template!.spec!.imagePullSecrets!.map(m => m.name!); + return deploy!.spec!.template!.spec!.imagePullSecrets!.map( + imagePullSecret => imagePullSecret.name!, + ); }; const moduleYaml = await resource.manyFromFile(`${outputDir}/pepr-module-${uuid}.yaml`); diff --git a/integration/helpers/resource.ts b/integration/helpers/resource.ts index 03acc6b4f..50eaadcf7 100644 --- a/integration/helpers/resource.ts +++ b/integration/helpers/resource.ts @@ -50,8 +50,8 @@ export async function manyFromFile(path: string): Promise { } case "yaml": - ret = parseAllDocuments(await readFile(path, { encoding: "utf8" })).map(m => - m.contents!.toJSON(), + ret = parseAllDocuments(await readFile(path, { encoding: "utf8" })).map(yamlDoc => + yamlDoc.contents!.toJSON(), ); break; diff --git a/integration/helpers/time.ts b/integration/helpers/time.ts index 691991012..d12c78591 100644 --- a/integration/helpers/time.ts +++ b/integration/helpers/time.ts @@ -16,7 +16,7 @@ export async function nap(ms: number): Promise { } export function toMs(human: string) { - const splits = human.split("").map(m => m.trim()); + const splits = human.split("").map(str => str.trim()); const groups: string[] = []; splits.forEach(next => { From cec588ba90d7ac2ce1e2e0e3289dd306403f5489 Mon Sep 17 00:00:00 2001 From: Barrett LaFrance Date: Tue, 14 Jan 2025 15:10:33 -0600 Subject: [PATCH 41/51] wip: PR feedback - remove placeholder comment --- integration/cli/build.nonconflict.test.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/integration/cli/build.nonconflict.test.ts b/integration/cli/build.nonconflict.test.ts index 037c62f9a..410901f2d 100644 --- a/integration/cli/build.nonconflict.test.ts +++ b/integration/cli/build.nonconflict.test.ts @@ -180,10 +180,6 @@ describe("build", () => { .at(0); expect(component.charts).toContainEqual(chart); }); - - // it("--rbac-mode, ...todo!", async () => { - // --rbac-mode scoped - // } }); }); }); From 9cabc5bce2610f1cae0231779280df5666a683a4 Mon Sep 17 00:00:00 2001 From: Barrett LaFrance Date: Tue, 14 Jan 2025 15:17:08 -0600 Subject: [PATCH 42/51] wip: PR feedback - remove flag precedence comment-question --- integration/cli/build.registryinfo.test.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/integration/cli/build.registryinfo.test.ts b/integration/cli/build.registryinfo.test.ts index 2ce6c8343..ae03947c7 100644 --- a/integration/cli/build.registryinfo.test.ts +++ b/integration/cli/build.registryinfo.test.ts @@ -66,7 +66,6 @@ describe("build", () => { ); it("outputs appropriate configuration", async () => { - // overwrites --custom-image..? const image = `${registryInfo}/custom-pepr-controller:0.0.0-development`; { From 84e93140d58843331af681e14027feb8f80fb13b Mon Sep 17 00:00:00 2001 From: Barrett LaFrance Date: Tue, 14 Jan 2025 15:22:47 -0600 Subject: [PATCH 43/51] wip: PR feedback - expand short variable name --- integration/cli/init.test.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/integration/cli/init.test.ts b/integration/cli/init.test.ts index c8be64776..ab80641ff 100644 --- a/integration/cli/init.test.ts +++ b/integration/cli/init.test.ts @@ -35,11 +35,11 @@ describe("init", () => { async () => { const name = "flags-name"; const desc = "flags-desc"; - const errb = "reject"; + const errorBehavior = "reject"; const argz = [ `--name ${name}`, `--description ${desc}`, - `--errorBehavior ${errb}`, + `--errorBehavior ${errorBehavior}`, "--confirm", "--skip-post-init", ].join(" "); @@ -53,7 +53,7 @@ describe("init", () => { ); expect(packageJson.name).toBe(name); expect(packageJson.description).toBe(desc); - expect(packageJson.pepr.onError).toBe(errb); + expect(packageJson.pepr.onError).toBe(errorBehavior); }, time.toMs("2m"), ); From d802fe3d127c51d270c66c5f24917574f9af15e4 Mon Sep 17 00:00:00 2001 From: Barrett LaFrance Date: Tue, 14 Jan 2025 15:48:26 -0600 Subject: [PATCH 44/51] wip: PR feedback - use fs.existsSync instead of file helper --- integration/cli/build.nonconflict.test.ts | 6 ++--- integration/cli/build.version.test.ts | 4 ++-- integration/helpers/file.test.ts | 28 ----------------------- integration/helpers/file.ts | 14 ------------ 4 files changed, 5 insertions(+), 47 deletions(-) delete mode 100644 integration/helpers/file.test.ts delete mode 100644 integration/helpers/file.ts diff --git a/integration/cli/build.nonconflict.test.ts b/integration/cli/build.nonconflict.test.ts index 410901f2d..764c35ebd 100644 --- a/integration/cli/build.nonconflict.test.ts +++ b/integration/cli/build.nonconflict.test.ts @@ -4,12 +4,12 @@ import { beforeAll, describe, expect, it } from "@jest/globals"; import * as path from "node:path"; import * as fs from "node:fs/promises"; +import { existsSync } from "node:fs"; import { kind } from "kubernetes-fluent-client"; import { Workdir } from "../helpers/workdir"; import * as time from "../helpers/time"; import * as pepr from "../helpers/pepr"; import * as resource from "../helpers/resource"; -import * as file from "../helpers/file"; const FILE = path.basename(__filename); const HERE = __dirname; @@ -87,9 +87,9 @@ describe("build", () => { it("--output-dir, works", async () => { const dist = `${testModule}/dist`; - expect(await file.exists(dist)).toBe(false); + expect(existsSync(dist)).toBe(false); - expect(await file.exists(outputDir)).toBe(true); + expect(existsSync(outputDir)).toBe(true); }); it("--custom-image, works", async () => { diff --git a/integration/cli/build.version.test.ts b/integration/cli/build.version.test.ts index 2b38f5ae7..a63715e7b 100644 --- a/integration/cli/build.version.test.ts +++ b/integration/cli/build.version.test.ts @@ -4,10 +4,10 @@ import { beforeAll, describe, expect, it } from "@jest/globals"; import * as path from "node:path"; import * as fs from "node:fs/promises"; +import { existsSync } from "node:fs"; import { Workdir } from "../helpers/workdir"; import * as time from "../helpers/time"; import * as pepr from "../helpers/pepr"; -import * as file from "../helpers/file"; const FILE = path.basename(__filename); const HERE = __dirname; @@ -50,7 +50,7 @@ describe("build", () => { expect(build.stderr.join("").trim()).toBe(""); expect(build.stdout.join("").trim()).toContain(cliVersion); - expect(await file.exists(`${testModule}/dist`)).toBe(false); + expect(existsSync(`${testModule}/dist`)).toBe(false); }, time.toMs("1m"), ); diff --git a/integration/helpers/file.test.ts b/integration/helpers/file.test.ts deleted file mode 100644 index ba872ca16..000000000 --- a/integration/helpers/file.test.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { beforeAll, describe, expect, it } from "@jest/globals"; -import * as path from "node:path"; -import * as fs from "node:fs/promises"; -import { Workdir } from "../helpers/workdir"; -import * as sut from "./file"; - -const FILE = path.basename(__filename); -const HERE = __dirname; - -describe("exists", () => { - const workdir = new Workdir(`${FILE}-exists`, `${HERE}/../testroot/helpers`); - const real = `${workdir.path()}/exists.txt`; - - beforeAll(async () => { - await workdir.recreate(); - await fs.writeFile(real, "I exist!"); - }); - - it("returns true when exists", async () => { - const result = await sut.exists(real); - expect(result).toBe(true); - }); - - it("returns false when missing", async () => { - const result = await sut.exists(`${real}.nope`); - expect(result).toBe(false); - }); -}); diff --git a/integration/helpers/file.ts b/integration/helpers/file.ts deleted file mode 100644 index 7ce54b298..000000000 --- a/integration/helpers/file.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { access } from "node:fs/promises"; - -export async function exists(path: string): Promise { - try { - await access(path); - return true; - } catch (e) { - if (e.code === "ENOENT") { - return false; - } else { - throw e; - } - } -} From 3f824f093ad22f18e367794312b00c13a60fd9d4 Mon Sep 17 00:00:00 2001 From: Barrett LaFrance Date: Tue, 14 Jan 2025 15:57:21 -0600 Subject: [PATCH 45/51] wip: PR feedback - rm unneeded pepr.copyModule helper --- integration/helpers/pepr.test.ts | 24 ------------------------ integration/helpers/pepr.ts | 15 +-------------- 2 files changed, 1 insertion(+), 38 deletions(-) diff --git a/integration/helpers/pepr.test.ts b/integration/helpers/pepr.test.ts index 8332d1ba2..b8afb42a7 100644 --- a/integration/helpers/pepr.test.ts +++ b/integration/helpers/pepr.test.ts @@ -44,30 +44,6 @@ describe("pepr", () => { }); }); - describe("copyModule", () => { - const workdir = new Workdir(`${FILE}-copyModule`, `${HERE}/../testroot/helpers`); - - beforeAll(async () => await workdir.recreate()); - - it("copies & configs pepr module", async () => { - const srcPath = `${workdir.path()}/src`; - const dstPath = `${workdir.path()}/dst`; - - const packageSrc = `${srcPath}/package.json`; - let packageJson = { - name: "src", - }; - await fs.mkdir(srcPath, { recursive: true }); - await fs.writeFile(packageSrc, JSON.stringify(packageJson, null, 2)); - - await sut.copyModule(srcPath, dstPath); - - const packageDst = `${dstPath}/package.json`; - packageJson = JSON.parse(await fs.readFile(packageDst, { encoding: "utf8" })); - expect(packageJson.name).toBe("dst"); - }); - }); - describe("cli", () => { const workdir = new Workdir(`${FILE}-cli`, `${HERE}/../testroot/helpers`); diff --git a/integration/helpers/pepr.ts b/integration/helpers/pepr.ts index 3d27dc56c..3d57b3acc 100644 --- a/integration/helpers/pepr.ts +++ b/integration/helpers/pepr.ts @@ -1,6 +1,5 @@ import { resolve } from "node:path"; -import { cp, readFile, writeFile } from "node:fs/promises"; -import { basename } from "node:path"; +import { readFile, writeFile } from "node:fs/promises"; import { Spec, Cmd, Result } from "./cmd"; import { clone } from "ramda"; @@ -22,18 +21,6 @@ export async function tgzifyModule(modulePath: string): Promise { await writeFile(packagePath, JSON.stringify(packageJson, null, 2)); } -export async function copyModule(src: string, dst: string): Promise { - await cp(src, dst, { recursive: true }); - - // jest fails to run if given a file hierarchy that includes more than one - // module with the same name -- this copies-then-rename is to avoid that - const packagePath = `${dst}/package.json`; - const packageJson = JSON.parse(await readFile(packagePath, { encoding: "utf8" })); - packageJson.name = basename(dst); - - await writeFile(packagePath, JSON.stringify(packageJson, null, 2)); -} - export async function cli(workdir: string, spec: Spec): Promise { const root = await projectRoot(); const tgz = `file://${root}/pepr-0.0.0-development.tgz`; From b72960a697c90bcbf571dbfa8a01f12f154414fc Mon Sep 17 00:00:00 2001 From: Barrett LaFrance Date: Tue, 14 Jan 2025 16:10:49 -0600 Subject: [PATCH 46/51] wip: PR feedback - use fs.existsSync in Workdir helper --- integration/helpers/workdir.ts | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/integration/helpers/workdir.ts b/integration/helpers/workdir.ts index 60e5b74cd..fd3a49944 100644 --- a/integration/helpers/workdir.ts +++ b/integration/helpers/workdir.ts @@ -1,6 +1,7 @@ import * as os from "node:os"; import * as path from "node:path"; import * as fs from "node:fs/promises"; +import { existsSync } from "node:fs"; import * as time from "./time"; export class Workdir { @@ -22,15 +23,7 @@ export class Workdir { } async exists() { - try { - await fs.access(this.path()); - return true; - } catch (e) { - if (e.message.includes("no such file or directory")) { - return false; - } - throw e; - } + return existsSync(this.path()); } async isEmpty() { From 18e833a528d4218f946a59b57291629834fdafd5 Mon Sep 17 00:00:00 2001 From: Barrett <81570928+btlghrants@users.noreply.github.com> Date: Tue, 14 Jan 2025 16:12:30 -0600 Subject: [PATCH 47/51] Update integration/prep.sh Co-authored-by: Sam Mayer --- integration/prep.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/integration/prep.sh b/integration/prep.sh index 8de83daa6..d5ad2e5d3 100755 --- a/integration/prep.sh +++ b/integration/prep.sh @@ -1,4 +1,6 @@ #!/bin/sh +# This script makes a version of the npm cache for local use to avoid installing test artifacts into the global npm cache. +# This isn't an issue in CI where environments are ephemeral, but is useful for local testing. ME="$(readlink -f "$0")" HERE="$(dirname "$ME")" ROOT="$(dirname "$HERE")" From c9c0c28e68c8192459fa5f40661578e429268a9d Mon Sep 17 00:00:00 2001 From: Barrett LaFrance Date: Tue, 14 Jan 2025 16:44:02 -0600 Subject: [PATCH 48/51] wip: rm dead import --- integration/cli/build.noembed.test.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/integration/cli/build.noembed.test.ts b/integration/cli/build.noembed.test.ts index 6b06c3f47..32f2bb04f 100644 --- a/integration/cli/build.noembed.test.ts +++ b/integration/cli/build.noembed.test.ts @@ -8,7 +8,6 @@ import { Workdir } from "../helpers/workdir"; import * as time from "../helpers/time"; import * as pepr from "../helpers/pepr"; import * as resource from "../helpers/resource"; -import * as file from "../helpers/file"; const FILE = path.basename(__filename); const HERE = __dirname; From fe536ebede074d4618c679481e8e88f44e9d3581 Mon Sep 17 00:00:00 2001 From: Barrett LaFrance Date: Tue, 14 Jan 2025 17:07:26 -0600 Subject: [PATCH 49/51] wip: rm dead import --- integration/cli/build.noembed.test.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/integration/cli/build.noembed.test.ts b/integration/cli/build.noembed.test.ts index 32f2bb04f..cefdeb34d 100644 --- a/integration/cli/build.noembed.test.ts +++ b/integration/cli/build.noembed.test.ts @@ -4,6 +4,7 @@ import { beforeAll, describe, expect, it } from "@jest/globals"; import * as path from "node:path"; import * as fs from "node:fs/promises"; +import { existsSync } from "node:fs"; import { Workdir } from "../helpers/workdir"; import * as time from "../helpers/time"; import * as pepr from "../helpers/pepr"; @@ -68,7 +69,7 @@ describe("build", () => { `${testModule}/dist/${uuid}-chart/`, ]; for (const path of missing) { - expect(await file.exists(path)).toBe(false); + expect(existsSync(path)).toBe(false); } const found = [ @@ -77,7 +78,7 @@ describe("build", () => { `${testModule}/dist/pepr.js.LEGAL.txt`, ]; for (const path of found) { - expect(await file.exists(path)).toBe(true); + expect(existsSync(path)).toBe(true); } }, time.toMs("1m"), From 92ec7c36a7b894537388150ac74769a1e8856402 Mon Sep 17 00:00:00 2001 From: Sam Mayer Date: Wed, 15 Jan 2025 14:00:44 -0600 Subject: [PATCH 50/51] chore: consolidate file parsing implementation (#1663) ## Description This PR provides a fix to feedback on #1642 ## Related Issue Relates to #1640 ## Type of change - [ ] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [x] Other (security config, docs update, etc) ## Checklist before merging - [x] Unit, [Journey](https://github.com/defenseunicorns/pepr/tree/main/journey), [E2E Tests](https://github.com/defenseunicorns/pepr-excellent-examples), [docs](https://github.com/defenseunicorns/pepr/tree/main/docs), [adr](https://github.com/defenseunicorns/pepr/tree/main/adr) added or updated as needed - [x] [Contributor Guide Steps](https://docs.pepr.dev/main/contribute/#submitting-a-pull-request) followed --- integration/cli/build.noembed.test.ts | 2 +- integration/cli/build.nonconflict.test.ts | 26 ++++++--- integration/cli/build.registryinfo.test.ts | 8 +-- integration/helpers/resource.test.ts | 14 ++--- integration/helpers/resource.ts | 64 ++++++---------------- 5 files changed, 48 insertions(+), 66 deletions(-) diff --git a/integration/cli/build.noembed.test.ts b/integration/cli/build.noembed.test.ts index cefdeb34d..e364f1ae2 100644 --- a/integration/cli/build.noembed.test.ts +++ b/integration/cli/build.noembed.test.ts @@ -51,7 +51,7 @@ describe("build", () => { expect(build.stderr.join("").trim()).toContain("Error: Cannot find module"); expect(build.stdout.join("").trim()).toContain(""); - packageJson = await resource.oneFromFile(`${testModule}/package.json`); + packageJson = await resource.resourcesFromFile(`${testModule}/package.json`); uuid = packageJson.pepr.uuid; }, time.toMs("1m"), diff --git a/integration/cli/build.nonconflict.test.ts b/integration/cli/build.nonconflict.test.ts index 764c35ebd..63cab02cc 100644 --- a/integration/cli/build.nonconflict.test.ts +++ b/integration/cli/build.nonconflict.test.ts @@ -69,7 +69,7 @@ describe("build", () => { expect(build.stderr.join("").trim()).toBe(""); expect(build.stdout.join("").trim()).toContain("K8s resource for the module saved"); - packageJson = await resource.oneFromFile(`${testModule}/package.json`); + packageJson = await resource.resourcesFromFile(`${testModule}/package.json`); uuid = packageJson.pepr.uuid; }, time.toMs("1m"), @@ -93,7 +93,9 @@ describe("build", () => { }); it("--custom-image, works", async () => { - const moduleYaml = await resource.manyFromFile(`${outputDir}/pepr-module-${uuid}.yaml`); + const moduleYaml = await resource.resourcesFromFile( + `${outputDir}/pepr-module-${uuid}.yaml`, + ); { const admission = resource.select(moduleYaml, kind.Deployment, `pepr-${uuid}`); const admissionImage = getDepConImg(admission, "server"); @@ -104,13 +106,15 @@ describe("build", () => { expect(watcherImage).toBe(customImage); } - const zarfYaml = await resource.oneFromFile(`${outputDir}/zarf.yaml`); + const zarfYaml = await resource.resourcesFromFile(`${outputDir}/zarf.yaml`); { const componentImage = zarfYaml.components.at(0).images.at(0); expect(componentImage).toBe(customImage); } - const valuesYaml = await resource.oneFromFile(`${outputDir}/${uuid}-chart/values.yaml`); + const valuesYaml = await resource.resourcesFromFile( + `${outputDir}/${uuid}-chart/values.yaml`, + ); { const admissionImage = valuesYaml.admission.image; expect(admissionImage).toBe(customImage); @@ -121,7 +125,9 @@ describe("build", () => { }); it("--timeout, works", async () => { - const moduleYaml = await resource.manyFromFile(`${outputDir}/pepr-module-${uuid}.yaml`); + const moduleYaml = await resource.resourcesFromFile( + `${outputDir}/pepr-module-${uuid}.yaml`, + ); { const mwc = resource.select( moduleYaml, @@ -145,7 +151,9 @@ describe("build", () => { expect(webhook.timeoutSeconds).toBe(timeout); } - const valuesYaml = await resource.oneFromFile(`${outputDir}/${uuid}-chart/values.yaml`); + const valuesYaml = await resource.resourcesFromFile( + `${outputDir}/${uuid}-chart/values.yaml`, + ); expect(valuesYaml.admission.webhookTimeout).toBe(timeout); }); @@ -156,7 +164,9 @@ describe("build", () => { ); }; - const moduleYaml = await resource.manyFromFile(`${outputDir}/pepr-module-${uuid}.yaml`); + const moduleYaml = await resource.resourcesFromFile( + `${outputDir}/pepr-module-${uuid}.yaml`, + ); const admission = resource.select(moduleYaml, kind.Deployment, `pepr-${uuid}`); const admissionSecrets = getDepImgPull(admission); expect(admissionSecrets).toEqual([withPullSecret]); @@ -174,7 +184,7 @@ describe("build", () => { localPath: `${uuid}-chart`, }; - const zarfYaml = await resource.oneFromFile(`${outputDir}/zarf.yaml`); + const zarfYaml = await resource.resourcesFromFile(`${outputDir}/zarf.yaml`); const component = zarfYaml.components .filter((component: { name: string }) => component.name === "module") .at(0); diff --git a/integration/cli/build.registryinfo.test.ts b/integration/cli/build.registryinfo.test.ts index ae03947c7..e192e84f7 100644 --- a/integration/cli/build.registryinfo.test.ts +++ b/integration/cli/build.registryinfo.test.ts @@ -59,7 +59,7 @@ describe("build", () => { expect(build.stderr.join("").trim()).toBe(""); expect(build.stdout.join("").trim()).toContain("K8s resource for the module saved"); - packageJson = await resource.oneFromFile(`${testModule}/package.json`); + packageJson = await resource.resourcesFromFile(`${testModule}/package.json`); uuid = packageJson.pepr.uuid; }, time.toMs("1m"), @@ -69,7 +69,7 @@ describe("build", () => { const image = `${registryInfo}/custom-pepr-controller:0.0.0-development`; { - const moduleYaml = await resource.manyFromFile( + const moduleYaml = await resource.resourcesFromFile( `${testModule}/dist/pepr-module-${uuid}.yaml`, ); const admission = resource.select(moduleYaml, kind.Deployment, `pepr-${uuid}`); @@ -81,12 +81,12 @@ describe("build", () => { expect(watcherImage).toBe(image); } { - const zarfYaml = await resource.oneFromFile(`${testModule}/dist/zarf.yaml`); + const zarfYaml = await resource.resourcesFromFile(`${testModule}/dist/zarf.yaml`); const componentImage = zarfYaml.components.at(0).images.at(0); expect(componentImage).toBe(image); } { - const valuesYaml = await resource.oneFromFile( + const valuesYaml = await resource.resourcesFromFile( `${testModule}/dist/${uuid}-chart/values.yaml`, ); const admissionImage = valuesYaml.admission.image; diff --git a/integration/helpers/resource.test.ts b/integration/helpers/resource.test.ts index 787737b7a..4330a8543 100644 --- a/integration/helpers/resource.test.ts +++ b/integration/helpers/resource.test.ts @@ -17,7 +17,7 @@ beforeAll(async () => { await workdir.recreate(); }); -describe("oneFromFile", () => { +describe("resourcesFromFile", () => { it("can load one resource from .json file", async () => { const oneJson = `${workdir.path()}/one.json`; await fs.writeFile( @@ -28,7 +28,7 @@ describe("oneFromFile", () => { } `, ); - const result = await sut.oneFromFile(oneJson); + const result = await sut.resourcesFromFile(oneJson); expect(result.one).toBe("json"); }); @@ -41,12 +41,12 @@ describe("oneFromFile", () => { one: yaml `, ); - const result = await sut.oneFromFile(oneYaml); + const result = await sut.resourcesFromFile(oneYaml); expect(result.one).toBe("yaml"); }); }); -describe("manyFromFile", () => { +describe("resourcesFromFile", () => { it("can load many resources from .json file", async () => { const manyJson = `${workdir.path()}/many.json`; await fs.writeFile( @@ -65,7 +65,7 @@ describe("manyFromFile", () => { ] `, ); - const result = await sut.manyFromFile(manyJson); + const result = await sut.resourcesFromFile(manyJson); expect(result.at(0).one).toBe("json"); expect(result.at(1).two).toBe("json"); expect(result.at(2).three).toBe("json"); @@ -84,7 +84,7 @@ describe("manyFromFile", () => { three: yaml `, ); - const result = await sut.manyFromFile(manyYaml); + const result = await sut.resourcesFromFile(manyYaml); expect(result.at(0).one).toBe("yaml"); expect(result.at(1).two).toBe("yaml"); expect(result.at(2).three).toBe("yaml"); @@ -115,7 +115,7 @@ describe("select", () => { fake: news `, ); - const many = await sut.manyFromFile(manyYaml); + const many = await sut.resourcesFromFile(manyYaml); const sec = sut.select(many, kind.Secret, "sec"); const cm = sut.select(many, kind.ConfigMap, "cm"); diff --git a/integration/helpers/resource.ts b/integration/helpers/resource.ts index 50eaadcf7..876590508 100644 --- a/integration/helpers/resource.ts +++ b/integration/helpers/resource.ts @@ -1,65 +1,37 @@ import { readFile } from "node:fs/promises"; import { kind, KubernetesObject } from "kubernetes-fluent-client"; -import { parseDocument, parseAllDocuments } from "yaml"; +import { parseAllDocuments } from "yaml"; /** - * Read one resource from file, rehydrated as a JS object + * Read resources from a file and return them as JS objects. * - * @param path Path to file holding one JSON (*.json) object / YAML (*.yaml) document - * @returns JS object + * @param path Path to the file (supports JSON (*.json) or YAML (*.yaml)) + * @returns JS object or array of JS objects. */ /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ -export async function oneFromFile(path: string): Promise { - const ext = path.split(".").at(-1); +export async function resourcesFromFile(path: string): Promise { + const extension = path.split(".").at(-1); - let ret: object; - switch (ext) { - case "json": { - const all = JSON.parse(await readFile(path, { encoding: "utf8" })); - ret = Array.isArray(all) ? all.at(0) : all; - break; - } - - case "yaml": - ret = parseDocument(await readFile(path, { encoding: "utf8" })).contents!.toJSON(); - break; - - default: - throw `oops: don't recognize file of type ".${ext}"`; - } - - return ret; -} + let result: object | object[]; + const content = await readFile(path, { encoding: "utf8" }); -/** - * Read many resources from file, rehydrated as an array of JS objects - * - * @param path Path to file holding an array of JSON (*.json) objects / multiple concatinated YAML (*.yaml) documents - * @returns Array of JS objects - */ -/* eslint-disable-next-line @typescript-eslint/no-explicit-any */ -export async function manyFromFile(path: string): Promise { - const ext = path.split(".").at(-1); - - let ret: object[]; - switch (ext) { + switch (extension) { case "json": { - const all = JSON.parse(await readFile(path, { encoding: "utf8" })); - ret = Array.isArray(all) ? all : [all]; + const parsed = JSON.parse(content); + result = Array.isArray(parsed) ? parsed : [parsed]; break; } - - case "yaml": - ret = parseAllDocuments(await readFile(path, { encoding: "utf8" })).map(yamlDoc => - yamlDoc.contents!.toJSON(), - ); + case "yaml": { + const documents = parseAllDocuments(content).map(doc => doc.contents!.toJSON()); + result = documents.length === 1 ? documents[0] : documents; break; - + } default: - throw `oops: don't recognize file of type ".${ext}"`; + throw new Error(`Unsupported file type ".${extension}"`); } - return ret; + // If the result is an array with one element, return the single element + return Array.isArray(result) && result.length === 1 ? result[0] : result; } /** From 5196e7b08c95a26faa80e6eee91afbc681a6a274 Mon Sep 17 00:00:00 2001 From: Barrett LaFrance Date: Wed, 15 Jan 2025 14:08:30 -0600 Subject: [PATCH 51/51] chore: Mac support / module func name simplification --- integration/cli/build.noembed.test.ts | 2 +- integration/cli/build.nonconflict.test.ts | 26 +++++++--------------- integration/cli/build.registryinfo.test.ts | 10 ++++----- integration/helpers/cmd.test.ts | 2 +- integration/helpers/resource.test.ts | 14 ++++++------ integration/helpers/resource.ts | 2 +- 6 files changed, 22 insertions(+), 34 deletions(-) diff --git a/integration/cli/build.noembed.test.ts b/integration/cli/build.noembed.test.ts index e364f1ae2..15b51ca4c 100644 --- a/integration/cli/build.noembed.test.ts +++ b/integration/cli/build.noembed.test.ts @@ -51,7 +51,7 @@ describe("build", () => { expect(build.stderr.join("").trim()).toContain("Error: Cannot find module"); expect(build.stdout.join("").trim()).toContain(""); - packageJson = await resource.resourcesFromFile(`${testModule}/package.json`); + packageJson = await resource.fromFile(`${testModule}/package.json`); uuid = packageJson.pepr.uuid; }, time.toMs("1m"), diff --git a/integration/cli/build.nonconflict.test.ts b/integration/cli/build.nonconflict.test.ts index 63cab02cc..6be2dde9a 100644 --- a/integration/cli/build.nonconflict.test.ts +++ b/integration/cli/build.nonconflict.test.ts @@ -69,7 +69,7 @@ describe("build", () => { expect(build.stderr.join("").trim()).toBe(""); expect(build.stdout.join("").trim()).toContain("K8s resource for the module saved"); - packageJson = await resource.resourcesFromFile(`${testModule}/package.json`); + packageJson = await resource.fromFile(`${testModule}/package.json`); uuid = packageJson.pepr.uuid; }, time.toMs("1m"), @@ -93,9 +93,7 @@ describe("build", () => { }); it("--custom-image, works", async () => { - const moduleYaml = await resource.resourcesFromFile( - `${outputDir}/pepr-module-${uuid}.yaml`, - ); + const moduleYaml = await resource.fromFile(`${outputDir}/pepr-module-${uuid}.yaml`); { const admission = resource.select(moduleYaml, kind.Deployment, `pepr-${uuid}`); const admissionImage = getDepConImg(admission, "server"); @@ -106,15 +104,13 @@ describe("build", () => { expect(watcherImage).toBe(customImage); } - const zarfYaml = await resource.resourcesFromFile(`${outputDir}/zarf.yaml`); + const zarfYaml = await resource.fromFile(`${outputDir}/zarf.yaml`); { const componentImage = zarfYaml.components.at(0).images.at(0); expect(componentImage).toBe(customImage); } - const valuesYaml = await resource.resourcesFromFile( - `${outputDir}/${uuid}-chart/values.yaml`, - ); + const valuesYaml = await resource.fromFile(`${outputDir}/${uuid}-chart/values.yaml`); { const admissionImage = valuesYaml.admission.image; expect(admissionImage).toBe(customImage); @@ -125,9 +121,7 @@ describe("build", () => { }); it("--timeout, works", async () => { - const moduleYaml = await resource.resourcesFromFile( - `${outputDir}/pepr-module-${uuid}.yaml`, - ); + const moduleYaml = await resource.fromFile(`${outputDir}/pepr-module-${uuid}.yaml`); { const mwc = resource.select( moduleYaml, @@ -151,9 +145,7 @@ describe("build", () => { expect(webhook.timeoutSeconds).toBe(timeout); } - const valuesYaml = await resource.resourcesFromFile( - `${outputDir}/${uuid}-chart/values.yaml`, - ); + const valuesYaml = await resource.fromFile(`${outputDir}/${uuid}-chart/values.yaml`); expect(valuesYaml.admission.webhookTimeout).toBe(timeout); }); @@ -164,9 +156,7 @@ describe("build", () => { ); }; - const moduleYaml = await resource.resourcesFromFile( - `${outputDir}/pepr-module-${uuid}.yaml`, - ); + const moduleYaml = await resource.fromFile(`${outputDir}/pepr-module-${uuid}.yaml`); const admission = resource.select(moduleYaml, kind.Deployment, `pepr-${uuid}`); const admissionSecrets = getDepImgPull(admission); expect(admissionSecrets).toEqual([withPullSecret]); @@ -184,7 +174,7 @@ describe("build", () => { localPath: `${uuid}-chart`, }; - const zarfYaml = await resource.resourcesFromFile(`${outputDir}/zarf.yaml`); + const zarfYaml = await resource.fromFile(`${outputDir}/zarf.yaml`); const component = zarfYaml.components .filter((component: { name: string }) => component.name === "module") .at(0); diff --git a/integration/cli/build.registryinfo.test.ts b/integration/cli/build.registryinfo.test.ts index e192e84f7..9c1777b18 100644 --- a/integration/cli/build.registryinfo.test.ts +++ b/integration/cli/build.registryinfo.test.ts @@ -59,7 +59,7 @@ describe("build", () => { expect(build.stderr.join("").trim()).toBe(""); expect(build.stdout.join("").trim()).toContain("K8s resource for the module saved"); - packageJson = await resource.resourcesFromFile(`${testModule}/package.json`); + packageJson = await resource.fromFile(`${testModule}/package.json`); uuid = packageJson.pepr.uuid; }, time.toMs("1m"), @@ -69,9 +69,7 @@ describe("build", () => { const image = `${registryInfo}/custom-pepr-controller:0.0.0-development`; { - const moduleYaml = await resource.resourcesFromFile( - `${testModule}/dist/pepr-module-${uuid}.yaml`, - ); + const moduleYaml = await resource.fromFile(`${testModule}/dist/pepr-module-${uuid}.yaml`); const admission = resource.select(moduleYaml, kind.Deployment, `pepr-${uuid}`); const admissionImage = getDepConImg(admission, "server"); expect(admissionImage).toBe(image); @@ -81,12 +79,12 @@ describe("build", () => { expect(watcherImage).toBe(image); } { - const zarfYaml = await resource.resourcesFromFile(`${testModule}/dist/zarf.yaml`); + const zarfYaml = await resource.fromFile(`${testModule}/dist/zarf.yaml`); const componentImage = zarfYaml.components.at(0).images.at(0); expect(componentImage).toBe(image); } { - const valuesYaml = await resource.resourcesFromFile( + const valuesYaml = await resource.fromFile( `${testModule}/dist/${uuid}-chart/values.yaml`, ); const admissionImage = valuesYaml.admission.image; diff --git a/integration/helpers/cmd.test.ts b/integration/helpers/cmd.test.ts index 7d080321a..30fd43ab7 100644 --- a/integration/helpers/cmd.test.ts +++ b/integration/helpers/cmd.test.ts @@ -27,7 +27,7 @@ describe("runRaw()", () => { }); it("accepts working directory", async () => { - const expected = "/tmp"; + const expected = "/"; const { stdout } = await new Cmd({ cwd: expected, cmd: `pwd` }).runRaw(); expect(stdout.join("")).toBe(expected); }); diff --git a/integration/helpers/resource.test.ts b/integration/helpers/resource.test.ts index 4330a8543..53918f68d 100644 --- a/integration/helpers/resource.test.ts +++ b/integration/helpers/resource.test.ts @@ -17,7 +17,7 @@ beforeAll(async () => { await workdir.recreate(); }); -describe("resourcesFromFile", () => { +describe("fromFile", () => { it("can load one resource from .json file", async () => { const oneJson = `${workdir.path()}/one.json`; await fs.writeFile( @@ -28,7 +28,7 @@ describe("resourcesFromFile", () => { } `, ); - const result = await sut.resourcesFromFile(oneJson); + const result = await sut.fromFile(oneJson); expect(result.one).toBe("json"); }); @@ -41,12 +41,12 @@ describe("resourcesFromFile", () => { one: yaml `, ); - const result = await sut.resourcesFromFile(oneYaml); + const result = await sut.fromFile(oneYaml); expect(result.one).toBe("yaml"); }); }); -describe("resourcesFromFile", () => { +describe("fromFile", () => { it("can load many resources from .json file", async () => { const manyJson = `${workdir.path()}/many.json`; await fs.writeFile( @@ -65,7 +65,7 @@ describe("resourcesFromFile", () => { ] `, ); - const result = await sut.resourcesFromFile(manyJson); + const result = await sut.fromFile(manyJson); expect(result.at(0).one).toBe("json"); expect(result.at(1).two).toBe("json"); expect(result.at(2).three).toBe("json"); @@ -84,7 +84,7 @@ describe("resourcesFromFile", () => { three: yaml `, ); - const result = await sut.resourcesFromFile(manyYaml); + const result = await sut.fromFile(manyYaml); expect(result.at(0).one).toBe("yaml"); expect(result.at(1).two).toBe("yaml"); expect(result.at(2).three).toBe("yaml"); @@ -115,7 +115,7 @@ describe("select", () => { fake: news `, ); - const many = await sut.resourcesFromFile(manyYaml); + const many = await sut.fromFile(manyYaml); const sec = sut.select(many, kind.Secret, "sec"); const cm = sut.select(many, kind.ConfigMap, "cm"); diff --git a/integration/helpers/resource.ts b/integration/helpers/resource.ts index 876590508..69612f9fc 100644 --- a/integration/helpers/resource.ts +++ b/integration/helpers/resource.ts @@ -9,7 +9,7 @@ import { parseAllDocuments } from "yaml"; * @returns JS object or array of JS objects. */ /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ -export async function resourcesFromFile(path: string): Promise { +export async function fromFile(path: string): Promise { const extension = path.split(".").at(-1); let result: object | object[];