Skip to content

Commit

Permalink
Merge branch 'main' of github.com:HubSpot/hubspot-cli into jy/add-pro…
Browse files Browse the repository at this point in the history
…ject-translation
  • Loading branch information
joe-yeager committed Jan 14, 2025
2 parents b03f01e + 48e9d58 commit bca759e
Show file tree
Hide file tree
Showing 20 changed files with 510 additions and 530 deletions.
3 changes: 2 additions & 1 deletion acceptance-tests/tests/workflows/secretsFlow.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ async function waitForSecretsListToContainSecret(testState: TestState) {
.toContain(SECRET.name);
}

describe('Secrets Flow', () => {
// TODO: Re-enable when the caching issue is resolved on the BE
describe.skip('Secrets Flow', () => {
let testState: TestState;

beforeAll(async () => {
Expand Down
43 changes: 37 additions & 6 deletions bin/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,13 @@ const { logger } = require('@hubspot/local-dev-lib/logger');
const { addUserAgentHeader } = require('@hubspot/local-dev-lib/http');
const {
loadConfig,
getAccountId,
configFileExists,
getConfigPath,
validateConfig,
} = require('@hubspot/local-dev-lib/config');
const { logError } = require('../lib/errorHandlers/index');
const {
setLogLevel,
getCommandName,
injectAccountIdMiddleware,
} = require('../lib/commonOpts');
const { setLogLevel, getCommandName } = require('../lib/commonOpts');
const { validateAccount } = require('../lib/validation');
const {
trackHelpUsage,
Expand All @@ -27,7 +24,7 @@ const { getIsInProject } = require('../lib/projects');
const pkg = require('../package.json');
const { i18n } = require('../lib/lang');
const { EXIT_CODES } = require('../lib/enums/exitCodes');
const { UI_COLORS, uiCommandReference } = require('../lib/ui');
const { UI_COLORS, uiCommandReference, uiDeprecatedTag } = require('../lib/ui');
const { checkAndWarnGitInclusion } = require('../lib/ui/git');

const removeCommand = require('../commands/remove');
Expand Down Expand Up @@ -176,6 +173,39 @@ const SKIP_CONFIG_VALIDATION = {
auth: { target: true },
};

const handleDeprecatedEnvVariables = options => {
// HUBSPOT_PORTAL_ID is deprecated, but we'll still support it for now
// The HubSpot GH Deploy Action still uses HUBSPOT_PORTAL_ID
if (
options.useEnv &&
process.env.HUBSPOT_PORTAL_ID &&
!process.env.HUBSPOT_ACCOUNT_ID
) {
uiDeprecatedTag(
i18n(`${i18nKey}.handleDeprecatedEnvVariables.portalEnvVarDeprecated`, {
configPath: getConfigPath(),
})
);
process.env.HUBSPOT_ACCOUNT_ID = process.env.HUBSPOT_PORTAL_ID;
}
};

/**
* Auto-injects the derivedAccountId flag into all commands
*/
const injectAccountIdMiddleware = async options => {
const { account } = options;

// Preserves the original --account flag for certain commands.
options.providedAccountId = account;

if (options.useEnv && process.env.HUBSPOT_ACCOUNT_ID) {
options.derivedAccountId = parseInt(process.env.HUBSPOT_ACCOUNT_ID, 10);
} else {
options.derivedAccountId = getAccountId(account);
}
};

const loadConfigMiddleware = async options => {
// Skip this when no command is provided
if (!options._.length) {
Expand Down Expand Up @@ -261,6 +291,7 @@ const argv = yargs
.middleware([
setLogLevel,
setRequestHeaders,
handleDeprecatedEnvVariables,
loadConfigMiddleware,
injectAccountIdMiddleware,
checkAndWarnGitInclusionMiddleware,
Expand Down
7 changes: 3 additions & 4 deletions commands/project/dev.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,10 @@ const {
isAppDeveloperAccount,
} = require('../../lib/accountTypes');
const { getValidEnv } = require('@hubspot/local-dev-lib/environment');

const { ComponentTypes } = require('../../types/Projects');
const {
findProjectComponents,
getProjectComponentTypes,
COMPONENT_TYPES,
} = require('../../lib/projects/structure');
const {
confirmDefaultAccountIsTarget,
Expand Down Expand Up @@ -82,8 +81,8 @@ exports.handler = async options => {
const components = await findProjectComponents(projectDir);
const runnableComponents = components.filter(component => component.runnable);
const componentTypes = getProjectComponentTypes(runnableComponents);
const hasPrivateApps = !!componentTypes[COMPONENT_TYPES.privateApp];
const hasPublicApps = !!componentTypes[COMPONENT_TYPES.publicApp];
const hasPrivateApps = !!componentTypes[ComponentTypes.PrivateApp];
const hasPublicApps = !!componentTypes[ComponentTypes.PublicApp];

if (runnableComponents.length === 0) {
logger.error(
Expand Down
17 changes: 6 additions & 11 deletions commands/sandbox/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ const { EXIT_CODES } = require('../../lib/enums/exitCodes');
const { getAccountConfig, getEnv } = require('@hubspot/local-dev-lib/config');
const { uiFeatureHighlight, uiBetaTag } = require('../../lib/ui');
const {
sandboxTypeMap,
SANDBOX_TYPE_MAP,
getAvailableSyncTypes,
syncTypes,
SYNC_TYPES,
validateSandboxUsageLimits,
} = require('../../lib/sandboxes');
const { getValidEnv } = require('@hubspot/local-dev-lib/environment');
Expand Down Expand Up @@ -65,7 +65,7 @@ exports.handler = async options => {
let typePrompt;
let namePrompt;

if ((type && !sandboxTypeMap[type.toLowerCase()]) || !type) {
if ((type && !SANDBOX_TYPE_MAP[type.toLowerCase()]) || !type) {
if (!force) {
typePrompt = await sandboxTypePrompt();
} else {
Expand All @@ -74,7 +74,7 @@ exports.handler = async options => {
}
}
const sandboxType = type
? sandboxTypeMap[type.toLowerCase()]
? SANDBOX_TYPE_MAP[type.toLowerCase()]
: typePrompt.type;

// Check usage limits and exit if parent portal has no available sandboxes for the selected type
Expand Down Expand Up @@ -141,12 +141,7 @@ exports.handler = async options => {
const sandboxAccountConfig = getAccountConfig(result.sandbox.sandboxHubId);
// For v1 sandboxes, keep sync here. Once we migrate to v2, this will be handled by BE automatically
const handleSyncSandbox = async syncTasks => {
await syncSandbox({
accountConfig: sandboxAccountConfig,
parentAccountConfig: accountConfig,
env,
syncTasks,
});
await syncSandbox(sandboxAccountConfig, accountConfig, env, syncTasks);
};
try {
let availableSyncTasks = await getAvailableSyncTypes(
Expand All @@ -156,7 +151,7 @@ exports.handler = async options => {

if (!contactRecordsSyncPromptResult) {
availableSyncTasks = availableSyncTasks.filter(
t => t.type !== syncTypes.OBJECT_RECORDS
t => t.type !== SYNC_TYPES.OBJECT_RECORDS
);
}
await handleSyncSandbox(availableSyncTasks);
Expand Down
8 changes: 3 additions & 5 deletions commands/theme/preview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,8 @@ const { ApiErrorContext, logError } = require('../../lib/errorHandlers/index');
const { handleExit, handleKeypress } = require('../../lib/process');
const { getThemeJSONPath } = require('@hubspot/local-dev-lib/cms/themes');
const { getProjectConfig } = require('../../lib/projects');
const {
findProjectComponents,
COMPONENT_TYPES,
} = require('../../lib/projects/structure');
const { findProjectComponents } = require('../../lib/projects/structure');
const { ComponentTypes } = require('../../types/Projects');
const { preview } = require('@hubspot/theme-preview-dev-server');
const { hasFeature } = require('../../lib/hasFeature');
const i18nKey = 'commands.theme.subcommands.preview';
Expand Down Expand Up @@ -85,7 +83,7 @@ const determineSrcAndDest = async options => {
if (!themeJsonPath) {
const projectComponents = await findProjectComponents(projectDir);
const themeComponents = projectComponents.filter(
c => c.type === COMPONENT_TYPES.hublTheme
c => c.type === ComponentTypes.HublTheme
);
if (themeComponents.length === 0) {
logger.error(i18n(`${i18nKey}.errors.noThemeComponents`));
Expand Down
4 changes: 4 additions & 0 deletions lang/en.lyaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ en:
cliUpdateNotification: "HubSpot CLI version {{#cyan}}{{#bold}}{currentVersion}{{/bold}}{{/cyan}} is outdated.\nRun {{ updateCommand }} to upgrade to version {{#cyan}}{{#bold}}{latestVersion}{{/bold}}{{/cyan}}"
srcIsProject: "\"{{ src }}\" is in a project folder. Did you mean \"hs project {{command}}\"?"
setDefaultAccountMoved: "This command has moved. Try `hs accounts use` instead"
handleDeprecatedEnvVariables:
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."
completion:
Expand Down Expand Up @@ -1418,6 +1420,7 @@ en:
failure:
invalidUser: "Couldn't create {{#bold}}{{ accountName }}{{/bold}} because your account has been removed from {{#bold}}{{ parentAccountName }}{{/bold}} or your permission set doesn't allow you to create the sandbox. To update your permissions, contact a super admin in {{#bold}}{{ parentAccountName }}{{/bold}}."
403Gating: "Couldn't create {{#bold}}{{ accountName }}{{/bold}} because {{#bold}}{{ parentAccountName }}{{/bold}} does not have access to development sandboxes. To opt in to the CRM Development Beta and use development sandboxes, visit https://app.hubspot.com/l/product-updates/in-beta?update=13899236."
usageLimitsFetch: "Unable to fetch sandbox usage limits. Please try again."
limit:
developer:
one: "{{#bold}}{{ accountName }}{{/bold}} reached the limit of {{ limit }} development sandbox.
Expand Down Expand Up @@ -1477,6 +1480,7 @@ en:
syncInProgress: "Couldn't run the sync because there's another sync in progress. Wait for the current sync to finish and then try again. To check the sync status, visit the sync activity log: {{ url }}."
notSuperAdmin: "Couldn't run the sync because you are not a super admin in {{ account }}. Ask the account owner for super admin access to the sandbox."
objectNotFound: "Couldn't sync the sandbox because {{#bold}}{{ account }}{{/bold}} may have been deleted through the UI. Run {{#bold}}hs sandbox delete{{/bold}} to remove this account from the config. "
syncTypeFetch: "Unable to fetch available sandbox sync types. Please try again."
errorHandlers:
index:
errorOccurred: "Error: {{ error }}"
Expand Down
116 changes: 88 additions & 28 deletions lib/DevServerManager.ts
Original file line number Diff line number Diff line change
@@ -1,48 +1,77 @@
// @ts-nocheck
const { logger } = require('@hubspot/local-dev-lib/logger');
const { COMPONENT_TYPES } = require('./projects/structure');
const { i18n } = require('./lang');
const { promptUser } = require('./prompts/promptUtils');
const { DevModeInterface } = require('@hubspot/ui-extensions-dev-server');
const {
import { logger } from '@hubspot/local-dev-lib/logger';
import { Environment } from '@hubspot/local-dev-lib/types/Config';
import { i18n } from './lang';
import { promptUser } from './prompts/promptUtils';
import { DevModeInterface as UIEDevModeInterface } from '@hubspot/ui-extensions-dev-server';
import {
startPortManagerServer,
stopPortManagerServer,
requestPorts,
} = require('@hubspot/local-dev-lib/portManager');
const {
} from '@hubspot/local-dev-lib/portManager';
import {
getHubSpotApiOrigin,
getHubSpotWebsiteOrigin,
} = require('@hubspot/local-dev-lib/urls');
const { getAccountConfig } = require('@hubspot/local-dev-lib/config');
} from '@hubspot/local-dev-lib/urls';
import { getAccountConfig } from '@hubspot/local-dev-lib/config';
import { ProjectConfig, ComponentTypes, Component } from '../types/Projects';

const i18nKey = 'lib.DevServerManager';

const SERVER_KEYS = {
privateApp: 'privateApp',
publicApp: 'publicApp',
} as const;

type ServerKey = keyof typeof SERVER_KEYS;

type DevServerInterface = {
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
setup?: Function;
start?: (options: object) => Promise<void>;
fileChange?: (filePath: string, event: string) => Promise<void>;
cleanup?: () => Promise<void>;
};

type DevServer = {
componentType: ComponentTypes;
serverInterface: DevServerInterface;
};

type ComponentsByType = {
[key in ComponentTypes]?: { [key: string]: Component };
};

class DevServerManager {
private initialized: boolean;
private started: boolean;
private componentsByType: ComponentsByType;
private devServers: { [key in ServerKey]: DevServer };

constructor() {
this.initialized = false;
this.started = false;
this.componentsByType = {};
this.server = null;
this.path = null;
this.devServers = {
[SERVER_KEYS.privateApp]: {
componentType: COMPONENT_TYPES.privateApp,
serverInterface: DevModeInterface,
componentType: ComponentTypes.PrivateApp,
serverInterface: UIEDevModeInterface,
},
[SERVER_KEYS.publicApp]: {
componentType: COMPONENT_TYPES.publicApp,
serverInterface: DevModeInterface,
componentType: ComponentTypes.PublicApp,
serverInterface: UIEDevModeInterface,
},
};
}

async iterateDevServers(callback) {
const serverKeys = Object.keys(this.devServers);
async iterateDevServers(
callback: (
serverInterface: DevServerInterface,
compatibleComponents: {
[key: string]: Component;
}
) => Promise<void>
): Promise<void> {
const serverKeys: ServerKey[] = Object.keys(this.devServers) as ServerKey[];

for (let i = 0; i < serverKeys.length; i++) {
const serverKey = serverKeys[i];
Expand All @@ -59,21 +88,37 @@ class DevServerManager {
}
}

arrangeComponentsByType(components) {
return components.reduce((acc, component) => {
arrangeComponentsByType(components: Component[]): ComponentsByType {
return components.reduce<ComponentsByType>((acc, component) => {
if (!acc[component.type]) {
acc[component.type] = {};
}

acc[component.type][component.config.name] = component;
if ('name' in component.config && component.config.name) {
acc[component.type]![component.config.name] = component;
}

return acc;
}, {});
}

async setup({ components, onUploadRequired, accountId, setActiveApp }) {
async setup({
components,
onUploadRequired,
accountId,
setActiveApp,
}: {
components: Component[];
onUploadRequired: () => void;
accountId: number;
setActiveApp: (appUid: string | undefined) => Promise<void>;
}): Promise<void> {
this.componentsByType = this.arrangeComponentsByType(components);
const { env } = getAccountConfig(accountId);
let env: Environment;
const accountConfig = getAccountConfig(accountId);
if (accountConfig) {
env = accountConfig.env;
}
await startPortManagerServer();
await this.iterateDevServers(
async (serverInterface, compatibleComponents) => {
Expand All @@ -96,7 +141,13 @@ class DevServerManager {
this.initialized = true;
}

async start({ accountId, projectConfig }) {
async start({
accountId,
projectConfig,
}: {
accountId: number;
projectConfig: ProjectConfig;
}): Promise<void> {
if (this.initialized) {
await this.iterateDevServers(async serverInterface => {
if (serverInterface.start) {
Expand All @@ -114,7 +165,13 @@ class DevServerManager {
this.started = true;
}

fileChange({ filePath, event }) {
async fileChange({
filePath,
event,
}: {
filePath: string;
event: string;
}): Promise<void> {
if (this.started) {
this.iterateDevServers(async serverInterface => {
if (serverInterface.fileChange) {
Expand All @@ -124,7 +181,7 @@ class DevServerManager {
}
}

async cleanup() {
async cleanup(): Promise<void> {
if (this.started) {
await this.iterateDevServers(async serverInterface => {
if (serverInterface.cleanup) {
Expand All @@ -137,4 +194,7 @@ class DevServerManager {
}
}

module.exports = new DevServerManager();
const Manager = new DevServerManager();

export default Manager;
module.exports = Manager;
Loading

0 comments on commit bca759e

Please sign in to comment.