Skip to content

Commit

Permalink
Merge branch 'main' into br/remove-account-util
Browse files Browse the repository at this point in the history
  • Loading branch information
brandenrodgers committed Jan 17, 2025
2 parents 5dc138b + 40afea2 commit 1eef132
Show file tree
Hide file tree
Showing 23 changed files with 617 additions and 690 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
8 changes: 1 addition & 7 deletions commands/logs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,7 @@ const endpointLog = async (accountId, functionPath, options) => {
}
};

await tailLogs({
accountId,
compact,
tailCall,
fetchLatest,
name: functionPath,
});
await tailLogs(accountId, functionPath, fetchLatest, tailCall, compact);
} else if (latest) {
try {
const { data } = await getLatestFunctionLog(accountId, functionPath);
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
29 changes: 12 additions & 17 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 All @@ -28,7 +28,7 @@ const {
HUBSPOT_ACCOUNT_TYPES,
HUBSPOT_ACCOUNT_TYPE_STRINGS,
} = require('@hubspot/local-dev-lib/constants/config');
const { buildNewAccount } = require('../../lib/buildAccount');
const { buildSandbox } = require('../../lib/buildAccount');
const {
hubspotAccountNamePrompt,
} = require('../../lib/prompts/accountNamePrompt');
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 @@ -130,23 +130,18 @@ exports.handler = async options => {
}

try {
const { result } = await buildNewAccount({
name: sandboxName,
accountType: sandboxType,
const result = await buildSandbox(
sandboxName,
accountConfig,
sandboxType,
env,
force,
});
force
);

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
8 changes: 5 additions & 3 deletions lang/en.lyaml
Original file line number Diff line number Diff line change
Expand Up @@ -972,7 +972,7 @@ en:
convertFields:
describe: "If true, converts any javascript fields files contained in module folder or project root."
clean:
describe: "Will cause upload to delete files in your HubSpot account that are not found locally."
describe: "Will delete the destination directory and its contents before uploading. This will also clear the global content associated with any global partial templates and modules."
force:
describe: "Skips confirmation prompts when doing a clean upload."
previewUrl: "To preview this theme, visit: {{ previewUrl }}"
Expand All @@ -987,7 +987,7 @@ en:
uploading: "Uploading files from \"{{ src }}\" to \"{{ dest }}\" in the Design Manager of account {{ accountId }}"
notUploaded: "There was an error processing \"{{ src }}\". The file has not been uploaded."
cleaning: "Removing \"{{ filePath }}\" from account {{ accountId }} and uploading local..."
confirmCleanUpload: "You are about to remove any remote files in \"{{ filePath }}\" on HubSpot account {{ accountId }} that don't exist locally. Are you sure you want to do this?"
confirmCleanUpload: "You are about to delete the directory \"{{ filePath }}\" and its contents on HubSpot account {{ accountId }} before uploading. This will also clear the global content associated with any global partial templates and modules. Are you sure you want to do this?"
watch:
describe: "Watch a directory on your computer for changes and upload the changed files to the HubSpot CMS."
errors:
Expand Down Expand Up @@ -1420,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 @@ -1479,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 All @@ -1497,7 +1499,7 @@ en:
missingScopeError: "Couldn't execute the {{ request }} because the access key for {{ accountName }} is missing required scopes. To update scopes, run {{ authCommand }}. Then deactivate the existing key and generate a new one that includes the missing scopes."
serverless:
verifyAccessKeyAndUserAccess:
fetchScopeDataError: "Error verifying access of scopeGroup {{ scopeGroup }}: {{ error }}"
fetchScopeDataError: "Error verifying access of scopeGroup {{ scopeGroup }}:"
portalMissingScope: "Your account does not have access to this action. Talk to an account admin to request it."
userMissingScope: "You don't have access to this action. Ask an account admin to change your permissions in Users & Teams settings."
genericMissingScope: "Your access key does not allow this action. Please generate a new access key by running `hs auth personalaccesskey`."
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 1eef132

Please sign in to comment.