@pagopa/dx-cli 0.22.4 → 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/README.md +18 -0
- package/dist/adapters/commander/commands/add.d.ts +2 -6
- package/dist/adapters/commander/commands/add.js +4 -8
- package/dist/adapters/commander/commands/init.d.ts +2 -6
- package/dist/adapters/commander/commands/init.js +6 -5
- package/dist/adapters/commander/commands/savemoney.d.ts +11 -0
- package/dist/adapters/commander/commands/savemoney.js +30 -5
- package/dist/adapters/commander/commands/spec.d.ts +10 -0
- package/dist/adapters/commander/commands/spec.js +13 -0
- package/dist/adapters/commander/index.js +6 -2
- package/dist/adapters/commander/spec.d.ts +16 -0
- package/dist/adapters/commander/spec.js +54 -0
- package/dist/adapters/plop/generators/environment/actions.js +3 -3
- package/dist/adapters/plop/index.js +3 -5
- package/dist/adapters/plop/templates-path.d.ts +5 -0
- package/dist/adapters/plop/templates-path.js +6 -0
- package/dist/domain/dependencies.d.ts +15 -2
- package/dist/domain/spec.d.ts +50 -0
- package/dist/domain/spec.js +8 -0
- package/dist/index.js +15 -12
- 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/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.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/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/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__/prompts.test.d.ts +0 -1
- package/dist/adapters/plop/generators/environment/__tests__/prompts.test.js +0 -182
- 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 -19
- package/dist/domain/__tests__/data.js +0 -28
- 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,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,19 +0,0 @@
|
|
|
1
|
-
import { Octokit } from "octokit";
|
|
2
|
-
import { DeepMockProxy, MockProxy } from "vitest-mock-extended";
|
|
3
|
-
import { Config } from "../../config.js";
|
|
4
|
-
import { AuthorizationService } from "../authorization.js";
|
|
5
|
-
import { GitHubService } from "../github.js";
|
|
6
|
-
import { PackageJson, PackageJsonReader } from "../package-json.js";
|
|
7
|
-
import { RepositoryReader } from "../repository.js";
|
|
8
|
-
import { ValidationReporter } from "../validation.js";
|
|
9
|
-
export declare const makeMockPackageJson: (overrides?: Partial<PackageJson>) => PackageJson;
|
|
10
|
-
export declare const makeMockDependencies: () => {
|
|
11
|
-
authorizationService: MockProxy<AuthorizationService>;
|
|
12
|
-
gitHubService: MockProxy<GitHubService>;
|
|
13
|
-
octokit: DeepMockProxy<Octokit>;
|
|
14
|
-
packageJsonReader: MockProxy<PackageJsonReader>;
|
|
15
|
-
repositoryReader: MockProxy<RepositoryReader>;
|
|
16
|
-
validationReporter: MockProxy<ValidationReporter>;
|
|
17
|
-
};
|
|
18
|
-
export declare const makeMockConfig: () => Config;
|
|
19
|
-
export declare const makeMockRepositoryRoot: () => string;
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { mock, mockDeep } 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
|
-
authorizationService: mock(),
|
|
17
|
-
gitHubService: mock(),
|
|
18
|
-
octokit: mockDeep(),
|
|
19
|
-
packageJsonReader: mock(),
|
|
20
|
-
repositoryReader: mock(),
|
|
21
|
-
validationReporter: mock(),
|
|
22
|
-
});
|
|
23
|
-
export const makeMockConfig = () => ({
|
|
24
|
-
minVersions: {
|
|
25
|
-
nx: "22",
|
|
26
|
-
},
|
|
27
|
-
});
|
|
28
|
-
export const makeMockRepositoryRoot = () => "a/repo/root";
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,332 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it, vi } from "vitest";
|
|
2
|
-
import { environmentSchema, getInitializationStatus, getTerraformBackend, hasUserPermissionToInitialize, } from "../environment.js";
|
|
3
|
-
const createMockCloudAccountService = (overrides = {}) => ({
|
|
4
|
-
getTerraformBackend: vi.fn().mockResolvedValue(undefined),
|
|
5
|
-
hasUserPermissionToInitialize: vi.fn().mockResolvedValue(true),
|
|
6
|
-
initialize: vi.fn().mockResolvedValue(undefined),
|
|
7
|
-
isInitialized: vi.fn().mockResolvedValue(true),
|
|
8
|
-
provisionTerraformBackend: vi.fn().mockResolvedValue(undefined),
|
|
9
|
-
...overrides,
|
|
10
|
-
});
|
|
11
|
-
const createMockCloudAccount = (overrides = {}) => ({
|
|
12
|
-
csp: "azure",
|
|
13
|
-
defaultLocation: "westeurope",
|
|
14
|
-
displayName: "Test Account",
|
|
15
|
-
id: "test-account-id",
|
|
16
|
-
...overrides,
|
|
17
|
-
});
|
|
18
|
-
const createMockEnvironment = (overrides = {}) => ({
|
|
19
|
-
cloudAccounts: [createMockCloudAccount()],
|
|
20
|
-
name: "dev",
|
|
21
|
-
prefix: "dx",
|
|
22
|
-
...overrides,
|
|
23
|
-
});
|
|
24
|
-
const createMockTerraformBackend = (overrides = {}) => ({
|
|
25
|
-
resourceGroupName: "dx-d-itn-tf-rg",
|
|
26
|
-
storageAccountName: "dxditntfst",
|
|
27
|
-
subscriptionId: "00000000-0000-0000-0000-000000000000",
|
|
28
|
-
type: "azurerm",
|
|
29
|
-
...overrides,
|
|
30
|
-
});
|
|
31
|
-
describe("getInitializationStatus", () => {
|
|
32
|
-
it("should return initialized true when all cloud accounts are initialized and backend exists", async () => {
|
|
33
|
-
const mockBackend = createMockTerraformBackend();
|
|
34
|
-
const mockService = createMockCloudAccountService({
|
|
35
|
-
getTerraformBackend: vi.fn().mockResolvedValue(mockBackend),
|
|
36
|
-
isInitialized: vi.fn().mockResolvedValue(true),
|
|
37
|
-
});
|
|
38
|
-
const environment = createMockEnvironment();
|
|
39
|
-
const result = await getInitializationStatus(mockService, environment);
|
|
40
|
-
expect(result).toEqual({ initialized: true });
|
|
41
|
-
});
|
|
42
|
-
it("should return CLOUD_ACCOUNT_NOT_INITIALIZED issue when cloud account is not initialized", async () => {
|
|
43
|
-
const cloudAccount = createMockCloudAccount({ id: "uninitialized-id" });
|
|
44
|
-
const mockBackend = createMockTerraformBackend();
|
|
45
|
-
const mockService = createMockCloudAccountService({
|
|
46
|
-
getTerraformBackend: vi.fn().mockResolvedValue(mockBackend),
|
|
47
|
-
isInitialized: vi.fn().mockResolvedValue(false),
|
|
48
|
-
});
|
|
49
|
-
const environment = createMockEnvironment({
|
|
50
|
-
cloudAccounts: [cloudAccount],
|
|
51
|
-
});
|
|
52
|
-
const result = await getInitializationStatus(mockService, environment);
|
|
53
|
-
expect(result).toEqual({
|
|
54
|
-
initialized: false,
|
|
55
|
-
issues: [
|
|
56
|
-
{
|
|
57
|
-
cloudAccount,
|
|
58
|
-
type: "CLOUD_ACCOUNT_NOT_INITIALIZED",
|
|
59
|
-
},
|
|
60
|
-
],
|
|
61
|
-
});
|
|
62
|
-
});
|
|
63
|
-
it("should return MISSING_REMOTE_BACKEND issue when terraform backend is not found", async () => {
|
|
64
|
-
const mockService = createMockCloudAccountService({
|
|
65
|
-
getTerraformBackend: vi.fn().mockResolvedValue(undefined),
|
|
66
|
-
isInitialized: vi.fn().mockResolvedValue(true),
|
|
67
|
-
});
|
|
68
|
-
const environment = createMockEnvironment();
|
|
69
|
-
const result = await getInitializationStatus(mockService, environment);
|
|
70
|
-
expect(result).toEqual({
|
|
71
|
-
initialized: false,
|
|
72
|
-
issues: [
|
|
73
|
-
{
|
|
74
|
-
type: "MISSING_REMOTE_BACKEND",
|
|
75
|
-
},
|
|
76
|
-
],
|
|
77
|
-
});
|
|
78
|
-
});
|
|
79
|
-
it("should return multiple issues when both cloud account is not initialized and backend is missing", async () => {
|
|
80
|
-
const cloudAccount = createMockCloudAccount();
|
|
81
|
-
const mockService = createMockCloudAccountService({
|
|
82
|
-
getTerraformBackend: vi.fn().mockResolvedValue(undefined),
|
|
83
|
-
isInitialized: vi.fn().mockResolvedValue(false),
|
|
84
|
-
});
|
|
85
|
-
const environment = createMockEnvironment({
|
|
86
|
-
cloudAccounts: [cloudAccount],
|
|
87
|
-
});
|
|
88
|
-
const result = await getInitializationStatus(mockService, environment);
|
|
89
|
-
expect(result).toEqual({
|
|
90
|
-
initialized: false,
|
|
91
|
-
issues: [
|
|
92
|
-
{
|
|
93
|
-
cloudAccount,
|
|
94
|
-
type: "CLOUD_ACCOUNT_NOT_INITIALIZED",
|
|
95
|
-
},
|
|
96
|
-
{
|
|
97
|
-
type: "MISSING_REMOTE_BACKEND",
|
|
98
|
-
},
|
|
99
|
-
],
|
|
100
|
-
});
|
|
101
|
-
});
|
|
102
|
-
it("should check initialization for each cloud account with correct parameters", async () => {
|
|
103
|
-
const cloudAccount1 = createMockCloudAccount({ id: "account-1" });
|
|
104
|
-
const cloudAccount2 = createMockCloudAccount({ id: "account-2" });
|
|
105
|
-
const mockBackend = createMockTerraformBackend();
|
|
106
|
-
const isInitializedMock = vi.fn().mockResolvedValue(true);
|
|
107
|
-
const mockService = createMockCloudAccountService({
|
|
108
|
-
getTerraformBackend: vi.fn().mockResolvedValue(mockBackend),
|
|
109
|
-
isInitialized: isInitializedMock,
|
|
110
|
-
});
|
|
111
|
-
const environment = createMockEnvironment({
|
|
112
|
-
cloudAccounts: [cloudAccount1, cloudAccount2],
|
|
113
|
-
name: "prod",
|
|
114
|
-
prefix: "io",
|
|
115
|
-
});
|
|
116
|
-
await getInitializationStatus(mockService, environment);
|
|
117
|
-
expect(isInitializedMock).toHaveBeenCalledTimes(2);
|
|
118
|
-
expect(isInitializedMock).toHaveBeenCalledWith("account-1", expect.objectContaining({
|
|
119
|
-
name: "prod",
|
|
120
|
-
prefix: "io",
|
|
121
|
-
}));
|
|
122
|
-
expect(isInitializedMock).toHaveBeenCalledWith("account-2", expect.objectContaining({
|
|
123
|
-
name: "prod",
|
|
124
|
-
prefix: "io",
|
|
125
|
-
}));
|
|
126
|
-
});
|
|
127
|
-
it("should return issues for multiple uninitialized cloud accounts", async () => {
|
|
128
|
-
const cloudAccount1 = createMockCloudAccount({ id: "account-1" });
|
|
129
|
-
const cloudAccount2 = createMockCloudAccount({ id: "account-2" });
|
|
130
|
-
const mockBackend = createMockTerraformBackend();
|
|
131
|
-
const mockService = createMockCloudAccountService({
|
|
132
|
-
getTerraformBackend: vi.fn().mockResolvedValue(mockBackend),
|
|
133
|
-
isInitialized: vi.fn().mockResolvedValue(false),
|
|
134
|
-
});
|
|
135
|
-
const environment = createMockEnvironment({
|
|
136
|
-
cloudAccounts: [cloudAccount1, cloudAccount2],
|
|
137
|
-
});
|
|
138
|
-
const result = await getInitializationStatus(mockService, environment);
|
|
139
|
-
expect(result).toEqual({
|
|
140
|
-
initialized: false,
|
|
141
|
-
issues: [
|
|
142
|
-
{
|
|
143
|
-
cloudAccount: cloudAccount1,
|
|
144
|
-
type: "CLOUD_ACCOUNT_NOT_INITIALIZED",
|
|
145
|
-
},
|
|
146
|
-
{
|
|
147
|
-
cloudAccount: cloudAccount2,
|
|
148
|
-
type: "CLOUD_ACCOUNT_NOT_INITIALIZED",
|
|
149
|
-
},
|
|
150
|
-
],
|
|
151
|
-
});
|
|
152
|
-
});
|
|
153
|
-
});
|
|
154
|
-
describe("getTerraformBackend", () => {
|
|
155
|
-
it("should return the terraform backend when it exists", async () => {
|
|
156
|
-
const mockBackend = createMockTerraformBackend();
|
|
157
|
-
const mockService = createMockCloudAccountService({
|
|
158
|
-
getTerraformBackend: vi.fn().mockResolvedValue(mockBackend),
|
|
159
|
-
});
|
|
160
|
-
const environment = createMockEnvironment();
|
|
161
|
-
const result = await getTerraformBackend(mockService, environment);
|
|
162
|
-
expect(result).toEqual(mockBackend);
|
|
163
|
-
});
|
|
164
|
-
it("should return undefined when no terraform backend exists", async () => {
|
|
165
|
-
const mockService = createMockCloudAccountService({
|
|
166
|
-
getTerraformBackend: vi.fn().mockResolvedValue(undefined),
|
|
167
|
-
});
|
|
168
|
-
const environment = createMockEnvironment();
|
|
169
|
-
const result = await getTerraformBackend(mockService, environment);
|
|
170
|
-
expect(result).toBeUndefined();
|
|
171
|
-
});
|
|
172
|
-
it("should call getTerraformBackend with correct parameters", async () => {
|
|
173
|
-
const getTerraformBackendMock = vi.fn().mockResolvedValue(undefined);
|
|
174
|
-
const mockService = createMockCloudAccountService({
|
|
175
|
-
getTerraformBackend: getTerraformBackendMock,
|
|
176
|
-
});
|
|
177
|
-
const environment = createMockEnvironment({
|
|
178
|
-
cloudAccounts: [createMockCloudAccount({ id: "my-account" })],
|
|
179
|
-
name: "uat",
|
|
180
|
-
prefix: "io",
|
|
181
|
-
});
|
|
182
|
-
await getTerraformBackend(mockService, environment);
|
|
183
|
-
expect(getTerraformBackendMock).toHaveBeenCalledWith("my-account", expect.objectContaining({
|
|
184
|
-
name: "uat",
|
|
185
|
-
prefix: "io",
|
|
186
|
-
}));
|
|
187
|
-
});
|
|
188
|
-
it("should return the first backend found when multiple cloud accounts exist", async () => {
|
|
189
|
-
const mockBackend = createMockTerraformBackend({
|
|
190
|
-
storageAccountName: "firstaccountst",
|
|
191
|
-
});
|
|
192
|
-
const getTerraformBackendMock = vi.fn().mockResolvedValue(mockBackend);
|
|
193
|
-
const mockService = createMockCloudAccountService({
|
|
194
|
-
getTerraformBackend: getTerraformBackendMock,
|
|
195
|
-
});
|
|
196
|
-
const environment = createMockEnvironment({
|
|
197
|
-
cloudAccounts: [
|
|
198
|
-
createMockCloudAccount({ id: "account-1" }),
|
|
199
|
-
createMockCloudAccount({ id: "account-2" }),
|
|
200
|
-
],
|
|
201
|
-
});
|
|
202
|
-
const result = await getTerraformBackend(mockService, environment);
|
|
203
|
-
expect(result).toEqual(mockBackend);
|
|
204
|
-
// Should only call for the first account due to early return
|
|
205
|
-
expect(getTerraformBackendMock).toHaveBeenCalledTimes(1);
|
|
206
|
-
});
|
|
207
|
-
it("should return undefined when environment has no cloud accounts", async () => {
|
|
208
|
-
const mockService = createMockCloudAccountService();
|
|
209
|
-
const environment = createMockEnvironment({
|
|
210
|
-
cloudAccounts: [],
|
|
211
|
-
});
|
|
212
|
-
const result = await getTerraformBackend(mockService, environment);
|
|
213
|
-
expect(result).toBeUndefined();
|
|
214
|
-
});
|
|
215
|
-
});
|
|
216
|
-
describe("hasUserPermissionToInitialize", () => {
|
|
217
|
-
it("should return true when all cloud accounts have permission", async () => {
|
|
218
|
-
const mockService = createMockCloudAccountService({
|
|
219
|
-
hasUserPermissionToInitialize: vi.fn().mockResolvedValue(true),
|
|
220
|
-
});
|
|
221
|
-
const environment = createMockEnvironment({
|
|
222
|
-
cloudAccounts: [
|
|
223
|
-
createMockCloudAccount({ id: "account-1" }),
|
|
224
|
-
createMockCloudAccount({ id: "account-2" }),
|
|
225
|
-
],
|
|
226
|
-
});
|
|
227
|
-
const result = await hasUserPermissionToInitialize(mockService, environment);
|
|
228
|
-
expect(result).toBe(true);
|
|
229
|
-
});
|
|
230
|
-
it("should return false when any cloud account lacks permission", async () => {
|
|
231
|
-
const hasUserPermissionMock = vi
|
|
232
|
-
.fn()
|
|
233
|
-
.mockResolvedValueOnce(true)
|
|
234
|
-
.mockResolvedValueOnce(false);
|
|
235
|
-
const mockService = createMockCloudAccountService({
|
|
236
|
-
hasUserPermissionToInitialize: hasUserPermissionMock,
|
|
237
|
-
});
|
|
238
|
-
const environment = createMockEnvironment({
|
|
239
|
-
cloudAccounts: [
|
|
240
|
-
createMockCloudAccount({ id: "account-1" }),
|
|
241
|
-
createMockCloudAccount({ id: "account-2" }),
|
|
242
|
-
],
|
|
243
|
-
});
|
|
244
|
-
const result = await hasUserPermissionToInitialize(mockService, environment);
|
|
245
|
-
expect(result).toBe(false);
|
|
246
|
-
expect(hasUserPermissionMock).toHaveBeenCalledTimes(2);
|
|
247
|
-
});
|
|
248
|
-
it("should short-circuit and return false on first unauthorized account", async () => {
|
|
249
|
-
const hasUserPermissionMock = vi.fn().mockResolvedValue(false);
|
|
250
|
-
const mockService = createMockCloudAccountService({
|
|
251
|
-
hasUserPermissionToInitialize: hasUserPermissionMock,
|
|
252
|
-
});
|
|
253
|
-
const environment = createMockEnvironment({
|
|
254
|
-
cloudAccounts: [
|
|
255
|
-
createMockCloudAccount({ id: "account-1" }),
|
|
256
|
-
createMockCloudAccount({ id: "account-2" }),
|
|
257
|
-
createMockCloudAccount({ id: "account-3" }),
|
|
258
|
-
],
|
|
259
|
-
});
|
|
260
|
-
const result = await hasUserPermissionToInitialize(mockService, environment);
|
|
261
|
-
expect(result).toBe(false);
|
|
262
|
-
// Should only check the first account before short-circuiting
|
|
263
|
-
expect(hasUserPermissionMock).toHaveBeenCalledTimes(1);
|
|
264
|
-
expect(hasUserPermissionMock).toHaveBeenCalledWith("account-1");
|
|
265
|
-
});
|
|
266
|
-
it("should call service with correct cloud account IDs", async () => {
|
|
267
|
-
const hasUserPermissionMock = vi.fn().mockResolvedValue(true);
|
|
268
|
-
const mockService = createMockCloudAccountService({
|
|
269
|
-
hasUserPermissionToInitialize: hasUserPermissionMock,
|
|
270
|
-
});
|
|
271
|
-
const environment = createMockEnvironment({
|
|
272
|
-
cloudAccounts: [
|
|
273
|
-
createMockCloudAccount({ id: "account-a" }),
|
|
274
|
-
createMockCloudAccount({ id: "account-b" }),
|
|
275
|
-
],
|
|
276
|
-
});
|
|
277
|
-
await hasUserPermissionToInitialize(mockService, environment);
|
|
278
|
-
expect(hasUserPermissionMock).toHaveBeenCalledTimes(2);
|
|
279
|
-
expect(hasUserPermissionMock).toHaveBeenNthCalledWith(1, "account-a");
|
|
280
|
-
expect(hasUserPermissionMock).toHaveBeenNthCalledWith(2, "account-b");
|
|
281
|
-
});
|
|
282
|
-
});
|
|
283
|
-
describe("environmentSchema — prefix transforms", () => {
|
|
284
|
-
const baseEnv = {
|
|
285
|
-
cloudAccounts: [
|
|
286
|
-
{
|
|
287
|
-
csp: "azure",
|
|
288
|
-
defaultLocation: "westeurope",
|
|
289
|
-
displayName: "Test Account",
|
|
290
|
-
id: "test-account-id",
|
|
291
|
-
},
|
|
292
|
-
],
|
|
293
|
-
name: "dev",
|
|
294
|
-
prefix: "dx",
|
|
295
|
-
};
|
|
296
|
-
it("lowercases an uppercase prefix", () => {
|
|
297
|
-
const result = environmentSchema.safeParse({ ...baseEnv, prefix: "ABC" });
|
|
298
|
-
expect(result.success).toBe(true);
|
|
299
|
-
expect(result.success && result.data.prefix).toBe("abc");
|
|
300
|
-
});
|
|
301
|
-
it("lowercases a mixed-case prefix", () => {
|
|
302
|
-
const result = environmentSchema.safeParse({ ...baseEnv, prefix: "AbCd" });
|
|
303
|
-
expect(result.success).toBe(true);
|
|
304
|
-
expect(result.success && result.data.prefix).toBe("abcd");
|
|
305
|
-
});
|
|
306
|
-
it("trims leading and trailing whitespace from prefix", () => {
|
|
307
|
-
const result = environmentSchema.safeParse({ ...baseEnv, prefix: " dx " });
|
|
308
|
-
expect(result.success).toBe(true);
|
|
309
|
-
expect(result.success && result.data.prefix).toBe("dx");
|
|
310
|
-
});
|
|
311
|
-
it("trims and lowercases prefix together", () => {
|
|
312
|
-
const result = environmentSchema.safeParse({ ...baseEnv, prefix: " DX " });
|
|
313
|
-
expect(result.success).toBe(true);
|
|
314
|
-
expect(result.success && result.data.prefix).toBe("dx");
|
|
315
|
-
});
|
|
316
|
-
it("still rejects a prefix shorter than 2 characters after trim", () => {
|
|
317
|
-
const result = environmentSchema.safeParse({ ...baseEnv, prefix: " a " });
|
|
318
|
-
expect(result.success).toBe(false);
|
|
319
|
-
});
|
|
320
|
-
it("still rejects a prefix longer than 4 characters after trim", () => {
|
|
321
|
-
const result = environmentSchema.safeParse({
|
|
322
|
-
...baseEnv,
|
|
323
|
-
prefix: "abcde",
|
|
324
|
-
});
|
|
325
|
-
expect(result.success).toBe(false);
|
|
326
|
-
});
|
|
327
|
-
it("accepts a valid lowercase prefix unchanged", () => {
|
|
328
|
-
const result = environmentSchema.safeParse({ ...baseEnv, prefix: "dx" });
|
|
329
|
-
expect(result.success).toBe(true);
|
|
330
|
-
expect(result.success && result.data.prefix).toBe("dx");
|
|
331
|
-
});
|
|
332
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|