Skip to content

Conversation

camden11
Copy link
Contributor

@camden11 camden11 commented Feb 3, 2025

Description and Context

This PR rebuilds the config module from the ground up. The new config module has a variety of improvements over the old one:

  • Combines the functionality of the old config/config and config/CLIConfiguration into a single file.
  • Supports both global and local config files
  • Reads configs with both the current account fields and deprecated portal fields, but converts them into a standardized format (no need to check portalId vs accountId anymore)
  • No longer loads config files into a JS object instance - instead treats the config file as the single source of truth. This means we will no longer run into issues when different dependencies of the CLI use different LDL vesions
  • Safer and more usable type system - most functions are guaranteed to return the expected type (or throw) and more fields on the HubSpotConfig and HubSpotConfigAccount types are guaranteed to exist. No more checking for null and undefined everywhere!
  • Renames many functions for clarity
  • Simpler, more streamlined setup within the repo - there are now only two three config files (added one for defaultAccountOverride stuff), down from five. config/index contains all exported functionality, and config/utils contains all non-exported helper functions
  • ... and probably more that I'm not thinking of

Note: the majority of new functionality is in config/index and config/utils, both of which are hidden by default

TODO

  • This will require a substantial update to the CLI to maintain compatibility with the breaking changes here
  • I haven't yet merged in the account override work since it appears to still be in flux. Will be working with @kemmerle on that. Default account override functionality added
  • There are still a few exported instances in LDL, namely OAuth2Manager and logger. We will need to take care of those too, but I figured this PR is big enough as is

Who to Notify

@joe-yeager @brandenrodgers @kemmerle

@camden11 camden11 changed the title Dynamic config Config Revamp Feb 12, 2025

Returns config data for a specific account, given the account's ID or name.

## Example config
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I updated the existing content of the readme to reflect the changes I made, but it may make sense to rethink it completely

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah good call. That could always be done as a follow up

@@ -1,268 +1,406 @@
import * as config_DEPRECATED from './config_DEPRECATED';
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file is more or less net new, but because it has the same name as the old one, GH is showing a diff.

}
return config_DEPRECATED.deleteEmptyConfigFile();
export function getConfigFilePath(): string {
const { configFilePathFromEnvironment } = getConfigPathEnvironmentVariables();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getConfigFilePath checks for a HUBSPOT_CONFIG_PATH environment variable if the user is using a custom path - this variable will need to be set by the CLI if the user passes in the --config flag

if (CLIConfiguration.isActive()) {
return CLIConfiguration.config;
export function getConfig(): HubSpotConfig {
const { useEnvironmentConfig } = getConfigPathEnvironmentVariables();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same with environment config - a user passes in the --use-env flag to the CLI, the CLI should set the USE_ENVIRONMENT_CONFIG env variable to tell LDL to use environment variables. These new environment variables let us avoid needing to have configPath and useEnv arguments for every function that accesses the config

} else {
config_DEPRECATED.updateHttpTimeout(timeout);
export function updateConfigAccount(
updatedAccount: HubSpotConfigAccount
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function now accepts a full updated account rather than just fields to update. This makes it easier to use TS to confirm that updates are valid (for example, TS would have no way to know the auth type of the account you're trying to update, and therefore would allow updating accounts to have invalid auth)

export function updateConfigAccount(
updatedAccount: HubSpotConfigAccount
): void {
if (!isConfigAccountValid(updatedAccount)) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We still manually check validity just in case though!

HTTP_USE_LOCALHOST: 'HTTP_USE_LOCALHOST',
ALLOW_USAGE_TRACKING: 'ALLOW_USAGE_TRACKING',
DEFAULT_CMS_PUBLISH_MODE: 'DEFUALT_CMS_PUBLISH_MODE',
USE_ENVIRONMENT_CONFIG: 'USE_ENVIRONMENT_CONFIG',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Slight nit, but does it make sense for USE_ENVIRONMENT_CONFIG to include "hubspot" in the name somewhere? It doesn't matter a ton if the CLI is setting it, but I imagine people can also manually set this if they want to.

config/utils.ts Outdated

export function getConfigAccountIndexById(
accounts: Array<HubSpotConfigAccount>,
id: string | number
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible for accountId to be anything except for a number in this new format?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, this should just be number

config/utils.ts Outdated

return {
identifier: isId ? identifierAsNumber : accountIdentifier,
identifierType: isId ? 'accountId' : 'name',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a blocker, but could it potentially prevent some future pain by making these identifiers constants?

describe('writeConfigFile()', () => {
it('writes formatted config to file', () => {
// eslint-disable-next-line @typescript-eslint/no-empty-function
mockFs.ensureFileSync.mockImplementation(() => {});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a blocker, but you could get rid of the ignores if you make these return undefined instead

} from '../constants/config';
import { i18n } from '../utils/lang';
import { FileSystemError } from '../models/FileSystemError';
import { getAllConfigAccounts } from './index';
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I opted to move this stuff to its own file because it doesn't directly interact with the config file

Copy link
Contributor

@joe-yeager joe-yeager left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the new approach a lot!

@brandenrodgers
Copy link
Contributor

Code lgtm 👌 we should chat about what the rollout strategy looks like

...configOptions,
portalId: accountIdentifier,
});
export function getConfigAccountIfExists(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was reviewing one of your PR's in the CLI, and this util tripped me up a little. This is effectively the same functionality as getConfigAccountByInferredIdentifier. But the naming of this util doesn't make it clear that we're inferring the identifier.`

Also here's a relevant comment from a CLI PR

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants