@meltstudio/meltctl 4.33.2 → 4.34.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.
|
@@ -2,4 +2,6 @@ export declare function getCurrentCliVersion(): Promise<string>;
|
|
|
2
2
|
export declare function getLatestCliVersion(): Promise<string | null>;
|
|
3
3
|
export declare function compareVersions(current: string, latest: string): boolean;
|
|
4
4
|
export declare function isCI(): boolean;
|
|
5
|
+
export type UpdateSeverity = 'none' | 'patch' | 'minor' | 'major';
|
|
6
|
+
export declare function getUpdateSeverity(current: string, latest: string): UpdateSeverity;
|
|
5
7
|
export declare function checkAndEnforceUpdate(): Promise<void>;
|
|
@@ -72,6 +72,19 @@ export function isCI() {
|
|
|
72
72
|
process.env.MELTCTL_SKIP_UPDATE_CHECK // Custom override
|
|
73
73
|
);
|
|
74
74
|
}
|
|
75
|
+
export function getUpdateSeverity(current, latest) {
|
|
76
|
+
const parseCurrent = current.split('-')[0].split('.').map(Number);
|
|
77
|
+
const parseLatest = latest.split('-')[0].split('.').map(Number);
|
|
78
|
+
const [curMajor = 0, curMinor = 0, curPatch = 0] = parseCurrent;
|
|
79
|
+
const [latMajor = 0, latMinor = 0, latPatch = 0] = parseLatest;
|
|
80
|
+
if (latMajor > curMajor)
|
|
81
|
+
return 'major';
|
|
82
|
+
if (latMajor === curMajor && latMinor > curMinor)
|
|
83
|
+
return 'minor';
|
|
84
|
+
if (latMajor === curMajor && latMinor === curMinor && latPatch > curPatch)
|
|
85
|
+
return 'patch';
|
|
86
|
+
return 'none';
|
|
87
|
+
}
|
|
75
88
|
export async function checkAndEnforceUpdate() {
|
|
76
89
|
// Skip update check in CI environments
|
|
77
90
|
if (isCI()) {
|
|
@@ -84,27 +97,37 @@ export async function checkAndEnforceUpdate() {
|
|
|
84
97
|
if (!latestVersion) {
|
|
85
98
|
return;
|
|
86
99
|
}
|
|
87
|
-
|
|
88
|
-
if (
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
console.log(chalk.yellow(`Current version: ${currentVersion}`));
|
|
95
|
-
console.log(chalk.green(`Latest version: ${latestVersion}`));
|
|
96
|
-
console.log();
|
|
97
|
-
console.log(chalk.white('Please update meltctl to continue:'));
|
|
98
|
-
console.log();
|
|
99
|
-
console.log(chalk.cyan(' npm install -g @meltstudio/meltctl@latest'));
|
|
100
|
-
console.log();
|
|
101
|
-
console.log(chalk.gray('Or with yarn:'));
|
|
102
|
-
console.log(chalk.cyan(' yarn global add @meltstudio/meltctl@latest'));
|
|
100
|
+
const severity = getUpdateSeverity(currentVersion, latestVersion);
|
|
101
|
+
if (severity === 'none') {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
const updateCmd = 'npm install -g @meltstudio/meltctl@latest';
|
|
105
|
+
if (severity === 'patch') {
|
|
106
|
+
// Patch updates: warn but allow continuing
|
|
103
107
|
console.log();
|
|
104
|
-
console.log(chalk.
|
|
108
|
+
console.log(chalk.yellow(` Update available: ${currentVersion} → ${latestVersion} (run: ${updateCmd})`));
|
|
105
109
|
console.log();
|
|
106
|
-
|
|
110
|
+
return;
|
|
107
111
|
}
|
|
112
|
+
// Minor/major updates: block until updated
|
|
113
|
+
console.log();
|
|
114
|
+
console.log(chalk.red('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
|
|
115
|
+
console.log(chalk.red.bold(' ⚠️ Update Required'));
|
|
116
|
+
console.log(chalk.red('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
|
|
117
|
+
console.log();
|
|
118
|
+
console.log(chalk.yellow(`Current version: ${currentVersion}`));
|
|
119
|
+
console.log(chalk.green(`Latest version: ${latestVersion}`));
|
|
120
|
+
console.log();
|
|
121
|
+
console.log(chalk.white('Please update meltctl to continue:'));
|
|
122
|
+
console.log();
|
|
123
|
+
console.log(chalk.cyan(` ${updateCmd}`));
|
|
124
|
+
console.log();
|
|
125
|
+
console.log(chalk.gray('Or with yarn:'));
|
|
126
|
+
console.log(chalk.cyan(' yarn global add @meltstudio/meltctl@latest'));
|
|
127
|
+
console.log();
|
|
128
|
+
console.log(chalk.gray('To skip this check (CI/CD), set MELTCTL_SKIP_UPDATE_CHECK=1'));
|
|
129
|
+
console.log();
|
|
130
|
+
process.exit(1);
|
|
108
131
|
}
|
|
109
132
|
catch {
|
|
110
133
|
// If any error occurs during version check, allow continuing
|
|
@@ -9,7 +9,7 @@ vi.mock('fs-extra', () => ({
|
|
|
9
9
|
}));
|
|
10
10
|
import { execSync } from 'child_process';
|
|
11
11
|
import fs from 'fs-extra';
|
|
12
|
-
import { getCurrentCliVersion, getLatestCliVersion, compareVersions, isCI, checkAndEnforceUpdate, } from './version-check.js';
|
|
12
|
+
import { getCurrentCliVersion, getLatestCliVersion, compareVersions, getUpdateSeverity, isCI, checkAndEnforceUpdate, } from './version-check.js';
|
|
13
13
|
beforeEach(() => {
|
|
14
14
|
vi.clearAllMocks();
|
|
15
15
|
vi.spyOn(console, 'log').mockImplementation(() => { });
|
|
@@ -96,6 +96,26 @@ describe('isCI', () => {
|
|
|
96
96
|
expect(isCI()).toBe(true);
|
|
97
97
|
});
|
|
98
98
|
});
|
|
99
|
+
describe('getUpdateSeverity', () => {
|
|
100
|
+
it('returns major when major version is higher', () => {
|
|
101
|
+
expect(getUpdateSeverity('1.0.0', '2.0.0')).toBe('major');
|
|
102
|
+
});
|
|
103
|
+
it('returns minor when minor version is higher', () => {
|
|
104
|
+
expect(getUpdateSeverity('1.0.0', '1.1.0')).toBe('minor');
|
|
105
|
+
});
|
|
106
|
+
it('returns patch when only patch is higher', () => {
|
|
107
|
+
expect(getUpdateSeverity('1.0.0', '1.0.1')).toBe('patch');
|
|
108
|
+
});
|
|
109
|
+
it('returns none when versions are equal', () => {
|
|
110
|
+
expect(getUpdateSeverity('1.0.0', '1.0.0')).toBe('none');
|
|
111
|
+
});
|
|
112
|
+
it('returns none when current is newer', () => {
|
|
113
|
+
expect(getUpdateSeverity('2.0.0', '1.0.0')).toBe('none');
|
|
114
|
+
});
|
|
115
|
+
it('returns major over minor', () => {
|
|
116
|
+
expect(getUpdateSeverity('1.5.3', '2.0.0')).toBe('major');
|
|
117
|
+
});
|
|
118
|
+
});
|
|
99
119
|
describe('checkAndEnforceUpdate', () => {
|
|
100
120
|
it('skips check in CI environment', async () => {
|
|
101
121
|
process.env.CI = 'true';
|
|
@@ -119,13 +139,29 @@ describe('checkAndEnforceUpdate', () => {
|
|
|
119
139
|
await checkAndEnforceUpdate();
|
|
120
140
|
// Should not throw or exit
|
|
121
141
|
});
|
|
122
|
-
it('
|
|
142
|
+
it('blocks on minor version update', async () => {
|
|
123
143
|
const exitSpy = vi.spyOn(process, 'exit').mockImplementation(() => undefined);
|
|
124
144
|
fs.readJson.mockResolvedValue({ version: '4.25.0' });
|
|
125
145
|
execSync.mockReturnValue('"4.26.0"\n');
|
|
126
146
|
await checkAndEnforceUpdate();
|
|
127
147
|
expect(exitSpy).toHaveBeenCalledWith(1);
|
|
128
148
|
});
|
|
149
|
+
it('blocks on major version update', async () => {
|
|
150
|
+
const exitSpy = vi.spyOn(process, 'exit').mockImplementation(() => undefined);
|
|
151
|
+
fs.readJson.mockResolvedValue({ version: '4.33.0' });
|
|
152
|
+
execSync.mockReturnValue('"5.0.0"\n');
|
|
153
|
+
await checkAndEnforceUpdate();
|
|
154
|
+
expect(exitSpy).toHaveBeenCalledWith(1);
|
|
155
|
+
});
|
|
156
|
+
it('warns but does not block on patch update', async () => {
|
|
157
|
+
const exitSpy = vi.spyOn(process, 'exit').mockImplementation(() => undefined);
|
|
158
|
+
fs.readJson.mockResolvedValue({ version: '4.33.0' });
|
|
159
|
+
execSync.mockReturnValue('"4.33.2"\n');
|
|
160
|
+
await checkAndEnforceUpdate();
|
|
161
|
+
expect(exitSpy).not.toHaveBeenCalled();
|
|
162
|
+
const logCalls = console.log.mock.calls.map((c) => String(c[0]));
|
|
163
|
+
expect(logCalls.some((msg) => msg.includes('Update available'))).toBe(true);
|
|
164
|
+
});
|
|
129
165
|
it('allows continuing when getCurrentCliVersion throws', async () => {
|
|
130
166
|
;
|
|
131
167
|
fs.readJson.mockRejectedValue(new Error('file not found'));
|
package/package.json
CHANGED