Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,15 @@
"mixpanel": "^0.18.1",
"ora": "^5.4.1",
"package-manager-detector": "^1.3.0",
"semver": "^7.7.2",
"ts-pattern": "catalog:"
},
"peerDependencies": {
"prisma": "catalog:"
},
"devDependencies": {
"@types/better-sqlite3": "^7.6.13",
"@types/semver": "^7.7.0",
"@types/tmp": "catalog:",
"@zenstackhq/eslint-config": "workspace:*",
"@zenstackhq/runtime": "workspace:*",
Expand Down
5 changes: 4 additions & 1 deletion packages/cli/src/actions/info.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,15 @@ async function getZenStackPackages(projectPath: string): Promise<Array<{ pkg: st
with: { type: 'json' },
})
).default;
if (depPkgJson.private) {
return undefined;
}
return { pkg, version: depPkgJson.version as string };
} catch {
return { pkg, version: undefined };
}
}),
);

return result;
return result.filter((p) => !!p);
}
20 changes: 19 additions & 1 deletion packages/cli/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Command, CommanderError, Option } from 'commander';
import * as actions from './actions';
import { CliError } from './cli-error';
import { telemetry } from './telemetry';
import { getVersion } from './utils/version-utils';
import { checkNewVersion, getVersion } from './utils/version-utils';

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

const noVersionCheckOption = new Option('--no-version-check', 'do not check for new version');

program
.command('generate')
.description('Run code generation plugins.')
.addOption(schemaOption)
.addOption(noVersionCheckOption)
.addOption(new Option('-o, --output <path>', 'default output directory for code generation'))
.addOption(new Option('--silent', 'suppress all output except errors').default(false))
.action(generateAction);
Expand All @@ -65,6 +68,7 @@ function createProgram() {
migrateCommand
.command('dev')
.addOption(schemaOption)
.addOption(noVersionCheckOption)
.addOption(new Option('-n, --name <name>', 'migration name'))
.addOption(new Option('--create-only', 'only create migration, do not apply'))
.addOption(migrationsOption)
Expand All @@ -76,26 +80,30 @@ function createProgram() {
.addOption(schemaOption)
.addOption(new Option('--force', 'skip the confirmation prompt'))
.addOption(migrationsOption)
.addOption(noVersionCheckOption)
.description('Reset your database and apply all migrations, all data will be lost.')
.action((options) => migrateAction('reset', options));

migrateCommand
.command('deploy')
.addOption(schemaOption)
.addOption(noVersionCheckOption)
.addOption(migrationsOption)
.description('Deploy your pending migrations to your production/staging database.')
.action((options) => migrateAction('deploy', options));

migrateCommand
.command('status')
.addOption(schemaOption)
.addOption(noVersionCheckOption)
.addOption(migrationsOption)
.description('Check the status of your database migrations.')
.action((options) => migrateAction('status', options));

migrateCommand
.command('resolve')
.addOption(schemaOption)
.addOption(noVersionCheckOption)
.addOption(migrationsOption)
.addOption(new Option('--applied <migration>', 'record a specific migration as applied'))
.addOption(new Option('--rolled-back <migration>', 'record a specific migration as rolled back'))
Expand All @@ -108,6 +116,7 @@ function createProgram() {
.command('push')
.description('Push the state from your schema to your database.')
.addOption(schemaOption)
.addOption(noVersionCheckOption)
.addOption(new Option('--accept-data-loss', 'ignore data loss warnings'))
.addOption(new Option('--force-reset', 'force a reset of the database before push'))
.action((options) => dbAction('push', options));
Expand All @@ -116,20 +125,29 @@ function createProgram() {
.command('info')
.description('Get information of installed ZenStack packages.')
.argument('[path]', 'project path', '.')
.addOption(noVersionCheckOption)
.action(infoAction);

program
.command('init')
.description('Initialize an existing project for ZenStack.')
.argument('[path]', 'project path', '.')
.addOption(noVersionCheckOption)
.action(initAction);

program
.command('check')
.description('Check a ZModel schema for syntax or semantic errors.')
.addOption(schemaOption)
.addOption(noVersionCheckOption)
.action(checkAction);

program.hook('preAction', async (_thisCommand, actionCommand) => {
if (actionCommand.getOptionValue('versionCheck') !== false) {
await checkNewVersion();
}
});

return program;
}

Expand Down
37 changes: 37 additions & 0 deletions packages/cli/src/utils/version-utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import colors from 'colors';
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import semver from 'semver';

const CHECK_VERSION_TIMEOUT = 2000;
const VERSION_CHECK_TAG = 'next';

export function getVersion() {
try {
Expand All @@ -11,3 +16,35 @@ export function getVersion() {
return undefined;
}
}

export async function checkNewVersion() {
const currVersion = getVersion();
let latestVersion: string;
try {
latestVersion = await getLatestVersion();
} catch {
// noop
return;
}

if (latestVersion && currVersion && semver.gt(latestVersion, currVersion)) {
console.log(`A newer version ${colors.cyan(latestVersion)} is available.`);
}
}

export async function getLatestVersion() {
const fetchResult = await fetch(`https://registry.npmjs.org/@zenstackhq/cli/${VERSION_CHECK_TAG}`, {
headers: { accept: 'application/vnd.npm.install-v1+json; q=1.0, application/json; q=0.8, */*' },
signal: AbortSignal.timeout(CHECK_VERSION_TIMEOUT),
});

if (fetchResult.ok) {
const data: any = await fetchResult.json();
const latestVersion = data?.version;
if (typeof latestVersion === 'string' && semver.valid(latestVersion)) {
return latestVersion;
}
}

throw new Error('invalid npm registry response');
}
35 changes: 27 additions & 8 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.