Skip to content

Commit 1d1f2c9

Browse files
authored
feat: new version check (#222)
* feat: new version check * update
1 parent 11658f2 commit 1d1f2c9

File tree

5 files changed

+89
-10
lines changed

5 files changed

+89
-10
lines changed

packages/cli/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,15 @@
3838
"mixpanel": "^0.18.1",
3939
"ora": "^5.4.1",
4040
"package-manager-detector": "^1.3.0",
41+
"semver": "^7.7.2",
4142
"ts-pattern": "catalog:"
4243
},
4344
"peerDependencies": {
4445
"prisma": "catalog:"
4546
},
4647
"devDependencies": {
4748
"@types/better-sqlite3": "^7.6.13",
49+
"@types/semver": "^7.7.0",
4850
"@types/tmp": "catalog:",
4951
"@zenstackhq/eslint-config": "workspace:*",
5052
"@zenstackhq/runtime": "workspace:*",

packages/cli/src/actions/info.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,15 @@ async function getZenStackPackages(projectPath: string): Promise<Array<{ pkg: st
5757
with: { type: 'json' },
5858
})
5959
).default;
60+
if (depPkgJson.private) {
61+
return undefined;
62+
}
6063
return { pkg, version: depPkgJson.version as string };
6164
} catch {
6265
return { pkg, version: undefined };
6366
}
6467
}),
6568
);
6669

67-
return result;
70+
return result.filter((p) => !!p);
6871
}

packages/cli/src/index.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { Command, CommanderError, Option } from 'commander';
44
import * as actions from './actions';
55
import { CliError } from './cli-error';
66
import { telemetry } from './telemetry';
7-
import { getVersion } from './utils/version-utils';
7+
import { checkNewVersion, getVersion } from './utils/version-utils';
88

99
const generateAction = async (options: Parameters<typeof actions.generate>[0]): Promise<void> => {
1010
await telemetry.trackCommand('generate', () => actions.generate(options));
@@ -51,10 +51,13 @@ function createProgram() {
5151
`schema file (with extension ${schemaExtensions}). Defaults to "zenstack/schema.zmodel" unless specified in package.json.`,
5252
);
5353

54+
const noVersionCheckOption = new Option('--no-version-check', 'do not check for new version');
55+
5456
program
5557
.command('generate')
5658
.description('Run code generation plugins.')
5759
.addOption(schemaOption)
60+
.addOption(noVersionCheckOption)
5861
.addOption(new Option('-o, --output <path>', 'default output directory for code generation'))
5962
.addOption(new Option('--silent', 'suppress all output except errors').default(false))
6063
.action(generateAction);
@@ -65,6 +68,7 @@ function createProgram() {
6568
migrateCommand
6669
.command('dev')
6770
.addOption(schemaOption)
71+
.addOption(noVersionCheckOption)
6872
.addOption(new Option('-n, --name <name>', 'migration name'))
6973
.addOption(new Option('--create-only', 'only create migration, do not apply'))
7074
.addOption(migrationsOption)
@@ -76,26 +80,30 @@ function createProgram() {
7680
.addOption(schemaOption)
7781
.addOption(new Option('--force', 'skip the confirmation prompt'))
7882
.addOption(migrationsOption)
83+
.addOption(noVersionCheckOption)
7984
.description('Reset your database and apply all migrations, all data will be lost.')
8085
.action((options) => migrateAction('reset', options));
8186

8287
migrateCommand
8388
.command('deploy')
8489
.addOption(schemaOption)
90+
.addOption(noVersionCheckOption)
8591
.addOption(migrationsOption)
8692
.description('Deploy your pending migrations to your production/staging database.')
8793
.action((options) => migrateAction('deploy', options));
8894

8995
migrateCommand
9096
.command('status')
9197
.addOption(schemaOption)
98+
.addOption(noVersionCheckOption)
9299
.addOption(migrationsOption)
93100
.description('Check the status of your database migrations.')
94101
.action((options) => migrateAction('status', options));
95102

96103
migrateCommand
97104
.command('resolve')
98105
.addOption(schemaOption)
106+
.addOption(noVersionCheckOption)
99107
.addOption(migrationsOption)
100108
.addOption(new Option('--applied <migration>', 'record a specific migration as applied'))
101109
.addOption(new Option('--rolled-back <migration>', 'record a specific migration as rolled back'))
@@ -108,6 +116,7 @@ function createProgram() {
108116
.command('push')
109117
.description('Push the state from your schema to your database.')
110118
.addOption(schemaOption)
119+
.addOption(noVersionCheckOption)
111120
.addOption(new Option('--accept-data-loss', 'ignore data loss warnings'))
112121
.addOption(new Option('--force-reset', 'force a reset of the database before push'))
113122
.action((options) => dbAction('push', options));
@@ -116,20 +125,29 @@ function createProgram() {
116125
.command('info')
117126
.description('Get information of installed ZenStack packages.')
118127
.argument('[path]', 'project path', '.')
128+
.addOption(noVersionCheckOption)
119129
.action(infoAction);
120130

121131
program
122132
.command('init')
123133
.description('Initialize an existing project for ZenStack.')
124134
.argument('[path]', 'project path', '.')
135+
.addOption(noVersionCheckOption)
125136
.action(initAction);
126137

127138
program
128139
.command('check')
129140
.description('Check a ZModel schema for syntax or semantic errors.')
130141
.addOption(schemaOption)
142+
.addOption(noVersionCheckOption)
131143
.action(checkAction);
132144

145+
program.hook('preAction', async (_thisCommand, actionCommand) => {
146+
if (actionCommand.getOptionValue('versionCheck') !== false) {
147+
await checkNewVersion();
148+
}
149+
});
150+
133151
return program;
134152
}
135153

packages/cli/src/utils/version-utils.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
1+
import colors from 'colors';
12
import fs from 'node:fs';
23
import path from 'node:path';
34
import { fileURLToPath } from 'node:url';
5+
import semver from 'semver';
6+
7+
const CHECK_VERSION_TIMEOUT = 2000;
8+
const VERSION_CHECK_TAG = 'next';
49

510
export function getVersion() {
611
try {
@@ -11,3 +16,35 @@ export function getVersion() {
1116
return undefined;
1217
}
1318
}
19+
20+
export async function checkNewVersion() {
21+
const currVersion = getVersion();
22+
let latestVersion: string;
23+
try {
24+
latestVersion = await getLatestVersion();
25+
} catch {
26+
// noop
27+
return;
28+
}
29+
30+
if (latestVersion && currVersion && semver.gt(latestVersion, currVersion)) {
31+
console.log(`A newer version ${colors.cyan(latestVersion)} is available.`);
32+
}
33+
}
34+
35+
export async function getLatestVersion() {
36+
const fetchResult = await fetch(`https://registry.npmjs.org/@zenstackhq/cli/${VERSION_CHECK_TAG}`, {
37+
headers: { accept: 'application/vnd.npm.install-v1+json; q=1.0, application/json; q=0.8, */*' },
38+
signal: AbortSignal.timeout(CHECK_VERSION_TIMEOUT),
39+
});
40+
41+
if (fetchResult.ok) {
42+
const data: any = await fetchResult.json();
43+
const latestVersion = data?.version;
44+
if (typeof latestVersion === 'string' && semver.valid(latestVersion)) {
45+
return latestVersion;
46+
}
47+
}
48+
49+
throw new Error('invalid npm registry response');
50+
}

pnpm-lock.yaml

Lines changed: 27 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)