aws / aws/aws-cdk

aws-s3-deployment: Source.asset bundling ignores props changes between stack instances

Open
#24,436 9 comments 1 reaction 0 assignees View on GitHub
@aws-cdk/aws-s3-deployment bug effort/medium p2
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.