Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
f9dd09c
feat: Migrations polish
joe-yeager Apr 17, 2025
6714d3f
Merge branch 'main' of github.com:HubSpot/hubspot-cli into jy/migrati…
joe-yeager Apr 17, 2025
656c407
clean up dedupe logic
joe-yeager Apr 17, 2025
b21050c
Remove duplicate log message
joe-yeager Apr 17, 2025
1caccd5
feat: Incorporate UX feedback
joe-yeager Apr 22, 2025
d2dc2c0
Merge branch 'main' of github.com:HubSpot/hubspot-cli into jy/migrati…
joe-yeager Apr 22, 2025
ec59980
Clean up, add componentErrorDetails
joe-yeager Apr 22, 2025
1079ae2
Update suggestion for uid
joe-yeager Apr 22, 2025
b76f437
Add unstable flag
joe-yeager Apr 23, 2025
7ab98ab
Tweaks to flags
joe-yeager Apr 23, 2025
66a31b3
remove intermediate variable
joe-yeager Apr 23, 2025
8f6b3d9
UX Feedback
joe-yeager Apr 24, 2025
1081cdc
sort the apps based on if they are migratable, and add a separator
joe-yeager Apr 24, 2025
c224594
Merge branch 'main' of github.com:HubSpot/hubspot-cli into jy/migrati…
joe-yeager Apr 24, 2025
a40ef97
Remove component detail errors since it is in flux
joe-yeager Apr 24, 2025
a5e988c
Update log message
joe-yeager Apr 24, 2025
29b603c
Remove redundant sort
joe-yeager Apr 24, 2025
7dafd63
application -> app
joe-yeager Apr 24, 2025
c2eda82
chore: Add verbiage for linked to GH Repo
joe-yeager Apr 24, 2025
253c2f1
Merge branch 'main' of github.com:HubSpot/hubspot-cli into jy/add-git…
joe-yeager Apr 24, 2025
cf90e63
chore: Add error case for GH connected projects
joe-yeager Apr 24, 2025
50f9ea0
Merge branch 'main' of github.com:HubSpot/hubspot-cli into jy/add-git…
joe-yeager Apr 24, 2025
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
12 changes: 6 additions & 6 deletions lang/en.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
// @ts-nocheck
import chalk from 'chalk';
import { uiAccountDescription, uiCommandReference, uiLink } from '../lib/ui';

type LangFunction = (...args: (string | number)[]) => string;

type LangObject = {
[key: string]: string | LangFunction | LangObject;
};
import { getProjectSettingsUrl } from '../lib/projects/urls';

type LangFunction = (...args: (string | number)[]) => string;

Expand Down Expand Up @@ -3452,6 +3447,11 @@ export const lib = {
upToDate: 'App is already up to date',
isPrivateApp: 'Private apps are not currently migratable',
listedInMarketplace: 'Listed apps are not currently migratable',
projectConnectedToGitHub: (
projectName: string | undefined,
accountId: number
) =>
`The project is linked to a GitHub repository. ${uiLink('Visit the project settings page to unlink it', getProjectSettingsUrl(projectName, accountId))}`,
partOfProjectAlready: `This app is part of a project, run ${uiCommandReference('hs project migrate')} from the project directory to migrate it`,
generic: reasonCode => `Unable to migrate app: ${reasonCode}`,
},
Expand Down
28 changes: 23 additions & 5 deletions lib/app/migrate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,23 @@ export type MigrateAppArgs = CommonArgs &
platformVersion: string;
};

function getUnmigratableReason(reasonCode: string): string {
function getUnmigratableReason(
reasonCode: string,
projectName: string | undefined,
accountId: number
): string {
switch (reasonCode) {
case UNMIGRATABLE_REASONS.UP_TO_DATE:
return lib.migrate.errors.unmigratableReasons.upToDate;
case UNMIGRATABLE_REASONS.IS_A_PRIVATE_APP:
return lib.migrate.errors.unmigratableReasons.isPrivateApp;
case UNMIGRATABLE_REASONS.LISTED_IN_MARKETPLACE:
return lib.migrate.errors.unmigratableReasons.listedInMarketplace;
case UNMIGRATABLE_REASONS.PROJECT_CONNECTED_TO_GITHUB:
return lib.migrate.errors.unmigratableReasons.projectConnectedToGitHub(
projectName,
accountId
);
case CLI_UNMIGRATABLE_REASONS.PART_OF_PROJECT_ALREADY:
return lib.migrate.errors.unmigratableReasons.partOfProjectAlready;
default:
Expand Down Expand Up @@ -128,7 +137,7 @@ async function fetchMigrationApps(
if (allApps.length === 0 || !allApps.some(app => app.isMigratable)) {
const reasons = filteredUnmigratableApps.map(
app =>
`${chalk.bold(app.appName)}: ${getUnmigratableReason(app.unmigratableReason)}`
`${chalk.bold(app.appName)}: ${getUnmigratableReason(app.unmigratableReason, app.projectName, derivedAccountId)}`
);

throw new Error(
Expand All @@ -151,15 +160,22 @@ async function fetchMigrationApps(
return allApps;
}

async function promptForAppToMigrate(allApps: MigrationApp[]) {
async function promptForAppToMigrate(
allApps: MigrationApp[],
derivedAccountId: number
) {
const appChoices = allApps.map(app => ({
name: app.isMigratable
? app.appName
: `[${chalk.yellow('DISABLED')}] ${app.appName} `,
value: app,
disabled: app.isMigratable
? false
: getUnmigratableReason(app.unmigratableReason),
: getUnmigratableReason(
app.unmigratableReason,
app.projectName,
derivedAccountId
),
}));

const enabledChoices = appChoices.filter(app => !app.disabled);
Expand All @@ -180,6 +196,7 @@ async function promptForAppToMigrate(allApps: MigrationApp[]) {
}
async function selectAppToMigrate(
allApps: MigrationApp[],
derivedAccountId: number,
appId?: number,
projectConfig?: LoadedProjectConfig
): Promise<{ proceed: boolean; appIdToMigrate?: number }> {
Expand All @@ -194,7 +211,7 @@ async function selectAppToMigrate(

let appIdToMigrate = appId;
if (!appIdToMigrate) {
appIdToMigrate = await promptForAppToMigrate(allApps);
appIdToMigrate = await promptForAppToMigrate(allApps, derivedAccountId);
}

const selectedApp = allApps.find(app => app.appId === appIdToMigrate);
Expand Down Expand Up @@ -259,6 +276,7 @@ async function handleMigrationSetup(

const { proceed, appIdToMigrate } = await selectAppToMigrate(
allApps,
derivedAccountId,
appId,
projectConfig
);
Expand Down
8 changes: 8 additions & 0 deletions lib/projects/urls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@ export function getProjectDetailUrl(
return `${getProjectHomeUrl(accountId)}/project/${projectName}`;
}

export function getProjectSettingsUrl(
projectName: string,
accountId: number
): string | undefined {
if (!projectName) return;
return `${getProjectDetailUrl(projectName, accountId)}/settings`;
}

export function getProjectActivityUrl(
projectName: string,
accountId: number
Expand Down