From 0eb306a61cf88b8be3be86852cb66b1d99ad713f Mon Sep 17 00:00:00 2001 From: Gao Sun Date: Wed, 5 Oct 2022 02:30:37 +0800 Subject: [PATCH] feat(cli): database config command --- packages/cli/package.json | 4 ++- packages/cli/src/commands/database/index.ts | 13 ++++++++ packages/cli/src/commands/database/url.ts | 12 ++++++++ packages/cli/src/commands/install.ts | 24 ++++++++++++++- packages/cli/src/index.ts | 22 ++----------- packages/cli/src/utilities.ts | 34 +++++++++++++++++++++ pnpm-lock.yaml | 10 +++--- 7 files changed, 92 insertions(+), 27 deletions(-) create mode 100644 packages/cli/src/commands/database/index.ts create mode 100644 packages/cli/src/commands/database/url.ts diff --git a/packages/cli/package.json b/packages/cli/package.json index 56516eee8..08cac6beb 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -35,13 +35,15 @@ }, "dependencies": { "chalk": "^4.1.2", + "find-up": "^5.0.0", "got": "^11.8.2", "hpagent": "^1.0.0", "inquirer": "^8.2.2", "ora": "^5.0.0", "semver": "^7.3.7", "tar": "^6.1.11", - "yargs": "^17.6.0" + "yargs": "^17.6.0", + "zod": "^3.18.0" }, "devDependencies": { "@silverhand/eslint-config": "1.0.0", diff --git a/packages/cli/src/commands/database/index.ts b/packages/cli/src/commands/database/index.ts new file mode 100644 index 000000000..5622a095a --- /dev/null +++ b/packages/cli/src/commands/database/index.ts @@ -0,0 +1,13 @@ +import { CommandModule } from 'yargs'; + +import { noop } from '../../utilities'; +import { getUrl } from './url'; + +const database: CommandModule = { + command: ['database ', 'db'], + describe: 'Commands for Logto database', + builder: (yargs) => yargs.command(getUrl), + handler: noop, +}; + +export default database; diff --git a/packages/cli/src/commands/database/url.ts b/packages/cli/src/commands/database/url.ts new file mode 100644 index 000000000..5f35fd2fc --- /dev/null +++ b/packages/cli/src/commands/database/url.ts @@ -0,0 +1,12 @@ +import { CommandModule } from 'yargs'; + +import { getConfig } from '../../utilities'; + +export const getUrl: CommandModule = { + command: 'get-url', + describe: 'Get database URL in Logto config file', + handler: async () => { + const { databaseUrl } = await getConfig(); + console.log(databaseUrl); + }, +}; diff --git a/packages/cli/src/commands/install.ts b/packages/cli/src/commands/install.ts index 04602d718..7d95d9be4 100644 --- a/packages/cli/src/commands/install.ts +++ b/packages/cli/src/commands/install.ts @@ -9,6 +9,7 @@ import inquirer from 'inquirer'; import ora from 'ora'; import * as semver from 'semver'; import tar from 'tar'; +import { CommandModule } from 'yargs'; import { downloadFile, log, safeExecSync } from '../utilities'; @@ -102,7 +103,7 @@ const decompress = async (toPath: string, tarPath: string) => { decompressSpinner.succeed(); }; -const install = async ({ path: pathArgument = defaultPath, silent = false }: InstallArgs) => { +const installLogto = async ({ path: pathArgument = defaultPath, silent = false }: InstallArgs) => { validateNodeVersion(); const instancePath = (!silent && (await getInstancePath())) || pathArgument; @@ -122,4 +123,25 @@ const install = async ({ path: pathArgument = defaultPath, silent = false }: Ins ); }; +const install: CommandModule, { path?: string; silent?: boolean }> = { + command: ['init', 'i', 'install'], + describe: 'Download and run the latest Logto release', + builder: (yargs) => + yargs.options({ + path: { + alias: 'p', + describe: 'Path of Logto, must be a non-existing path', + type: 'string', + }, + silent: { + alias: 's', + describe: 'Entering non-interactive mode', + type: 'boolean', + }, + }), + handler: async ({ path, silent }) => { + await installLogto({ path, silent }); + }, +}; + export default install; diff --git a/packages/cli/src/index.ts b/packages/cli/src/index.ts index 7ddb8b74a..4628e575f 100644 --- a/packages/cli/src/index.ts +++ b/packages/cli/src/index.ts @@ -1,28 +1,12 @@ import yargs from 'yargs'; import { hideBin } from 'yargs/helpers'; +import database from './commands/database'; import install from './commands/install'; void yargs(hideBin(process.argv)) - .command( - ['init', 'i', 'install'], - 'Download and run the latest Logto release', - { - path: { - alias: 'p', - describe: 'Path of Logto, must be a non-existing path', - type: 'string', - }, - silent: { - alias: 's', - describe: 'Entering non-interactive mode', - type: 'boolean', - }, - }, - async ({ path, silent }) => { - await install({ path, silent }); - } - ) + .command(install) + .command(database) .demandCommand(1) .showHelpOnFail(true) .strict() diff --git a/packages/cli/src/utilities.ts b/packages/cli/src/utilities.ts index f5e60060d..13d86abc4 100644 --- a/packages/cli/src/utilities.ts +++ b/packages/cli/src/utilities.ts @@ -1,10 +1,16 @@ import { execSync } from 'child_process'; import { createWriteStream } from 'fs'; +import { readFile } from 'fs/promises'; +import os from 'os'; +import path from 'path'; import chalk from 'chalk'; +import findUp from 'find-up'; import got, { Progress } from 'got'; import { HttpsProxyAgent } from 'hpagent'; import ora from 'ora'; +// eslint-disable-next-line id-length +import z from 'zod'; export const safeExecSync = (command: string) => { try { @@ -68,3 +74,31 @@ export const downloadFile = async (url: string, destination: string) => { }); }); }; + +// Intended +// eslint-disable-next-line @typescript-eslint/no-empty-function +export const noop = () => {}; + +// Logto config +const logtoConfig = '.logto.json'; + +const getConfigJson = async () => { + const configPath = (await findUp(logtoConfig)) ?? path.join(os.homedir(), logtoConfig); + + try { + const raw = await readFile(configPath, 'utf8'); + + // Prefer `unknown` over the original return type `any`, will guard later + // eslint-disable-next-line no-restricted-syntax + return JSON.parse(raw) as unknown; + } catch {} +}; + +export const getConfig = async () => { + return z + .object({ + databaseUrl: z.string().optional(), + }) + .default({}) + .parse(await getConfigJson()); +}; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 79e6f73c7..99e6ae017 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -30,6 +30,7 @@ importers: '@types/yargs': ^17.0.13 chalk: ^4.1.2 eslint: ^8.21.0 + find-up: ^5.0.0 got: ^11.8.2 hpagent: ^1.0.0 inquirer: ^8.2.2 @@ -42,8 +43,10 @@ importers: ts-node: ^10.9.1 typescript: ^4.7.4 yargs: ^17.6.0 + zod: ^3.18.0 dependencies: chalk: 4.1.2 + find-up: 5.0.0 got: 11.8.3 hpagent: 1.0.0 inquirer: 8.2.2 @@ -51,6 +54,7 @@ importers: semver: 7.3.7 tar: 6.1.11 yargs: 17.6.0 + zod: 3.18.0 devDependencies: '@silverhand/eslint-config': 1.0.0_swk2g7ygmfleszo5c33j4vooni '@silverhand/ts-config': 1.0.0_typescript@4.7.4 @@ -7493,7 +7497,6 @@ packages: dependencies: locate-path: 6.0.0 path-exists: 4.0.0 - dev: true /flat-cache/3.0.4: resolution: {integrity: sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==} @@ -10290,7 +10293,6 @@ packages: engines: {node: '>=10'} dependencies: p-locate: 5.0.0 - dev: true /lodash._reinterpolate/3.0.0: resolution: {integrity: sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=} @@ -11920,7 +11922,6 @@ packages: engines: {node: '>=10'} dependencies: yocto-queue: 0.1.0 - dev: true /p-locate/2.0.0: resolution: {integrity: sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==} @@ -11941,7 +11942,6 @@ packages: engines: {node: '>=10'} dependencies: p-limit: 3.1.0 - dev: true /p-map-series/2.1.0: resolution: {integrity: sha512-RpYIIK1zXSNEOdwxcfe7FdvGcs7+y5n8rifMhMNWvaxRNMPINJHF5GDeuVxWqnfrcHPSCnp7Oo5yNXHId9Av2Q==} @@ -12205,7 +12205,6 @@ packages: /path-exists/4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} - dev: true /path-is-absolute/1.0.1: resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} @@ -15764,7 +15763,6 @@ packages: /yocto-queue/0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} - dev: true /zod/3.18.0: resolution: {integrity: sha512-gwTm8RfUCe8l9rDwN5r2A17DkAa8Ez4Yl4yXqc5VqeGaXaJahzYYXbTwvhroZi0SNBqTwh/bKm2N0mpCzuw4bA==}