Skip to content

Safer copy logging POC #1473

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Apr 30, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions commands/project/migrate.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { ArgumentsCamelCase, Argv } from 'yargs';
import { logger } from '@hubspot/local-dev-lib/logger';
import {
AccountArgs,
CommonArgs,
Expand All @@ -15,6 +14,7 @@ import { EXIT_CODES } from '../../lib/enums/exitCodes';
import { makeYargsBuilder } from '../../lib/yargsUtils';
import { uiBetaTag, uiCommandReference } from '../../lib/ui';
import { commands } from '../../lang/en';
import { uiLogger } from '../../lib/ui/logger';

export type ProjectMigrateArgs = CommonArgs &
AccountArgs &
Expand All @@ -35,16 +35,16 @@ async function handler(
const projectConfig = await getProjectConfig();

if (!projectConfig.projectConfig) {
logger.error(
uiLogger.error(
commands.project.migrate.errors.noProjectConfig(
uiCommandReference('hs app migrate')
)
);
return process.exit(EXIT_CODES.ERROR);
}

logger.log();
logger.log(
uiLogger.log('');
uiLogger.log(
uiBetaTag(commands.project.migrate.preamble(platformVersion), false)
);
const { derivedAccountId } = args;
Expand Down
16 changes: 8 additions & 8 deletions lang/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1207,8 +1207,7 @@ export const commands = {
},
logs: {
processExited: 'Stopping watcher...',
watchCancelledFromUi: () =>
`The watch process has been cancelled from the UI. Any changes made since cancelling have not been uploaded. To resume watching, rerun ${chalk.yellow('`hs project watch`')}.`,
watchCancelledFromUi: `The watch process has been cancelled from the UI. Any changes made since cancelling have not been uploaded. To resume watching, rerun ${uiCommandReference('hs project watch')}.`,
resuming: 'Resuming watcher...',
uploadSucceeded: (remotePath, filePath) =>
`Uploaded file "${filePath}" to "${remotePath}"`,
Expand Down Expand Up @@ -2679,8 +2678,7 @@ export const lib = {
validateAccountOption: {
invalidPublicAppAccount: `This project contains a public app. The "--account" flag must point to a developer test account to develop this project locally. Alternatively, change your default account to an App Developer Account using ${uiCommandReference('hs accounts use')} and run ${uiCommandReference('hs project dev')} to set up a new Developer Test Account.`,
invalidPrivateAppAccount: `This project contains a private app. The account specified with the "--account" flag points to a developer account, which do not support the local development of private apps. Update the "--account" flag to point to a standard, sandbox, or developer test account, or change your default account by running ${uiCommandReference('hs accounts use')}.`,
nonSandboxWarning: command =>
`Testing in a sandbox is strongly recommended. To switch the target account, select an option below or run ${chalk.bold(command)} before running the command again.`,
nonSandboxWarning: `Testing in a sandbox is strongly recommended. To switch the target account, select an option below or run ${uiCommandReference('hs accounts use')} before running the command again.`,
publicAppNonDeveloperTestAccountWarning: `Local development of public apps is only supported in ${chalk.bold('developer test accounts')}.`,
},
createNewProjectForLocalDev: {
Expand Down Expand Up @@ -2731,6 +2729,9 @@ export const lib = {
srcOutsideProjectDir: (projectConfig, srcDir) =>
`Invalid value for 'srcDir' in ${projectConfig}: ${chalk.bold(`srcDir: "${srcDir}"`)}\n\t'srcDir' must be a relative path to a folder under the project root, such as "." or "./src"`,
},
getProjectConfig: {
error: 'Could not read from project config',
},
ensureProjectExists: {
createPrompt: (projectName, accountIdentifier) =>
`The project ${projectName} does not exist in ${accountIdentifier}. Would you like to create it?`,
Expand All @@ -2747,12 +2748,12 @@ export const lib = {
},
logFeedbackMessage: {
feedbackHeader: "We'd love to hear your feedback!",
feedbackMessage: command =>
`How are you liking the new projects and developer tools? \n > Run \`${chalk.yellow(command)}\` to let us know what you think!\n`,
feedbackMessage: `How are you liking the new projects and developer tools? \n > Run ${uiCommandReference('hs feedback')} to let us know what you think!\n`,
},
},
projectBuildAndDeploy: {
makePollTaskStatusFunc: {
errorSummary: 'See below for a summary of errors.',
componentCountSingular: 'Found 1 component in this project\n',
componentCount: numComponents =>
`Found ${numComponents} components in this project\n`,
Expand Down Expand Up @@ -3464,8 +3465,7 @@ export const lib = {
noAppsEligible: (accountId, reasons: string[]) =>
`No apps in account ${accountId} are currently migratable${reasons.length ? `\n - ${reasons.join('\n - ')}` : ''}`,

invalidAccountTypeTitle: () =>
`${chalk.bold('Developer account not targeted')}`,
invalidAccountTypeTitle: `${chalk.bold('Developer account not targeted')}`,
invalidAccountTypeDescription: (useCommand, authCommand) =>
`Only public apps created in a developer account can be converted to a project component. Select a connected developer account with ${useCommand} or ${authCommand} and try again.`,
appWithAppIdNotFound: appId =>
Expand Down
20 changes: 10 additions & 10 deletions lib/app/migrate.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { logger } from '@hubspot/local-dev-lib/logger';
import path from 'path';
import { getCwd, sanitizeFileName } from '@hubspot/local-dev-lib/path';
import { extractZipArchive } from '@hubspot/local-dev-lib/archive';
Expand Down Expand Up @@ -47,6 +46,7 @@ import {
getProjectBuildDetailUrl,
getProjectDetailUrl,
} from '../projects/urls';
import { uiLogger } from '../ui/logger';

export type MigrateAppArgs = CommonArgs &
AccountArgs &
Expand Down Expand Up @@ -247,22 +247,22 @@ async function selectAppToMigrate(
});

if (migratableComponents.size !== 0) {
logger.log(
uiLogger.log(
lib.migrate.componentsToBeMigrated(
`\n - ${[...migratableComponents].join('\n - ')}`
)
);
}

if (unmigratableComponents.size !== 0) {
logger.log(
uiLogger.log(
lib.migrate.componentsThatWillNotBeMigrated(
`\n - ${[...unmigratableComponents].join('\n - ')}`
)
);
}

logger.log();
uiLogger.log('');

const promptMessage = projectConfig?.projectConfig
? `${lib.migrate.projectMigrationWarning} ${lib.migrate.prompt.proceed}`
Expand Down Expand Up @@ -517,7 +517,7 @@ async function downloadProjectFiles(
// Move the existing source directory to archive
fs.renameSync(path.join(projectDir, srcDir), archiveDest);

logger.info(lib.migrate.sourceContentsMoved(archiveDest));
uiLogger.info(lib.migrate.sourceContentsMoved(archiveDest));
} else {
absoluteDestPath = projectDest
? path.resolve(getCwd(), projectDest)
Expand All @@ -538,7 +538,7 @@ async function downloadProjectFiles(
text: lib.migrate.spinners.downloadingProjectContentsComplete,
});

logger.success(`Saved ${projectName} to ${projectDest}`);
uiLogger.success(`Saved ${projectName} to ${projectDest}`);
} catch (error) {
SpinniesManager.fail('fetchingMigratedProject', {
text: lib.migrate.spinners.downloadingProjectContentsFailed,
Expand Down Expand Up @@ -617,14 +617,14 @@ export async function migrateApp2025_2(
projectConfig
);

logger.log(
uiLogger.log(
uiLink(
'Project Details',
getProjectDetailUrl(projectName, derivedAccountId)!
)
);

logger.log(
uiLogger.log(
uiLink(
'Build Details',
getProjectBuildDetailUrl(projectName, buildId, derivedAccountId)!
Expand All @@ -634,8 +634,8 @@ export async function migrateApp2025_2(

export function logInvalidAccountError(): void {
uiLine();
logger.error(lib.migrate.errors.invalidAccountTypeTitle);
logger.log(
uiLogger.error(lib.migrate.errors.invalidAccountTypeTitle);
uiLogger.log(
lib.migrate.errors.invalidAccountTypeDescription(
uiCommandReference('hs account use'),
uiCommandReference('hs auth')
Expand Down
4 changes: 2 additions & 2 deletions lib/projects/ProjectLogsManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { getProjectConfig } from './config';
import { ensureProjectExists } from './ensureProjectExists';
import { fetchProjectComponentsMetadata } from '@hubspot/local-dev-lib/api/projects';
import { AppFunctionComponentMetadata } from '@hubspot/local-dev-lib/types/ComponentStructure';
import { logger } from '@hubspot/local-dev-lib/logger';
import { uiLogger } from '../ui/logger';
import { commands } from '../../lang/en';

class _ProjectLogsManager {
Expand Down Expand Up @@ -71,7 +71,7 @@ class _ProjectLogsManager {
}

if (!this.accountId) {
logger.debug(
uiLogger.debug(
commands.project.logs.errors.projectLogsManagerNotInitialized
);
throw new Error(commands.project.logs.errors.generic);
Expand Down
36 changes: 19 additions & 17 deletions lib/projects/buildAndDeploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { HubSpotPromise } from '@hubspot/local-dev-lib/types/Http';
import { ComponentStructureResponse } from '@hubspot/local-dev-lib/types/ComponentStructure';
import { Build } from '@hubspot/local-dev-lib/types/Build';
import { Deploy } from '@hubspot/local-dev-lib/types/Deploy';
import { logger } from '@hubspot/local-dev-lib/logger';
import {
getBuildStatus,
getBuildStructure,
Expand Down Expand Up @@ -39,6 +38,7 @@ import {
} from '../../types/Projects';
import { EXIT_CODES } from '../enums/exitCodes';
import { lib } from '../../lang/en';
import { uiLogger } from '../ui/logger';

const SPINNER_STATUS = {
SPINNING: 'spinning',
Expand Down Expand Up @@ -116,7 +116,7 @@ type PollTaskStatusFunction<T extends ProjectTask> = (
function handleTaskStatusError(
statusText: ProjectPollStatusFunctionText
): never {
logger.error(
uiLogger.error(
lib.projectBuildAndDeploy.makePollTaskStatusFunc.errorFetchingTaskStatus(
statusText.TYPE_KEY === PROJECT_BUILD_TEXT.TYPE_KEY ? 'build' : 'deploy'
)
Expand All @@ -141,7 +141,7 @@ function makePollTaskStatusFunc<T extends ProjectTask>({
const displayId = deployedBuildId || taskId;

if (linkToHubSpot && !silenceLogs) {
logger.log(
uiLogger.log(
`\n${linkToHubSpot(accountId, taskName, taskId, deployedBuildId)}\n`
);
}
Expand Down Expand Up @@ -244,7 +244,7 @@ function makePollTaskStatusFunc<T extends ProjectTask>({
const { data } = await statusFn(accountId, taskName, taskId);
taskStatus = data;
} catch (e) {
logger.debug(e);
uiLogger.debug(e);
logError(
e,
new ApiErrorContext({
Expand Down Expand Up @@ -323,15 +323,17 @@ function makePollTaskStatusFunc<T extends ProjectTask>({
);

uiLine();
logger.log(
uiLogger.log(
`${statusStrings.SUBTASK_FAIL(
failedSubtasks.length === 1
? getSubtaskName(failedSubtasks[0])
: failedSubtasks.length + ' components',
displayId
)}\n`
);
logger.log('See below for a summary of errors.');
uiLogger.log(
lib.projectBuildAndDeploy.makePollTaskStatusFunc.errorSummary
);
uiLine();

const displayErrors = failedSubtasks.filter(
Expand All @@ -343,18 +345,18 @@ function makePollTaskStatusFunc<T extends ProjectTask>({
);

displayErrors.forEach(subTask => {
logger.log(
uiLogger.log(
`\n--- ${chalk.bold(
getSubtaskName(subTask)
)} failed with the following error ---`
);
logger.error(subTask.errorMessage);
uiLogger.error(subTask.errorMessage);

// Log nested errors
if (subTask.standardError && subTask.standardError.errors) {
logger.log();
uiLogger.log('');
subTask.standardError.errors.forEach(error => {
logger.log(error.message);
uiLogger.log(error.message);
});
}
});
Expand Down Expand Up @@ -385,7 +387,7 @@ function pollBuildAutodeployStatus(
const response = await getBuildStatus(accountId, taskName, buildId);
build = response.data;
} catch (e) {
logger.debug(e);
uiLogger.debug(e);
return reject(
new Error(
lib.projectBuildAndDeploy.pollBuildAutodeployStatusError(buildId)
Expand Down Expand Up @@ -485,9 +487,9 @@ export async function displayWarnLogs(
if (result && result.logs) {
const logLength = result.logs.length;
result.logs.forEach((log, i) => {
logger.warn(log.message);
uiLogger.warn(log.message);
if (i < logLength - 1) {
logger.log('');
uiLogger.log('');
}
});
}
Expand Down Expand Up @@ -524,7 +526,7 @@ export async function pollProjectBuildAndDeploy(
return result;
} else if (buildStatus.isAutoDeployEnabled) {
if (!silenceLogs) {
logger.log(
uiLogger.log(
lib.projectBuildAndDeploy.pollProjectBuildAndDeploy.buildSucceededAutomaticallyDeploying(
buildId,
uiAccountDescription(accountId)
Expand Down Expand Up @@ -561,7 +563,7 @@ export async function pollProjectBuildAndDeploy(
result.succeeded = false;
}
} else if (!silenceLogs) {
logger.log(
uiLogger.log(
lib.projectBuildAndDeploy.pollProjectBuildAndDeploy.unableToFindAutodeployStatus(
buildId,
uiLink(
Expand All @@ -576,14 +578,14 @@ export async function pollProjectBuildAndDeploy(
try {
if (tempFile) {
tempFile.removeCallback();
logger.debug(
uiLogger.debug(
lib.projectBuildAndDeploy.pollProjectBuildAndDeploy.cleanedUpTempFile(
tempFile.name
)
);
}
} catch (e) {
logger.error(e);
logError(e);
}

if (result && result.deployResult) {
Expand Down
Loading