From cac833e83e6250aea0295487c6bf67b0c7a66bfa Mon Sep 17 00:00:00 2001 From: HugoRCD Date: Sun, 31 Mar 2024 13:56:53 +0200 Subject: [PATCH] feat: auto-suggest and execute command on error --- apps/cli/src/commands/create.ts | 20 ++++------- apps/cli/src/commands/link.ts | 7 +++- apps/cli/src/commands/open.ts | 14 +++++--- apps/cli/src/commands/pull.ts | 12 +++++-- apps/cli/src/commands/push.ts | 12 +++++-- apps/cli/src/utils/connection.ts | 8 +++-- apps/cli/src/utils/projects.ts | 24 ++++++++++---- apps/cli/src/utils/suggest.ts | 57 ++++++++++++++++++++++++++++++++ 8 files changed, 121 insertions(+), 33 deletions(-) create mode 100644 apps/cli/src/utils/suggest.ts diff --git a/apps/cli/src/commands/create.ts b/apps/cli/src/commands/create.ts index 37cac3f1..72eeb2ce 100644 --- a/apps/cli/src/commands/create.ts +++ b/apps/cli/src/commands/create.ts @@ -1,7 +1,7 @@ -import { defineCommand, runCommand } from 'citty' +import { defineCommand } from 'citty' import consola from 'consola' import { createProject } from '../utils/projects.ts' -import link from './link.ts' +import { suggestLinkProject } from '../utils/suggest.ts' export default defineCommand({ meta: { @@ -21,19 +21,13 @@ export default defineCommand({ const name = ctx.args.name consola.start(`Creating project ${ name }...`) try { - await createProject(name) + let project = await createProject(name) consola.success(`Project ${ name } created successfully!`) - const linkProject = await consola.prompt('Do you want to link the project? (y/n)', { - default: 'y', - type: 'confirm', - }) - if (linkProject) { - await runCommand(link, { rawArgs: [name] }).then(() => { - consola.success('Project linked successfully!') - }).catch(() => { - consola.error('Failed to link the project') - }) + const linkedProject = await suggestLinkProject(name) + if (linkedProject) { + project = linkedProject } + return project } catch (e) { consola.error('Failed to create project') } diff --git a/apps/cli/src/commands/link.ts b/apps/cli/src/commands/link.ts index 84c445c5..956ded8c 100644 --- a/apps/cli/src/commands/link.ts +++ b/apps/cli/src/commands/link.ts @@ -1,6 +1,8 @@ -import { defineCommand } from 'citty' +import { defineCommand, runCommand } from 'citty' import { consola } from 'consola' import { getProjectByName, getProjects, writeProjectConfig } from '../utils/projects.ts' +import { suggestCreateProject } from '../utils/suggest.ts' +import create from './create.ts' export default defineCommand({ meta: { @@ -23,6 +25,7 @@ export default defineCommand({ const project = await getProjectByName(name) if (!project) { consola.error(`Project with name ${name} not found`) + await suggestCreateProject(name) return } writeProjectConfig(project) @@ -33,6 +36,7 @@ export default defineCommand({ const projects = await getProjects() if (!projects.length) { consola.error('No projects found') + await suggestCreateProject(name) return } @@ -53,6 +57,7 @@ export default defineCommand({ writeProjectConfig(project) consola.success('Project linked successfully') + return project } catch (e) { consola.error('An error occurred while selecting the project') } diff --git a/apps/cli/src/commands/open.ts b/apps/cli/src/commands/open.ts index 776db998..63d633b9 100644 --- a/apps/cli/src/commands/open.ts +++ b/apps/cli/src/commands/open.ts @@ -2,18 +2,24 @@ import { defineCommand } from 'citty' import { consola } from 'consola' import open from 'open' import { getProjectId } from '../utils/projects.ts' +import { suggestLinkProjects } from '../utils/suggest.ts' export default defineCommand({ meta: { name: 'open', description: 'Open the project in the browser', }, - setup() { + async setup() { consola.info('Opening the project in the browser...') - const projectId = getProjectId() + let projectId = getProjectId() if (!projectId) { - consola.error('No project linked run `shelve link` to link a project') - return + consola.error('The current project is not linked to a remote project') + const linkedProject = await suggestLinkProjects() + if (linkedProject) { + projectId = linkedProject.id + } else { + return + } } open(`https://shelve.hrcd.fr/app/project/${ projectId }`).then(r => r) }, diff --git a/apps/cli/src/commands/pull.ts b/apps/cli/src/commands/pull.ts index a4a9096c..02c50578 100644 --- a/apps/cli/src/commands/pull.ts +++ b/apps/cli/src/commands/pull.ts @@ -2,6 +2,7 @@ import { defineCommand } from 'citty' import consola from 'consola' import { createEnvFile, getProjectVariable } from '../utils/env.ts' import { getProjectId } from '../utils/projects.ts' +import { suggestLinkProjects } from '../utils/suggest.ts' export default defineCommand({ meta: { @@ -18,10 +19,15 @@ export default defineCommand({ }, }, async run(ctx) { - const projectId = getProjectId() + let projectId = getProjectId() if (!projectId) { - consola.error('Project is not linked run `shelve link` to link the project') - return + consola.error('The current project is not linked to a remote project') + const linkedProject = await suggestLinkProjects() + if (linkedProject) { + projectId = linkedProject.id + } else { + return + } } const variables = await getProjectVariable(projectId, ctx.args.env) createEnvFile(variables) diff --git a/apps/cli/src/commands/push.ts b/apps/cli/src/commands/push.ts index 0336723d..6bb68464 100644 --- a/apps/cli/src/commands/push.ts +++ b/apps/cli/src/commands/push.ts @@ -2,6 +2,7 @@ import { defineCommand } from 'citty' import consola from 'consola' import { pushProjectVariable } from '../utils/env.ts' import { getProjectId } from '../utils/projects.ts' +import { suggestLinkProjects } from '../utils/suggest.ts' export default defineCommand({ meta: { @@ -18,10 +19,15 @@ export default defineCommand({ }, }, async run(ctx) { - const projectId = getProjectId() + let projectId = getProjectId() if (!projectId) { - consola.error('Project is not linked run `shelve link` to link the project') - return + consola.error('The current project is not linked to a remote project') + const linkedProject = await suggestLinkProjects() + if (linkedProject) { + projectId = linkedProject.id + } else { + return + } } await pushProjectVariable(projectId, ctx.args.env) consola.success('Pushed successfully!') diff --git a/apps/cli/src/utils/connection.ts b/apps/cli/src/utils/connection.ts index 775e0d2b..ceac84b8 100644 --- a/apps/cli/src/utils/connection.ts +++ b/apps/cli/src/utils/connection.ts @@ -1,6 +1,7 @@ import { ofetch } from 'ofetch' import consola from 'consola' import { loadUserConfig, writeUserConfig } from './config.ts' +import { suggestLogin } from './suggest.ts' const SHELVE_API_URL = process.env.NODE_ENV === 'development' ? 'http://localhost:3000/api' : 'https://shelve.hrcd.fr/api' @@ -12,10 +13,11 @@ export const $api: any = ofetch.create({ Cookie: `authToken=${loadUserConfig().authToken || ''}` } }, - onResponseError(ctx) { + async onResponseError(ctx) { if (ctx.response.status === 401) { - writeUserConfig({ ...loadUserConfig(), authToken: null }) - consola.error('Authentication failed, please login again using `shelve login`') + writeUserConfig({...loadUserConfig(), authToken: null}) + consola.error('Authentication failed') + await suggestLogin().then(r => r) } } }) diff --git a/apps/cli/src/utils/projects.ts b/apps/cli/src/utils/projects.ts index 02ab587e..6bf4f7c3 100644 --- a/apps/cli/src/utils/projects.ts +++ b/apps/cli/src/utils/projects.ts @@ -2,6 +2,7 @@ import fs from 'fs' import type { Project } from '@shelve/types' import consola from 'consola' import { $api } from './connection.ts' +import { suggestLinkProject } from './suggest.ts' export async function getProjects(): Promise { return await $api('/project', { @@ -79,11 +80,22 @@ export function addDotShelveToGitignore(): void { } } -export async function createProject(name: string): Promise { - return await $api('/project', { - method: 'POST', - body: { - name, +export async function createProject(name: string): Promise { + try { + let project = await $api('/project', { + method: 'POST', + body: { + name, + } + }) + consola.success(`Project ${ name } created successfully!`) + const linkedProject = await suggestLinkProject(name) + if (linkedProject) { + project = linkedProject } - }) + return project + } catch (e) { + consola.error('Failed to create project') + return null + } } diff --git a/apps/cli/src/utils/suggest.ts b/apps/cli/src/utils/suggest.ts new file mode 100644 index 00000000..e8175af0 --- /dev/null +++ b/apps/cli/src/utils/suggest.ts @@ -0,0 +1,57 @@ +import consola from 'consola' +import { runCommand } from 'citty' +import type { Project } from '@shelve/types' +import link from '../commands/link.ts' +import login from '../commands/login.ts' +import { createProject } from './projects.ts' + +export async function suggestCreateProject(name?: string): Promise { + const accept = await consola.prompt('Do you want to create a project? (y/n)', { + default: 'y', + type: 'confirm', + }) + if (accept) { + if (name) { + return await createProject(name) + } + const projectName = await consola.prompt('Give your project a name', { + placeholder: 'my-project' + }) + return await createProject(projectName) + } + return null +} + +export async function suggestLinkProject(name: string): Promise { + const linkProject = await consola.prompt('Do you want to link the project? (y/n)', { + default: 'y', + type: 'confirm', + }) + if (linkProject) { + const res = await runCommand(link, {rawArgs: ['--name', name]}) as { result: Project } + return res.result + } + return null +} + +export async function suggestLinkProjects(): Promise { + const linkProject = await consola.prompt('Do you want to link a project? (y/n)', { + default: 'y', + type: 'confirm', + }) + if (linkProject) { + const res = await runCommand(link, {rawArgs: []}) as { result: Project } + return res.result + } + return null +} + +export async function suggestLogin(): Promise { + const accept = await consola.prompt('Do you want to login? (y/n)', { + default: 'y', + type: 'confirm', + }) + if (accept) { + await runCommand(login, {rawArgs: []}) + } +}