aws-s3-deployment: Source.asset bundling ignores props changes between stack instances
- Dominant language
- TypeScript
- Stars
- 12.9k
- Forks
- 4.6k
- Avg merge
- 2d 3h
- Merged PRs (30d)
- 83
Description
### Describe the bug
If an app with multiple stack instances compiles uses `Source.asset()` to compile as part of the deployment, and the result is dependent on the stacks props, only first build will be correct, as the asset is reused for the next build. `AssetHashType.OUTPUT` or `AssetHashType.SOURCE` does not seem to make a difference, neither does putting the props in the environment variables.
This is for a local build, but I expect a remove build to do the same.
### Expected Behavior
The build should change if props change (or at least it should be possible to communicate which props), so that props can be used to adjust the build.
### Current Behavior
The build is correct for the first stack, the second stack never rebuilds.
### Reproduction Steps
app.ts:
``` typescript
#!/usr/bin/env node
import 'source-map-support/register';
import * as cdk from 'aws-cdk-lib';
import {S3DeploymentTsStack} from './stack';
const app = new cdk.App();
new S3DeploymentTsStack(app, 'S3DeploymentTsStackA', {
env: { account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION },
test: 'a'
});
new S3DeploymentTsStack(app, 'S3DeploymentTsStackB', {
env: { account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION },
test: 'b'
});
new S3DeploymentTsStack(app, 'S3DeploymentTsStackC', {
env: { account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION },
test: 'c'
});
```
stack.ts:
``` typescript
import {BundlingOptions, DockerImage} from 'aws-cdk-lib';
import * as cdk from 'aws-cdk-lib';
import {Source} from 'aws-cdk-lib/aws-s3-deployment';
import {execSync} from 'child_process';
import { Construct } from 'constructs';
import * as s3deploy from 'aws-cdk-lib/aws-s3-deployment';
export interface S3DeploymentTsStackProps extends cdk.StackProps {
readonly test: string;
}
export class S3DeploymentTsStack extends cdk.Stack {
constructor(scope: Construct, id: string, props: S3DeploymentTsStackProps) {
super(scope, id, props);
const bucket = new cdk.aws_s3.Bucket(this, 'Bucket');
new s3deploy.BucketDeployment(this, 'DeployWebsite', {
sources: [Source.asset('../../assets/test-asset', {
bundling: {
command: ['sh', '-c', 'echo "Docker build not supported"'],
image: DockerImage.fromRegistry('alpine'),
local: {
tryBundle(outputDir: string, options: BundlingOptions): boolean {
execSync(`echo "hello mr ${props.test}" > ${outputDir}/output.txt`);
return true;
}
}
}
})],
destinationBucket: bucket,
});
new cdk.CfnOutput(this, 'BucketName', { value: bucket.bucketName });
}
}
```
Please note that the reproduction is not really dependent on the asset folder, as it's just doing a simple echo. In the actual issue, I was building an application, where the props was used to set the API endpoint used, to choose the API endpoint, depending on stage
### Possible Solution
A possibility could be to require all props to go through the environment, and then make the environment part of the default hash (and state that requirement clearly).
Another could be to simply document the behaviour with a clear example of how to incorporate the props into the hash. After looking at it how it works internally, it's kind of obvious that it cannot be determined which props were used, but there is nothing in the documentation on how the default hash works as far as I can see, and it is _very_ surprising when you're using it for the first time.
### Additional Information/Context
_No response_
### CDK CLI Version
2.63.0 (build 7f4e35e)
### Framework Version
_No response_
### Node.js Version
v18.14.0
### OS
Linux (Ubuntu)
### Language
Typescript
### Language Version
4.9.3
### Other information
_No response_
Contributor guide
Research direction
Start with Source.asset(), BucketDeployment, and the BundlingOptions/local.tryBundle path described in the reproduction, then run the three-stack example to confirm that only the first bundle reflects props.test. Trace how asset hashes and bundling reuse are determined. Done should establish a props-aware rebuild behavior or document a clear supported way to include those values in the hash.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- aws, typescript
- Domain
- build-system, cloud
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100