Skip to content

Commit

Permalink
Merge branch 'master' into lambda-nodejs-env
Browse files Browse the repository at this point in the history
  • Loading branch information
mergify[bot] authored Jun 1, 2020
2 parents 8486eef + c704d16 commit 36a2137
Show file tree
Hide file tree
Showing 30 changed files with 867 additions and 137 deletions.
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ BREAKING CHANGE: Description of what broke and how to achieve this behavior now
### Step 5: Pull Request

* Push to a GitHub fork or to a branch (naming convention: `<user>/<feature-bug-name>`)
* Submit a Pull Requests on GitHub and assign the PR for a review to the "awslabs/aws-cdk" team.
* Submit a Pull Request on GitHub. A reviewer will later be assigned by the maintainers.
* Please follow the PR checklist written below. We trust our contributors to self-check, and this helps that process!
* Discuss review comments and iterate until you get at least one “Approve”. When iterating, push new commits to the
same branch. Usually all these are going to be squashed when you merge to master. The commit messages should be hints
Expand Down
4 changes: 2 additions & 2 deletions packages/@aws-cdk/aws-apigateway/lib/deployment.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { CfnResource, Construct, Lazy, RemovalPolicy, Resource, Stack } from '@aws-cdk/core';
import * as crypto from 'crypto';
import { CfnDeployment } from './apigateway.generated';
import { IRestApi, RestApi } from './restapi';
import { IRestApi, RestApi, SpecRestApi } from './restapi';

export interface DeploymentProps {
/**
Expand Down Expand Up @@ -155,7 +155,7 @@ class LatestDeploymentResource extends CfnDeployment {
* add via `addToLogicalId`.
*/
protected prepare() {
if (this.api instanceof RestApi) { // Ignore IRestApi that are imported
if (this.api instanceof RestApi || this.api instanceof SpecRestApi) { // Ignore IRestApi that are imported

// Add CfnRestApi to the logical id so a new deployment is triggered when any of its properties change.
const cfnRestApiCF = (this.api.node.defaultChild as any)._toCloudFormation();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
"Name": "my-api"
}
},
"myapiDeployment92F2CB49": {
"myapiDeployment92F2CB49eb6b0027bfbdb20b09988607569e06bd": {
"Type": "AWS::ApiGateway::Deployment",
"Properties": {
"RestApiId": {
Expand All @@ -60,7 +60,7 @@
"Ref": "myapi4C7BF186"
},
"DeploymentId": {
"Ref": "myapiDeployment92F2CB49"
"Ref": "myapiDeployment92F2CB49eb6b0027bfbdb20b09988607569e06bd"
},
"StageName": "prod"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
"Name": "my-api"
}
},
"myapiDeployment92F2CB49": {
"myapiDeployment92F2CB49a59bca458e4fac1fcd742212ded42a65": {
"Type": "AWS::ApiGateway::Deployment",
"Properties": {
"RestApiId": {
Expand All @@ -69,7 +69,7 @@
"Ref": "myapi4C7BF186"
},
"DeploymentId": {
"Ref": "myapiDeployment92F2CB49"
"Ref": "myapiDeployment92F2CB49a59bca458e4fac1fcd742212ded42a65"
},
"StageName": "prod"
}
Expand Down
2 changes: 1 addition & 1 deletion packages/@aws-cdk/aws-codepipeline-actions/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
"devDependencies": {
"@aws-cdk/assert": "0.0.0",
"@aws-cdk/aws-cloudtrail": "0.0.0",
"@types/lodash": "^4.14.152",
"@types/lodash": "^4.14.153",
"@types/nodeunit": "^0.0.31",
"cdk-build-tools": "0.0.0",
"cdk-integ-tools": "0.0.0",
Expand Down
99 changes: 79 additions & 20 deletions packages/@aws-cdk/aws-codepipeline/lib/pipeline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -749,34 +749,52 @@ export class Pipeline extends PipelineBase {
private validateArtifacts(): string[] {
const ret = new Array<string>();

const outputArtifactNames = new Set<string>();
for (const stage of this._stages) {
const sortedActions = stage.actionDescriptors.sort((a1, a2) => a1.runOrder - a2.runOrder);

for (const action of sortedActions) {
// start with inputs
const inputArtifacts = action.inputs;
for (const inputArtifact of inputArtifacts) {
if (!inputArtifact.artifactName) {
ret.push(`Action '${action.actionName}' has an unnamed input Artifact that's not used as an output`);
} else if (!outputArtifactNames.has(inputArtifact.artifactName)) {
ret.push(`Artifact '${inputArtifact.artifactName}' was used as input before being used as output`);
const producers: Record<string, PipelineLocation> = {};
const firstConsumers: Record<string, PipelineLocation> = {};

for (const [stageIndex, stage] of enumerate(this._stages)) {
// For every output artifact, get the producer
for (const action of stage.actionDescriptors) {
const actionLoc = new PipelineLocation(stageIndex, stage, action);

for (const outputArtifact of action.outputs) {
// output Artifacts always have a name set
const name = outputArtifact.artifactName!;
if (producers[name]) {
ret.push(`Both Actions '${producers[name].actionName}' and '${action.actionName}' are producting Artifact '${name}'. Every artifact can only be produced once.`);
continue;
}

producers[name] = actionLoc;
}

// then process outputs by adding them to the Set
const outputArtifacts = action.outputs;
for (const outputArtifact of outputArtifacts) {
// output Artifacts always have a name set
if (outputArtifactNames.has(outputArtifact.artifactName!)) {
ret.push(`Artifact '${outputArtifact.artifactName}' has been used as an output more than once`);
} else {
outputArtifactNames.add(outputArtifact.artifactName!);
// For every input artifact, get the first consumer
for (const inputArtifact of action.inputs) {
const name = inputArtifact.artifactName;
if (!name) {
ret.push(`Action '${action.actionName}' is using an unnamed input Artifact, which is not being produced in this pipeline`);
continue;
}

firstConsumers[name] = firstConsumers[name] ? firstConsumers[name].first(actionLoc) : actionLoc;
}
}
}

// Now validate that every input artifact is produced before it's
// being consumed.
for (const [artifactName, consumerLoc] of Object.entries(firstConsumers)) {
const producerLoc = producers[artifactName];
if (!producerLoc) {
ret.push(`Action '${consumerLoc.actionName}' is using input Artifact '${artifactName}', which is not being produced in this pipeline`);
continue;
}

if (consumerLoc.beforeOrEqual(producerLoc)) {
ret.push(`${consumerLoc} is consuming input Artifact '${artifactName}' before it is being produced at ${producerLoc}`);
}
}

return ret;
}

Expand Down Expand Up @@ -874,3 +892,44 @@ interface CrossRegionInfo {

readonly region?: string;
}

function enumerate<A>(xs: A[]): Array<[number, A]> {
const ret = new Array<[number, A]>();
for (let i = 0; i < xs.length; i++) {
ret.push([i, xs[i]]);
}
return ret;
}

class PipelineLocation {
constructor(private readonly stageIndex: number, private readonly stage: IStage, private readonly action: FullActionDescriptor) {
}

public get stageName() {
return this.stage.stageName;
}

public get actionName() {
return this.action.actionName;
}

/**
* Returns whether a is before or the same order as b
*/
public beforeOrEqual(rhs: PipelineLocation) {
if (this.stageIndex !== rhs.stageIndex) { return rhs.stageIndex < rhs.stageIndex; }
return this.action.runOrder <= rhs.action.runOrder;
}

/**
* Returns the first location between this and the other one
*/
public first(rhs: PipelineLocation) {
return this.beforeOrEqual(rhs) ? this : rhs;
}

public toString() {
// runOrders are 1-based, so make the stageIndex also 1-based otherwise it's going to be confusing.
return `Stage ${this.stageIndex + 1} Action ${this.action.runOrder} ('${this.stageName}'/'${this.actionName}')`;
}
}
59 changes: 56 additions & 3 deletions packages/@aws-cdk/aws-codepipeline/test/test.artifacts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export = {
test.equal(errors.length, 1);
const error = errors[0];
test.same(error.source, pipeline);
test.equal(error.message, "Action 'Build' has an unnamed input Artifact that's not used as an output");
test.equal(error.message, "Action 'Build' is using an unnamed input Artifact, which is not being produced in this pipeline");

test.done();
},
Expand Down Expand Up @@ -82,7 +82,7 @@ export = {
test.equal(errors.length, 1);
const error = errors[0];
test.same(error.source, pipeline);
test.equal(error.message, "Artifact 'named' was used as input before being used as output");
test.equal(error.message, "Action 'Build' is using input Artifact 'named', which is not being produced in this pipeline");

test.done();
},
Expand Down Expand Up @@ -119,7 +119,7 @@ export = {
test.equal(errors.length, 1);
const error = errors[0];
test.same(error.source, pipeline);
test.equal(error.message, "Artifact 'Artifact_Source_Source' has been used as an output more than once");
test.equal(error.message, "Both Actions 'Source' and 'Build' are producting Artifact 'Artifact_Source_Source'. Every artifact can only be produced once.");

test.done();
},
Expand Down Expand Up @@ -173,6 +173,59 @@ export = {
test.done();
},

'violation of runOrder constraints is detected and reported'(test: Test) {
const stack = new cdk.Stack();

const sourceOutput1 = new codepipeline.Artifact('sourceOutput1');
const buildOutput1 = new codepipeline.Artifact('buildOutput1');
const sourceOutput2 = new codepipeline.Artifact('sourceOutput2');

const pipeline = new codepipeline.Pipeline(stack, 'Pipeline', {
stages: [
{
stageName: 'Source',
actions: [
new FakeSourceAction({
actionName: 'source1',
output: sourceOutput1,
}),
new FakeSourceAction({
actionName: 'source2',
output: sourceOutput2,
}),
],
},
{
stageName: 'Build',
actions: [
new FakeBuildAction({
actionName: 'build1',
input: sourceOutput1,
output: buildOutput1,
runOrder: 3,
}),
new FakeBuildAction({
actionName: 'build2',
input: sourceOutput2,
extraInputs: [buildOutput1],
output: new codepipeline.Artifact('buildOutput2'),
runOrder: 2,
}),
],
},
],
});

const errors = validate(stack);

test.equal(errors.length, 1);
const error = errors[0];
test.same(error.source, pipeline);
test.equal(error.message, "Stage 2 Action 2 ('Build'/'build2') is consuming input Artifact 'buildOutput1' before it is being produced at Stage 2 Action 3 ('Build'/'build1')");

test.done();
},

'without a name, sanitize the auto stage-action derived name'(test: Test) {
const stack = new cdk.Stack();

Expand Down
30 changes: 29 additions & 1 deletion packages/@aws-cdk/aws-cognito/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -446,4 +446,32 @@ pool.addDomain('CustomDomain', {

Read more about [Using the Amazon Cognito
Domain](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-assign-domain-prefix.html) and [Using Your Own
Domain](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-add-custom-domain.html).
Domain](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-add-custom-domain.html)

The `signInUrl()` methods returns the fully qualified URL to the login page for the user pool. This page comes from the
hosted UI configured with Cognito. Learn more at [Hosted UI with the Amazon Cognito
Console](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-app-integration.html#cognito-user-pools-create-an-app-integration).

```ts
const userpool = new UserPool(this, 'UserPool', {
// ...
});
const client = userpool.addClient('Client', {
// ...
oAuth: {
flows: {
implicitCodeGrant: true,
},
callbackUrls: [
'https://myapp.com/home',
'https://myapp.com/users',
]
}
})
const domain = userpool.addDomain('Domain', {
// ...
});
const signInUrl = domain.signInUrl(client, {
redirectUrl: 'https://myapp.com/home', // must be a URL configured under 'callbackUrls' with the client
})
```
Loading

0 comments on commit 36a2137

Please sign in to comment.