@pagopa/dx-cli 0.6.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/index.js +392 -56
- package/package.json +5 -2
package/bin/index.js
CHANGED
|
@@ -2,22 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
4
|
import "core-js/actual/set/index.js";
|
|
5
|
-
import { configure, getConsoleSink, getLogger as
|
|
6
|
-
|
|
7
|
-
// src/adapters/codemods/example.ts
|
|
8
|
-
import { okAsync } from "neverthrow";
|
|
9
|
-
var apply = () => {
|
|
10
|
-
console.log("Hello from example codemod!");
|
|
11
|
-
return okAsync(void 0);
|
|
12
|
-
};
|
|
13
|
-
var example_default = {
|
|
14
|
-
apply,
|
|
15
|
-
description: "An example codemod that does nothing",
|
|
16
|
-
id: "example"
|
|
17
|
-
};
|
|
5
|
+
import { configure, getConsoleSink, getLogger as getLogger9 } from "@logtape/logtape";
|
|
18
6
|
|
|
19
7
|
// src/adapters/codemods/registry.ts
|
|
20
|
-
import { okAsync
|
|
8
|
+
import { okAsync } from "neverthrow";
|
|
21
9
|
var LocalCodemodRegistry = class {
|
|
22
10
|
#m;
|
|
23
11
|
constructor() {
|
|
@@ -27,22 +15,359 @@ var LocalCodemodRegistry = class {
|
|
|
27
15
|
this.#m.set(codemod.id, codemod);
|
|
28
16
|
}
|
|
29
17
|
getAll() {
|
|
30
|
-
return
|
|
18
|
+
return okAsync(Array.from(this.#m.values()));
|
|
31
19
|
}
|
|
32
20
|
getById(id) {
|
|
33
|
-
return
|
|
21
|
+
return okAsync(this.#m.get(id));
|
|
34
22
|
}
|
|
35
23
|
};
|
|
36
24
|
|
|
25
|
+
// src/adapters/codemods/update-code-review.ts
|
|
26
|
+
import { getLogger as getLogger2 } from "@logtape/logtape";
|
|
27
|
+
import { replaceInFile } from "replace-in-file";
|
|
28
|
+
|
|
29
|
+
// src/adapters/codemods/git.ts
|
|
30
|
+
import { getLogger } from "@logtape/logtape";
|
|
31
|
+
import { Octokit } from "octokit";
|
|
32
|
+
var getLatestCommitSha = async (owner, repo, ref = "main") => {
|
|
33
|
+
const octokit = new Octokit();
|
|
34
|
+
const response = await octokit.rest.repos.getCommit({
|
|
35
|
+
owner,
|
|
36
|
+
ref,
|
|
37
|
+
repo
|
|
38
|
+
});
|
|
39
|
+
return response.data.sha;
|
|
40
|
+
};
|
|
41
|
+
var getLatestCommitShaOrRef = async (owner, repo, ref = "main") => {
|
|
42
|
+
const logger2 = getLogger(["dx-cli", "codemod"]);
|
|
43
|
+
return getLatestCommitSha(owner, repo, ref).catch(() => {
|
|
44
|
+
logger2.warn(
|
|
45
|
+
"Failed to fetch the latest commit from {owner}/{repo}, fallback to {fallback}",
|
|
46
|
+
{ fallback: ref, owner, repo }
|
|
47
|
+
);
|
|
48
|
+
return ref;
|
|
49
|
+
});
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
// src/adapters/codemods/update-code-review.ts
|
|
53
|
+
var updateJSCodeReview = async (sha) => {
|
|
54
|
+
const logger2 = getLogger2(["dx-cli", "codemod"]);
|
|
55
|
+
const results = await replaceInFile({
|
|
56
|
+
allowEmptyPaths: true,
|
|
57
|
+
files: [".github/workflows/*.yaml"],
|
|
58
|
+
from: [/pagopa\/dx\/.github\/workflows\/js_code_review.yaml@(\S+)/g],
|
|
59
|
+
to: [`pagopa/dx/.github/workflows/js_code_review.yaml@${sha}`]
|
|
60
|
+
});
|
|
61
|
+
const updated = results.filter((r) => r.hasChanged).map((r) => r.file);
|
|
62
|
+
updated.forEach((filename) => {
|
|
63
|
+
logger2.info("Workflow {filename} updated", { filename });
|
|
64
|
+
});
|
|
65
|
+
return updated;
|
|
66
|
+
};
|
|
67
|
+
var updateCodeReview = {
|
|
68
|
+
apply: async () => {
|
|
69
|
+
const logger2 = getLogger2(["dx-cli", "codemod"]);
|
|
70
|
+
const owner = "pagopa";
|
|
71
|
+
const repo = "dx";
|
|
72
|
+
return getLatestCommitSha(owner, repo).then(async (sha) => {
|
|
73
|
+
await updateJSCodeReview(sha);
|
|
74
|
+
}).catch(() => {
|
|
75
|
+
logger2.error(
|
|
76
|
+
"Failed to fetch the latest commit sha from {owner}/{repo}",
|
|
77
|
+
{
|
|
78
|
+
owner,
|
|
79
|
+
repo
|
|
80
|
+
}
|
|
81
|
+
);
|
|
82
|
+
});
|
|
83
|
+
},
|
|
84
|
+
description: "Update js_code_review workflow to its latest version",
|
|
85
|
+
id: "update-code-review"
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
// src/adapters/codemods/use-azure-appsvc.ts
|
|
89
|
+
import { getLogger as getLogger3 } from "@logtape/logtape";
|
|
90
|
+
import { replaceInFile as replaceInFile2 } from "replace-in-file";
|
|
91
|
+
import YAML from "yaml";
|
|
92
|
+
var isChildOf = (path2, key) => {
|
|
93
|
+
const ancestor = path2.at(-1);
|
|
94
|
+
return YAML.isPair(ancestor) && YAML.isScalar(ancestor.key) && typeof ancestor.key.value === "string" && ancestor.key.value === key;
|
|
95
|
+
};
|
|
96
|
+
var migrateWorkflow = (sha) => (workflow, filename) => {
|
|
97
|
+
const logger2 = getLogger3(["dx-cli", "codemod"]);
|
|
98
|
+
logger2.debug("Processing {filename} file", { filename });
|
|
99
|
+
const document = YAML.parseDocument(workflow);
|
|
100
|
+
let updated = false;
|
|
101
|
+
YAML.visit(document, {
|
|
102
|
+
Map(_, map, path2) {
|
|
103
|
+
if (isChildOf(path2, "jobs") || isChildOf(path2, "with")) {
|
|
104
|
+
return void 0;
|
|
105
|
+
}
|
|
106
|
+
if (map.has("jobs")) {
|
|
107
|
+
return void 0;
|
|
108
|
+
}
|
|
109
|
+
if (map.has("uses")) {
|
|
110
|
+
const uses = map.get("uses");
|
|
111
|
+
if (typeof uses === "string" && uses.match(
|
|
112
|
+
/^pagopa\/dx\/.github\/workflows\/(web|function)_app_deploy/
|
|
113
|
+
)) {
|
|
114
|
+
logger2.debug("Adding disable_auto_staging_deploy");
|
|
115
|
+
map.addIn(["with", "disable_auto_staging_deploy"], true);
|
|
116
|
+
map.set("permissions", {
|
|
117
|
+
attestations: "write",
|
|
118
|
+
contents: "read",
|
|
119
|
+
"id-token": "write"
|
|
120
|
+
});
|
|
121
|
+
updated = true;
|
|
122
|
+
return void 0;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return YAML.visit.SKIP;
|
|
126
|
+
},
|
|
127
|
+
Pair(_, pair) {
|
|
128
|
+
if (YAML.isScalar(pair.key)) {
|
|
129
|
+
if (pair.key.value === "function_app_name") {
|
|
130
|
+
updated = true;
|
|
131
|
+
logger2.debug("Updating function_app_name to web_app_name");
|
|
132
|
+
return new YAML.Pair("web_app_name", pair.value);
|
|
133
|
+
}
|
|
134
|
+
if (pair.key.value === "use_staging_slot") {
|
|
135
|
+
updated = true;
|
|
136
|
+
logger2.debug("Removing use_staging_slot");
|
|
137
|
+
return YAML.visit.REMOVE;
|
|
138
|
+
}
|
|
139
|
+
if (pair.key.value === "uses") {
|
|
140
|
+
updated = true;
|
|
141
|
+
logger2.debug("Updating uses value");
|
|
142
|
+
return new YAML.Pair(
|
|
143
|
+
"uses",
|
|
144
|
+
`pagopa/dx/.github/workflows/release-azure-appsvc.yaml@${sha}`
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
if (updated) {
|
|
151
|
+
logger2.info("Workflow {filename} updated", {
|
|
152
|
+
filename
|
|
153
|
+
});
|
|
154
|
+
return YAML.stringify(document);
|
|
155
|
+
}
|
|
156
|
+
logger2.debug("No changes applied to {filename}", { filename });
|
|
157
|
+
return workflow;
|
|
158
|
+
};
|
|
159
|
+
var useAzureAppsvc = {
|
|
160
|
+
apply: async () => {
|
|
161
|
+
const sha = await getLatestCommitShaOrRef("pagopa", "dx");
|
|
162
|
+
await replaceInFile2({
|
|
163
|
+
allowEmptyPaths: true,
|
|
164
|
+
files: [".github/workflows/*.yaml"],
|
|
165
|
+
processor: migrateWorkflow(sha)
|
|
166
|
+
});
|
|
167
|
+
},
|
|
168
|
+
description: "Refactor legacy deploy workflows to use release-azure-appsvc",
|
|
169
|
+
id: "use-azure-appsvc"
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
// src/adapters/codemods/use-pnpm.ts
|
|
173
|
+
import { getLogger as getLogger4 } from "@logtape/logtape";
|
|
174
|
+
import { $ } from "execa";
|
|
175
|
+
import * as fs from "fs/promises";
|
|
176
|
+
import { replaceInFile as replaceInFile3 } from "replace-in-file";
|
|
177
|
+
import YAML2 from "yaml";
|
|
178
|
+
var NPM = class {
|
|
179
|
+
lockFileName = "package-lock.json";
|
|
180
|
+
async listWorkspaces() {
|
|
181
|
+
const { stdout } = await $`npm query .workspace`;
|
|
182
|
+
const workspaces = JSON.parse(stdout);
|
|
183
|
+
const workspaceNames = [];
|
|
184
|
+
if (Array.isArray(workspaces)) {
|
|
185
|
+
for (const ws of workspaces) {
|
|
186
|
+
if (Object.hasOwn(ws, "name")) {
|
|
187
|
+
workspaceNames.push(ws.name);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
return workspaceNames;
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
var Yarn = class {
|
|
195
|
+
lockFileName = "yarn.lock";
|
|
196
|
+
async listWorkspaces() {
|
|
197
|
+
const { stdout } = await $({ lines: true })`yarn workspaces list --json`;
|
|
198
|
+
const workspaceNames = [];
|
|
199
|
+
for (const line of stdout) {
|
|
200
|
+
const ws = JSON.parse(line);
|
|
201
|
+
if (Object.hasOwn(ws, "name")) {
|
|
202
|
+
workspaceNames.push(ws.name);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
return workspaceNames;
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
async function extractPackageExtensions() {
|
|
209
|
+
try {
|
|
210
|
+
const yarnrc = await fs.readFile(".yarnrc.yml", "utf-8");
|
|
211
|
+
const parsed = YAML2.parse(yarnrc);
|
|
212
|
+
if (parsed.packageExtensions) {
|
|
213
|
+
return parsed.packageExtensions;
|
|
214
|
+
}
|
|
215
|
+
} catch {
|
|
216
|
+
}
|
|
217
|
+
return void 0;
|
|
218
|
+
}
|
|
219
|
+
async function preparePackageJsonForPnpm() {
|
|
220
|
+
const packageJson2 = await fs.readFile("package.json", "utf-8");
|
|
221
|
+
const manifest = JSON.parse(packageJson2);
|
|
222
|
+
let workspaces = [];
|
|
223
|
+
if (Object.hasOwn(manifest, "packageManager")) {
|
|
224
|
+
delete manifest.packageManager;
|
|
225
|
+
}
|
|
226
|
+
if (Object.hasOwn(manifest, "workspaces")) {
|
|
227
|
+
if (Array.isArray(manifest.workspaces)) {
|
|
228
|
+
workspaces = manifest.workspaces;
|
|
229
|
+
}
|
|
230
|
+
delete manifest.workspaces;
|
|
231
|
+
}
|
|
232
|
+
await fs.writeFile("package.json", JSON.stringify(manifest, null, 2));
|
|
233
|
+
return workspaces;
|
|
234
|
+
}
|
|
235
|
+
async function removeFiles(...files) {
|
|
236
|
+
await Promise.all(
|
|
237
|
+
files.map(
|
|
238
|
+
(file) => (
|
|
239
|
+
// Remove the file if it exists, fail silently if it doesn't.
|
|
240
|
+
fs.rm(file, { force: true, recursive: true }).catch(() => void 0)
|
|
241
|
+
)
|
|
242
|
+
)
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
async function replacePMOccurrences() {
|
|
246
|
+
const logger2 = getLogger4(["dx-cli", "codemod"]);
|
|
247
|
+
logger2.info("Replacing yarn and npm occurrences in files...");
|
|
248
|
+
const results = await replaceInFile3({
|
|
249
|
+
allowEmptyPaths: true,
|
|
250
|
+
files: ["**/*.json", "**/*.md", "**/Dockerfile", "**/docker-compose.yml"],
|
|
251
|
+
from: [
|
|
252
|
+
"https://yarnpkg.com/",
|
|
253
|
+
"https://classic.yarnpkg.com/",
|
|
254
|
+
/\b(yarn workspace|npm -(\b-workspace\b|\bw\b)) (\S+)\b/g,
|
|
255
|
+
/\b(yarn workspace|npm -(\b-workspace\b|\bw\b)) /g,
|
|
256
|
+
/\b(yarn install --immutable|npm ci)\b/g,
|
|
257
|
+
/\b(yarn -q dlx|npx)\b/g,
|
|
258
|
+
/\b(Yarn|npm)\b/gi
|
|
259
|
+
],
|
|
260
|
+
ignore: ["**/node_modules/**", "**/dist/**", "**/build/**"],
|
|
261
|
+
to: [
|
|
262
|
+
"https://pnpm.io/",
|
|
263
|
+
"https://pnpm.io/",
|
|
264
|
+
"pnpm --filter $1",
|
|
265
|
+
"pnpm --filter <package-selector>",
|
|
266
|
+
"pnpm install --frozen-lockfile",
|
|
267
|
+
"pnpm dlx",
|
|
268
|
+
"pnpm"
|
|
269
|
+
]
|
|
270
|
+
});
|
|
271
|
+
const count = results.reduce(
|
|
272
|
+
(acc, file) => file.hasChanged ? acc + 1 : acc,
|
|
273
|
+
0
|
|
274
|
+
);
|
|
275
|
+
logger2.info("Replaced yarn occurrences in {count} files", { count });
|
|
276
|
+
}
|
|
277
|
+
async function updateDXWorkflows() {
|
|
278
|
+
const logger2 = getLogger4(["dx-cli", "codemod"]);
|
|
279
|
+
logger2.info("Updating Github Workflows workflows...");
|
|
280
|
+
const sha = await getLatestCommitShaOrRef("pagopa", "dx");
|
|
281
|
+
const ignore = await updateJSCodeReview(sha);
|
|
282
|
+
await replaceInFile3({
|
|
283
|
+
allowEmptyPaths: true,
|
|
284
|
+
files: [".github/workflows/*.yaml"],
|
|
285
|
+
ignore,
|
|
286
|
+
processor: migrateWorkflow(sha)
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
async function writePnpmWorkspaceFile(workspaces, packageExtensions) {
|
|
290
|
+
const pnpmWorkspace = {
|
|
291
|
+
packageExtensions,
|
|
292
|
+
packages: workspaces.length > 0 ? workspaces : ["apps/*", "packages/*"]
|
|
293
|
+
};
|
|
294
|
+
const yamlContent = YAML2.stringify(pnpmWorkspace);
|
|
295
|
+
await fs.writeFile("pnpm-workspace.yaml", yamlContent, "utf-8");
|
|
296
|
+
}
|
|
297
|
+
var apply = async (info) => {
|
|
298
|
+
if (info.packageManager === "pnpm") {
|
|
299
|
+
throw new Error("Project is already using pnpm");
|
|
300
|
+
}
|
|
301
|
+
const pm = info.packageManager === "yarn" ? new Yarn() : new NPM();
|
|
302
|
+
const logger2 = getLogger4(["dx-cli", "codemod"]);
|
|
303
|
+
const localWorkspaces = await pm.listWorkspaces();
|
|
304
|
+
logger2.info("Using the {protocol} protocol for local dependencies", {
|
|
305
|
+
protocol: "workspace:"
|
|
306
|
+
});
|
|
307
|
+
if (localWorkspaces.length > 0) {
|
|
308
|
+
await replaceInFile3({
|
|
309
|
+
allowEmptyPaths: true,
|
|
310
|
+
files: ["**/package.json"],
|
|
311
|
+
from: localWorkspaces.map((ws) => new RegExp(`"${ws}": ".*?"`, "g")),
|
|
312
|
+
to: localWorkspaces.map((ws) => `"${ws}": "workspace:^"`)
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
logger2.info("Remove unused fields from {file}", {
|
|
316
|
+
file: "package.json"
|
|
317
|
+
});
|
|
318
|
+
const workspaces = await preparePackageJsonForPnpm();
|
|
319
|
+
const packageExtensions = info.packageManager === "yarn" ? await extractPackageExtensions() : void 0;
|
|
320
|
+
logger2.info("Create {file}", {
|
|
321
|
+
file: "pnpm-workspace.yaml"
|
|
322
|
+
});
|
|
323
|
+
await writePnpmWorkspaceFile(workspaces, packageExtensions);
|
|
324
|
+
await $`corepack pnpm@latest add --config pnpm-plugin-pagopa`;
|
|
325
|
+
logger2.info("Remove node_modules and yarn files");
|
|
326
|
+
await removeFiles(
|
|
327
|
+
".yarnrc",
|
|
328
|
+
".yarnrc.yml",
|
|
329
|
+
"yarn.config.cjs",
|
|
330
|
+
".yarn",
|
|
331
|
+
".pnp.cjs",
|
|
332
|
+
".pnp.loader.cjs",
|
|
333
|
+
"node_modules"
|
|
334
|
+
);
|
|
335
|
+
const stat2 = await fs.stat(pm.lockFileName);
|
|
336
|
+
if (stat2.isFile()) {
|
|
337
|
+
logger2.info("Importing {source} to {target}", {
|
|
338
|
+
source: pm.lockFileName,
|
|
339
|
+
target: "pnpm-lock.yaml"
|
|
340
|
+
});
|
|
341
|
+
await $`corepack pnpm@latest import ${pm.lockFileName}`;
|
|
342
|
+
await removeFiles(pm.lockFileName);
|
|
343
|
+
} else {
|
|
344
|
+
logger2.info("No {source} file found, skipping import.", {
|
|
345
|
+
source: pm.lockFileName
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
await replacePMOccurrences();
|
|
349
|
+
await updateDXWorkflows();
|
|
350
|
+
logger2.info("Setting pnpm as the package manager...");
|
|
351
|
+
await $`corepack use pnpm@latest`;
|
|
352
|
+
};
|
|
353
|
+
var use_pnpm_default = {
|
|
354
|
+
apply,
|
|
355
|
+
description: "Migrate the project to use pnpm as the package manager",
|
|
356
|
+
id: "use-pnpm"
|
|
357
|
+
};
|
|
358
|
+
|
|
37
359
|
// src/adapters/codemods/index.ts
|
|
38
360
|
var registry = new LocalCodemodRegistry();
|
|
39
|
-
registry.add(
|
|
361
|
+
registry.add(use_pnpm_default);
|
|
362
|
+
registry.add(useAzureAppsvc);
|
|
363
|
+
registry.add(updateCodeReview);
|
|
40
364
|
var codemods_default = registry;
|
|
41
365
|
|
|
42
366
|
// src/adapters/commander/index.ts
|
|
43
367
|
import { Command as Command6 } from "commander";
|
|
44
368
|
|
|
45
369
|
// src/adapters/commander/commands/codemod.ts
|
|
370
|
+
import { getLogger as getLogger5 } from "@logtape/logtape";
|
|
46
371
|
import { Command } from "commander";
|
|
47
372
|
var makeCodemodCommand = ({
|
|
48
373
|
applyCodemodById: applyCodemodById2,
|
|
@@ -50,16 +375,14 @@ var makeCodemodCommand = ({
|
|
|
50
375
|
}) => new Command("codemod").description("Manage and apply migration scripts to the repository").addCommand(
|
|
51
376
|
new Command("list").description("List available migration scripts").action(async function() {
|
|
52
377
|
await listCodemods2().andTee(
|
|
53
|
-
(codemods) => (
|
|
54
|
-
// eslint-disable-next-line no-console
|
|
55
|
-
console.table(codemods, ["id", "description"])
|
|
56
|
-
)
|
|
378
|
+
(codemods) => console.table(codemods, ["id", "description"])
|
|
57
379
|
).orTee((error) => this.error(error.message));
|
|
58
380
|
})
|
|
59
381
|
).addCommand(
|
|
60
382
|
new Command("apply").argument("<id>", "The id of the codemod to apply").description("Apply migration scripts to the repository").action(async function(id) {
|
|
383
|
+
const logger2 = getLogger5(["dx-cli", "codemod"]);
|
|
61
384
|
await applyCodemodById2(id).andTee(() => {
|
|
62
|
-
|
|
385
|
+
logger2.info("Codemod applied \u2705");
|
|
63
386
|
}).orTee((error) => this.error(error.message));
|
|
64
387
|
})
|
|
65
388
|
);
|
|
@@ -140,7 +463,7 @@ var checkMonorepoScripts = async (dependencies, config2) => {
|
|
|
140
463
|
|
|
141
464
|
// src/domain/repository.ts
|
|
142
465
|
import { ok as ok2 } from "neverthrow";
|
|
143
|
-
import
|
|
466
|
+
import fs2 from "path";
|
|
144
467
|
import coerce from "semver/functions/coerce.js";
|
|
145
468
|
import semverGte from "semver/functions/gte.js";
|
|
146
469
|
var isVersionValid = (version, minVersion) => {
|
|
@@ -155,7 +478,7 @@ var checkPreCommitConfig = async (dependencies, config2) => {
|
|
|
155
478
|
const { repositoryReader: repositoryReader2 } = dependencies;
|
|
156
479
|
const checkName = "Pre-commit Configuration";
|
|
157
480
|
const preCommitResult = await repositoryReader2.fileExists(
|
|
158
|
-
|
|
481
|
+
fs2.join(config2.repository.root, ".pre-commit-config.yaml")
|
|
159
482
|
);
|
|
160
483
|
if (preCommitResult.isOk() && preCommitResult.value) {
|
|
161
484
|
return ok2({
|
|
@@ -176,7 +499,7 @@ var checkTurboConfig = async (dependencies, config2) => {
|
|
|
176
499
|
const checkName = "Turbo Configuration";
|
|
177
500
|
const repoRoot2 = config2.repository.root;
|
|
178
501
|
const turboResult = await repositoryReader2.fileExists(
|
|
179
|
-
|
|
502
|
+
fs2.join(repoRoot2, "turbo.json")
|
|
180
503
|
);
|
|
181
504
|
if (turboResult.isErr()) {
|
|
182
505
|
return ok2({
|
|
@@ -315,7 +638,7 @@ var makeDoctorCommand = (dependencies, config2) => new Command2().name("doctor")
|
|
|
315
638
|
import { Command as Command3 } from "commander";
|
|
316
639
|
|
|
317
640
|
// src/domain/info.ts
|
|
318
|
-
import { getLogger } from "@logtape/logtape";
|
|
641
|
+
import { getLogger as getLogger6 } from "@logtape/logtape";
|
|
319
642
|
import { join } from "path";
|
|
320
643
|
var detectFromLockFile = async (dependencies, config2) => {
|
|
321
644
|
const { repositoryReader: repositoryReader2 } = dependencies;
|
|
@@ -341,7 +664,7 @@ var detectPackageManager = async (dependencies, config2) => {
|
|
|
341
664
|
var detectNodeVersion = async ({ repositoryReader: repositoryReader2 }, nodeVersionFilePath) => await repositoryReader2.readFile(nodeVersionFilePath).map((nodeVersion) => nodeVersion.trim()).unwrapOr(void 0);
|
|
342
665
|
var detectTerraformVersion = async ({ repositoryReader: repositoryReader2 }, terraformVersionFilePath) => await repositoryReader2.readFile(terraformVersionFilePath).map((tfVersion) => tfVersion.trim()).unwrapOr(void 0);
|
|
343
666
|
var detectTurboVersion = ({ devDependencies }) => devDependencies.get("turbo")?.trim();
|
|
344
|
-
var getInfo =
|
|
667
|
+
var getInfo = (dependencies, config2) => async () => ({
|
|
345
668
|
node: await detectNodeVersion(
|
|
346
669
|
{ repositoryReader: dependencies.repositoryReader },
|
|
347
670
|
`${config2.repository.root}/.node-version`
|
|
@@ -354,13 +677,13 @@ var getInfo = async (dependencies, config2) => ({
|
|
|
354
677
|
turbo: detectTurboVersion(dependencies.packageJson)
|
|
355
678
|
});
|
|
356
679
|
var printInfo = (result) => {
|
|
357
|
-
const logger2 =
|
|
680
|
+
const logger2 = getLogger6("json");
|
|
358
681
|
logger2.info(JSON.stringify(result));
|
|
359
682
|
};
|
|
360
683
|
|
|
361
684
|
// src/adapters/commander/commands/info.ts
|
|
362
685
|
var makeInfoCommand = (dependencies, config2) => new Command3().name("info").description("Display information about the project").action(async () => {
|
|
363
|
-
const result = await getInfo(dependencies, config2);
|
|
686
|
+
const result = await getInfo(dependencies, config2)();
|
|
364
687
|
printInfo(result);
|
|
365
688
|
});
|
|
366
689
|
|
|
@@ -402,23 +725,21 @@ var makeInitCommand = () => new Command4().name("init").description(
|
|
|
402
725
|
import { Command as Command5 } from "commander";
|
|
403
726
|
|
|
404
727
|
// src/domain/version.ts
|
|
405
|
-
import { getLogger as
|
|
728
|
+
import { getLogger as getLogger7 } from "@logtape/logtape";
|
|
406
729
|
function printVersion() {
|
|
407
|
-
const logger2 =
|
|
408
|
-
logger2.info(`dx CLI version: ${"0.
|
|
730
|
+
const logger2 = getLogger7(["dx-cli", "version"]);
|
|
731
|
+
logger2.info(`dx CLI version: ${"0.8.0"}`);
|
|
409
732
|
}
|
|
410
733
|
|
|
411
734
|
// src/adapters/commander/commands/version.ts
|
|
412
735
|
var makeVersionCommand = () => new Command5().name("version").alias("v").action(() => printVersion());
|
|
413
736
|
|
|
414
737
|
// src/adapters/commander/index.ts
|
|
415
|
-
var makeCli = (deps2, config2) => {
|
|
738
|
+
var makeCli = (deps2, config2, cliDeps) => {
|
|
416
739
|
const program2 = new Command6();
|
|
417
|
-
program2.name("dx").description("The CLI for DX-Platform").version("0.
|
|
740
|
+
program2.name("dx").description("The CLI for DX-Platform").version("0.8.0");
|
|
418
741
|
program2.addCommand(makeDoctorCommand(deps2, config2));
|
|
419
|
-
|
|
420
|
-
program2.addCommand(makeCodemodCommand(deps2));
|
|
421
|
-
}
|
|
742
|
+
program2.addCommand(makeCodemodCommand(cliDeps));
|
|
422
743
|
if (process.env.ENABLE_INIT_COMMAND) {
|
|
423
744
|
program2.addCommand(makeInitCommand());
|
|
424
745
|
}
|
|
@@ -428,9 +749,9 @@ var makeCli = (deps2, config2) => {
|
|
|
428
749
|
};
|
|
429
750
|
|
|
430
751
|
// src/adapters/logtape/validation-reporter.ts
|
|
431
|
-
import { getLogger as
|
|
752
|
+
import { getLogger as getLogger8 } from "@logtape/logtape";
|
|
432
753
|
var makeValidationReporter = () => {
|
|
433
|
-
const logger2 =
|
|
754
|
+
const logger2 = getLogger8(["dx-cli", "validation"]);
|
|
434
755
|
return {
|
|
435
756
|
reportCheckResult(result) {
|
|
436
757
|
if (result.isValid) {
|
|
@@ -448,7 +769,7 @@ import * as process3 from "process";
|
|
|
448
769
|
|
|
449
770
|
// src/adapters/node/fs/file-reader.ts
|
|
450
771
|
import { ResultAsync as ResultAsync6 } from "neverthrow";
|
|
451
|
-
import
|
|
772
|
+
import fs3 from "fs/promises";
|
|
452
773
|
|
|
453
774
|
// src/adapters/zod/index.ts
|
|
454
775
|
import { ResultAsync as ResultAsync5 } from "neverthrow";
|
|
@@ -465,13 +786,13 @@ var parseJson = Result2.fromThrowable(
|
|
|
465
786
|
);
|
|
466
787
|
|
|
467
788
|
// src/adapters/node/fs/file-reader.ts
|
|
468
|
-
var
|
|
469
|
-
|
|
789
|
+
var readFile2 = (filePath) => ResultAsync6.fromPromise(
|
|
790
|
+
fs3.readFile(filePath, "utf-8"),
|
|
470
791
|
(cause) => new Error(`Failed to read file: ${filePath}`, { cause })
|
|
471
792
|
);
|
|
472
|
-
var readFileAndDecode = (filePath, schema) =>
|
|
793
|
+
var readFileAndDecode = (filePath, schema) => readFile2(filePath).andThen(parseJson).andThen(decode(schema));
|
|
473
794
|
var fileExists = (path2) => ResultAsync6.fromPromise(
|
|
474
|
-
|
|
795
|
+
fs3.stat(path2),
|
|
475
796
|
() => new Error(`${path2} not found.`)
|
|
476
797
|
).map(() => true);
|
|
477
798
|
|
|
@@ -501,7 +822,7 @@ var makePackageJsonReader = () => ({
|
|
|
501
822
|
|
|
502
823
|
// src/adapters/node/repository.ts
|
|
503
824
|
import * as glob from "glob";
|
|
504
|
-
import { okAsync as
|
|
825
|
+
import { okAsync as okAsync2, ResultAsync as ResultAsync7 } from "neverthrow";
|
|
505
826
|
import * as path from "path";
|
|
506
827
|
import { z as z3 } from "zod/v4";
|
|
507
828
|
|
|
@@ -535,11 +856,11 @@ var resolveWorkspacePattern = (repoRoot2, pattern) => ResultAsync7.fromPromise(
|
|
|
535
856
|
subDirectories.map((directory) => path.join(repoRoot2, directory))
|
|
536
857
|
)
|
|
537
858
|
);
|
|
538
|
-
var getWorkspaces = (repoRoot2) =>
|
|
859
|
+
var getWorkspaces = (repoRoot2) => readFile2(path.join(repoRoot2, "pnpm-workspace.yaml")).andThen(parseYaml).andThen(
|
|
539
860
|
(obj) => (
|
|
540
861
|
// If no packages are defined, go on with an empty array
|
|
541
862
|
decode(z3.object({ packages: z3.array(z3.string()) }))(obj).orElse(
|
|
542
|
-
() =>
|
|
863
|
+
() => okAsync2({ packages: [] })
|
|
543
864
|
)
|
|
544
865
|
)
|
|
545
866
|
).andThen(
|
|
@@ -567,7 +888,7 @@ var makeRepositoryReader = () => ({
|
|
|
567
888
|
fileExists,
|
|
568
889
|
findRepositoryRoot,
|
|
569
890
|
getWorkspaces,
|
|
570
|
-
readFile
|
|
891
|
+
readFile: readFile2
|
|
571
892
|
});
|
|
572
893
|
|
|
573
894
|
// src/config.ts
|
|
@@ -581,10 +902,23 @@ var getConfig = (repositoryRoot2) => ({
|
|
|
581
902
|
});
|
|
582
903
|
|
|
583
904
|
// src/use-cases/apply-codemod.ts
|
|
584
|
-
import { errAsync, okAsync as
|
|
585
|
-
var
|
|
586
|
-
(codemod) => codemod ?
|
|
587
|
-
)
|
|
905
|
+
import { errAsync, okAsync as okAsync3, ResultAsync as ResultAsync8 } from "neverthrow";
|
|
906
|
+
var getCodemodById = (registry2, id) => registry2.getById(id).andThen(
|
|
907
|
+
(codemod) => codemod ? okAsync3(codemod) : errAsync(new Error(`Codemod with id ${id} not found`))
|
|
908
|
+
);
|
|
909
|
+
var safeGetInfo = (getInfo2) => ResultAsync8.fromPromise(
|
|
910
|
+
getInfo2(),
|
|
911
|
+
(error) => new Error("Failed to get info", { cause: error })
|
|
912
|
+
);
|
|
913
|
+
var applyCodemodById = (registry2, getInfo2) => (id) => ResultAsync8.combine([
|
|
914
|
+
safeGetInfo(getInfo2),
|
|
915
|
+
getCodemodById(registry2, id)
|
|
916
|
+
]).andThen(
|
|
917
|
+
([info, codemod]) => ResultAsync8.fromPromise(codemod.apply(info), (error) => {
|
|
918
|
+
const message = error instanceof Error ? `: ${error.message}` : "";
|
|
919
|
+
return new Error("Failed to apply codemod" + message, { cause: error });
|
|
920
|
+
})
|
|
921
|
+
);
|
|
588
922
|
|
|
589
923
|
// src/use-cases/list-codemods.ts
|
|
590
924
|
var listCodemods = (registry2) => () => registry2.getAll();
|
|
@@ -607,7 +941,7 @@ await configure({
|
|
|
607
941
|
}
|
|
608
942
|
}
|
|
609
943
|
});
|
|
610
|
-
var logger =
|
|
944
|
+
var logger = getLogger9(["dx-cli"]);
|
|
611
945
|
var repositoryReader = makeRepositoryReader();
|
|
612
946
|
var packageJsonReader = makePackageJsonReader();
|
|
613
947
|
var validationReporter = makeValidationReporter();
|
|
@@ -626,13 +960,15 @@ if (repoPackageJson.isErr()) {
|
|
|
626
960
|
}
|
|
627
961
|
var packageJson = repoPackageJson.value;
|
|
628
962
|
var deps = {
|
|
629
|
-
applyCodemodById: applyCodemodById(codemods_default),
|
|
630
|
-
listCodemods: listCodemods(codemods_default),
|
|
631
963
|
packageJson,
|
|
632
964
|
packageJsonReader,
|
|
633
965
|
repositoryReader,
|
|
634
966
|
validationReporter
|
|
635
967
|
};
|
|
636
968
|
var config = getConfig(repositoryRoot);
|
|
637
|
-
var
|
|
969
|
+
var useCases = {
|
|
970
|
+
applyCodemodById: applyCodemodById(codemods_default, getInfo(deps, config)),
|
|
971
|
+
listCodemods: listCodemods(codemods_default)
|
|
972
|
+
};
|
|
973
|
+
var program = makeCli(deps, config, useCases);
|
|
638
974
|
program.parse();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pagopa/dx-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "A CLI useful to manage DX tools.",
|
|
6
6
|
"repository": {
|
|
@@ -22,13 +22,16 @@
|
|
|
22
22
|
"@logtape/logtape": "^1.0.0",
|
|
23
23
|
"commander": "^14.0.0",
|
|
24
24
|
"core-js": "^3.44.0",
|
|
25
|
+
"execa": "^9.6.0",
|
|
25
26
|
"glob": "^11.0.3",
|
|
26
27
|
"neverthrow": "^8.2.0",
|
|
27
28
|
"node-plop": "^0.32.1",
|
|
29
|
+
"octokit": "^5.0.3",
|
|
30
|
+
"replace-in-file": "^8.3.0",
|
|
28
31
|
"semver": "^7.7.2",
|
|
29
32
|
"yaml": "^2.8.0",
|
|
30
33
|
"zod": "^3.25.28",
|
|
31
|
-
"@pagopa/monorepo-generator": "^0.
|
|
34
|
+
"@pagopa/monorepo-generator": "^0.8.0"
|
|
32
35
|
},
|
|
33
36
|
"devDependencies": {
|
|
34
37
|
"@tsconfig/node22": "22.0.2",
|