From 47e238b01a9ba6456960e285a7a748c47b054c17 Mon Sep 17 00:00:00 2001 From: Allison Kemmerle Date: Wed, 22 Jan 2025 12:33:53 -0500 Subject: [PATCH 01/15] Add error messages for default account override --- bin/cli.js | 26 +++++++++++++++++++++++++- lang/en.lyaml | 3 +++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/bin/cli.js b/bin/cli.js index 017485619..c95071986 100755 --- a/bin/cli.js +++ b/bin/cli.js @@ -13,6 +13,10 @@ const { getConfigPath, validateConfig, } = require('@hubspot/local-dev-lib/config'); +const { + DEFAULT_ACCOUNT_OVERRIDE_ERROR_INVALID_ID, + DEFAULT_ACCOUNT_OVERRIDE_ERROR_ACCOUNT_NOT_FOUND, +} = require('@hubspot/local-dev-lib/constants/config'); const { logError } = require('../lib/errorHandlers/index'); const { setLogLevel, getCommandName } = require('../lib/commonOpts'); const { validateAccount } = require('../lib/validation'); @@ -202,7 +206,27 @@ const injectAccountIdMiddleware = async options => { if (options.useEnv && process.env.HUBSPOT_ACCOUNT_ID) { options.derivedAccountId = parseInt(process.env.HUBSPOT_ACCOUNT_ID, 10); } else { - options.derivedAccountId = getAccountId(account); + try { + options.derivedAccountId = getAccountId(account); + } catch (error) { + logger.error(error.message || error); + if (error.cause === DEFAULT_ACCOUNT_OVERRIDE_ERROR_INVALID_ID) { + logger.log( + i18n(`${i18nKey}.injectAccountIdMiddleware.invalidAccountId`, { + overrideCommand: uiCommandReference('hs accounts create-override'), + }) + ); + } + if (error.cause === DEFAULT_ACCOUNT_OVERRIDE_ERROR_ACCOUNT_NOT_FOUND) { + logger.log( + i18n(`${i18nKey}.injectAccountIdMiddleware.accountNotFound`, { + configPath: getConfigPath(), + authCommand: uiCommandReference('hs accounts auth'), + }) + ); + } + process.exit(EXIT_CODES.ERROR); + } } }; diff --git a/lang/en.lyaml b/lang/en.lyaml index fd4f17732..cc26408d5 100644 --- a/lang/en.lyaml +++ b/lang/en.lyaml @@ -11,6 +11,9 @@ en: portalEnvVarDeprecated: "The HUBSPOT_PORTAL_ID environment variable is deprecated. Please use HUBSPOT_ACCOUNT_ID instead." loadConfigMiddleware: configFileExists: "A configuration file already exists at {{ configPath }}. To specify a new configuration file, delete the existing one and try again." + injectAccountIdMiddleware: + invalidAccountId: "In the default override file (.hs-account), the account ID must be a number. Please delete the current file and generate a new one using {{ overrideCommand }}." + accountNotFound: "The account in the default override file (.hs-account) was not found in the centralized config file at {{ configPath }}. You can authorize this account using {{ authCommand }}." completion: describe: "Enable bash completion shortcuts for commands. Concat the generated script to your .bashrc, .bash_profile, or .zshrc file." examples: From 038a074018897c3992fce5bfd972970efc98f745 Mon Sep 17 00:00:00 2001 From: Allison Kemmerle Date: Wed, 22 Jan 2025 14:32:54 -0500 Subject: [PATCH 02/15] Add support for create-override command --- commands/account.ts | 2 ++ commands/account/createOverride.ts | 58 ++++++++++++++++++++++++++++++ commands/account/list.ts | 5 +++ lang/en.lyaml | 10 ++++++ 4 files changed, 75 insertions(+) create mode 100644 commands/account/createOverride.ts diff --git a/commands/account.ts b/commands/account.ts index 42f9685ce..d29406aa4 100644 --- a/commands/account.ts +++ b/commands/account.ts @@ -7,6 +7,7 @@ const use = require('./account/use'); const info = require('./account/info'); const remove = require('./account/remove'); const clean = require('./account/clean'); +const createOverride = require('./account/createOverride'); const i18nKey = 'commands.account'; @@ -23,6 +24,7 @@ exports.builder = yargs => { .command(info) .command(remove) .command(clean) + .command(createOverride) .demandCommand(1, ''); return yargs; diff --git a/commands/account/createOverride.ts b/commands/account/createOverride.ts new file mode 100644 index 000000000..4f152d19d --- /dev/null +++ b/commands/account/createOverride.ts @@ -0,0 +1,58 @@ +// @ts-nocheck +const fs = require('fs-extra'); +const path = require('path'); +const { getCwd } = require('@hubspot/local-dev-lib/path'); +const { logger } = require('@hubspot/local-dev-lib/logger'); +const { + getConfigPath, + getAccountId, +} = require('@hubspot/local-dev-lib/config'); +const { addConfigOptions } = require('../../lib/commonOpts'); +const { i18n } = require('../../lib/lang'); +import { EXIT_CODES } from '../../lib/enums/exitCodes'; +const { selectAccountFromConfig } = require('../../lib/prompts/accountsPrompt'); + +const i18nKey = 'commands.account.subcommands.createOverride'; +exports.describe = null; // i18n(`${i18nKey}.describe`); + +exports.command = 'create-override [account]'; + +exports.handler = async options => { + let overrideDefaultAccount = options.account; + + if (!overrideDefaultAccount) { + overrideDefaultAccount = await selectAccountFromConfig(); + } else if (!getAccountId(overrideDefaultAccount)) { + logger.error( + i18n(`${i18nKey}.errors.accountNotFound`, { + specifiedAccount: overrideDefaultAccount, + configPath: getConfigPath(), + }) + ); + overrideDefaultAccount = await selectAccountFromConfig(); + } + const accountId = getAccountId(overrideDefaultAccount); + + try { + const overrideFilePath = path.join(getCwd(), '.hs-account'); + await fs.writeFile(overrideFilePath, accountId.toString(), 'utf8'); + logger.success(i18n(`${i18nKey}.success`, { overrideFilePath })); + } catch (e) { + logger.error(i18n(`${i18nKey}.errors.writeFile`, { error: e.message })); + process.exit(EXIT_CODES.ERROR); + } +}; + +exports.builder = yargs => { + addConfigOptions(yargs); + + yargs.example([ + ['$0 accounts create-override', i18n(`${i18nKey}.examples.default`)], + [ + '$0 accounts create-override 12345678', + i18n(`${i18nKey}.examples.withAccountId`), + ], + ]); + + return yargs; +}; diff --git a/commands/account/list.ts b/commands/account/list.ts index d2a6cd4ec..335a0619f 100644 --- a/commands/account/list.ts +++ b/commands/account/list.ts @@ -4,6 +4,7 @@ const { getConfigPath, getConfigDefaultAccount, getConfigAccounts, + getDefaultAccountOverrideFilePath, } = require('@hubspot/local-dev-lib/config'); const { getAccountIdentifier, @@ -85,6 +86,7 @@ exports.handler = async options => { trackCommandUsage('accounts-list', null, derivedAccountId); const configPath = getConfigPath(); + const overrideFilePath = getDefaultAccountOverrideFilePath(); const accountsList = getConfigAccounts(); const mappedPortalData = sortAndMapPortals(accountsList); const portalData = getPortalData(mappedPortalData); @@ -97,6 +99,9 @@ exports.handler = async options => { ); logger.log(i18n(`${i18nKey}.configPath`, { configPath })); + if (overrideFilePath) { + logger.log(i18n(`${i18nKey}.overrideFilePath`, { overrideFilePath })); + } logger.log( i18n(`${i18nKey}.defaultAccount`, { account: getConfigDefaultAccount(), diff --git a/lang/en.lyaml b/lang/en.lyaml index cc26408d5..56ce99742 100644 --- a/lang/en.lyaml +++ b/lang/en.lyaml @@ -21,11 +21,21 @@ en: account: describe: "Commands for managing configured accounts." subcommands: + createOverride: + describe: "Create a new default account override file (.hs-account) in the current working directory." + success: "Default account override file created at {{ overrideFilePath }}" + errors: + writeFile: "Unable to create the default account override file: {{ error }}" + accountNotFound: "The account \"{{ specifiedAccount }}\" could not be found in {{ configPath }}" + examples: + default: "Create a new default account override file (.hs-account) in the current working directory" + withAccountId: "Create a new default account override file (.hs-account) in the current working directory, using the account with accountId \"1234567\"" list: accounts: "{{#bold}}Accounts{{/bold}}:" defaultAccount: "{{#bold}}Default account{{/bold}}: {{ account }}" describe: "List names of accounts defined in config." configPath: "{{#bold}}Config path{{/bold}}: {{ configPath }}" + overrideFilePath: "{{#bold}}Default account override file path{{/bold}}: {{ overrideFilePath }}" labels: accountId: "Account ID" authType: "Auth Type" From 417ec76321953c746ee1ab8fd391a3e310ef9f7d Mon Sep 17 00:00:00 2001 From: Allison Kemmerle Date: Wed, 22 Jan 2025 14:36:57 -0500 Subject: [PATCH 03/15] Refactor create-override examples --- commands/account/createOverride.ts | 6 +++++- lang/en.lyaml | 3 ++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/commands/account/createOverride.ts b/commands/account/createOverride.ts index 4f152d19d..81a440b36 100644 --- a/commands/account/createOverride.ts +++ b/commands/account/createOverride.ts @@ -50,7 +50,11 @@ exports.builder = yargs => { ['$0 accounts create-override', i18n(`${i18nKey}.examples.default`)], [ '$0 accounts create-override 12345678', - i18n(`${i18nKey}.examples.withAccountId`), + i18n(`${i18nKey}.examples.idBased`), + ], + [ + '$0 accounts create-override MyAccount', + i18n(`${i18nKey}.examples.nameBased`), ], ]); diff --git a/lang/en.lyaml b/lang/en.lyaml index 56ce99742..9e983e5f7 100644 --- a/lang/en.lyaml +++ b/lang/en.lyaml @@ -29,7 +29,8 @@ en: accountNotFound: "The account \"{{ specifiedAccount }}\" could not be found in {{ configPath }}" examples: default: "Create a new default account override file (.hs-account) in the current working directory" - withAccountId: "Create a new default account override file (.hs-account) in the current working directory, using the account with accountId \"1234567\"" + idBased: "Create a new default account override file (.hs-account) in the current working directory, using the account with accountId \"1234567\"" + nameBased: "Create a new default account override file (.hs-account) in the current working directory, using the account with name \"MyAccount\"" list: accounts: "{{#bold}}Accounts{{/bold}}:" defaultAccount: "{{#bold}}Default account{{/bold}}: {{ account }}" From 76443f4aa36443d3e3c32dc45a69e2dfbec0f117 Mon Sep 17 00:00:00 2001 From: Allison Kemmerle Date: Wed, 22 Jan 2025 14:49:24 -0500 Subject: [PATCH 04/15] Fix tests p1 --- commands/__tests__/accounts.test.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/commands/__tests__/accounts.test.ts b/commands/__tests__/accounts.test.ts index 8ea0f6bc6..c3652498d 100644 --- a/commands/__tests__/accounts.test.ts +++ b/commands/__tests__/accounts.test.ts @@ -6,6 +6,7 @@ import use from '../account/use'; import info from '../account/info'; import remove from '../account/remove'; import clean from '../account/clean'; +import createOverride from '../account/createOverride'; jest.mock('yargs'); jest.mock('../account/list'); @@ -14,6 +15,7 @@ jest.mock('../account/use'); jest.mock('../account/info'); jest.mock('../account/remove'); jest.mock('../account/clean'); +jest.mock('../account/createOverride'); jest.mock('../../lib/commonOpts'); yargs.command.mockReturnValue(yargs); yargs.demandCommand.mockReturnValue(yargs); @@ -42,6 +44,7 @@ describe('commands/account', () => { ['info', info], ['remove', remove], ['clean', clean], + ['create-override', createOverride], ]; it('should demand the command takes one positional argument', () => { From 3dcae85e503725c08bc069ddcf121ec5ffd6da25 Mon Sep 17 00:00:00 2001 From: Allison Kemmerle Date: Thu, 23 Jan 2025 10:27:55 -0500 Subject: [PATCH 05/15] Convert create-override to TS --- commands/__tests__/accounts.test.ts | 4 +- commands/account/createOverride.ts | 65 +++++++++++++++++------------ lang/en.lyaml | 2 +- types/Yargs.ts | 17 ++++++++ 4 files changed, 59 insertions(+), 29 deletions(-) create mode 100644 types/Yargs.ts diff --git a/commands/__tests__/accounts.test.ts b/commands/__tests__/accounts.test.ts index c3652498d..398b19cb7 100644 --- a/commands/__tests__/accounts.test.ts +++ b/commands/__tests__/accounts.test.ts @@ -6,7 +6,7 @@ import use from '../account/use'; import info from '../account/info'; import remove from '../account/remove'; import clean from '../account/clean'; -import createOverride from '../account/createOverride'; +import * as createOverride from '../account/createOverride'; jest.mock('yargs'); jest.mock('../account/list'); @@ -44,7 +44,7 @@ describe('commands/account', () => { ['info', info], ['remove', remove], ['clean', clean], - ['create-override', createOverride], + ['createOverride', createOverride], ]; it('should demand the command takes one positional argument', () => { diff --git a/commands/account/createOverride.ts b/commands/account/createOverride.ts index 81a440b36..a262b0f0b 100644 --- a/commands/account/createOverride.ts +++ b/commands/account/createOverride.ts @@ -1,32 +1,41 @@ -// @ts-nocheck -const fs = require('fs-extra'); -const path = require('path'); -const { getCwd } = require('@hubspot/local-dev-lib/path'); -const { logger } = require('@hubspot/local-dev-lib/logger'); -const { - getConfigPath, - getAccountId, -} = require('@hubspot/local-dev-lib/config'); -const { addConfigOptions } = require('../../lib/commonOpts'); -const { i18n } = require('../../lib/lang'); +import fs from 'fs-extra'; +import path from 'path'; +import { Argv, ArgumentsCamelCase } from 'yargs'; +import { getCwd } from '@hubspot/local-dev-lib/path'; +import { logger } from '@hubspot/local-dev-lib/logger'; +import { getConfigPath, getAccountId } from '@hubspot/local-dev-lib/config'; +import { addConfigOptions } from '../../lib/commonOpts'; +import { i18n } from '../../lib/lang'; import { EXIT_CODES } from '../../lib/enums/exitCodes'; -const { selectAccountFromConfig } = require('../../lib/prompts/accountsPrompt'); +import { selectAccountFromConfig } from '../../lib/prompts/accountsPrompt'; +import { CommonArgs, ConfigOptions } from '../../types/Yargs'; const i18nKey = 'commands.account.subcommands.createOverride'; -exports.describe = null; // i18n(`${i18nKey}.describe`); -exports.command = 'create-override [account]'; +export const describe = null; // i18n(`${i18nKey}.describe`); -exports.handler = async options => { - let overrideDefaultAccount = options.account; +export const command = 'create-override [account]'; + +type AccountInfoArgs = CommonArgs & + ConfigOptions & { + account?: string | number; + }; + +export async function handler( + args: ArgumentsCamelCase +): Promise { + let overrideDefaultAccount = args.account; if (!overrideDefaultAccount) { overrideDefaultAccount = await selectAccountFromConfig(); - } else if (!getAccountId(overrideDefaultAccount)) { + } else if ( + (typeof overrideDefaultAccount !== 'string' && + typeof overrideDefaultAccount !== 'number') || + !getAccountId(overrideDefaultAccount) + ) { logger.error( i18n(`${i18nKey}.errors.accountNotFound`, { - specifiedAccount: overrideDefaultAccount, - configPath: getConfigPath(), + configPath: getConfigPath() || '', }) ); overrideDefaultAccount = await selectAccountFromConfig(); @@ -35,15 +44,19 @@ exports.handler = async options => { try { const overrideFilePath = path.join(getCwd(), '.hs-account'); - await fs.writeFile(overrideFilePath, accountId.toString(), 'utf8'); + await fs.writeFile(overrideFilePath, accountId!.toString(), 'utf8'); logger.success(i18n(`${i18nKey}.success`, { overrideFilePath })); - } catch (e) { - logger.error(i18n(`${i18nKey}.errors.writeFile`, { error: e.message })); + } catch (e: unknown) { + if (e instanceof Error) { + logger.error(i18n(`${i18nKey}.errors.writeFile`, { error: e.message })); + } else { + logger.error(i18n(`${i18nKey}.errors.writeFile`, { error: String(e) })); + } process.exit(EXIT_CODES.ERROR); } -}; +} -exports.builder = yargs => { +export function builder(yargs: Argv): Argv { addConfigOptions(yargs); yargs.example([ @@ -58,5 +71,5 @@ exports.builder = yargs => { ], ]); - return yargs; -}; + return yargs as Argv; +} diff --git a/lang/en.lyaml b/lang/en.lyaml index 9e983e5f7..4bf61e23a 100644 --- a/lang/en.lyaml +++ b/lang/en.lyaml @@ -26,7 +26,7 @@ en: success: "Default account override file created at {{ overrideFilePath }}" errors: writeFile: "Unable to create the default account override file: {{ error }}" - accountNotFound: "The account \"{{ specifiedAccount }}\" could not be found in {{ configPath }}" + accountNotFound: "The specified account could not be found in the config file {{ configPath }}" examples: default: "Create a new default account override file (.hs-account) in the current working directory" idBased: "Create a new default account override file (.hs-account) in the current working directory, using the account with accountId \"1234567\"" diff --git a/types/Yargs.ts b/types/Yargs.ts new file mode 100644 index 000000000..8df0172d1 --- /dev/null +++ b/types/Yargs.ts @@ -0,0 +1,17 @@ +import { Options } from 'yargs'; + +export type CommonArgs = { + derivedAccountId: number; + providedAccountId?: number; + d: boolean; + debug: boolean; +}; + +export type ConfigOptions = { + c?: string; + config?: string; +}; + +export type StringOptionType = Options & { + type: 'string'; +}; From ddc09845c43b886fba873d393a8e87545ffb6d96 Mon Sep 17 00:00:00 2001 From: Allison Kemmerle Date: Fri, 24 Jan 2025 13:51:43 -0500 Subject: [PATCH 06/15] Address feedback p1 --- commands/account/createOverride.ts | 6 +++++- lang/en.lyaml | 4 ++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/commands/account/createOverride.ts b/commands/account/createOverride.ts index e90c39618..1a306e9ec 100644 --- a/commands/account/createOverride.ts +++ b/commands/account/createOverride.ts @@ -3,6 +3,7 @@ import path from 'path'; import { Argv, ArgumentsCamelCase } from 'yargs'; import { getCwd } from '@hubspot/local-dev-lib/path'; import { logger } from '@hubspot/local-dev-lib/logger'; +import { DEFAULT_ACCOUNT_OVERRIDE_FILE_NAME } from '@hubspot/local-dev-lib/constants/config'; import { getConfigPath, getAccountId } from '@hubspot/local-dev-lib/config'; import { addConfigOptions } from '../../lib/commonOpts'; import { i18n } from '../../lib/lang'; @@ -43,7 +44,10 @@ export async function handler( const accountId = getAccountId(overrideDefaultAccount); try { - const overrideFilePath = path.join(getCwd(), '.hs-account'); + const overrideFilePath = path.join( + getCwd(), + DEFAULT_ACCOUNT_OVERRIDE_FILE_NAME + ); await fs.writeFile(overrideFilePath, accountId!.toString(), 'utf8'); logger.success(i18n(`${i18nKey}.success`, { overrideFilePath })); } catch (e: unknown) { diff --git a/lang/en.lyaml b/lang/en.lyaml index ddcb858a4..3579890ef 100644 --- a/lang/en.lyaml +++ b/lang/en.lyaml @@ -12,8 +12,8 @@ en: loadConfigMiddleware: configFileExists: "A configuration file already exists at {{ configPath }}. To specify a new configuration file, delete the existing one and try again." injectAccountIdMiddleware: - invalidAccountId: "In the default override file (.hs-account), the account ID must be a number. Please delete the current file and generate a new one using {{ overrideCommand }}." - accountNotFound: "The account in the default override file (.hs-account) was not found in the centralized config file at {{ configPath }}. You can authorize this account using {{ authCommand }}." + invalidAccountId: "In the default override file (.hsaccount), the account ID must be a number. Please delete the current file and generate a new one using {{ overrideCommand }}." + accountNotFound: "The account in the default override file (.hsaccount) wasn't found in your configured accounts. You can authorize this account using {{ authCommand }}." completion: describe: "Enable bash completion shortcuts for commands. Concat the generated script to your .bashrc, .bash_profile, or .zshrc file." examples: From 1a54e99c5df01461888928beeb34895c4de825f9 Mon Sep 17 00:00:00 2001 From: Allison Kemmerle Date: Fri, 24 Jan 2025 14:23:28 -0500 Subject: [PATCH 07/15] Add default account override to hs doctor --- lang/en.lyaml | 5 +++++ lib/doctor/Diagnosis.ts | 9 +++++++++ lib/doctor/DiagnosticInfoBuilder.ts | 7 ++++++- lib/doctor/Doctor.ts | 26 +++++++++++++++++++++++++- 4 files changed, 45 insertions(+), 2 deletions(-) diff --git a/lang/en.lyaml b/lang/en.lyaml index 3579890ef..ec3a55472 100644 --- a/lang/en.lyaml +++ b/lang/en.lyaml @@ -1525,6 +1525,9 @@ en: doctor: runningDiagnostics: "Running diagnostics..." diagnosticsComplete: "Diagnostics complete" + defaultAccountOverrideFileChecks: + overrideActive: "Default account override file active: {{ defaultAccountOverrideFile }}" + overrideAccountId: "Active account ID: {{ overrideAccountId }}" accountChecks: active: "Default account active" inactive: "Default account isn't active" @@ -1571,6 +1574,8 @@ en: defaultAccountSubHeader: "Default Account: {{accountDetails}}" noConfigFile: "CLI configuration not found" noConfigFileSecondary: "Run {{command}} and follow the prompts to create your CLI configuration file and connect it to your HubSpot account" + defaultAccountOverrideFile: + header: "Default account override file path:" projectConfig: header: "Project configuration" projectDirSubHeader: "Project dir: {{#bold}}{{ projectDir }}{{/bold}}" diff --git a/lib/doctor/Diagnosis.ts b/lib/doctor/Diagnosis.ts index 3196d8f6d..59bf2fbff 100644 --- a/lib/doctor/Diagnosis.ts +++ b/lib/doctor/Diagnosis.ts @@ -30,6 +30,7 @@ interface DiagnosisCategories { cli: DiagnosisCategory; project: DiagnosisCategory; cliConfig: DiagnosisCategory; + defaultAccountOverrideFile: DiagnosisCategory; } const i18nKey = `lib.doctor.diagnosis`; @@ -59,6 +60,10 @@ export class Diagnosis { header: i18n(`${i18nKey}.cliConfig.header`), sections: [], }, + defaultAccountOverrideFile: { + header: i18n(`${i18nKey}.defaultAccountOverrideFile.header`), + sections: [], + }, project: { header: i18n(`${i18nKey}.projectConfig.header`), subheaders: [ @@ -109,6 +114,10 @@ export class Diagnosis { this.diagnosis.cliConfig.sections.push(section); } + addDefaultAccountOverrideFileSection(section: Section): void { + this.diagnosis.defaultAccountOverrideFile.sections.push(section); + } + toString(): string { const output = []; for (const value of Object.values(this.diagnosis)) { diff --git a/lib/doctor/DiagnosticInfoBuilder.ts b/lib/doctor/DiagnosticInfoBuilder.ts index d63c05e89..06583a55f 100644 --- a/lib/doctor/DiagnosticInfoBuilder.ts +++ b/lib/doctor/DiagnosticInfoBuilder.ts @@ -10,7 +10,10 @@ import { AuthType, } from '@hubspot/local-dev-lib/types/Accounts'; import { Project } from '@hubspot/local-dev-lib/types/Project'; -import { getAccountId } from '@hubspot/local-dev-lib/config'; +import { + getAccountId, + getDefaultAccountOverrideFilePath, +} from '@hubspot/local-dev-lib/config'; import { getAccountConfig, getConfigPath } from '@hubspot/local-dev-lib/config'; import { getAccessToken } from '@hubspot/local-dev-lib/personalAccessKey'; import { walk } from '@hubspot/local-dev-lib/fs'; @@ -36,6 +39,7 @@ export interface DiagnosticInfo extends FilesInfo { path?: string; versions: { [hubspotCli]: string; node: string; npm: string | null }; config: string | null; + defaultAccountOverrideFile: string | null | undefined; project: { details?: Project; config?: ProjectConfig; @@ -110,6 +114,7 @@ export class DiagnosticInfoBuilder { arch, path: mainModule?.path, config: getConfigPath(), + defaultAccountOverrideFile: getDefaultAccountOverrideFilePath(), versions: { [hubspotCli]: pkg.version, node, diff --git a/lib/doctor/Doctor.ts b/lib/doctor/Doctor.ts index dea9bdbc3..5b8c7a6d4 100644 --- a/lib/doctor/Doctor.ts +++ b/lib/doctor/Doctor.ts @@ -1,5 +1,8 @@ import { logger } from '@hubspot/local-dev-lib/logger'; -import { getAccountId } from '@hubspot/local-dev-lib/config'; +import { + getAccountId, + getResolvedDefaultAccountForCWD, +} from '@hubspot/local-dev-lib/config'; import SpinniesManager from '../ui/SpinniesManager'; import { @@ -64,6 +67,7 @@ export class Doctor { await Promise.all([ ...this.performCliChecks(), ...this.performCliConfigChecks(), + ...this.performDefaultAccountOverrideFileChecks(), ...(this.projectConfig?.projectConfig ? this.performProjectChecks() : []), ]); @@ -112,6 +116,26 @@ export class Doctor { return [this.checkIfAccessTokenValid()]; } + private performDefaultAccountOverrideFileChecks(): Array> { + const localI18nKey = `${i18nKey}.defaultAccountOverrideFileChecks`; + if (this.diagnosticInfo?.defaultAccountOverrideFile) { + this.diagnosis?.addDefaultAccountOverrideFileSection({ + type: 'warning', + message: i18n(`${localI18nKey}.overrideActive`, { + defaultAccountOverrideFile: + this.diagnosticInfo.defaultAccountOverrideFile, + }), + }); + this.diagnosis?.addDefaultAccountOverrideFileSection({ + type: 'warning', + message: i18n(`${localI18nKey}.overrideAccountId`, { + overrideAccountId: getResolvedDefaultAccountForCWD(), + }), + }); + } + return []; + } + private async checkIfAccessTokenValid(): Promise { const localI18nKey = `${i18nKey}.accountChecks`; try { From db018c3656f12da5fd7e313025a56f6607ffc7cc Mon Sep 17 00:00:00 2001 From: Allison Kemmerle Date: Wed, 29 Jan 2025 11:49:42 -0500 Subject: [PATCH 08/15] Change variable name --- lib/doctor/Doctor.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/doctor/Doctor.ts b/lib/doctor/Doctor.ts index 5b8c7a6d4..388fbacd1 100644 --- a/lib/doctor/Doctor.ts +++ b/lib/doctor/Doctor.ts @@ -1,7 +1,7 @@ import { logger } from '@hubspot/local-dev-lib/logger'; import { getAccountId, - getResolvedDefaultAccountForCWD, + getCWDAccountOverride, } from '@hubspot/local-dev-lib/config'; import SpinniesManager from '../ui/SpinniesManager'; @@ -129,7 +129,7 @@ export class Doctor { this.diagnosis?.addDefaultAccountOverrideFileSection({ type: 'warning', message: i18n(`${localI18nKey}.overrideAccountId`, { - overrideAccountId: getResolvedDefaultAccountForCWD(), + overrideAccountId: getCWDAccountOverride(), }), }); } From 5b758d2e4b814cb8abc89bba8cb54cb3c25df7b1 Mon Sep 17 00:00:00 2001 From: Allison Kemmerle Date: Wed, 29 Jan 2025 12:26:49 -0500 Subject: [PATCH 09/15] Address feedback p2 --- bin/cli.js | 6 +++--- commands/account/createOverride.ts | 26 ++++++++++++-------------- lang/en.lyaml | 4 +++- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/bin/cli.js b/bin/cli.js index c95071986..409f1251b 100755 --- a/bin/cli.js +++ b/bin/cli.js @@ -209,11 +209,11 @@ const injectAccountIdMiddleware = async options => { try { options.derivedAccountId = getAccountId(account); } catch (error) { - logger.error(error.message || error); + logError(error); if (error.cause === DEFAULT_ACCOUNT_OVERRIDE_ERROR_INVALID_ID) { logger.log( i18n(`${i18nKey}.injectAccountIdMiddleware.invalidAccountId`, { - overrideCommand: uiCommandReference('hs accounts create-override'), + overrideCommand: uiCommandReference('hs account create-override'), }) ); } @@ -221,7 +221,7 @@ const injectAccountIdMiddleware = async options => { logger.log( i18n(`${i18nKey}.injectAccountIdMiddleware.accountNotFound`, { configPath: getConfigPath(), - authCommand: uiCommandReference('hs accounts auth'), + authCommand: uiCommandReference('hs account auth'), }) ); } diff --git a/commands/account/createOverride.ts b/commands/account/createOverride.ts index 1a306e9ec..e58ab1a36 100644 --- a/commands/account/createOverride.ts +++ b/commands/account/createOverride.ts @@ -9,6 +9,7 @@ import { addConfigOptions } from '../../lib/commonOpts'; import { i18n } from '../../lib/lang'; import { EXIT_CODES } from '../../lib/enums/exitCodes'; import { selectAccountFromConfig } from '../../lib/prompts/accountsPrompt'; +import { logError } from '../../lib/errorHandlers/index'; import { CommonArgs, ConfigArgs } from '../../types/Yargs'; const i18nKey = 'commands.account.subcommands.createOverride'; @@ -19,7 +20,7 @@ export const command = 'create-override [account]'; type AccountInfoArgs = CommonArgs & ConfigArgs & { - account?: string | number; + account: string | number; }; export async function handler( @@ -29,11 +30,7 @@ export async function handler( if (!overrideDefaultAccount) { overrideDefaultAccount = await selectAccountFromConfig(); - } else if ( - (typeof overrideDefaultAccount !== 'string' && - typeof overrideDefaultAccount !== 'number') || - !getAccountId(overrideDefaultAccount) - ) { + } else if (!getAccountId(overrideDefaultAccount)) { logger.error( i18n(`${i18nKey}.errors.accountNotFound`, { configPath: getConfigPath() || '', @@ -50,12 +47,9 @@ export async function handler( ); await fs.writeFile(overrideFilePath, accountId!.toString(), 'utf8'); logger.success(i18n(`${i18nKey}.success`, { overrideFilePath })); + process.exit(EXIT_CODES.SUCCESS); } catch (e: unknown) { - if (e instanceof Error) { - logger.error(i18n(`${i18nKey}.errors.writeFile`, { error: e.message })); - } else { - logger.error(i18n(`${i18nKey}.errors.writeFile`, { error: String(e) })); - } + logError(e); process.exit(EXIT_CODES.ERROR); } } @@ -63,14 +57,18 @@ export async function handler( export function builder(yargs: Argv): Argv { addConfigOptions(yargs); + yargs.positional('account', { + describe: i18n(`${i18nKey}.options.account.describe`), + type: 'string', + }); yargs.example([ - ['$0 accounts create-override', i18n(`${i18nKey}.examples.default`)], + ['$0 account create-override', i18n(`${i18nKey}.examples.default`)], [ - '$0 accounts create-override 12345678', + '$0 account create-override 12345678', i18n(`${i18nKey}.examples.idBased`), ], [ - '$0 accounts create-override MyAccount', + '$0 account create-override MyAccount', i18n(`${i18nKey}.examples.nameBased`), ], ]); diff --git a/lang/en.lyaml b/lang/en.lyaml index ec3a55472..93d13aa9f 100644 --- a/lang/en.lyaml +++ b/lang/en.lyaml @@ -25,8 +25,10 @@ en: describe: "Create a new default account override file (.hs-account) in the current working directory." success: "Default account override file created at {{ overrideFilePath }}" errors: - writeFile: "Unable to create the default account override file: {{ error }}" accountNotFound: "The specified account could not be found in the config file {{ configPath }}" + options: + account: + describe: "Name or ID of the account to create an override file for." examples: default: "Create a new default account override file (.hs-account) in the current working directory" idBased: "Create a new default account override file (.hs-account) in the current working directory, using the account with accountId \"1234567\"" From 7d2b836f306248d8ecbef3aefe4299baf89e1969 Mon Sep 17 00:00:00 2001 From: Allison Kemmerle Date: Wed, 29 Jan 2025 12:27:14 -0500 Subject: [PATCH 10/15] Bump to experimental LDL version --- package.json | 2 +- yarn.lock | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index be85f2311..60f69ba52 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "license": "Apache-2.0", "repository": "https://github.com/HubSpot/hubspot-cli", "dependencies": { - "@hubspot/local-dev-lib": "3.1.3", + "@hubspot/local-dev-lib": "0.1.2-experimental.0", "@hubspot/serverless-dev-runtime": "7.0.1", "@hubspot/theme-preview-dev-server": "0.0.10", "@hubspot/ui-extensions-dev-server": "0.8.40", diff --git a/yarn.lock b/yarn.lock index 9f7d6f2e4..b8795bc5f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1422,10 +1422,10 @@ vite-plugin-inspect "^0.4.3" vite-plugin-mkcert "1.16.0" -"@hubspot/local-dev-lib@2.0.1": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@hubspot/local-dev-lib/-/local-dev-lib-2.0.1.tgz#58736428de6c79092ee7cd80ed99a69ba65886ce" - integrity sha512-S2Cvwx/ZyWvGMzP+69x6cD40HgrkZdqJsrytD4S0J8oo04FvhHAh4OvX6TwING1Rhb6TUPP1lhPrORT48miMIg== +"@hubspot/local-dev-lib@0.1.2-experimental.0": + version "0.1.2-experimental.0" + resolved "https://registry.yarnpkg.com/@hubspot/local-dev-lib/-/local-dev-lib-0.1.2-experimental.0.tgz#acee11ff909899950db49fd53b3d534b2f9faa88" + integrity sha512-BRdInBVu1UjlnsUjbXQpeMqg0JQxVmas+YIQ4fLwUXzvQY3BQL8JJDoewSqk8q3wK4WIZ+mVUJEc5W7hEM5RkA== dependencies: address "^2.0.1" axios "^1.3.5" @@ -1446,10 +1446,10 @@ semver "^6.3.0" unixify "^1.0.0" -"@hubspot/local-dev-lib@3.1.3": - version "3.1.3" - resolved "https://registry.yarnpkg.com/@hubspot/local-dev-lib/-/local-dev-lib-3.1.3.tgz#c6f3fa80b4b688ca33ce6f5276b81a3fd570c8ee" - integrity sha512-XwgR9a43Gg0HCOR6RH/HHXTRyGbG9NUuBiOeXC3KmhOjMy0CpJv/LDa8lnW6HBp1f8QHBDvbblHxG3WXchLV0Q== +"@hubspot/local-dev-lib@2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@hubspot/local-dev-lib/-/local-dev-lib-2.0.1.tgz#58736428de6c79092ee7cd80ed99a69ba65886ce" + integrity sha512-S2Cvwx/ZyWvGMzP+69x6cD40HgrkZdqJsrytD4S0J8oo04FvhHAh4OvX6TwING1Rhb6TUPP1lhPrORT48miMIg== dependencies: address "^2.0.1" axios "^1.3.5" From 12b62849d2398bc77fd9b07ef38642d0ca8b9465 Mon Sep 17 00:00:00 2001 From: Allison Kemmerle Date: Wed, 29 Jan 2025 12:44:29 -0500 Subject: [PATCH 11/15] Fix doctor tests --- lib/doctor/__tests__/Diagnosis.test.ts | 1 + lib/doctor/__tests__/DiagnosticInfoBuilder.test.ts | 10 ++++++++++ .../__snapshots__/DiagnosticInfoBuilder.test.ts.snap | 1 + 3 files changed, 12 insertions(+) diff --git a/lib/doctor/__tests__/Diagnosis.test.ts b/lib/doctor/__tests__/Diagnosis.test.ts index a9985c4a4..070416ffd 100644 --- a/lib/doctor/__tests__/Diagnosis.test.ts +++ b/lib/doctor/__tests__/Diagnosis.test.ts @@ -16,6 +16,7 @@ describe('lib/doctor/Diagnosis', () => { account: {}, arch: process.arch, config: 'path/to/config.json', + defaultAccountOverrideFile: 'path/to/default/account/override/.hsaccount', configFiles: [], envFiles: [], files: [], diff --git a/lib/doctor/__tests__/DiagnosticInfoBuilder.test.ts b/lib/doctor/__tests__/DiagnosticInfoBuilder.test.ts index ac741a807..f8bff0c26 100644 --- a/lib/doctor/__tests__/DiagnosticInfoBuilder.test.ts +++ b/lib/doctor/__tests__/DiagnosticInfoBuilder.test.ts @@ -19,6 +19,7 @@ import { getAccountId as _getAccountId, getAccountConfig as _getAccountConfig, getConfigPath as _getConfigPath, + getDefaultAccountOverrideFilePath as _getDefaultAccountOverrideFilePath, } from '@hubspot/local-dev-lib/config'; import { getAccessToken as _getAccessToken } from '@hubspot/local-dev-lib/personalAccessKey'; import { walk as _walk } from '@hubspot/local-dev-lib/fs'; @@ -38,6 +39,10 @@ const getAccountConfig = _getAccountConfig as jest.MockedFunction< const getConfigPath = _getConfigPath as jest.MockedFunction< typeof _getConfigPath >; +const getDefaultAccountOverrideFilePath = + _getDefaultAccountOverrideFilePath as jest.MockedFunction< + typeof _getDefaultAccountOverrideFilePath + >; const getAccountId = _getAccountId as jest.MockedFunction; const getProjectConfig = _getProjectConfig as jest.MockedFunction< typeof _getProjectConfig @@ -116,6 +121,8 @@ describe('lib/doctor/DiagnosticInfo', () => { const npmVersion = 'v8.17.0'; const configPath = '/path/to/config'; + const defaultAccountOverrideFile = + 'path/to/default/account/override/.hsaccount'; beforeEach(() => { builder = new DiagnosticInfoBuilder(processInfo); @@ -157,6 +164,9 @@ describe('lib/doctor/DiagnosticInfo', () => { } as unknown as HubSpotPromise); getAccessToken.mockResolvedValue(accessToken); getConfigPath.mockReturnValue(configPath); + getDefaultAccountOverrideFilePath.mockReturnValue( + defaultAccountOverrideFile + ); utilPromisify.mockReturnValue(jest.fn().mockResolvedValue(npmVersion)); }); diff --git a/lib/doctor/__tests__/__snapshots__/DiagnosticInfoBuilder.test.ts.snap b/lib/doctor/__tests__/__snapshots__/DiagnosticInfoBuilder.test.ts.snap index 4bef91f57..7f6937c89 100644 --- a/lib/doctor/__tests__/__snapshots__/DiagnosticInfoBuilder.test.ts.snap +++ b/lib/doctor/__tests__/__snapshots__/DiagnosticInfoBuilder.test.ts.snap @@ -18,6 +18,7 @@ exports[`lib/doctor/DiagnosticInfo generateDiagnosticInfo should gather the requ "src/app/public-app.json", "src/app/app.functions/serverless.json", ], + "defaultAccountOverrideFile": "path/to/default/account/override/.hsaccount", "envFiles": [ "src/app/app.functions/.env", ], From d152eb498c6aa4e3d07ecf28f0518c4c7b42a486 Mon Sep 17 00:00:00 2001 From: Allison Kemmerle Date: Wed, 29 Jan 2025 12:54:59 -0500 Subject: [PATCH 12/15] v7.0.9-experimental.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 60f69ba52..ca4610003 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@hubspot/cli", - "version": "7.0.1", + "version": "7.0.9-experimental.0", "description": "The official CLI for developing on HubSpot", "license": "Apache-2.0", "repository": "https://github.com/HubSpot/hubspot-cli", From 3cb9c4b8c3e2f171fc96e70836a9c644a3df8f1f Mon Sep 17 00:00:00 2001 From: Allison Kemmerle Date: Wed, 5 Feb 2025 15:25:07 -0500 Subject: [PATCH 13/15] Fix type name --- commands/account/createOverride.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/commands/account/createOverride.ts b/commands/account/createOverride.ts index e58ab1a36..c5165e3cc 100644 --- a/commands/account/createOverride.ts +++ b/commands/account/createOverride.ts @@ -18,13 +18,13 @@ export const describe = null; // i18n(`${i18nKey}.describe`); export const command = 'create-override [account]'; -type AccountInfoArgs = CommonArgs & +type AccountCreateOverrideArgs = CommonArgs & ConfigArgs & { account: string | number; }; export async function handler( - args: ArgumentsCamelCase + args: ArgumentsCamelCase ): Promise { let overrideDefaultAccount = args.account; @@ -54,7 +54,7 @@ export async function handler( } } -export function builder(yargs: Argv): Argv { +export function builder(yargs: Argv): Argv { addConfigOptions(yargs); yargs.positional('account', { @@ -73,5 +73,5 @@ export function builder(yargs: Argv): Argv { ], ]); - return yargs as Argv; + return yargs as Argv; } From 5cdb2178041106ba8f1ea6733e535a3c005628e4 Mon Sep 17 00:00:00 2001 From: Allison Kemmerle Date: Thu, 6 Feb 2025 11:09:21 -0500 Subject: [PATCH 14/15] Address feedback 206 --- lib/doctor/Doctor.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/doctor/Doctor.ts b/lib/doctor/Doctor.ts index 388fbacd1..a248c46b6 100644 --- a/lib/doctor/Doctor.ts +++ b/lib/doctor/Doctor.ts @@ -67,10 +67,11 @@ export class Doctor { await Promise.all([ ...this.performCliChecks(), ...this.performCliConfigChecks(), - ...this.performDefaultAccountOverrideFileChecks(), ...(this.projectConfig?.projectConfig ? this.performProjectChecks() : []), ]); + this.performDefaultAccountOverrideFileChecks(); + SpinniesManager.succeed('runningDiagnostics', { text: i18n(`${i18nKey}.diagnosticsComplete`), succeedColor: 'white', @@ -116,7 +117,7 @@ export class Doctor { return [this.checkIfAccessTokenValid()]; } - private performDefaultAccountOverrideFileChecks(): Array> { + private performDefaultAccountOverrideFileChecks(): void { const localI18nKey = `${i18nKey}.defaultAccountOverrideFileChecks`; if (this.diagnosticInfo?.defaultAccountOverrideFile) { this.diagnosis?.addDefaultAccountOverrideFileSection({ @@ -133,7 +134,6 @@ export class Doctor { }), }); } - return []; } private async checkIfAccessTokenValid(): Promise { From ae96cfb71ff23ce5206d7d55c93aa34d896389f6 Mon Sep 17 00:00:00 2001 From: Allison Kemmerle Date: Thu, 6 Feb 2025 11:19:24 -0500 Subject: [PATCH 15/15] Bump LDL version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 41ad957cd..964a75405 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "license": "Apache-2.0", "repository": "https://github.com/HubSpot/hubspot-cli", "dependencies": { - "@hubspot/local-dev-lib": "0.1.2-experimental.0", + "@hubspot/local-dev-lib": "3.3.0", "@hubspot/serverless-dev-runtime": "7.0.2", "@hubspot/theme-preview-dev-server": "0.0.10", "@hubspot/ui-extensions-dev-server": "0.8.42",