@pagopa/dx-cli 0.23.0 → 0.23.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +5 -5
- package/templates/monorepo/nx.json +0 -1
- package/dist/adapters/azure/__tests__/cloud-account-repository.test.d.ts +0 -1
- package/dist/adapters/azure/__tests__/cloud-account-repository.test.js +0 -95
- package/dist/adapters/azure/__tests__/cloud-account-service.test.d.ts +0 -1
- package/dist/adapters/azure/__tests__/cloud-account-service.test.js +0 -378
- package/dist/adapters/codemods/__tests__/registry.test.d.ts +0 -1
- package/dist/adapters/codemods/__tests__/registry.test.js +0 -56
- package/dist/adapters/codemods/__tests__/use-azure-appsvc.test.d.ts +0 -1
- package/dist/adapters/codemods/__tests__/use-azure-appsvc.test.js +0 -77
- package/dist/adapters/codemods/__tests__/use-pnpm.test.d.ts +0 -1
- package/dist/adapters/codemods/__tests__/use-pnpm.test.js +0 -148
- package/dist/adapters/commander/__tests__/env.test.d.ts +0 -1
- package/dist/adapters/commander/__tests__/env.test.js +0 -45
- package/dist/adapters/commander/__tests__/error-reporting.test.d.ts +0 -1
- package/dist/adapters/commander/__tests__/error-reporting.test.js +0 -63
- package/dist/adapters/commander/__tests__/exit-with-error.test.d.ts +0 -1
- package/dist/adapters/commander/__tests__/exit-with-error.test.js +0 -92
- package/dist/adapters/commander/__tests__/global-options.test.d.ts +0 -1
- package/dist/adapters/commander/__tests__/global-options.test.js +0 -33
- package/dist/adapters/commander/__tests__/spec.test.d.ts +0 -8
- package/dist/adapters/commander/__tests__/spec.test.js +0 -264
- package/dist/adapters/commander/commands/__tests__/add.test.d.ts +0 -4
- package/dist/adapters/commander/commands/__tests__/add.test.js +0 -167
- package/dist/adapters/commander/commands/__tests__/init-command.test.d.ts +0 -4
- package/dist/adapters/commander/commands/__tests__/init-command.test.js +0 -44
- package/dist/adapters/commander/commands/__tests__/init.test.d.ts +0 -4
- package/dist/adapters/commander/commands/__tests__/init.test.js +0 -48
- package/dist/adapters/commander/commands/__tests__/preconditions.test.d.ts +0 -1
- package/dist/adapters/commander/commands/__tests__/preconditions.test.js +0 -32
- package/dist/adapters/commander/commands/__tests__/savemoney.test.d.ts +0 -8
- package/dist/adapters/commander/commands/__tests__/savemoney.test.js +0 -60
- package/dist/adapters/commander/commands/__tests__/spec.test.d.ts +0 -7
- package/dist/adapters/commander/commands/__tests__/spec.test.js +0 -85
- package/dist/adapters/commander/presenters/__tests__/index.test.d.ts +0 -1
- package/dist/adapters/commander/presenters/__tests__/index.test.js +0 -23
- package/dist/adapters/commander/presenters/__tests__/json.test.d.ts +0 -1
- package/dist/adapters/commander/presenters/__tests__/json.test.js +0 -108
- package/dist/adapters/commander/presenters/__tests__/text.test.d.ts +0 -1
- package/dist/adapters/commander/presenters/__tests__/text.test.js +0 -60
- package/dist/adapters/github/__tests__/github-repo.spec.d.ts +0 -1
- package/dist/adapters/github/__tests__/github-repo.spec.js +0 -67
- package/dist/adapters/node/__tests__/data.d.ts +0 -18
- package/dist/adapters/node/__tests__/data.js +0 -22
- package/dist/adapters/node/__tests__/package-json.test.d.ts +0 -1
- package/dist/adapters/node/__tests__/package-json.test.js +0 -86
- package/dist/adapters/node/__tests__/repository.test.d.ts +0 -1
- package/dist/adapters/node/__tests__/repository.test.js +0 -77
- package/dist/adapters/node/fs/__tests__/file-reader.test.d.ts +0 -1
- package/dist/adapters/node/fs/__tests__/file-reader.test.js +0 -80
- package/dist/adapters/node/json/__tests__/index.test.d.ts +0 -1
- package/dist/adapters/node/json/__tests__/index.test.js +0 -14
- package/dist/adapters/octokit/__tests__/index.test.d.ts +0 -1
- package/dist/adapters/octokit/__tests__/index.test.js +0 -414
- package/dist/adapters/pagopa-technology/__tests__/authorization.test.d.ts +0 -4
- package/dist/adapters/pagopa-technology/__tests__/authorization.test.js +0 -548
- package/dist/adapters/plop/__tests__/run-actions.test.d.ts +0 -1
- package/dist/adapters/plop/__tests__/run-actions.test.js +0 -68
- package/dist/adapters/plop/actions/__tests__/init-cloud-accounts.test.d.ts +0 -1
- package/dist/adapters/plop/actions/__tests__/init-cloud-accounts.test.js +0 -171
- package/dist/adapters/plop/actions/__tests__/provision-terraform-backend.test.d.ts +0 -1
- package/dist/adapters/plop/actions/__tests__/provision-terraform-backend.test.js +0 -134
- package/dist/adapters/plop/generators/__tests__/temp-dir.d.ts +0 -2
- package/dist/adapters/plop/generators/__tests__/temp-dir.js +0 -13
- package/dist/adapters/plop/generators/environment/__tests__/actions.test.d.ts +0 -2
- package/dist/adapters/plop/generators/environment/__tests__/actions.test.js +0 -92
- package/dist/adapters/plop/generators/environment/__tests__/generation.test.d.ts +0 -1
- package/dist/adapters/plop/generators/environment/__tests__/generation.test.js +0 -213
- package/dist/adapters/plop/generators/environment/__tests__/prompts.test.d.ts +0 -1
- package/dist/adapters/plop/generators/environment/__tests__/prompts.test.js +0 -182
- package/dist/adapters/plop/generators/monorepo/__tests__/generation.test.d.ts +0 -1
- package/dist/adapters/plop/generators/monorepo/__tests__/generation.test.js +0 -79
- package/dist/adapters/plop/helpers/__tests__/resource-prefix.test.d.ts +0 -1
- package/dist/adapters/plop/helpers/__tests__/resource-prefix.test.js +0 -113
- package/dist/adapters/plop/helpers/__tests__/terraform-state-key.test.d.ts +0 -1
- package/dist/adapters/plop/helpers/__tests__/terraform-state-key.test.js +0 -35
- package/dist/adapters/plop/helpers/__tests__/validate-prompt.test.d.ts +0 -1
- package/dist/adapters/plop/helpers/__tests__/validate-prompt.test.js +0 -60
- package/dist/adapters/yaml/__tests__/index.test.d.ts +0 -1
- package/dist/adapters/yaml/__tests__/index.test.js +0 -53
- package/dist/domain/__tests__/data.d.ts +0 -15
- package/dist/domain/__tests__/data.js +0 -26
- package/dist/domain/__tests__/environment.test.d.ts +0 -1
- package/dist/domain/__tests__/environment.test.js +0 -332
- package/dist/domain/__tests__/info.test.d.ts +0 -1
- package/dist/domain/__tests__/info.test.js +0 -77
- package/dist/domain/__tests__/package-json.test.d.ts +0 -1
- package/dist/domain/__tests__/package-json.test.js +0 -39
- package/dist/domain/__tests__/repository.test.d.ts +0 -1
- package/dist/domain/__tests__/repository.test.js +0 -111
- package/dist/domain/__tests__/workspace.test.d.ts +0 -1
- package/dist/domain/__tests__/workspace.test.js +0 -57
- package/dist/use-cases/__tests__/apply-codemod.test.d.ts +0 -1
- package/dist/use-cases/__tests__/apply-codemod.test.js +0 -71
- package/dist/use-cases/__tests__/list-codemods.test.d.ts +0 -1
- package/dist/use-cases/__tests__/list-codemods.test.js +0 -37
- package/dist/use-cases/__tests__/request-authorization.test.d.ts +0 -4
- package/dist/use-cases/__tests__/request-authorization.test.js +0 -43
|
@@ -1,182 +0,0 @@
|
|
|
1
|
-
// Tests for workspaceSchema transforms (lowercase and trim on domain).
|
|
2
|
-
import inquirer from "inquirer";
|
|
3
|
-
import { describe, expect, it, vi } from "vitest";
|
|
4
|
-
import prompts, { formatInitializationDetails, workspaceSchema, } from "../prompts.js";
|
|
5
|
-
describe("workspaceSchema — domain transforms", () => {
|
|
6
|
-
it("lowercases an uppercase domain", () => {
|
|
7
|
-
const result = workspaceSchema.safeParse({ domain: "API" });
|
|
8
|
-
expect(result.success).toBe(true);
|
|
9
|
-
expect(result.success && result.data.domain).toBe("api");
|
|
10
|
-
});
|
|
11
|
-
it("lowercases a mixed-case domain", () => {
|
|
12
|
-
const result = workspaceSchema.safeParse({ domain: "MyDomain" });
|
|
13
|
-
expect(result.success).toBe(true);
|
|
14
|
-
expect(result.success && result.data.domain).toBe("mydomain");
|
|
15
|
-
});
|
|
16
|
-
it("trims leading and trailing whitespace from domain", () => {
|
|
17
|
-
const result = workspaceSchema.safeParse({ domain: " aPi " });
|
|
18
|
-
expect(result.success).toBe(true);
|
|
19
|
-
expect(result.success && result.data.domain).toBe("api");
|
|
20
|
-
});
|
|
21
|
-
it("requires domain to be provided", () => {
|
|
22
|
-
const result = workspaceSchema.safeParse({});
|
|
23
|
-
expect(result.success).toBe(false);
|
|
24
|
-
});
|
|
25
|
-
it("rejects domains that would create nested paths", () => {
|
|
26
|
-
const result = workspaceSchema.safeParse({ domain: "core/platform" });
|
|
27
|
-
expect(result.success).toBe(false);
|
|
28
|
-
});
|
|
29
|
-
});
|
|
30
|
-
describe("formatInitializationDetails", () => {
|
|
31
|
-
const account = (overrides = {}) => ({
|
|
32
|
-
csp: "azure",
|
|
33
|
-
defaultLocation: "italynorth",
|
|
34
|
-
displayName: "DEV-FooBar",
|
|
35
|
-
id: "sub-123",
|
|
36
|
-
...overrides,
|
|
37
|
-
});
|
|
38
|
-
const notInitializedStatus = (issues) => ({
|
|
39
|
-
initialized: false,
|
|
40
|
-
issues,
|
|
41
|
-
});
|
|
42
|
-
it("lists each uninitialized cloud account by displayName", () => {
|
|
43
|
-
const status = notInitializedStatus([
|
|
44
|
-
{
|
|
45
|
-
cloudAccount: account({ displayName: "DEV-A" }),
|
|
46
|
-
type: "CLOUD_ACCOUNT_NOT_INITIALIZED",
|
|
47
|
-
},
|
|
48
|
-
{
|
|
49
|
-
cloudAccount: account({ displayName: "DEV-B" }),
|
|
50
|
-
type: "CLOUD_ACCOUNT_NOT_INITIALIZED",
|
|
51
|
-
},
|
|
52
|
-
]);
|
|
53
|
-
const output = formatInitializationDetails(status);
|
|
54
|
-
expect(output).toContain('Azure subscription "DEV-A"');
|
|
55
|
-
expect(output).toContain('Azure subscription "DEV-B"');
|
|
56
|
-
expect(output).toContain("managed identity");
|
|
57
|
-
expect(output).toContain("OIDC");
|
|
58
|
-
expect(output).toContain("ARM_CLIENT_ID");
|
|
59
|
-
expect(output).toContain("ARM_SUBSCRIPTION_ID");
|
|
60
|
-
expect(output).not.toContain("ARM_TENANT_ID");
|
|
61
|
-
expect(output).toContain("Key Vault");
|
|
62
|
-
});
|
|
63
|
-
it("includes the Terraform backend section when MISSING_REMOTE_BACKEND issue is present", () => {
|
|
64
|
-
const status = notInitializedStatus([
|
|
65
|
-
{ cloudAccount: account(), type: "CLOUD_ACCOUNT_NOT_INITIALIZED" },
|
|
66
|
-
{ type: "MISSING_REMOTE_BACKEND" },
|
|
67
|
-
]);
|
|
68
|
-
const output = formatInitializationDetails(status);
|
|
69
|
-
expect(output).toContain("Terraform remote backend");
|
|
70
|
-
expect(output).toContain("Storage Account");
|
|
71
|
-
});
|
|
72
|
-
it("omits the Terraform backend section when no MISSING_REMOTE_BACKEND issue is present", () => {
|
|
73
|
-
const status = notInitializedStatus([
|
|
74
|
-
{ cloudAccount: account(), type: "CLOUD_ACCOUNT_NOT_INITIALIZED" },
|
|
75
|
-
]);
|
|
76
|
-
const output = formatInitializationDetails(status);
|
|
77
|
-
expect(output).not.toContain("Terraform remote backend");
|
|
78
|
-
});
|
|
79
|
-
it("omits the cloud account section when no CLOUD_ACCOUNT_NOT_INITIALIZED issues are present", () => {
|
|
80
|
-
const status = notInitializedStatus([{ type: "MISSING_REMOTE_BACKEND" }]);
|
|
81
|
-
const output = formatInitializationDetails(status);
|
|
82
|
-
expect(output).not.toContain("Azure subscription");
|
|
83
|
-
expect(output).toContain("Terraform remote backend");
|
|
84
|
-
});
|
|
85
|
-
it("returns an empty string when there are no relevant issues", () => {
|
|
86
|
-
const status = notInitializedStatus([]);
|
|
87
|
-
expect(formatInitializationDetails(status)).toBe("");
|
|
88
|
-
});
|
|
89
|
-
});
|
|
90
|
-
describe("prompts", () => {
|
|
91
|
-
it("prompts for the GitHub runner app client ID when initialization is required", async () => {
|
|
92
|
-
const cloudAccount = {
|
|
93
|
-
csp: "azure",
|
|
94
|
-
defaultLocation: "italynorth",
|
|
95
|
-
displayName: "DEV-FooBar",
|
|
96
|
-
id: "sub-123",
|
|
97
|
-
};
|
|
98
|
-
const cloudAccountRepository = {
|
|
99
|
-
list: vi.fn().mockResolvedValue([cloudAccount]),
|
|
100
|
-
};
|
|
101
|
-
const cloudAccountService = {
|
|
102
|
-
getTerraformBackend: vi.fn().mockResolvedValue(undefined),
|
|
103
|
-
hasUserPermissionToInitialize: vi.fn().mockResolvedValue(true),
|
|
104
|
-
initialize: vi.fn().mockResolvedValue(undefined),
|
|
105
|
-
isInitialized: vi.fn().mockResolvedValue(false),
|
|
106
|
-
provisionTerraformBackend: vi.fn().mockResolvedValue(undefined),
|
|
107
|
-
};
|
|
108
|
-
const promptSpy = vi.spyOn(inquirer, "prompt");
|
|
109
|
-
const consoleLogSpy = vi
|
|
110
|
-
.spyOn(console, "log")
|
|
111
|
-
.mockImplementation(() => undefined);
|
|
112
|
-
promptSpy
|
|
113
|
-
.mockResolvedValueOnce({
|
|
114
|
-
env: {
|
|
115
|
-
cloudAccounts: [cloudAccount],
|
|
116
|
-
name: "dev",
|
|
117
|
-
prefix: "dx",
|
|
118
|
-
},
|
|
119
|
-
tags: {
|
|
120
|
-
BusinessUnit: "Platform",
|
|
121
|
-
CostCenter: "TS000",
|
|
122
|
-
ManagementTeam: "Engineering",
|
|
123
|
-
},
|
|
124
|
-
workspace: {
|
|
125
|
-
domain: "payments",
|
|
126
|
-
},
|
|
127
|
-
})
|
|
128
|
-
.mockResolvedValueOnce({
|
|
129
|
-
[cloudAccount.id]: "italynorth",
|
|
130
|
-
})
|
|
131
|
-
.mockResolvedValueOnce({
|
|
132
|
-
init: true,
|
|
133
|
-
})
|
|
134
|
-
.mockResolvedValueOnce({
|
|
135
|
-
runnerAppCredentials: {
|
|
136
|
-
clientId: "app-client-id",
|
|
137
|
-
id: "app-id",
|
|
138
|
-
installationId: "installation-id",
|
|
139
|
-
key: "private-key",
|
|
140
|
-
},
|
|
141
|
-
});
|
|
142
|
-
try {
|
|
143
|
-
const result = await prompts({
|
|
144
|
-
cloudAccountRepository,
|
|
145
|
-
cloudAccountService,
|
|
146
|
-
github: {
|
|
147
|
-
owner: "pagopa",
|
|
148
|
-
repo: "dx",
|
|
149
|
-
},
|
|
150
|
-
})(inquirer);
|
|
151
|
-
const runnerCredentialQuestions = promptSpy.mock.calls[3]?.[0];
|
|
152
|
-
expect(runnerCredentialQuestions).toEqual(expect.arrayContaining([
|
|
153
|
-
expect.objectContaining({
|
|
154
|
-
message: "GitHub Runner App ID",
|
|
155
|
-
name: "runnerAppCredentials.id",
|
|
156
|
-
}),
|
|
157
|
-
expect.objectContaining({
|
|
158
|
-
message: "GitHub Runner App Client ID",
|
|
159
|
-
name: "runnerAppCredentials.clientId",
|
|
160
|
-
}),
|
|
161
|
-
expect.objectContaining({
|
|
162
|
-
message: "GitHub Runner App Installation ID",
|
|
163
|
-
name: "runnerAppCredentials.installationId",
|
|
164
|
-
}),
|
|
165
|
-
expect.objectContaining({
|
|
166
|
-
message: "GitHub Runner App Private Key",
|
|
167
|
-
name: "runnerAppCredentials.key",
|
|
168
|
-
}),
|
|
169
|
-
]));
|
|
170
|
-
expect(result.init?.runnerAppCredentials).toEqual({
|
|
171
|
-
clientId: "app-client-id",
|
|
172
|
-
id: "app-id",
|
|
173
|
-
installationId: "installation-id",
|
|
174
|
-
key: "private-key",
|
|
175
|
-
});
|
|
176
|
-
}
|
|
177
|
-
finally {
|
|
178
|
-
promptSpy.mockRestore();
|
|
179
|
-
consoleLogSpy.mockRestore();
|
|
180
|
-
}
|
|
181
|
-
});
|
|
182
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import nodePlop from "node-plop";
|
|
2
|
-
/**
|
|
3
|
-
* Contract tests for the monorepo generator.
|
|
4
|
-
*
|
|
5
|
-
* They generate a real repository in a temp directory, but they only
|
|
6
|
-
* assert the generator-specific contract: payload interpolation,
|
|
7
|
-
* injected action outputs, and post-processing we own. They
|
|
8
|
-
* intentionally avoid asserting generic Plop copy/render behavior.
|
|
9
|
-
*/
|
|
10
|
-
import * as fs from "node:fs/promises";
|
|
11
|
-
import * as os from "node:os";
|
|
12
|
-
import * as path from "node:path";
|
|
13
|
-
import { afterAll, beforeAll, describe, expect, it } from "vitest";
|
|
14
|
-
import { resolveTemplatesPath } from "../../../templates-path.js";
|
|
15
|
-
import { cleanupTempDir, readGeneratedFiles, } from "../../__tests__/temp-dir.js";
|
|
16
|
-
import getActions from "../actions.js";
|
|
17
|
-
import { PLOP_MONOREPO_GENERATOR_NAME } from "../index.js";
|
|
18
|
-
/**
|
|
19
|
-
* Register stub versions of the custom action types that would normally
|
|
20
|
-
* call external services (GitHub API, Node.js releases, shell commands).
|
|
21
|
-
*/
|
|
22
|
-
const registerStubActions = (plop) => {
|
|
23
|
-
plop.setActionType("getNodeVersion", async (data) => {
|
|
24
|
-
data.nodeVersion = "22.14.0";
|
|
25
|
-
return "Fetched latest version: 22.14.0";
|
|
26
|
-
});
|
|
27
|
-
plop.setActionType("fetchGithubRelease", async (data, ctx) => {
|
|
28
|
-
const resultKey = ctx.resultKey;
|
|
29
|
-
data[resultKey] = "1.11.0";
|
|
30
|
-
return `Fetched latest version: 1.11.0`;
|
|
31
|
-
});
|
|
32
|
-
plop.setActionType("setupPnpm", async () => "Monorepo bootstrapped");
|
|
33
|
-
};
|
|
34
|
-
describe("monorepo generator — file generation", () => {
|
|
35
|
-
let tmpDir;
|
|
36
|
-
let originalCwd;
|
|
37
|
-
const payload = {
|
|
38
|
-
repoDescription: "A test repository for DX",
|
|
39
|
-
repoName: "my-test-repo",
|
|
40
|
-
repoOwner: "pagopa",
|
|
41
|
-
};
|
|
42
|
-
beforeAll(async () => {
|
|
43
|
-
originalCwd = process.cwd();
|
|
44
|
-
tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "dx-cli-monorepo-test-"));
|
|
45
|
-
process.chdir(tmpDir);
|
|
46
|
-
const plop = await nodePlop();
|
|
47
|
-
registerStubActions(plop);
|
|
48
|
-
plop.setGenerator(PLOP_MONOREPO_GENERATOR_NAME, {
|
|
49
|
-
actions: getActions(resolveTemplatesPath("monorepo")),
|
|
50
|
-
description: "A scaffold for a monorepo repository",
|
|
51
|
-
prompts: [],
|
|
52
|
-
});
|
|
53
|
-
const generator = plop.getGenerator(PLOP_MONOREPO_GENERATOR_NAME);
|
|
54
|
-
const result = await generator.runActions(payload);
|
|
55
|
-
const realFailures = result.failures.filter((f) => f.error !== "Aborted due to previous action failure");
|
|
56
|
-
if (realFailures.length > 0) {
|
|
57
|
-
const summary = realFailures
|
|
58
|
-
.map((f) => `${f.type}: ${f.error}`)
|
|
59
|
-
.join("\n");
|
|
60
|
-
throw new Error(`Generator failed:\n${summary}`);
|
|
61
|
-
}
|
|
62
|
-
});
|
|
63
|
-
afterAll(async () => {
|
|
64
|
-
process.chdir(originalCwd);
|
|
65
|
-
await cleanupTempDir(tmpDir);
|
|
66
|
-
});
|
|
67
|
-
it("materializes repository metadata from the generator payload", async () => {
|
|
68
|
-
const generatedFiles = await readGeneratedFiles(path.join(tmpDir, payload.repoName), ["package.json"]);
|
|
69
|
-
expect(generatedFiles).toMatchSnapshot();
|
|
70
|
-
});
|
|
71
|
-
it("propagates action outputs into generated version files", async () => {
|
|
72
|
-
const generatedFiles = await readGeneratedFiles(path.join(tmpDir, payload.repoName), [".node-version", ".terraform-version", ".pre-commit-config.yaml"]);
|
|
73
|
-
expect(generatedFiles).toMatchSnapshot();
|
|
74
|
-
});
|
|
75
|
-
it("applies the repository-specific gitignore customization", async () => {
|
|
76
|
-
const generatedFiles = await readGeneratedFiles(path.join(tmpDir, payload.repoName), [".gitignore"]);
|
|
77
|
-
expect(generatedFiles).toMatchSnapshot();
|
|
78
|
-
});
|
|
79
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "vitest";
|
|
2
|
-
import { resourcePrefix } from "../resource-prefix.js";
|
|
3
|
-
const createMockPayload = (overrides = {}) => ({
|
|
4
|
-
env: {
|
|
5
|
-
cloudAccounts: [],
|
|
6
|
-
name: "dev",
|
|
7
|
-
prefix: "dx",
|
|
8
|
-
},
|
|
9
|
-
workspace: {
|
|
10
|
-
domain: "",
|
|
11
|
-
},
|
|
12
|
-
...overrides,
|
|
13
|
-
});
|
|
14
|
-
describe("resourcePrefix", () => {
|
|
15
|
-
it("should return prefix with env prefix and environment short code when domain is empty", () => {
|
|
16
|
-
const payload = createMockPayload({
|
|
17
|
-
env: {
|
|
18
|
-
cloudAccounts: [],
|
|
19
|
-
name: "dev",
|
|
20
|
-
prefix: "dx",
|
|
21
|
-
},
|
|
22
|
-
workspace: {
|
|
23
|
-
domain: "",
|
|
24
|
-
},
|
|
25
|
-
});
|
|
26
|
-
const result = resourcePrefix(payload);
|
|
27
|
-
expect(result).toBe("dx-d");
|
|
28
|
-
});
|
|
29
|
-
it("should return prefix with env prefix, environment short code, and domain when domain is provided", () => {
|
|
30
|
-
const payload = createMockPayload({
|
|
31
|
-
env: {
|
|
32
|
-
cloudAccounts: [],
|
|
33
|
-
name: "dev",
|
|
34
|
-
prefix: "dx",
|
|
35
|
-
},
|
|
36
|
-
workspace: {
|
|
37
|
-
domain: "api",
|
|
38
|
-
},
|
|
39
|
-
});
|
|
40
|
-
const result = resourcePrefix(payload);
|
|
41
|
-
expect(result).toBe("dx-d-api");
|
|
42
|
-
});
|
|
43
|
-
it("should handle prod environment with short code 'p'", () => {
|
|
44
|
-
const payload = createMockPayload({
|
|
45
|
-
env: {
|
|
46
|
-
cloudAccounts: [],
|
|
47
|
-
name: "prod",
|
|
48
|
-
prefix: "pgo",
|
|
49
|
-
},
|
|
50
|
-
workspace: {
|
|
51
|
-
domain: "core",
|
|
52
|
-
},
|
|
53
|
-
});
|
|
54
|
-
const result = resourcePrefix(payload);
|
|
55
|
-
expect(result).toBe("pgo-p-core");
|
|
56
|
-
});
|
|
57
|
-
it("should handle uat environment with short code 'u'", () => {
|
|
58
|
-
const payload = createMockPayload({
|
|
59
|
-
env: {
|
|
60
|
-
cloudAccounts: [],
|
|
61
|
-
name: "uat",
|
|
62
|
-
prefix: "test",
|
|
63
|
-
},
|
|
64
|
-
workspace: {
|
|
65
|
-
domain: "web",
|
|
66
|
-
},
|
|
67
|
-
});
|
|
68
|
-
const result = resourcePrefix(payload);
|
|
69
|
-
expect(result).toBe("test-u-web");
|
|
70
|
-
});
|
|
71
|
-
it("should convert result to lowercase", () => {
|
|
72
|
-
const payload = createMockPayload({
|
|
73
|
-
env: {
|
|
74
|
-
cloudAccounts: [
|
|
75
|
-
{
|
|
76
|
-
csp: "azure",
|
|
77
|
-
defaultLocation: "westeurope",
|
|
78
|
-
displayName: "Test Account",
|
|
79
|
-
id: "test-account-id",
|
|
80
|
-
},
|
|
81
|
-
],
|
|
82
|
-
name: "prod",
|
|
83
|
-
prefix: "UPPER",
|
|
84
|
-
},
|
|
85
|
-
workspace: {
|
|
86
|
-
domain: "DOMAIN",
|
|
87
|
-
},
|
|
88
|
-
});
|
|
89
|
-
const result = resourcePrefix(payload);
|
|
90
|
-
expect(result).toBe("upper-p-domain");
|
|
91
|
-
});
|
|
92
|
-
it("should handle different prefix lengths", () => {
|
|
93
|
-
const payload = createMockPayload({
|
|
94
|
-
env: {
|
|
95
|
-
cloudAccounts: [
|
|
96
|
-
{
|
|
97
|
-
csp: "azure",
|
|
98
|
-
defaultLocation: "westeurope",
|
|
99
|
-
displayName: "Test Account",
|
|
100
|
-
id: "test-account-id",
|
|
101
|
-
},
|
|
102
|
-
],
|
|
103
|
-
name: "dev",
|
|
104
|
-
prefix: "ab",
|
|
105
|
-
},
|
|
106
|
-
workspace: {
|
|
107
|
-
domain: "",
|
|
108
|
-
},
|
|
109
|
-
});
|
|
110
|
-
const result = resourcePrefix(payload);
|
|
111
|
-
expect(result).toBe("ab-d");
|
|
112
|
-
});
|
|
113
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tests for Terraform state key generation used by the environment generator.
|
|
3
|
-
*/
|
|
4
|
-
import { describe, expect, it } from "vitest";
|
|
5
|
-
import { terraformStateKey } from "../terraform-state-key.js";
|
|
6
|
-
const createMockContext = (overrides = {}) => ({
|
|
7
|
-
env: {
|
|
8
|
-
cloudAccounts: [],
|
|
9
|
-
name: "dev",
|
|
10
|
-
prefix: "dx",
|
|
11
|
-
},
|
|
12
|
-
workspace: {
|
|
13
|
-
domain: "shared",
|
|
14
|
-
},
|
|
15
|
-
...overrides,
|
|
16
|
-
});
|
|
17
|
-
describe("terraformStateKey", () => {
|
|
18
|
-
it("returns keys using the prefix/domain/scope convention", () => {
|
|
19
|
-
const result = terraformStateKey(createMockContext(), "bootstrapper");
|
|
20
|
-
expect(result).toBe("dx/shared/bootstrapper.tfstate");
|
|
21
|
-
});
|
|
22
|
-
it("supports hyphenated names", () => {
|
|
23
|
-
const result = terraformStateKey(createMockContext({
|
|
24
|
-
workspace: { domain: "playground" },
|
|
25
|
-
}), "mcp-server");
|
|
26
|
-
expect(result).toBe("dx/playground/mcp-server.tfstate");
|
|
27
|
-
});
|
|
28
|
-
it("rejects names that would create nested paths", () => {
|
|
29
|
-
expect(() => terraformStateKey(createMockContext(), "core/root")).toThrow(/Terraform state name may contain only lowercase letters, numbers, and hyphens/u);
|
|
30
|
-
});
|
|
31
|
-
it("rejects names with uppercase letters or surrounding spaces", () => {
|
|
32
|
-
expect(() => terraformStateKey(createMockContext(), "Mcp-Server")).toThrow(/Terraform state name may contain only lowercase letters, numbers, and hyphens/u);
|
|
33
|
-
expect(() => terraformStateKey(createMockContext(), " mcp-server ")).toThrow(/Terraform state name may contain only lowercase letters, numbers, and hyphens/u);
|
|
34
|
-
});
|
|
35
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
// Tests for the shared validatePrompt helper.
|
|
2
|
-
import { describe, expect, it } from "vitest";
|
|
3
|
-
import { z } from "zod/v4";
|
|
4
|
-
import { validatePrompt } from "../validate-prompt.js";
|
|
5
|
-
describe("validatePrompt", () => {
|
|
6
|
-
it("returns true when input is valid", () => {
|
|
7
|
-
const schema = z.string().min(1, "Must not be empty");
|
|
8
|
-
const validate = validatePrompt(schema);
|
|
9
|
-
const result = validate("hello");
|
|
10
|
-
expect(result).toBe(true);
|
|
11
|
-
});
|
|
12
|
-
it("returns a string error message when input is invalid", () => {
|
|
13
|
-
const schema = z.string().min(1, "Must not be empty");
|
|
14
|
-
const validate = validatePrompt(schema);
|
|
15
|
-
const result = validate("");
|
|
16
|
-
expect(typeof result).toBe("string");
|
|
17
|
-
expect(result).not.toBe(true);
|
|
18
|
-
});
|
|
19
|
-
it("returns the pretty-printed zod error message", () => {
|
|
20
|
-
const schema = z.string().min(3, "Too short");
|
|
21
|
-
const validate = validatePrompt(schema);
|
|
22
|
-
const result = validate("ab");
|
|
23
|
-
expect(result).toContain("Too short");
|
|
24
|
-
});
|
|
25
|
-
it("returns true for input that passes a min/max length schema", () => {
|
|
26
|
-
const schema = z.string().min(2).max(4);
|
|
27
|
-
const validate = validatePrompt(schema);
|
|
28
|
-
expect(validate("ab")).toBe(true);
|
|
29
|
-
expect(validate("abc")).toBe(true);
|
|
30
|
-
expect(validate("abcd")).toBe(true);
|
|
31
|
-
});
|
|
32
|
-
it("returns error string when input is too short for min/max length schema", () => {
|
|
33
|
-
const schema = z.string().min(2).max(4);
|
|
34
|
-
const validate = validatePrompt(schema);
|
|
35
|
-
const result = validate("a");
|
|
36
|
-
expect(typeof result).toBe("string");
|
|
37
|
-
});
|
|
38
|
-
it("returns error string when input is too long for min/max length schema", () => {
|
|
39
|
-
const schema = z.string().min(2).max(4);
|
|
40
|
-
const validate = validatePrompt(schema);
|
|
41
|
-
const result = validate("abcde");
|
|
42
|
-
expect(typeof result).toBe("string");
|
|
43
|
-
});
|
|
44
|
-
it("validates input after schema transforms are applied", () => {
|
|
45
|
-
// Schema with trim+toLowerCase then min length check
|
|
46
|
-
const schema = z.string().trim().toLowerCase().min(2);
|
|
47
|
-
const validate = validatePrompt(schema);
|
|
48
|
-
// " A " after trim is "A", after toLowerCase is "a" → length 1 → fails min(2)
|
|
49
|
-
const result = validate(" A ");
|
|
50
|
-
expect(typeof result).toBe("string");
|
|
51
|
-
});
|
|
52
|
-
it("works with a non-string schema", () => {
|
|
53
|
-
const schema = z.array(z.string()).min(1, "Select at least one item");
|
|
54
|
-
const validate = validatePrompt(schema);
|
|
55
|
-
expect(validate(["item1"])).toBe(true);
|
|
56
|
-
const result = validate([]);
|
|
57
|
-
expect(typeof result).toBe("string");
|
|
58
|
-
expect(result).toContain("Select at least one item");
|
|
59
|
-
});
|
|
60
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import { err, ok } from "neverthrow";
|
|
2
|
-
import { describe, expect, it } from "vitest";
|
|
3
|
-
import { parseYaml } from "../index.js";
|
|
4
|
-
describe("parseYaml", () => {
|
|
5
|
-
const yamlContent = `
|
|
6
|
-
packages:
|
|
7
|
-
- packages/*
|
|
8
|
-
- apps/*
|
|
9
|
-
- infra/modules/*
|
|
10
|
-
|
|
11
|
-
catalog:
|
|
12
|
-
prettier: 3.6.2
|
|
13
|
-
eslint: ^9.30.1
|
|
14
|
-
typescript: ~5.8.3
|
|
15
|
-
tsup: ^8.5.0
|
|
16
|
-
vitest: ^3.2.4
|
|
17
|
-
'@vitest/coverage-v8': ^3.2.4
|
|
18
|
-
'@tsconfig/node20': ^20.1.6
|
|
19
|
-
'@types/node': ^20.19.4
|
|
20
|
-
|
|
21
|
-
onlyBuiltDependencies:
|
|
22
|
-
- esbuild
|
|
23
|
-
|
|
24
|
-
packageImportMethod: clone-or-copy
|
|
25
|
-
`;
|
|
26
|
-
it("should parse valid YAML content", () => {
|
|
27
|
-
const result = parseYaml(yamlContent);
|
|
28
|
-
expect(result).toStrictEqual(ok({
|
|
29
|
-
catalog: {
|
|
30
|
-
"@tsconfig/node20": "^20.1.6",
|
|
31
|
-
"@types/node": "^20.19.4",
|
|
32
|
-
"@vitest/coverage-v8": "^3.2.4",
|
|
33
|
-
eslint: "^9.30.1",
|
|
34
|
-
prettier: "3.6.2",
|
|
35
|
-
tsup: "^8.5.0",
|
|
36
|
-
typescript: "~5.8.3",
|
|
37
|
-
vitest: "^3.2.4",
|
|
38
|
-
},
|
|
39
|
-
onlyBuiltDependencies: ["esbuild"],
|
|
40
|
-
packageImportMethod: "clone-or-copy",
|
|
41
|
-
packages: ["packages/*", "apps/*", "infra/modules/*"],
|
|
42
|
-
}));
|
|
43
|
-
});
|
|
44
|
-
it("should parse empty YAML content", () => {
|
|
45
|
-
const yamlContent = "";
|
|
46
|
-
const result = parseYaml(yamlContent);
|
|
47
|
-
expect(result).toStrictEqual(ok(null));
|
|
48
|
-
});
|
|
49
|
-
it("should return an error for invalid YAML content", () => {
|
|
50
|
-
const result = parseYaml("invalid: yaml: content: here");
|
|
51
|
-
expect(result).toStrictEqual(err(new Error("Failed to parse YAML")));
|
|
52
|
-
});
|
|
53
|
-
});
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import type { MockProxy } from "vitest-mock-extended";
|
|
2
|
-
import { Config } from "../../config.js";
|
|
3
|
-
import { GitHubAuthFactory } from "../dependencies.js";
|
|
4
|
-
import { PackageJson, PackageJsonReader } from "../package-json.js";
|
|
5
|
-
import { RepositoryReader } from "../repository.js";
|
|
6
|
-
import { ValidationReporter } from "../validation.js";
|
|
7
|
-
export declare const makeMockPackageJson: (overrides?: Partial<PackageJson>) => PackageJson;
|
|
8
|
-
export declare const makeMockDependencies: () => {
|
|
9
|
-
packageJsonReader: MockProxy<PackageJsonReader>;
|
|
10
|
-
repositoryReader: MockProxy<RepositoryReader>;
|
|
11
|
-
requireGitHubAuth: GitHubAuthFactory;
|
|
12
|
-
validationReporter: MockProxy<ValidationReporter>;
|
|
13
|
-
};
|
|
14
|
-
export declare const makeMockConfig: () => Config;
|
|
15
|
-
export declare const makeMockRepositoryRoot: () => string;
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { mock } from "vitest-mock-extended";
|
|
2
|
-
export const makeMockPackageJson = (overrides = {}) => {
|
|
3
|
-
const basePackageJson = {
|
|
4
|
-
dependencies: new Map(),
|
|
5
|
-
devDependencies: new Map(),
|
|
6
|
-
name: "test-package",
|
|
7
|
-
packageManager: "pnpm",
|
|
8
|
-
scripts: new Map(),
|
|
9
|
-
};
|
|
10
|
-
return {
|
|
11
|
-
...basePackageJson,
|
|
12
|
-
...overrides,
|
|
13
|
-
};
|
|
14
|
-
};
|
|
15
|
-
export const makeMockDependencies = () => ({
|
|
16
|
-
packageJsonReader: mock(),
|
|
17
|
-
repositoryReader: mock(),
|
|
18
|
-
requireGitHubAuth: mock(),
|
|
19
|
-
validationReporter: mock(),
|
|
20
|
-
});
|
|
21
|
-
export const makeMockConfig = () => ({
|
|
22
|
-
minVersions: {
|
|
23
|
-
nx: "22",
|
|
24
|
-
},
|
|
25
|
-
});
|
|
26
|
-
export const makeMockRepositoryRoot = () => "a/repo/root";
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|