From 8a33cab1efd58af8b88373d5a77622ab4a3e786e Mon Sep 17 00:00:00 2001 From: ymc9 <104139426+ymc9@users.noreply.github.com> Date: Thu, 24 Nov 2022 15:16:33 +0800 Subject: [PATCH 1/3] feat: add "init" command to CLI --- docs/quick-start.md | 10 +--- packages/schema/src/cli/cli-util.ts | 87 +++++++++++++++++++++++++++++ packages/schema/src/cli/index.ts | 18 +++++- packages/schema/src/telemetry.ts | 8 +++ 4 files changed, 113 insertions(+), 10 deletions(-) diff --git a/docs/quick-start.md b/docs/quick-start.md index 7d9f52d51..91ee9d499 100644 --- a/docs/quick-start.md +++ b/docs/quick-start.md @@ -45,15 +45,7 @@ It's good idea to install the [VSCode extension](https://marketplace.visualstudi ## Adding to an existing project -To add ZenStack to an existing Next.js + Typescript project, follow the steps below: - -1. Install zenstack cli - -```bash -npm install --save-dev zenstack -``` - -2. Initialize the project +To add ZenStack to an existing Next.js + Typescript project, run command below: ```bash npx zenstack init diff --git a/packages/schema/src/cli/cli-util.ts b/packages/schema/src/cli/cli-util.ts index ec1bbb283..177d8df6f 100644 --- a/packages/schema/src/cli/cli-util.ts +++ b/packages/schema/src/cli/cli-util.ts @@ -12,6 +12,93 @@ import { GENERATED_CODE_PATH } from '../generator/constants'; import { Context, GeneratorError } from '../generator/types'; import { CliError } from './cli-error'; +/** + * Initializes an existing project for ZenStack + */ +export async function initProject(projectPath: string) { + const schema = path.join(projectPath, 'zenstack', 'schema.zmodel'); + if (fs.existsSync(schema)) { + console.warn(colors.yellow(`Model already exists: ${schema}`)); + throw new CliError(`schema file already exists`); + } + + // create a default model + if (!fs.existsSync(path.join(projectPath, 'zenstack'))) { + fs.mkdirSync(path.join(projectPath, 'zenstack')); + } + + fs.writeFileSync( + schema, + `// This is a sample model to get you started. +// Learn how to model you app: https://zenstack.dev/#/modeling-your-app. + +/* + * A sample data source using local sqlite db. + * See how to use a different db: https://zenstack.dev/#/zmodel-data-source. + */ +datasource db { + provider = 'sqlite' + url = 'file:./todo.db' +} + +/* + * User model + */ +model User { + id String @id @default(cuid()) + email String @unique @email + password String @password @omit @length(8, 16) + posts Post[] + + // everybody can signup + @@allow('create', true) + + // full access by self + @@allow('all', auth() == this) +} + +/* + * Post model + */ +model Post { + id String @id @default(cuid()) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + title String @length(1, 256) + content String + published Boolean @default(false) + author User? @relation(fields: [authorId], references: [id]) + authorId String? + + // allow read for all signin users + @@allow('read', auth() != null && published) + + // full access by author + @@allow('all', author == auth()) +} +` + ); + + // add zenstack/schema.prisma to .gitignore + const gitIgnorePath = path.join(projectPath, '.gitignore'); + let gitIgnoreContent = ''; + if (fs.existsSync(gitIgnorePath)) { + gitIgnoreContent = + fs.readFileSync(gitIgnorePath, { encoding: 'utf-8' }) + '\n'; + } + + if (!gitIgnoreContent.includes('zenstack/schema.prisma')) { + gitIgnoreContent += 'zenstack/schema.prisma\n'; + fs.writeFileSync(gitIgnorePath, gitIgnoreContent); + } + + console.log(`Sample model generated at: ${colors.green(schema)} + +Please check the following guide on how to model your app: + https://zenstack.dev/#/modeling-your-app. +`); +} + /** * Loads a zmodel document from a file. * @param fileName File name diff --git a/packages/schema/src/cli/index.ts b/packages/schema/src/cli/index.ts index 3cc3c2447..a4dadc24f 100644 --- a/packages/schema/src/cli/index.ts +++ b/packages/schema/src/cli/index.ts @@ -7,7 +7,17 @@ import { ZModelLanguageMetaData } from '../language-server/generated/module'; import telemetry from '../telemetry'; import { execSync } from '../utils/exec-utils'; import { CliError } from './cli-error'; -import { runGenerator } from './cli-util'; +import { initProject, runGenerator } from './cli-util'; + +export const initAction = async (projectPath: string): Promise => { + await telemetry.trackSpan( + 'cli:command:start', + 'cli:command:complete', + 'cli:command:error', + { command: 'init' }, + () => initProject(projectPath) + ); +}; export const generateAction = async (options: { schema: string; @@ -108,6 +118,12 @@ export default async function (): Promise { //#region wraps Prisma commands + program + .command('init') + .description('Set up a new ZenStack project.') + .argument('', 'project path') + .action(initAction); + program .command('generate') .description( diff --git a/packages/schema/src/telemetry.ts b/packages/schema/src/telemetry.ts index ca4eeda13..d265aca61 100644 --- a/packages/schema/src/telemetry.ts +++ b/packages/schema/src/telemetry.ts @@ -5,6 +5,7 @@ import cuid from 'cuid'; import * as os from 'os'; import sleep from 'sleep-promise'; import exitHook from 'async-exit-hook'; +import { CliError } from './cli/cli-error'; /** * Telemetry events @@ -57,6 +58,13 @@ export class Telemetry { // a small delay to ensure telemetry is sent await sleep(this.exitWait); } + + if (err instanceof CliError) { + // error already handled + } else { + throw err; + } + process.exit(1); }); } From 7feab4eefff4bc131a5e6ca417a005c31e41c873 Mon Sep 17 00:00:00 2001 From: ymc9 <104139426+ymc9@users.noreply.github.com> Date: Thu, 24 Nov 2022 15:54:42 +0800 Subject: [PATCH 2/3] update telemetry --- packages/schema/src/telemetry.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/schema/src/telemetry.ts b/packages/schema/src/telemetry.ts index d265aca61..b35a81299 100644 --- a/packages/schema/src/telemetry.ts +++ b/packages/schema/src/telemetry.ts @@ -6,6 +6,7 @@ import * as os from 'os'; import sleep from 'sleep-promise'; import exitHook from 'async-exit-hook'; import { CliError } from './cli/cli-error'; +import { CommanderError } from 'commander'; /** * Telemetry events @@ -59,7 +60,7 @@ export class Telemetry { await sleep(this.exitWait); } - if (err instanceof CliError) { + if (err instanceof CliError || err instanceof CommanderError) { // error already handled } else { throw err; From bf4d7b880079b2b5c26814f9207e439ee63d0629 Mon Sep 17 00:00:00 2001 From: ymc9 <104139426+ymc9@users.noreply.github.com> Date: Thu, 24 Nov 2022 16:05:45 +0800 Subject: [PATCH 3/3] bump version --- package.json | 2 +- packages/internal/package.json | 2 +- packages/runtime/package.json | 2 +- packages/schema/package.json | 2 +- samples/todo/package.json | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 6678de452..f69de5a34 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "zenstack-monorepo", - "version": "0.3.9", + "version": "0.3.10", "description": "", "scripts": { "build": "pnpm -r build", diff --git a/packages/internal/package.json b/packages/internal/package.json index c4f420314..f0c40e8c4 100644 --- a/packages/internal/package.json +++ b/packages/internal/package.json @@ -1,6 +1,6 @@ { "name": "@zenstackhq/internal", - "version": "0.3.9", + "version": "0.3.10", "displayName": "ZenStack Internal Library", "description": "ZenStack internal runtime library. This package is for supporting runtime functionality of ZenStack and not supposed to be used directly.", "repository": { diff --git a/packages/runtime/package.json b/packages/runtime/package.json index fe6f3854b..866d92df9 100644 --- a/packages/runtime/package.json +++ b/packages/runtime/package.json @@ -1,7 +1,7 @@ { "name": "@zenstackhq/runtime", "displayName": "ZenStack Runtime Library", - "version": "0.3.9", + "version": "0.3.10", "description": "This package contains runtime library for consuming client and server side code generated by ZenStack.", "repository": { "type": "git", diff --git a/packages/schema/package.json b/packages/schema/package.json index 2cb3d1a5d..1470294b3 100644 --- a/packages/schema/package.json +++ b/packages/schema/package.json @@ -3,7 +3,7 @@ "publisher": "zenstack", "displayName": "ZenStack Language Tools", "description": "A toolkit for modeling data and access policies in full-stack development with Next.js and Typescript", - "version": "0.3.9", + "version": "0.3.10", "author": { "name": "ZenStack Team" }, diff --git a/samples/todo/package.json b/samples/todo/package.json index 620af9d33..8e841bd76 100644 --- a/samples/todo/package.json +++ b/samples/todo/package.json @@ -1,6 +1,6 @@ { "name": "todo", - "version": "0.3.9", + "version": "0.3.10", "private": true, "scripts": { "dev": "next dev",