|
| 1 | +import z from "zod"; |
1 | 2 | import fs from "fs";
|
2 | 3 | import path from "path";
|
3 | 4 | import fetch from "node-fetch";
|
4 | 5 | import inquirer from "inquirer";
|
| 6 | +import { spawnSync } from "child_process"; |
5 | 7 | import { installDependencies } from "../utils/installDependencies.js";
|
| 8 | +import { getUserPackageManager } from "../utils/getUserPkgManager.js"; |
| 9 | + |
| 10 | +interface YarnListOutput { |
| 11 | + data: { |
| 12 | + trees: Array<{ name: string; version: string }>; |
| 13 | + }; |
| 14 | +} |
| 15 | + |
| 16 | +function getInstalledVersion(packageName: string, packageManager: string, projectPath: string) { |
| 17 | + let installedVersion = null; |
| 18 | + if (packageManager === "npm" || packageManager === "pnpm") { |
| 19 | + const { stdout } = spawnSync(packageManager, ["list", packageName, "--json", "--depth=0"], { |
| 20 | + cwd: projectPath, |
| 21 | + }); |
| 22 | + installedVersion = JSON.parse(stdout.toString()).dependencies[packageName].version; |
| 23 | + } else if (packageManager === "yarn") { |
| 24 | + const { stdout } = spawnSync(packageManager, ["list", "--json", "--depth=0"], { |
| 25 | + cwd: projectPath, |
| 26 | + }); |
| 27 | + const parsedOutput: YarnListOutput = JSON.parse(stdout.toString()); |
| 28 | + if (Array.isArray(parsedOutput.data.trees)) { |
| 29 | + const tree = parsedOutput.data.trees.find((tree) => tree.name === packageName); |
| 30 | + if (tree) { |
| 31 | + installedVersion = tree.version; |
| 32 | + } |
| 33 | + } |
| 34 | + } |
| 35 | + return installedVersion; |
| 36 | +} |
6 | 37 |
|
7 | 38 | export async function updateCommand(projectPath: string) {
|
| 39 | + const triggerDevPackage = "@trigger.dev"; |
| 40 | + const packageManager = await getUserPackageManager(projectPath); |
8 | 41 | const packageJsonPath = path.join(projectPath, "package.json");
|
9 |
| - |
| 42 | + // In case no package.json found |
10 | 43 | if (!fs.existsSync(packageJsonPath)) {
|
11 |
| - console.error("package.json not found in the current directory."); |
| 44 | + console.error(`package.json not found in the ${projectPath} directory.`); |
12 | 45 | return;
|
13 | 46 | }
|
14 |
| - |
15 | 47 | const packageJsonData = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
|
16 | 48 | const dependencies = packageJsonData.dependencies || {};
|
17 | 49 | const devDependencies = packageJsonData.devDependencies || {};
|
18 |
| - |
19 |
| - const triggerPackages = Object.keys({ ...dependencies, ...devDependencies }).filter( |
20 |
| - (packageName) => packageName.startsWith("@trigger.dev/") |
21 |
| - ); |
22 |
| - |
| 50 | + const allDependencies = Object.keys({ ...dependencies, ...devDependencies }); |
| 51 | + const triggerPackages = allDependencies.filter((pkg) => pkg.startsWith(triggerDevPackage)); |
| 52 | + // If there are no @trigger.dev packages |
23 | 53 | if (triggerPackages.length === 0) {
|
24 | 54 | console.log("No @trigger.dev/* packages found in package.json.");
|
25 | 55 | return;
|
26 | 56 | }
|
27 |
| - |
| 57 | + // Get an array of the latest versions of @trigger.dev packages |
28 | 58 | const newVersions = await Promise.all(
|
29 | 59 | triggerPackages.map(async (packageName) => {
|
30 | 60 | try {
|
| 61 | + const installedVersion = getInstalledVersion(packageName, packageManager, projectPath); |
31 | 62 | const response = await fetch(`https://registry.npmjs.org/${packageName}`);
|
32 |
| - const data = await response.json(); |
33 |
| - const latestVersion = data["dist-tags"].latest; |
34 |
| - return { packageName, latestVersion }; |
| 63 | + if (response.ok) { |
| 64 | + const data = await response.json(); |
| 65 | + const schema = z.object({ |
| 66 | + "dist-tags": z.object({ |
| 67 | + latest: z.string(), |
| 68 | + }), |
| 69 | + }); |
| 70 | + const parsed = schema.parse(data); |
| 71 | + return { packageName, installedVersion, latestVersion: parsed["dist-tags"].latest }; |
| 72 | + } |
| 73 | + return null; |
35 | 74 | } catch (error) {
|
36 | 75 | // @ts-ignore
|
37 | 76 | console.error(`Error fetching version for ${packageName}: ${error.message}`);
|
38 | 77 | return null;
|
39 | 78 | }
|
40 | 79 | })
|
41 | 80 | );
|
| 81 | + // Filter the packages with null and what don't match what |
| 82 | + // they are installed with so that they can be updated |
42 | 83 | const packagesToUpdate = newVersions.filter(
|
43 |
| - (entry) => entry !== null && entry.latestVersion !== dependencies[entry.packageName] |
| 84 | + (pkg) => pkg && pkg.latestVersion !== pkg.installedVersion |
44 | 85 | );
|
45 |
| - |
| 86 | + // If no packages require any updation |
46 | 87 | if (packagesToUpdate.length === 0) {
|
47 | 88 | console.log("All @trigger.dev/* packages are up to date.");
|
48 | 89 | return;
|
49 | 90 | }
|
50 |
| - |
| 91 | + // Inform the user of the dependencies that can be updated |
51 | 92 | console.log("Newer versions found for the following packages:");
|
52 | 93 | packagesToUpdate.forEach((entry) => {
|
53 |
| - console.log( |
54 |
| - `- ${entry.packageName}: current ${dependencies[entry.packageName]} -> latest ${ |
55 |
| - entry.latestVersion |
56 |
| - }` |
57 |
| - ); |
| 94 | + if (entry) { |
| 95 | + console.log( |
| 96 | + `- ${entry.packageName}: current ${dependencies[entry.packageName]} -> latest ${ |
| 97 | + entry.latestVersion |
| 98 | + }` |
| 99 | + ); |
| 100 | + } |
58 | 101 | });
|
59 |
| - |
| 102 | + // Ask the user if they want to update the dependencies |
60 | 103 | const { confirm } = await inquirer.prompt({
|
61 | 104 | type: "confirm",
|
62 | 105 | name: "confirm",
|
63 | 106 | message: "Do you want to update these packages in package.json and re-install dependencies?",
|
64 | 107 | });
|
65 |
| - |
66 | 108 | if (confirm) {
|
67 | 109 | packagesToUpdate.forEach((entry) => {
|
68 |
| - dependencies[entry.packageName] = entry.latestVersion; |
| 110 | + if (entry) { |
| 111 | + dependencies[entry.packageName] = entry.latestVersion; |
| 112 | + } |
69 | 113 | });
|
70 |
| - |
71 | 114 | fs.writeFileSync(packageJsonPath, JSON.stringify(packageJsonData, null, 2));
|
72 |
| - |
73 | 115 | console.log("package.json updated. Reinstalling dependencies...");
|
74 | 116 | await installDependencies(projectPath);
|
75 | 117 | } else {
|
|
0 commit comments