@pagopa/dx-cli 0.15.1 → 0.15.3
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/bin/index.js +8 -1280
- package/dist/adapters/azure/__tests__/cloud-account-repository.test.d.ts +1 -0
- package/dist/adapters/azure/__tests__/cloud-account-repository.test.js +95 -0
- package/dist/adapters/azure/__tests__/cloud-account-service.test.d.ts +1 -0
- package/dist/adapters/azure/__tests__/cloud-account-service.test.js +95 -0
- package/dist/adapters/azure/cloud-account-repository.d.ts +12 -0
- package/dist/adapters/azure/cloud-account-repository.js +23 -0
- package/dist/adapters/azure/cloud-account-service.d.ts +22 -0
- package/dist/adapters/azure/cloud-account-service.js +255 -0
- package/dist/adapters/azure/locations.d.ts +7 -0
- package/dist/adapters/azure/locations.js +21 -0
- package/dist/adapters/codemods/__tests__/registry.test.d.ts +1 -0
- package/dist/adapters/codemods/__tests__/registry.test.js +59 -0
- package/dist/adapters/codemods/__tests__/use-azure-appsvc.test.d.ts +1 -0
- package/dist/adapters/codemods/__tests__/use-azure-appsvc.test.js +77 -0
- package/dist/adapters/codemods/__tests__/use-pnpm.test.d.ts +1 -0
- package/dist/adapters/codemods/__tests__/use-pnpm.test.js +148 -0
- package/dist/adapters/codemods/git.d.ts +2 -0
- package/dist/adapters/codemods/git.js +18 -0
- package/dist/adapters/codemods/index.d.ts +3 -0
- package/dist/adapters/codemods/index.js +9 -0
- package/dist/adapters/codemods/registry.d.ts +8 -0
- package/dist/adapters/codemods/registry.js +16 -0
- package/dist/adapters/codemods/update-code-review.d.ts +3 -0
- package/dist/adapters/codemods/update-code-review.js +60 -0
- package/dist/adapters/codemods/use-azure-appsvc.d.ts +3 -0
- package/dist/adapters/codemods/use-azure-appsvc.js +84 -0
- package/dist/adapters/codemods/use-pnpm.d.ts +22 -0
- package/dist/adapters/codemods/use-pnpm.js +214 -0
- package/dist/adapters/codemods/yaml.d.ts +2 -0
- package/dist/adapters/codemods/yaml.js +8 -0
- package/dist/adapters/commander/commands/codemod.d.ts +8 -0
- package/dist/adapters/commander/commands/codemod.js +22 -0
- package/dist/adapters/commander/commands/doctor.d.ts +4 -0
- package/dist/adapters/commander/commands/doctor.js +12 -0
- package/dist/adapters/commander/commands/info.d.ts +3 -0
- package/dist/adapters/commander/commands/info.js +9 -0
- package/dist/adapters/commander/commands/init.d.ts +7 -0
- package/dist/adapters/commander/commands/init.js +126 -0
- package/dist/adapters/commander/commands/savemoney.d.ts +2 -0
- package/dist/adapters/commander/commands/savemoney.js +26 -0
- package/dist/adapters/commander/index.d.ts +7 -0
- package/dist/adapters/commander/index.js +19 -0
- package/dist/adapters/execa/terraform.d.ts +27 -0
- package/dist/adapters/execa/terraform.js +28 -0
- package/dist/adapters/github/__tests__/github-repo.spec.d.ts +1 -0
- package/dist/adapters/github/__tests__/github-repo.spec.js +67 -0
- package/dist/adapters/github/github-repo.d.ts +2 -0
- package/dist/adapters/github/github-repo.js +31 -0
- package/dist/adapters/logtape/validation-reporter.d.ts +2 -0
- package/dist/adapters/logtape/validation-reporter.js +14 -0
- package/dist/adapters/node/__tests__/data.d.ts +18 -0
- package/dist/adapters/node/__tests__/data.js +22 -0
- package/dist/adapters/node/__tests__/package-json.test.d.ts +1 -0
- package/dist/adapters/node/__tests__/package-json.test.js +86 -0
- package/dist/adapters/node/__tests__/repository.test.d.ts +1 -0
- package/dist/adapters/node/__tests__/repository.test.js +77 -0
- package/dist/adapters/node/fs/__tests__/file-reader.test.d.ts +1 -0
- package/dist/adapters/node/fs/__tests__/file-reader.test.js +80 -0
- package/dist/adapters/node/fs/file-reader.d.ts +24 -0
- package/dist/adapters/node/fs/file-reader.js +26 -0
- package/dist/adapters/node/json/__tests__/index.test.d.ts +1 -0
- package/dist/adapters/node/json/__tests__/index.test.js +14 -0
- package/dist/adapters/node/json/index.d.ts +2 -0
- package/dist/adapters/node/json/index.js +2 -0
- package/dist/adapters/node/package-json.d.ts +2 -0
- package/dist/adapters/node/package-json.js +22 -0
- package/dist/adapters/node/release.d.ts +2 -0
- package/dist/adapters/node/release.js +33 -0
- package/dist/adapters/node/repository.d.ts +2 -0
- package/dist/adapters/node/repository.js +47 -0
- package/dist/adapters/octokit/__tests__/index.test.d.ts +1 -0
- package/dist/adapters/octokit/__tests__/index.test.js +197 -0
- package/dist/adapters/octokit/index.d.ts +24 -0
- package/dist/adapters/octokit/index.js +65 -0
- package/dist/adapters/plop/actions/__tests__/init-cloud-accounts.test.d.ts +1 -0
- package/dist/adapters/plop/actions/__tests__/init-cloud-accounts.test.js +115 -0
- package/dist/adapters/plop/actions/__tests__/provision-terraform-backend.test.d.ts +1 -0
- package/dist/adapters/plop/actions/__tests__/provision-terraform-backend.test.js +116 -0
- package/dist/adapters/plop/actions/fetch-github-release.d.ts +12 -0
- package/dist/adapters/plop/actions/fetch-github-release.js +20 -0
- package/dist/adapters/plop/actions/get-node-version.d.ts +2 -0
- package/dist/adapters/plop/actions/get-node-version.js +9 -0
- package/dist/adapters/plop/actions/get-terraform-backend.d.ts +3 -0
- package/dist/adapters/plop/actions/get-terraform-backend.js +17 -0
- package/dist/adapters/plop/actions/init-cloud-accounts.d.ts +5 -0
- package/dist/adapters/plop/actions/init-cloud-accounts.js +13 -0
- package/dist/adapters/plop/actions/provision-terraform-backend.d.ts +10 -0
- package/dist/adapters/plop/actions/provision-terraform-backend.js +16 -0
- package/dist/adapters/plop/actions/semver.d.ts +19 -0
- package/dist/adapters/plop/actions/semver.js +27 -0
- package/dist/adapters/plop/actions/setup-pnpm.d.ts +2 -0
- package/dist/adapters/plop/actions/setup-pnpm.js +26 -0
- package/dist/adapters/plop/generators/environment/__tests__/actions.test.d.ts +2 -0
- package/dist/adapters/plop/generators/environment/__tests__/actions.test.js +55 -0
- package/dist/adapters/plop/generators/environment/actions.d.ts +2 -0
- package/dist/adapters/plop/generators/environment/actions.js +54 -0
- package/dist/adapters/plop/generators/environment/index.d.ts +3 -0
- package/dist/adapters/plop/generators/environment/index.js +19 -0
- package/dist/adapters/plop/generators/environment/prompts.d.ts +66 -0
- package/dist/adapters/plop/generators/environment/prompts.js +166 -0
- package/dist/adapters/plop/generators/monorepo/actions.d.ts +51 -0
- package/dist/adapters/plop/generators/monorepo/actions.js +35 -0
- package/dist/adapters/plop/generators/monorepo/index.d.ts +6 -0
- package/dist/adapters/plop/generators/monorepo/index.js +17 -0
- package/dist/adapters/plop/generators/monorepo/prompts.d.ts +10 -0
- package/dist/adapters/plop/generators/monorepo/prompts.js +31 -0
- package/dist/adapters/plop/helpers/__tests__/resource-prefix.test.d.ts +1 -0
- package/dist/adapters/plop/helpers/__tests__/resource-prefix.test.js +113 -0
- package/dist/adapters/plop/helpers/env-short.d.ts +3 -0
- package/dist/adapters/plop/helpers/env-short.js +9 -0
- package/dist/adapters/plop/helpers/resource-prefix.d.ts +5 -0
- package/dist/adapters/plop/helpers/resource-prefix.js +18 -0
- package/dist/adapters/plop/index.d.ts +8 -0
- package/dist/adapters/plop/index.js +24 -0
- package/dist/adapters/terraform/fmt.d.ts +1 -0
- package/dist/adapters/terraform/fmt.js +17 -0
- package/dist/adapters/yaml/__tests__/index.test.d.ts +1 -0
- package/dist/adapters/yaml/__tests__/index.test.js +53 -0
- package/dist/adapters/yaml/index.d.ts +8 -0
- package/dist/adapters/yaml/index.js +9 -0
- package/dist/adapters/zod/index.d.ts +23 -0
- package/dist/adapters/zod/index.js +22 -0
- package/dist/config.d.ts +6 -0
- package/dist/config.js +5 -0
- package/dist/domain/__tests__/data.d.ts +17 -0
- package/dist/domain/__tests__/data.js +27 -0
- package/dist/domain/__tests__/environment.test.d.ts +1 -0
- package/dist/domain/__tests__/environment.test.js +282 -0
- package/dist/domain/__tests__/info.test.d.ts +1 -0
- package/dist/domain/__tests__/info.test.js +77 -0
- package/dist/domain/__tests__/package-json.test.d.ts +1 -0
- package/dist/domain/__tests__/package-json.test.js +39 -0
- package/dist/domain/__tests__/repository.test.d.ts +1 -0
- package/dist/domain/__tests__/repository.test.js +101 -0
- package/dist/domain/__tests__/workspace.test.d.ts +1 -0
- package/dist/domain/__tests__/workspace.test.js +57 -0
- package/dist/domain/cloud-account.d.ts +28 -0
- package/dist/domain/cloud-account.js +12 -0
- package/dist/domain/codemod.d.ts +11 -0
- package/dist/domain/codemod.js +1 -0
- package/dist/domain/dependencies.d.ts +10 -0
- package/dist/domain/dependencies.js +1 -0
- package/dist/domain/doctor.d.ts +10 -0
- package/dist/domain/doctor.js +50 -0
- package/dist/domain/environment.d.ts +40 -0
- package/dist/domain/environment.js +57 -0
- package/dist/domain/github-repo.d.ts +6 -0
- package/dist/domain/github-repo.js +8 -0
- package/dist/domain/github.d.ts +37 -0
- package/dist/domain/github.js +29 -0
- package/dist/domain/info.d.ts +11 -0
- package/dist/domain/info.js +52 -0
- package/dist/domain/package-json.d.ts +42 -0
- package/dist/domain/package-json.js +69 -0
- package/dist/domain/remote-backend.d.ts +8 -0
- package/dist/domain/remote-backend.js +9 -0
- package/dist/domain/repository.d.ts +13 -0
- package/dist/domain/repository.js +72 -0
- package/dist/domain/validation.d.ts +16 -0
- package/dist/domain/validation.js +1 -0
- package/dist/domain/workspace.d.ts +9 -0
- package/dist/domain/workspace.js +32 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +35 -0
- package/dist/use-cases/__tests__/apply-codemod.test.d.ts +1 -0
- package/dist/use-cases/__tests__/apply-codemod.test.js +73 -0
- package/dist/use-cases/__tests__/list-codemods.test.d.ts +1 -0
- package/dist/use-cases/__tests__/list-codemods.test.js +38 -0
- package/dist/use-cases/apply-codemod.d.ts +5 -0
- package/dist/use-cases/apply-codemod.js +14 -0
- package/dist/use-cases/list-codemods.d.ts +4 -0
- package/dist/use-cases/list-codemods.js +1 -0
- package/package.json +19 -8
- package/templates/environment/bootstrapper/{{env.name}}/data.tf.hbs +13 -0
- package/templates/environment/bootstrapper/{{env.name}}/main.tf.hbs +70 -0
- package/templates/environment/bootstrapper/{{env.name}}/providers.tf.hbs +26 -0
- package/templates/environment/core/{{env.name}}/main.tf.hbs +21 -0
- package/templates/environment/core/{{env.name}}/outputs.tf.hbs +8 -0
- package/templates/environment/core/{{env.name}}/providers.tf.hbs +21 -0
- package/templates/environment/shared/backend.tf.hbs +14 -0
- package/templates/environment/shared/locals.tf.hbs +26 -0
- package/templates/monorepo/.editorconfig +8 -0
- package/templates/monorepo/.node-version.hbs +1 -0
- package/templates/monorepo/.pre-commit-config.yaml.hbs +34 -0
- package/templates/monorepo/.prettierignore +5 -0
- package/templates/monorepo/.terraform-version.hbs +1 -0
- package/templates/monorepo/.trivyignore +16 -0
- package/templates/monorepo/README.md.hbs +163 -0
- package/templates/monorepo/infra/repository/main.tf.hbs +11 -0
- package/templates/monorepo/infra/repository/outputs.tf.hbs +11 -0
- package/templates/monorepo/infra/repository/providers.tf.hbs +13 -0
- package/templates/monorepo/package.json.hbs +7 -0
- package/templates/monorepo/pnpm-workspace.yaml +7 -0
- package/templates/monorepo/turbo.json +29 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { migrateWorkflow } from "../use-azure-appsvc.js";
|
|
3
|
+
describe("migrateWorkflow", () => {
|
|
4
|
+
const sha = "testsha";
|
|
5
|
+
const migrate = migrateWorkflow(sha);
|
|
6
|
+
it("adds disable_auto_staging_deploy under with for web_app_deploy", () => {
|
|
7
|
+
const input = `
|
|
8
|
+
jobs:
|
|
9
|
+
deploy:
|
|
10
|
+
uses: pagopa/dx/.github/workflows/web_app_deploy.yaml@main
|
|
11
|
+
with:
|
|
12
|
+
web_app_name: my-app
|
|
13
|
+
use_staging_slot: true
|
|
14
|
+
`;
|
|
15
|
+
const output = migrate(input, "workflow.yaml");
|
|
16
|
+
expect(output).toContain("disable_auto_staging_deploy: true");
|
|
17
|
+
});
|
|
18
|
+
it("adds disable_auto_staging_deploy under with for function_app_deploy", () => {
|
|
19
|
+
const input = `
|
|
20
|
+
jobs:
|
|
21
|
+
deploy:
|
|
22
|
+
uses: pagopa/dx/.github/workflows/function_app_deploy.yaml@main
|
|
23
|
+
with:
|
|
24
|
+
function_app_name: my-func
|
|
25
|
+
use_staging_slot: true
|
|
26
|
+
`;
|
|
27
|
+
const output = migrate(input, "workflow.yaml");
|
|
28
|
+
expect(output).toContain("disable_auto_staging_deploy: true");
|
|
29
|
+
});
|
|
30
|
+
it("renames function_app_name to web_app_name", () => {
|
|
31
|
+
const input = `
|
|
32
|
+
jobs:
|
|
33
|
+
deploy:
|
|
34
|
+
uses: pagopa/dx/.github/workflows/function_app_deploy.yaml@main
|
|
35
|
+
with:
|
|
36
|
+
function_app_name: my-func
|
|
37
|
+
`;
|
|
38
|
+
const output = migrate(input, "workflow.yaml");
|
|
39
|
+
expect(output).toContain("web_app_name: my-func");
|
|
40
|
+
expect(output).not.toContain("function_app_name:");
|
|
41
|
+
});
|
|
42
|
+
it("removes use_staging_slot", () => {
|
|
43
|
+
const input = `
|
|
44
|
+
jobs:
|
|
45
|
+
deploy:
|
|
46
|
+
uses: pagopa/dx/.github/workflows/web_app_deploy.yaml@main
|
|
47
|
+
with:
|
|
48
|
+
web_app_name: my-app
|
|
49
|
+
use_staging_slot: true
|
|
50
|
+
`;
|
|
51
|
+
const output = migrate(input, "workflow.yaml");
|
|
52
|
+
expect(output).not.toContain("use_staging_slot:");
|
|
53
|
+
});
|
|
54
|
+
it("updates uses to release-azure-appsvc.yaml@sha", () => {
|
|
55
|
+
const input = `
|
|
56
|
+
jobs:
|
|
57
|
+
deploy:
|
|
58
|
+
uses: pagopa/dx/.github/workflows/web_app_deploy.yaml@main
|
|
59
|
+
with:
|
|
60
|
+
web_app_name: my-app
|
|
61
|
+
`;
|
|
62
|
+
const output = migrate(input, "workflow.yaml");
|
|
63
|
+
expect(output).toContain(`uses: pagopa/dx/.github/workflows/release-azure-appsvc-v1.yaml@${sha}`);
|
|
64
|
+
});
|
|
65
|
+
it("does not change unrelated workflows", () => {
|
|
66
|
+
const input = `
|
|
67
|
+
jobs:
|
|
68
|
+
build:
|
|
69
|
+
runs-on: ubuntu-latest
|
|
70
|
+
steps:
|
|
71
|
+
- name: Checkout
|
|
72
|
+
uses: actions/checkout@v3
|
|
73
|
+
`;
|
|
74
|
+
const output = migrate(input, "workflow.yaml");
|
|
75
|
+
expect(output).toBe(input);
|
|
76
|
+
});
|
|
77
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, test, vi } from "vitest";
|
|
2
|
+
import YAML from "yaml";
|
|
3
|
+
import { extractPackageExtensions, NPM, preparePackageJsonForPnpm, usePnpm, writePnpmWorkspaceFile, Yarn, } from "../use-pnpm.js";
|
|
4
|
+
const { readFile, stdout, writeFile } = vi.hoisted(() => ({
|
|
5
|
+
readFile: vi.fn(async () => ""),
|
|
6
|
+
stdout: vi.fn(),
|
|
7
|
+
writeFile: vi.fn(),
|
|
8
|
+
}));
|
|
9
|
+
vi.mock("execa", () => ({
|
|
10
|
+
$: vi.fn((opts) => {
|
|
11
|
+
const hasOptions = typeof opts === "object" && Object.hasOwn(opts, "lines");
|
|
12
|
+
if (hasOptions) {
|
|
13
|
+
return () => stdout().then((output) => ({
|
|
14
|
+
stdout: output.split("\n"),
|
|
15
|
+
}));
|
|
16
|
+
}
|
|
17
|
+
return stdout().then((output) => ({
|
|
18
|
+
stdout: output,
|
|
19
|
+
}));
|
|
20
|
+
}),
|
|
21
|
+
}));
|
|
22
|
+
vi.mock("node:fs/promises", () => ({
|
|
23
|
+
default: {
|
|
24
|
+
appendFile: () => Promise.resolve(),
|
|
25
|
+
readFile,
|
|
26
|
+
rm: () => Promise.resolve(),
|
|
27
|
+
stat: () => Promise.resolve({
|
|
28
|
+
isFile: () => true,
|
|
29
|
+
}),
|
|
30
|
+
writeFile,
|
|
31
|
+
},
|
|
32
|
+
}));
|
|
33
|
+
vi.mock("../git.js", async () => ({
|
|
34
|
+
getLatestCommitShaOrRef: async () => "dummy-sha",
|
|
35
|
+
}));
|
|
36
|
+
describe("pm", () => {
|
|
37
|
+
test("yarn workspaces are parsed correctly", async () => {
|
|
38
|
+
const yarn = new Yarn();
|
|
39
|
+
stdout.mockResolvedValueOnce(`{"location":".","name":"io-messages"}\n{"location":"apps/citizen-func","name":"citizen-func"}`);
|
|
40
|
+
const workspaces = await yarn.listWorkspaces();
|
|
41
|
+
expect(workspaces).toEqual(["io-messages", "citizen-func"]);
|
|
42
|
+
});
|
|
43
|
+
test("npm workspaces are parsed correctly", async () => {
|
|
44
|
+
const npm = new NPM();
|
|
45
|
+
stdout.mockResolvedValueOnce(`[{ "name": "io-messages", "location": "." },{ "name": "citizen-func", "location": "apps/citizen-func" }]`);
|
|
46
|
+
const workspaces = await npm.listWorkspaces();
|
|
47
|
+
expect(workspaces).toEqual(["io-messages", "citizen-func"]);
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
describe("extractPackageExtensions", () => {
|
|
51
|
+
beforeEach(() => {
|
|
52
|
+
vi.clearAllMocks();
|
|
53
|
+
});
|
|
54
|
+
test("returns packageExtensions only if present", async () => {
|
|
55
|
+
const yarnrc = {
|
|
56
|
+
packageExtensions: {
|
|
57
|
+
"some-package@*": {
|
|
58
|
+
peerDependencies: {
|
|
59
|
+
react: "*",
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
readFile.mockResolvedValueOnce(YAML.stringify(yarnrc));
|
|
65
|
+
await expect(extractPackageExtensions()).resolves.toEqual(yarnrc.packageExtensions);
|
|
66
|
+
expect(readFile).toHaveBeenCalledOnce();
|
|
67
|
+
});
|
|
68
|
+
test("returns undefined if packageExtensions is not present", async () => {
|
|
69
|
+
const yarnrc = {
|
|
70
|
+
someOtherField: {},
|
|
71
|
+
};
|
|
72
|
+
readFile.mockResolvedValueOnce(YAML.stringify(yarnrc));
|
|
73
|
+
await expect(extractPackageExtensions()).resolves.toBeUndefined();
|
|
74
|
+
expect(readFile).toHaveBeenCalledOnce();
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
describe("preparePackageJsonForPnpm", () => {
|
|
78
|
+
beforeEach(() => {
|
|
79
|
+
vi.clearAllMocks();
|
|
80
|
+
});
|
|
81
|
+
test("removes packageManager field and keeps workspaces", async () => {
|
|
82
|
+
const packageJson = {
|
|
83
|
+
name: "test-monorepo",
|
|
84
|
+
packageManager: "yarn@1.22.10",
|
|
85
|
+
version: "1.0.0",
|
|
86
|
+
workspaces: ["packages/*"],
|
|
87
|
+
};
|
|
88
|
+
readFile.mockResolvedValueOnce(JSON.stringify(packageJson, null, 2));
|
|
89
|
+
const workspaces = await preparePackageJsonForPnpm();
|
|
90
|
+
expect(workspaces).toEqual(["packages/*"]);
|
|
91
|
+
expect(readFile).toHaveBeenCalledOnce();
|
|
92
|
+
expect(writeFile).toHaveBeenCalledWith("package.json", JSON.stringify({
|
|
93
|
+
name: packageJson.name,
|
|
94
|
+
version: packageJson.version,
|
|
95
|
+
}, null, 2));
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
describe("writePnpmWorkspaceFile", () => {
|
|
99
|
+
beforeEach(() => {
|
|
100
|
+
vi.clearAllMocks();
|
|
101
|
+
});
|
|
102
|
+
test("writes pnpm-workspace.yaml with given workspaces", async () => {
|
|
103
|
+
const workspaces = ["packages/*", "apps/*"];
|
|
104
|
+
const packageExtensions = {
|
|
105
|
+
"express@*": {
|
|
106
|
+
peerDependencies: {
|
|
107
|
+
typescript: "*",
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
};
|
|
111
|
+
await writePnpmWorkspaceFile(workspaces, packageExtensions);
|
|
112
|
+
expect(writeFile).toHaveBeenCalledWith("pnpm-workspace.yaml", expect.stringContaining(YAML.stringify({ packages: workspaces })), "utf-8");
|
|
113
|
+
expect(writeFile).toHaveBeenCalledWith("pnpm-workspace.yaml", expect.stringContaining(YAML.stringify({ packageExtensions })), "utf-8");
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
describe("usePnpm", () => {
|
|
117
|
+
beforeEach(() => {
|
|
118
|
+
vi.resetAllMocks();
|
|
119
|
+
});
|
|
120
|
+
test("rejects if the project is already using pnpm", async () => {
|
|
121
|
+
await expect(usePnpm("pnpm", "10.20")).rejects.toThrow();
|
|
122
|
+
});
|
|
123
|
+
test.each([
|
|
124
|
+
{ expected: false, version: "18.0.0" },
|
|
125
|
+
{ expected: false, version: "20.10.0" },
|
|
126
|
+
{ expected: false, version: "20.19.4" },
|
|
127
|
+
{ expected: true, version: "22.0.0" },
|
|
128
|
+
{ expected: true, version: "20.19.5" },
|
|
129
|
+
])("rejects if Node.js version is less than required ($version)", async ({ expected, version }) => {
|
|
130
|
+
stdout.mockResolvedValue("[]");
|
|
131
|
+
readFile.mockResolvedValueOnce(JSON.stringify({ name: "test-monorepo", workspaces: [] }));
|
|
132
|
+
await expect(usePnpm("npm", version).then(() => true, () => false)).resolves.toBe(expected);
|
|
133
|
+
});
|
|
134
|
+
test("moves workspaces from package.json to pnpm-workspace.yaml", async () => {
|
|
135
|
+
const packageJson = {
|
|
136
|
+
name: "test-monorepo",
|
|
137
|
+
packageManager: "yarn@1.22.10",
|
|
138
|
+
version: "1.0.0",
|
|
139
|
+
workspaces: ["packages/*"],
|
|
140
|
+
};
|
|
141
|
+
readFile.mockResolvedValueOnce(JSON.stringify(packageJson, null, 2));
|
|
142
|
+
stdout.mockResolvedValue(`[]`); // npm list workspaces
|
|
143
|
+
await usePnpm("npm", "22.0.0");
|
|
144
|
+
expect(writeFile).toHaveBeenNthCalledWith(2, "pnpm-workspace.yaml", expect.stringContaining(YAML.stringify({
|
|
145
|
+
packages: packageJson.workspaces,
|
|
146
|
+
})), "utf-8");
|
|
147
|
+
});
|
|
148
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { getLogger } from "@logtape/logtape";
|
|
2
|
+
import { Octokit } from "octokit";
|
|
3
|
+
export const getLatestCommitSha = async (owner, repo, ref = "main") => {
|
|
4
|
+
const octokit = new Octokit();
|
|
5
|
+
const response = await octokit.rest.repos.getCommit({
|
|
6
|
+
owner,
|
|
7
|
+
ref,
|
|
8
|
+
repo,
|
|
9
|
+
});
|
|
10
|
+
return response.data.sha;
|
|
11
|
+
};
|
|
12
|
+
export const getLatestCommitShaOrRef = async (owner, repo, ref = "main") => {
|
|
13
|
+
const logger = getLogger(["dx-cli", "codemod"]);
|
|
14
|
+
return getLatestCommitSha(owner, repo, ref).catch(() => {
|
|
15
|
+
logger.warn("Failed to fetch the latest commit from {owner}/{repo}, fallback to {fallback}", { fallback: ref, owner, repo });
|
|
16
|
+
return ref;
|
|
17
|
+
});
|
|
18
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { LocalCodemodRegistry } from "./registry.js";
|
|
2
|
+
import { updateCodeReview } from "./update-code-review.js";
|
|
3
|
+
import { useAzureAppsvc } from "./use-azure-appsvc.js";
|
|
4
|
+
import usePnpm from "./use-pnpm.js";
|
|
5
|
+
const registry = new LocalCodemodRegistry();
|
|
6
|
+
registry.add(usePnpm);
|
|
7
|
+
registry.add(useAzureAppsvc);
|
|
8
|
+
registry.add(updateCodeReview);
|
|
9
|
+
export default registry;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Codemod, CodemodRegistry } from "../../domain/codemod.js";
|
|
2
|
+
export declare class LocalCodemodRegistry implements CodemodRegistry {
|
|
3
|
+
#private;
|
|
4
|
+
constructor();
|
|
5
|
+
add(codemod: Codemod): void;
|
|
6
|
+
getAll(): import("neverthrow").ResultAsync<Codemod[], never>;
|
|
7
|
+
getById(id: string): import("neverthrow").ResultAsync<Codemod | undefined, never>;
|
|
8
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { okAsync } from "neverthrow";
|
|
2
|
+
export class LocalCodemodRegistry {
|
|
3
|
+
#m;
|
|
4
|
+
constructor() {
|
|
5
|
+
this.#m = new Map();
|
|
6
|
+
}
|
|
7
|
+
add(codemod) {
|
|
8
|
+
this.#m.set(codemod.id, codemod);
|
|
9
|
+
}
|
|
10
|
+
getAll() {
|
|
11
|
+
return okAsync(Array.from(this.#m.values()));
|
|
12
|
+
}
|
|
13
|
+
getById(id) {
|
|
14
|
+
return okAsync(this.#m.get(id));
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { getLogger } from "@logtape/logtape";
|
|
2
|
+
import { replaceInFile } from "replace-in-file";
|
|
3
|
+
import * as YAML from "yaml";
|
|
4
|
+
import { getLatestCommitSha } from "./git.js";
|
|
5
|
+
import { isChildOf } from "./yaml.js";
|
|
6
|
+
export const updateJSCodeReviewJob = (sha) => (workflow, filename) => {
|
|
7
|
+
const logger = getLogger(["dx-cli", "codemod"]);
|
|
8
|
+
const document = YAML.parseDocument(workflow);
|
|
9
|
+
let updated = false;
|
|
10
|
+
YAML.visit(document, {
|
|
11
|
+
Map(_, map, path) {
|
|
12
|
+
if (map.has("jobs") || isChildOf(path, "jobs")) {
|
|
13
|
+
return undefined;
|
|
14
|
+
}
|
|
15
|
+
if (map.has("uses")) {
|
|
16
|
+
const uses = map.get("uses");
|
|
17
|
+
if (typeof uses === "string" &&
|
|
18
|
+
uses.startsWith("pagopa/dx/.github/workflows/js_code_review.yaml@")) {
|
|
19
|
+
map.set("secrets", "inherit");
|
|
20
|
+
map.set("permissions", {
|
|
21
|
+
contents: "read",
|
|
22
|
+
"pull-requests": "write",
|
|
23
|
+
});
|
|
24
|
+
map.set("uses", `pagopa/dx/.github/workflows/js_code_review.yaml@${sha}`);
|
|
25
|
+
updated = true;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return YAML.visit.SKIP;
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
if (updated) {
|
|
32
|
+
logger.info("Workflow {filename} updated", {
|
|
33
|
+
filename,
|
|
34
|
+
});
|
|
35
|
+
return YAML.stringify(document);
|
|
36
|
+
}
|
|
37
|
+
return workflow;
|
|
38
|
+
};
|
|
39
|
+
export const updateCodeReview = {
|
|
40
|
+
apply: async () => {
|
|
41
|
+
const logger = getLogger(["dx-cli", "codemod"]);
|
|
42
|
+
const owner = "pagopa";
|
|
43
|
+
const repo = "dx";
|
|
44
|
+
return getLatestCommitSha(owner, repo)
|
|
45
|
+
.then(async (sha) => {
|
|
46
|
+
await replaceInFile({
|
|
47
|
+
allowEmptyPaths: true,
|
|
48
|
+
files: [".github/workflows/*.yaml"],
|
|
49
|
+
processor: updateJSCodeReviewJob(sha),
|
|
50
|
+
});
|
|
51
|
+
})
|
|
52
|
+
.catch(() => {
|
|
53
|
+
logger.error("Failed to fetch the latest commit sha from {repository}", {
|
|
54
|
+
repository: `${owner}/${repo}`,
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
},
|
|
58
|
+
description: "Update js_code_review workflow to its latest version",
|
|
59
|
+
id: "update-code-review",
|
|
60
|
+
};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { getLogger } from "@logtape/logtape";
|
|
2
|
+
import { replaceInFile } from "replace-in-file";
|
|
3
|
+
import YAML from "yaml";
|
|
4
|
+
import { getLatestCommitShaOrRef } from "./git.js";
|
|
5
|
+
import { isChildOf } from "./yaml.js";
|
|
6
|
+
export const migrateWorkflow = (sha) => (workflow, filename) => {
|
|
7
|
+
const logger = getLogger(["dx-cli", "codemod"]);
|
|
8
|
+
logger.debug("Processing {filename} file", { filename });
|
|
9
|
+
const document = YAML.parseDocument(workflow);
|
|
10
|
+
let updated = false;
|
|
11
|
+
/**
|
|
12
|
+
* Visit the YAML AST to find and update specific keys
|
|
13
|
+
* - Visit the tree until we find job with "uses" containing "web_app_deploy" or "function_app_deploy"
|
|
14
|
+
* - Add "disable_auto_staging_deploy: true" under "with"
|
|
15
|
+
* - Rename "function_app_name" to "web_app_name"
|
|
16
|
+
* - Remove "use_staging_slot"
|
|
17
|
+
* - Update "uses" to point to "pagopa/dx/.github/workflows/release-azure-appsvc.yaml@LATEST_SHA"
|
|
18
|
+
*/
|
|
19
|
+
YAML.visit(document, {
|
|
20
|
+
Map(_, map, path) {
|
|
21
|
+
if (isChildOf(path, "jobs") || isChildOf(path, "with")) {
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
if (map.has("jobs")) {
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
if (map.has("uses")) {
|
|
28
|
+
const uses = map.get("uses");
|
|
29
|
+
if (typeof uses === "string" &&
|
|
30
|
+
uses.match(/^pagopa\/dx\/.github\/workflows\/(web|function)_app_deploy/)) {
|
|
31
|
+
logger.debug("Adding disable_auto_staging_deploy");
|
|
32
|
+
map.addIn(["with", "disable_auto_staging_deploy"], true);
|
|
33
|
+
map.set("permissions", {
|
|
34
|
+
attestations: "write",
|
|
35
|
+
contents: "read",
|
|
36
|
+
"id-token": "write",
|
|
37
|
+
});
|
|
38
|
+
updated = true;
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return YAML.visit.SKIP;
|
|
43
|
+
},
|
|
44
|
+
Pair(_, pair) {
|
|
45
|
+
if (YAML.isScalar(pair.key)) {
|
|
46
|
+
if (pair.key.value === "function_app_name") {
|
|
47
|
+
updated = true;
|
|
48
|
+
logger.debug("Updating function_app_name to web_app_name");
|
|
49
|
+
return new YAML.Pair("web_app_name", pair.value);
|
|
50
|
+
}
|
|
51
|
+
if (pair.key.value === "use_staging_slot") {
|
|
52
|
+
updated = true;
|
|
53
|
+
logger.debug("Removing use_staging_slot");
|
|
54
|
+
return YAML.visit.REMOVE;
|
|
55
|
+
}
|
|
56
|
+
if (pair.key.value === "uses") {
|
|
57
|
+
updated = true;
|
|
58
|
+
logger.debug("Updating uses value");
|
|
59
|
+
return new YAML.Pair("uses", `pagopa/dx/.github/workflows/release-azure-appsvc-v1.yaml@${sha}`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
if (updated) {
|
|
65
|
+
logger.info("Workflow {filename} updated", {
|
|
66
|
+
filename,
|
|
67
|
+
});
|
|
68
|
+
return YAML.stringify(document);
|
|
69
|
+
}
|
|
70
|
+
logger.debug("No changes applied to {filename}", { filename });
|
|
71
|
+
return workflow;
|
|
72
|
+
};
|
|
73
|
+
export const useAzureAppsvc = {
|
|
74
|
+
apply: async () => {
|
|
75
|
+
const sha = await getLatestCommitShaOrRef("pagopa", "dx");
|
|
76
|
+
await replaceInFile({
|
|
77
|
+
allowEmptyPaths: true,
|
|
78
|
+
files: [".github/workflows/*.yaml"],
|
|
79
|
+
processor: migrateWorkflow(sha),
|
|
80
|
+
});
|
|
81
|
+
},
|
|
82
|
+
description: "Refactor legacy deploy workflows to use release-azure-appsvc",
|
|
83
|
+
id: "use-azure-appsvc",
|
|
84
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
type NodePackageManager = {
|
|
2
|
+
listWorkspaces(): Promise<string[]>;
|
|
3
|
+
lockFileName: string;
|
|
4
|
+
};
|
|
5
|
+
export declare class NPM implements NodePackageManager {
|
|
6
|
+
lockFileName: string;
|
|
7
|
+
listWorkspaces(): Promise<string[]>;
|
|
8
|
+
}
|
|
9
|
+
export declare class Yarn implements NodePackageManager {
|
|
10
|
+
lockFileName: string;
|
|
11
|
+
listWorkspaces(): Promise<string[]>;
|
|
12
|
+
}
|
|
13
|
+
export declare function extractPackageExtensions(): Promise<object | undefined>;
|
|
14
|
+
export declare function preparePackageJsonForPnpm(): Promise<string[]>;
|
|
15
|
+
export declare function writePnpmWorkspaceFile(workspaces: string[], packageExtensions: object | undefined): Promise<void>;
|
|
16
|
+
export declare const usePnpm: (packageManager: string, currentNodeVersion: string) => Promise<void>;
|
|
17
|
+
declare const _default: {
|
|
18
|
+
apply: (info: import("../../domain/info.js").InfoResult) => Promise<void>;
|
|
19
|
+
description: string;
|
|
20
|
+
id: string;
|
|
21
|
+
};
|
|
22
|
+
export default _default;
|