From ff5f04f4c708fdc27fb6b7a53f7aa9853c602f21 Mon Sep 17 00:00:00 2001 From: YaroShkvorets Date: Mon, 30 Dec 2024 18:53:20 -0500 Subject: [PATCH 1/3] properly handle ESC and Ctrl-C on prompts --- packages/cli/src/commands/add.ts | 78 ++++++++++++++------------- packages/cli/src/commands/auth.ts | 26 ++++----- packages/cli/src/commands/deploy.ts | 44 ++++++++------- packages/cli/src/commands/init.ts | 80 ++++++++++++++++------------ packages/cli/src/commands/publish.ts | 20 +++---- 5 files changed, 136 insertions(+), 112 deletions(-) diff --git a/packages/cli/src/commands/add.ts b/packages/cli/src/commands/add.ts index 63a604025..776280be4 100644 --- a/packages/cli/src/commands/add.ts +++ b/packages/cli/src/commands/add.ts @@ -103,21 +103,23 @@ export default class AddCommand extends Command { } catch (error) { // we cannot ask user to do prompt in test environment if (process.env.NODE_ENV !== 'test') { - const { abi: abiFile } = await prompt.ask<{ abi: string }>([ - { - type: 'input', - name: 'abi', - message: 'ABI file (path)', - validate: async (value: string) => { - try { - EthereumABI.load(contractName, value); - return true; - } catch (e) { - return `Failed to load ABI from ${value}: ${e.message}`; - } + const { abi: abiFile } = await prompt + .ask<{ abi: string }>([ + { + type: 'input', + name: 'abi', + message: 'ABI file (path)', + validate: async (value: string) => { + try { + EthereumABI.load(contractName, value); + return true; + } catch (e) { + return `Failed to load ABI from ${value}: ${e.message}`; + } + }, }, - }, - ]); + ]) + .catch(() => this.exit(1)); // properly handle ESC ethabi = EthereumABI.load(contractName, abiFile); } } @@ -130,18 +132,20 @@ export default class AddCommand extends Command { // we cannot ask user to do prompt in test environment if (process.env.NODE_ENV !== 'test') { // If we can't get the start block, we'll just leave it out of the manifest - const { startBlock: userInputStartBlock } = await prompt.ask<{ startBlock: string }>([ - { - type: 'input', - name: 'startBlock', - message: 'Start Block', - initial: '0', - validate: value => parseInt(value) >= 0, - result(value) { - return value; + const { startBlock: userInputStartBlock } = await prompt + .ask<{ startBlock: string }>([ + { + type: 'input', + name: 'startBlock', + message: 'Start Block', + initial: '0', + validate: value => parseInt(value) >= 0, + result(value) { + return value; + }, }, - }, - ]); + ]) + .catch(() => this.exit(1)); startBlock = userInputStartBlock; } } @@ -155,18 +159,20 @@ export default class AddCommand extends Command { } catch (error) { // not asking user to do prompt in test environment if (process.env.NODE_ENV !== 'test') { - const { contractName: userInputContractName } = await prompt.ask<{ contractName: string }>([ - { - type: 'input', - name: 'contractName', - message: 'Contract Name', - initial: 'Contract', - validate: value => value && value.length > 0, - result(value) { - return value; + const { contractName: userInputContractName } = await prompt + .ask<{ contractName: string }>([ + { + type: 'input', + name: 'contractName', + message: 'Contract Name', + initial: 'Contract', + validate: value => value && value.length > 0, + result(value) { + return value; + }, }, - }, - ]); + ]) + .catch(() => this.exit(1)); contractName = userInputContractName; } } diff --git a/packages/cli/src/commands/auth.ts b/packages/cli/src/commands/auth.ts index a09a830ca..cc10520c5 100644 --- a/packages/cli/src/commands/auth.ts +++ b/packages/cli/src/commands/auth.ts @@ -28,18 +28,20 @@ export default class AuthCommand extends Command { const { node } = chooseNodeUrl({}); - const { deployKey } = await prompt.ask<{ deployKey: string }>([ - { - type: 'input', - name: 'deployKey', - message: () => 'What is your Subgraph Studio deploy key?', - required: true, - initial: initialDeployKey, - skip: this.validateStudioDeployKey(initialDeployKey), - validate: value => - this.validateStudioDeployKey(value) || `Invalid Subgraph Studio deploy key: ${value}`, - }, - ]); + const { deployKey } = await prompt + .ask<{ deployKey: string }>([ + { + type: 'input', + name: 'deployKey', + message: () => 'What is your Subgraph Studio deploy key?', + required: true, + initial: initialDeployKey, + skip: this.validateStudioDeployKey(initialDeployKey), + validate: value => + this.validateStudioDeployKey(value) || `Invalid Subgraph Studio deploy key: ${value}`, + }, + ]) + .catch(() => this.exit(1)); try { await saveDeployKey(node!, deployKey); diff --git a/packages/cli/src/commands/deploy.ts b/packages/cli/src/commands/deploy.ts index 91cd92147..599c80073 100644 --- a/packages/cli/src/commands/deploy.ts +++ b/packages/cli/src/commands/deploy.ts @@ -111,16 +111,18 @@ export default class DeployCommand extends Command { }, } = await this.parse(DeployCommand); - const { subgraphName } = await prompt.ask<{ subgraphName: string }>([ - { - type: 'input', - name: 'subgraphName', - message: () => 'What is the subgraph name?', - skip: () => !!subgraphNameArg, - initial: subgraphNameArg, - required: true, - }, - ]); + const { subgraphName } = await prompt + .ask<{ subgraphName: string }>([ + { + type: 'input', + name: 'subgraphName', + message: () => 'What is the subgraph name?', + skip: () => !!subgraphNameArg, + initial: subgraphNameArg, + required: true, + }, + ]) + .catch(() => this.exit(1)); const { node } = chooseNodeUrl({ node: nodeFlag, @@ -153,16 +155,18 @@ export default class DeployCommand extends Command { } // Ask for label if not on hosted service - const { versionLabel } = await prompt.ask<{ versionLabel: string }>([ - { - type: 'input', - name: 'versionLabel', - message: () => 'Which version label to use? (e.g. "v0.0.1")', - initial: versionLabelFlag, - skip: () => !!versionLabelFlag, - required: true, - }, - ]); + const { versionLabel } = await prompt + .ask<{ versionLabel: string }>([ + { + type: 'input', + name: 'versionLabel', + message: () => 'Which version label to use? (e.g. "v0.0.1")', + initial: versionLabelFlag, + skip: () => !!versionLabelFlag, + required: true, + }, + ]) + .catch(() => this.exit(1)); const deploySubgraph = async (ipfsHash: string) => { const spinner = print.spin(`Deploying to Graph node ${requestUrl}`); diff --git a/packages/cli/src/commands/init.ts b/packages/cli/src/commands/init.ts index d9b9e020b..0a306bfc5 100644 --- a/packages/cli/src/commands/init.ts +++ b/packages/cli/src/commands/init.ts @@ -253,10 +253,12 @@ export default class InitCommand extends Command { } if (fromExample) { - const answers = await processFromExampleInitForm.bind(this)({ - subgraphName, - directory, - }); + const answers = await processFromExampleInitForm + .bind(this)({ + subgraphName, + directory, + }) + .catch(() => this.exit(1)); if (!answers) { this.exit(1); @@ -274,19 +276,21 @@ export default class InitCommand extends Command { ); } else { // Otherwise, take the user through the interactive form - const answers = await processInitForm.bind(this)({ - abi, - abiPath, - directory, - source: fromContract, - indexEvents, - fromExample, - subgraphName, - contractName, - startBlock, - spkgPath, - ipfsUrl: ipfs, - }); + const answers = await processInitForm + .bind(this)({ + abi, + abiPath, + directory, + source: fromContract, + indexEvents, + fromExample, + subgraphName, + contractName, + startBlock, + spkgPath, + ipfsUrl: ipfs, + }) + .catch(() => this.exit(1)); if (!answers) { this.exit(1); } @@ -966,12 +970,13 @@ async function initSubgraphFromExample( }; }, ) { - let overwrite = false; if (filesystem.exists(directory)) { - overwrite = await prompt.confirm( - 'Directory already exists, do you want to initialize the subgraph here (files will be overwritten) ?', - false, - ); + const overwrite = await prompt + .confirm( + 'Directory already exists, do you want to initialize the subgraph here (files will be overwritten) ?', + false, + ) + .catch(() => false); if (!overwrite) { this.exit(1); @@ -1005,7 +1010,7 @@ async function initSubgraphFromExample( return { result: false, error: `Example not found: ${fromExample}` }; } - filesystem.copy(exampleSubgraphPath, directory, { overwrite }); + filesystem.copy(exampleSubgraphPath, directory, { overwrite: true }); return true; } finally { filesystem.remove(tmpDir); @@ -1129,14 +1134,17 @@ async function initSubgraphFromContract( }, ) { const isComposedSubgraph = protocolInstance.isComposedSubgraph(); - if ( - filesystem.exists(directory) && - !(await prompt.confirm( - 'Directory already exists, do you want to initialize the subgraph here (files will be overwritten) ?', - false, - )) - ) { - this.exit(1); + if (filesystem.exists(directory)) { + const overwrite = await prompt + .confirm( + 'Directory already exists, do you want to initialize the subgraph here (files will be overwritten) ?', + false, + ) + .catch(() => false); + + if (!overwrite) { + this.exit(1); + } } let entities: string[] | undefined; @@ -1232,10 +1240,12 @@ async function initSubgraphFromContract( } while (addContract) { - addContract = await addAnotherContract.bind(this)({ - protocolInstance, - directory, - }); + addContract = await addAnotherContract + .bind(this)({ + protocolInstance, + directory, + }) + .catch(() => false); } } diff --git a/packages/cli/src/commands/publish.ts b/packages/cli/src/commands/publish.ts index 0eb6e509d..aadc7b6ea 100644 --- a/packages/cli/src/commands/publish.ts +++ b/packages/cli/src/commands/publish.ts @@ -67,15 +67,17 @@ export default class PublishCommand extends Command { protocolNetwork: string | undefined; apiKey: string | undefined; }) { - const { openBrowser } = await prompt.ask<{ openBrowser: boolean }>([ - { - type: 'confirm', - name: 'openBrowser', - message: () => `Open up the browser to continue publishing ?`, - initial: true, - required: true, - }, - ]); + const { openBrowser } = await prompt + .ask<{ openBrowser: boolean }>([ + { + type: 'confirm', + name: 'openBrowser', + message: () => `Open up the browser to continue publishing ?`, + initial: true, + required: true, + }, + ]) + .catch(() => this.exit(1)); if (!openBrowser) { this.exit(0); From dec8e07d07a960dc210c9aa61c8eec40d3f2338c Mon Sep 17 00:00:00 2001 From: YaroShkvorets Date: Mon, 30 Dec 2024 18:54:56 -0500 Subject: [PATCH 2/3] changeset --- .changeset/ninety-laws-exercise.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/ninety-laws-exercise.md diff --git a/.changeset/ninety-laws-exercise.md b/.changeset/ninety-laws-exercise.md new file mode 100644 index 000000000..35b513f5a --- /dev/null +++ b/.changeset/ninety-laws-exercise.md @@ -0,0 +1,5 @@ +--- +'@graphprotocol/graph-cli': patch +--- + +fix confusing "no error" message when pressing Escape on prompts From 5349d1f07a9d1cd1fedb70c87ca94e90eeb63174 Mon Sep 17 00:00:00 2001 From: YaroShkvorets Date: Mon, 30 Dec 2024 19:13:26 -0500 Subject: [PATCH 3/3] remove unneeded catch --- packages/cli/src/commands/init.ts | 38 ++++++++++++++----------------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/packages/cli/src/commands/init.ts b/packages/cli/src/commands/init.ts index 0a306bfc5..f50927eb6 100644 --- a/packages/cli/src/commands/init.ts +++ b/packages/cli/src/commands/init.ts @@ -253,12 +253,10 @@ export default class InitCommand extends Command { } if (fromExample) { - const answers = await processFromExampleInitForm - .bind(this)({ - subgraphName, - directory, - }) - .catch(() => this.exit(1)); + const answers = await processFromExampleInitForm.bind(this)({ + subgraphName, + directory, + }); if (!answers) { this.exit(1); @@ -276,21 +274,19 @@ export default class InitCommand extends Command { ); } else { // Otherwise, take the user through the interactive form - const answers = await processInitForm - .bind(this)({ - abi, - abiPath, - directory, - source: fromContract, - indexEvents, - fromExample, - subgraphName, - contractName, - startBlock, - spkgPath, - ipfsUrl: ipfs, - }) - .catch(() => this.exit(1)); + const answers = await processInitForm.bind(this)({ + abi, + abiPath, + directory, + source: fromContract, + indexEvents, + fromExample, + subgraphName, + contractName, + startBlock, + spkgPath, + ipfsUrl: ipfs, + }); if (!answers) { this.exit(1); }