diff --git a/packages/@aws-cdk/tmp-toolkit-helpers/src/api/io/private/messages.ts b/packages/@aws-cdk/tmp-toolkit-helpers/src/api/io/private/messages.ts index ae5f57507..ba76c81c8 100644 --- a/packages/@aws-cdk/tmp-toolkit-helpers/src/api/io/private/messages.ts +++ b/packages/@aws-cdk/tmp-toolkit-helpers/src/api/io/private/messages.ts @@ -74,9 +74,10 @@ export const IO = { }), // 3: Import & Migrate - CDK_TOOLKIT_E3900: make.error({ + CDK_TOOLKIT_E3900: make.error({ code: 'CDK_TOOLKIT_E3900', description: 'Resource import failed', + interface: 'ErrorPayload', }), // 4: Diff (4xxx) @@ -92,9 +93,10 @@ export const IO = { description: 'Provides total time in deploy action, including synth and rollback', interface: 'Duration', }), - CDK_TOOLKIT_I5002: make.info({ + CDK_TOOLKIT_I5002: make.info({ code: 'CDK_TOOLKIT_I5002', description: 'Provides time for resource migration', + interface: 'Duration', }), CDK_TOOLKIT_W5021: make.warn({ code: 'CDK_TOOLKIT_W5021', diff --git a/packages/@aws-cdk/toolkit-lib/docs/message-registry.md b/packages/@aws-cdk/toolkit-lib/docs/message-registry.md index ec488a8bb..befcd4be8 100644 --- a/packages/@aws-cdk/toolkit-lib/docs/message-registry.md +++ b/packages/@aws-cdk/toolkit-lib/docs/message-registry.md @@ -16,10 +16,10 @@ group: Documents | `CDK_TOOLKIT_I1901` | Provides stack data | `result` | {@link StackAndAssemblyData} | | `CDK_TOOLKIT_I1902` | Successfully deployed stacks | `result` | {@link AssemblyData} | | `CDK_TOOLKIT_I2901` | Provides details on the selected stacks and their dependencies | `result` | {@link StackDetailsPayload} | -| `CDK_TOOLKIT_E3900` | Resource import failed | `error` | n/a | +| `CDK_TOOLKIT_E3900` | Resource import failed | `error` | {@link ErrorPayload} | | `CDK_TOOLKIT_I5000` | Provides deployment times | `info` | {@link Duration} | | `CDK_TOOLKIT_I5001` | Provides total time in deploy action, including synth and rollback | `info` | {@link Duration} | -| `CDK_TOOLKIT_I5002` | Provides time for resource migration | `info` | n/a | +| `CDK_TOOLKIT_I5002` | Provides time for resource migration | `info` | {@link Duration} | | `CDK_TOOLKIT_W5021` | Empty non-existent stack, deployment is skipped | `warn` | n/a | | `CDK_TOOLKIT_W5022` | Empty existing stack, stack will be destroyed | `warn` | n/a | | `CDK_TOOLKIT_I5031` | Informs about any log groups that are traced as part of the deployment | `info` | n/a | diff --git a/packages/aws-cdk/lib/api/bootstrap/bootstrap-environment.ts b/packages/aws-cdk/lib/api/bootstrap/bootstrap-environment.ts index f32fdaa68..7a731974f 100644 --- a/packages/aws-cdk/lib/api/bootstrap/bootstrap-environment.ts +++ b/packages/aws-cdk/lib/api/bootstrap/bootstrap-environment.ts @@ -1,12 +1,10 @@ -import { info } from 'console'; import * as path from 'path'; import type * as cxapi from '@aws-cdk/cx-api'; import type { BootstrapEnvironmentOptions, BootstrappingParameters } from './bootstrap-props'; import { BootstrapStack, bootstrapVersionFromTemplate } from './deploy-bootstrap'; import { legacyBootstrapTemplate } from './legacy-template'; import { ToolkitError } from '../../../../@aws-cdk/tmp-toolkit-helpers/src/api'; -import type { IoHelper } from '../../../../@aws-cdk/tmp-toolkit-helpers/src/api/io/private'; -import { warn } from '../../cli/messages'; +import { IO, type IoHelper } from '../../../../@aws-cdk/tmp-toolkit-helpers/src/api/io/private'; import { bundledPackageRootDir, loadStructuredFile, serializeStructure } from '../../util'; import type { SDK, SdkProvider } from '../aws-auth'; import type { SuccessfulDeployStackResult } from '../deployments'; @@ -125,14 +123,16 @@ export class Bootstrapper { accounts.filter(acc => !params.untrustedAccounts?.map(String).includes(String(acc))); const trustedAccounts = removeUntrusted(params.trustedAccounts ?? splitCfnArray(current.parameters.TrustedAccounts)); - info(`Trusted accounts for deployment: ${trustedAccounts.length > 0 ? trustedAccounts.join(', ') : '(none)'}`); + await this.ioHelper.notify(IO.DEFAULT_TOOLKIT_INFO.msg( + `Trusted accounts for deployment: ${trustedAccounts.length > 0 ? trustedAccounts.join(', ') : '(none)'}`, + )); const trustedAccountsForLookup = removeUntrusted( params.trustedAccountsForLookup ?? splitCfnArray(current.parameters.TrustedAccountsForLookup), ); - info( + await this.ioHelper.notify(IO.DEFAULT_TOOLKIT_INFO.msg( `Trusted accounts for lookup: ${trustedAccountsForLookup.length > 0 ? trustedAccountsForLookup.join(', ') : '(none)'}`, - ); + )); const cloudFormationExecutionPolicies = params.cloudFormationExecutionPolicies ?? splitCfnArray(current.parameters.CloudFormationExecutionPolicies); @@ -151,7 +151,7 @@ export class Bootstrapper { // Would leave AdministratorAccess policies with a trust relationship, without the user explicitly // approving the trust policy. const implicitPolicy = `arn:${partition}:iam::aws:policy/AdministratorAccess`; - await this.ioHelper.notify(warn( + await this.ioHelper.notify(IO.DEFAULT_TOOLKIT_WARN.msg( `Using default execution policy of '${implicitPolicy}'. Pass '--cloudformation-execution-policies' to customize.`, )); } else if (cloudFormationExecutionPolicies.length === 0) { @@ -160,7 +160,7 @@ export class Bootstrapper { ); } else { // Remind people what the current settings are - info(`Execution policies: ${cloudFormationExecutionPolicies.join(', ')}`); + await this.ioHelper.notify(IO.DEFAULT_TOOLKIT_INFO.msg(`Execution policies: ${cloudFormationExecutionPolicies.join(', ')}`)); } // * If an ARN is given, that ARN. Otherwise: @@ -199,15 +199,15 @@ export class Bootstrapper { } if (currentPermissionsBoundary !== policyName) { if (!currentPermissionsBoundary) { - await this.ioHelper.notify(warn( + await this.ioHelper.notify(IO.DEFAULT_TOOLKIT_WARN.msg( `Adding new permissions boundary ${policyName}`, )); } else if (!policyName) { - await this.ioHelper.notify(warn( + await this.ioHelper.notify(IO.DEFAULT_TOOLKIT_WARN.msg( `Removing existing permissions boundary ${currentPermissionsBoundary}`, )); } else { - await this.ioHelper.notify(warn( + await this.ioHelper.notify(IO.DEFAULT_TOOLKIT_WARN.msg( `Changing permissions boundary from ${currentPermissionsBoundary} to ${policyName}`, )); } diff --git a/packages/aws-cdk/lib/api/bootstrap/deploy-bootstrap.ts b/packages/aws-cdk/lib/api/bootstrap/deploy-bootstrap.ts index e6011e323..f29be758f 100644 --- a/packages/aws-cdk/lib/api/bootstrap/deploy-bootstrap.ts +++ b/packages/aws-cdk/lib/api/bootstrap/deploy-bootstrap.ts @@ -11,8 +11,7 @@ import { BOOTSTRAP_VERSION_RESOURCE, DEFAULT_BOOTSTRAP_VARIANT, } from './bootstrap-props'; -import type { IoHelper } from '../../../../@aws-cdk/tmp-toolkit-helpers/src/api/io/private'; -import { warn } from '../../cli/messages'; +import { IO, type IoHelper } from '../../../../@aws-cdk/tmp-toolkit-helpers/src/api/io/private'; import type { SDK, SdkProvider } from '../aws-auth'; import type { SuccessfulDeployStackResult } from '../deployments'; import { assertIsSuccessfulDeployStackResult } from '../deployments'; @@ -90,7 +89,7 @@ export class BootstrapStack { const currentVariant = this.currentToolkitInfo.variant; const newVariant = bootstrapVariantFromTemplate(template); if (currentVariant !== newVariant) { - await this.ioHelper.notify(warn( + await this.ioHelper.notify(IO.DEFAULT_TOOLKIT_WARN.msg( `Bootstrap stack already exists, containing '${currentVariant}'. Not overwriting it with a template containing '${newVariant}' (use --force if you intend to overwrite)`, )); return abortResponse; @@ -100,13 +99,13 @@ export class BootstrapStack { const newVersion = bootstrapVersionFromTemplate(template); const currentVersion = this.currentToolkitInfo.version; if (newVersion < currentVersion) { - await this.ioHelper.notify(warn( + await this.ioHelper.notify(IO.DEFAULT_TOOLKIT_WARN.msg( `Bootstrap stack already at version ${currentVersion}. Not downgrading it to version ${newVersion} (use --force if you intend to downgrade)`, )); if (newVersion === 0) { // A downgrade with 0 as target version means we probably have a new-style bootstrap in the account, // and an old-style bootstrap as current target, which means the user probably forgot to put this flag in. - await this.ioHelper.notify(warn( + await this.ioHelper.notify(IO.DEFAULT_TOOLKIT_WARN.msg( "(Did you set the '@aws-cdk/core:newStyleStackSynthesis' feature flag in cdk.json?)", )); } diff --git a/packages/aws-cdk/lib/api/deployments/assets.ts b/packages/aws-cdk/lib/api/deployments/assets.ts index 62fcd0578..f0c1fd727 100644 --- a/packages/aws-cdk/lib/api/deployments/assets.ts +++ b/packages/aws-cdk/lib/api/deployments/assets.ts @@ -5,8 +5,7 @@ import * as cxapi from '@aws-cdk/cx-api'; import * as chalk from 'chalk'; import type { AssetManifestBuilder } from './asset-manifest-builder'; import { ToolkitError } from '../../../../@aws-cdk/tmp-toolkit-helpers/src/api'; -import type { IoHelper } from '../../../../@aws-cdk/tmp-toolkit-helpers/src/api/io/private'; -import { debug } from '../../cli/messages'; +import { IO, type IoHelper } from '../../../../@aws-cdk/tmp-toolkit-helpers/src/api/io/private'; import type { EnvironmentResources } from '../environment'; import type { ToolkitInfo } from '../toolkit-info'; @@ -44,11 +43,11 @@ export async function addMetadataAssetsToManifest( const reuseAsset = reuse.indexOf(asset.id) > -1; if (reuseAsset) { - await ioHelper.notify(debug(`Reusing asset ${asset.id}: ${JSON.stringify(asset)}`)); + await ioHelper.notify(IO.DEFAULT_TOOLKIT_DEBUG.msg(`Reusing asset ${asset.id}: ${JSON.stringify(asset)}`)); continue; } - await ioHelper.notify(debug(`Preparing asset ${asset.id}: ${JSON.stringify(asset)}`)); + await ioHelper.notify(IO.DEFAULT_TOOLKIT_DEBUG.msg(`Preparing asset ${asset.id}: ${JSON.stringify(asset)}`)); if (!stack.assembly) { throw new ToolkitError('Unexpected: stack assembly is required in order to find assets in assembly directory'); } @@ -98,7 +97,7 @@ async function prepareFileAsset( const key = `${s3Prefix}${baseName}`; const s3url = `s3://${toolkitInfo.bucketName}/${key}`; - await ioHelper.notify(debug(`Storing asset ${asset.path} at ${s3url}`)); + await ioHelper.notify(IO.DEFAULT_TOOLKIT_DEBUG.msg(`Storing asset ${asset.path} at ${s3url}`)); assetManifest.addFileAsset(asset.sourceHash, { path: asset.path, diff --git a/packages/aws-cdk/lib/api/deployments/checks.ts b/packages/aws-cdk/lib/api/deployments/checks.ts index e57e1d6e4..63ee6f40b 100644 --- a/packages/aws-cdk/lib/api/deployments/checks.ts +++ b/packages/aws-cdk/lib/api/deployments/checks.ts @@ -1,6 +1,5 @@ import { ToolkitError } from '../../../../@aws-cdk/tmp-toolkit-helpers/src/api'; -import type { IoHelper } from '../../../../@aws-cdk/tmp-toolkit-helpers/src/api/io/private'; -import { debug } from '../../cli/messages'; +import { IO, type IoHelper } from '../../../../@aws-cdk/tmp-toolkit-helpers/src/api/io/private'; import type { SDK } from '../aws-auth'; export async function determineAllowCrossAccountAssetPublishing( @@ -34,8 +33,8 @@ export async function determineAllowCrossAccountAssetPublishing( // of creating bootstrap resources. If they do, there's nothing for us to validate, // but we can't use that as a reason to disallow cross-account publishing. We'll just // have to trust they did their due diligence. So we fail open. - await ioHelper.notify(debug(`Error determining cross account asset publishing: ${e}`)); - await ioHelper.notify(debug('Defaulting to allowing cross account asset publishing')); + await ioHelper.notify(IO.DEFAULT_TOOLKIT_DEBUG.msg(`Error determining cross account asset publishing: ${e}`)); + await ioHelper.notify(IO.DEFAULT_TOOLKIT_DEBUG.msg('Defaulting to allowing cross account asset publishing')); return true; } } diff --git a/packages/aws-cdk/lib/api/deployments/cloudformation.ts b/packages/aws-cdk/lib/api/deployments/cloudformation.ts index 7375d3287..290a312d7 100644 --- a/packages/aws-cdk/lib/api/deployments/cloudformation.ts +++ b/packages/aws-cdk/lib/api/deployments/cloudformation.ts @@ -15,8 +15,7 @@ import { AssetManifest } from 'cdk-assets'; import { AssetManifestBuilder } from './asset-manifest-builder'; import type { Deployments } from './deployments'; import { ToolkitError } from '../../../../@aws-cdk/tmp-toolkit-helpers/src/api'; -import type { IoHelper } from '../../../../@aws-cdk/tmp-toolkit-helpers/src/api/io/private'; -import { debug } from '../../cli/messages'; +import { IO, type IoHelper } from '../../../../@aws-cdk/tmp-toolkit-helpers/src/api/io/private'; import { formatErrorMessage, deserializeStructure } from '../../util'; import type { ICloudFormationClient, SdkProvider } from '../aws-auth'; import { StackStatus } from '../stack-events'; @@ -295,7 +294,7 @@ export async function waitForChangeSet( changeSetName: string, { fetchAll }: { fetchAll: boolean }, ): Promise { - await ioHelper.notify(debug(format('Waiting for changeset %s on stack %s to finish creating...', changeSetName, stackName))); + await ioHelper.notify(IO.DEFAULT_TOOLKIT_DEBUG.msg(format('Waiting for changeset %s on stack %s to finish creating...', changeSetName, stackName))); const ret = await waitFor(async () => { const description = await describeChangeSet(cfn, stackName, changeSetName, { fetchAll, @@ -303,7 +302,7 @@ export async function waitForChangeSet( // The following doesn't use a switch because tsc will not allow fall-through, UNLESS it is allows // EVERYWHERE that uses this library directly or indirectly, which is undesirable. if (description.Status === 'CREATE_PENDING' || description.Status === 'CREATE_IN_PROGRESS') { - await ioHelper.notify(debug(format('Changeset %s on stack %s is still creating', changeSetName, stackName))); + await ioHelper.notify(IO.DEFAULT_TOOLKIT_DEBUG.msg(format('Changeset %s on stack %s is still creating', changeSetName, stackName))); return undefined; } @@ -360,7 +359,7 @@ export async function createDiffChangeSet( // This causes CreateChangeSet to fail with `Template Error: Fn::Equals cannot be partially collapsed`. for (const resource of Object.values(options.stack.template.Resources ?? {})) { if ((resource as any).Type === 'AWS::CloudFormation::Stack') { - await ioHelper.notify(debug('This stack contains one or more nested stacks, falling back to template-only diff...')); + await ioHelper.notify(IO.DEFAULT_TOOLKIT_DEBUG.msg('This stack contains one or more nested stacks, falling back to template-only diff...')); return undefined; } @@ -430,7 +429,7 @@ async function uploadBodyParameterAndCreateChangeSet( role: executionRoleArn, }); } catch (e: any) { - await ioHelper.notify(debug(e)); + await ioHelper.notify(IO.DEFAULT_TOOLKIT_DEBUG.msg(e)); options.stream.write( 'Could not create a change set, will base the diff on template differences (run again with -v to see the reason)\n', ); @@ -472,7 +471,7 @@ export async function createChangeSet( ): Promise { await cleanupOldChangeset(options.cfn, ioHelper, options.changeSetName, options.stack.stackName); - await ioHelper.notify(debug(`Attempting to create ChangeSet with name ${options.changeSetName} for stack ${options.stack.stackName}`)); + await ioHelper.notify(IO.DEFAULT_TOOLKIT_DEBUG.msg(`Attempting to create ChangeSet with name ${options.changeSetName} for stack ${options.stack.stackName}`)); const templateParams = TemplateParameters.fromTemplate(options.stack.template); const stackParams = templateParams.supplyAll(options.parameters); @@ -492,7 +491,7 @@ export async function createChangeSet( Capabilities: ['CAPABILITY_IAM', 'CAPABILITY_NAMED_IAM', 'CAPABILITY_AUTO_EXPAND'], }); - await ioHelper.notify(debug(format('Initiated creation of changeset: %s; waiting for it to finish creating...', changeSet.Id))); + await ioHelper.notify(IO.DEFAULT_TOOLKIT_DEBUG.msg(format('Initiated creation of changeset: %s; waiting for it to finish creating...', changeSet.Id))); // Fetching all pages if we'll execute, so we can have the correct change count when monitoring. const createdChangeSet = await waitForChangeSet(options.cfn, ioHelper, options.stack.stackName, options.changeSetName, { fetchAll: options.willExecute, @@ -517,7 +516,7 @@ async function cleanupOldChangeset( ) { // Delete any existing change sets generated by CDK since change set names must be unique. // The delete request is successful as long as the stack exists (even if the change set does not exist). - await ioHelper.notify(debug(`Removing existing change set with name ${changeSetName} if it exists`)); + await ioHelper.notify(IO.DEFAULT_TOOLKIT_DEBUG.msg(`Removing existing change set with name ${changeSetName} if it exists`)); await cfn.deleteChangeSet({ StackName: stackName, ChangeSetName: changeSetName, @@ -619,16 +618,16 @@ export async function stabilizeStack( ioHelper: IoHelper, stackName: string, ) { - await ioHelper.notify(debug(format('Waiting for stack %s to finish creating or updating...', stackName))); + await ioHelper.notify(IO.DEFAULT_TOOLKIT_DEBUG.msg(format('Waiting for stack %s to finish creating or updating...', stackName))); return waitFor(async () => { const stack = await CloudFormationStack.lookup(cfn, stackName); if (!stack.exists) { - await ioHelper.notify(debug(format('Stack %s does not exist', stackName))); + await ioHelper.notify(IO.DEFAULT_TOOLKIT_DEBUG.msg(format('Stack %s does not exist', stackName))); return null; } const status = stack.stackStatus; if (status.isInProgress) { - await ioHelper.notify(debug(format('Stack %s has an ongoing operation in progress and is not stable (%s)', stackName, status))); + await ioHelper.notify(IO.DEFAULT_TOOLKIT_DEBUG.msg(format('Stack %s has an ongoing operation in progress and is not stable (%s)', stackName, status))); return undefined; } else if (status.isReviewInProgress) { // This may happen if a stack creation operation is interrupted before the ChangeSet execution starts. Recovering @@ -637,7 +636,7 @@ export async function stabilizeStack( // "forever" we proceed as if the stack was existing and stable. If there is a concurrent operation that just // hasn't finished proceeding just yet, either this operation or the concurrent one may fail due to the other one // having made progress. Which is fine. I guess. - await ioHelper.notify(debug(format('Stack %s is in REVIEW_IN_PROGRESS state. Considering this is a stable status (%s)', stackName, status))); + await ioHelper.notify(IO.DEFAULT_TOOLKIT_DEBUG.msg(format('Stack %s is in REVIEW_IN_PROGRESS state. Considering this is a stable status (%s)', stackName, status))); } return stack; diff --git a/packages/aws-cdk/lib/api/deployments/deployments.ts b/packages/aws-cdk/lib/api/deployments/deployments.ts index fe664a391..c4bf1e83b 100644 --- a/packages/aws-cdk/lib/api/deployments/deployments.ts +++ b/packages/aws-cdk/lib/api/deployments/deployments.ts @@ -27,8 +27,7 @@ import { type RootTemplateWithNestedStacks, } from './nested-stack-helpers'; import { ToolkitError } from '../../../../@aws-cdk/tmp-toolkit-helpers/src/api'; -import type { IoHelper } from '../../../../@aws-cdk/tmp-toolkit-helpers/src/api/io/private'; -import { debug, warn } from '../../cli/messages'; +import { IO, type IoHelper } from '../../../../@aws-cdk/tmp-toolkit-helpers/src/api/io/private'; import { formatErrorMessage } from '../../util'; import type { SdkProvider } from '../aws-auth/sdk-provider'; import { type EnvironmentResources, EnvironmentAccess } from '../environment'; @@ -362,7 +361,7 @@ export class Deployments { } public async readCurrentTemplate(stackArtifact: cxapi.CloudFormationStackArtifact): Promise