@zapier/zapier-sdk-cli 0.13.16 → 0.14.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/CHANGELOG.md +12 -0
- package/dist/cli.cjs +296 -20
- package/dist/cli.mjs +296 -22
- package/dist/index.cjs +29 -5
- package/dist/index.mjs +30 -6
- package/dist/package.json +4 -1
- package/dist/src/cli.js +32 -2
- package/dist/src/plugins/login/index.js +0 -2
- package/dist/src/utils/auth/login.js +3 -2
- package/dist/src/utils/cli-generator.js +10 -2
- package/dist/src/utils/errors.d.ts +16 -0
- package/dist/src/utils/errors.js +19 -0
- package/dist/src/utils/log.d.ts +1 -0
- package/dist/src/utils/log.js +5 -0
- package/dist/src/utils/package-manager-detector.d.ts +16 -0
- package/dist/src/utils/package-manager-detector.js +77 -0
- package/dist/src/utils/parameter-resolver.js +6 -5
- package/dist/src/utils/spinner.js +9 -1
- package/dist/src/utils/version-checker.d.ts +17 -0
- package/dist/src/utils/version-checker.js +154 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -1
- package/src/cli.ts +34 -2
- package/src/plugins/login/index.ts +0 -3
- package/src/utils/auth/login.ts +7 -3
- package/src/utils/cli-generator.ts +15 -2
- package/src/utils/errors.ts +26 -0
- package/src/utils/log.ts +5 -0
- package/src/utils/package-manager-detector.ts +83 -0
- package/src/utils/parameter-resolver.ts +6 -5
- package/src/utils/spinner.ts +8 -1
- package/src/utils/version-checker.test.ts +199 -0
- package/src/utils/version-checker.ts +236 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zapier/zapier-sdk-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.1",
|
|
4
4
|
"description": "Command line interface for Zapier SDK",
|
|
5
5
|
"main": "dist/index.cjs",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -34,12 +34,15 @@
|
|
|
34
34
|
"chalk": "^5.3.0",
|
|
35
35
|
"cli-table3": "^0.6.5",
|
|
36
36
|
"commander": "^12.0.0",
|
|
37
|
+
"conf": "^14.0.0",
|
|
37
38
|
"esbuild": "^0.25.5",
|
|
38
39
|
"express": "^5.1.0",
|
|
39
40
|
"inquirer": "^12.6.3",
|
|
41
|
+
"is-installed-globally": "^1.0.0",
|
|
40
42
|
"jsonwebtoken": "^9.0.2",
|
|
41
43
|
"open": "^10.2.0",
|
|
42
44
|
"ora": "^8.2.0",
|
|
45
|
+
"package-json": "^10.0.1",
|
|
43
46
|
"pkce-challenge": "^5.0.0",
|
|
44
47
|
"typescript": "^5.8.3",
|
|
45
48
|
"zod": "^3.25.67",
|
package/src/cli.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import { Command } from "commander";
|
|
3
|
+
import { Command, CommanderError } from "commander";
|
|
4
4
|
import { generateCliCommands } from "./utils/cli-generator";
|
|
5
5
|
import { createZapierCliSdk } from "./sdk";
|
|
6
6
|
import packageJson from "../package.json" with { type: "json" };
|
|
7
|
+
import { ZapierCliError } from "./utils/errors";
|
|
8
|
+
import { checkAndNotifyUpdates } from "./utils/version-checker";
|
|
7
9
|
|
|
8
10
|
const program = new Command();
|
|
9
11
|
|
|
@@ -61,4 +63,34 @@ generateCliCommands(program, sdk);
|
|
|
61
63
|
|
|
62
64
|
// MCP command now handled by plugin
|
|
63
65
|
|
|
64
|
-
|
|
66
|
+
// Override Commander's default exit behavior to handle our custom errors
|
|
67
|
+
program.exitOverride();
|
|
68
|
+
|
|
69
|
+
(async () => {
|
|
70
|
+
let exitCode = 0;
|
|
71
|
+
|
|
72
|
+
// Start version checking non-blocking
|
|
73
|
+
const versionCheckPromise = checkAndNotifyUpdates({
|
|
74
|
+
packageName: packageJson.name,
|
|
75
|
+
currentVersion: packageJson.version,
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
try {
|
|
79
|
+
await program.parseAsync();
|
|
80
|
+
} catch (error) {
|
|
81
|
+
if (error instanceof ZapierCliError) {
|
|
82
|
+
exitCode = error.exitCode;
|
|
83
|
+
} else if (error instanceof CommanderError) {
|
|
84
|
+
exitCode = error.exitCode;
|
|
85
|
+
} else {
|
|
86
|
+
// For any other unexpected errors, exit with code 1
|
|
87
|
+
console.error("Unexpected error:", error);
|
|
88
|
+
exitCode = 1;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Wait for version checking to complete
|
|
93
|
+
await versionCheckPromise;
|
|
94
|
+
|
|
95
|
+
process.exit(exitCode);
|
|
96
|
+
})();
|
|
@@ -54,9 +54,6 @@ const loginWithSdk = createFunction(
|
|
|
54
54
|
const user = await getLoggedInUser();
|
|
55
55
|
|
|
56
56
|
console.log(`✅ Successfully logged in as ${user.email}`);
|
|
57
|
-
|
|
58
|
-
// Force immediate exit to prevent hanging (especially in development with tsx)
|
|
59
|
-
setTimeout(() => process.exit(0), 100);
|
|
60
57
|
},
|
|
61
58
|
);
|
|
62
59
|
|
package/src/utils/auth/login.ts
CHANGED
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
getAuthTokenUrl,
|
|
21
21
|
getAuthAuthorizeUrl,
|
|
22
22
|
} from "@zapier/zapier-sdk-cli-login";
|
|
23
|
+
import { ZapierCliUserCancellationError } from "../errors";
|
|
23
24
|
|
|
24
25
|
const findAvailablePort = (): Promise<number> => {
|
|
25
26
|
return new Promise((resolve, reject) => {
|
|
@@ -91,8 +92,11 @@ const login = async ({
|
|
|
91
92
|
|
|
92
93
|
log.info(`Using port ${availablePort} for OAuth callback`);
|
|
93
94
|
|
|
94
|
-
const {
|
|
95
|
-
|
|
95
|
+
const {
|
|
96
|
+
promise: promisedCode,
|
|
97
|
+
resolve: setCode,
|
|
98
|
+
reject: rejectCode,
|
|
99
|
+
} = getCallablePromise<string>();
|
|
96
100
|
|
|
97
101
|
const app = express();
|
|
98
102
|
|
|
@@ -116,7 +120,7 @@ const login = async ({
|
|
|
116
120
|
const cleanup = () => {
|
|
117
121
|
server.close();
|
|
118
122
|
log.info("\n❌ Login cancelled by user");
|
|
119
|
-
|
|
123
|
+
rejectCode(new ZapierCliUserCancellationError());
|
|
120
124
|
};
|
|
121
125
|
|
|
122
126
|
process.on("SIGINT", cleanup);
|
|
@@ -11,6 +11,7 @@ import { SchemaParameterResolver } from "./parameter-resolver";
|
|
|
11
11
|
import { formatItemsFromSchema, formatJsonOutput } from "./schema-formatter";
|
|
12
12
|
import chalk from "chalk";
|
|
13
13
|
import inquirer from "inquirer";
|
|
14
|
+
import { ZapierCliError, ZapierCliExitError } from "./errors";
|
|
14
15
|
|
|
15
16
|
// ============================================================================
|
|
16
17
|
// Types
|
|
@@ -387,20 +388,32 @@ function createCommandConfig(
|
|
|
387
388
|
console.error(
|
|
388
389
|
"\n" + chalk.dim(`Use --help to see available options`),
|
|
389
390
|
);
|
|
391
|
+
throw new ZapierCliExitError("Validation failed", 1);
|
|
390
392
|
} catch {
|
|
391
|
-
console.error(
|
|
393
|
+
console.error(
|
|
394
|
+
chalk.red("Error:"),
|
|
395
|
+
error instanceof Error ? error.message : String(error),
|
|
396
|
+
);
|
|
397
|
+
throw new ZapierCliExitError(
|
|
398
|
+
error instanceof Error ? error.message : String(error),
|
|
399
|
+
1,
|
|
400
|
+
);
|
|
392
401
|
}
|
|
402
|
+
} else if (error instanceof ZapierCliError) {
|
|
403
|
+
// Re-throw all CLI errors as-is
|
|
404
|
+
throw error;
|
|
393
405
|
} else if (error instanceof ZapierError) {
|
|
394
406
|
// Handle SDK errors with clean, user-friendly messages using our formatter
|
|
395
407
|
const formattedMessage = formatErrorMessage(error);
|
|
396
408
|
console.error(chalk.red("❌ Error:"), formattedMessage);
|
|
409
|
+
throw new ZapierCliExitError(formattedMessage, 1);
|
|
397
410
|
} else {
|
|
398
411
|
// Handle other errors
|
|
399
412
|
const errorMessage =
|
|
400
413
|
error instanceof Error ? error.message : "Unknown error";
|
|
401
414
|
console.error(chalk.red("❌ Error:"), errorMessage);
|
|
415
|
+
throw new ZapierCliExitError(errorMessage, 1);
|
|
402
416
|
}
|
|
403
|
-
process.exit(1);
|
|
404
417
|
}
|
|
405
418
|
};
|
|
406
419
|
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { ZapierError } from "@zapier/zapier-sdk";
|
|
2
|
+
|
|
3
|
+
export abstract class ZapierCliError extends ZapierError {
|
|
4
|
+
public abstract readonly exitCode: number;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export class ZapierCliUserCancellationError extends ZapierCliError {
|
|
8
|
+
public readonly name = "ZapierCliUserCancellationError";
|
|
9
|
+
public readonly code = "ZAPIER_CLI_USER_CANCELLATION";
|
|
10
|
+
public readonly exitCode = 0;
|
|
11
|
+
|
|
12
|
+
constructor(message: string = "Operation cancelled by user") {
|
|
13
|
+
super(message);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export class ZapierCliExitError extends ZapierCliError {
|
|
18
|
+
public readonly name = "ZapierCliExitError";
|
|
19
|
+
public readonly code = "ZAPIER_CLI_EXIT";
|
|
20
|
+
public readonly exitCode: number;
|
|
21
|
+
|
|
22
|
+
constructor(message: string, exitCode: number = 1) {
|
|
23
|
+
super(message);
|
|
24
|
+
this.exitCode = exitCode;
|
|
25
|
+
}
|
|
26
|
+
}
|
package/src/utils/log.ts
CHANGED
|
@@ -13,6 +13,11 @@ const log = {
|
|
|
13
13
|
warn: (message: string, ...args: unknown[]) => {
|
|
14
14
|
console.log(chalk.yellow("⚠"), message, ...args);
|
|
15
15
|
},
|
|
16
|
+
debug: (message: string, ...args: unknown[]) => {
|
|
17
|
+
if (process.env.DEBUG === "true" || process.argv.includes("--debug")) {
|
|
18
|
+
console.log(chalk.gray("🐛"), message, ...args);
|
|
19
|
+
}
|
|
20
|
+
},
|
|
16
21
|
};
|
|
17
22
|
|
|
18
23
|
export default log;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { existsSync } from "fs";
|
|
2
|
+
import { join } from "path";
|
|
3
|
+
import isInstalledGlobally from "is-installed-globally";
|
|
4
|
+
|
|
5
|
+
export interface PackageManagerInfo {
|
|
6
|
+
name: "npm" | "yarn" | "pnpm" | "bun" | "unknown";
|
|
7
|
+
source: "runtime" | "lockfile" | "fallback";
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Detect which package manager is being used or configured for this project.
|
|
12
|
+
*
|
|
13
|
+
* Returns an object like:
|
|
14
|
+
* { name: 'npm' | 'yarn' | 'pnpm' | 'bun' | 'unknown', source: 'runtime' | 'lockfile' | 'fallback' }
|
|
15
|
+
*/
|
|
16
|
+
export function detectPackageManager(cwd = process.cwd()): PackageManagerInfo {
|
|
17
|
+
// --- 1. Runtime detection (based on env)
|
|
18
|
+
const ua = process.env.npm_config_user_agent;
|
|
19
|
+
if (ua) {
|
|
20
|
+
if (ua.includes("yarn")) return { name: "yarn", source: "runtime" };
|
|
21
|
+
if (ua.includes("pnpm")) return { name: "pnpm", source: "runtime" };
|
|
22
|
+
if (ua.includes("bun")) return { name: "bun", source: "runtime" };
|
|
23
|
+
if (ua.includes("npm")) return { name: "npm", source: "runtime" };
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// --- 2. Lockfile detection (based on files in cwd)
|
|
27
|
+
const files: Array<[string, PackageManagerInfo["name"]]> = [
|
|
28
|
+
["pnpm-lock.yaml", "pnpm"],
|
|
29
|
+
["yarn.lock", "yarn"],
|
|
30
|
+
["bun.lockb", "bun"],
|
|
31
|
+
["package-lock.json", "npm"],
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
for (const [file, name] of files) {
|
|
35
|
+
if (existsSync(join(cwd, file))) {
|
|
36
|
+
return { name, source: "lockfile" };
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// --- 3. Fallback
|
|
41
|
+
return { name: "unknown", source: "fallback" };
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Get the appropriate update command for the detected package manager.
|
|
46
|
+
* Returns global update commands if globally installed, local commands if locally installed.
|
|
47
|
+
*/
|
|
48
|
+
export function getUpdateCommand(packageName: string): string {
|
|
49
|
+
const pm = detectPackageManager();
|
|
50
|
+
const isGlobal = isInstalledGlobally;
|
|
51
|
+
|
|
52
|
+
if (isGlobal) {
|
|
53
|
+
// Global update commands
|
|
54
|
+
switch (pm.name) {
|
|
55
|
+
case "yarn":
|
|
56
|
+
return `yarn global upgrade ${packageName}@latest`;
|
|
57
|
+
case "pnpm":
|
|
58
|
+
return `pnpm update -g ${packageName}@latest`;
|
|
59
|
+
case "bun":
|
|
60
|
+
return `bun update -g ${packageName}@latest`;
|
|
61
|
+
case "npm":
|
|
62
|
+
return `npm update -g ${packageName}@latest`;
|
|
63
|
+
case "unknown":
|
|
64
|
+
// Default to npm since it's most widely supported
|
|
65
|
+
return `npm update -g ${packageName}@latest`;
|
|
66
|
+
}
|
|
67
|
+
} else {
|
|
68
|
+
// Local update commands
|
|
69
|
+
switch (pm.name) {
|
|
70
|
+
case "yarn":
|
|
71
|
+
return `yarn upgrade ${packageName}@latest`;
|
|
72
|
+
case "pnpm":
|
|
73
|
+
return `pnpm update ${packageName}@latest`;
|
|
74
|
+
case "bun":
|
|
75
|
+
return `bun update ${packageName}@latest`;
|
|
76
|
+
case "npm":
|
|
77
|
+
return `npm update ${packageName}@latest`;
|
|
78
|
+
case "unknown":
|
|
79
|
+
// Default to npm since it's most widely supported
|
|
80
|
+
return `npm update ${packageName}@latest`;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -2,6 +2,7 @@ import inquirer from "inquirer";
|
|
|
2
2
|
import chalk from "chalk";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
import type { ZapierSdk } from "@zapier/zapier-sdk";
|
|
5
|
+
import { ZapierCliUserCancellationError } from "./errors";
|
|
5
6
|
|
|
6
7
|
// ============================================================================
|
|
7
8
|
// Types
|
|
@@ -209,7 +210,7 @@ export class SchemaParameterResolver {
|
|
|
209
210
|
} catch (error) {
|
|
210
211
|
if (this.isUserCancellation(error)) {
|
|
211
212
|
console.log(chalk.yellow("\n\nOperation cancelled by user"));
|
|
212
|
-
|
|
213
|
+
throw new ZapierCliUserCancellationError();
|
|
213
214
|
}
|
|
214
215
|
throw error;
|
|
215
216
|
}
|
|
@@ -257,7 +258,7 @@ export class SchemaParameterResolver {
|
|
|
257
258
|
} catch (error) {
|
|
258
259
|
if (this.isUserCancellation(error)) {
|
|
259
260
|
console.log(chalk.yellow("\n\nOperation cancelled by user"));
|
|
260
|
-
|
|
261
|
+
throw new ZapierCliUserCancellationError();
|
|
261
262
|
}
|
|
262
263
|
throw error;
|
|
263
264
|
}
|
|
@@ -302,7 +303,7 @@ export class SchemaParameterResolver {
|
|
|
302
303
|
} catch (error) {
|
|
303
304
|
if (this.isUserCancellation(error)) {
|
|
304
305
|
console.log(chalk.yellow("\n\nOperation cancelled by user"));
|
|
305
|
-
|
|
306
|
+
throw new ZapierCliUserCancellationError();
|
|
306
307
|
}
|
|
307
308
|
throw error;
|
|
308
309
|
}
|
|
@@ -670,7 +671,7 @@ export class SchemaParameterResolver {
|
|
|
670
671
|
} catch (error) {
|
|
671
672
|
if (this.isUserCancellation(error)) {
|
|
672
673
|
console.log(chalk.yellow("\n\nOperation cancelled by user"));
|
|
673
|
-
|
|
674
|
+
throw new ZapierCliUserCancellationError();
|
|
674
675
|
}
|
|
675
676
|
throw error;
|
|
676
677
|
}
|
|
@@ -755,7 +756,7 @@ export class SchemaParameterResolver {
|
|
|
755
756
|
} catch (error) {
|
|
756
757
|
if (this.isUserCancellation(error)) {
|
|
757
758
|
console.log(chalk.yellow("\n\nOperation cancelled by user"));
|
|
758
|
-
|
|
759
|
+
throw new ZapierCliUserCancellationError();
|
|
759
760
|
}
|
|
760
761
|
throw error;
|
|
761
762
|
}
|
package/src/utils/spinner.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import ora from "ora";
|
|
2
|
+
import { ZapierCliUserCancellationError } from "./errors";
|
|
2
3
|
|
|
3
4
|
export const spinPromise = async <T>(
|
|
4
5
|
promise: Promise<T>,
|
|
@@ -10,7 +11,13 @@ export const spinPromise = async <T>(
|
|
|
10
11
|
spinner.succeed();
|
|
11
12
|
return result;
|
|
12
13
|
} catch (error) {
|
|
13
|
-
|
|
14
|
+
if (error instanceof ZapierCliUserCancellationError) {
|
|
15
|
+
// For user cancellation, just stop the spinner without showing failure
|
|
16
|
+
spinner.stop();
|
|
17
|
+
} else {
|
|
18
|
+
// For actual errors, show failure
|
|
19
|
+
spinner.fail();
|
|
20
|
+
}
|
|
14
21
|
throw error;
|
|
15
22
|
}
|
|
16
23
|
};
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
2
|
+
import { checkForUpdates, displayUpdateNotification } from "./version-checker";
|
|
3
|
+
|
|
4
|
+
// Mock package-json
|
|
5
|
+
vi.mock("package-json", () => ({
|
|
6
|
+
default: vi.fn(),
|
|
7
|
+
}));
|
|
8
|
+
|
|
9
|
+
// Mock chalk to make testing easier
|
|
10
|
+
vi.mock("chalk", () => ({
|
|
11
|
+
default: {
|
|
12
|
+
red: Object.assign((text: string) => text, {
|
|
13
|
+
bold: (text: string) => text,
|
|
14
|
+
}),
|
|
15
|
+
yellow: Object.assign((text: string) => text, {
|
|
16
|
+
bold: (text: string) => text,
|
|
17
|
+
}),
|
|
18
|
+
bold: (text: string) => text,
|
|
19
|
+
},
|
|
20
|
+
}));
|
|
21
|
+
|
|
22
|
+
// Mock log module
|
|
23
|
+
vi.mock("./log", () => ({
|
|
24
|
+
default: {
|
|
25
|
+
debug: vi.fn(),
|
|
26
|
+
},
|
|
27
|
+
}));
|
|
28
|
+
|
|
29
|
+
// Mock conf module
|
|
30
|
+
const mockConf = {
|
|
31
|
+
get: vi.fn(),
|
|
32
|
+
set: vi.fn(),
|
|
33
|
+
};
|
|
34
|
+
vi.mock("conf", () => ({
|
|
35
|
+
default: vi.fn().mockImplementation(() => mockConf),
|
|
36
|
+
}));
|
|
37
|
+
|
|
38
|
+
const mockPackageJson = vi.mocked(await import("package-json")).default;
|
|
39
|
+
|
|
40
|
+
describe("version-checker", () => {
|
|
41
|
+
beforeEach(() => {
|
|
42
|
+
vi.clearAllMocks();
|
|
43
|
+
// Ensure cache is cleared between tests by returning undefined from get
|
|
44
|
+
mockConf.get.mockReturnValue(undefined);
|
|
45
|
+
// Suppress console output during tests
|
|
46
|
+
vi.spyOn(console, "log").mockImplementation(() => {});
|
|
47
|
+
vi.spyOn(console, "error").mockImplementation(() => {});
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
describe("checkForUpdates", () => {
|
|
51
|
+
it("should detect when an update is available", async () => {
|
|
52
|
+
mockPackageJson.mockResolvedValue({
|
|
53
|
+
version: "1.0.1",
|
|
54
|
+
deprecated: false,
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
const result = await checkForUpdates({
|
|
58
|
+
packageName: "test-package",
|
|
59
|
+
currentVersion: "1.0.0",
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
expect(result).toEqual({
|
|
63
|
+
hasUpdate: true,
|
|
64
|
+
latestVersion: "1.0.1",
|
|
65
|
+
currentVersion: "1.0.0",
|
|
66
|
+
isDeprecated: false,
|
|
67
|
+
deprecationMessage: undefined,
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it("should detect when package is deprecated", async () => {
|
|
72
|
+
mockPackageJson.mockResolvedValue({
|
|
73
|
+
version: "1.0.0",
|
|
74
|
+
deprecated: "This package is no longer maintained",
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
const result = await checkForUpdates({
|
|
78
|
+
packageName: "test-package",
|
|
79
|
+
currentVersion: "1.0.0",
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
expect(result).toEqual({
|
|
83
|
+
hasUpdate: false,
|
|
84
|
+
latestVersion: "1.0.0",
|
|
85
|
+
currentVersion: "1.0.0",
|
|
86
|
+
isDeprecated: true,
|
|
87
|
+
deprecationMessage: "This package is no longer maintained",
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it("should handle when no update is available", async () => {
|
|
92
|
+
mockPackageJson.mockResolvedValue({
|
|
93
|
+
version: "1.0.0",
|
|
94
|
+
deprecated: false,
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
const result = await checkForUpdates({
|
|
98
|
+
packageName: "test-package",
|
|
99
|
+
currentVersion: "1.0.0",
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
expect(result).toEqual({
|
|
103
|
+
hasUpdate: false,
|
|
104
|
+
latestVersion: "1.0.0",
|
|
105
|
+
currentVersion: "1.0.0",
|
|
106
|
+
isDeprecated: false,
|
|
107
|
+
deprecationMessage: undefined,
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it("should handle network errors gracefully", async () => {
|
|
112
|
+
mockPackageJson.mockRejectedValue(new Error("Network error"));
|
|
113
|
+
|
|
114
|
+
const result = await checkForUpdates({
|
|
115
|
+
packageName: "test-package",
|
|
116
|
+
currentVersion: "1.0.0",
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
expect(result).toEqual({
|
|
120
|
+
hasUpdate: false,
|
|
121
|
+
currentVersion: "1.0.0",
|
|
122
|
+
isDeprecated: false,
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
describe("displayUpdateNotification", () => {
|
|
128
|
+
it("should display deprecation warning", () => {
|
|
129
|
+
const consoleSpy = vi
|
|
130
|
+
.spyOn(console, "error")
|
|
131
|
+
.mockImplementation(() => {});
|
|
132
|
+
|
|
133
|
+
displayUpdateNotification(
|
|
134
|
+
{
|
|
135
|
+
hasUpdate: false,
|
|
136
|
+
currentVersion: "1.0.0",
|
|
137
|
+
isDeprecated: true,
|
|
138
|
+
deprecationMessage: "This package is deprecated",
|
|
139
|
+
},
|
|
140
|
+
"test-package",
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
expect(consoleSpy).toHaveBeenCalledWith(
|
|
144
|
+
expect.stringContaining("DEPRECATION WARNING"),
|
|
145
|
+
);
|
|
146
|
+
expect(consoleSpy).toHaveBeenCalledWith(
|
|
147
|
+
expect.stringContaining("This package is deprecated"),
|
|
148
|
+
);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it("should display update notification", () => {
|
|
152
|
+
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => {});
|
|
153
|
+
|
|
154
|
+
displayUpdateNotification(
|
|
155
|
+
{
|
|
156
|
+
hasUpdate: true,
|
|
157
|
+
currentVersion: "1.0.0",
|
|
158
|
+
latestVersion: "1.0.1",
|
|
159
|
+
isDeprecated: false,
|
|
160
|
+
},
|
|
161
|
+
"test-package",
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
expect(consoleSpy).toHaveBeenCalledWith(
|
|
165
|
+
expect.stringContaining("Update available!"),
|
|
166
|
+
);
|
|
167
|
+
expect(consoleSpy).toHaveBeenCalledWith(
|
|
168
|
+
expect.stringContaining("pnpm update test-package"),
|
|
169
|
+
);
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
it("should display both deprecation and update notifications", () => {
|
|
173
|
+
const consoleErrorSpy = vi
|
|
174
|
+
.spyOn(console, "error")
|
|
175
|
+
.mockImplementation(() => {});
|
|
176
|
+
const consoleLogSpy = vi
|
|
177
|
+
.spyOn(console, "log")
|
|
178
|
+
.mockImplementation(() => {});
|
|
179
|
+
|
|
180
|
+
displayUpdateNotification(
|
|
181
|
+
{
|
|
182
|
+
hasUpdate: true,
|
|
183
|
+
currentVersion: "1.0.0",
|
|
184
|
+
latestVersion: "1.0.1",
|
|
185
|
+
isDeprecated: true,
|
|
186
|
+
deprecationMessage: "This package is deprecated",
|
|
187
|
+
},
|
|
188
|
+
"test-package",
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
expect(consoleErrorSpy).toHaveBeenCalledWith(
|
|
192
|
+
expect.stringContaining("DEPRECATION WARNING"),
|
|
193
|
+
);
|
|
194
|
+
expect(consoleLogSpy).toHaveBeenCalledWith(
|
|
195
|
+
expect.stringContaining("Update available!"),
|
|
196
|
+
);
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
});
|