@@ -3,6 +3,7 @@ import * as path from 'path';
33import * as cxschema from '@aws-cdk/cloud-assembly-schema' ;
44import * as cxapi from '@aws-cdk/cx-api' ;
55import { CloudAssemblyBuilder } from '@aws-cdk/cx-api' ;
6+ import { WorkGraph } from '../lib/util/work-graph' ;
67import { WorkGraphBuilder } from '../lib/util/work-graph-builder' ;
78import { AssetBuildNode , AssetPublishNode , StackNode , WorkNode } from '../lib/util/work-graph-types' ;
89
@@ -36,14 +37,14 @@ describe('with some stacks and assets', () => {
3637
3738 expect ( graph . node ( 'F1:D1-publish' ) ) . toEqual ( expect . objectContaining ( {
3839 type : 'asset-publish' ,
39- dependencies : new Set ( [ 'F1:D1 -build' ] ) ,
40+ dependencies : new Set ( [ 'F1-build' ] ) ,
4041 } as Partial < AssetPublishNode > ) ) ;
4142 } ) ;
4243
4344 test ( 'with prebuild off, asset building inherits dependencies from their parent stack' , ( ) => {
4445 const graph = new WorkGraphBuilder ( false ) . build ( assembly . artifacts ) ;
4546
46- expect ( graph . node ( 'F1:D1 -build' ) ) . toEqual ( expect . objectContaining ( {
47+ expect ( graph . node ( 'F1-build' ) ) . toEqual ( expect . objectContaining ( {
4748 type : 'asset-build' ,
4849 dependencies : new Set ( [ 'stack0' , 'stack1' ] ) ,
4950 } as Partial < AssetBuildNode > ) ) ;
@@ -52,7 +53,7 @@ describe('with some stacks and assets', () => {
5253 test ( 'with prebuild on, assets only have their own dependencies' , ( ) => {
5354 const graph = new WorkGraphBuilder ( true ) . build ( assembly . artifacts ) ;
5455
55- expect ( graph . node ( 'F1:D1 -build' ) ) . toEqual ( expect . objectContaining ( {
56+ expect ( graph . node ( 'F1-build' ) ) . toEqual ( expect . objectContaining ( {
5657 type : 'asset-build' ,
5758 dependencies : new Set ( [ 'stack0' ] ) ,
5859 } as Partial < AssetBuildNode > ) ) ;
@@ -138,17 +139,11 @@ describe('tests that use assets', () => {
138139
139140 const assembly = rootBuilder . buildAssembly ( ) ;
140141
141- const traversal : string [ ] = [ ] ;
142142 const graph = new WorkGraphBuilder ( true ) . build ( assembly . artifacts ) ;
143- await graph . doParallel ( 1 , {
144- deployStack : async ( node ) => { traversal . push ( node . id ) ; } ,
145- buildAsset : async ( node ) => { traversal . push ( node . id ) ; } ,
146- publishAsset : async ( node ) => { traversal . push ( node . id ) ; } ,
147- } ) ;
143+ const traversal = await traverseAndRecord ( graph ) ;
148144
149- expect ( traversal ) . toHaveLength ( 4 ) ; // 1 asset build, 1 asset publish, 2 stacks
150145 expect ( traversal ) . toEqual ( [
151- 'work-graph-builder.test.js:D1 -build' ,
146+ 'work-graph-builder.test.js-build' ,
152147 'work-graph-builder.test.js:D1-publish' ,
153148 'StackA' ,
154149 'StackB' ,
@@ -171,6 +166,53 @@ describe('tests that use assets', () => {
171166 // THEN
172167 expect ( graph . findCycle ( ) ) . toBeUndefined ( ) ;
173168 } ) ;
169+
170+ test ( 'the same asset to different destinations is only built once' , async ( ) => {
171+ addStack ( rootBuilder , 'StackA' , {
172+ environment : 'aws://11111/us-east-1' ,
173+ dependencies : [ 'StackA.assets' ] ,
174+ } ) ;
175+ addAssets ( rootBuilder , 'StackA.assets' , {
176+ files : {
177+ abcdef : {
178+ source : { path : __dirname } ,
179+ destinations : {
180+ D1 : { bucketName : 'bucket1' , objectKey : 'key' } ,
181+ D2 : { bucketName : 'bucket2' , objectKey : 'key' } ,
182+ } ,
183+ } ,
184+ } ,
185+ } ) ;
186+
187+ addStack ( rootBuilder , 'StackB' , {
188+ environment : 'aws://11111/us-east-1' ,
189+ dependencies : [ 'StackB.assets' , 'StackA' ] ,
190+ } ) ;
191+ addAssets ( rootBuilder , 'StackB.assets' , {
192+ files : {
193+ abcdef : {
194+ source : { path : __dirname } ,
195+ destinations : {
196+ D3 : { bucketName : 'bucket3' , objectKey : 'key' } ,
197+ } ,
198+ } ,
199+ } ,
200+ } ) ;
201+
202+ const assembly = rootBuilder . buildAssembly ( ) ;
203+
204+ const graph = new WorkGraphBuilder ( true ) . build ( assembly . artifacts ) ;
205+ const traversal = await traverseAndRecord ( graph ) ;
206+
207+ expect ( traversal ) . toEqual ( [
208+ 'abcdef-build' ,
209+ 'abcdef:D1-publish' ,
210+ 'abcdef:D2-publish' ,
211+ 'StackA' ,
212+ 'abcdef:D3-publish' ,
213+ 'StackB' ,
214+ ] ) ;
215+ } ) ;
174216} ) ;
175217
176218/**
@@ -251,3 +293,13 @@ function assertableNode<A extends WorkNode>(x: A) {
251293 dependencies : Array . from ( x . dependencies ) ,
252294 } ;
253295}
296+
297+ async function traverseAndRecord ( graph : WorkGraph ) {
298+ const ret : string [ ] = [ ] ;
299+ await graph . doParallel ( 1 , {
300+ deployStack : async ( node ) => { ret . push ( node . id ) ; } ,
301+ buildAsset : async ( node ) => { ret . push ( node . id ) ; } ,
302+ publishAsset : async ( node ) => { ret . push ( node . id ) ; } ,
303+ } ) ;
304+ return ret ;
305+ }
0 commit comments