@@ -4,6 +4,7 @@ import * as chalk from 'chalk';
4
4
import * as chokidar from 'chokidar' ;
5
5
import * as fs from 'fs-extra' ;
6
6
import { ToolkitServices } from './private' ;
7
+ import { formatErrorMessage } from '../../../../aws-cdk/lib/util/error' ;
7
8
import { AssetBuildTime , DeployOptions , RequireApproval } from '../actions/deploy' ;
8
9
import { buildParameterMap , removePublishedAssets } from '../actions/deploy/private' ;
9
10
import { DestroyOptions } from '../actions/destroy' ;
@@ -349,7 +350,7 @@ export class Toolkit extends CloudAssemblySourceBuilder implements AsyncDisposab
349
350
stack,
350
351
deployName : stack . stackName ,
351
352
roleArn : options . roleArn ,
352
- toolkitStackName : options . toolkitStackName ,
353
+ toolkitStackName : this . toolkitStackName ,
353
354
reuseAssets : options . reuseAssets ,
354
355
notificationArns,
355
356
tags,
@@ -616,16 +617,46 @@ export class Toolkit extends CloudAssemblySourceBuilder implements AsyncDisposab
616
617
const ioHost = withAction ( this . ioHost , 'rollback' ) ;
617
618
const timer = Timer . start ( ) ;
618
619
const assembly = await this . assemblyFromSource ( cx ) ;
619
- const stacks = await assembly . selectStacksV2 ( options . stacks ) ;
620
+ const stacks = assembly . selectStacksV2 ( options . stacks ) ;
620
621
await this . validateStacksMetadata ( stacks , ioHost ) ;
621
622
const synthTime = timer . end ( ) ;
622
623
await ioHost . notify ( info ( `\n✨ Synthesis time: ${ synthTime . asSec } s\n` , 'CDK_TOOLKIT_I5001' , {
623
624
time : synthTime . asMs ,
624
625
} ) ) ;
625
626
626
- // temporary
627
- // eslint-disable-next-line @cdklabs/no-throw-default-error
628
- throw new Error ( 'Not implemented yet' ) ;
627
+ if ( stacks . stackCount === 0 ) {
628
+ await ioHost . notify ( error ( 'No stacks selected' ) ) ;
629
+ return ;
630
+ }
631
+
632
+ let anyRollbackable = false ;
633
+
634
+ for ( const stack of stacks . stackArtifacts ) {
635
+ await ioHost . notify ( info ( `Rolling back ${ chalk . bold ( stack . displayName ) } ` ) ) ;
636
+ const startRollbackTime = Timer . start ( ) ;
637
+ const deployments = await this . deploymentsForAction ( 'rollback' ) ;
638
+ try {
639
+ const result = await deployments . rollbackStack ( {
640
+ stack,
641
+ roleArn : options . roleArn ,
642
+ toolkitStackName : this . toolkitStackName ,
643
+ force : options . orphanFailedResources ,
644
+ validateBootstrapStackVersion : options . validateBootstrapStackVersion ,
645
+ orphanLogicalIds : options . orphanLogicalIds ,
646
+ } ) ;
647
+ if ( ! result . notInRollbackableState ) {
648
+ anyRollbackable = true ;
649
+ }
650
+ const elapsedRollbackTime = startRollbackTime . end ( ) ;
651
+ await ioHost . notify ( info ( `\n✨ Rollback time: ${ elapsedRollbackTime . asSec } s\n` ) ) ;
652
+ } catch ( e : any ) {
653
+ await ioHost . notify ( error ( `\n ❌ ${ chalk . bold ( stack . displayName ) } failed: ${ formatErrorMessage ( e ) } ` ) ) ;
654
+ throw new ToolkitError ( 'Rollback failed (use --force to orphan failing resources)' ) ;
655
+ }
656
+ }
657
+ if ( ! anyRollbackable ) {
658
+ throw new ToolkitError ( 'No stacks were in a state that could be rolled back' ) ;
659
+ }
629
660
}
630
661
631
662
/**
0 commit comments