@@ -869,8 +869,9 @@ function getShortResourceType(resourceType: string): string {
869869
870870/**
871871 * Create CDK-style progress callback
872+ * @param filter - Optional filter: 'delete' to only show DELETE events, 'create' for CREATE, etc.
872873 */
873- function createProgressCallback ( ) : ( event : {
874+ function createProgressCallback ( filter ?: 'delete' | 'create' | 'update' ) : ( event : {
874875 resourceId : string
875876 resourceType : string
876877 status : string
@@ -879,8 +880,27 @@ function createProgressCallback(): (event: {
879880} ) => void {
880881 const maxIdLength = 35
881882 const maxTypeLength = 30
883+ const seenEvents = new Set < string > ( )
882884
883885 return ( event ) => {
886+ // Filter events based on type if specified
887+ if ( filter === 'delete' && ! event . status . includes ( 'DELETE' ) ) {
888+ return
889+ }
890+ if ( filter === 'create' && ! event . status . includes ( 'CREATE' ) ) {
891+ return
892+ }
893+ if ( filter === 'update' && ! event . status . includes ( 'UPDATE' ) ) {
894+ return
895+ }
896+
897+ // Deduplicate events (same resource + status)
898+ const eventKey = `${ event . resourceId } :${ event . status } `
899+ if ( seenEvents . has ( eventKey ) ) {
900+ return
901+ }
902+ seenEvents . add ( eventKey )
903+
884904 const resourceId = event . resourceId . padEnd ( maxIdLength ) . substring ( 0 , maxIdLength )
885905 const resourceType = getShortResourceType ( event . resourceType ) . padEnd ( maxTypeLength ) . substring ( 0 , maxTypeLength )
886906 const status = formatResourceStatus ( event . status )
@@ -1333,9 +1353,8 @@ export async function undeployStack(options: UndeployStackOptions): Promise<void
13331353 const projectConfig = await getProjectConfig ( )
13341354 const stackName = `stacks-cloud-${ environment } `
13351355
1336- log . info ( `Undeploying infrastructure from ${ environment } in ${ region } ...` )
1337- log . info ( `Stack: ${ stackName } ` )
1338- log . info ( '' )
1356+ console . log ( `Undeploying ${ stackName } from ${ region } ...` )
1357+ console . log ( '' )
13391358
13401359 try {
13411360 const { CloudFormationClient, AWSClient } = await import ( 'ts-cloud/aws' )
@@ -1347,7 +1366,7 @@ export async function undeployStack(options: UndeployStackOptions): Promise<void
13471366 const describeResult = await cf . describeStacks ( { stackName } )
13481367 if ( describeResult . Stacks && describeResult . Stacks . length > 0 ) {
13491368 const stack = describeResult . Stacks [ 0 ]
1350- log . info ( `Current stack status: ${ formatResourceStatus ( stack . StackStatus ) } ` )
1369+ console . log ( `Current status: ${ formatResourceStatus ( stack . StackStatus ) } ` )
13511370 stackExists = true
13521371 }
13531372 }
@@ -1356,12 +1375,12 @@ export async function undeployStack(options: UndeployStackOptions): Promise<void
13561375 }
13571376
13581377 if ( ! stackExists ) {
1359- log . info ( `Stack ${ stackName } does not exist. Nothing to undeploy.` )
1378+ console . log ( `Stack ${ stackName } does not exist. Nothing to undeploy.` )
13601379 return
13611380 }
13621381
13631382 // Clean up any HTTPS listeners before deletion to avoid DELETE_FAILED
1364- log . info ( 'Checking for resources to clean up before deletion...' )
1383+ if ( verbose ) console . log ( 'Checking for resources to clean up before deletion...' )
13651384 try {
13661385 const client = new AWSClient ( )
13671386
@@ -1397,7 +1416,7 @@ export async function undeployStack(options: UndeployStackOptions): Promise<void
13971416 let deletedListeners = 0
13981417 for ( const listener of listenerList ) {
13991418 if ( listener . Protocol === 'HTTPS' ) {
1400- log . info ( ` Removing HTTPS listener on port ${ listener . Port } ...` )
1419+ if ( verbose ) console . log ( ` Removing HTTPS listener on port ${ listener . Port } ...` )
14011420 const deleteParams = {
14021421 Action : 'DeleteListener' ,
14031422 ListenerArn : listener . ListenerArn ,
@@ -1415,62 +1434,58 @@ export async function undeployStack(options: UndeployStackOptions): Promise<void
14151434 }
14161435 }
14171436
1418- if ( deletedListeners > 0 ) {
1419- log . success ( ` Cleaned up ${ deletedListeners } HTTPS listener(s)`)
1437+ if ( deletedListeners > 0 && verbose ) {
1438+ console . log ( `✓ Cleaned up ${ deletedListeners } HTTPS listener(s)`)
14201439 await new Promise ( resolve => setTimeout ( resolve , 2000 ) )
14211440 }
14221441 }
14231442 }
14241443 catch ( cleanupError : any ) {
14251444 if ( verbose ) {
1426- log . warn ( `Cleanup warning : ${ cleanupError . message } `)
1445+ console . log ( `Warning : ${ cleanupError . message } `)
14271446 }
14281447 }
14291448
14301449 // Initiate stack deletion
1431- log . info ( '' )
1432- log . info ( 'Initiating stack deletion...' )
1433- log . info ( '' )
1450+ console . log ( 'Deleting stack...' )
1451+ console . log ( '' )
14341452
14351453 await cf . deleteStack ( stackName )
14361454
14371455 // Print header for resource status table
1438- console . log ( ` ${ 'ResourceId' . padEnd ( 35 ) } ${ 'ResourceType' . padEnd ( 30 ) } Status` )
1439- console . log ( ' ' + '-' . repeat ( 80 ) )
1440-
1441- // Wait for deletion with progress callback
1442- await cf . waitForStackWithProgress ( stackName , 'stack-delete-complete' , createProgressCallback ( ) )
1443-
1444- log . info ( '' )
1445- log . success ( 'Infrastructure undeployed successfully!' )
1446- log . info ( '' )
1447- log . info ( '═══════════════════════════════════════════════════════════════' )
1448- log . info ( ' UNDEPLOY SUMMARY' )
1449- log . info ( '═══════════════════════════════════════════════════════════════' )
1450- log . info ( '' )
1451- log . info ( ` Stack: ${ stackName } ` )
1452- log . info ( ` Status: DELETED` )
1453- log . info ( ` Environment: ${ environment } ` )
1454- log . info ( ` Region: ${ region } ` )
1455- log . info ( '' )
1456- log . info ( '═══════════════════════════════════════════════════════════════' )
1457- log . info ( '' )
1456+ console . log ( ` ${ 'Resource' . padEnd ( 35 ) } ${ 'Type' . padEnd ( 30 ) } Status` )
1457+ console . log ( ' ' + '─' . repeat ( 85 ) )
1458+
1459+ // Wait for deletion with progress callback - only show DELETE events
1460+ await cf . waitForStackWithProgress ( stackName , 'stack-delete-complete' , createProgressCallback ( 'delete' ) )
1461+
1462+ console . log ( '' )
1463+ console . log ( '═══════════════════════════════════════════════════════════════════════════════════════' )
1464+ console . log ( '' )
1465+ console . log ( ' ✓ Infrastructure removed successfully' )
1466+ console . log ( '' )
1467+ console . log ( ` Stack: ${ stackName } ` )
1468+ console . log ( ` Environment: ${ environment } ` )
1469+ console . log ( ` Region: ${ region } ` )
1470+ console . log ( '' )
1471+ console . log ( '═══════════════════════════════════════════════════════════════════════════════════════' )
1472+ console . log ( '' )
14581473 }
14591474 catch ( error : any ) {
14601475 const errorStr = String ( error . message || error )
14611476
14621477 // Handle stack doesn't exist
14631478 if ( errorStr . includes ( 'does not exist' ) ) {
1464- log . info ( '' )
1465- log . success ( ' Stack already deleted or does not exist.')
1479+ console . log ( '' )
1480+ console . log ( '✓ Stack already deleted or does not exist.')
14661481 return
14671482 }
14681483
14691484 // Handle DELETE_FAILED - need to retain some resources
14701485 if ( error . code === 'DELETE_FAILED' || errorStr . includes ( 'DELETE_FAILED' ) ) {
1471- log . warn ( '' )
1472- log . warn ( 'Some resources could not be deleted automatically' )
1473- log . info ( 'Identifying resources to retain...' )
1486+ console . log ( '' )
1487+ console . log ( 'Some resources could not be deleted automatically' )
1488+ console . log ( 'Identifying resources to retain...' )
14741489
14751490 const { CloudFormationClient } = await import ( 'ts-cloud/aws' )
14761491 const cf = new CloudFormationClient ( region )
@@ -1483,35 +1498,35 @@ export async function undeployStack(options: UndeployStackOptions): Promise<void
14831498 . map ( ( r : any ) => r . LogicalResourceId )
14841499
14851500 if ( failedResources . length > 0 ) {
1486- log . info ( `Retaining ${ failedResources . length } resource(s):` )
1487- failedResources . forEach ( ( r : string ) => log . info ( ` - ${ r } ` ) )
1488- log . info ( '' )
1501+ console . log ( `Retaining ${ failedResources . length } resource(s):` )
1502+ failedResources . forEach ( ( r : string ) => console . log ( ` - ${ r } ` ) )
1503+ console . log ( '' )
14891504
14901505 // Retry with retained resources
1491- log . info ( 'Retrying deletion with retained resources...' )
1506+ console . log ( 'Retrying deletion with retained resources...' )
14921507 await cf . deleteStack ( stackName , undefined , failedResources )
1493- await cf . waitForStackWithProgress ( stackName , 'stack-delete-complete' , createProgressCallback ( ) )
1508+ await cf . waitForStackWithProgress ( stackName , 'stack-delete-complete' , createProgressCallback ( 'delete' ) )
14941509
1495- log . info ( '' )
1496- log . success ( ' Stack removed (with retained resources)')
1497- log . info ( '' )
1498- log . info ( 'Note: Some resources were retained and may need manual cleanup.' )
1499- log . info ( 'Run `./buddy cloud:cleanup` to clean up remaining resources.' )
1510+ console . log ( '' )
1511+ console . log ( '✓ Stack removed (with retained resources)')
1512+ console . log ( '' )
1513+ console . log ( 'Note: Some resources were retained and may need manual cleanup.' )
1514+ console . log ( 'Run `./buddy cloud:cleanup` to clean up remaining resources.' )
15001515 return
15011516 }
15021517 }
15031518 catch ( retryError : any ) {
15041519 const retryErrorStr = String ( retryError . message || retryError )
15051520 if ( retryErrorStr . includes ( 'does not exist' ) ) {
1506- log . info ( '' )
1507- log . success ( ' Stack deleted successfully!')
1521+ console . log ( '' )
1522+ console . log ( '✓ Stack deleted successfully!')
15081523 return
15091524 }
15101525 throw retryError
15111526 }
15121527 }
15131528
1514- log . error ( `Stack deletion failed: ${ error . message } ` )
1529+ console . error ( `Stack deletion failed: ${ error . message } ` )
15151530 throw error
15161531 }
15171532}
0 commit comments