Skip to content

Commit f217fe8

Browse files
authored
Merge branch 'master' into c9-repo-support
2 parents 97586eb + 171b039 commit f217fe8

File tree

65 files changed

+1397
-242
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

65 files changed

+1397
-242
lines changed

.gitignore

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# VSCode extension
2-
.vscode/
2+
3+
# Store launch config in repo but not settings
4+
.vscode/settings.json
35
/.favorites.json
46

57
# TypeScript incremental build states

.vscode/launch.json

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
// Use IntelliSense to learn about possible attributes.
3+
// Hover to view descriptions of existing attributes.
4+
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5+
"version": "0.2.0",
6+
"configurations": [
7+
{
8+
// Has convenient settings for attaching to a NodeJS process for debugging purposes
9+
// that are NOT the default and otherwise every developers has to configure for
10+
// themselves again and again.
11+
"type": "node",
12+
"request": "attach",
13+
"name": "Attach to NodeJS",
14+
// If we don't do this, every step-into into an async function call will go into
15+
// NodeJS internals which are hard to step out of.
16+
"skipFiles": [
17+
"<node_internals>/**"
18+
],
19+
// Saves some button-pressing latency on attaching
20+
"stopOnEntry": false
21+
}
22+
]
23+
}

CHANGELOG.md

+7
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,13 @@
22

33
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
44

5+
## [1.42.1](https://github.com/aws/aws-cdk/compare/v1.42.0...v1.42.1) (2020-06-01)
6+
7+
8+
### Bug Fixes
9+
10+
* **lambda:** `SingletonFunction.grantInvoke()` API fails with error 'No child with id' ([#8296](https://github.com/aws/aws-cdk/issues/8296)) ([b4e264c](https://github.com/aws/aws-cdk/commit/b4e264c024bc58053412be1343bed6458628f7cb)), closes [#8240](https://github.com/aws/aws-cdk/issues/8240)
11+
512
## [1.42.0](https://github.com/aws/aws-cdk/compare/v1.41.0...v1.42.0) (2020-05-27)
613

714

CONTRIBUTING.md

+21-2
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ and let us know if it's not up-to-date (even better, submit a PR with your corr
4343
- [Troubleshooting](#troubleshooting)
4444
- [Debugging](#debugging)
4545
- [Connecting the VS Code Debugger](#connecting-the-vs-code-debugger)
46+
- [Run a CDK unit test in the debugger](#run-a-cdk-unit-test-in-the-debugger)
4647
- [Related Repositories](#related-repositories)
4748

4849
## Getting Started
@@ -234,7 +235,7 @@ BREAKING CHANGE: Description of what broke and how to achieve this behavior now
234235
### Step 5: Pull Request
235236

236237
* Push to a GitHub fork or to a branch (naming convention: `<user>/<feature-bug-name>`)
237-
* Submit a Pull Requests on GitHub and assign the PR for a review to the "awslabs/aws-cdk" team.
238+
* Submit a Pull Request on GitHub. A reviewer will later be assigned by the maintainers.
238239
* Please follow the PR checklist written below. We trust our contributors to self-check, and this helps that process!
239240
* Discuss review comments and iterate until you get at least one “Approve”. When iterating, push new commits to the
240241
same branch. Usually all these are going to be squashed when you merge to master. The commit messages should be hints
@@ -327,7 +328,7 @@ All packages in the repo use a standard base configuration found at [eslintrc.js
327328
This can be customized for any package by modifying the `.eslintrc` file found at its root.
328329

329330
If you're using the VS Code and would like to see eslint violations on it, install the [eslint
330-
extension](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint).
331+
extension](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint).
331332

332333
#### pkglint
333334

@@ -910,6 +911,24 @@ To debug your CDK application along with the CDK repository,
910911
6. The debug view, should now have a launch configuration called 'Debug hello-cdk' and launching that will start the debugger.
911912
7. Any time you modify the CDK app or any of the CDK modules, they need to be re-built and depending on the change the `link-all.sh` script from step#2, may need to be re-run. Only then, would VS code recognize the change and potentially the breakpoint.
912913

914+
### Run a CDK unit test in the debugger
915+
916+
If you want to run the VSCode debugger on unit tests of the CDK project
917+
itself, do the following:
918+
919+
1. Set a breakpoint inside your unit test.
920+
2. In your terminal, depending on the type of test, run either:
921+
922+
```
923+
# (For tests names test.xxx.ts)
924+
$ node --inspect-brk /path/to/aws-cdk/node_modules/.bin/nodeunit -t 'TESTNAME'
925+
926+
# (For tests names xxxx.test.ts)
927+
$ node --inspect-brk /path/to/aws-cdk/node_modules/.bin/jest -i -t 'TESTNAME'
928+
```
929+
930+
3. On the `Run` pane of VSCode, select the run configuration **Attach to NodeJS** and click the button.
931+
913932
## Related Repositories
914933

915934
* [Samples](https://github.com/aws-samples/aws-cdk-examples): includes sample code in multiple languages

lerna.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,5 @@
1010
"tools/*"
1111
],
1212
"rejectCycles": "true",
13-
"version": "1.42.0"
13+
"version": "1.42.1"
1414
}

packages/@aws-cdk/aws-apigateway/lib/deployment.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { CfnResource, Construct, Lazy, RemovalPolicy, Resource, Stack } from '@aws-cdk/core';
22
import * as crypto from 'crypto';
33
import { CfnDeployment } from './apigateway.generated';
4-
import { IRestApi, RestApi } from './restapi';
4+
import { IRestApi, RestApi, SpecRestApi } from './restapi';
55

66
export interface DeploymentProps {
77
/**
@@ -155,7 +155,7 @@ class LatestDeploymentResource extends CfnDeployment {
155155
* add via `addToLogicalId`.
156156
*/
157157
protected prepare() {
158-
if (this.api instanceof RestApi) { // Ignore IRestApi that are imported
158+
if (this.api instanceof RestApi || this.api instanceof SpecRestApi) { // Ignore IRestApi that are imported
159159

160160
// Add CfnRestApi to the logical id so a new deployment is triggered when any of its properties change.
161161
const cfnRestApiCF = (this.api.node.defaultChild as any)._toCloudFormation();

packages/@aws-cdk/aws-apigateway/test/integ.api-definition.asset.expected.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
"Name": "my-api"
4545
}
4646
},
47-
"myapiDeployment92F2CB49": {
47+
"myapiDeployment92F2CB49eb6b0027bfbdb20b09988607569e06bd": {
4848
"Type": "AWS::ApiGateway::Deployment",
4949
"Properties": {
5050
"RestApiId": {
@@ -60,7 +60,7 @@
6060
"Ref": "myapi4C7BF186"
6161
},
6262
"DeploymentId": {
63-
"Ref": "myapiDeployment92F2CB49"
63+
"Ref": "myapiDeployment92F2CB49eb6b0027bfbdb20b09988607569e06bd"
6464
},
6565
"StageName": "prod"
6666
}

packages/@aws-cdk/aws-apigateway/test/integ.api-definition.inline.expected.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@
5353
"Name": "my-api"
5454
}
5555
},
56-
"myapiDeployment92F2CB49": {
56+
"myapiDeployment92F2CB49a59bca458e4fac1fcd742212ded42a65": {
5757
"Type": "AWS::ApiGateway::Deployment",
5858
"Properties": {
5959
"RestApiId": {
@@ -69,7 +69,7 @@
6969
"Ref": "myapi4C7BF186"
7070
},
7171
"DeploymentId": {
72-
"Ref": "myapiDeployment92F2CB49"
72+
"Ref": "myapiDeployment92F2CB49a59bca458e4fac1fcd742212ded42a65"
7373
},
7474
"StageName": "prod"
7575
}

packages/@aws-cdk/aws-codepipeline-actions/lib/codecommit/source-action.ts

+6-2
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,10 @@ export class CodeCommitSourceAction extends Action {
8787
private readonly props: CodeCommitSourceActionProps;
8888

8989
constructor(props: CodeCommitSourceActionProps) {
90-
const branch = props.branch || 'master';
90+
const branch = props.branch ?? 'master';
91+
if (!branch) {
92+
throw new Error("'branch' parameter cannot be an empty string");
93+
}
9194

9295
super({
9396
...props,
@@ -119,7 +122,8 @@ export class CodeCommitSourceAction extends Action {
119122
const createEvent = this.props.trigger === undefined ||
120123
this.props.trigger === CodeCommitTrigger.EVENTS;
121124
if (createEvent) {
122-
this.props.repository.onCommit(stage.pipeline.node.uniqueId + 'EventRule', {
125+
const branchIdDisambiguator = this.branch === 'master' ? '' : `-${this.branch}-`;
126+
this.props.repository.onCommit(`${stage.pipeline.node.uniqueId}${branchIdDisambiguator}EventRule`, {
123127
target: new targets.CodePipeline(stage.pipeline),
124128
branches: [this.branch],
125129
});

packages/@aws-cdk/aws-codepipeline-actions/test/codecommit/test.codecommit-source-action.ts

+60
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,66 @@ export = {
110110
test.done();
111111
},
112112

113+
'cannot be created with an empty branch'(test: Test) {
114+
const stack = new Stack();
115+
const repo = new codecommit.Repository(stack, 'MyRepo', {
116+
repositoryName: 'my-repo',
117+
});
118+
119+
test.throws(() => {
120+
new cpactions.CodeCommitSourceAction({
121+
actionName: 'Source2',
122+
repository: repo,
123+
output: new codepipeline.Artifact(),
124+
branch: '',
125+
});
126+
}, /'branch' parameter cannot be an empty string/);
127+
128+
test.done();
129+
},
130+
131+
'allows using the same repository multiple times with different branches when trigger=EVENTS'(test: Test) {
132+
const stack = new Stack();
133+
134+
const repo = new codecommit.Repository(stack, 'MyRepo', {
135+
repositoryName: 'my-repo',
136+
});
137+
const sourceOutput1 = new codepipeline.Artifact();
138+
const sourceOutput2 = new codepipeline.Artifact();
139+
new codepipeline.Pipeline(stack, 'MyPipeline', {
140+
stages: [
141+
{
142+
stageName: 'Source',
143+
actions: [
144+
new cpactions.CodeCommitSourceAction({
145+
actionName: 'Source1',
146+
repository: repo,
147+
output: sourceOutput1,
148+
}),
149+
new cpactions.CodeCommitSourceAction({
150+
actionName: 'Source2',
151+
repository: repo,
152+
output: sourceOutput2,
153+
branch: 'develop',
154+
}),
155+
],
156+
},
157+
{
158+
stageName: 'Build',
159+
actions: [
160+
new cpactions.CodeBuildAction({
161+
actionName: 'Build',
162+
project: new codebuild.PipelineProject(stack, 'MyProject'),
163+
input: sourceOutput1,
164+
}),
165+
],
166+
},
167+
],
168+
});
169+
170+
test.done();
171+
},
172+
113173
'exposes variables for other actions to consume'(test: Test) {
114174
const stack = new Stack();
115175

packages/@aws-cdk/aws-codepipeline/lib/pipeline.ts

+79-20
Original file line numberDiff line numberDiff line change
@@ -749,34 +749,52 @@ export class Pipeline extends PipelineBase {
749749
private validateArtifacts(): string[] {
750750
const ret = new Array<string>();
751751

752-
const outputArtifactNames = new Set<string>();
753-
for (const stage of this._stages) {
754-
const sortedActions = stage.actionDescriptors.sort((a1, a2) => a1.runOrder - a2.runOrder);
755-
756-
for (const action of sortedActions) {
757-
// start with inputs
758-
const inputArtifacts = action.inputs;
759-
for (const inputArtifact of inputArtifacts) {
760-
if (!inputArtifact.artifactName) {
761-
ret.push(`Action '${action.actionName}' has an unnamed input Artifact that's not used as an output`);
762-
} else if (!outputArtifactNames.has(inputArtifact.artifactName)) {
763-
ret.push(`Artifact '${inputArtifact.artifactName}' was used as input before being used as output`);
752+
const producers: Record<string, PipelineLocation> = {};
753+
const firstConsumers: Record<string, PipelineLocation> = {};
754+
755+
for (const [stageIndex, stage] of enumerate(this._stages)) {
756+
// For every output artifact, get the producer
757+
for (const action of stage.actionDescriptors) {
758+
const actionLoc = new PipelineLocation(stageIndex, stage, action);
759+
760+
for (const outputArtifact of action.outputs) {
761+
// output Artifacts always have a name set
762+
const name = outputArtifact.artifactName!;
763+
if (producers[name]) {
764+
ret.push(`Both Actions '${producers[name].actionName}' and '${action.actionName}' are producting Artifact '${name}'. Every artifact can only be produced once.`);
765+
continue;
764766
}
767+
768+
producers[name] = actionLoc;
765769
}
766770

767-
// then process outputs by adding them to the Set
768-
const outputArtifacts = action.outputs;
769-
for (const outputArtifact of outputArtifacts) {
770-
// output Artifacts always have a name set
771-
if (outputArtifactNames.has(outputArtifact.artifactName!)) {
772-
ret.push(`Artifact '${outputArtifact.artifactName}' has been used as an output more than once`);
773-
} else {
774-
outputArtifactNames.add(outputArtifact.artifactName!);
771+
// For every input artifact, get the first consumer
772+
for (const inputArtifact of action.inputs) {
773+
const name = inputArtifact.artifactName;
774+
if (!name) {
775+
ret.push(`Action '${action.actionName}' is using an unnamed input Artifact, which is not being produced in this pipeline`);
776+
continue;
775777
}
778+
779+
firstConsumers[name] = firstConsumers[name] ? firstConsumers[name].first(actionLoc) : actionLoc;
776780
}
777781
}
778782
}
779783

784+
// Now validate that every input artifact is produced before it's
785+
// being consumed.
786+
for (const [artifactName, consumerLoc] of Object.entries(firstConsumers)) {
787+
const producerLoc = producers[artifactName];
788+
if (!producerLoc) {
789+
ret.push(`Action '${consumerLoc.actionName}' is using input Artifact '${artifactName}', which is not being produced in this pipeline`);
790+
continue;
791+
}
792+
793+
if (consumerLoc.beforeOrEqual(producerLoc)) {
794+
ret.push(`${consumerLoc} is consuming input Artifact '${artifactName}' before it is being produced at ${producerLoc}`);
795+
}
796+
}
797+
780798
return ret;
781799
}
782800

@@ -874,3 +892,44 @@ interface CrossRegionInfo {
874892

875893
readonly region?: string;
876894
}
895+
896+
function enumerate<A>(xs: A[]): Array<[number, A]> {
897+
const ret = new Array<[number, A]>();
898+
for (let i = 0; i < xs.length; i++) {
899+
ret.push([i, xs[i]]);
900+
}
901+
return ret;
902+
}
903+
904+
class PipelineLocation {
905+
constructor(private readonly stageIndex: number, private readonly stage: IStage, private readonly action: FullActionDescriptor) {
906+
}
907+
908+
public get stageName() {
909+
return this.stage.stageName;
910+
}
911+
912+
public get actionName() {
913+
return this.action.actionName;
914+
}
915+
916+
/**
917+
* Returns whether a is before or the same order as b
918+
*/
919+
public beforeOrEqual(rhs: PipelineLocation) {
920+
if (this.stageIndex !== rhs.stageIndex) { return rhs.stageIndex < rhs.stageIndex; }
921+
return this.action.runOrder <= rhs.action.runOrder;
922+
}
923+
924+
/**
925+
* Returns the first location between this and the other one
926+
*/
927+
public first(rhs: PipelineLocation) {
928+
return this.beforeOrEqual(rhs) ? this : rhs;
929+
}
930+
931+
public toString() {
932+
// runOrders are 1-based, so make the stageIndex also 1-based otherwise it's going to be confusing.
933+
return `Stage ${this.stageIndex + 1} Action ${this.action.runOrder} ('${this.stageName}'/'${this.actionName}')`;
934+
}
935+
}

0 commit comments

Comments
 (0)