From 2a1241b0ce80e6436c084a0a5fce8c5c10eb7949 Mon Sep 17 00:00:00 2001 From: Joey Blake Date: Thu, 26 Sep 2024 17:32:50 -0400 Subject: [PATCH 1/3] add message and prompt if fetching elevate into a non-project location, and project create --- packages/cli/commands/fetch.js | 22 +++++++ packages/cli/commands/project/create.js | 6 +- packages/cli/lang/en.lyaml | 6 ++ packages/cli/lib/projects.js | 58 ++++++++++++++++--- .../lib/prompts/fetchProjectAssetPrompt.js | 17 ++++++ 5 files changed, 101 insertions(+), 8 deletions(-) create mode 100644 packages/cli/lib/prompts/fetchProjectAssetPrompt.js diff --git a/packages/cli/commands/fetch.js b/packages/cli/commands/fetch.js index 93105f251..c7bbffe20 100644 --- a/packages/cli/commands/fetch.js +++ b/packages/cli/commands/fetch.js @@ -17,6 +17,11 @@ const { i18n } = require('../lib/lang'); const i18nKey = 'commands.fetch'; const { EXIT_CODES } = require('../lib/enums/exitCodes'); const { logErrorInstance } = require('../lib/errorHandlers/standardErrors'); +const { getIsInProject } = require('../lib/projects'); +const { + fetchProjectAssetPrompt, +} = require('../lib/prompts/fetchProjectAssetPrompt'); +const { uiFeatureHighlight } = require('../lib/ui'); exports.command = 'fetch [dest]'; exports.describe = i18n(`${i18nKey}.describe`); @@ -35,6 +40,23 @@ exports.handler = async options => { process.exit(EXIT_CODES.ERROR); } + // If fetching the Elevate theme, check if the destination is in a project. + if ('@hubspot/elevate' === src) { + const inProject = getIsInProject(resolveLocalPath(dest)); + // If not in a project, alert the user. Otherwise proceed with the fetch. + if (!inProject) { + const fetchAnyway = await fetchProjectAssetPrompt(src); + if (!fetchAnyway.continue) { + logger.log(''); + uiFeatureHighlight( + ['projectCreateCommand'], + i18n(`${i18nKey}.info.createElevateProjectTitle`) + ); + process.exit(EXIT_CODES.SUCCESS); + } + } + } + const accountId = getAccountId(options); const mode = getMode(options); diff --git a/packages/cli/commands/project/create.js b/packages/cli/commands/project/create.js index 422cdd8c8..0ef514f32 100644 --- a/packages/cli/commands/project/create.js +++ b/packages/cli/commands/project/create.js @@ -47,6 +47,8 @@ exports.handler = async options => { options ); + const { isHubSpotAsset } = template; + trackCommandUsage('project-create', { type: template.name }, accountId); await createProjectConfig( @@ -54,7 +56,8 @@ exports.handler = async options => { options.name || name, template, options.templateSource, - githubRef + githubRef, + accountId ); logger.log(''); @@ -63,6 +66,7 @@ exports.handler = async options => { 'projectDevCommand', 'projectHelpCommand', 'feedbackCommand', + isHubSpotAsset && 'projectUploadCommand', 'sampleProjects', ]); }; diff --git a/packages/cli/lang/en.lyaml b/packages/cli/lang/en.lyaml index e7ec1ce73..1298ef49b 100644 --- a/packages/cli/lang/en.lyaml +++ b/packages/cli/lang/en.lyaml @@ -280,6 +280,8 @@ en: describe: "Fetch a file, directory or module from HubSpot and write to a path on your computer." errors: sourceRequired: "A source to fetch is required." + info: + createElevateProjectTitle: "Create a project and select the \"Elevate\" theme" options: staging: describe: "Retrieve staged changes for project" @@ -1064,6 +1066,8 @@ en: logFeedbackMessage: feedbackHeader: "We'd love to hear your feedback!" feedbackMessage: "How are you liking the new projects and developer tools? \n > Run `{{#yellow}}hs feedback{{/yellow}}` to let us know what you think!\n" + errors: + downloadFileOrFolder: "Not all files in folder \"{{ src }}\" were successfully fetched. Run `{{#yellow}}{{ command }}{{/yellow}}` again to finish download" ui: betaTag: "{{#bold}}[BETA]{{/bold}}" betaWarning: @@ -1196,6 +1200,8 @@ en: invalidPersonalAccessKeyCopy: "Please copy the actual access key rather than the bullets that mask it." folderOverwritePrompt: overwriteConfirm: "The folder with name \"{{ folderName }}\" already exists. Overwrite?" + fetchProjectAssetPrompt: + fetchConfirm: "\"{{ assetPath }}\" requires a HubSpot project to work. Would you like to continue fetching without creating a project?" createTemplatePrompt: selectTemplate: "Select the type of template to create" createModulePrompt: diff --git a/packages/cli/lib/projects.js b/packages/cli/lib/projects.js index c309acde9..7e4ecc636 100644 --- a/packages/cli/lib/projects.js +++ b/packages/cli/lib/projects.js @@ -49,6 +49,8 @@ const { logApiErrorInstance, ApiErrorContext, } = require('./errorHandlers/apiErrors'); +const { downloadFileOrFolder } = require('@hubspot/local-dev-lib/fileMapper'); +const { DEFAULT_MODE } = require('@hubspot/local-dev-lib/constants/files'); const i18nKey = 'lib.projects'; @@ -107,7 +109,8 @@ const createProjectConfig = async ( projectName, template, templateSource, - githubRef + githubRef, + accountId ) => { const { projectConfig, projectDir } = await getProjectConfig(projectPath); @@ -146,12 +149,25 @@ const createProjectConfig = async ( const hasCustomTemplateSource = Boolean(templateSource); - await downloadGithubRepoContents( - templateSource || HUBSPOT_PROJECT_COMPONENTS_GITHUB_PATH, - template.path, - projectPath, - hasCustomTemplateSource ? undefined : githubRef - ); + const { isHubSpotAsset } = template; + + // if template config is marked `isHubSpotAsset` download no-template project to fetch the @hubspot asset into it. + if (isHubSpotAsset) { + await downloadGithubRepoContents( + HUBSPOT_PROJECT_COMPONENTS_GITHUB_PATH, + 'projects/no-template', + projectPath, + githubRef + ); + } else { + await downloadGithubRepoContents( + templateSource || HUBSPOT_PROJECT_COMPONENTS_GITHUB_PATH, + template.path, + projectPath, + hasCustomTemplateSource ? undefined : githubRef + ); + } + const _config = JSON.parse(fs.readFileSync(projectConfigPath)); writeProjectConfig(projectConfigPath, { ..._config, @@ -162,6 +178,34 @@ const createProjectConfig = async ( fs.ensureDirSync(path.join(projectPath, 'src')); } + if (isHubSpotAsset) { + const assetPath = template.path; + const destinationPath = path.join( + projectPath, + template.insertPath, + template.name + ); + // fetch the @hubspot asset and place it in the new project folder + try { + // Fetch and write file/folder. + await downloadFileOrFolder( + accountId, + assetPath, + destinationPath, + DEFAULT_MODE, + false + ); + } catch (err) { + logger.error( + i18n(`${i18nKey}.errors.downloadFileOrFolder`, { + src: template.path, + command: `hs fetch ${assetPath} ${destinationPath}`, + }) + ); + process.exit(EXIT_CODES.ERROR); + } + } + return true; }; diff --git a/packages/cli/lib/prompts/fetchProjectAssetPrompt.js b/packages/cli/lib/prompts/fetchProjectAssetPrompt.js new file mode 100644 index 000000000..8cfbae5a0 --- /dev/null +++ b/packages/cli/lib/prompts/fetchProjectAssetPrompt.js @@ -0,0 +1,17 @@ +const { promptUser } = require('./promptUtils'); +const { i18n } = require('../lang'); + +const i18nKey = 'lib.prompts.fetchProjectAssetPrompt'; + +const fetchProjectAssetPrompt = assetPath => { + return promptUser({ + type: 'confirm', + name: 'continue', + message: i18n(`${i18nKey}.fetchConfirm`, { assetPath }), + default: false, + }); +}; + +module.exports = { + fetchProjectAssetPrompt, +}; From b5b9ff883d7b5f5aca2f1bba2f025baf2b0d30c7 Mon Sep 17 00:00:00 2001 From: Joey Blake Date: Fri, 27 Sep 2024 10:00:00 -0400 Subject: [PATCH 2/3] drop not really necessary feature highlight --- packages/cli/commands/project/create.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/cli/commands/project/create.js b/packages/cli/commands/project/create.js index 0ef514f32..da88903dd 100644 --- a/packages/cli/commands/project/create.js +++ b/packages/cli/commands/project/create.js @@ -47,8 +47,6 @@ exports.handler = async options => { options ); - const { isHubSpotAsset } = template; - trackCommandUsage('project-create', { type: template.name }, accountId); await createProjectConfig( @@ -66,7 +64,6 @@ exports.handler = async options => { 'projectDevCommand', 'projectHelpCommand', 'feedbackCommand', - isHubSpotAsset && 'projectUploadCommand', 'sampleProjects', ]); }; From be9b363a8a040f0d4c02a1c9e9167f5b118f251a Mon Sep 17 00:00:00 2001 From: Joey Blake Date: Fri, 4 Oct 2024 09:34:11 -0400 Subject: [PATCH 3/3] formatting adjustments --- packages/cli/lang/en.lyaml | 2 +- packages/cli/lib/projects.js | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/cli/lang/en.lyaml b/packages/cli/lang/en.lyaml index 1298ef49b..2c297ec03 100644 --- a/packages/cli/lang/en.lyaml +++ b/packages/cli/lang/en.lyaml @@ -1067,7 +1067,7 @@ en: feedbackHeader: "We'd love to hear your feedback!" feedbackMessage: "How are you liking the new projects and developer tools? \n > Run `{{#yellow}}hs feedback{{/yellow}}` to let us know what you think!\n" errors: - downloadFileOrFolder: "Not all files in folder \"{{ src }}\" were successfully fetched. Run `{{#yellow}}{{ command }}{{/yellow}}` again to finish download" + downloadFileOrFolder: "Not all files in folder {{#bold}}\"{{ src }}\"{{/bold}} were successfully fetched. Run {{ command }} again to finish download" ui: betaTag: "{{#bold}}[BETA]{{/bold}}" betaWarning: diff --git a/packages/cli/lib/projects.js b/packages/cli/lib/projects.js index 7e4ecc636..37e4b5a59 100644 --- a/packages/cli/lib/projects.js +++ b/packages/cli/lib/projects.js @@ -42,7 +42,12 @@ const { getCwd, getAbsoluteFilePath } = require('@hubspot/local-dev-lib/path'); const { downloadGithubRepoContents } = require('@hubspot/local-dev-lib/github'); const { promptUser } = require('./prompts/promptUtils'); const { EXIT_CODES } = require('./enums/exitCodes'); -const { uiLine, uiLink, uiAccountDescription } = require('../lib/ui'); +const { + uiLine, + uiLink, + uiAccountDescription, + uiCommandReference, +} = require('../lib/ui'); const { i18n } = require('./lang'); const SpinniesManager = require('./ui/SpinniesManager'); const { @@ -199,7 +204,9 @@ const createProjectConfig = async ( logger.error( i18n(`${i18nKey}.errors.downloadFileOrFolder`, { src: template.path, - command: `hs fetch ${assetPath} ${destinationPath}`, + command: uiCommandReference( + `hs fetch ${assetPath} ${destinationPath}` + ), }) ); process.exit(EXIT_CODES.ERROR);