diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md deleted file mode 100644 index 5371d422793e3..0000000000000 --- a/.github/ISSUE_TEMPLATE.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -name: "\U00002753 General Issue" -about: Create a new issue -labels: needs-triage ---- - - - -## :question: General Issue - - - -### The Question - - -### Environment - - - **CDK CLI Version:** - - **Module Version:** - - **Node.js Version:** - - **OS:** - - **Language:** - - -### Other information - diff --git a/.github/ISSUE_TEMPLATE/bug.md b/.github/ISSUE_TEMPLATE/bug.md deleted file mode 100644 index 6835abe99e034..0000000000000 --- a/.github/ISSUE_TEMPLATE/bug.md +++ /dev/null @@ -1,54 +0,0 @@ ---- -name: "\U0001F41B Bug Report" -about: Report a bug -title: "(module name): short issue description" -labels: bug, needs-triage ---- - - - - - - -### Reproduction Steps - - - -### What did you expect to happen? - - - -### What actually happened? - - - - -### Environment - - - **CDK CLI Version :** - - **Framework Version:** - - **Node.js Version:** - - **OS :** - - **Language (Version):** - -### Other - - - - - - ---- - -This is :bug: Bug Report diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml new file mode 100644 index 0000000000000..f77fa5beb193e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug.yml @@ -0,0 +1,108 @@ +name: Bug Report +description: Report a bug +title: "(module name): short issue description" +labels: [bug, needs-triage] +body: + - type: textarea + id: problem + attributes: + label: What is the problem? + validations: + required: true + + - type: textarea + id: reproduction + attributes: + label: Reproduction Steps + description: | + Minimal amount of code that causes the bug (if possible) or a reference. + + The code sample should be an SSCCE. See http://sscce.org/ for details. + In short, provide a code sample that we can copy/paste, run and reproduce. + validations: + required: true + + - type: textarea + id: expected + attributes: + label: What did you expect to happen? + description: | + What were you trying to achieve by performing the steps above? + validations: + required: true + + - type: textarea + id: actual + attributes: + label: What actually happened? + description: | + What is the unexpected behavior you were seeing? If you got an error, paste it here. + validations: + required: true + + - type: input + id: cdk-version + attributes: + label: CDK CLI Version + description: Output of `cdk version` + validations: + required: true + + - type: input + id: framework-version + attributes: + label: Framework Version + validations: + required: false + + - type: input + id: node-version + attributes: + label: Node.js Version + validations: + required: true + + - type: input + id: operating-system + attributes: + label: OS + validations: + required: true + + - type: dropdown + id: language + attributes: + label: Language + multiple: true + options: + - Typescript + - Python + - .NET + - Java + - Go + validations: + required: true + + - type: input + id: language-version + attributes: + label: Language Version + description: E.g. TypeScript (3.8.3) | Java (8) | Python (3.7.3) + validations: + required: false + + - type: textarea + id: other + attributes: + label: Other information + description: | + e.g. detailed explanation, stacktraces, related issues, suggestions how to fix, links for us to have context, eg. associated pull-request, stackoverflow, slack, etc + validations: + required: false + + - type: markdown + attributes: + value: | + --- + + This is :bug: Bug Report diff --git a/.github/ISSUE_TEMPLATE/doc.md b/.github/ISSUE_TEMPLATE/doc.md deleted file mode 100644 index 3c8a1dc691d0e..0000000000000 --- a/.github/ISSUE_TEMPLATE/doc.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -name: "📕 Documentation Issue" -about: Issue in the reference documentation or developer guide -title: "(module name): short issue description" -labels: feature-request, documentation, needs-triage ---- - - - - - - - - - - - - - ---- - -This is a 📕 documentation issue diff --git a/.github/ISSUE_TEMPLATE/doc.yml b/.github/ISSUE_TEMPLATE/doc.yml new file mode 100644 index 0000000000000..974a752cac810 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/doc.yml @@ -0,0 +1,32 @@ +name: Documentation Issue +description: Issue in the reference documentation or developer guide +title: "(module name): short issue description" +labels: [feature-request, documentation, needs-triage] +body: + - type: markdown + attributes: + value: | + Developer guide? Raise issue/pr here: https://github.com/awsdocs/aws-cdk-guide + + Want to help? Submit a pull request here: https://github.com/aws/aws-cdk + + - type: input + id: doc-link + attributes: + label: link to reference doc page + validations: + required: false + + - type: textarea + id: issue + attributes: + label: Describe your issue? + validations: + required: true + + - type: markdown + attributes: + value: | + --- + + This is a 📕 documentation issue diff --git a/.github/ISSUE_TEMPLATE/feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.md deleted file mode 100644 index 163f2f54d0b88..0000000000000 --- a/.github/ISSUE_TEMPLATE/feature-request.md +++ /dev/null @@ -1,46 +0,0 @@ ---- -name: "\U0001F680 Feature Request" -about: Request a new feature -title: "(module name): short issue description" -labels: feature-request, needs-triage ---- - - - - - - - -### Use Case - - - - - - - -### Proposed Solution - - - - - - - -### Other - - - - - - - -* [ ] :wave: I may be able to implement this feature request -* [ ] :warning: This feature might incur a breaking change - ---- - -This is a :rocket: Feature Request diff --git a/.github/ISSUE_TEMPLATE/feature-request.yml b/.github/ISSUE_TEMPLATE/feature-request.yml new file mode 100644 index 0000000000000..a16053f420a82 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-request.yml @@ -0,0 +1,56 @@ +name: Feature Request +description: Request a new feature +title: "(module name): short issue description" +labels: [feature-request, needs-triage] +body: + - type: textarea + id: description + attributes: + label: Description + description: Short description of the feature you are proposing. + validations: + required: true + + - type: textarea + id: use-case + attributes: + label: Use Case + description: | + Why do you need this feature? + validations: + required: true + + - type: textarea + id: solution + attributes: + label: Proposed Solution + description: | + Please include prototype/workaround/sketch/reference implementation. + validations: + required: true + + - type: textarea + id: other + attributes: + label: Other information + description: | + e.g. detailed explanation, stacktraces, related issues, suggestions how to fix, links for us to have context, eg. associated pull-request, stackoverflow, slack, etc + validations: + required: false + + - type: checkboxes + id: acknowledgments + attributes: + label: Acknowledge + options: + - label: I may be able to implement this feature request + required: false + - label: This feature might incur a breaking change + required: false + + - type: markdown + attributes: + value: | + --- + + This is a :rocket: Feature Request diff --git a/.github/ISSUE_TEMPLATE/general-issue.yml b/.github/ISSUE_TEMPLATE/general-issue.yml new file mode 100644 index 0000000000000..61119a33a761c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/general-issue.yml @@ -0,0 +1,87 @@ +name: General Issue +description: Create a new issue +title: "(module name): short issue description" +labels: [needs-triage, guidance] +body: + - type: markdown + attributes: + value: | + If there is an issue regarding developer guide, please create an issue [here](https://github.com/awsdocs/aws-cdk-guide/issues). + + - type: input + id: issue + attributes: + label: General Issue + description: | + For support questions, please first reference our [documentation](https://docs.aws.amazon.com/cdk/api/latest), then use [Stackoverflow](https://stackoverflow.com/questions/tagged/aws-cdk). This repository's issues are intended for feature requests and bug reports. + validations: + required: true + + - type: textarea + id: question + attributes: + label: The Question + description: | + Ask your question here. Include any details relevant. Make sure you are not falling prey to the [X/Y problem](http://xyproblem.info)! + validations: + required: true + + - type: input + id: cdk-version + attributes: + label: CDK CLI Version + description: Output of `cdk version` + validations: + required: true + + - type: input + id: framework-version + attributes: + label: Framework Version + validations: + required: false + + - type: input + id: node-version + attributes: + label: Node.js Version + validations: + required: false + + - type: input + id: operating-system + attributes: + label: OS + validations: + required: false + + - type: dropdown + id: language + attributes: + label: Language + multiple: true + options: + - Typescript + - Python + - .NET + - Java + - Go + validations: + required: true + + - type: input + id: language-version + attributes: + label: Language Version + description: E.g. TypeScript (3.8.3) | Java (8) | Python (3.7.3) + validations: + required: false + + - type: textarea + id: other + attributes: + label: Other information + description: | + e.g. detailed explanation, stacktraces, related issues, suggestions how to fix, links for us to have context, eg. associated pull-request, stackoverflow, slack, etc + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/general-issues.md b/.github/ISSUE_TEMPLATE/general-issues.md deleted file mode 100644 index 2b478904a6fca..0000000000000 --- a/.github/ISSUE_TEMPLATE/general-issues.md +++ /dev/null @@ -1,35 +0,0 @@ ---- -name: "\U00002753 General Issue" -about: Create a new issue -title: "(module name): short issue description" -labels: needs-triage, guidance ---- - - - -## :question: General Issue - - - -### The Question - - -### Environment - - - **CDK CLI Version:** - - **Module Version:** - - **Node.js Version:** - - **OS:** - - **Language (Version):** - - -### Other information - diff --git a/.github/ISSUE_TEMPLATE/tracking.md b/.github/ISSUE_TEMPLATE/tracking.md deleted file mode 100644 index b3655dfaa6dca..0000000000000 --- a/.github/ISSUE_TEMPLATE/tracking.md +++ /dev/null @@ -1,68 +0,0 @@ ---- -name: "📊 Tracking Issue" -title: "📊Tracking: [service]" -about: Add a module tracking issue (internal use only) -labels: management/tracking ---- - -Add your +1 👍 to help us prioritize high-level constructs for this service ---- - -### Overview: - - - - - - - -[AWS Docs](url) - -### Maturity: CloudFormation Resources Only - - -See the [AWS Construct Library Module Lifecycle doc](https://github.com/aws/aws-cdk-rfcs/blob/master/text/0107-construct-library-module-lifecycle.md) for more information about maturity levels. - - -### Implementation: - -See the [CDK API Reference](url) for more implementation details. - - - - - - -### Issue list: - - - - - - - - ---- -This is a 📊Tracking Issue diff --git a/.github/ISSUE_TEMPLATE/tracking.yml b/.github/ISSUE_TEMPLATE/tracking.yml new file mode 100644 index 0000000000000..0ecfc903b002c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/tracking.yml @@ -0,0 +1,76 @@ +name: Tracking Issue +description: Add a module tracking issue (internal use only) +title: "Tracking: [service]" +labels: [management/tracking] +body: + - type: markdown + attributes: + value: | + Add your +1 👍 to help us prioritize high-level constructs for this service + + - type: textarea + id: overview + attributes: + label: Overview + description: | + Summary of the service (leverage the service’s product page for the text) and a link to the relevant AWS Docs. This should be the same text that we put at the top of the package’s README.md. + validations: + required: true + + - type: input + id: cdk-api-docs-link + attributes: + label: Link to the service’s CDK Construct Library API reference page. + validations: + required: true + + - type: dropdown + id: maturity + attributes: + label: "Maturity: CloudFormation Resources Only" + description: | + See the [AWS Construct Library Module Lifecycle doc](https://github.com/aws/aws-cdk-rfcs/blob/master/text/0107-construct-library-module-lifecycle.md) for more information about maturity levels. + options: + - CloudFormation Resources Only + - Experimental + - Developer Preview + - Stable + validations: + required: true + + - type: textarea + id: implementation + attributes: + label: Implementation + description: | + Checklist of use cases, constructs, features (such as grant methods) that will ship in this package. This is not required until the issue is added to the public roadmap. + validations: + required: true + + - type: textarea + id: issue-list + attributes: + label: Issue list + description: | + Checklist of links to feature requests, bugs, and PRs that are in scope for GA release of this module (not required until the issues is added to the public roadmap). + value: | + - [ ] + - [ ] + validations: + required: true + + - type: markdown + attributes: + value: | + Labels to add: + - package/[name] (create new labels if they don’t already exist) + - needs-design (if cfn-only) + - management/roadmap (when added to the roadmap) + - in-progress (when added to “working on it” column of the roadmap) + + - type: markdown + attributes: + value: | + --- + + This is a 📊 Tracking Issue diff --git a/.github/workflows/auto-approve.yml b/.github/workflows/auto-approve.yml index dc3e7febfcf07..6e186b15f078f 100644 --- a/.github/workflows/auto-approve.yml +++ b/.github/workflows/auto-approve.yml @@ -8,10 +8,10 @@ on: jobs: auto-approve: if: > - contains(github.event.pull_request.labels.*.name, 'pr/auto-approve') && - (github.event.pull_request.user.login == 'aws-cdk-automation' - || github.event.pull_request.user.login == 'dependabot[bot]' - || github.event.pull_request.user.login == 'dependabot-preview[bot]') + github.event.pull_request.user.login == 'dependabot[bot]' + || github.event.pull_request.user.login == 'dependabot-preview[bot]' + || (contains(github.event.pull_request.labels.*.name, 'pr/auto-approve') + && github.event.pull_request.user.login == 'aws-cdk-automation') runs-on: ubuntu-latest permissions: pull-requests: write diff --git a/.github/workflows/close-stale-issues.yml b/.github/workflows/close-stale-issues.yml index db75a56aa7f8b..487a095e0c372 100644 --- a/.github/workflows/close-stale-issues.yml +++ b/.github/workflows/close-stale-issues.yml @@ -2,6 +2,7 @@ name: "Close Stale Issues" # Controls when the action will run. on: + workflow_dispatch: schedule: - cron: "0 6 * * *" @@ -9,6 +10,8 @@ jobs: cleanup: permissions: issues: write + contents: read + pull-requests: write runs-on: ubuntu-latest name: Stale issue job steps: @@ -32,8 +35,8 @@ jobs: closed-for-staleness-label: closed-for-staleness # Issue timing - days-before-stale: 7 - days-before-close: 4 + days-before-stale: 2 + days-before-close: 5 days-before-ancient: 365 # If you don't want to mark a issue as being ancient based on a @@ -43,6 +46,6 @@ jobs: minimum-upvotes-to-exempt: 5 repo-token: ${{ secrets.GITHUB_TOKEN }} - # loglevel: DEBUG + loglevel: DEBUG # Set dry-run to true to not perform label or close actions. dry-run: false diff --git a/.github/workflows/issue-label-assign.yml b/.github/workflows/issue-label-assign.yml index 0d34e0fa4d4a0..1c9c5997781bd 100644 --- a/.github/workflows/issue-label-assign.yml +++ b/.github/workflows/issue-label-assign.yml @@ -40,20 +40,20 @@ jobs: {"area":"@aws-cdk/aws-appmesh","keywords":["aws-appmesh","app-mesh","GatewayRoute","VirtualGateway","VirtualNode","VirtualRouter","VirtualService"],"labels":["@aws-cdk/aws-appmesh"],"assignees":["Seiya6329"]}, {"area":"@aws-cdk/aws-appstream","keywords":["aws-appstream","app-stream"],"labels":["@aws-cdk/aws-appstream"],"assignees":["madeline-k"]}, {"area":"@aws-cdk/aws-appsync","keywords":["aws-appsync","app-sync","appsyncfunction","graphqlapi","dynamodbdatasource","lambdadatasource","nonedatasource","rdsdatasource","resolver"],"labels":["@aws-cdk/aws-appsync"],"assignees":["otaviomacedo"]}, - {"area":"@aws-cdk/aws-athena","keywords":["aws-athena","athena","cfndatacatalog","cfnnamedquery","cfnworkgroup"],"labels":["@aws-cdk/aws-athena"],"assignees":["BenChaimberg"]}, + {"area":"@aws-cdk/aws-athena","keywords":["aws-athena","athena","cfndatacatalog","cfnnamedquery","cfnworkgroup"],"labels":["@aws-cdk/aws-athena"],"assignees":["comcalvi"]}, {"area":"@aws-cdk/aws-auditmanager","keywords":["(aws-auditmanager)","(auditmanager)"],"labels":["@aws-cdk/aws-auditmanager"],"assignees":["njlynch"]}, {"area":"@aws-cdk/aws-autoscaling","keywords":["aws-autoscaling","auto-scaling","AutoScalingGroup","LifescycleHook","scheduledaction"],"labels":["@aws-cdk/aws-autoscaling"],"assignees":["comcalvi"]}, {"area":"@aws-cdk/aws-autoscaling-api","keywords":["aws-autoscaling-api","autoscaling-api"],"labels":["@aws-cdk/aws-autoscaling-api"],"assignees":["comcalvi"]}, {"area":"@aws-cdk/aws-autoscaling-common","keywords":["aws-autoscaling-common","autoscaling-common","arbitraryintervals","completescalinginterval","scalinginterval"],"labels":["@aws-cdk/aws-autoscaling-common"],"assignees":["comcalvi"]}, {"area":"@aws-cdk/aws-autoscaling-hooktargets","keywords":["aws-autoscaling-hooktargets","autoscaling hooktargets","functionhook","queuehook","topichook"],"labels":["@aws-cdk/aws-autoscaling-hooktargets"],"assignees":["comcalvi"]}, {"area":"@aws-cdk/aws-autoscalingplans","keywords":["aws-autoscalingplans","autoscaling-plans","cfnscalingplan"],"labels":["@aws-cdk/aws-autoscalingplans"],"assignees":["comcalvi"]}, - {"area":"@aws-cdk/aws-backup","keywords":["aws-backup","backupplan","backupselection","backupvault"],"labels":["@aws-cdk/aws-backup"],"assignees":["BenChaimberg"]}, + {"area":"@aws-cdk/aws-backup","keywords":["aws-backup","backupplan","backupselection","backupvault"],"labels":["@aws-cdk/aws-backup"],"assignees":["kaizen3031593"]}, {"area":"@aws-cdk/aws-batch","keywords":["aws-batch","batch","computeenvironment","jobdefinition","jobqueue"],"labels":["@aws-cdk/aws-batch"],"assignees":["madeline-k"]}, {"area":"@aws-cdk/aws-budgets","keywords":["aws-budgets","budgets","cfnbudget"],"labels":["@aws-cdk/aws-budgets"],"assignees":["njlynch"]}, {"area":"@aws-cdk/aws-cassandra","keywords":["aws-cassandra","cassandra","cfnkeyspace"],"labels":["@aws-cdk/aws-cassandra"],"assignees":["otaviomacedo"]}, {"area":"@aws-cdk/aws-ce","keywords":["aws-ce","cfnanomalymonitor","cfncostcategory"],"labels":["@aws-cdk/aws-ce"],"assignees":["njlynch"]}, {"area":"@aws-cdk/aws-certificatemanager","keywords":["aws-certificatemanager","certificate-manager","dnsvalidatedcertificate","acm"],"labels":["@aws-cdk/aws-certificatemanager"],"assignees":["njlynch"]}, - {"area":"@aws-cdk/aws-chatbot","keywords":["aws-chatbot","chatbot","slackchannelconfiguration"],"labels":["@aws-cdk/aws-chatbot"],"assignees":["BenChaimberg"]}, + {"area":"@aws-cdk/aws-chatbot","keywords":["aws-chatbot","chatbot","slackchannelconfiguration"],"labels":["@aws-cdk/aws-chatbot"],"assignees":["kaizen3031593"]}, {"area":"@aws-cdk/aws-cloud9","keywords":["aws-cloud9","cloud 9","ec2environment"],"labels":["@aws-cdk/aws-cloud9"],"assignees":["skinny85"]}, {"area":"@aws-cdk/aws-cloudformation","keywords":["aws-cloudformation","nestedstack","customresource"],"labels":["@aws-cdk/aws-cloudformation"],"assignees":["rix0rrr"]}, {"area":"@aws-cdk/aws-cloudfront","keywords":["aws-cloudfront","cloud front","cachepolicy","cloudfrontwebdistribution"],"labels":["@aws-cdk/aws-cloudfront"],"assignees":["njlynch"]}, @@ -75,9 +75,9 @@ jobs: {"area":"@aws-cdk/aws-cognito","keywords":["aws-cognito","cognito","userpool","userpoolclient","userpooldomain"],"labels":["@aws-cdk/aws-cognito"],"assignees":["nija-at"]}, {"area":"@aws-cdk/aws-config","keywords":["aws-config","accesskeysrotated","CloudFormationStackDriftDetectionCheck","CloudFormationStackNotificationCheck","managedrule"],"labels":["@aws-cdk/aws-config"],"assignees":["rix0rrr"]}, {"area":"@aws-cdk/aws-customerprofiles","keywords":["(aws-customerprofiles)","(customerprofiles)"],"labels":["@aws-cdk/aws-customerprofiles"],"assignees":["otaviomacedo"]}, - {"area":"@aws-cdk/aws-databrew","keywords":["(aws-databrew)","(databrew)"],"labels":["@aws-cdk/aws-databrew"],"assignees":["BenChaimberg"]}, - {"area":"@aws-cdk/aws-datapipeline","keywords":["aws-datapipeline","data-pipeline"],"labels":["@aws-cdk/aws-datapipeline"],"assignees":["BenChaimberg"]}, - {"area":"@aws-cdk/aws-datasync","keywords":["(aws-datasync)","(datasync)"],"labels":["@aws-cdk/aws-datasync"],"assignees":["BenChaimberg"]}, + {"area":"@aws-cdk/aws-databrew","keywords":["(aws-databrew)","(databrew)"],"labels":["@aws-cdk/aws-databrew"],"assignees":["kaizen3031593"]}, + {"area":"@aws-cdk/aws-datapipeline","keywords":["aws-datapipeline","data-pipeline"],"labels":["@aws-cdk/aws-datapipeline"],"assignees":["kaizen3031593"]}, + {"area":"@aws-cdk/aws-datasync","keywords":["(aws-datasync)","(datasync)"],"labels":["@aws-cdk/aws-datasync"],"assignees":["kaizen3031593"]}, {"area":"@aws-cdk/aws-dax","keywords":["aws-dax","dax"],"labels":["@aws-cdk/aws-dax"],"assignees":["skinny85"]}, {"area":"@aws-cdk/aws-detective","keywords":["aws-detective","detective"],"labels":["@aws-cdk/aws-detective"],"assignees":["skinny85"]}, {"area":"@aws-cdk/aws-devopsguru","keywords":["(aws-devopsguru)","(devopsguru)"],"labels":["@aws-cdk/aws-devopsguru"],"assignees":["nija-at"]}, @@ -101,9 +101,9 @@ jobs: {"area":"@aws-cdk/aws-elasticloadbalancingv2","keywords":["aws-elasticloadbalancingv2","elastic-loadbalancing-v2","elbv2","applicationlistener","applicationloadbalancer","applicationtargetgroup","networklistener","networkloadbalancer","networktargetgroup"],"labels":["@aws-cdk/aws-elasticloadbalancingv2"],"assignees":["njlynch"]}, {"area":"@aws-cdk/aws-elasticloadbalancingv2-actions","keywords":["(aws-elasticloadbalancingv2-actions)","(elasticloadbalancingv2-actions)"],"labels":["@aws-cdk/aws-elasticloadbalancingv2-actions"],"assignees":["njlynch"]}, {"area":"@aws-cdk/aws-elasticloadbalancingv2-targets","keywords":["aws-elasticloadbalancingv2-targets","elbv2 targets"],"labels":["@aws-cdk/aws-elasticloadbalancingv2-targets"],"assignees":["njlynch"]}, - {"area":"@aws-cdk/aws-elasticsearch","keywords":["aws-elasticsearch","elastic-search"],"labels":["@aws-cdk/aws-elasticsearch"],"assignees":["BenChaimberg"]}, - {"area":"@aws-cdk/aws-emr","keywords":["aws-emr","emr"],"labels":["@aws-cdk/aws-emr"],"assignees":["BenChaimberg"]}, - {"area":"@aws-cdk/aws-emrcontainers","keywords":["(aws-emrcontainers)","(emrcontainers)"],"labels":["@aws-cdk/aws-emrcontainers"],"assignees":["BenChaimberg"]}, + {"area":"@aws-cdk/aws-elasticsearch","keywords":["aws-elasticsearch","elastic-search"],"labels":["@aws-cdk/aws-elasticsearch"],"assignees":["kaizen3031593"]}, + {"area":"@aws-cdk/aws-emr","keywords":["aws-emr","emr"],"labels":["@aws-cdk/aws-emr"],"assignees":["kaizen3031593"]}, + {"area":"@aws-cdk/aws-emrcontainers","keywords":["(aws-emrcontainers)","(emrcontainers)"],"labels":["@aws-cdk/aws-emrcontainers"],"assignees":["kaizen3031593"]}, {"area":"@aws-cdk/aws-events","keywords":["aws-events","events","event-bridge","eventbus"],"labels":["@aws-cdk/aws-events"],"assignees":["rix0rrr"]}, {"area":"@aws-cdk/aws-events-targets","keywords":["aws-events-targets","events-targets","events targets"],"labels":["@aws-cdk/aws-events-targets"],"assignees":["rix0rrr"]}, {"area":"@aws-cdk/aws-eventschemas","keywords":["aws-eventschemas","event schemas"],"labels":["@aws-cdk/aws-eventschemas"],"assignees":["skinny85"]}, @@ -115,7 +115,7 @@ jobs: {"area":"@aws-cdk/aws-gamelift","keywords":["aws-gamelift","game lift"],"labels":["@aws-cdk/aws-gamelift"],"assignees":["madeline-k"]}, {"area":"@aws-cdk/aws-globalaccelerator","keywords":["aws-globalaccelerator","global-accelerator"],"labels":["@aws-cdk/aws-globalaccelerator"],"assignees":["rix0rrr"]}, {"area":"@aws-cdk/aws-globalaccelerator-endpoints","keywords":["(aws-globalaccelerator-endpoints)","(globalaccelerator-endpoints)"],"labels":["@aws-cdk/aws-globalaccelerator-endpoints"],"assignees":["rix0rrr"]}, - {"area":"@aws-cdk/aws-glue","keywords":["aws-glue","glue"],"labels":["@aws-cdk/aws-glue"],"assignees":["BenChaimberg"]}, + {"area":"@aws-cdk/aws-glue","keywords":["aws-glue","glue"],"labels":["@aws-cdk/aws-glue"],"assignees":["kaizen3031593"]}, {"area":"@aws-cdk/aws-greengrass","keywords":["aws-greengrass","green-grass"],"labels":["@aws-cdk/aws-greengrass"],"assignees":["skinny85"]}, {"area":"@aws-cdk/aws-greengrassv2","keywords":["(aws-greengrassv2)","(greengrassv2)"],"labels":["@aws-cdk/aws-greengrassv2"],"assignees":["skinny85"]}, {"area":"@aws-cdk/aws-groundstation","keywords":["(aws-groundstation)","(groundstation)"],"labels":["@aws-cdk/aws-groundstation"],"assignees":["rix0rrr"]}, @@ -138,7 +138,7 @@ jobs: {"area":"@aws-cdk/aws-kinesisanalytics-flink","keywords":["(aws-kinesisanalytics-flink)","(kinesisanalytics-flink)"],"labels":["@aws-cdk/aws-kinesisanalytics-flink"],"assignees":["otaviomacedo"]}, {"area":"@aws-cdk/aws-kinesisfirehose","keywords":["aws-kinesisfirehose","kinesisfirehose"],"labels":["@aws-cdk/aws-kinesisfirehose"],"assignees":["otaviomacedo"]}, {"area":"@aws-cdk/aws-kms","keywords":["key-management-service","aws-kms","kms"],"labels":["@aws-cdk/aws-kms"],"assignees":["njlynch"]}, - {"area":"@aws-cdk/aws-lakeformation","keywords":["data-lake","aws-lakeformation","lakeformation"],"labels":["@aws-cdk/aws-lakeformation"],"assignees":["BenChaimberg"]}, + {"area":"@aws-cdk/aws-lakeformation","keywords":["data-lake","aws-lakeformation","lakeformation"],"labels":["@aws-cdk/aws-lakeformation"],"assignees":["comcalvi"]}, {"area":"@aws-cdk/aws-lambda","keywords":["function","layerversion","aws-lambda","lambda"],"labels":["@aws-cdk/aws-lambda"],"assignees":["nija-at"]}, {"area":"@aws-cdk/aws-lambda-destinations","keywords":["(aws-lambda-destinations)","(lambda-destinations)"],"labels":["@aws-cdk/aws-lambda-destinations"],"assignees":["nija-at"]}, {"area":"@aws-cdk/aws-lambda-event-sources","keywords":["dynamoeventsource","aws-lambda-event-sources","lambda-event-sources","apieventsource","kinesiseventsource"],"labels":["@aws-cdk/aws-lambda-event-sources"],"assignees":["nija-at"]}, @@ -148,8 +148,8 @@ jobs: {"area":"@aws-cdk/aws-licensemanager","keywords":["(aws-licensemanager)","(licensemanager)"],"labels":["@aws-cdk/aws-licensemanager"],"assignees":["njlynch"]}, {"area":"@aws-cdk/aws-logs","keywords":["loggroup","aws-logs","logs","logretention"],"labels":["@aws-cdk/aws-logs"],"assignees":["rix0rrr"]}, {"area":"@aws-cdk/aws-logs-destinations","keywords":["aws-logs-destinations","lambdadestination","kinesisdestination","logs-destinations"],"labels":["@aws-cdk/aws-logs-destinations"],"assignees":["rix0rrr"]}, - {"area":"@aws-cdk/aws-lookoutmetrics","keywords":["(aws-lookoutmetrics)","(lookoutmetrics)"],"labels":["@aws-cdk/aws-lookoutmetrics"],"assignees":["BenChaimberg"]}, - {"area":"@aws-cdk/aws-lookoutvision","keywords":["(aws-lookoutvision)","(lookoutvision)"],"labels":["@aws-cdk/aws-lookoutvision"],"assignees":["BenChaimberg"]}, + {"area":"@aws-cdk/aws-lookoutmetrics","keywords":["(aws-lookoutmetrics)","(lookoutmetrics)"],"labels":["@aws-cdk/aws-lookoutmetrics"],"assignees":["comcalvi"]}, + {"area":"@aws-cdk/aws-lookoutvision","keywords":["(aws-lookoutvision)","(lookoutvision)"],"labels":["@aws-cdk/aws-lookoutvision"],"assignees":["comcalvi"]}, {"area":"@aws-cdk/aws-macie","keywords":["aws-macie","macie"],"labels":["@aws-cdk/aws-macie"],"assignees":["njlynch"]}, {"area":"@aws-cdk/aws-managedblockchain","keywords":["aws-managedblockchain","managedblockchain"],"labels":["@aws-cdk/aws-managedblockchain"],"assignees":["skinny85"]}, {"area":"@aws-cdk/aws-mediaconnect","keywords":["(aws-mediaconnect)","(mediaconnect)"],"labels":["@aws-cdk/aws-mediaconnect"],"assignees":["skinny85"]}, @@ -163,13 +163,14 @@ jobs: {"area":"@aws-cdk/aws-networkfirewall","keywords":["(aws-networkfirewall)","(networkfirewall)"],"labels":["@aws-cdk/aws-networkfirewall"],"assignees":["skinny85"]}, {"area":"@aws-cdk/aws-networkmanager","keywords":["aws-networkmanager","networkmanager","globalnetwork"],"labels":["@aws-cdk/aws-networkmanager"],"assignees":["skinny85"]}, {"area":"@aws-cdk/aws-nimblestudio","keywords":["(aws-nimblestudio)","(nimblestudio)"],"labels":["@aws-cdk/aws-nimblestudio"],"assignees":["madeline-k"]}, + {"area":"@aws-cdk/aws-opensearchservice","keywords":["aws-opensearchservice","opensearchservice","aws-opensearch","opensearch"],"labels":["@aws-cdk/aws-opensearch"],"assignees":["kaizen3031593"]}, {"area":"@aws-cdk/aws-opsworks","keywords":["aws-opsworks","opsworks"],"labels":["@aws-cdk/aws-opsworks"],"assignees":["madeline-k"]}, {"area":"@aws-cdk/aws-opsworkscm","keywords":["aws-opsworkscm","opsworkscm"],"labels":["@aws-cdk/aws-opsworkscm"],"assignees":["madeline-k"]}, {"area":"@aws-cdk/aws-personalize","keywords":["aws-personalize","personalize"],"labels":["@aws-cdk/aws-personalize"],"assignees":["njlynch"]}, {"area":"@aws-cdk/aws-pinpoint","keywords":["aws-pinpoint","pinpoint"],"labels":["@aws-cdk/aws-pinpoint"],"assignees":["otaviomacedo"]}, {"area":"@aws-cdk/aws-pinpointemail","keywords":["aws-pinpointemail","pinpointemail"],"labels":["@aws-cdk/aws-pinpointemail"],"assignees":["otaviomacedo"]}, {"area":"@aws-cdk/aws-qldb","keywords":["aws-qldb","qldb"],"labels":["@aws-cdk/aws-qldb"],"assignees":["skinny85"]}, - {"area":"@aws-cdk/aws-quicksight","keywords":["(aws-quicksight)","(quicksight)"],"labels":["@aws-cdk/aws-quicksight"],"assignees":["BenChaimberg"]}, + {"area":"@aws-cdk/aws-quicksight","keywords":["(aws-quicksight)","(quicksight)"],"labels":["@aws-cdk/aws-quicksight"],"assignees":["comcalvi"]}, {"area":"@aws-cdk/aws-ram","keywords":["aws-ram","ram", "resource-access-manager"],"labels":["@aws-cdk/aws-ram"],"assignees":["madeline-k"]}, {"area":"@aws-cdk/aws-rds","keywords":["aws-rds","rds", "database-cluster","database-instance"],"labels":["@aws-cdk/aws-rds"],"assignees":["skinny85"]}, {"area":"@aws-cdk/aws-redshift","keywords":["aws-redshift","redshift"],"labels":["@aws-cdk/aws-redshift"],"assignees":["njlynch"]}, @@ -201,9 +202,9 @@ jobs: {"area":"@aws-cdk/aws-sqs","keywords":["queue","simple-queue-service","aws-sqs","sqs","fifo"],"labels":["@aws-cdk/aws-sqs"],"assignees":["njlynch"]}, {"area":"@aws-cdk/aws-ssm","keywords":["aws-ssm","ssm","systems-manager","stringparameter","stringlistparameter"],"labels":["@aws-cdk/aws-ssm"],"assignees":["njlynch"]}, {"area":"@aws-cdk/aws-sso","keywords":["aws-sso","sso","single-sign-on"],"labels":["@aws-cdk/aws-sso"],"assignees":["skinny85"]}, - {"area":"@aws-cdk/aws-stepfunctions","keywords":["aws-stepfunctions","stepfunctions","state machine", "chain"],"labels":["@aws-cdk/aws-stepfunctions"],"assignees":["BenChaimberg"]}, - {"area":"@aws-cdk/aws-stepfunctions-tasks","keywords":["aws-stepfunctions-tasks","stepfunctions-tasks"],"labels":["@aws-cdk/aws-stepfunctions-tasks"],"assignees":["BenChaimberg"]}, - {"area":"@aws-cdk/aws-synthetics","keywords":["aws-synthetics","synthetics", "canary"],"labels":["@aws-cdk/aws-synthetics"],"assignees":["BenChaimberg"]}, + {"area":"@aws-cdk/aws-stepfunctions","keywords":["aws-stepfunctions","stepfunctions","state machine", "chain"],"labels":["@aws-cdk/aws-stepfunctions"],"assignees":["kaizen3031593"]}, + {"area":"@aws-cdk/aws-stepfunctions-tasks","keywords":["aws-stepfunctions-tasks","stepfunctions-tasks"],"labels":["@aws-cdk/aws-stepfunctions-tasks"],"assignees":["kaizen3031593"]}, + {"area":"@aws-cdk/aws-synthetics","keywords":["aws-synthetics","synthetics", "canary"],"labels":["@aws-cdk/aws-synthetics"],"assignees":["kaizen3031593"]}, {"area":"@aws-cdk/aws-timestream","keywords":["aws-timestream","timestream"],"labels":["@aws-cdk/aws-timestream"],"assignees":["skinny85"]}, {"area":"@aws-cdk/aws-transfer","keywords":["aws-transfer","transfer"],"labels":["@aws-cdk/aws-transfer"],"assignees":["otaviomacedo"]}, {"area":"@aws-cdk/aws-waf","keywords":["waf","web-application-firewall"],"labels":["@aws-cdk/aws-waf"],"assignees":["njlynch"]}, diff --git a/.github/workflows/pr-linter.yml b/.github/workflows/pr-linter.yml index 36f20b6456d0b..d88d64d89537d 100644 --- a/.github/workflows/pr-linter.yml +++ b/.github/workflows/pr-linter.yml @@ -24,10 +24,10 @@ jobs: uses: actions/checkout@v2 - name: Install & Build prlint - run: cd tools/prlint && yarn install --frozen-lockfile && yarn build+test + run: cd tools/@aws-cdk/prlint && yarn install --frozen-lockfile && yarn build+test - name: Validate - uses: ./tools/prlint + uses: ./tools/@aws-cdk/prlint env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} REPO_ROOT: ${{ github.workspace }} diff --git a/.github/workflows/yarn-upgrade.yml b/.github/workflows/yarn-upgrade.yml index 2b5737a13ec1b..ea9f2bee5dd31 100644 --- a/.github/workflows/yarn-upgrade.yml +++ b/.github/workflows/yarn-upgrade.yml @@ -18,9 +18,9 @@ jobs: uses: actions/checkout@v2 - name: Set up Node - uses: actions/setup-node@v2.4.0 + uses: actions/setup-node@v2.4.1 with: - node-version: 10 + node-version: 12 - name: Locate Yarn cache id: yarn-cache diff --git a/.gitignore b/.gitignore index a2281906f6867..70bbad3393e00 100644 --- a/.gitignore +++ b/.gitignore @@ -45,3 +45,4 @@ yarn-error.log .nzm-* /.versionrc.json +RELEASE_NOTES.md diff --git a/.gitpod.yml b/.gitpod.yml index 2e63da1c1cb98..ac367f2ce4329 100644 --- a/.gitpod.yml +++ b/.gitpod.yml @@ -3,11 +3,11 @@ github: pullRequestsFromForks: true addComment: true -image: jsii/superchain +image: jsii/superchain:1-buster-slim tasks: - init: yarn build --skip-test --no-bail --skip-prereqs --skip-compat vscode: extensions: - - dbaeumer.vscode-eslint@2.1.5:9Wg0Glx/TwD8ElFBg+FKcQ== + - dbaeumer.vscode-eslint@2.1.20 diff --git a/.yarnrc b/.yarnrc index 591e9c3d57b96..ac05beb3696fd 100644 --- a/.yarnrc +++ b/.yarnrc @@ -1 +1,9 @@ --install.check-files true # install will verify file tree of packages for consistency + +# Use the npm registry instead of yarns mirror. +# npm treats registry.npmjs.org as a special value that means 'the current +# configured package' in package-lock and npm-shrinkwrap. if we use +# registry.yarnpkg.com in our shrinkwrap then users with a custom registry will +# be forced to registry.yarnpkg.com. +# https://github.com/npm/cli/issues/3783 +registry "https://registry.npmjs.org" diff --git a/CHANGELOG.md b/CHANGELOG.md index d6b5328d87b1c..f254623e858c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,163 @@ 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. +## [1.128.0](https://github.com/aws/aws-cdk/compare/v1.127.0...v1.128.0) (2021-10-14) + + +### ⚠ BREAKING CHANGES TO EXPERIMENTAL FEATURES + +* **assertions:** Starting this release, the `assertions` module will be +published to Maven with the name 'assertions' instead of +'cdk-assertions'. + +### Features + +* **apigatewayv2-integrations:** http api - support for request parameter mapping ([#15630](https://github.com/aws/aws-cdk/issues/15630)) ([0452aed](https://github.com/aws/aws-cdk/commit/0452aed2f00198e05bd65b1d20246f7de0b24e20)) +* **cli:** hotswap deployments for ECS Services ([#16864](https://github.com/aws/aws-cdk/issues/16864)) ([ad7288f](https://github.com/aws/aws-cdk/commit/ad7288f35a17fcfbecd7080e99ece4873fa99ad2)) +* **codepipeline:** add support for string user parameters to the Lambda invoke action ([#16946](https://github.com/aws/aws-cdk/issues/16946)) ([e19ea31](https://github.com/aws/aws-cdk/commit/e19ea31dbf62446edaf5131c75246098ab05da6e)), closes [#16776](https://github.com/aws/aws-cdk/issues/16776) +* **lambda:** docker platform for architecture ([#16858](https://github.com/aws/aws-cdk/issues/16858)) ([5c258a3](https://github.com/aws/aws-cdk/commit/5c258a30367a4922e404eb26e5aa076720846fbe)) +* **lambda-event-sources:** self managed kafka: support sasl/plain authentication ([#16712](https://github.com/aws/aws-cdk/issues/16712)) ([d4ad93f](https://github.com/aws/aws-cdk/commit/d4ad93f30877b26b851caa81d3a4a1d80df55164)) +* **stepfunctions-tasks:** AWS SDK service integrations ([#16746](https://github.com/aws/aws-cdk/issues/16746)) ([ae840ff](https://github.com/aws/aws-cdk/commit/ae840ff1abb8283a1290dae5859f5729a9cf72b1)), closes [#16780](https://github.com/aws/aws-cdk/issues/16780) + + +### Bug Fixes + +* **ecs:** add ASG capacity via Capacity Provider by not specifying machineImageType ([#16361](https://github.com/aws/aws-cdk/issues/16361)) ([93b3fdc](https://github.com/aws/aws-cdk/commit/93b3fdce80f0997d7b809f9ef7e3edd1e75e1f42)), closes [#16360](https://github.com/aws/aws-cdk/issues/16360) +* **servicecatalog:** Allow users to create multiple product versions from assets. ([#16914](https://github.com/aws/aws-cdk/issues/16914)) ([958d755](https://github.com/aws/aws-cdk/commit/958d755ff7acaf016e3f8969bf5ab07d4dc2977b)) +* **codebuild:** add build image AMAZON_LINUX_2_ARM_2 ([#16931](https://github.com/aws/aws-cdk/issues/16931)) ([370cb31](https://github.com/aws/aws-cdk/commit/370cb310cce3fccc5381d8d53130e21b266de868)), closes [#16930](https://github.com/aws/aws-cdk/issues/16930) +* **core:** asset hash is different between linux and windows ([#16945](https://github.com/aws/aws-cdk/issues/16945)) ([59950dd](https://github.com/aws/aws-cdk/commit/59950dd331635fb707aac819529614c0f3e47ee5)), closes [#14555](https://github.com/aws/aws-cdk/issues/14555) [#16928](https://github.com/aws/aws-cdk/issues/16928) +* **ecs-patterns:** minScalingCapacity cannot be set to 0 ([#16961](https://github.com/aws/aws-cdk/issues/16961)) ([589f284](https://github.com/aws/aws-cdk/commit/589f284acec8530aa9824b75a5daef4632e98985)), closes [#15632](https://github.com/aws/aws-cdk/issues/15632) [#14336](https://github.com/aws/aws-cdk/issues/14336) +* **ssm:** StringParameter accepts ParameterType.AWS_EC2_IMAGE_ID as type ([#16884](https://github.com/aws/aws-cdk/issues/16884)) ([2b353be](https://github.com/aws/aws-cdk/commit/2b353be5291cbcdc56a8863038eed4a5f2adc65f)), closes [#16806](https://github.com/aws/aws-cdk/issues/16806) +* use registry.npmjs.com to fix shinkwrap resolves ([#16607](https://github.com/aws/aws-cdk/issues/16607)) ([8f91531](https://github.com/aws/aws-cdk/commit/8f91531c3c25900316d40d5564450566a03e27ee)) + + +### Miscellaneous Chores + +* **assertions:** consistent naming in maven ([#16921](https://github.com/aws/aws-cdk/issues/16921)) ([0dcd9ec](https://github.com/aws/aws-cdk/commit/0dcd9eca3a1014c39f92d9e052b67974fc751af0)) + +## [1.127.0](https://github.com/aws/aws-cdk/compare/v1.126.0...v1.127.0) (2021-10-08) + + +### ⚠ BREAKING CHANGES TO EXPERIMENTAL FEATURES + +* **assertions:** `Match.absentProperty()` becomes `Match.absent()`, and its type changes from `string` to `Matcher`. + +### Features + +* **appsync:** Lambda Authorizer for AppSync GraphqlApi ([#16743](https://github.com/aws/aws-cdk/issues/16743)) ([bdbe8b6](https://github.com/aws/aws-cdk/commit/bdbe8b6cf6ab1ae261dddeb39576749e768183b3)), closes [#16380](https://github.com/aws/aws-cdk/issues/16380) +* **chatbot:** allow adding a sns topic in existing SlackChannel ([#16643](https://github.com/aws/aws-cdk/issues/16643)) ([d29a20b](https://github.com/aws/aws-cdk/commit/d29a20bece48829e5dddbf3fd9045a96f1440c02)), closes [#15588](https://github.com/aws/aws-cdk/issues/15588) +* **cfnspec:** cloudformation spec v43.0.0 ([#16748](https://github.com/aws/aws-cdk/issues/16748)) ([7c473a6](https://github.com/aws/aws-cdk/commit/7c473a6efa1f7e07799a96f649cb32f66d178e43)) +* **cli:** hotswap deployments for StepFunctions State Machines ([#16489](https://github.com/aws/aws-cdk/issues/16489)) ([c3417f6](https://github.com/aws/aws-cdk/commit/c3417f651e45170efd339960fbb0e4957bcbd3a3)) +* **ec2:** add X2gd instances ([#16810](https://github.com/aws/aws-cdk/issues/16810)) ([6d468d2](https://github.com/aws/aws-cdk/commit/6d468d2f742aad8bc9de6bfe9650c3cdccd30a32)), closes [#16794](https://github.com/aws/aws-cdk/issues/16794) +* **ecr-assets:** control docker image asset hash ([#16070](https://github.com/aws/aws-cdk/issues/16070)) ([13f67e7](https://github.com/aws/aws-cdk/commit/13f67e7dbcf2ca7a921e7ffb932f260c74005408)), closes [#15936](https://github.com/aws/aws-cdk/issues/15936) +* **elbv2:** support ALB target for NLB ([#16687](https://github.com/aws/aws-cdk/issues/16687)) ([27cc821](https://github.com/aws/aws-cdk/commit/27cc82186c73db5e68e00448133dd6e79e13d90c)), closes [#16679](https://github.com/aws/aws-cdk/issues/16679) + + +### Bug Fixes + +* **assertions:** `hasResourceProperties` is incompatible with `Match.not` and `Match.absent` ([#16678](https://github.com/aws/aws-cdk/issues/16678)) ([6f0a507](https://github.com/aws/aws-cdk/commit/6f0a5076b1e074fd33ed118af8e48b72d7593418)), closes [#16626](https://github.com/aws/aws-cdk/issues/16626) +* **cloudfront:** EdgeFunctions cannot be created when IDs contain spaces ([#16845](https://github.com/aws/aws-cdk/issues/16845)) ([b0752c5](https://github.com/aws/aws-cdk/commit/b0752c5dcd0f1fa64b39d1b80ab2c0e0a99a72b0)), closes [#16832](https://github.com/aws/aws-cdk/issues/16832) +* **cloudwatch:** alarms with accountId fails in regions that don't support cross-account alarms ([#16875](https://github.com/aws/aws-cdk/issues/16875)) ([54472a0](https://github.com/aws/aws-cdk/commit/54472a0ccebe208dca3402367626a938731544b0)), closes [#16874](https://github.com/aws/aws-cdk/issues/16874) +* **iam:** not possible to represent `Principal: *` ([#16843](https://github.com/aws/aws-cdk/issues/16843)) ([6829a2a](https://github.com/aws/aws-cdk/commit/6829a2abe4d020d6a6eae7ff31e23b43d8762920)) +* **lambda:** currentVersion fails when architecture specified ([#16849](https://github.com/aws/aws-cdk/issues/16849)) ([8a0d369](https://github.com/aws/aws-cdk/commit/8a0d3699d7fc3dff70aa6416d30a30b57d29ff7e)), closes [#16814](https://github.com/aws/aws-cdk/issues/16814) +* **s3:** auto-delete fails when bucket has been deleted manually ([#16645](https://github.com/aws/aws-cdk/issues/16645)) ([7b4fa72](https://github.com/aws/aws-cdk/commit/7b4fa721deac1d263d86c1d552c984fa1486f42e)), closes [#16619](https://github.com/aws/aws-cdk/issues/16619) + + +### Miscellaneous Chores + +* **assertions:** replace `absentProperty()` with `absent()` and support it as a `Matcher` type ([#16653](https://github.com/aws/aws-cdk/issues/16653)) ([c980185](https://github.com/aws/aws-cdk/commit/c980185142c58821b7ae7ef0b88c6c98ca8f0246)) + +## [1.126.0](https://github.com/aws/aws-cdk/compare/v1.125.0...v1.126.0) (2021-10-05) + + +### ⚠ BREAKING CHANGES TO EXPERIMENTAL FEATURES + +* **assertions:** The `templateMatches()` API previously performed +an exact match. The default behavior has been updated to be +"object-like". + +### Features + +* **assertions:** matcher support for `templateMatches()` API ([#16789](https://github.com/aws/aws-cdk/issues/16789)) ([0fb2179](https://github.com/aws/aws-cdk/commit/0fb21799b0da3185c2d4ba91a8ef9729c71fbd5a)) +* **apprunner:** support the Service L2 construct ([#15810](https://github.com/aws/aws-cdk/issues/15810)) ([3cea941](https://github.com/aws/aws-cdk/commit/3cea9419b6c02b3b5eb952b7e03b5a132e5e9630)), closes [#14813](https://github.com/aws/aws-cdk/issues/14813) +* **aws-ec2:** userdata cfn-signal signal resource which is different than the attached resource ([#16264](https://github.com/aws/aws-cdk/issues/16264)) ([f24a1ae](https://github.com/aws/aws-cdk/commit/f24a1ae21b30868146b30a0897dc659f99241de4)) +* **backup:** expose method to add statements to the vault policy ([#16597](https://github.com/aws/aws-cdk/issues/16597)) ([3ff1537](https://github.com/aws/aws-cdk/commit/3ff15378c1463920d010231df7d4c801d28b4486)) +* **cfnspec:** cloudformation spec v42.0.0 ([#16639](https://github.com/aws/aws-cdk/issues/16639)) ([2157acd](https://github.com/aws/aws-cdk/commit/2157acd4287dc9df1ae4642bbe049c181e3432b6)) +* **cloudfront:** support Behavior-specific viewer protocol policy for CloudFrontWebDistribution ([#16389](https://github.com/aws/aws-cdk/issues/16389)) ([5c028c5](https://github.com/aws/aws-cdk/commit/5c028c54aa7635dd55095257ebe81bdf2158ea39)), closes [#7086](https://github.com/aws/aws-cdk/issues/7086) +* **cloudwatch:** support cross-environment search expressions ([#16539](https://github.com/aws/aws-cdk/issues/16539)) ([c165138](https://github.com/aws/aws-cdk/commit/c165138fa7c3456e530ffeab9b7a038914cc2dca)), closes [#9039](https://github.com/aws/aws-cdk/issues/9039) +* **eks:** `connectAutoScalingGroupCapacity` on imported clusters ([#14650](https://github.com/aws/aws-cdk/issues/14650)) ([7f7be08](https://github.com/aws/aws-cdk/commit/7f7be089fa84afd0ab009a7feca2df4315749bc3)) +* **eks:** add warning to fargateProfile ([#16631](https://github.com/aws/aws-cdk/issues/16631)) ([41fdebb](https://github.com/aws/aws-cdk/commit/41fdebb974a2b29ba461757d210fa3a8b8cdc73d)), closes [#16349](https://github.com/aws/aws-cdk/issues/16349) +* **stepfunctions-tasks:** add step concurrency level to EmrCreateCluster ([#15242](https://github.com/aws/aws-cdk/issues/15242)) ([1deea90](https://github.com/aws/aws-cdk/commit/1deea9005656c2f0f25c56e773145b6e0ebcbb1b)), closes [#15223](https://github.com/aws/aws-cdk/issues/15223) +* allow stale bot trigger manually ([#16586](https://github.com/aws/aws-cdk/issues/16586)) ([fc8cfee](https://github.com/aws/aws-cdk/commit/fc8cfee77008314d59eda8f18d2c91c23e2a23ab)) + + +### Bug Fixes + +* **eks:** Support for http proxy in EKS onEvent lambda ([#16609](https://github.com/aws/aws-cdk/issues/16609)) ([cf22280](https://github.com/aws/aws-cdk/commit/cf222806f781c3476dd942c57787ad0f4924dc04)), closes [/github.com/aws/aws-cdk/blob/7dae114b7aac46321b8d8572e6837428b4c633b2/tools/pkglint/lib/rules.ts#L1332](https://github.com/aws//github.com/aws/aws-cdk/blob/7dae114b7aac46321b8d8572e6837428b4c633b2/tools/pkglint/lib/rules.ts/issues/L1332) +* **eks:** support http proxy in EKS onEvent lambda ([#16657](https://github.com/aws/aws-cdk/issues/16657)) ([87c9570](https://github.com/aws/aws-cdk/commit/87c957029ba5adecc9dddd72d9190d8a7abb913f)), closes [/github.com/aws/aws-cdk/pull/16657#issuecomment-928260661](https://github.com/aws//github.com/aws/aws-cdk/pull/16657/issues/issuecomment-928260661) [/github.com/aws/aws-cdk/pull/16657#issuecomment-928529421](https://github.com/aws//github.com/aws/aws-cdk/pull/16657/issues/issuecomment-928529421) [/github.com/aws/aws-cdk/blob/7dae114b7aac46321b8d8572e6837428b4c633b2/tools/pkglint/lib/rules.ts#L1332](https://github.com/aws//github.com/aws/aws-cdk/blob/7dae114b7aac46321b8d8572e6837428b4c633b2/tools/pkglint/lib/rules.ts/issues/L1332) +* **cli:** progress bar overshoots count by 1 for stack updates ([#16168](https://github.com/aws/aws-cdk/issues/16168)) ([0c8ecb8](https://github.com/aws/aws-cdk/commit/0c8ecb8cfc2cec9fd8c9f238c049b604a0f149fe)) +* **config:** add SourceAccount condition to Lambda permission ([#16617](https://github.com/aws/aws-cdk/issues/16617)) ([cfcaf45](https://github.com/aws/aws-cdk/commit/cfcaf452da163efa33df752b0ff026b3ea608dfc)) +* **elasticloadbalancingv2:** Incorrect validation on `NetworkLoadBalancer.configureHealthCheck()` ([#16445](https://github.com/aws/aws-cdk/issues/16445)) ([140892a](https://github.com/aws/aws-cdk/commit/140892af639c78eebebecf687eb1b37ab75d643d)) +* **iam:** `User.fromUserArn` does not work for ARNs that include a path ([#16269](https://github.com/aws/aws-cdk/issues/16269)) ([5c69c94](https://github.com/aws/aws-cdk/commit/5c69c941bc5e7284f5873110e7c7c86cdeba42fb)), closes [40aws-cdk/aws-iam/lib/role.ts#L191-L194](https://github.com/40aws-cdk/aws-iam/lib/role.ts/issues/L191-L194) [#16256](https://github.com/aws/aws-cdk/issues/16256) +* **s3:** setting `autoDeleteObjects` to `false` empties the bucket ([#16756](https://github.com/aws/aws-cdk/issues/16756)) ([21836f2](https://github.com/aws/aws-cdk/commit/21836f249395045a4a697fbfe553fe17e1c5e6a1)), closes [#16603](https://github.com/aws/aws-cdk/issues/16603) +* **route53-targets:** ApiGateway does not accept RestApiBase ([#16610](https://github.com/aws/aws-cdk/issues/16610)) ([20071bb](https://github.com/aws/aws-cdk/commit/20071bb12648adeab96e4dbcb31f5bd50c5f631d)), closes [#16227](https://github.com/aws/aws-cdk/issues/16227) +* **sns:** cannot use numeric filter policy with 0 values ([#16551](https://github.com/aws/aws-cdk/issues/16551)) ([62b6762](https://github.com/aws/aws-cdk/commit/62b6762195324cf04758ab96ed20925b4939b773)), closes [#16549](https://github.com/aws/aws-cdk/issues/16549) + + +### Reverts + +* **aws-eks:** "fix(aws-eks): Support for http proxy in EKS onEvent lambda" ([#16651](https://github.com/aws/aws-cdk/issues/16651)) ([376c837](https://github.com/aws/aws-cdk/commit/376c83749cd4b5260df724dabe2e44e0dc3f792a)) + +## [1.125.0](https://github.com/aws/aws-cdk/compare/v1.124.0...v1.125.0) (2021-09-29) + + +### Features + +* **lambda:** support for ARM architecture ([b3ba35e](https://github.com/aws/aws-cdk/commit/b3ba35e9b8b157303a29350031885eff0c73b05b)) + +## [1.124.0](https://github.com/aws/aws-cdk/compare/v1.123.0...v1.124.0) (2021-09-21) + + +### ⚠ BREAKING CHANGES TO EXPERIMENTAL FEATURES + +* **assertions:** the `findResources()` API previously returned a list of resources, but now returns a map of logical id to resource. +* **assertions:** the `findOutputs()` API previously returned a list of outputs, but now returns a map of logical id to output. +* **assertions:** the `findMappings()` API previously returned a list of mappings, but now returns a map of logical id to mapping. + +### Features + +* **assertions:** capture matching value ([#16426](https://github.com/aws/aws-cdk/issues/16426)) ([cc74f92](https://github.com/aws/aws-cdk/commit/cc74f92f275a338cb53caa7d6f124ab0dd960f0b)) +* **assertions:** findXxx() APIs now includes the logical id as part of its result ([#16454](https://github.com/aws/aws-cdk/issues/16454)) ([532a72b](https://github.com/aws/aws-cdk/commit/532a72b133e6ebd0c7b8b7c65b273bb0e6f3293c)) +* **assertions:** match into serialized json ([#16456](https://github.com/aws/aws-cdk/issues/16456)) ([fed30fc](https://github.com/aws/aws-cdk/commit/fed30fc815bac1006003524ac6232778f3c3babe)) +* **batch:** fargate support for jobs ([#15848](https://github.com/aws/aws-cdk/issues/15848)) ([066bcb1](https://github.com/aws/aws-cdk/commit/066bcb1e5d53192bd465190c8a4f81c5838987f4)), closes [#13591](https://github.com/aws/aws-cdk/issues/13591) [#13590](https://github.com/aws/aws-cdk/issues/13590) [#13591](https://github.com/aws/aws-cdk/issues/13591) +* **cfnspec:** cloudformation spec v41.1.0 ([#16472](https://github.com/aws/aws-cdk/issues/16472)) ([28875f9](https://github.com/aws/aws-cdk/commit/28875f9dda4911d3a2fcfcdc6e6d8358bee7c689)) +* **cfnspec:** cloudformation spec v41.1.0 ([#16524](https://github.com/aws/aws-cdk/issues/16524)) ([124a7a1](https://github.com/aws/aws-cdk/commit/124a7a1c20981c72bfdce0c857c87c46c6cb5f51)) +* **cfnspec:** cloudformation spec v41.2.0 ([#16550](https://github.com/aws/aws-cdk/issues/16550)) ([e047bd8](https://github.com/aws/aws-cdk/commit/e047bd80ab08f49a22408eb8c5401f4306747eff)) +* **ec2/ecs:** `cacheInContext` properties for machine images ([#16021](https://github.com/aws/aws-cdk/issues/16021)) ([430f50a](https://github.com/aws/aws-cdk/commit/430f50a546e9c575f8cdbd259367e440d985e68f)), closes [#12484](https://github.com/aws/aws-cdk/issues/12484) +* **ecs-service-extensions:** Publish Extension ([#16326](https://github.com/aws/aws-cdk/issues/16326)) ([c6c5941](https://github.com/aws/aws-cdk/commit/c6c594159c7fbda66f40fe8666f70b6806bb2d5e)) +* **glue:** Job construct ([#12506](https://github.com/aws/aws-cdk/issues/12506)) ([fc74110](https://github.com/aws/aws-cdk/commit/fc74110ff7eae544d9cfc11b2f6779169f17d145)), closes [#12443](https://github.com/aws/aws-cdk/issues/12443) +* **lambda:** configure workdir for docker image based functions ([#16111](https://github.com/aws/aws-cdk/issues/16111)) ([b3eafc2](https://github.com/aws/aws-cdk/commit/b3eafc2dc61ed69de20196fa08a4df3c29ecc894)) +* **lambda:** use bundling docker image from ECR public for dotnet and go runtimes ([#16281](https://github.com/aws/aws-cdk/issues/16281)) ([9bbfd18](https://github.com/aws/aws-cdk/commit/9bbfd185c2383612e2be7317a091b72cc5e7a120)) +* **neptune:** add engine version 1.0.5.0 ([#16394](https://github.com/aws/aws-cdk/issues/16394)) ([deaac4a](https://github.com/aws/aws-cdk/commit/deaac4a16e957bd046f24a6c26d735fc4cf980bd)), closes [#16388](https://github.com/aws/aws-cdk/issues/16388) +* **pipeline:** allow enabling KMS key rotation for cross-region Stacks ([#16468](https://github.com/aws/aws-cdk/issues/16468)) ([2a629dd](https://github.com/aws/aws-cdk/commit/2a629dd7a86cc36c3a503bfc5957880c9edd4d49)), closes [#14381](https://github.com/aws/aws-cdk/issues/14381) +* **rds:** region replication for generated secrets ([#16497](https://github.com/aws/aws-cdk/issues/16497)) ([1e9d8be](https://github.com/aws/aws-cdk/commit/1e9d8be0a81e1f875bf8b31c701e1069bb98728e)), closes [#16480](https://github.com/aws/aws-cdk/issues/16480) +* **redshift:** manage database users and tables via cdk ([#15931](https://github.com/aws/aws-cdk/issues/15931)) ([a9d5118](https://github.com/aws/aws-cdk/commit/a9d51185a144cd4962c85227ae5b904510399fa4)), closes [#9815](https://github.com/aws/aws-cdk/issues/9815) +* **s3-deployment:** enable efs support for handling large files in lambda ([#15220](https://github.com/aws/aws-cdk/issues/15220)) ([2737119](https://github.com/aws/aws-cdk/commit/27371197a24ce6c9212fc99e120c5d77fa08065e)) +* **sns:** adding support for firehose subscription protocol ([#15764](https://github.com/aws/aws-cdk/issues/15764)) ([18aff6b](https://github.com/aws/aws-cdk/commit/18aff6b4c0a5e17c64685ac384b243c16cd910f1)) +* **stepfunctions-tasks:** support Associate Workflow Executions on StepFunctionsStartExecution via associateWithParent property ([#16475](https://github.com/aws/aws-cdk/issues/16475)) ([7d3b90b](https://github.com/aws/aws-cdk/commit/7d3b90b2097aa9b7170a77befcee5822d5d0c3e7)), closes [#14778](https://github.com/aws/aws-cdk/issues/14778) + + +### Bug Fixes + +* **apigatewayv2:** ApiMapping does not depend on DomainName ([#16201](https://github.com/aws/aws-cdk/issues/16201)) ([1e247d8](https://github.com/aws/aws-cdk/commit/1e247d89adbc09ff79b87753fcd78b238a6752e8)), closes [#15464](https://github.com/aws/aws-cdk/issues/15464) +* **cloudformation-diff:** cdk diff not picking up differences if old/new value is in format n.n.n ([#16050](https://github.com/aws/aws-cdk/issues/16050)) ([38426c9](https://github.com/aws/aws-cdk/commit/38426c985d5e0713bbbf14fa639520eca6294124)), closes [#15935](https://github.com/aws/aws-cdk/issues/15935) +* **config:** the IGW mapping to correct resource type ([#16464](https://github.com/aws/aws-cdk/issues/16464)) ([23d9b6a](https://github.com/aws/aws-cdk/commit/23d9b6a7d5b213e4a1ba4a71984e8e19e3657bd7)), closes [#16463](https://github.com/aws/aws-cdk/issues/16463) +* **core:** asset hash of symlinked dir is wrong ([#16429](https://github.com/aws/aws-cdk/issues/16429)) ([36ff738](https://github.com/aws/aws-cdk/commit/36ff73809a37998e15176cb8815c118e7ea0c295)) +* **ec2:** set proper role for --role argument of cfn-init ([#16503](https://github.com/aws/aws-cdk/issues/16503)) ([cdbd65d](https://github.com/aws/aws-cdk/commit/cdbd65dc525147810650b4c32d48664a38abede1)), closes [#16501](https://github.com/aws/aws-cdk/issues/16501) +* **logs:** log retention fails with OperationAbortedException ([#16083](https://github.com/aws/aws-cdk/issues/16083)) ([3e9f04d](https://github.com/aws/aws-cdk/commit/3e9f04dbbd7aadb8ab4394fefd6281f1d6d30fe0)), closes [aws#15709](https://github.com/aws/aws/issues/15709) +* **route53resolver:** FirewallDomainList throws with wildcard domains ([#16538](https://github.com/aws/aws-cdk/issues/16538)) ([643e5ee](https://github.com/aws/aws-cdk/commit/643e5ee519095968a758942220f1e3a6c20f54b3)), closes [#16527](https://github.com/aws/aws-cdk/issues/16527) +* **SSM API docs:** Typo `SecretString` -> `SecureString` and note how SecureStrings cannot be created via CDK ([#16228](https://github.com/aws/aws-cdk/issues/16228)) ([950e875](https://github.com/aws/aws-cdk/commit/950e875bfb431c051b5ee2fd405aaf7f2b47bfeb)) + ## [1.123.0](https://github.com/aws/aws-cdk/compare/v1.122.0...v1.123.0) (2021-09-16) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8c85b5a2ce259..b6568c7be1263 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -16,9 +16,9 @@ let us know if it's not up-to-date (even better, submit a PR with your correcti - [Getting Started](#getting-started) - [Pull Requests](#pull-requests) - [Step 1: Find something to work on](#step-1-find-something-to-work-on) - - [Step 2: Design (optional)](#step-2-design-optional) + - [Step 2: Design (optional)](#step-2-design) - [Step 3: Work your Magic](#step-3-work-your-magic) - - [Step 4: Pull Request](#step-5-pull-request) + - [Step 4: Pull Request](#step-4-pull-request) - [Step 5: Merge](#step-5-merge) - [Breaking Changes](#breaking-changes) - [Documentation](#documentation) @@ -319,7 +319,13 @@ $ yarn watch & # runs in the background ## Breaking Changes -_NOTE: Breaking changes will not be allowed in the upcoming v2 release. These instructions apply to v1._ +**_NOTE_**: _Starting with version 2.0.0 of the AWS CDK, **all modules and members vended as part of the main CDK library**_ +_**(`aws-cdk-lib`) will always be stable**; we are committing to never introduce breaking changes in a non-major bump._ +_Breaking changes are only allowed on pre-released (experimental or dev preview) modules_ +_(those with a `stability` of `experimental` in their respective `package.json` files)._ +_For v1, each module is separately released. For v2, only `stable` modules are released as part of the_ +_main `aws-cdk-lib` release, and all `experimental` modules are released independently as `-alpha` versions,_ +_and not included in the main CDK library._ Whenever you are making changes, there is a chance for those changes to be *breaking* existing users of the library. A change is breaking if there are @@ -455,6 +461,47 @@ If the new behavior is going to be breaking, the user must opt in to it, either Of these two, the first one is preferred if possible (as feature flags have non-local effects which can cause unintended effects). +### Adding new experimental ("preview") APIs + +To make sure we can keep adding features fast, while keeping our commitment to +not release breaking changes, we are introducing a new model - API Previews. +APIs that we want to get in front of developers early, and are not yet +finalized, will be added to the AWS CDK with a specific suffix: `BetaX`. APIs +with the preview suffix will never be removed, instead they will be deprecated +and replaced by either the stable version (without the suffix), or by a newer +preview version. For example, assume we add the method +`grantAwesomePowerBeta1`: + +```ts +/** + * This methods grants awesome powers + */ +grantAwesomePowerBeta1(); +``` + +Times goes by, we get feedback that this method will actually be much better +if it accept a `Principal`. Since adding a required property is a breaking +change, we will add `grantAwesomePowerBeta2()` and deprecate +`grantAwesomePowerBeta1`: + +```ts +/** +* This methods grants awesome powers to the given principal +* +* @param grantee The principal to grant powers to +*/ +grantAwesomePowerBeta2(grantee: iam.IGrantable) + +/** +* This methods grants awesome powers +* @deprecated use grantAwesomePowerBeta2 +*/ +grantAwesomePowerBeta1() +``` + +When we decide its time to graduate the API, the latest preview version will +be deprecated and the final version - `grantAwesomePower` will be added. + ## Documentation Every module's README is rendered as the landing page of the official documentation. For example, this is @@ -602,7 +649,7 @@ The following linters are used: #### eslint -All packages in the repo use a standard base configuration found at [eslintrc.js](tools/cdk-build-tools/config/eslintrc.js). +All packages in the repo use a standard base configuration found at [eslintrc.js](tools/@aws-cdk/cdk-build-tools/config/eslintrc.js). This can be customized for any package by modifying the `.eslintrc` file found at its root. If you're using the VS Code and would like to see eslint violations on it, install the [eslint @@ -780,7 +827,7 @@ the feature flag. A couple of [jest helper methods] are available for use with unit tests. These help run unit tests that test behaviour when flags are enabled or disabled in the two major versions. -[jest helper methods]: https://github.com/aws/aws-cdk/blob/master/tools/cdk-build-tools/lib/feature-flag.ts +[jest helper methods]: https://github.com/aws/aws-cdk/blob/master/tools/@aws-cdk/cdk-build-tools/lib/feature-flag.ts ## Versioning and Release diff --git a/build.sh b/build.sh index 99719cd328874..aae39e94ea730 100755 --- a/build.sh +++ b/build.sh @@ -93,4 +93,11 @@ if [ "$check_compat" == "true" ]; then /bin/bash scripts/check-api-compatibility.sh fi +# Create the release notes for the current version. These are ephemeral and not saved in source. +# Skip this step for a "bump candidate" build, where a new, fake version number has been created +# without any corresponding changelog entries. +if ! ${BUMP_CANDIDATE:-false}; then + node ./scripts/create-release-notes.js +fi + touch $BUILD_INDICATOR diff --git a/buildspec-pr.yaml b/buildspec-pr.yaml index 3d6ee87c8d1ff..647b78849b3e8 100644 --- a/buildspec-pr.yaml +++ b/buildspec-pr.yaml @@ -12,6 +12,10 @@ phases: # Install yarn if it wasn't already present in the image - yarn --version || npm -g install yarn + + # Packing the mono-libraries (monocdk & aws-cdk-lib) can cause + # memory errors. Increasing this value allows our build to more consistently succeed + - (command -v sysctl || yum install -y procps-ng) && /sbin/sysctl -w vm.max_map_count=2251954 build: commands: - /bin/bash ./build.sh --extract diff --git a/buildspec.yaml b/buildspec.yaml index 3f2bb4e7e1102..0fc990a17c805 100644 --- a/buildspec.yaml +++ b/buildspec.yaml @@ -12,6 +12,10 @@ phases: # Install yarn if it wasn't already present in the image - yarn --version || npm -g install yarn + + # Packing the mono-libraries (monocdk & aws-cdk-lib) can cause + # memory errors. Increasing this value allows our build to more consistently succeed + - /sbin/sysctl -w vm.max_map_count=2251954 build: commands: - 'if ${BUMP_CANDIDATE:-false}; then /bin/bash ./scripts/bump-candidate.sh; fi' diff --git a/bump.sh b/bump.sh index b3c04198b50d3..597cfa8e15489 100755 --- a/bump.sh +++ b/bump.sh @@ -18,6 +18,6 @@ cd ${scriptdir} yarn install --frozen-lockfile if [[ "${LEGACY_BUMP:-}" == "" ]]; then # if we're using 'cdk-release' for the bump, build that package, including all of its dependencies - npx lerna run build --include-dependencies --scope cdk-release + npx lerna run build --include-dependencies --scope @aws-cdk/cdk-release fi ${scriptdir}/scripts/bump.js ${1:-minor} diff --git a/docs/CLOUDFORMATION.md b/docs/CLOUDFORMATION.md new file mode 100644 index 0000000000000..726ec4e423ab5 --- /dev/null +++ b/docs/CLOUDFORMATION.md @@ -0,0 +1,188 @@ +# CloudFormation internals + +This is documenting CloudFormation internals, that may come in useful when developing +custom resources, working on the CLI or debugging CloudFormation operations. + +If you are a user of the CDK, you do not need to read this (except maybe out of interest). + +## CloudFormation stack lifecycle + +This shows the states a CloudFormation stack goes through in its lifetime. + +For the `_IN_PROGRESS` states, the letter `[C,U,D]` indicates whether in that +state resource `Creates`, `Updates` or `Deletes` are performed. + +`GetTemplate` will return: + +- For `Creates`: the template that we are creating. During rollback of a `Create`, it + will show the template that failed to create. +- For `Updates`: during the roll-forward it will return the template we are updating + to. During rollback, it will show the template we are rolling back to. + +```text + ╔══════════════════╗ + ║ ║ + ║ ║──────────────────┐ + ║ ║ ▼ + ╚══════════════════╝ ┌────────────────────┐ + │ │ │ + │ │ REVIEW_IN_PROGRESS │ + │ │ │ + │ └────────────────────┘ + │ │ + ├───────────────────────────┘ + ▼ + ┌────────────────────┐ ┌─────────────────────┐ ╔════════════════════╗ + │ │ │ │ ║ ║ + │ CREATE_IN_PROGRESS │─────▶│ROLLBACK_IN_PROGRESS │──┬───▶║ CREATE_FAILED ║ + │ [C] │ │ [D] │ │ ║ ║ + └────────────────────┘ └─────────────────────┘ │ ╚════════════════════╝ + │ ▼ + │ ╔════════════════════╗ + │ ║ ║ + │ ║ ROLLBACK_FAILED ║ + │ ║ ║ + ▼ ╚════════════════════╝ + ╔═════════════════════════╗ + ║ CREATE_COMPLETE ║ +┌──║ UPDATE_COMPLETE ║◀─────────────────────────────────┬─────────────────┐ +│ ║UPDATE_ROLLBACK_COMPLETE ║ │ │ +│ ╚═════════════════════════╝ │ │ +│ │ │ │ +│ │ │ │ +│ ▼ │ │ +│ ┌────────────────────┐ ┌────────────────────┐ │ +│ │ │ │ UPDATE_COMPLETE_ │ │ +│ │ UPDATE_IN_PROGRESS │─────────────────────────▶│CLEANUP_IN_PROGRESS │ │ +│ │ [C,U] │ │ [D] │ │ +│ └────────────────────┘◀────────────────────┐ └────────────────────┘ │ +│ │ │ │ +│ ├──────────────────┐ │ │ +│ │ ▼ │ │ +│ │ ╔════════════════════╗ │ │ +│ │ ║ (no-rollback) ║ │ │ +│ │ ║ UPDATE_FAILED ║──┘ │ +│ │ ║ ║ │ +│ │ ╚════════════════════╝ │ +│ │ │ │ +│ ├──────────────────┘ │ +│ ▼ │ +│ ┌────────────────────┐ ┌──────────────────────────────┐ │ +│ │ UPDATE_ROLLBACK_ │ │ UPDATE_ROLLBACK_COMPLETE_ │ │ +│ │ IN_PROGRESS │────────────────────▶│ CLEANUP_IN_PROGRESS │──┘ +│ │ [U] │ │ [D] │ +│ └────────────────────┘ └──────────────────────────────┘ +│ │ ▲ +│ ▼ │ +│ ╔════════════════════╗ +│ ║ UPDATE_ROLLBACK_ ║ +│ ║ FAILED ║ +│ ║ ║ +│ ╚════════════════════╝ +│ │ +│ │ +│ ▼ +│ ┌─────────────────────┐ ╔════════════════════╗ +│ │ DELETE_IN_PROGRESS │ ║ ║ +└───▶│ [D] │───────▶║ DELETE_FAILED ║ + │ │ ║ ║ + └─────────────────────┘ ╚════════════════════╝ + │ + │ + ▼ + ╔════════════════════╗ + ║ ║ + ║ DELETE_COMPLETE ║ + ║ ║ + ╚════════════════════╝ +``` + +### Rollbacks + +When rolling back: + +* `ROLLBACK_IN_PROGRESS` will exclusively do deletes. +* `UPDATE_ROLLBACK_IN_PROGRESS` will do updates, + `UPDATE_ROLLBACK_COMPLETE_CLEANUP_IN_PROGRESS` will do deletes, including for + resources that got created in this update. + +## Resource lifecycle + +Below shows the lifecycle of single resource. + +Of note is that `CREATE_FAILED` and `UPDATE_FAILED` are not stable states. They will +be immediately followed by delete and an update back to the original state, respectively. + +(We have yet to research what happens when a rollback update fails). + +```text + ╔════════════════════════╗ + ║ ║ + ║ ║ + ║ ║ + ╚════════════════════════╝ + │ + │ + ▼ + ┌────────────────────────┐ ┌────────────────────┐ + │ │ │ │ + │ CREATE_IN_PROGRESS │─────────────▶│ CREATE_FAILED │──┐ + │ │ │ │ │ + └────────────────────────┘ └────────────────────┘ │ + │ │ + │ │ + ▼ │ + ╔═════════════════════════╗ │ + ║ ║ │ + ┌─────────────║ CREATE_COMPLETE ║ │ + │ ║ ║ │ + │ ╚═════════════════════════╝ │ + │ │ │ + │ │ custom resource │ + │ ▼ rollback │ + │ ┌─────────────────────────┐◀──────────────────────────────────┐ │ + │ │ │ │ │ + │ │ UPDATE_IN_PROGRESS │──────────────────────┐ │ │ + │ │ │ │ │ │ + │ └─────────────────────────┘ │ │ │ + │ │ │ │ │ + │ │ │ │ │ + │ ▼ ▼ │ │ + │ ╔═════════════════════════╗ ┌─────────────────────────┐ │ + │ ║ ║ │ │ │ + │ ║ UPDATE_COMPLETE ║◀────────│ UPDATE_FAILED │ │ + │ ║ ║ no-op │ │ │ + │ ╚═════════════════════════╝ rollback└─────────────────────────┘ │ + │ │ │ + └──────────────────────────┤ │ + │ │ + ▼ │ + ┌─────────────────────────┐ │ + │ │ │ +┌────────────────────────────────▶│ DELETE_IN_PROGRESS │◀────────────────────────────────────┤ +│ │ │ │ +│ └─────────────────────────┘ │ +│ │ │ +│ ┌─────────────────────────────────┼──────────────────────────────────┐ │ +│ │ │ │ │ +│ ▼ ▼ ▼ │ +╔═════════════════════════╗ ╔═════════════════════════╗ ╔═════════════════════════╗ │ +║ ║ ║ ║ ║ ║ │ +║ DELETE_FAILED ║ ║ DELETE_SKIPPED ║ ║ DELETE_COMPLETE ║◀─┘ +║ ║ ║ ║ ║ ║ +╚═════════════════════════╝ ╚═════════════════════════╝ ╚═════════════════════════╝ +``` + +### Custom Resources + +- A custom resource is updated whenever any of its properties change. It is not + re-executed when its source code changes. +- Boolean properties are stringified. `true` and `false` in `Properties` are turned + into `"true"` and `"false"`. +- When releasing a new version of a custom resource, be aware that you may still + get properties from any of its previous versions. +- If you return a different PhysicalId from a custom resource during an Update, + CloudFormation will send a `Delete` of the previous PhysicalId during + cleanup. +- If an `Update` fails, CloudFormation will trigger a second `Update` during rollback. + The rollback update will have `ResourceProperties=OLD` and `OldResourceProperties=NEW`. \ No newline at end of file diff --git a/lerna.json b/lerna.json index 0fcae573a32ae..81738d74fb433 100644 --- a/lerna.json +++ b/lerna.json @@ -9,7 +9,9 @@ "packages/@monocdk-experiment/*", "packages/@aws-cdk/*/lambda-packages/*", "tools/*", - "scripts/script-tests" + "tools/@aws-cdk/*", + "scripts/script-tests", + "packages/individual-packages/*" ], "rejectCycles": "true", "version": "0.0.0" diff --git a/package.json b/package.json index 029b1989ea072..97612d72cea6f 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "include": "dependencies/node-version" }, "scripts": { - "pkglint": "lerna --scope pkglint run build && lerna run pkglint", + "pkglint": "lerna --scope @aws-cdk/pkglint run build && lerna run pkglint", "build": "./build.sh", "pack": "./pack.sh", "compat": "./scripts/check-api-compatibility.sh", @@ -18,21 +18,19 @@ "@yarnpkg/lockfile": "^1.1.0", "conventional-changelog-cli": "^2.1.1", "fs-extra": "^9.1.0", - "graceful-fs": "^4.2.6", - "jest-junit": "^12.2.0", - "jsii-diff": "^1.34.0", - "jsii-pacmak": "^1.34.0", - "jsii-reflect": "^1.34.0", - "jsii-rosetta": "^1.34.0", + "graceful-fs": "^4.2.8", + "jest-junit": "^12.3.0", + "jsii-diff": "^1.39.0", + "jsii-pacmak": "^1.39.0", + "jsii-reflect": "^1.39.0", + "jsii-rosetta": "^1.39.0", "lerna": "^4.0.0", "patch-package": "^6.4.7", "standard-version": "^9.3.1", "typescript": "~3.9.10" }, - "tap-mocha-reporter-resolutions-comment": "should be removed or reviewed when nodeunit dependency is dropped or adjusted", "resolutions": { - "tap-mocha-reporter": "^5.0.1", - "string-width": "^4.2.2" + "string-width": "^4.2.3" }, "repository": { "type": "git", @@ -66,7 +64,9 @@ "packages/@monocdk-experiment/*", "packages/@aws-cdk/*/lambda-packages/*", "tools/*", - "scripts/script-tests" + "tools/@aws-cdk/*", + "scripts/@aws-cdk/script-tests", + "packages/individual-packages/*" ], "nohoist": [ "**/jszip", @@ -182,5 +182,8 @@ "monocdk/yaml", "monocdk/yaml/**" ] + }, + "dependencies": { + "string-width": "^4.2.3" } } diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/.eslintrc.js b/packages/@aws-cdk-containers/ecs-service-extensions/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/.eslintrc.js +++ b/packages/@aws-cdk-containers/ecs-service-extensions/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/jest.config.js b/packages/@aws-cdk-containers/ecs-service-extensions/jest.config.js index 983d4635f71f4..e88b48ab04549 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/jest.config.js +++ b/packages/@aws-cdk-containers/ecs-service-extensions/jest.config.js @@ -1,4 +1,4 @@ -const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +const baseConfig = require('../../../tools/@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = { ...baseConfig, coverageThreshold: { diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/package.json b/packages/@aws-cdk-containers/ecs-service-extensions/package.json index 0c124971b150d..3c6620d80ecbc 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/package.json +++ b/packages/@aws-cdk-containers/ecs-service-extensions/package.json @@ -36,16 +36,13 @@ "organization": true }, "license": "Apache-2.0", - "cdk-build": { - "jest": true - }, "devDependencies": { "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", "jest": "^26.6.3", - "pkglint": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.assign-public-ip.expected.json b/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.assign-public-ip.expected.json index f3a7aeeb43fb1..1c061588d688d 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.assign-public-ip.expected.json +++ b/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.assign-public-ip.expected.json @@ -714,7 +714,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParametersc02a0f4f3094701fe7fc414690fc416909b3a1f04dcba086e366807a15f2b0b4S3Bucket52DB41A7" + "Ref": "AssetParameters1cd4a64795df8938c7ff3d71caa4b3fd27d3d5caa222517813b08ae2a6494d3eS3Bucket1AECFCFD" }, "S3Key": { "Fn::Join": [ @@ -727,7 +727,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersc02a0f4f3094701fe7fc414690fc416909b3a1f04dcba086e366807a15f2b0b4S3VersionKey0F583551" + "Ref": "AssetParameters1cd4a64795df8938c7ff3d71caa4b3fd27d3d5caa222517813b08ae2a6494d3eS3VersionKey2ACFB47F" } ] } @@ -740,7 +740,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersc02a0f4f3094701fe7fc414690fc416909b3a1f04dcba086e366807a15f2b0b4S3VersionKey0F583551" + "Ref": "AssetParameters1cd4a64795df8938c7ff3d71caa4b3fd27d3d5caa222517813b08ae2a6494d3eS3VersionKey2ACFB47F" } ] } @@ -877,7 +877,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParametersc02a0f4f3094701fe7fc414690fc416909b3a1f04dcba086e366807a15f2b0b4S3Bucket52DB41A7" + "Ref": "AssetParameters1cd4a64795df8938c7ff3d71caa4b3fd27d3d5caa222517813b08ae2a6494d3eS3Bucket1AECFCFD" }, "S3Key": { "Fn::Join": [ @@ -890,7 +890,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersc02a0f4f3094701fe7fc414690fc416909b3a1f04dcba086e366807a15f2b0b4S3VersionKey0F583551" + "Ref": "AssetParameters1cd4a64795df8938c7ff3d71caa4b3fd27d3d5caa222517813b08ae2a6494d3eS3VersionKey2ACFB47F" } ] } @@ -903,7 +903,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersc02a0f4f3094701fe7fc414690fc416909b3a1f04dcba086e366807a15f2b0b4S3VersionKey0F583551" + "Ref": "AssetParameters1cd4a64795df8938c7ff3d71caa4b3fd27d3d5caa222517813b08ae2a6494d3eS3VersionKey2ACFB47F" } ] } @@ -1044,7 +1044,7 @@ } }, "Handler": "framework.onEvent", - "Runtime": "nodejs14.x", + "Runtime": "nodejs12.x", "Timeout": 900 }, "DependsOn": [ @@ -1190,7 +1190,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters4600faecd25ab407ff0a9d16f935c93062aaea5d415e97046bb8befe6c8ec02cS3BucketD609D0D9" + "Ref": "AssetParameters1c4eb88f5a8270f387281dcff6e3493840634113c4d57044f4aff74e3ef94c2dS3Bucket4C71F166" }, "S3Key": { "Fn::Join": [ @@ -1203,7 +1203,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters4600faecd25ab407ff0a9d16f935c93062aaea5d415e97046bb8befe6c8ec02cS3VersionKey77CF589B" + "Ref": "AssetParameters1c4eb88f5a8270f387281dcff6e3493840634113c4d57044f4aff74e3ef94c2dS3VersionKey0124EFC4" } ] } @@ -1216,7 +1216,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters4600faecd25ab407ff0a9d16f935c93062aaea5d415e97046bb8befe6c8ec02cS3VersionKey77CF589B" + "Ref": "AssetParameters1c4eb88f5a8270f387281dcff6e3493840634113c4d57044f4aff74e3ef94c2dS3VersionKey0124EFC4" } ] } @@ -1242,17 +1242,17 @@ } }, "Parameters": { - "AssetParametersc02a0f4f3094701fe7fc414690fc416909b3a1f04dcba086e366807a15f2b0b4S3Bucket52DB41A7": { + "AssetParameters1cd4a64795df8938c7ff3d71caa4b3fd27d3d5caa222517813b08ae2a6494d3eS3Bucket1AECFCFD": { "Type": "String", - "Description": "S3 bucket for asset \"c02a0f4f3094701fe7fc414690fc416909b3a1f04dcba086e366807a15f2b0b4\"" + "Description": "S3 bucket for asset \"1cd4a64795df8938c7ff3d71caa4b3fd27d3d5caa222517813b08ae2a6494d3e\"" }, - "AssetParametersc02a0f4f3094701fe7fc414690fc416909b3a1f04dcba086e366807a15f2b0b4S3VersionKey0F583551": { + "AssetParameters1cd4a64795df8938c7ff3d71caa4b3fd27d3d5caa222517813b08ae2a6494d3eS3VersionKey2ACFB47F": { "Type": "String", - "Description": "S3 key for asset version \"c02a0f4f3094701fe7fc414690fc416909b3a1f04dcba086e366807a15f2b0b4\"" + "Description": "S3 key for asset version \"1cd4a64795df8938c7ff3d71caa4b3fd27d3d5caa222517813b08ae2a6494d3e\"" }, - "AssetParametersc02a0f4f3094701fe7fc414690fc416909b3a1f04dcba086e366807a15f2b0b4ArtifactHash85B8E84D": { + "AssetParameters1cd4a64795df8938c7ff3d71caa4b3fd27d3d5caa222517813b08ae2a6494d3eArtifactHashC1CF90D5": { "Type": "String", - "Description": "Artifact hash for asset \"c02a0f4f3094701fe7fc414690fc416909b3a1f04dcba086e366807a15f2b0b4\"" + "Description": "Artifact hash for asset \"1cd4a64795df8938c7ff3d71caa4b3fd27d3d5caa222517813b08ae2a6494d3e\"" }, "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1": { "Type": "String", @@ -1266,17 +1266,17 @@ "Type": "String", "Description": "Artifact hash for asset \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" }, - "AssetParameters4600faecd25ab407ff0a9d16f935c93062aaea5d415e97046bb8befe6c8ec02cS3BucketD609D0D9": { + "AssetParameters1c4eb88f5a8270f387281dcff6e3493840634113c4d57044f4aff74e3ef94c2dS3Bucket4C71F166": { "Type": "String", - "Description": "S3 bucket for asset \"4600faecd25ab407ff0a9d16f935c93062aaea5d415e97046bb8befe6c8ec02c\"" + "Description": "S3 bucket for asset \"1c4eb88f5a8270f387281dcff6e3493840634113c4d57044f4aff74e3ef94c2d\"" }, - "AssetParameters4600faecd25ab407ff0a9d16f935c93062aaea5d415e97046bb8befe6c8ec02cS3VersionKey77CF589B": { + "AssetParameters1c4eb88f5a8270f387281dcff6e3493840634113c4d57044f4aff74e3ef94c2dS3VersionKey0124EFC4": { "Type": "String", - "Description": "S3 key for asset version \"4600faecd25ab407ff0a9d16f935c93062aaea5d415e97046bb8befe6c8ec02c\"" + "Description": "S3 key for asset version \"1c4eb88f5a8270f387281dcff6e3493840634113c4d57044f4aff74e3ef94c2d\"" }, - "AssetParameters4600faecd25ab407ff0a9d16f935c93062aaea5d415e97046bb8befe6c8ec02cArtifactHash86CFA15D": { + "AssetParameters1c4eb88f5a8270f387281dcff6e3493840634113c4d57044f4aff74e3ef94c2dArtifactHash6350D824": { "Type": "String", - "Description": "Artifact hash for asset \"4600faecd25ab407ff0a9d16f935c93062aaea5d415e97046bb8befe6c8ec02c\"" + "Description": "Artifact hash for asset \"1c4eb88f5a8270f387281dcff6e3493840634113c4d57044f4aff74e3ef94c2d\"" } }, "Outputs": { diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/tsconfig.json b/packages/@aws-cdk-containers/ecs-service-extensions/tsconfig.json index b886d9b504084..124a3ce0d3346 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/tsconfig.json +++ b/packages/@aws-cdk-containers/ecs-service-extensions/tsconfig.json @@ -92,16 +92,16 @@ "path": "../../@aws-cdk/assert" }, { - "path": "../../../tools/cdk-build-tools" + "path": "../../../tools/@aws-cdk/cdk-build-tools" }, { - "path": "../../../tools/cdk-integ-tools" + "path": "../../../tools/@aws-cdk/cdk-integ-tools" }, { - "path": "../../../tools/cfn2ts" + "path": "../../../tools/@aws-cdk/cfn2ts" }, { - "path": "../../../tools/pkglint" + "path": "../../../tools/@aws-cdk/pkglint" } ], "_generated_by_jsii_": "Generated by jsii - safe to delete, and ideally should be in .gitignore" diff --git a/packages/@aws-cdk/alexa-ask/.eslintrc.js b/packages/@aws-cdk/alexa-ask/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/alexa-ask/.eslintrc.js +++ b/packages/@aws-cdk/alexa-ask/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/alexa-ask/jest.config.js b/packages/@aws-cdk/alexa-ask/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/alexa-ask/jest.config.js +++ b/packages/@aws-cdk/alexa-ask/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/alexa-ask/package.json b/packages/@aws-cdk/alexa-ask/package.json index cf42ce0ff70cd..e773c5c1e9364 100644 --- a/packages/@aws-cdk/alexa-ask/package.json +++ b/packages/@aws-cdk/alexa-ask/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "Alexa::ASK", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -74,11 +73,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/app-delivery/.eslintrc.js b/packages/@aws-cdk/app-delivery/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/app-delivery/.eslintrc.js +++ b/packages/@aws-cdk/app-delivery/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/app-delivery/jest.config.js b/packages/@aws-cdk/app-delivery/jest.config.js index cd664e1d069e5..34818e1593f6b 100644 --- a/packages/@aws-cdk/app-delivery/jest.config.js +++ b/packages/@aws-cdk/app-delivery/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +const baseConfig = require('../../../tools/@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/app-delivery/package.json b/packages/@aws-cdk/app-delivery/package.json index 9b5bb232938dd..ef9a52c744e36 100644 --- a/packages/@aws-cdk/app-delivery/package.json +++ b/packages/@aws-cdk/app-delivery/package.json @@ -54,21 +54,20 @@ "@aws-cdk/aws-codepipeline-actions": "0.0.0", "@aws-cdk/aws-events": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", + "@aws-cdk/cloud-assembly-schema": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/cx-api": "0.0.0", - "@aws-cdk/cloud-assembly-schema": "0.0.0", "constructs": "^3.3.69" }, "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "@types/nodeunit": "^0.0.32", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "fast-check": "^2.17.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "fast-check": "^2.18.0", + "jest": "^26.6.3" }, "repository": { "type": "git", @@ -82,9 +81,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "cdk-build": { - "jest": true - }, "keywords": [ "aws", "cdk" @@ -96,9 +92,9 @@ "@aws-cdk/aws-codepipeline-actions": "0.0.0", "@aws-cdk/aws-events": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", + "@aws-cdk/cloud-assembly-schema": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/cx-api": "0.0.0", - "@aws-cdk/cloud-assembly-schema": "0.0.0", "constructs": "^3.3.69" }, "engines": { diff --git a/packages/@aws-cdk/assert-internal/.eslintrc.js b/packages/@aws-cdk/assert-internal/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/assert-internal/.eslintrc.js +++ b/packages/@aws-cdk/assert-internal/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/assert-internal/jest.config.js b/packages/@aws-cdk/assert-internal/jest.config.js index ac8c47076506a..6a8dc8ed67646 100644 --- a/packages/@aws-cdk/assert-internal/jest.config.js +++ b/packages/@aws-cdk/assert-internal/jest.config.js @@ -1,4 +1,4 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = { ...baseConfig, coverageThreshold: { diff --git a/packages/@aws-cdk/assert-internal/package.json b/packages/@aws-cdk/assert-internal/package.json index 4d9ae5a6a5ec8..c8fa0b2fca84d 100644 --- a/packages/@aws-cdk/assert-internal/package.json +++ b/packages/@aws-cdk/assert-internal/package.json @@ -24,10 +24,10 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", "jest": "^26.6.3", - "pkglint": "0.0.0", "ts-jest": "^26.5.6" }, "dependencies": { @@ -57,9 +57,6 @@ }, "stability": "experimental", "maturity": "experimental", - "cdk-build": { - "jest": true - }, "publishConfig": { "tag": "latest" }, diff --git a/packages/@aws-cdk/assert/.eslintrc.js b/packages/@aws-cdk/assert/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/assert/.eslintrc.js +++ b/packages/@aws-cdk/assert/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/assert/jest.config.js b/packages/@aws-cdk/assert/jest.config.js index 582b2b3040eb0..06408ea0581b8 100644 --- a/packages/@aws-cdk/assert/jest.config.js +++ b/packages/@aws-cdk/assert/jest.config.js @@ -1,4 +1,4 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = { ...baseConfig, coverageThreshold: { diff --git a/packages/@aws-cdk/assert/package.json b/packages/@aws-cdk/assert/package.json index a4366c4372345..156a2b583f02c 100644 --- a/packages/@aws-cdk/assert/package.json +++ b/packages/@aws-cdk/assert/package.json @@ -17,7 +17,6 @@ "build+test+extract": "yarn build+test" }, "cdk-build": { - "jest": true, "pre": [ "./clone.sh" ], @@ -35,13 +34,13 @@ }, "license": "Apache-2.0", "devDependencies": { - "aws-cdk-migration": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", + "aws-cdk-migration": "0.0.0", "constructs": "^3.3.69", "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0", "ts-jest": "^26.5.6" }, "dependencies": { diff --git a/packages/@aws-cdk/assertions/.eslintrc.js b/packages/@aws-cdk/assertions/.eslintrc.js index 7d73af332f5d8..274069c3dd9e0 100644 --- a/packages/@aws-cdk/assertions/.eslintrc.js +++ b/packages/@aws-cdk/assertions/.eslintrc.js @@ -1,4 +1,4 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = { ...baseConfig, diff --git a/packages/@aws-cdk/assertions/README.md b/packages/@aws-cdk/assertions/README.md index 0c2d9d1ecdadf..47a27cbbd2513 100644 --- a/packages/@aws-cdk/assertions/README.md +++ b/packages/@aws-cdk/assertions/README.md @@ -21,20 +21,20 @@ The `Template` class includes a set of methods for writing assertions against Cl To create `Template` from CDK stack, start off with: -```ts +```ts nofixture import { Stack } from '@aws-cdk/core'; import { Template } from '@aws-cdk/assertions'; -const stack = new Stack(...) -... -const assert = Template.fromStack(stack); +const stack = new Stack(/* ... */); +// ... +const template = Template.fromStack(stack); ``` Alternatively, assertions can be run on an existing CloudFormation template - -```ts -const template = fs.readFileSync('/path/to/template/file'); -const assert = Template.fromString(template); +```ts fixture=init +const templateJson = '{ "Resources": ... }'; /* The CloudFormation template as JSON serialized string. */ +const template = Template.fromString(templateJson); ``` ## Full Template Match @@ -43,26 +43,32 @@ The simplest assertion would be to assert that the template matches a given template. ```ts -assert.templateMatches({ +const expected = { Resources: { Type: 'Foo::Bar', Properties: { Baz: 'Qux', }, }, -}); +}; + +template.templateMatches(expected); ``` -The `Template` class also supports [snapshot -testing](https://jestjs.io/docs/snapshot-testing) using jest. +By default, the `templateMatches()` API will use the an 'object-like' comparison, +which means that it will allow for the actual template to be a superset of the +given expectation. See [Special Matchers](#special-matchers) for details on how +to change this. -```ts -// using jest -expect(Template.fromStack(stack)).toMatchSnapshot(); -``` +Snapshot testing is a common technique to store a snapshot of the output and +compare it during future changes. Since CloudFormation templates are human readable, +they are a good target for åßsnapshot testing. + +The `toJSON()` method on the `Template` can be used to produce a well formatted JSON +of the CloudFormation template that can be used as a snapshot. -For non-javascript languages, the `toJSON()` can be called to get an in-memory object -of the template. +See [Snapshot Testing in Jest](https://jestjs.io/docs/snapshot-testing) and [Snapshot +Testing in Java](https://json-snapshot.github.io/). ## Counting Resources @@ -70,7 +76,7 @@ This module allows asserting the number of resources of a specific type found in a template. ```ts -assert.resourceCountIs('Foo::Bar', 2); +template.resourceCountIs('Foo::Bar', 2); ``` ## Resource Matching & Retrieval @@ -82,21 +88,23 @@ The following code asserts that the `Properties` section of a resource of type `Foo::Bar` contains the specified properties - ```ts -assert.hasResourceProperties('Foo::Bar', { +const expected = { Foo: 'Bar', Baz: 5, Qux: [ 'Waldo', 'Fred' ], -}); +}; +template.hasResourceProperties('Foo::Bar', expected); ``` Alternatively, if you would like to assert the entire resource definition, you can use the `hasResource()` API. ```ts -assert.hasResource('Foo::Bar', { +const expected = { Properties: { Foo: 'Bar' }, DependsOn: [ 'Waldo', 'Fred' ], -}); +}; +template.hasResource('Foo::Bar', expected); ``` Beyond assertions, the module provides APIs to retrieve matching resources. @@ -114,28 +122,31 @@ that matches specific properties. The following code asserts that a template con an Output with a `logicalId` of `Foo` and the specified properties - ```ts -assert.hasOutput('Foo', { +const expected = { Value: 'Bar', Export: { Name: 'ExportBaz' }, -}); +}; +template.hasOutput('Foo', expected); ``` If you want to match against all Outputs in the template, use `*` as the `logicalId`. ```ts -assert.hasOutput('*', { +const expected = { Value: 'Bar', Export: { Name: 'ExportBaz' }, -}); +}; +template.hasOutput('*', expected); ``` `findOutputs()` will return a set of outputs that match the `logicalId` and `props`, and you can use the `'*'` special case as well. ```ts -const result = assert.findOutputs('*', { +const expected = { Value: 'Fred', -}); +}; +const result = template.findOutputs('*', expected); expect(result.Foo).toEqual({ Value: 'Fred', Description: 'FooFred' }); expect(result.Bar).toEqual({ Value: 'Fred', Description: 'BarFred' }); ``` @@ -144,9 +155,9 @@ The APIs `hasMapping()` and `findMappings()` provide similar functionalities. ## Special Matchers -The expectation provided to the `hasXXX()` and `findXXX()` methods, besides -carrying literal values, as seen in the above examples, also accept special -matchers. +The expectation provided to the `hasXxx()`, `findXxx()` and `templateMatches()` +APIs, besides carrying literal values, as seen in the above examples, also accept +special matchers. They are available as part of the `Match` class. @@ -175,18 +186,20 @@ level, the list of keys in the target is a subset of the provided pattern. // } // The following will NOT throw an assertion error -assert.hasResourceProperties('Foo::Bar', { +const expected = { Fred: Match.objectLike({ Wobble: 'Flob', }), -}); +}; +template.hasResourceProperties('Foo::Bar', expected); // The following will throw an assertion error -assert.hasResourceProperties('Foo::Bar', { +const unexpected = { Fred: Match.objectLike({ Brew: 'Coffee', - }) -}); + }), +} +template.hasResourceProperties('Foo::Bar', unexpected); ``` The `Match.objectEquals()` API can be used to assert a target as a deep exact @@ -194,8 +207,8 @@ match. ### Presence and Absence -The `Match.absentProperty()` matcher can be used to specify that a specific -property should not exist on the target. This can be used within `Match.objectLike()` +The `Match.absent()` matcher can be used to specify that a specific +value should not exist on the target. This can be used within `Match.objectLike()` or outside of any matchers. ```ts @@ -214,18 +227,20 @@ or outside of any matchers. // } // The following will NOT throw an assertion error -assert.hasResourceProperties('Foo::Bar', { +const expected = { Fred: Match.objectLike({ - Bob: Match.absentProperty(), + Bob: Match.absent(), }), -}); +}; +template.hasResourceProperties('Foo::Bar', expected); // The following will throw an assertion error -assert.hasResourceProperties('Foo::Bar', { +const unexpected = { Fred: Match.objectLike({ - Wobble: Match.absentProperty(), - }) -}); + Wobble: Match.absent(), + }), +}; +template.hasResourceProperties('Foo::Bar', unexpected); ``` The `Match.anyValue()` matcher can be used to specify that a specific value should be found @@ -250,18 +265,20 @@ This matcher can be combined with any of the other matchers. // } // The following will NOT throw an assertion error -assert.hasResourceProperties('Foo::Bar', { +const expected = { Fred: { Wobble: [Match.anyValue(), "Flip"], }, -}); +}; +template.hasResourceProperties('Foo::Bar', expected); // The following will throw an assertion error -assert.hasResourceProperties('Foo::Bar', { +const unexpected = { Fred: { Wimble: Match.anyValue(), }, -}); +}; +template.hasResourceProperties('Foo::Bar', unexpected); ``` ### Array Matchers @@ -284,14 +301,16 @@ This API will perform subset match on the target. // } // The following will NOT throw an assertion error -assert.hasResourceProperties('Foo::Bar', { +const expected = { Fred: Match.arrayWith(['Flob']), -}); +}; +template.hasResourceProperties('Foo::Bar', expected); // The following will throw an assertion error -assert.hasResourceProperties('Foo::Bar', Match.objectLike({ - Fred: Match.arrayWith(['Wobble']); -}}); +const unexpected = Match.objectLike({ + Fred: Match.arrayWith(['Wobble']), +}); +template.hasResourceProperties('Foo::Bar', unexpected); ``` *Note:* The list of items in the pattern array should be in order as they appear in the @@ -319,14 +338,16 @@ not match the pattern specified. // } // The following will NOT throw an assertion error -assert.hasResourceProperties('Foo::Bar', { +const expected = { Fred: Match.not(['Flob']), -}); +}; +template.hasResourceProperties('Foo::Bar', expected); // The following will throw an assertion error -assert.hasResourceProperties('Foo::Bar', Match.objectLike({ - Fred: Match.not(['Flob', 'Cat']); -}}); +const unexpected = Match.objectLike({ + Fred: Match.not(['Flob', 'Cat']), +}); +template.hasResourceProperties('Foo::Bar', unexpected); ``` ### Serialized JSON @@ -353,18 +374,20 @@ The `Match.serializedJson()` matcher allows deep matching within a stringified J // } // The following will NOT throw an assertion error -assert.hasResourceProperties('Foo::Bar', { +const expected = { Baz: Match.serializedJson({ Fred: Match.arrayWith(["Waldo"]), }), -}); +}; +template.hasResourceProperties('Foo::Bar', expected); // The following will throw an assertion error -assert.hasResourceProperties('Foo::Bar', { +const unexpected = { Baz: Match.serializedJson({ Fred: ["Waldo", "Johnny"], }), -}); +}; +template.hasResourceProperties('Foo::Bar', unexpected); ``` [Pipeline BuildSpec]: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-codebuild-project-source.html#cfn-codebuild-project-source-buildspec @@ -392,37 +415,12 @@ matching resource. const fredCapture = new Capture(); const waldoCapture = new Capture(); -assert.hasResourceProperties('Foo::Bar', { +const expected = { Fred: fredCapture, Waldo: ["Qix", waldoCapture], -}); +} +template.hasResourceProperties('Foo::Bar', expected); fredCapture.asArray(); // returns ["Flob", "Cat"] waldoCapture.asString(); // returns "Qux" ``` - -## Strongly typed languages - -Some of the APIs documented above, such as `templateMatches()` and -`hasResourceProperties()` accept fluently an arbitrary JSON (like) structure -its parameter. -This fluency is available only in dynamically typed languages like javascript -and Python. - -For strongly typed languages, like Java, you can achieve similar fluency using -any popular JSON deserializer. The following Java example uses `Gson` - - -```java -// In Java, using text blocks and Gson -import com.google.gson.Gson; - -String json = """ - { - "Foo": "Bar", - "Baz": 5, - "Qux": [ "Waldo", "Fred" ], - } """; - -Map expected = new Gson().fromJson(json, Map.class); -assert.hasResourceProperties("Foo::Bar", expected); -``` diff --git a/packages/@aws-cdk/assertions/jest.config.js b/packages/@aws-cdk/assertions/jest.config.js index e2cea817aefd7..50cd7fd05c74f 100644 --- a/packages/@aws-cdk/assertions/jest.config.js +++ b/packages/@aws-cdk/assertions/jest.config.js @@ -1,4 +1,4 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = { ...baseConfig, coverageThreshold: { diff --git a/packages/@aws-cdk/assertions/lib/match.ts b/packages/@aws-cdk/assertions/lib/match.ts index 4fea0ed0f713e..70ad96dbee300 100644 --- a/packages/@aws-cdk/assertions/lib/match.ts +++ b/packages/@aws-cdk/assertions/lib/match.ts @@ -1,6 +1,6 @@ import { Matcher, MatchResult } from './matcher'; +import { AbsentMatch } from './private/matchers/absent'; import { getType } from './private/type'; -import { ABSENT } from './vendored/assert'; /** * Partial and special matching during template assertions. @@ -9,8 +9,8 @@ export abstract class Match { /** * Use this matcher in the place of a field's value, if the field must not be present. */ - public static absentProperty(): string { - return ABSENT; + public static absent(): Matcher { + return new AbsentMatch('absent'); } /** @@ -128,10 +128,6 @@ class LiteralMatch extends Matcher { return result; } - if (this.pattern === ABSENT) { - throw new Error('absentProperty() can only be used in an object matcher'); - } - if (actual !== this.pattern) { result.push(this, [], `Expected ${this.pattern} but received ${actual}`); } @@ -184,9 +180,10 @@ class ArrayMatch extends Matcher { const patternElement = this.pattern[patternIdx]; const matcher = Matcher.isMatcher(patternElement) ? patternElement : new LiteralMatch(this.name, patternElement); - if (this.subsequence && matcher instanceof AnyMatch) { - // array subsequence matcher is not compatible with anyValue() matcher. They don't make sense to be used together. - throw new Error('The Matcher anyValue() cannot be nested within arrayWith()'); + const matcherName = matcher.name; + if (this.subsequence && (matcherName == 'absent' || matcherName == 'anyValue')) { + // array subsequence matcher is not compatible with anyValue() or absent() matcher. They don't make sense to be used together. + throw new Error(`The Matcher ${matcherName}() cannot be nested within arrayWith()`); } const innerResult = matcher.test(actual[actualIdx]); @@ -252,13 +249,7 @@ class ObjectMatch extends Matcher { } for (const [patternKey, patternVal] of Object.entries(this.pattern)) { - if (patternVal === ABSENT) { - if (patternKey in actual) { - result.push(this, [`/${patternKey}`], 'Key should be absent'); - } - continue; - } - if (!(patternKey in actual)) { + if (!(patternKey in actual) && !(patternVal instanceof AbsentMatch)) { result.push(this, [`/${patternKey}`], 'Missing key'); continue; } @@ -338,4 +329,4 @@ class AnyMatch extends Matcher { } return result; } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/assertions/lib/private/mappings.ts b/packages/@aws-cdk/assertions/lib/private/mappings.ts index e19afe541d204..e080843dd87f8 100644 --- a/packages/@aws-cdk/assertions/lib/private/mappings.ts +++ b/packages/@aws-cdk/assertions/lib/private/mappings.ts @@ -1,8 +1,8 @@ -import { StackInspector } from '../vendored/assert'; import { filterLogicalId, formatFailure, matchSection } from './section'; +import { Template } from './template'; -export function findMappings(inspector: StackInspector, logicalId: string, props: any = {}): { [key: string]: { [key: string]: any } } { - const section: { [key: string] : {} } = inspector.value.Mappings; +export function findMappings(template: Template, logicalId: string, props: any = {}): { [key: string]: { [key: string]: any } } { + const section: { [key: string] : {} } = template.Mappings; const result = matchSection(filterLogicalId(section, logicalId), props); if (!result.match) { @@ -12,8 +12,8 @@ export function findMappings(inspector: StackInspector, logicalId: string, props return result.matches; } -export function hasMapping(inspector: StackInspector, logicalId: string, props: any): string | void { - const section: { [key: string]: {} } = inspector.value.Mappings; +export function hasMapping(template: Template, logicalId: string, props: any): string | void { + const section: { [key: string]: {} } = template.Mappings; const result = matchSection(filterLogicalId(section, logicalId), props); if (result.match) { diff --git a/packages/@aws-cdk/assertions/lib/private/matchers/absent.ts b/packages/@aws-cdk/assertions/lib/private/matchers/absent.ts new file mode 100644 index 0000000000000..0681f8ada8214 --- /dev/null +++ b/packages/@aws-cdk/assertions/lib/private/matchers/absent.ts @@ -0,0 +1,15 @@ +import { Matcher, MatchResult } from '../../matcher'; + +export class AbsentMatch extends Matcher { + constructor(public readonly name: string) { + super(); + } + + public test(actual: any): MatchResult { + const result = new MatchResult(actual); + if (actual !== undefined) { + result.push(this, [], `Received ${actual}, but key should be absent`); + } + return result; + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/assertions/lib/private/outputs.ts b/packages/@aws-cdk/assertions/lib/private/outputs.ts index 320016d22a8eb..f00f05bc9bb0f 100644 --- a/packages/@aws-cdk/assertions/lib/private/outputs.ts +++ b/packages/@aws-cdk/assertions/lib/private/outputs.ts @@ -1,8 +1,8 @@ -import { StackInspector } from '../vendored/assert'; import { filterLogicalId, formatFailure, matchSection } from './section'; +import { Template } from './template'; -export function findOutputs(inspector: StackInspector, logicalId: string, props: any = {}): { [key: string]: { [key: string]: any } } { - const section: { [key: string] : {} } = inspector.value.Outputs; +export function findOutputs(template: Template, logicalId: string, props: any = {}): { [key: string]: { [key: string]: any } } { + const section = template.Outputs; const result = matchSection(filterLogicalId(section, logicalId), props); if (!result.match) { @@ -12,8 +12,8 @@ export function findOutputs(inspector: StackInspector, logicalId: string, props: return result.matches; } -export function hasOutput(inspector: StackInspector, logicalId: string, props: any): string | void { - const section: { [key: string]: {} } = inspector.value.Outputs; +export function hasOutput(template: Template, logicalId: string, props: any): string | void { + const section: { [key: string]: {} } = template.Outputs; const result = matchSection(filterLogicalId(section, logicalId), props); if (result.match) { return; diff --git a/packages/@aws-cdk/assertions/lib/private/resources.ts b/packages/@aws-cdk/assertions/lib/private/resources.ts index 81b77346f61f5..68e8e6c2ddff8 100644 --- a/packages/@aws-cdk/assertions/lib/private/resources.ts +++ b/packages/@aws-cdk/assertions/lib/private/resources.ts @@ -1,13 +1,10 @@ -import { StackInspector } from '../vendored/assert'; +import { Match, Matcher } from '..'; +import { AbsentMatch } from './matchers/absent'; import { formatFailure, matchSection } from './section'; +import { Resource, Template } from './template'; -// Partial type for CloudFormation Resource -type Resource = { - Type: string; -} - -export function findResources(inspector: StackInspector, type: string, props: any = {}): { [key: string]: { [key: string]: any } } { - const section: { [key: string] : Resource } = inspector.value.Resources; +export function findResources(template: Template, type: string, props: any = {}): { [key: string]: { [key: string]: any } } { + const section = template.Resources; const result = matchSection(filterType(section, type), props); if (!result.match) { @@ -17,10 +14,9 @@ export function findResources(inspector: StackInspector, type: string, props: an return result.matches; } -export function hasResource(inspector: StackInspector, type: string, props: any): string | void { - const section: { [key: string]: Resource } = inspector.value.Resources; +export function hasResource(template: Template, type: string, props: any): string | void { + const section = template.Resources; const result = matchSection(filterType(section, type), props); - if (result.match) { return; } @@ -35,6 +31,39 @@ export function hasResource(inspector: StackInspector, type: string, props: any) ].join('\n'); } +export function hasResourceProperties(template: Template, type: string, props: any): string | void { + // amended needs to be a deep copy to avoid modifying the template. + let amended = JSON.parse(JSON.stringify(template)); + + // special case to exclude AbsentMatch because adding an empty Properties object will affect its evaluation. + if (!Matcher.isMatcher(props) || !(props instanceof AbsentMatch)) { + amended = addEmptyProperties(amended); + } + + return hasResource(amended, type, Match.objectLike({ + Properties: props, + })); +} + +export function countResources(template: Template, type: string): number { + const section = template.Resources; + const types = filterType(section, type); + + return Object.entries(types).length; +} + +function addEmptyProperties(template: Template): Template { + let section = template.Resources; + + Object.keys(section).map((key) => { + if (!section[key].hasOwnProperty('Properties')) { + section[key].Properties = {}; + } + }); + + return template; +} + function filterType(section: { [key: string]: Resource }, type: string): { [key: string]: Resource } { return Object.entries(section ?? {}) .filter(([_, v]) => v.Type === type) diff --git a/packages/@aws-cdk/assertions/lib/private/template.ts b/packages/@aws-cdk/assertions/lib/private/template.ts new file mode 100644 index 0000000000000..3b44368138435 --- /dev/null +++ b/packages/@aws-cdk/assertions/lib/private/template.ts @@ -0,0 +1,16 @@ +// Partial types for CloudFormation Template + +export type Template = { + Resources: { [logicalId: string]: Resource }, + Outputs: { [logicalId: string]: Output }, + Mappings: { [logicalId: string]: Mapping } +} + +export type Resource = { + Type: string; + [key: string]: any; +} + +export type Output = { [key: string]: any }; + +export type Mapping = { [key: string]: any }; \ No newline at end of file diff --git a/packages/@aws-cdk/assertions/lib/template.ts b/packages/@aws-cdk/assertions/lib/template.ts index e6f721d928576..01e0d3376dc8c 100644 --- a/packages/@aws-cdk/assertions/lib/template.ts +++ b/packages/@aws-cdk/assertions/lib/template.ts @@ -3,8 +3,8 @@ import { Match } from './match'; import { Matcher } from './matcher'; import { findMappings, hasMapping } from './private/mappings'; import { findOutputs, hasOutput } from './private/outputs'; -import { findResources, hasResource } from './private/resources'; -import * as assert from './vendored/assert'; +import { countResources, findResources, hasResource, hasResourceProperties } from './private/resources'; +import { Template as TemplateType } from './private/template'; /** * Suite of assertions that can be run on a CDK stack. @@ -39,12 +39,10 @@ export class Template { return new Template(JSON.parse(template)); } - private readonly template: { [key: string]: any }; - private readonly inspector: assert.StackInspector; + private readonly template: TemplateType; private constructor(template: { [key: string]: any }) { - this.template = template; - this.inspector = new assert.StackInspector(template); + this.template = template as TemplateType; } /** @@ -61,8 +59,10 @@ export class Template { * @param count number of expected instances */ public resourceCountIs(type: string, count: number): void { - const assertion = assert.countResources(type, count); - assertion.assertOrThrow(this.inspector); + const counted = countResources(this.template, type); + if (counted !== count) { + throw new Error(`Expected ${count} resources of type ${type} but found ${counted}`); + } } /** @@ -74,9 +74,10 @@ export class Template { * @param props the 'Properties' section of the resource as should be expected in the template. */ public hasResourceProperties(type: string, props: any): void { - this.hasResource(type, Match.objectLike({ - Properties: Matcher.isMatcher(props) ? props : Match.objectLike(props), - })); + const matchError = hasResourceProperties(this.template, type, props); + if (matchError) { + throw new Error(matchError); + } } /** @@ -88,7 +89,7 @@ export class Template { * @param props the entire defintion of the resource as should be expected in the template. */ public hasResource(type: string, props: any): void { - const matchError = hasResource(this.inspector, type, props); + const matchError = hasResource(this.template, type, props); if (matchError) { throw new Error(matchError); } @@ -102,7 +103,7 @@ export class Template { * Use the `Match` APIs to configure a different behaviour. */ public findResources(type: string, props: any = {}): { [key: string]: { [key: string]: any } } { - return findResources(this.inspector, type, props); + return findResources(this.template, type, props); } /** @@ -113,7 +114,7 @@ export class Template { * @param props the output as should be expected in the template. */ public hasOutput(logicalId: string, props: any): void { - const matchError = hasOutput(this.inspector, logicalId, props); + const matchError = hasOutput(this.template, logicalId, props); if (matchError) { throw new Error(matchError); } @@ -127,7 +128,7 @@ export class Template { * Use the `Match` APIs to configure a different behaviour. */ public findOutputs(logicalId: string, props: any = {}): { [key: string]: { [key: string]: any } } { - return findOutputs(this.inspector, logicalId, props); + return findOutputs(this.template, logicalId, props); } /** @@ -138,7 +139,7 @@ export class Template { * @param props the output as should be expected in the template. */ public hasMapping(logicalId: string, props: any): void { - const matchError = hasMapping(this.inspector, logicalId, props); + const matchError = hasMapping(this.template, logicalId, props); if (matchError) { throw new Error(matchError); } @@ -152,16 +153,23 @@ export class Template { * Use the `Match` APIs to configure a different behaviour. */ public findMappings(logicalId: string, props: any = {}): { [key: string]: { [key: string]: any } } { - return findMappings(this.inspector, logicalId, props); + return findMappings(this.template, logicalId, props); } /** * Assert that the CloudFormation template matches the given value * @param expected the expected CloudFormation template as key-value pairs. */ - public templateMatches(expected: {[key: string]: any}): void { - const assertion = assert.matchTemplate(expected); - assertion.assertOrThrow(this.inspector); + public templateMatches(expected: any): void { + const matcher = Matcher.isMatcher(expected) ? expected : Match.objectLike(expected); + const result = matcher.test(this.template); + + if (result.hasFailed()) { + throw new Error([ + 'Template did not match as expected. The following mismatches were found:', + ...result.toHumanStrings().map(s => `\t${s}`), + ].join('\n')); + } } } diff --git a/packages/@aws-cdk/assertions/package.json b/packages/@aws-cdk/assertions/package.json index 952063b3423f6..e87d1c9526302 100644 --- a/packages/@aws-cdk/assertions/package.json +++ b/packages/@aws-cdk/assertions/package.json @@ -29,7 +29,7 @@ "package": "software.amazon.awscdk.assertions", "maven": { "groupId": "software.amazon.awscdk", - "artifactId": "cdk-assertions" + "artifactId": "assertions" } }, "dotnet": { @@ -46,12 +46,18 @@ ] } }, - "projectReferences": true + "projectReferences": true, + "metadata": { + "jsii": { + "rosetta": { + "strict": true + } + } + } }, "cdk-build": { - "jest": true, - "pre": [ - "./vendor-in.sh" + "post": [ + "yarn rosetta:extract" ] }, "author": { @@ -61,12 +67,11 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "@aws-cdk/cfnspec": "0.0.0", "constructs": "^3.3.69", "jest": "^26.6.3", - "pkglint": "0.0.0", "ts-jest": "^26.5.6" }, "dependencies": { @@ -77,8 +82,8 @@ "constructs": "^3.3.69", "diff": "^5.0.0", "fast-deep-equal": "^3.1.3", - "string-width": "^4.2.2", - "table": "^6.7.1" + "string-width": "^4.2.3", + "table": "^6.7.2" }, "peerDependencies": { "@aws-cdk/cloud-assembly-schema": "0.0.0", @@ -107,15 +112,6 @@ "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" }, - "nozem": { - "ostools": ["dirname", "cd", "bash", "rm", "xargs", "sed", "mkdir", "rsync", "cat", "find"], - "additionalDirs": [ - "../cfnspec/lib", - "ARTIFACTS:../cfnspec/spec", - "../cloudformation-diff", - "../assert-internal" - ] - }, "stability": "experimental", "maturity": "experimental", "publishConfig": { diff --git a/packages/@aws-cdk/assertions/rosetta/default.ts-fixture b/packages/@aws-cdk/assertions/rosetta/default.ts-fixture new file mode 100644 index 0000000000000..53eee35747e52 --- /dev/null +++ b/packages/@aws-cdk/assertions/rosetta/default.ts-fixture @@ -0,0 +1,13 @@ +import { Construct, Stack } from '@aws-cdk/core'; +import { Capture, Match, Template } from '@aws-cdk/assertions'; + +class Fixture extends Stack { + constructor(scope: Construct, id: string) { + super(scope, id); + + const stack = new Stack(); + const template = Template.fromStack(stack); + + /// here + } +} diff --git a/packages/@aws-cdk/assertions/rosetta/init.ts-fixture b/packages/@aws-cdk/assertions/rosetta/init.ts-fixture new file mode 100644 index 0000000000000..ce18625a2744b --- /dev/null +++ b/packages/@aws-cdk/assertions/rosetta/init.ts-fixture @@ -0,0 +1,3 @@ +import { Template } from '@aws-cdk/assertions'; + +/// here \ No newline at end of file diff --git a/packages/@aws-cdk/assertions/test/match.test.ts b/packages/@aws-cdk/assertions/test/match.test.ts index b0c92a2da2c8f..0b1ce784f9023 100644 --- a/packages/@aws-cdk/assertions/test/match.test.ts +++ b/packages/@aws-cdk/assertions/test/match.test.ts @@ -77,7 +77,7 @@ describe('Matchers', () => { }); test('absent', () => { - expect(() => Match.exact(Match.absentProperty()).test('foo')).toThrow(/absentProperty/); + expect(() => Match.exact(Match.absent())).toThrow(/cannot directly contain another matcher/); }); }); @@ -125,8 +125,9 @@ describe('Matchers', () => { expectFailure(matcher, [{ foo: 'baz', fred: 'waldo' }], [/Missing element at pattern index 0/]); }); - test('absent', () => { - expect(() => Match.arrayWith([Match.absentProperty()]).test(['foo'])).toThrow(/absentProperty/); + test('incompatible with absent', () => { + matcher = Match.arrayWith(['foo', Match.absent()]); + expect(() => matcher.test(['foo', 'bar'])).toThrow(/absent\(\) cannot be nested within arrayWith\(\)/); }); test('incompatible with anyValue', () => { @@ -184,9 +185,9 @@ describe('Matchers', () => { }); test('absent', () => { - matcher = Match.objectLike({ foo: Match.absentProperty() }); + matcher = Match.objectLike({ foo: Match.absent() }); expectPass(matcher, { bar: 'baz' }); - expectFailure(matcher, { foo: 'baz' }, [/Key should be absent at \/foo/]); + expectFailure(matcher, { foo: 'baz' }, [/key should be absent at \/foo/]); }); }); @@ -363,6 +364,26 @@ describe('Matchers', () => { expectFailure(matcher, '{ "Foo"', [/invalid JSON string/i]); }); }); + + describe('absent', () => { + let matcher: Matcher; + + test('simple', () => { + matcher = Match.absent(); + expectFailure(matcher, 'foo', ['Received foo, but key should be absent']); + expectPass(matcher, undefined); + }); + + test('nested in object', () => { + matcher = Match.objectLike({ foo: Match.absent() }); + expectFailure(matcher, { foo: 'bar' }, [/key should be absent at \/foo/]); + expectFailure(matcher, { foo: [1, 2] }, [/key should be absent at \/foo/]); + expectFailure(matcher, { foo: null }, [/key should be absent at \/foo/]); + + expectPass(matcher, { foo: undefined }); + expectPass(matcher, {}); + }); + }); }); function expectPass(matcher: Matcher, target: any): void { diff --git a/packages/@aws-cdk/assertions/test/template.test.ts b/packages/@aws-cdk/assertions/test/template.test.ts index 7c3221763446c..3384cda21207f 100644 --- a/packages/@aws-cdk/assertions/test/template.test.ts +++ b/packages/@aws-cdk/assertions/test/template.test.ts @@ -82,10 +82,10 @@ describe('Template', () => { const inspect = Template.fromStack(stack); inspect.resourceCountIs('Foo::Bar', 1); - expect(() => inspect.resourceCountIs('Foo::Bar', 0)).toThrow(/has 1 resource of type Foo::Bar/); - expect(() => inspect.resourceCountIs('Foo::Bar', 2)).toThrow(/has 1 resource of type Foo::Bar/); + expect(() => inspect.resourceCountIs('Foo::Bar', 0)).toThrow('Expected 0 resources of type Foo::Bar but found 1'); + expect(() => inspect.resourceCountIs('Foo::Bar', 2)).toThrow('Expected 2 resources of type Foo::Bar but found 1'); - expect(() => inspect.resourceCountIs('Foo::Baz', 1)).toThrow(/has 0 resource of type Foo::Baz/); + expect(() => inspect.resourceCountIs('Foo::Baz', 1)).toThrow('Expected 1 resources of type Foo::Baz but found 0'); }); test('no resource', () => { @@ -94,7 +94,7 @@ describe('Template', () => { const inspect = Template.fromStack(stack); inspect.resourceCountIs('Foo::Bar', 0); - expect(() => inspect.resourceCountIs('Foo::Bar', 1)).toThrow(/has 0 resource of type Foo::Bar/); + expect(() => inspect.resourceCountIs('Foo::Bar', 1)).toThrow('Expected 1 resources of type Foo::Bar but found 0'); }); }); @@ -132,7 +132,7 @@ describe('Template', () => { Properties: { baz: 'waldo' }, }, }, - })).toThrowError(); + })).toThrowError(/Expected waldo but received qux at \/Resources\/Foo\/Properties\/baz/); }); }); @@ -248,11 +248,11 @@ describe('Template', () => { const inspect = Template.fromStack(stack); inspect.hasResource('Foo::Bar', { - Properties: Match.objectLike({ foo: Match.absentProperty() }), + Properties: Match.objectLike({ foo: Match.absent() }), }); expect(() => inspect.hasResource('Foo::Bar', { - Properties: Match.objectLike({ baz: Match.absentProperty() }), - })).toThrow(/Key should be absent at \/Properties\/baz/); + Properties: Match.objectLike({ baz: Match.absent() }), + })).toThrow(/key should be absent at \/Properties\/baz/); }); test('incorrect types', () => { @@ -269,6 +269,80 @@ describe('Template', () => { }); }); + describe('hasResourceProperties', () => { + test('exact match', () => { + const stack = new Stack(); + new CfnResource(stack, 'Foo', { + type: 'Foo::Bar', + properties: { baz: 'qux' }, + }); + + const inspect = Template.fromStack(stack); + inspect.hasResourceProperties('Foo::Bar', { baz: 'qux' }); + + expect(() => inspect.hasResourceProperties('Foo::Bar', { baz: 'waldo' })) + .toThrow(/Expected waldo but received qux at \/Properties\/baz/); + + expect(() => inspect.hasResourceProperties('Foo::Bar', { baz: 'qux', fred: 'waldo' })) + .toThrow(/Missing key at \/Properties\/fred/); + }); + + test('absent - with properties', () => { + const stack = new Stack(); + new CfnResource(stack, 'Foo', { + type: 'Foo::Bar', + properties: { baz: 'qux' }, + }); + + const inspect = Template.fromStack(stack); + + inspect.hasResourceProperties('Foo::Bar', { + bar: Match.absent(), + }); + + expect(() => inspect.hasResourceProperties('Foo::Bar', { + baz: Match.absent(), + })).toThrow(/key should be absent at \/Properties\/baz/); + }); + + test('absent - no properties', () => { + const stack = new Stack(); + new CfnResource(stack, 'Foo', { + type: 'Foo::Bar', + }); + + const inspect = Template.fromStack(stack); + + expect(() => inspect.hasResourceProperties('Foo::Bar', { bar: Match.absent(), baz: 'qux' })) + .toThrow(/Missing key at \/Properties\/baz/); + + inspect.hasResourceProperties('Foo::Bar', Match.absent()); + }); + + test('not - with properties', () => { + const stack = new Stack(); + new CfnResource(stack, 'Foo', { + type: 'Foo::Bar', + properties: { baz: 'qux' }, + }); + + const inspect = Template.fromStack(stack); + inspect.hasResourceProperties('Foo::Bar', Match.not({ + baz: 'boo', + })); + }); + + test('not - no properties', () => { + const stack = new Stack(); + new CfnResource(stack, 'Foo', { + type: 'Foo::Bar', + }); + + const inspect = Template.fromStack(stack); + inspect.hasResourceProperties('Foo::Bar', Match.not({ baz: 'qux' })); + }); + }); + describe('getResources', () => { test('matching resource type', () => { const stack = new Stack(); diff --git a/packages/@aws-cdk/assertions/vendor-in.sh b/packages/@aws-cdk/assertions/vendor-in.sh deleted file mode 100755 index 803ff1a7a28ff..0000000000000 --- a/packages/@aws-cdk/assertions/vendor-in.sh +++ /dev/null @@ -1,57 +0,0 @@ -#!/bin/bash - -set -e - -porta_sed() { - local lookup=$1 - local replacement=$2 - local file=$3 - - # inplace replacement of sed is not portable across BSD and GNU. Use backup extension and then delete. - sed -i'.del' "s^${lookup}^${replacement}^g" $file - rm $file.del -} -export -f porta_sed - -echo "⏳ Vendoring in modules..." - -scriptdir=$(cd $(dirname $0) && pwd) -cd $scriptdir - -if [[ "$PHASE" == "transform" ]]; then - # Make the script short-circuit when running in the packages/individual-packages build context. - # That's required because the build done by individual-pkg-gen does import re-writing when copying the TS files - # (because it needs to know which modules are also unstable to do the rewriting correctly), - # but the vendor.sh script runs only after the 'build' script for this package has been invoked, - # which means any TS files copied by it successfully would not have their imports re-written. - exit 0 -fi - -set -euo pipefail -dest="lib/vendored" -mkdir -p $dest - -# cfnspec -mkdir -p $dest/cfnspec -rsync -a --exclude '*.d.ts' --exclude '*.js' ../cfnspec/lib/ $dest/cfnspec/lib -rsync -a ../cfnspec/spec/ $dest/cfnspec/spec - -# cloudformation-diff -rsync -a --exclude '*.d.ts' --exclude '*.js' ../cloudformation-diff/lib/ $dest/cloudformation-diff -find $dest/cloudformation-diff -name '*.ts' | xargs -n1 bash -c 'porta_sed "$@"' _ '@aws-cdk/cfnspec' '../../cfnspec/lib' - -# assert-internal -rsync -a --exclude '*.d.ts' --exclude '*.js' ../assert-internal/lib/ $dest/assert -find $dest/assert -name '*.ts' | xargs -n1 bash -c 'porta_sed "$@"' _ '@aws-cdk/cloudformation-diff' '../../cloudformation-diff' - -# readme -cat > $dest/README.md < - Amazon API Gateway is a fully managed service that makes it easy for developers to publish, maintain, monitor, and secure APIs at any scale. Create an API to access data, business logic, or functionality from your back-end services, such @@ -79,7 +78,7 @@ The following code defines a REST API that routes all requests to the specified AWS Lambda function: ```ts -const backend = new lambda.Function(...); +declare const backend: lambda.Function; new apigateway.LambdaRestApi(this, 'myapi', { handler: backend, }); @@ -89,7 +88,7 @@ You can also supply `proxy: false`, in which case you will have to explicitly define the API model: ```ts -const backend = new lambda.Function(...); +declare const backend: lambda.Function; const api = new apigateway.LambdaRestApi(this, 'myapi', { handler: backend, proxy: false @@ -134,7 +133,9 @@ The following example shows how to integrate the `GET /book/{book_id}` method to an AWS Lambda function: ```ts -const getBookHandler = new lambda.Function(...); +declare const getBookHandler: lambda.Function; +declare const book: apigateway.Resource; + const getBookIntegration = new apigateway.LambdaIntegration(getBookHandler); book.addMethod('GET', getBookIntegration); ``` @@ -142,6 +143,9 @@ book.addMethod('GET', getBookIntegration); Integration options can be optionally be specified: ```ts +declare const getBookHandler: lambda.Function; +declare const getBookIntegration: apigateway.LambdaIntegration; + const getBookIntegration = new apigateway.LambdaIntegration(getBookHandler, { contentHandling: apigateway.ContentHandling.CONVERT_TO_TEXT, // convert to base64 credentialsPassthrough: true, // use caller identity to invoke the function @@ -151,6 +155,9 @@ const getBookIntegration = new apigateway.LambdaIntegration(getBookHandler, { Method options can optionally be specified when adding methods: ```ts +declare const book: apigateway.Resource; +declare const getBookIntegration: apigateway.LambdaIntegration; + book.addMethod('GET', getBookIntegration, { authorizationType: apigateway.AuthorizationType.IAM, apiKeyRequired: true @@ -162,9 +169,9 @@ It is possible to also integrate with AWS services in a different region. The fo ```ts const getMessageIntegration = new apigateway.AwsIntegration({ - service: 'sqs', - path: 'queueName', - region: 'eu-west-1' + service: 'sqs', + path: 'queueName', + region: 'eu-west-1' }); ``` @@ -172,11 +179,13 @@ const getMessageIntegration = new apigateway.AwsIntegration({ A usage plan specifies who can access one or more deployed API stages and methods, and the rate at which they can be accessed. The plan uses API keys to identify API clients and meters access to the associated API stages for each key. -Usage plans also allow configuring throttling limits and quota limits that are enforced on individual client API keys. +Usage plans also allow configuring throttling limits and quota limits that are enforced on individual client API keys. The following example shows how to create and asscociate a usage plan and an API key: ```ts +declare const integration: apigateway.LambdaIntegration; + const api = new apigateway.RestApi(this, 'hello-api'); const v1 = api.root.addResource('v1'); @@ -198,6 +207,10 @@ plan.addApiKey(key); To associate a plan to a given RestAPI stage: ```ts +declare const plan: apigateway.UsagePlan; +declare const api: apigateway.RestApi; +declare const echoMethod: apigateway.Method; + plan.addApiStage({ stage: api.deploymentStage, throttle: [ @@ -215,13 +228,14 @@ plan.addApiStage({ Existing usage plans can be imported into a CDK app using its id. ```ts -const importedUsagePlan = UsagePlan.fromUsagePlanId(stack, 'imported-usage-plan', ''); +const importedUsagePlan = apigateway.UsagePlan.fromUsagePlanId(this, 'imported-usage-plan', ''); ``` The name and value of the API Key can be specified at creation; if not provided, a name and value will be automatically generated by API Gateway. ```ts +declare const api: apigateway.RestApi; const key = api.addApiKey('ApiKey', { apiKeyName: 'myApiKey1', value: 'MyApiKeyThatIsAtLeast20Characters', @@ -231,14 +245,16 @@ const key = api.addApiKey('ApiKey', { Existing API keys can also be imported into a CDK app using its id. ```ts -const importedKey = ApiKey.fromApiKeyId(this, 'imported-key', ''); +const importedKey = apigateway.ApiKey.fromApiKeyId(this, 'imported-key', ''); ``` The "grant" methods can be used to give prepackaged sets of permissions to other resources. The following code provides read permission to an API key. ```ts -importedKey.grantRead(lambda); +declare const importedKey: apigateway.ApiKey; +declare const lambdaFn: lambda.Function; +importedKey.grantRead(lambdaFn); ``` ### ⚠️ Multiple API Keys @@ -254,6 +270,9 @@ being deleted remain unchanged. Make note of the logical ids of these API keys before removing any, and set it as part of the `addApiKey()` method: ```ts +declare const usageplan: apigateway.UsagePlan; +declare const apiKey: apigateway.ApiKey; + usageplan.addApiKey(apiKey, { overrideLogicalId: '...', }); @@ -271,6 +290,8 @@ The API key created has the specified rate limits, such as quota and throttles, The following example shows how to use a rate limited api key : ```ts +declare const api: apigateway.RestApi; + const key = new apigateway.RateLimitedApiKey(this, 'rate-limited-api-key', { customerId: 'hello-customer', resources: [api], @@ -300,7 +321,9 @@ const resource = api.root.addResource('v1'); You can define more parameters on the integration to tune the behavior of API Gateway ```ts -const integration = new LambdaIntegration(hello, { +declare const hello: lambda.Function; + +const integration = new apigateway.LambdaIntegration(hello, { proxy: false, requestParameters: { // You can define mapping parameters from your method to your integration @@ -317,7 +340,7 @@ const integration = new LambdaIntegration(hello, { 'application/json': JSON.stringify({ action: 'sayHello', pollId: "$util.escapeJavaScript($input.params('who'))" }) }, // This parameter defines the behavior of the engine is no suitable response template is found - passthroughBehavior: PassthroughBehavior.NEVER, + passthroughBehavior: apigateway.PassthroughBehavior.NEVER, integrationResponses: [ { // Successful response from the Lambda function, no filter defined @@ -360,17 +383,19 @@ const integration = new LambdaIntegration(hello, { You can define models for your responses (and requests) ```ts +declare const api: apigateway.RestApi; + // We define the JSON Schema for the transformed valid response const responseModel = api.addModel('ResponseModel', { contentType: 'application/json', modelName: 'ResponseModel', schema: { - schema: JsonSchemaVersion.DRAFT4, + schema: apigateway.JsonSchemaVersion.DRAFT4, title: 'pollResponse', - type: JsonSchemaType.OBJECT, + type: apigateway.JsonSchemaType.OBJECT, properties: { - state: { type: JsonSchemaType.STRING }, - greeting: { type: JsonSchemaType.STRING } + state: { type: apigateway.JsonSchemaType.STRING }, + greeting: { type: apigateway.JsonSchemaType.STRING } } } }); @@ -380,12 +405,12 @@ const errorResponseModel = api.addModel('ErrorResponseModel', { contentType: 'application/json', modelName: 'ErrorResponseModel', schema: { - schema: JsonSchemaVersion.DRAFT4, + schema: apigateway.JsonSchemaVersion.DRAFT4, title: 'errorResponse', - type: JsonSchemaType.OBJECT, + type: apigateway.JsonSchemaType.OBJECT, properties: { - state: { type: JsonSchemaType.STRING }, - message: { type: JsonSchemaType.STRING } + state: { type: apigateway.JsonSchemaType.STRING }, + message: { type: apigateway.JsonSchemaType.STRING } } } }); @@ -395,6 +420,11 @@ const errorResponseModel = api.addModel('ErrorResponseModel', { And reference all on your method definition. ```ts +declare const integration: apigateway.LambdaIntegration; +declare const resource: apigateway.Resource; +declare const responseModel: apigateway.Model; +declare const errorResponseModel: apigateway.Model; + resource.addMethod('GET', integration, { // We can mark the parameters as required requestParameters: { @@ -405,7 +435,7 @@ resource.addMethod('GET', integration, { requestValidatorName: 'test-validator', validateRequestBody: true, validateRequestParameters: false - } + }, methodResponses: [ { // Successful response from the integration @@ -455,12 +485,12 @@ integration. This means that all API methods that do not explicitly define an integration will be routed to this AWS Lambda function. ```ts -const booksBackend = new apigateway.LambdaIntegration(...); +declare const booksBackend: apigateway.LambdaIntegration; const api = new apigateway.RestApi(this, 'books', { defaultIntegration: booksBackend }); -const books = new api.root.addResource('books'); +const books = api.root.addResource('books'); books.addMethod('GET'); // integrated with `booksBackend` books.addMethod('POST'); // integrated with `booksBackend` @@ -477,8 +507,10 @@ Read more about authorization scopes Authorization scopes for a Method can be configured using the `authorizationScopes` property as shown below - ```ts +declare const books: apigateway.Resource; + books.addMethod('GET', new apigateway.HttpIntegration('http://amazon.com'), { - authorizationType: AuthorizationType.COGNITO, + authorizationType: apigateway.AuthorizationType.COGNITO, authorizationScopes: ['Scope1','Scope2'] }); ``` @@ -489,8 +521,10 @@ The `addProxy` method can be used to install a greedy `{proxy+}` resource on a path. By default, this also installs an `"ANY"` method: ```ts +declare const resource: apigateway.Resource; +declare const handler: lambda.Function; const proxy = resource.addProxy({ - defaultIntegration: new LambdaIntegration(handler), + defaultIntegration: new apigateway.LambdaIntegration(handler), // "false" will require explicitly adding methods on the `proxy` resource anyMethod: true // "true" is the default @@ -507,6 +541,9 @@ that can be used for controlling access to your REST APIs. The following CDK code provides 'execute-api' permission to an IAM user, via IAM policies, for the 'GET' method on the `books` resource: ```ts +declare const books: apigateway.Resource; +declare const iamUser: iam.User; + const getBooks = books.addMethod('GET', new apigateway.HttpIntegration('http://amazon.com'), { authorizationType: apigateway.AuthorizationType.IAM }); @@ -541,10 +578,8 @@ inputs and outputs of the Lambda handler. The following code attaches a token-based Lambda authorizer to the 'GET' Method of the Book resource: ```ts -const authFn = new lambda.Function(this, 'booksAuthorizerLambda', { - // ... - // ... -}); +declare const authFn: lambda.Function; +declare const books: apigateway.Resource; const auth = new apigateway.TokenAuthorizer(this, 'booksAuthorizer', { handler: authFn @@ -583,14 +618,12 @@ inputs and outputs of the Lambda handler. The following code attaches a request-based Lambda authorizer to the 'GET' Method of the Book resource: ```ts -const authFn = new lambda.Function(this, 'booksAuthorizerLambda', { - // ... - // ... -}); +declare const authFn: lambda.Function; +declare const books: apigateway.Resource; const auth = new apigateway.RequestAuthorizer(this, 'booksAuthorizer', { handler: authFn, - identitySources: [IdentitySource.header('Authorization')] + identitySources: [apigateway.IdentitySource.header('Authorization')] }); books.addMethod('GET', new apigateway.HttpIntegration('http://amazon.com'), { @@ -616,12 +649,13 @@ API Gateway also allows [Amazon Cognito user pools as authorizer](https://docs.a The following snippet configures a Cognito user pool as an authorizer: ```ts -const userPool = new cognito.UserPool(stack, 'UserPool'); +const userPool = new cognito.UserPool(this, 'UserPool'); const auth = new apigateway.CognitoUserPoolsAuthorizer(this, 'booksAuthorizer', { cognitoUserPools: [userPool] }); +declare const books: apigateway.Resource; books.addMethod('GET', new apigateway.HttpIntegration('http://amazon.com'), { authorizer: auth, authorizationType: apigateway.AuthorizationType.COGNITO, @@ -633,11 +667,13 @@ books.addMethod('GET', new apigateway.HttpIntegration('http://amazon.com'), { Mutual TLS can be configured to limit access to your API based by using client certificates instead of (or as an extension of) using authorization headers. ```ts -new apigw.DomainName(this, 'domain-name', { +declare const acm: any; + +new apigateway.DomainName(this, 'domain-name', { domainName: 'example.com', certificate: acm.Certificate.fromCertificateArn(this, 'cert', 'arn:aws:acm:us-east-1:1111111:certificate/11-3336f1-44483d-adc7-9cd375c5169d'), mtls: { - bucket: new Bucket(this, 'bucket'), + bucket: new s3.Bucket(this, 'bucket'), key: 'truststore.pem', version: 'version', }, @@ -712,7 +748,9 @@ To associate an API with a custom domain, use the `domainName` configuration whe you define your API: ```ts -const api = new apigw.RestApi(this, 'MyDomain', { +declare const acmCertificateForExampleCom: any; + +const api = new apigateway.RestApi(this, 'MyDomain', { domainName: { domainName: 'example.com', certificate: acmCertificateForExampleCom, @@ -734,6 +772,9 @@ CNAME records only for subdomains.) import * as route53 from '@aws-cdk/aws-route53'; import * as targets from '@aws-cdk/aws-route53-targets'; +declare const api: apigateway.RestApi; +declare const hostedZoneForExampleCom: any; + new route53.ARecord(this, 'CustomDomainAliasRecord', { zone: hostedZoneForExampleCom, target: route53.RecordTarget.fromAlias(new targets.ApiGateway(api)) @@ -743,11 +784,13 @@ new route53.ARecord(this, 'CustomDomainAliasRecord', { You can also define a `DomainName` resource directly in order to customize the default behavior: ```ts -new apigw.DomainName(this, 'custom-domain', { +declare const acmCertificateForExampleCom: any; + +new apigateway.DomainName(this, 'custom-domain', { domainName: 'example.com', certificate: acmCertificateForExampleCom, - endpointType: apigw.EndpointType.EDGE, // default is REGIONAL - securityPolicy: apigw.SecurityPolicy.TLS_1_2 + endpointType: apigateway.EndpointType.EDGE, // default is REGIONAL + securityPolicy: apigateway.SecurityPolicy.TLS_1_2 }); ``` @@ -756,6 +799,10 @@ The following example will map the URL to the `api1` API and to the `api2` API. ```ts +declare const domain: apigateway.DomainName; +declare const api1: apigateway.RestApi; +declare const api2: apigateway.RestApi; + domain.addBasePathMapping(api1, { basePath: 'go-to-api1' }); domain.addBasePathMapping(api2, { basePath: 'boom' }); ``` @@ -764,10 +811,13 @@ You can specify the API `Stage` to which this base path URL will map to. By defa `deploymentStage` of the `RestApi`. ```ts -const betaDeploy = new Deployment(this, 'beta-deployment', { +declare const domain: apigateway.DomainName; +declare const restapi: apigateway.RestApi; + +const betaDeploy = new apigateway.Deployment(this, 'beta-deployment', { api: restapi, }); -const betaStage = new Stage(this, 'beta-stage', { +const betaStage = new apigateway.Stage(this, 'beta-stage', { deployment: betaDeploy, }); domain.addBasePathMapping(restapi, { basePath: 'api/beta', stage: betaStage }); @@ -777,6 +827,8 @@ If you don't specify `basePath`, all URLs under this domain will be mapped to the API, and you won't be able to map another API to the same domain: ```ts +declare const domain: apigateway.DomainName; +declare const api: apigateway.RestApi; domain.addBasePathMapping(api); ``` @@ -786,6 +838,9 @@ domain as demonstrated above. If you wish to setup this domain with an Amazon Route53 alias, use the `targets.ApiGatewayDomain`: ```ts +declare const hostedZoneForExampleCom: any; +declare const domainName: apigateway.DomainName; + import * as route53 from '@aws-cdk/aws-route53'; import * as targets from '@aws-cdk/aws-route53-targets'; @@ -809,17 +864,17 @@ Gateway](https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-log ```ts // production stage -const prdLogGroup = new cwlogs.LogGroup(this, "PrdLogs"); +const prdLogGroup = new logs.LogGroup(this, "PrdLogs"); const api = new apigateway.RestApi(this, 'books', { deployOptions: { accessLogDestination: new apigateway.LogGroupLogDestination(prdLogGroup), accessLogFormat: apigateway.AccessLogFormat.jsonWithStandardFields() } }) -const deployment = new apigateway.Deployment(stack, 'Deployment', {api}); +const deployment = new apigateway.Deployment(this, 'Deployment', {api}); // development stage -const devLogGroup = new cwlogs.LogGroup(this, "DevLogs"); +const devLogGroup = new logs.LogGroup(this, "DevLogs"); new apigateway.Stage(this, 'dev', { deployment, accessLogDestination: new apigateway.LogGroupLogDestination(devLogGroup), @@ -840,7 +895,7 @@ new apigateway.Stage(this, 'dev', { The following code will generate the access log in the [CLF format](https://en.wikipedia.org/wiki/Common_Log_Format). ```ts -const logGroup = new cwlogs.LogGroup(this, "ApiGatewayAccessLogs"); +const logGroup = new logs.LogGroup(this, "ApiGatewayAccessLogs"); const api = new apigateway.RestApi(this, 'books', { deployOptions: { accessLogDestination: new apigateway.LogGroupLogDestination(logGroup), @@ -852,12 +907,12 @@ You can also configure your own access log format by using the `AccessLogFormat. `AccessLogField` provides commonly used fields. The following code configures access log to contain. ```ts -const logGroup = new cwlogs.LogGroup(this, "ApiGatewayAccessLogs"); +const logGroup = new logs.LogGroup(this, "ApiGatewayAccessLogs"); new apigateway.RestApi(this, 'books', { deployOptions: { accessLogDestination: new apigateway.LogGroupLogDestination(logGroup), accessLogFormat: apigateway.AccessLogFormat.custom( - `${AccessLogField.contextRequestId()} ${AccessLogField.contextErrorMessage()} ${AccessLogField.contextErrorMessageString()}` + `${apigateway.AccessLogField.contextRequestId()} ${apigateway.AccessLogField.contextErrorMessage()} ${apigateway.AccessLogField.contextErrorMessageString()}` ) } }); @@ -924,6 +979,8 @@ The following example will add an OPTIONS method to the `myResource` API resourc only allows GET and PUT HTTP requests from the origin ```ts +declare const myResource: apigateway.Resource; + myResource.addCorsPreflight({ allowOrigins: [ 'https://amazon.com' ], allowMethods: [ 'GET', 'PUT' ] @@ -937,6 +994,8 @@ API reference for a detailed list of supported configuration options. You can specify defaults this at the resource level, in which case they will be applied to the entire resource sub-tree: ```ts +declare const resource: apigateway.Resource; + const subtree = resource.addResource('subtree', { defaultCorsPreflightOptions: { allowOrigins: [ 'https://amazon.com' ] @@ -957,9 +1016,9 @@ API gateway allows you to specify an To define an endpoint type for the API gateway, use `endpointConfiguration` property: ```ts -const api = new apigw.RestApi(stack, 'api', { +const api = new apigateway.RestApi(this, 'api', { endpointConfiguration: { - types: [ apigw.EndpointType.EDGE ] + types: [ apigateway.EndpointType.EDGE ] } }); ``` @@ -972,10 +1031,11 @@ Route53 Alias DNS record which you can use to invoke your private APIs. More inf Here is an example: ```ts -const someEndpoint: IVpcEndpoint = /* Get or Create endpoint here */ -const api = new apigw.RestApi(stack, 'api', { +declare const someEndpoint: ec2.IVpcEndpoint; + +const api = new apigateway.RestApi(this, 'api', { endpointConfiguration: { - types: [ apigw.EndpointType.PRIVATE ], + types: [ apigateway.EndpointType.PRIVATE ], vpcEndpoints: [ someEndpoint ] } }); @@ -998,18 +1058,20 @@ Method. The following code sets up a private integration with a network load balancer - ```ts -const vpc = new ec2.Vpc(stack, 'VPC'); -const nlb = new elbv2.NetworkLoadBalancer(stack, 'NLB', { +import * as elbv2 from '@aws-cdk/aws-elasticloadbalancingv2'; + +const vpc = new ec2.Vpc(this, 'VPC'); +const nlb = new elbv2.NetworkLoadBalancer(this, 'NLB', { vpc, }); -const link = new apigw.VpcLink(stack, 'link', { +const link = new apigateway.VpcLink(this, 'link', { targets: [nlb], }); -const integration = new apigw.Integration({ - type: apigw.IntegrationType.HTTP_PROXY, +const integration = new apigateway.Integration({ + type: apigateway.IntegrationType.HTTP_PROXY, options: { - connectionType: apigw.ConnectionType.VPC_LINK, + connectionType: apigateway.ConnectionType.VPC_LINK, vpcLink: link, }, }); @@ -1023,9 +1085,7 @@ property. Any existing `VpcLink` resource can be imported into the CDK app via the `VpcLink.fromVpcLinkId()`. ```ts -const stack = new Stack(app, 'my-stack'); - -const awesomeLink = VpcLink.fromVpcLinkId(stack, 'awesome-vpc-link', 'us-east-1_oiuR12Abd'); +const awesomeLink = apigateway.VpcLink.fromVpcLinkId(this, 'awesome-vpc-link', 'us-east-1_oiuR12Abd'); ``` ## Gateway response @@ -1042,7 +1102,7 @@ The following code configures a Gateway Response when the response is 'access de ```ts const api = new apigateway.RestApi(this, 'books-api'); api.addGatewayResponse('test-response', { - type: ResponseType.ACCESS_DENIED, + type: apigateway.ResponseType.ACCESS_DENIED, statusCode: '500', responseHeaders: { 'Access-Control-Allow-Origin': "test.com", @@ -1063,12 +1123,14 @@ OpenAPI](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gatewa The following code creates a REST API using an external OpenAPI definition JSON file - ```ts +declare const integration: apigateway.Integration; + const api = new apigateway.SpecRestApi(this, 'books-api', { apiDefinition: apigateway.ApiDefinition.fromAsset('path-to-file.json') }); const booksResource = api.root.addResource('books') -booksResource.addMethod('GET', ...); +booksResource.addMethod('GET', integration); ``` It is possible to use the `addResource()` API to define additional API Gateway Resources. @@ -1095,8 +1157,10 @@ By default, `SpecRestApi` will create an edge optimized endpoint. This can be modified as shown below: ```ts +declare const apiDefinition: apigateway.ApiDefinition; + const api = new apigateway.SpecRestApi(this, 'ExampleRestApi', { - // ... + apiDefinition, endpointTypes: [apigateway.EndpointType.PRIVATE] }); ``` @@ -1114,7 +1178,7 @@ The APIs with the `metric` prefix can be used to get reference to specific metri the method below refers to the client side errors metric for this API. ```ts -const api = new apigw.RestApi(stack, 'my-api'); +const api = new apigateway.RestApi(this, 'my-api'); const clientErrorMetric = api.metricClientError(); ``` diff --git a/packages/@aws-cdk/aws-apigateway/jest.config.js b/packages/@aws-cdk/aws-apigateway/jest.config.js index 82c5d0bb93666..3403249680be2 100644 --- a/packages/@aws-cdk/aws-apigateway/jest.config.js +++ b/packages/@aws-cdk/aws-apigateway/jest.config.js @@ -1,4 +1,4 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = { ...baseConfig, coverageThreshold: { diff --git a/packages/@aws-cdk/aws-apigateway/lib/access-log.ts b/packages/@aws-cdk/aws-apigateway/lib/access-log.ts index 726a6928315ee..bc73b13d78604 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/access-log.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/access-log.ts @@ -486,15 +486,17 @@ export class AccessLogFormat { * Custom log format. * You can create any log format string. You can easily get the $ context variable by using the methods of AccessLogField. * @param format - * @example custom(JSON.stringify({ - * requestId: AccessLogField.contextRequestId(), - * sourceIp: AccessLogField.contextIdentitySourceIp(), - * method: AccessLogFiled.contextHttpMethod(), - * userContext: { - * sub: AccessLogField.contextAuthorizerClaims('sub'), - * email: AccessLogField.contextAuthorizerClaims('email') - * } - * })) + * @example + * + * apigateway.AccessLogFormat.custom(JSON.stringify({ + * requestId: apigateway.AccessLogField.contextRequestId(), + * sourceIp: apigateway.AccessLogField.contextIdentitySourceIp(), + * method: apigateway.AccessLogField.contextHttpMethod(), + * userContext: { + * sub: apigateway.AccessLogField.contextAuthorizerClaims('sub'), + * email: apigateway.AccessLogField.contextAuthorizerClaims('email') + * } + * })) */ public static custom(format: string): AccessLogFormat { return new AccessLogFormat(format); diff --git a/packages/@aws-cdk/aws-apigateway/lib/api-definition.ts b/packages/@aws-cdk/aws-apigateway/lib/api-definition.ts index 7b138cfcf23d1..850087920f152 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/api-definition.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/api-definition.ts @@ -21,7 +21,8 @@ export abstract class ApiDefinition { * schema of OpenAPI 2.0 or OpenAPI 3.0 * * @example - * ApiDefinition.fromInline({ + * + * apigateway.ApiDefinition.fromInline({ * openapi: '3.0.2', * paths: { * '/pets': { diff --git a/packages/@aws-cdk/aws-apigateway/lib/integrations/lambda.ts b/packages/@aws-cdk/aws-apigateway/lib/integrations/lambda.ts index 97772fe7eddb5..fb0c9a1e84934 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/integrations/lambda.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/integrations/lambda.ts @@ -32,8 +32,9 @@ export interface LambdaIntegrationOptions extends IntegrationOptions { * * @example * - * const handler = new lambda.Function(this, 'MyFunction', ...); - * api.addMethod('GET', new LambdaIntegration(handler)); + * declare const resource: apigateway.Resource; + * declare const handler: lambda.Function; + * resource.addMethod('GET', new apigateway.LambdaIntegration(handler)); * */ export class LambdaIntegration extends AwsIntegration { diff --git a/packages/@aws-cdk/aws-apigateway/lib/method.ts b/packages/@aws-cdk/aws-apigateway/lib/method.ts index ff9c4aaef47dd..919d27e6573be 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/method.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/method.ts @@ -74,15 +74,18 @@ export interface MethodOptions { * * @example * + * declare const api: apigateway.RestApi; + * declare const userLambda: lambda.Function; + * * const userModel: apigateway.Model = api.addModel('UserModel', { * schema: { - * type: apigateway.JsonSchemaType.OBJECT + * type: apigateway.JsonSchemaType.OBJECT, * properties: { * userId: { - * type: apigateway.JsonSchema.STRING + * type: apigateway.JsonSchemaType.STRING * }, * name: { - * type: apigateway.JsonSchema.STRING + * type: apigateway.JsonSchemaType.STRING * } * }, * required: ['userId'] diff --git a/packages/@aws-cdk/aws-apigateway/package.json b/packages/@aws-cdk/aws-apigateway/package.json index 414d689d1a6e3..132082167f0f6 100644 --- a/packages/@aws-cdk/aws-apigateway/package.json +++ b/packages/@aws-cdk/aws-apigateway/package.json @@ -57,8 +57,7 @@ "cloudformation": "AWS::ApiGateway", "env": { "AWSLINT_BASE_CONSTRUCT": true - }, - "jest": true + } }, "keywords": [ "aws", @@ -73,12 +72,12 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/aws-certificatemanager": "0.0.0", @@ -323,6 +322,7 @@ "attribute-tag:@aws-cdk/aws-apigateway.LambdaRestApi.restApiName", "from-method:@aws-cdk/aws-apigateway.Stage", "resource-attribute:@aws-cdk/aws-apigateway.ApiKey.apiKeyId", + "resource-attribute:@aws-cdk/aws-apigateway.GatewayResponse.gatewayResponseId", "resource-attribute:@aws-cdk/aws-apigateway.RateLimitedApiKey.apiKeyId" ] }, diff --git a/packages/@aws-cdk/aws-apigateway/rosetta/default.ts-fixture b/packages/@aws-cdk/aws-apigateway/rosetta/default.ts-fixture new file mode 100644 index 0000000000000..54f81e82e4460 --- /dev/null +++ b/packages/@aws-cdk/aws-apigateway/rosetta/default.ts-fixture @@ -0,0 +1,17 @@ +// Fixture with packages imported, but nothing else +import { Construct, Stack } from '@aws-cdk/core'; +import apigateway = require('@aws-cdk/aws-apigateway'); +import cognito = require('@aws-cdk/aws-cognito'); +import lambda = require('@aws-cdk/aws-lambda'); +import iam = require('@aws-cdk/aws-iam'); +import s3 = require('@aws-cdk/aws-s3'); +import ec2 = require('@aws-cdk/aws-ec2'); +import logs = require('@aws-cdk/aws-logs'); + +class Fixture extends Stack { + constructor(scope: Construct, id: string) { + super(scope, id); + + /// here + } +} diff --git a/packages/@aws-cdk/aws-apigateway/test/integ.restapi-import.lit.ts b/packages/@aws-cdk/aws-apigateway/test/integ.restapi-import.lit.ts index 2607281fbc923..77094eb60b600 100644 --- a/packages/@aws-cdk/aws-apigateway/test/integ.restapi-import.lit.ts +++ b/packages/@aws-cdk/aws-apigateway/test/integ.restapi-import.lit.ts @@ -31,7 +31,7 @@ class RootStack extends Stack { }); new DeployStack(this, { restApiId: restApi.restApiId, - methods: [...petsStack.methods, ...booksStack.methods], + methods: petsStack.methods.concat(booksStack.methods), }); new CfnOutput(this, 'PetsURL', { @@ -117,7 +117,11 @@ class DeployStack extends NestedStack { const deployment = new Deployment(this, 'Deployment', { api: RestApi.fromRestApiId(this, 'RestApi', props.restApiId), }); - (props.methods ?? []).forEach((method) => deployment.node.addDependency(method)); + if (props.methods) { + for (const method of props.methods) { + deployment.node.addDependency(method); + } + } new Stage(this, 'Stage', { deployment }); } } diff --git a/packages/@aws-cdk/aws-apigateway/test/usage-plan.test.ts b/packages/@aws-cdk/aws-apigateway/test/usage-plan.test.ts index 2cb6e4ed48ed2..195e17a0b7fbf 100644 --- a/packages/@aws-cdk/aws-apigateway/test/usage-plan.test.ts +++ b/packages/@aws-cdk/aws-apigateway/test/usage-plan.test.ts @@ -2,7 +2,7 @@ import '@aws-cdk/assert-internal/jest'; import { ResourcePart } from '@aws-cdk/assert-internal'; import * as cdk from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; -import { testFutureBehavior } from 'cdk-build-tools/lib/feature-flag'; +import { testFutureBehavior } from '@aws-cdk/cdk-build-tools/lib/feature-flag'; import * as apigateway from '../lib'; const RESOURCE_TYPE = 'AWS::ApiGateway::UsagePlan'; diff --git a/packages/@aws-cdk/aws-apigatewayv2-authorizers/.eslintrc.js b/packages/@aws-cdk/aws-apigatewayv2-authorizers/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-authorizers/.eslintrc.js +++ b/packages/@aws-cdk/aws-apigatewayv2-authorizers/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-apigatewayv2-authorizers/jest.config.js b/packages/@aws-cdk/aws-apigatewayv2-authorizers/jest.config.js index b5ccdecc15ee0..9f9ccac177e1b 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-authorizers/jest.config.js +++ b/packages/@aws-cdk/aws-apigatewayv2-authorizers/jest.config.js @@ -1,4 +1,4 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = { ...baseConfig, coverageThreshold: { @@ -7,4 +7,4 @@ module.exports = { branches: 70, }, }, -}; \ No newline at end of file +}; diff --git a/packages/@aws-cdk/aws-apigatewayv2-authorizers/package.json b/packages/@aws-cdk/aws-apigatewayv2-authorizers/package.json index 8466c95ddc9da..13c9a7d48efd3 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-authorizers/package.json +++ b/packages/@aws-cdk/aws-apigatewayv2-authorizers/package.json @@ -55,7 +55,6 @@ "build+test+extract": "yarn build+test && yarn rosetta:extract" }, "cdk-build": { - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -74,13 +73,13 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assertions": "0.0.0", - "@types/jest": "^26.0.24", - "@types/aws-lambda": "^8.10.79", "@aws-cdk/aws-apigatewayv2-integrations": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/aws-lambda": "^8.10.84", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/aws-apigatewayv2": "0.0.0", diff --git a/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/lambda.test.ts b/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/lambda.test.ts index 1f62ad76867b0..c9fdf62c17d57 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/lambda.test.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/lambda.test.ts @@ -103,7 +103,7 @@ describe('HttpLambdaAuthorizer', () => { // THEN Template.fromStack(stack).hasResourceProperties('AWS::ApiGatewayV2::Authorizer', { AuthorizerPayloadFormatVersion: '1.0', - EnableSimpleResponses: Match.absentProperty(), + EnableSimpleResponses: Match.absent(), }); }); diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/.eslintrc.js b/packages/@aws-cdk/aws-apigatewayv2-integrations/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/.eslintrc.js +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/README.md b/packages/@aws-cdk/aws-apigatewayv2-integrations/README.md index cce77fd6398e6..14eb72a56e7a4 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/README.md +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/README.md @@ -21,6 +21,7 @@ - [Lambda Integration](#lambda) - [HTTP Proxy Integration](#http-proxy) - [Private Integration](#private-integration) + - [Request Parameters](#request-parameters) - [WebSocket APIs](#websocket-apis) - [Lambda WebSocket Integration](#lambda-websocket-integration) @@ -149,6 +150,40 @@ const httpEndpoint = new HttpApi(stack, 'HttpProxyPrivateApi', { }); ``` +### Request Parameters + +Request parameter mapping allows API requests from clients to be modified before they reach backend integrations. +Parameter mapping can be used to specify modifications to request parameters. See [Transforming API requests and +responses](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-parameter-mapping.html). + +The following example creates a new header - `header2` - as a copy of `header1` and removes `header1`. + +```ts +const httpEndpoint = new HttpApi(stack, 'HttpProxyPrivateApi', { + defaultIntegration: new HttpAlbIntegration({ + // ... + requestParameters: new ParameterMapping() + .appendHeader('header2', MappingValue.header('header1')) + .removeHeader('header1'); + }), + }), +}); +``` + +To add mapping keys and values not yet supported by the CDK, use the `custom()` method: + +```ts +const httpEndpoint = new HttpApi(stack, 'HttpProxyPrivateApi', { + defaultIntegration: new HttpAlbIntegration({ + listener, + requestParameters: new ParameterMapping() + .custom('myKey', 'myValue'), + }), + }), +}); +``` + + ## WebSocket APIs WebSocket integrations connect a route to backend resources. The following integrations are supported in the CDK. diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/jest.config.js b/packages/@aws-cdk/aws-apigatewayv2-integrations/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/jest.config.js +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/http/alb.ts b/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/http/alb.ts index 656e0a550408f..e5e6d5c448663 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/http/alb.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/http/alb.ts @@ -44,6 +44,7 @@ export class HttpAlbIntegration extends HttpPrivateIntegration { connectionId: vpcLink.vpcLinkId, uri: this.props.listener.listenerArn, secureServerName: this.props.secureServerName, + parameterMapping: this.props.parameterMapping, }; } } diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/http/base-types.ts b/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/http/base-types.ts index db14e50f7fc54..1627b9b0c4deb 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/http/base-types.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/http/base-types.ts @@ -1,4 +1,4 @@ -import { HttpMethod, IVpcLink } from '@aws-cdk/aws-apigatewayv2'; +import { HttpMethod, IVpcLink, ParameterMapping } from '@aws-cdk/aws-apigatewayv2'; /** * Base options for private integration @@ -24,4 +24,11 @@ export interface HttpPrivateIntegrationOptions { */ readonly secureServerName?: string; + + /** + * Specifies how to transform HTTP requests before sending them to the backend + * @see https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-parameter-mapping.html + * @default undefined requests are sent to the backend unmodified + */ + readonly parameterMapping?: ParameterMapping; } diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/http/http-proxy.ts b/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/http/http-proxy.ts index a7ef2d1b4d7b9..70873c9582fc8 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/http/http-proxy.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/http/http-proxy.ts @@ -4,6 +4,7 @@ import { HttpRouteIntegrationConfig, HttpMethod, IHttpRouteIntegration, + ParameterMapping, PayloadFormatVersion, } from '@aws-cdk/aws-apigatewayv2'; @@ -21,6 +22,13 @@ export interface HttpProxyIntegrationProps { * @default HttpMethod.ANY */ readonly method?: HttpMethod; + + /** + * Specifies how to transform HTTP requests before sending them to the backend + * @see https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-parameter-mapping.html + * @default undefined requests are sent to the backend unmodified + */ + readonly parameterMapping?: ParameterMapping; } /** @@ -36,6 +44,7 @@ export class HttpProxyIntegration implements IHttpRouteIntegration { payloadFormatVersion: PayloadFormatVersion.VERSION_1_0, // 1.0 is required and is the only supported format type: HttpIntegrationType.HTTP_PROXY, uri: this.props.url, + parameterMapping: this.props.parameterMapping, }; } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/http/lambda.ts b/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/http/lambda.ts index 220d3dca57210..358263f724bda 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/http/lambda.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/http/lambda.ts @@ -4,6 +4,7 @@ import { HttpRouteIntegrationConfig, IHttpRouteIntegration, PayloadFormatVersion, + ParameterMapping, } from '@aws-cdk/aws-apigatewayv2'; import { ServicePrincipal } from '@aws-cdk/aws-iam'; import { IFunction } from '@aws-cdk/aws-lambda'; @@ -24,6 +25,13 @@ export interface LambdaProxyIntegrationProps { * @default PayloadFormatVersion.VERSION_2_0 */ readonly payloadFormatVersion?: PayloadFormatVersion; + + /** + * Specifies how to transform HTTP requests before sending them to the backend + * @see https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-parameter-mapping.html + * @default undefined requests are sent to the backend unmodified + */ + readonly parameterMapping?: ParameterMapping; } /** @@ -50,6 +58,7 @@ export class LambdaProxyIntegration implements IHttpRouteIntegration { type: HttpIntegrationType.LAMBDA_PROXY, uri: this.props.handler.functionArn, payloadFormatVersion: this.props.payloadFormatVersion ?? PayloadFormatVersion.VERSION_2_0, + parameterMapping: this.props.parameterMapping, }; } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/http/nlb.ts b/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/http/nlb.ts index 1c405b51b3bfd..7aae0aa002354 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/http/nlb.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/http/nlb.ts @@ -44,6 +44,7 @@ export class HttpNlbIntegration extends HttpPrivateIntegration { connectionId: vpcLink.vpcLinkId, uri: this.props.listener.listenerArn, secureServerName: this.props.secureServerName, + parameterMapping: this.props.parameterMapping, }; } } diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/http/service-discovery.ts b/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/http/service-discovery.ts index f9f204b6eba3e..6f3b8eedbea0a 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/http/service-discovery.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/http/service-discovery.ts @@ -34,6 +34,7 @@ export class HttpServiceDiscoveryIntegration extends HttpPrivateIntegration { connectionId: this.props.vpcLink.vpcLinkId, uri: this.props.service.serviceArn, secureServerName: this.props.secureServerName, + parameterMapping: this.props.parameterMapping, }; } } diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/package.json b/packages/@aws-cdk/aws-apigatewayv2-integrations/package.json index f857a94bc93f4..a950d542429e0 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/package.json +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/package.json @@ -53,7 +53,6 @@ "build+test+extract": "yarn build+test && yarn rosetta:extract" }, "cdk-build": { - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -72,10 +71,10 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assertions": "0.0.0", - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/aws-apigatewayv2": "0.0.0", diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/alb.test.ts b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/alb.test.ts index e5871da260bc2..3c25e92fe6d21 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/alb.test.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/alb.test.ts @@ -1,5 +1,5 @@ import { Template } from '@aws-cdk/assertions'; -import { HttpApi, HttpMethod, HttpRoute, HttpRouteKey, VpcLink } from '@aws-cdk/aws-apigatewayv2'; +import { HttpApi, HttpMethod, HttpRoute, HttpRouteKey, VpcLink, ParameterMapping, MappingValue } from '@aws-cdk/aws-apigatewayv2'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as elbv2 from '@aws-cdk/aws-elasticloadbalancingv2'; import { Stack } from '@aws-cdk/core'; @@ -143,4 +143,34 @@ describe('HttpAlbIntegration', () => { }, }); }); + + test('parameterMapping option is correctly recognized', () => { + // GIVEN + const stack = new Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const lb = new elbv2.ApplicationLoadBalancer(stack, 'lb', { vpc }); + const listener = lb.addListener('listener', { port: 80 }); + listener.addTargets('target', { port: 80 }); + + // WHEN + const api = new HttpApi(stack, 'HttpApi'); + new HttpRoute(stack, 'HttpProxyPrivateRoute', { + httpApi: api, + integration: new HttpAlbIntegration({ + listener, + parameterMapping: new ParameterMapping() + .appendHeader('header2', MappingValue.requestHeader('header1')) + .removeHeader('header1'), + }), + routeKey: HttpRouteKey.with('/pets'), + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::ApiGatewayV2::Integration', { + RequestParameters: { + 'append:header.header2': '$request.header.header1', + 'remove:header.header1': '', + }, + }); + }); }); diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/http-proxy.test.ts b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/http-proxy.test.ts index 0c76996fe7867..0f29ec0915fd9 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/http-proxy.test.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/http-proxy.test.ts @@ -1,5 +1,5 @@ import { Template } from '@aws-cdk/assertions'; -import { HttpApi, HttpIntegration, HttpIntegrationType, HttpMethod, HttpRoute, HttpRouteKey, PayloadFormatVersion } from '@aws-cdk/aws-apigatewayv2'; +import { HttpApi, HttpIntegration, HttpIntegrationType, HttpMethod, HttpRoute, HttpRouteKey, MappingValue, ParameterMapping, PayloadFormatVersion } from '@aws-cdk/aws-apigatewayv2'; import { Stack } from '@aws-cdk/core'; import { HttpProxyIntegration } from '../../lib'; @@ -71,4 +71,26 @@ describe('HttpProxyIntegration', () => { IntegrationUri: 'some-target-url', }); }); + + test('parameterMapping is correctly recognized', () => { + const stack = new Stack(); + const api = new HttpApi(stack, 'HttpApi'); + new HttpIntegration(stack, 'HttpInteg', { + httpApi: api, + integrationType: HttpIntegrationType.HTTP_PROXY, + integrationUri: 'some-target-url', + parameterMapping: new ParameterMapping() + .appendHeader('header2', MappingValue.requestHeader('header1')) + .removeHeader('header1'), + }); + + Template.fromStack(stack).hasResourceProperties('AWS::ApiGatewayV2::Integration', { + IntegrationType: 'HTTP_PROXY', + IntegrationUri: 'some-target-url', + RequestParameters: { + 'append:header.header2': '$request.header.header1', + 'remove:header.header1': '', + }, + }); + }); }); diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/lambda.test.ts b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/lambda.test.ts index d0ead43945ec4..85bb624a25d54 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/lambda.test.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/lambda.test.ts @@ -1,5 +1,5 @@ import { Template } from '@aws-cdk/assertions'; -import { HttpApi, HttpRoute, HttpRouteKey, PayloadFormatVersion } from '@aws-cdk/aws-apigatewayv2'; +import { HttpApi, HttpRoute, HttpRouteKey, MappingValue, ParameterMapping, PayloadFormatVersion } from '@aws-cdk/aws-apigatewayv2'; import { Code, Function, Runtime } from '@aws-cdk/aws-lambda'; import { App, Stack } from '@aws-cdk/core'; import { LambdaProxyIntegration } from '../../lib'; @@ -41,6 +41,28 @@ describe('LambdaProxyIntegration', () => { }); }); + test('parameterMapping selection', () => { + const stack = new Stack(); + const api = new HttpApi(stack, 'HttpApi'); + new HttpRoute(stack, 'LambdaProxyRoute', { + httpApi: api, + integration: new LambdaProxyIntegration({ + handler: fooFunction(stack, 'Fn'), + parameterMapping: new ParameterMapping() + .appendHeader('header2', MappingValue.requestHeader('header1')) + .removeHeader('header1'), + }), + routeKey: HttpRouteKey.with('/pets'), + }); + + Template.fromStack(stack).hasResourceProperties('AWS::ApiGatewayV2::Integration', { + RequestParameters: { + 'append:header.header2': '$request.header.header1', + 'remove:header.header1': '', + }, + }); + }); + test('no dependency cycles', () => { const app = new App(); const lambdaStack = new Stack(app, 'lambdaStack'); diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/nlb.test.ts b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/nlb.test.ts index a32d448d8e448..e1e18c43f49aa 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/nlb.test.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/nlb.test.ts @@ -1,5 +1,5 @@ import { Template } from '@aws-cdk/assertions'; -import { HttpApi, HttpMethod, HttpRoute, HttpRouteKey, VpcLink } from '@aws-cdk/aws-apigatewayv2'; +import { HttpApi, HttpMethod, HttpRoute, HttpRouteKey, MappingValue, ParameterMapping, VpcLink } from '@aws-cdk/aws-apigatewayv2'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as elbv2 from '@aws-cdk/aws-elasticloadbalancingv2'; import { Stack } from '@aws-cdk/core'; @@ -140,4 +140,34 @@ describe('HttpNlbIntegration', () => { }, }); }); + + test('paramaterMapping option is correctly recognized', () => { + // GIVEN + const stack = new Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const lb = new elbv2.NetworkLoadBalancer(stack, 'lb', { vpc }); + const listener = lb.addListener('listener', { port: 80 }); + listener.addTargets('target', { port: 80 }); + + // WHEN + const api = new HttpApi(stack, 'HttpApi'); + new HttpRoute(stack, 'HttpProxyPrivateRoute', { + httpApi: api, + integration: new HttpNlbIntegration({ + listener, + parameterMapping: new ParameterMapping() + .appendHeader('header2', MappingValue.requestHeader('header1')) + .removeHeader('header1'), + }), + routeKey: HttpRouteKey.with('/pets'), + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::ApiGatewayV2::Integration', { + RequestParameters: { + 'append:header.header2': '$request.header.header1', + 'remove:header.header1': '', + }, + }); + }); }); diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/service-discovery.test.ts b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/service-discovery.test.ts index 4d3bef328a637..e037004cada0e 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/service-discovery.test.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/service-discovery.test.ts @@ -1,5 +1,5 @@ import { Template } from '@aws-cdk/assertions'; -import { HttpApi, HttpMethod, HttpRoute, HttpRouteKey, VpcLink } from '@aws-cdk/aws-apigatewayv2'; +import { HttpApi, HttpMethod, HttpRoute, HttpRouteKey, MappingValue, ParameterMapping, VpcLink } from '@aws-cdk/aws-apigatewayv2'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as servicediscovery from '@aws-cdk/aws-servicediscovery'; import { Stack } from '@aws-cdk/core'; @@ -125,4 +125,38 @@ describe('HttpServiceDiscoveryIntegration', () => { }, }); }); + + test('parameterMapping option is correctly recognized', () => { + // GIVEN + const stack = new Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const vpcLink = new VpcLink(stack, 'VpcLink', { vpc }); + const namespace = new servicediscovery.PrivateDnsNamespace(stack, 'Namespace', { + name: 'foobar.com', + vpc, + }); + const service = namespace.createService('Service'); + + // WHEN + const api = new HttpApi(stack, 'HttpApi'); + new HttpRoute(stack, 'HttpProxyPrivateRoute', { + httpApi: api, + integration: new HttpServiceDiscoveryIntegration({ + vpcLink, + service, + parameterMapping: new ParameterMapping() + .appendHeader('header2', MappingValue.requestHeader('header1')) + .removeHeader('header1'), + }), + routeKey: HttpRouteKey.with('/pets'), + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::ApiGatewayV2::Integration', { + RequestParameters: { + 'append:header.header2': '$request.header.header1', + 'remove:header.header1': '', + }, + }); + }); }); diff --git a/packages/@aws-cdk/aws-apigatewayv2/.eslintrc.js b/packages/@aws-cdk/aws-apigatewayv2/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/.eslintrc.js +++ b/packages/@aws-cdk/aws-apigatewayv2/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-apigatewayv2/jest.config.js b/packages/@aws-cdk/aws-apigatewayv2/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/jest.config.js +++ b/packages/@aws-cdk/aws-apigatewayv2/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-apigatewayv2/lib/http/api.ts b/packages/@aws-cdk/aws-apigatewayv2/lib/http/api.ts index 254a29ea6d28b..32dfe0a0c2120 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/lib/http/api.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/lib/http/api.ts @@ -305,6 +305,7 @@ abstract class HttpApiBase extends ApiBase implements IHttpApi { // note that th connectionType: config.connectionType, payloadFormatVersion: config.payloadFormatVersion, secureServerName: config.secureServerName, + parameterMapping: config.parameterMapping, }); this._integrationCache.saveIntegration(scope, config, integration); diff --git a/packages/@aws-cdk/aws-apigatewayv2/lib/http/integration.ts b/packages/@aws-cdk/aws-apigatewayv2/lib/http/integration.ts index f832b5b7e3b21..df0cf84c13da0 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/lib/http/integration.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/lib/http/integration.ts @@ -3,6 +3,7 @@ import { Resource } from '@aws-cdk/core'; import { Construct } from 'constructs'; import { CfnIntegration } from '../apigatewayv2.generated'; import { IIntegration } from '../common'; +import { ParameterMapping } from '../parameter-mapping'; import { IHttpApi } from './api'; import { HttpMethod, IHttpRoute } from './route'; @@ -128,6 +129,13 @@ export interface HttpIntegrationProps { * @default undefined private integration traffic will use HTTP protocol */ readonly secureServerName?: string; + + /** + * Specifies how to transform HTTP requests before sending them to the backend + * @see https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-parameter-mapping.html + * @default undefined requests are sent to the backend unmodified + */ + readonly parameterMapping?: ParameterMapping; } /** @@ -149,6 +157,7 @@ export class HttpIntegration extends Resource implements IHttpIntegration { connectionId: props.connectionId, connectionType: props.connectionType, payloadFormatVersion: props.payloadFormatVersion?.version, + requestParameters: props.parameterMapping?.mappings, }); if (props.secureServerName) { @@ -237,4 +246,11 @@ export interface HttpRouteIntegrationConfig { * @default undefined private integration traffic will use HTTP protocol */ readonly secureServerName?: string; + + /** + * Specifies how to transform HTTP requests before sending them to the backend + * @see https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-parameter-mapping.html + * @default undefined requests are sent to the backend unmodified + */ + readonly parameterMapping?: ParameterMapping; } diff --git a/packages/@aws-cdk/aws-apigatewayv2/lib/http/stage.ts b/packages/@aws-cdk/aws-apigatewayv2/lib/http/stage.ts index 709f207a04435..ca40349975ec1 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/lib/http/stage.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/lib/http/stage.ts @@ -18,6 +18,11 @@ export interface IHttpStage extends IStage { */ readonly api: IHttpApi; + /** + * The custom domain URL to this stage + */ + readonly domainUrl: string; + /** * Metric for the number of client-side errors captured in a given period. * @@ -96,6 +101,7 @@ export interface HttpStageAttributes extends StageAttributes { } abstract class HttpStageBase extends StageBase implements IHttpStage { + public abstract readonly domainUrl: string; public abstract readonly api: IHttpApi; public metricClientError(props?: MetricOptions): Metric { @@ -140,6 +146,10 @@ export class HttpStage extends HttpStageBase { get url(): string { throw new Error('url is not available for imported stages.'); } + + get domainUrl(): string { + throw new Error('domainUrl is not available for imported stages.'); + } } return new Import(scope, id); } @@ -177,9 +187,6 @@ export class HttpStage extends HttpStageBase { return `https://${this.api.apiId}.execute-api.${s.region}.${s.urlSuffix}/${urlPath}`; } - /** - * The custom domain URL to this stage - */ public get domainUrl(): string { if (!this._apiMapping) { throw new Error('domainUrl is not available when no API mapping is associated with the Stage'); diff --git a/packages/@aws-cdk/aws-apigatewayv2/lib/index.ts b/packages/@aws-cdk/aws-apigatewayv2/lib/index.ts index 12dd8113f8b4c..81df171d98aa1 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/lib/index.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/lib/index.ts @@ -2,3 +2,4 @@ export * from './apigatewayv2.generated'; export * from './common'; export * from './http'; export * from './websocket'; +export * from './parameter-mapping'; \ No newline at end of file diff --git a/packages/@aws-cdk/aws-apigatewayv2/lib/parameter-mapping.ts b/packages/@aws-cdk/aws-apigatewayv2/lib/parameter-mapping.ts new file mode 100644 index 0000000000000..deb967d572de2 --- /dev/null +++ b/packages/@aws-cdk/aws-apigatewayv2/lib/parameter-mapping.ts @@ -0,0 +1,145 @@ +/** + * Represents a Mapping Value. + */ +export interface IMappingValue { + /** + * Represents a Mapping Value. + */ + readonly value: string; +}; + +/** + * Represents a Mapping Value. + */ +export class MappingValue implements IMappingValue { + /** + * Creates an empty mapping value. + */ + public static readonly NONE = new MappingValue(''); + + /** + * Creates a header mapping value. + */ + public static requestHeader(name: string) { return new MappingValue(`$request.header.${name}`); } + + /** + * Creates a query string mapping value. + */ + public static requestQueryString(name: string) { return new MappingValue(`$request.querystring.${name}`); } + + /** + * Creates a request body mapping value. + */ + public static requestBody(name: string) { return new MappingValue(`$request.body.${name}`); } + + /** + * Creates a request path mapping value. + */ + public static requestPath() { return new MappingValue('$request.path'); } + + /** + * Creates a request path parameter mapping value. + */ + public static requestPathParam(name: string) { return new MappingValue(`$request.path.${name}`); } + + /** + * Creates a context variable mapping value. + */ + public static contextVariable(variableName: string) { return new MappingValue(`$context.${variableName}`); } + + /** + * Creates a stage variable mapping value. + */ + public static stageVariable(variableName: string) { return new MappingValue(`$stageVariables.${variableName}`); } + + /** + * Creates a custom mapping value. + */ + public static custom(value: string) { return new MappingValue(value); } + + /** + * Represents a Mapping Value. + */ + public readonly value: string + + protected constructor(value: string) { + this.value = value; + } +} + +/** + * Represents a Parameter Mapping. + */ +export class ParameterMapping { + /** + * Represents all created parameter mappings. + */ + public readonly mappings: { [key: string]: string } + constructor() { + this.mappings = {}; + } + + /** + * Creates a mapping to append a header. + */ + public appendHeader(name: string, value: MappingValue): ParameterMapping { + this.mappings[`append:header.${name}`] = value.value; + return this; + } + + /** + * Creates a mapping to overwrite a header. + */ + public overwriteHeader(name: string, value: MappingValue): ParameterMapping { + this.mappings[`overwrite:header.${name}`] = value.value; + return this; + } + + /** + * Creates a mapping to remove a header. + */ + public removeHeader(name: string): ParameterMapping { + this.mappings[`remove:header.${name}`] = ''; + return this; + } + + /** + * Creates a mapping to append a query string. + */ + public appendQueryString(name: string, value: MappingValue): ParameterMapping { + this.mappings[`append:querystring.${name}`] = value.value; + return this; + } + + /** + * Creates a mapping to overwrite a querystring. + */ + public overwriteQueryString(name: string, value: MappingValue): ParameterMapping { + this.mappings[`overwrite:querystring.${name}`] = value.value; + return this; + } + + /** + * Creates a mapping to remove a querystring. + */ + public removeQueryString(name: string): ParameterMapping { + this.mappings[`remove:querystring.${name}`] = ''; + return this; + } + + /** + * Creates a mapping to overwrite a path. + */ + public overwritePath(value: MappingValue): ParameterMapping { + this.mappings['overwrite:path'] = value.value; + return this; + } + + /** + * Creates a custom mapping. + */ + public custom(key: string, value: string): ParameterMapping { + this.mappings[key] = value; + return this; + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-apigatewayv2/lib/websocket/api.ts b/packages/@aws-cdk/aws-apigatewayv2/lib/websocket/api.ts index f2f2653c94ee6..3d7d627ab4fef 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/lib/websocket/api.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/lib/websocket/api.ts @@ -21,7 +21,7 @@ export interface IWebSocketApi extends IApi { */ export interface WebSocketApiProps { /** - * Name for the WebSocket API resoruce + * Name for the WebSocket API resource * @default - id of the WebSocketApi construct. */ readonly apiName?: string; diff --git a/packages/@aws-cdk/aws-apigatewayv2/package.json b/packages/@aws-cdk/aws-apigatewayv2/package.json index d0f2d3b6288c2..349c1ab9517cf 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/package.json +++ b/packages/@aws-cdk/aws-apigatewayv2/package.json @@ -60,7 +60,6 @@ }, "cdk-build": { "cloudformation": "AWS::ApiGatewayV2", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -79,25 +78,25 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assertions": "0.0.0", - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/aws-certificatemanager": "0.0.0", + "@aws-cdk/aws-cloudwatch": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", - "@aws-cdk/aws-cloudwatch": "0.0.0", "@aws-cdk/core": "0.0.0", "constructs": "^3.3.69" }, "peerDependencies": { - "@aws-cdk/aws-ec2": "0.0.0", - "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-certificatemanager": "0.0.0", "@aws-cdk/aws-cloudwatch": "0.0.0", + "@aws-cdk/aws-ec2": "0.0.0", + "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/core": "0.0.0", "constructs": "^3.3.69" }, diff --git a/packages/@aws-cdk/aws-apigatewayv2/test/http/api.test.ts b/packages/@aws-cdk/aws-apigatewayv2/test/http/api.test.ts index dc096594d0ecd..200933eefbca9 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/test/http/api.test.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/test/http/api.test.ts @@ -1,9 +1,10 @@ import { Match, Template } from '@aws-cdk/assertions'; +import { Certificate } from '@aws-cdk/aws-certificatemanager'; import { Metric } from '@aws-cdk/aws-cloudwatch'; import * as ec2 from '@aws-cdk/aws-ec2'; import { Duration, Stack } from '@aws-cdk/core'; import { - CorsHttpMethod, + CorsHttpMethod, DomainName, HttpApi, HttpAuthorizer, HttpIntegrationType, HttpMethod, HttpRouteAuthorizerBindOptions, HttpRouteAuthorizerConfig, HttpRouteIntegrationBindOptions, HttpRouteIntegrationConfig, IHttpRouteAuthorizer, IHttpRouteIntegration, HttpNoneAuthorizer, PayloadFormatVersion, } from '../../lib'; @@ -127,7 +128,7 @@ describe('HttpApi', () => { new HttpApi(stack, 'HttpApi'); Template.fromStack(stack).hasResourceProperties('AWS::ApiGatewayV2::Api', { - CorsConfiguration: Match.absentProperty(), + CorsConfiguration: Match.absent(), }); }); @@ -374,6 +375,27 @@ describe('HttpApi', () => { expect(() => api.apiEndpoint).toThrow(/apiEndpoint is not configured/); }); + test('domainUrl can be retrieved for default stage', () => { + const stack = new Stack(); + const dn = new DomainName(stack, 'DN', { + domainName: 'example.com', + certificate: Certificate.fromCertificateArn(stack, 'cert', 'arn:aws:acm:us-east-1:111111111111:certificate'), + }); + + const api = new HttpApi(stack, 'Api', { + createDefaultStage: true, + defaultDomainMapping: { + domainName: dn, + }, + }); + + expect(stack.resolve(api.defaultStage?.domainUrl)).toEqual({ + 'Fn::Join': ['', [ + 'https://', { Ref: 'DNFDC76583' }, '/', + ]], + }); + }); + describe('default authorization settings', () => { test('can add default authorizer', () => { @@ -447,7 +469,7 @@ describe('HttpApi', () => { Template.fromStack(stack).hasResourceProperties('AWS::ApiGatewayV2::Route', { RouteKey: 'GET /chickens', AuthorizationType: 'NONE', - AuthorizerId: Match.absentProperty(), + AuthorizerId: Match.absent(), }); }); @@ -469,7 +491,7 @@ describe('HttpApi', () => { }); Template.fromStack(stack).hasResourceProperties('AWS::ApiGatewayV2::Route', { - AuthorizationScopes: Match.absentProperty(), + AuthorizationScopes: Match.absent(), }); }); diff --git a/packages/@aws-cdk/aws-apigatewayv2/test/http/route.test.ts b/packages/@aws-cdk/aws-apigatewayv2/test/http/route.test.ts index 9f64cfdfbd123..75d744b6b5bcc 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/test/http/route.test.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/test/http/route.test.ts @@ -1,8 +1,11 @@ import { Template } from '@aws-cdk/assertions'; import { Stack, App } from '@aws-cdk/core'; import { - HttpApi, HttpAuthorizer, HttpAuthorizerType, HttpConnectionType, HttpIntegrationType, HttpMethod, HttpRoute, HttpRouteAuthorizerBindOptions, - HttpRouteAuthorizerConfig, HttpRouteIntegrationConfig, HttpRouteKey, IHttpRouteAuthorizer, IHttpRouteIntegration, PayloadFormatVersion, + HttpApi, HttpAuthorizer, HttpAuthorizerType, HttpConnectionType, HttpIntegrationType, HttpMethod, HttpRoute, + HttpRouteAuthorizerBindOptions, HttpRouteAuthorizerConfig, HttpRouteIntegrationConfig, HttpRouteKey, IHttpRouteAuthorizer, IHttpRouteIntegration, + MappingValue, + ParameterMapping, + PayloadFormatVersion, } from '../../lib'; describe('HttpRoute', () => { @@ -174,6 +177,9 @@ describe('HttpRoute', () => { connectionType: HttpConnectionType.VPC_LINK, uri: 'some-target-arn', secureServerName: 'some-server-name', + parameterMapping: new ParameterMapping() + .appendHeader('header2', MappingValue.requestHeader('header1')) + .removeHeader('header1'), }; } } @@ -201,6 +207,47 @@ describe('HttpRoute', () => { Template.fromStack(stack).resourceCountIs('AWS::ApiGatewayV2::VpcLink', 0); }); + test('configures private integration correctly when parameter mappings are passed', () => { + // GIVEN + const stack = new Stack(); + const httpApi = new HttpApi(stack, 'HttpApi'); + + class PrivateIntegration implements IHttpRouteIntegration { + public bind(): HttpRouteIntegrationConfig { + return { + method: HttpMethod.ANY, + payloadFormatVersion: PayloadFormatVersion.VERSION_1_0, + type: HttpIntegrationType.HTTP_PROXY, + uri: 'some-target-arn', + parameterMapping: new ParameterMapping() + .appendHeader('header2', MappingValue.requestHeader('header1')) + .removeHeader('header1'), + }; + } + } + + // WHEN + new HttpRoute(stack, 'HttpRoute', { + httpApi, + integration: new PrivateIntegration(), + routeKey: HttpRouteKey.with('/books', HttpMethod.GET), + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::ApiGatewayV2::Integration', { + IntegrationType: 'HTTP_PROXY', + IntegrationMethod: 'ANY', + IntegrationUri: 'some-target-arn', + PayloadFormatVersion: '1.0', + RequestParameters: { + 'append:header.header2': '$request.header.header1', + 'remove:header.header1': '', + }, + }); + + Template.fromStack(stack).resourceCountIs('AWS::ApiGatewayV2::VpcLink', 0); + }); + test('can create route with an authorizer attached', () => { const stack = new Stack(); const httpApi = new HttpApi(stack, 'HttpApi'); diff --git a/packages/@aws-cdk/aws-appconfig/.eslintrc.js b/packages/@aws-cdk/aws-appconfig/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-appconfig/.eslintrc.js +++ b/packages/@aws-cdk/aws-appconfig/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-appconfig/jest.config.js b/packages/@aws-cdk/aws-appconfig/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-appconfig/jest.config.js +++ b/packages/@aws-cdk/aws-appconfig/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-appconfig/package.json b/packages/@aws-cdk/aws-appconfig/package.json index 87877e48cadd7..afa652c138049 100644 --- a/packages/@aws-cdk/aws-appconfig/package.json +++ b/packages/@aws-cdk/aws-appconfig/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::AppConfig", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-appflow/.eslintrc.js b/packages/@aws-cdk/aws-appflow/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-appflow/.eslintrc.js +++ b/packages/@aws-cdk/aws-appflow/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-appflow/jest.config.js b/packages/@aws-cdk/aws-appflow/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-appflow/jest.config.js +++ b/packages/@aws-cdk/aws-appflow/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-appflow/package.json b/packages/@aws-cdk/aws-appflow/package.json index 3c1164cb36e44..3e5d52954046c 100644 --- a/packages/@aws-cdk/aws-appflow/package.json +++ b/packages/@aws-cdk/aws-appflow/package.json @@ -55,8 +55,7 @@ "build+test+extract": "yarn build+test && yarn rosetta:extract" }, "cdk-build": { - "cloudformation": "AWS::AppFlow", - "jest": true + "cloudformation": "AWS::AppFlow" }, "keywords": [ "aws", @@ -72,11 +71,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-appintegrations/.eslintrc.js b/packages/@aws-cdk/aws-appintegrations/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-appintegrations/.eslintrc.js +++ b/packages/@aws-cdk/aws-appintegrations/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-appintegrations/jest.config.js b/packages/@aws-cdk/aws-appintegrations/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-appintegrations/jest.config.js +++ b/packages/@aws-cdk/aws-appintegrations/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-appintegrations/package.json b/packages/@aws-cdk/aws-appintegrations/package.json index df834c9675083..d0129f5818d65 100644 --- a/packages/@aws-cdk/aws-appintegrations/package.json +++ b/packages/@aws-cdk/aws-appintegrations/package.json @@ -58,7 +58,6 @@ }, "cdk-build": { "cloudformation": "AWS::AppIntegrations", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -77,11 +76,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", "@aws-cdk/assertions": "0.0.0", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-applicationautoscaling/.eslintrc.js b/packages/@aws-cdk/aws-applicationautoscaling/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-applicationautoscaling/.eslintrc.js +++ b/packages/@aws-cdk/aws-applicationautoscaling/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-applicationautoscaling/jest.config.js b/packages/@aws-cdk/aws-applicationautoscaling/jest.config.js index 3eef7ba398c07..211d217076e38 100644 --- a/packages/@aws-cdk/aws-applicationautoscaling/jest.config.js +++ b/packages/@aws-cdk/aws-applicationautoscaling/jest.config.js @@ -1,4 +1,4 @@ -const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +const baseConfig = require('../../../tools/@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = { ...baseConfig, coverageThreshold: { diff --git a/packages/@aws-cdk/aws-applicationautoscaling/package.json b/packages/@aws-cdk/aws-applicationautoscaling/package.json index 5026578a5d6d0..e0fb58dda98e7 100644 --- a/packages/@aws-cdk/aws-applicationautoscaling/package.json +++ b/packages/@aws-cdk/aws-applicationautoscaling/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::ApplicationAutoScaling", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,13 +72,13 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "fast-check": "^2.17.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "fast-check": "^2.18.0", + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-autoscaling-common": "0.0.0", diff --git a/packages/@aws-cdk/aws-applicationinsights/.eslintrc.js b/packages/@aws-cdk/aws-applicationinsights/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-applicationinsights/.eslintrc.js +++ b/packages/@aws-cdk/aws-applicationinsights/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-applicationinsights/jest.config.js b/packages/@aws-cdk/aws-applicationinsights/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-applicationinsights/jest.config.js +++ b/packages/@aws-cdk/aws-applicationinsights/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-applicationinsights/package.json b/packages/@aws-cdk/aws-applicationinsights/package.json index 3b0b998051313..28045bdba0613 100644 --- a/packages/@aws-cdk/aws-applicationinsights/package.json +++ b/packages/@aws-cdk/aws-applicationinsights/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::ApplicationInsights", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-appmesh/.eslintrc.js b/packages/@aws-cdk/aws-appmesh/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-appmesh/.eslintrc.js +++ b/packages/@aws-cdk/aws-appmesh/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-appmesh/README.md b/packages/@aws-cdk/aws-appmesh/README.md index b1779dffe6f8a..54bc79fade4c3 100644 --- a/packages/@aws-cdk/aws-appmesh/README.md +++ b/packages/@aws-cdk/aws-appmesh/README.md @@ -35,7 +35,7 @@ After you create your service mesh, you can create virtual services, virtual nod The following example creates the `AppMesh` service mesh with the default egress filter of `DROP_ALL`. See [the AWS CloudFormation `EgressFilter` resource](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-mesh-egressfilter.html) for more info on egress filters. ```ts -const mesh = new Mesh(stack, 'AppMesh', { +const mesh = new appmesh.Mesh(this, 'AppMesh', { meshName: 'myAwsMesh', }); ``` @@ -43,9 +43,9 @@ const mesh = new Mesh(stack, 'AppMesh', { The mesh can instead be created with the `ALLOW_ALL` egress filter by providing the `egressFilter` property. ```ts -const mesh = new Mesh(stack, 'AppMesh', { +const mesh = new appmesh.Mesh(this, 'AppMesh', { meshName: 'myAwsMesh', - egressFilter: MeshFilterType.ALLOW_ALL, + egressFilter: appmesh.MeshFilterType.ALLOW_ALL, }); ``` @@ -57,8 +57,9 @@ Virtual routers handle traffic for one or more virtual services within your mesh After you create a virtual router, you can create and associate routes to your virtual router that direct incoming requests to different virtual nodes. ```ts +declare const mesh: appmesh.Mesh; const router = mesh.addVirtualRouter('router', { - listeners: [ VirtualRouterListener.http(8080) ], + listeners: [appmesh.VirtualRouterListener.http(8080)], }); ``` @@ -68,16 +69,19 @@ The router can also be created using the `VirtualRouter` constructor (passing in This is particularly useful when splitting your resources between many stacks: for example, defining the mesh itself as part of an infrastructure stack, but defining the other resources, such as routers, in the application stack: ```ts -const mesh = new Mesh(infraStack, 'AppMesh', { +declare const infraStack: cdk.Stack; +declare const appStack: cdk.Stack; + +const mesh = new appmesh.Mesh(infraStack, 'AppMesh', { meshName: 'myAwsMesh', - egressFilter: MeshFilterType.ALLOW_ALL, + egressFilter: appmesh.MeshFilterType.ALLOW_ALL, }); // the VirtualRouter will belong to 'appStack', // even though the Mesh belongs to 'infraStack' -const router = new VirtualRouter(appStack, 'router', { +const router = new appmesh.VirtualRouter(appStack, 'router', { mesh, // notice that mesh is a required property when creating a router with the 'new' statement - listeners: [VirtualRouterListener.http(8081)], + listeners: [appmesh.VirtualRouterListener.http(8081)], }); ``` @@ -102,18 +106,22 @@ When creating a virtual service: Adding a virtual router as the provider: ```ts -new VirtualService(stack, 'virtual-service', { +declare const router: appmesh.VirtualRouter; + +new appmesh.VirtualService(this, 'virtual-service', { virtualServiceName: 'my-service.default.svc.cluster.local', // optional - virtualServiceProvider: VirtualServiceProvider.virtualRouter(router), + virtualServiceProvider: appmesh.VirtualServiceProvider.virtualRouter(router), }); ``` Adding a virtual node as the provider: ```ts -new VirtualService(stack, 'virtual-service', { +declare const node: appmesh.VirtualNode; + +new appmesh.VirtualService(this, 'virtual-service', { virtualServiceName: `my-service.default.svc.cluster.local`, // optional - virtualServiceProvider: VirtualServiceProvider.virtualNode(node), + virtualServiceProvider: appmesh.VirtualServiceProvider.virtualNode(node), }); ``` @@ -129,18 +137,19 @@ The response metadata for your new virtual node contains the Amazon Resource Nam > If you require your Envoy stats or tracing to use a different name, you can override the `node.cluster` value that is set by `APPMESH_VIRTUAL_NODE_NAME` with the `APPMESH_VIRTUAL_NODE_CLUSTER` environment variable. ```ts -const vpc = new ec2.Vpc(stack, 'vpc'); -const namespace = new servicediscovery.PrivateDnsNamespace(stack, 'test-namespace', { +const vpc = new ec2.Vpc(this, 'vpc'); +const namespace = new cloudmap.PrivateDnsNamespace(this, 'test-namespace', { vpc, name: 'domain.local', }); const service = namespace.createService('Svc'); +declare const mesh: appmesh.Mesh; const node = mesh.addVirtualNode('virtual-node', { - serviceDiscovery: ServiceDiscovery.cloudMap(service), - listeners: [VirtualNodeListener.http({ + serviceDiscovery: appmesh.ServiceDiscovery.cloudMap(service), + listeners: [appmesh.VirtualNodeListener.http({ port: 8081, - healthCheck: HealthCheck.http({ + healthCheck: appmesh.HealthCheck.http({ healthyThreshold: 3, interval: cdk.Duration.seconds(5), // minimum path: '/health-check-path', @@ -148,19 +157,22 @@ const node = mesh.addVirtualNode('virtual-node', { unhealthyThreshold: 2, }), })], - accessLog: AccessLog.fromFilePath('/dev/stdout'), + accessLog: appmesh.AccessLog.fromFilePath('/dev/stdout'), }); ``` Create a `VirtualNode` with the constructor and add tags. ```ts -const node = new VirtualNode(stack, 'node', { +declare const mesh: appmesh.Mesh; +declare const service: cloudmap.Service; + +const node = new appmesh.VirtualNode(this, 'node', { mesh, - serviceDiscovery: ServiceDiscovery.cloudMap(service), - listeners: [VirtualNodeListener.http({ + serviceDiscovery: appmesh.ServiceDiscovery.cloudMap(service), + listeners: [appmesh.VirtualNodeListener.http({ port: 8080, - healthCheck: HealthCheck.http({ + healthCheck: appmesh.HealthCheck.http({ healthyThreshold: 3, interval: cdk.Duration.seconds(5), path: '/ping', @@ -174,11 +186,11 @@ const node = new VirtualNode(stack, 'node', { backendDefaults: { tlsClientPolicy: { validation: { - trust: TlsValidationTrust.file('/keys/local_cert_chain.pem'), + trust: appmesh.TlsValidationTrust.file('/keys/local_cert_chain.pem'), }, }, }, - accessLog: AccessLog.fromFilePath('/dev/stdout'), + accessLog: appmesh.AccessLog.fromFilePath('/dev/stdout'), }); cdk.Tags.of(node).add('Environment', 'Dev'); @@ -187,12 +199,16 @@ cdk.Tags.of(node).add('Environment', 'Dev'); Create a `VirtualNode` with the constructor and add backend virtual service. ```ts -const node = new VirtualNode(stack, 'node', { +declare const mesh: appmesh.Mesh; +declare const router: appmesh.VirtualRouter; +declare const service: cloudmap.Service; + +const node = new appmesh.VirtualNode(this, 'node', { mesh, - serviceDiscovery: ServiceDiscovery.cloudMap(service), - listeners: [VirtualNodeListener.http({ + serviceDiscovery: appmesh.ServiceDiscovery.cloudMap(service), + listeners: [appmesh.VirtualNodeListener.http({ port: 8080, - healthCheck: HealthCheck.http({ + healthCheck: appmesh.HealthCheck.http({ healthyThreshold: 3, interval: cdk.Duration.seconds(5), path: '/ping', @@ -203,15 +219,15 @@ const node = new VirtualNode(stack, 'node', { idle: cdk.Duration.seconds(5), }, })], - accessLog: AccessLog.fromFilePath('/dev/stdout'), + accessLog: appmesh.AccessLog.fromFilePath('/dev/stdout'), }); -const virtualService = new VirtualService(stack, 'service-1', { - virtualServiceProvider: VirtualServiceProvider.virtualRouter(router), +const virtualService = new appmesh.VirtualService(this, 'service-1', { + virtualServiceProvider: appmesh.VirtualServiceProvider.virtualRouter(router), virtualServiceName: 'service1.domain.local', }); -node.addBackend(Backend.virtualService(virtualService)); +node.addBackend(appmesh.Backend.virtualService(virtualService)); ``` The `listeners` property can be left blank and added later with the `node.addListener()` method. The `serviceDiscovery` property must be specified when specifying a listener. @@ -231,45 +247,44 @@ Provide the TLS certificate to the proxy in one of the following ways: - A certificate provided by a Secrets Discovery Service (SDS) endpoint over local Unix Domain Socket (specify its `secretName`). -```typescript -import * as certificatemanager from '@aws-cdk/aws-certificatemanager'; - +```ts // A Virtual Node with listener TLS from an ACM provided certificate -const cert = new certificatemanager.Certificate(this, 'cert', {...}); +declare const cert: certificatemanager.Certificate; +declare const mesh: appmesh.Mesh; -const node = new VirtualNode(stack, 'node', { +const node = new appmesh.VirtualNode(this, 'node', { mesh, - serviceDiscovery: ServiceDiscovery.dns('node'), - listeners: [VirtualNodeListener.grpc({ + serviceDiscovery: appmesh.ServiceDiscovery.dns('node'), + listeners: [appmesh.VirtualNodeListener.grpc({ port: 80, tls: { - mode: TlsMode.STRICT, - certificate: TlsCertificate.acm(cert), + mode: appmesh.TlsMode.STRICT, + certificate: appmesh.TlsCertificate.acm(cert), }, })], }); // A Virtual Gateway with listener TLS from a customer provided file certificate -const gateway = new VirtualGateway(this, 'gateway', { - mesh: mesh, - listeners: [VirtualGatewayListener.grpc({ +const gateway = new appmesh.VirtualGateway(this, 'gateway', { + mesh, + listeners: [appmesh.VirtualGatewayListener.grpc({ port: 8080, tls: { - mode: TlsMode.STRICT, - certificate: TlsCertificate.file('path/to/certChain', 'path/to/privateKey'), + mode: appmesh.TlsMode.STRICT, + certificate: appmesh.TlsCertificate.file('path/to/certChain', 'path/to/privateKey'), }, })], virtualGatewayName: 'gateway', }); // A Virtual Gateway with listener TLS from a SDS provided certificate -const gateway2 = new VirtualGateway(this, 'gateway2', { - mesh: mesh, - listeners: [VirtualGatewayListener.http2({ +const gateway2 = new appmesh.VirtualGateway(this, 'gateway2', { + mesh, + listeners: [appmesh.VirtualGatewayListener.http2({ port: 8080, tls: { - mode: TlsMode.STRICT, - certificate: TlsCertificate.sds('secrete_certificate'), + mode: appmesh.TlsMode.STRICT, + certificate: appmesh.TlsCertificate.sds('secrete_certificate'), }, })], virtualGatewayName: 'gateway2', @@ -290,38 +305,39 @@ To enable mutual TLS authentication, add the `mutualTlsCertificate` property to > **Note** > Currently, a certificate from AWS Certificate Manager (ACM) cannot be used for mutual TLS authentication. -```typescript -import * as certificatemanager from '@aws-cdk/aws-certificatemanager'; +```ts +declare const mesh: appmesh.Mesh; -const node1 = new VirtualNode(stack, 'node1', { +const node1 = new appmesh.VirtualNode(this, 'node1', { mesh, - serviceDiscovery: ServiceDiscovery.dns('node'), - listeners: [VirtualNodeListener.grpc({ + serviceDiscovery: appmesh.ServiceDiscovery.dns('node'), + listeners: [appmesh.VirtualNodeListener.grpc({ port: 80, tls: { - mode: TlsMode.STRICT, - certificate: TlsCertificate.file('path/to/certChain', 'path/to/privateKey'), + mode: appmesh.TlsMode.STRICT, + certificate: appmesh.TlsCertificate.file('path/to/certChain', 'path/to/privateKey'), // Validate a file client certificates to enable mutual TLS authentication when a client provides a certificate. mutualTlsValidation: { - trust: TlsValidationTrust.file('path-to-certificate'), + trust: appmesh.TlsValidationTrust.file('path-to-certificate'), }, }, })], }); -const node2 = new VirtualNode(stack, 'node2', { +const certificateAuthorityArn = 'arn:aws:acm-pca:us-east-1:123456789012:certificate-authority/12345678-1234-1234-1234-123456789012'; +const node2 = new appmesh.VirtualNode(this, 'node2', { mesh, - serviceDiscovery: ServiceDiscovery.dns('node2'), + serviceDiscovery: appmesh.ServiceDiscovery.dns('node2'), backendDefaults: { tlsClientPolicy: { ports: [8080, 8081], validation: { - subjectAlternativeNames: SubjectAlternativeNames.matchingExactly('mesh-endpoint.apps.local'), - trust: TlsValidationTrust.acm([ - acmpca.CertificateAuthority.fromCertificateAuthorityArn(stack, 'certificate', certificateAuthorityArn)]), + subjectAlternativeNames: appmesh.SubjectAlternativeNames.matchingExactly('mesh-endpoint.apps.local'), + trust: appmesh.TlsValidationTrust.acm([ + acmpca.CertificateAuthority.fromCertificateAuthorityArn(this, 'certificate', certificateAuthorityArn)]), }, // Provide a SDS client certificate when a server requests it and enable mutual TLS authentication. - mutualTlsCertificate: TlsCertificate.sds('secret_certificate'), + mutualTlsCertificate: appmesh.TlsCertificate.sds('secret_certificate'), }, }, }); @@ -332,18 +348,19 @@ const node2 = new VirtualNode(stack, 'node2', { The `outlierDetection` property adds outlier detection to a Virtual Node listener. The properties `baseEjectionDuration`, `interval`, `maxEjectionPercent`, and `maxServerErrors` are required. -```typescript +```ts // Cloud Map service discovery is currently required for host ejection by outlier detection -const vpc = new ec2.Vpc(stack, 'vpc'); -const namespace = new servicediscovery.PrivateDnsNamespace(this, 'test-namespace', { +const vpc = new ec2.Vpc(this, 'vpc'); +const namespace = new cloudmap.PrivateDnsNamespace(this, 'test-namespace', { vpc, name: 'domain.local', }); const service = namespace.createService('Svc'); +declare const mesh: appmesh.Mesh; const node = mesh.addVirtualNode('virtual-node', { - serviceDiscovery: ServiceDiscovery.cloudMap(service), - listeners: [VirtualNodeListener.http({ + serviceDiscovery: appmesh.ServiceDiscovery.cloudMap(service), + listeners: [appmesh.VirtualNodeListener.http({ outlierDetection: { baseEjectionDuration: cdk.Duration.seconds(10), interval: cdk.Duration.seconds(30), @@ -358,16 +375,17 @@ const node = mesh.addVirtualNode('virtual-node', { The `connectionPool` property can be added to a Virtual Node listener or Virtual Gateway listener to add a request connection pool. Each listener protocol type has its own connection pool properties. -```typescript +```ts // A Virtual Node with a gRPC listener with a connection pool set -const node = new VirtualNode(stack, 'node', { +declare const mesh: appmesh.Mesh; +const node = new appmesh.VirtualNode(this, 'node', { mesh, // DNS service discovery can optionally specify the DNS response type as either LOAD_BALANCER or ENDPOINTS. // LOAD_BALANCER means that the DNS resolver returns a loadbalanced set of endpoints, // whereas ENDPOINTS means that the DNS resolver is returning all the endpoints. // By default, the response type is assumed to be LOAD_BALANCER - serviceDiscovery: ServiceDiscovery.dns('node', DnsResponseType.ENDPOINTS), - listeners: [VirtualNodeListener.http({ + serviceDiscovery: appmesh.ServiceDiscovery.dns('node', appmesh.DnsResponseType.ENDPOINTS), + listeners: [appmesh.VirtualNodeListener.http({ port: 80, connectionPool: { maxConnections: 100, @@ -377,9 +395,9 @@ const node = new VirtualNode(stack, 'node', { }); // A Virtual Gateway with a gRPC listener with a connection pool set -const gateway = new VirtualGateway(stack, 'gateway', { +const gateway = new appmesh.VirtualGateway(this, 'gateway', { mesh, - listeners: [VirtualGatewayListener.grpc({ + listeners: [appmesh.VirtualGatewayListener.grpc({ port: 8080, connectionPool: { maxRequests: 10, @@ -406,8 +424,11 @@ When specifying the method name, the service name must also be specified. For example, here's how to add an HTTP route that matches based on a prefix of the URL path: ```ts +declare const router: appmesh.VirtualRouter; +declare const node: appmesh.VirtualNode; + router.addRoute('route-http', { - routeSpec: RouteSpec.http({ + routeSpec: appmesh.RouteSpec.http({ weightedTargets: [ { virtualNode: node, @@ -415,7 +436,7 @@ router.addRoute('route-http', { ], match: { // Path that is passed to this method must start with '/'. - path: HttpRoutePathMatch.startsWith('/path-to-app'), + path: appmesh.HttpRoutePathMatch.startsWith('/path-to-app'), }, }), }); @@ -424,25 +445,28 @@ router.addRoute('route-http', { Add an HTTP2 route that matches based on exact path, method, scheme, headers, and query parameters: ```ts +declare const router: appmesh.VirtualRouter; +declare const node: appmesh.VirtualNode; + router.addRoute('route-http2', { - routeSpec: RouteSpec.http2({ + routeSpec: appmesh.RouteSpec.http2({ weightedTargets: [ { virtualNode: node, }, ], match: { - path: HttpRoutePathMatch.exactly('/exact'), - method: HttpRouteMethod.POST, - protocol: HttpRouteProtocol.HTTPS, + path: appmesh.HttpRoutePathMatch.exactly('/exact'), + method: appmesh.HttpRouteMethod.POST, + protocol: appmesh.HttpRouteProtocol.HTTPS, headers: [ // All specified headers must match for the route to match. - HeaderMatch.valueIs('Content-Type', 'application/json'), - HeaderMatch.valueIsNot('Content-Type', 'application/json'), + appmesh.HeaderMatch.valueIs('Content-Type', 'application/json'), + appmesh.HeaderMatch.valueIsNot('Content-Type', 'application/json'), ], queryParameters: [ // All specified query parameters must match for the route to match. - QueryParameterMatch.valueIs('query-field', 'value') + appmesh.QueryParameterMatch.valueIs('query-field', 'value') ], }, }), @@ -452,8 +476,11 @@ router.addRoute('route-http2', { Add a single route with two targets and split traffic 50/50: ```ts +declare const router: appmesh.VirtualRouter; +declare const node: appmesh.VirtualNode; + router.addRoute('route-http', { - routeSpec: RouteSpec.http({ + routeSpec: appmesh.RouteSpec.http({ weightedTargets: [ { virtualNode: node, @@ -465,7 +492,7 @@ router.addRoute('route-http', { }, ], match: { - path: HttpRoutePathMatch.startsWith('/path-to-app'), + path: appmesh.HttpRoutePathMatch.startsWith('/path-to-app'), }, }), }); @@ -474,14 +501,17 @@ router.addRoute('route-http', { Add an http2 route with retries: ```ts +declare const router: appmesh.VirtualRouter; +declare const node: appmesh.VirtualNode; + router.addRoute('route-http2-retry', { - routeSpec: RouteSpec.http2({ + routeSpec: appmesh.RouteSpec.http2({ weightedTargets: [{ virtualNode: node }], retryPolicy: { // Retry if the connection failed - tcpRetryEvents: [TcpRetryEvent.CONNECTION_ERROR], + tcpRetryEvents: [appmesh.TcpRetryEvent.CONNECTION_ERROR], // Retry if HTTP responds with a gateway error (502, 503, 504) - httpRetryEvents: [HttpRetryEvent.GATEWAY_ERROR], + httpRetryEvents: [appmesh.HttpRetryEvent.GATEWAY_ERROR], // Retry five times retryAttempts: 5, // Use a 1 second timeout per retry @@ -494,19 +524,22 @@ router.addRoute('route-http2-retry', { Add a gRPC route with retries: ```ts +declare const router: appmesh.VirtualRouter; +declare const node: appmesh.VirtualNode; + router.addRoute('route-grpc-retry', { - routeSpec: RouteSpec.grpc({ + routeSpec: appmesh.RouteSpec.grpc({ weightedTargets: [{ virtualNode: node }], match: { serviceName: 'servicename' }, retryPolicy: { - tcpRetryEvents: [TcpRetryEvent.CONNECTION_ERROR], - httpRetryEvents: [HttpRetryEvent.GATEWAY_ERROR], + tcpRetryEvents: [appmesh.TcpRetryEvent.CONNECTION_ERROR], + httpRetryEvents: [appmesh.HttpRetryEvent.GATEWAY_ERROR], // Retry if gRPC responds that the request was cancelled, a resource // was exhausted, or if the service is unavailable grpcRetryEvents: [ - GrpcRetryEvent.CANCELLED, - GrpcRetryEvent.RESOURCE_EXHAUSTED, - GrpcRetryEvent.UNAVAILABLE, + appmesh.GrpcRetryEvent.CANCELLED, + appmesh.GrpcRetryEvent.RESOURCE_EXHAUSTED, + appmesh.GrpcRetryEvent.UNAVAILABLE, ], retryAttempts: 5, retryTimeout: cdk.Duration.seconds(1), @@ -518,8 +551,11 @@ router.addRoute('route-grpc-retry', { Add an gRPC route that matches based on method name and metadata: ```ts +declare const router: appmesh.VirtualRouter; +declare const node: appmesh.VirtualNode; + router.addRoute('route-grpc-retry', { - routeSpec: RouteSpec.grpc({ + routeSpec: appmesh.RouteSpec.grpc({ weightedTargets: [{ virtualNode: node }], match: { // When method name is specified, service name must be also specified. @@ -527,8 +563,8 @@ router.addRoute('route-grpc-retry', { serviceName: 'servicename', metadata: [ // All specified metadata must match for the route to match. - HeaderMatch.valueStartsWith('Content-Type', 'application/'), - HeaderMatch.valueDoesNotStartWith('Content-Type', 'text/'), + appmesh.HeaderMatch.valueStartsWith('Content-Type', 'application/'), + appmesh.HeaderMatch.valueDoesNotStartWith('Content-Type', 'text/'), ], }, }), @@ -538,8 +574,11 @@ router.addRoute('route-grpc-retry', { Add a gRPC route with timeout: ```ts +declare const router: appmesh.VirtualRouter; +declare const node: appmesh.VirtualNode; + router.addRoute('route-http', { - routeSpec: RouteSpec.grpc({ + routeSpec: appmesh.RouteSpec.grpc({ weightedTargets: [ { virtualNode: node, @@ -569,13 +608,14 @@ using rules defined in gateway routes which can be added to your virtual gateway Create a virtual gateway with the constructor: ```ts +declare const mesh: appmesh.Mesh; const certificateAuthorityArn = 'arn:aws:acm-pca:us-east-1:123456789012:certificate-authority/12345678-1234-1234-1234-123456789012'; -const gateway = new VirtualGateway(stack, 'gateway', { +const gateway = new appmesh.VirtualGateway(this, 'gateway', { mesh: mesh, - listeners: [VirtualGatewayListener.http({ + listeners: [appmesh.VirtualGatewayListener.http({ port: 443, - healthCheck: HealthCheck.http({ + healthCheck: appmesh.HealthCheck.http({ interval: cdk.Duration.seconds(10), }), })], @@ -583,12 +623,12 @@ const gateway = new VirtualGateway(stack, 'gateway', { tlsClientPolicy: { ports: [8080, 8081], validation: { - trust: TlsValidationTrust.acm([ - acmpca.CertificateAuthority.fromCertificateAuthorityArn(stack, 'certificate', certificateAuthorityArn)]), + trust: appmesh.TlsValidationTrust.acm([ + acmpca.CertificateAuthority.fromCertificateAuthorityArn(this, 'certificate', certificateAuthorityArn)]), }, }, }, - accessLog: AccessLog.fromFilePath('/dev/stdout'), + accessLog: appmesh.AccessLog.fromFilePath('/dev/stdout'), virtualGatewayName: 'virtualGateway', }); ``` @@ -596,12 +636,14 @@ const gateway = new VirtualGateway(stack, 'gateway', { Add a virtual gateway directly to the mesh: ```ts +declare const mesh: appmesh.Mesh; + const gateway = mesh.addVirtualGateway('gateway', { - accessLog: AccessLog.fromFilePath('/dev/stdout'), + accessLog: appmesh.AccessLog.fromFilePath('/dev/stdout'), virtualGatewayName: 'virtualGateway', - listeners: [VirtualGatewayListener.http({ + listeners: [appmesh.VirtualGatewayListener.http({ port: 443, - healthCheck: HealthCheck.http({ + healthCheck: appmesh.HealthCheck.http({ interval: cdk.Duration.seconds(10), }), })], @@ -622,11 +664,14 @@ path (prefix, exact, or regex), HTTP method, host name, HTTP headers, and query By default, HTTP-based gateway routes match all requests. ```ts +declare const gateway: appmesh.VirtualGateway; +declare const virtualService: appmesh.VirtualService; + gateway.addGatewayRoute('gateway-route-http', { - routeSpec: GatewayRouteSpec.http({ + routeSpec: appmesh.GatewayRouteSpec.http({ routeTarget: virtualService, match: { - path: HttpGatewayRoutePathMatch.regex('regex'), + path: appmesh.HttpGatewayRoutePathMatch.regex('regex'), }, }), }); @@ -635,11 +680,14 @@ gateway.addGatewayRoute('gateway-route-http', { For gRPC-based gateway routes, the `match` field can be used to match on service name, host name, and metadata. ```ts +declare const gateway: appmesh.VirtualGateway; +declare const virtualService: appmesh.VirtualService; + gateway.addGatewayRoute('gateway-route-grpc', { - routeSpec: GatewayRouteSpec.grpc({ + routeSpec: appmesh.GatewayRouteSpec.grpc({ routeTarget: virtualService, match: { - hostname: GatewayRouteHostnameMatch.endsWith('.example.com'), + hostname: appmesh.GatewayRouteHostnameMatch.endsWith('.example.com'), }, }), }); @@ -649,23 +697,26 @@ For HTTP based gateway routes, App Mesh automatically rewrites the matched prefi This automatic rewrite configuration can be overwritten in following ways: ```ts +declare const gateway: appmesh.VirtualGateway; +declare const virtualService: appmesh.VirtualService; + gateway.addGatewayRoute('gateway-route-http', { - routeSpec: GatewayRouteSpec.http({ + routeSpec: appmesh.GatewayRouteSpec.http({ routeTarget: virtualService, match: { // This disables the default rewrite to '/', and retains original path. - path: HttpGatewayRoutePathMatch.startsWith('/path-to-app/', ''), + path: appmesh.HttpGatewayRoutePathMatch.startsWith('/path-to-app/', ''), }, }), }); gateway.addGatewayRoute('gateway-route-http-1', { - routeSpec: GatewayRouteSpec.http({ + routeSpec: appmesh.GatewayRouteSpec.http({ routeTarget: virtualService, match: { // If the request full path is '/path-to-app/xxxxx', this rewrites the path to '/rewrittenUri/xxxxx'. // Please note both `prefixPathMatch` and `rewriteTo` must start and end with the `/` character. - path: HttpGatewayRoutePathMatch.startsWith('/path-to-app/', '/rewrittenUri/'), + path: appmesh.HttpGatewayRoutePathMatch.startsWith('/path-to-app/', '/rewrittenUri/'), }, }), }); @@ -675,12 +726,15 @@ If matching other path (exact or regex), only specific rewrite path can be speci Unlike `startsWith()` method above, no default rewrite is performed. ```ts +declare const gateway: appmesh.VirtualGateway; +declare const virtualService: appmesh.VirtualService; + gateway.addGatewayRoute('gateway-route-http-2', { - routeSpec: GatewayRouteSpec.http({ + routeSpec: appmesh.GatewayRouteSpec.http({ routeTarget: virtualService, match: { // This rewrites the path from '/test' to '/rewrittenPath'. - path: HttpGatewayRoutePathMatch.exactly('/test', '/rewrittenPath'), + path: appmesh.HttpGatewayRoutePathMatch.exactly('/test', '/rewrittenPath'), }, }), }); @@ -691,11 +745,14 @@ the original request received at the Virtual Gateway to the destination Virtual This default host name rewrite can be configured by specifying the rewrite rule as one of the `match` property: ```ts +declare const gateway: appmesh.VirtualGateway; +declare const virtualService: appmesh.VirtualService; + gateway.addGatewayRoute('gateway-route-grpc', { - routeSpec: GatewayRouteSpec.grpc({ + routeSpec: appmesh.GatewayRouteSpec.grpc({ routeTarget: virtualService, match: { - hostname: GatewayRouteHostnameMatch.exactly('example.com'), + hostname: appmesh.GatewayRouteHostnameMatch.exactly('example.com'), // This disables the default rewrite to virtual service name and retain original request. rewriteRequestHostname: false, }, @@ -710,12 +767,13 @@ These imported resources can be used with other resources in your mesh as if the ```ts const arn = 'arn:aws:appmesh:us-east-1:123456789012:mesh/testMesh/virtualNode/testNode'; -VirtualNode.fromVirtualNodeArn(stack, 'importedVirtualNode', arn); +appmesh.VirtualNode.fromVirtualNodeArn(this, 'importedVirtualNode', arn); ``` ```ts -VirtualNode.fromVirtualNodeAttributes(stack, 'imported-virtual-node', { - mesh: Mesh.fromMeshName(stack, 'Mesh', 'testMesh'), +const virtualNodeName = 'my-virtual-node'; +appmesh.VirtualNode.fromVirtualNodeAttributes(this, 'imported-virtual-node', { + mesh: appmesh.Mesh.fromMeshName(this, 'Mesh', 'testMesh'), virtualNodeName: virtualNodeName, }); ``` @@ -724,11 +782,11 @@ To import a mesh, again there are two static methods, `fromMeshArn` and `fromMes ```ts const arn = 'arn:aws:appmesh:us-east-1:123456789012:mesh/testMesh'; -Mesh.fromMeshArn(stack, 'imported-mesh', arn); +appmesh.Mesh.fromMeshArn(this, 'imported-mesh', arn); ``` ```ts -Mesh.fromMeshName(stack, 'imported-mesh', 'abc'); +appmesh.Mesh.fromMeshName(this, 'imported-mesh', 'abc'); ``` ## IAM Grants @@ -737,8 +795,9 @@ Mesh.fromMeshName(stack, 'imported-mesh', 'abc'); Envoy access to stream generated config from App Mesh. ```ts -const gateway = new VirtualGateway(stack, 'testGateway', { mesh: mesh }); -const envoyUser = new iam.User(stack, 'envoyUser'); +declare const mesh: appmesh.Mesh; +const gateway = new appmesh.VirtualGateway(this, 'testGateway', { mesh }); +const envoyUser = new iam.User(this, 'envoyUser'); /** * This will grant `grantStreamAggregatedResources` ONLY for this gateway. @@ -754,10 +813,10 @@ A shared mesh allows resources created by different accounts to communicate with // This is the ARN for the mesh from different AWS IAM account ID. // Ensure mesh is properly shared with your account. For more details, see: https://github.com/aws/aws-cdk/issues/15404 const arn = 'arn:aws:appmesh:us-east-1:123456789012:mesh/testMesh'; -sharedMesh = Mesh.fromMeshArn(stack, 'imported-mesh', arn); +const sharedMesh = appmesh.Mesh.fromMeshArn(this, 'imported-mesh', arn); // This VirtualNode resource can communicate with the resources in the mesh from different AWS IAM account ID. -new VirtualNode(stack, 'test-node', { +new appmesh.VirtualNode(this, 'test-node', { mesh: sharedMesh, }); ``` diff --git a/packages/@aws-cdk/aws-appmesh/jest.config.js b/packages/@aws-cdk/aws-appmesh/jest.config.js index cd664e1d069e5..34818e1593f6b 100644 --- a/packages/@aws-cdk/aws-appmesh/jest.config.js +++ b/packages/@aws-cdk/aws-appmesh/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +const baseConfig = require('../../../tools/@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-appmesh/package.json b/packages/@aws-cdk/aws-appmesh/package.json index d67eeb9a0be40..989db40a2844f 100644 --- a/packages/@aws-cdk/aws-appmesh/package.json +++ b/packages/@aws-cdk/aws-appmesh/package.json @@ -58,8 +58,7 @@ "cloudformation": "AWS::AppMesh", "env": { "AWSLINT_BASE_CONSTRUCT": true - }, - "jest": true + } }, "nyc": { "statements": 75 @@ -78,13 +77,13 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-acmpca": "0.0.0", diff --git a/packages/@aws-cdk/aws-appmesh/rosetta/default.ts-fixture b/packages/@aws-cdk/aws-appmesh/rosetta/default.ts-fixture new file mode 100644 index 0000000000000..09e9b7277edcb --- /dev/null +++ b/packages/@aws-cdk/aws-appmesh/rosetta/default.ts-fixture @@ -0,0 +1,16 @@ +// Fixture with packages imported, but nothing else +import cdk = require('@aws-cdk/core'); +import acmpca = require('@aws-cdk/aws-acmpca'); +import appmesh = require('@aws-cdk/aws-appmesh'); +import certificatemanager = require('@aws-cdk/aws-certificatemanager'); +import cloudmap = require('@aws-cdk/aws-servicediscovery'); +import ec2 = require('@aws-cdk/aws-ec2'); +import iam = require('@aws-cdk/aws-iam'); + +class Fixture extends cdk.Stack { + constructor(scope: cdk.Construct, id: string) { + super(scope, id); + + /// here + } +} diff --git a/packages/@aws-cdk/aws-apprunner/.eslintrc.js b/packages/@aws-cdk/aws-apprunner/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-apprunner/.eslintrc.js +++ b/packages/@aws-cdk/aws-apprunner/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-apprunner/README.md b/packages/@aws-cdk/aws-apprunner/README.md index f6619f99bd149..e9c01f631d4b8 100644 --- a/packages/@aws-cdk/aws-apprunner/README.md +++ b/packages/@aws-cdk/aws-apprunner/README.md @@ -9,6 +9,14 @@ > > [CFN Resources]: https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib +![cdk-constructs: Experimental](https://img.shields.io/badge/cdk--constructs-experimental-important.svg?style=for-the-badge) + +> The APIs of higher level constructs in this module are experimental and under active development. +> They are subject to non-backward compatible changes or removal in any future version. These are +> not subject to the [Semantic Versioning](https://semver.org/) model and breaking changes will be +> announced in the release notes. This means that while you may use them, you may need to update +> your source code when upgrading to a newer version of this package. + --- @@ -18,3 +26,108 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aw ```ts import apprunner = require('@aws-cdk/aws-apprunner'); ``` + +## Introduction + +AWS App Runner is a fully managed service that makes it easy for developers to quickly deploy containerized web applications and APIs, at scale and with no prior infrastructure experience required. Start with your source code or a container image. App Runner automatically builds and deploys the web application and load balances traffic with encryption. App Runner also scales up or down automatically to meet your traffic needs. With App Runner, rather than thinking about servers or scaling, you have more time to focus on your applications. + +## Service + +The `Service` construct allows you to create AWS App Runner services with `ECR Public`, `ECR` or `Github` with the `source` property in the following scenarios: + +- `Source.fromEcr()` - To define the source repository from `ECR`. +- `Source.fromEcrPublic()` - To define the source repository from `ECR Public`. +- `Source.fromGitHub()` - To define the source repository from the `Github repository`. +- `Source.fromAsset()` - To define the source from local asset directory. + + +## ECR Public + +To create a `Service` with ECR Public: + +```ts +new Service(stack, 'Service', { + source: Source.fromEcrPublic({ + imageConfiguration: { port: 8000 }, + imageIdentifier: 'public.ecr.aws/aws-containers/hello-app-runner:latest', + }), +}); +``` + +## ECR + +To create a `Service` from an existing ECR repository: + +```ts +new Service(stack, 'Service', { + source: Source.fromEcr({ + imageConfiguration: { port: 80 }, + repository: ecr.Repository.fromRepositoryName(stack, 'NginxRepository', 'nginx'), + tag: 'latest', + }), +}); +``` + +To create a `Service` from local docker image asset directory built and pushed to Amazon ECR: + +```ts +const imageAsset = new assets.DockerImageAsset(stack, 'ImageAssets', { + directory: path.join(__dirname, './docker.assets'), +}); +new Service(stack, 'Service', { + source: Source.fromAsset({ + imageConfiguration: { port: 8000 }, + asset: imageAsset, + }), +}); +``` + +## GitHub + +To create a `Service` from the GitHub repository, you need to specify an existing App Runner `Connection`. + +See [Managing App Runner connections](https://docs.aws.amazon.com/apprunner/latest/dg/manage-connections.html) for more details. + +```ts +new Service(stack, 'Service', { + source: Source.fromGitHub({ + repositoryUrl: 'https://github.com/aws-containers/hello-app-runner', + branch: 'main', + configurationSource: ConfigurationSourceType.REPOSITORY, + connection: GitHubConnection.fromConnectionArn('CONNECTION_ARN'), + }), +}); +``` + +Use `codeConfigurationValues` to override configuration values with the `API` configuration source type. + +```ts +new Service(stack, 'Service', { + source: Source.fromGitHub({ + repositoryUrl: 'https://github.com/aws-containers/hello-app-runner', + branch: 'main', + configurationSource: ConfigurationSourceType.API, + codeConfigurationValues: { + runtime: Runtime.PYTHON_3, + port: '8000', + startCommand: 'python app.py', + buildCommand: 'yum install -y pycairo && pip install -r requirements.txt', + }, + connection: GitHubConnection.fromConnectionArn('CONNECTION_ARN'), + }), +}); +``` + + +## IAM Roles + +You are allowed to define `instanceRole` and `accessRole` for the `Service`. + +`instanceRole` - The IAM role that provides permissions to your App Runner service. These are permissions that +your code needs when it calls any AWS APIs. + +`accessRole` - The IAM role that grants the App Runner service access to a source repository. It's required for +ECR image repositories (but not for ECR Public repositories). If not defined, a new access role will be generated +when required. + +See [App Runner IAM Roles](https://docs.aws.amazon.com/apprunner/latest/dg/security_iam_service-with-iam.html#security_iam_service-with-iam-roles) for more details. diff --git a/packages/@aws-cdk/aws-apprunner/jest.config.js b/packages/@aws-cdk/aws-apprunner/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-apprunner/jest.config.js +++ b/packages/@aws-cdk/aws-apprunner/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-apprunner/lib/index.ts b/packages/@aws-cdk/aws-apprunner/lib/index.ts index bebaa074b0dd0..1aedf192186b1 100644 --- a/packages/@aws-cdk/aws-apprunner/lib/index.ts +++ b/packages/@aws-cdk/aws-apprunner/lib/index.ts @@ -1,2 +1,3 @@ // AWS::AppRunner CloudFormation Resources: export * from './apprunner.generated'; +export * from './service'; diff --git a/packages/@aws-cdk/aws-apprunner/lib/service.ts b/packages/@aws-cdk/aws-apprunner/lib/service.ts new file mode 100644 index 0000000000000..32e5151da9cbd --- /dev/null +++ b/packages/@aws-cdk/aws-apprunner/lib/service.ts @@ -0,0 +1,831 @@ +import * as ecr from '@aws-cdk/aws-ecr'; +import * as assets from '@aws-cdk/aws-ecr-assets'; +import * as iam from '@aws-cdk/aws-iam'; +import * as cdk from '@aws-cdk/core'; +import { Construct } from 'constructs'; +import { CfnService } from './apprunner.generated'; + +/** + * The image repository types + */ +export enum ImageRepositoryType { + /** + * Amazon ECR Public + */ + ECR_PUBLIC = 'ECR_PUBLIC', + + /** + * Amazon ECR + */ + ECR = 'ECR', +} + +/** + * The number of CPU units reserved for each instance of your App Runner service. + * + */ +export class Cpu { + /** + * 1 vCPU + */ + public static readonly ONE_VCPU = Cpu.of('1 vCPU') + + /** + * 2 vCPU + */ + public static readonly TWO_VCPU = Cpu.of('2 vCPU') + + /** + * Custom CPU unit + * + * @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apprunner-service-instanceconfiguration.html#cfn-apprunner-service-instanceconfiguration-cpu + * + * @param unit custom CPU unit + */ + public static of(unit: string) { return new Cpu(unit); } + + /** + * + * @param unit The unit of CPU. + */ + private constructor(public readonly unit: string) {} +} + + +/** + * The amount of memory reserved for each instance of your App Runner service. + */ +export class Memory { + /** + * 2 GB(for 1 vCPU) + */ + public static readonly TWO_GB = Memory.of('2 GB') + + /** + * 3 GB(for 1 vCPU) + */ + public static readonly THREE_GB = Memory.of('3 GB') + + /** + * 4 GB(for 1 or 2 vCPU) + */ + public static readonly FOUR_GB = Memory.of('4 GB') + + /** + * Custom Memory unit + * + * @param unit custom Memory unit + * + * @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apprunner-service-instanceconfiguration.html#cfn-apprunner-service-instanceconfiguration-memory + */ + public static of(unit: string) { return new Memory(unit); } + + /** + * + * @param unit The unit of memory. + */ + private constructor(public readonly unit: string) { } +} + +/** + * The code runtimes + */ +export class Runtime { + /** + * NodeJS 12 + */ + public static readonly NODEJS_12 = Runtime.of('NODEJS_12') + + /** + * Python 3 + */ + public static readonly PYTHON_3 = Runtime.of('PYTHON_3') + + /** + * Other runtimes + * + * @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apprunner-service-codeconfigurationvalues.html#cfn-apprunner-service-codeconfigurationvalues-runtime for all available runtimes. + * + * @param name runtime name + * + */ + public static of(name: string) { return new Runtime(name); } + + /** + * + * @param name The runtime name. + */ + private constructor(public readonly name: string) { } +} + + +/** + * Result of binding `Source` into a `Service`. + */ +export interface SourceConfig { + /** + * The image repository configuration (mutually exclusive with `codeRepository`). + * + * @default - no image repository. + */ + readonly imageRepository?: ImageRepository; + + /** + * The ECR repository (required to grant the pull privileges for the iam role). + * + * @default - no ECR repository. + */ + readonly ecrRepository?: ecr.IRepository; + + /** + * The code repository configuration (mutually exclusive with `imageRepository`). + * + * @default - no code repository. + */ + readonly codeRepository?: CodeRepositoryProps; +} + +/** + * Properties of the Github repository for `Source.fromGitHub()` + */ +export interface GithubRepositoryProps { + /** + * The code configuration values. Will be ignored if configurationSource is `REPOSITORY`. + * @default - no values will be passed. The `apprunner.yaml` from the github reopsitory will be used instead. + */ + readonly codeConfigurationValues?: CodeConfigurationValues; + + /** + * The source of the App Runner configuration. + */ + readonly configurationSource: ConfigurationSourceType; + + /** + * The location of the repository that contains the source code. + */ + readonly repositoryUrl: string; + + /** + * The branch name that represents a specific version for the repository. + * + * @default main + */ + readonly branch?: string; + + /** + * ARN of the connection to Github. Only required for Github source. + */ + readonly connection: GitHubConnection; +} + + +/** + * Properties of the image repository for `Source.fromEcrPublic()` + */ +export interface EcrPublicProps { + /** + * The image configuration for the image from ECR Public. + * @default - no image configuration will be passed. The default `port` will be 8080. + * @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apprunner-service-imageconfiguration.html#cfn-apprunner-service-imageconfiguration-port + */ + readonly imageConfiguration?: ImageConfiguration; + /** + * The ECR Public image URI. + */ + readonly imageIdentifier: string; +} + +/** + * Properties of the image repository for `Source.fromEcr()` + */ +export interface EcrProps { + /** + * The image configuration for the image from ECR. + * @default - no image configuration will be passed. The default `port` will be 8080. + * @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apprunner-service-imageconfiguration.html#cfn-apprunner-service-imageconfiguration-port + */ + readonly imageConfiguration?: ImageConfiguration; + /** + * Represents the ECR repository. + */ + readonly repository: ecr.IRepository; + /** + * Image tag. + * @default - 'latest' + */ + readonly tag?: string; +} + +/** + * Properties of the image repository for `Source.fromAsset()` + */ +export interface AssetProps { + /** + * The image configuration for the image built from the asset. + * @default - no image configuration will be passed. The default `port` will be 8080. + * @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apprunner-service-imageconfiguration.html#cfn-apprunner-service-imageconfiguration-port + */ + readonly imageConfiguration?: ImageConfiguration; + /** + * Represents the docker image asset. + */ + readonly asset: assets.DockerImageAsset; +} + + +/** + * Represents the App Runner service source. + */ +export abstract class Source { + /** + * Source from the GitHub repository. + */ + public static fromGitHub(props: GithubRepositoryProps): GithubSource { + return new GithubSource(props); + } + /** + * Source from the ECR repository. + */ + public static fromEcr(props: EcrProps): EcrSource { + return new EcrSource(props); + } + /** + * Source from the ECR Public repository. + */ + public static fromEcrPublic(props: EcrPublicProps): EcrPublicSource { + return new EcrPublicSource(props); + } + /** + * Source from local assets. + */ + public static fromAsset(props: AssetProps): AssetSource { + return new AssetSource(props); + } + /** + * Called when the Job is initialized to allow this object to bind. + */ + public abstract bind(scope: Construct): SourceConfig; +} + +/** + * Represents the service source from a Github repository. + */ +export class GithubSource extends Source { + private readonly props: GithubRepositoryProps + constructor(props: GithubRepositoryProps) { + super(); + this.props = props; + } + public bind(_scope: Construct): SourceConfig { + return { + codeRepository: { + codeConfiguration: { + configurationSource: this.props.configurationSource, + configurationValues: this.props.codeConfigurationValues, + }, + repositoryUrl: this.props.repositoryUrl, + sourceCodeVersion: { + type: 'BRANCH', + value: this.props.branch ?? 'main', + }, + connection: this.props.connection, + }, + }; + } +} +/** + * Represents the service source from ECR. + */ +export class EcrSource extends Source { + private readonly props: EcrProps + constructor(props: EcrProps) { + super(); + this.props = props; + } + public bind(_scope: Construct): SourceConfig { + return { + imageRepository: { + imageConfiguration: this.props.imageConfiguration, + imageIdentifier: this.props.repository.repositoryUriForTag(this.props.tag || 'latest'), + imageRepositoryType: ImageRepositoryType.ECR, + }, + ecrRepository: this.props.repository, + }; + } +} + +/** + * Represents the service source from ECR Public. + */ +export class EcrPublicSource extends Source { + private readonly props: EcrPublicProps; + constructor(props: EcrPublicProps) { + super(); + this.props = props; + } + public bind(_scope: Construct): SourceConfig { + return { + imageRepository: { + imageConfiguration: this.props.imageConfiguration, + imageIdentifier: this.props.imageIdentifier, + imageRepositoryType: ImageRepositoryType.ECR_PUBLIC, + }, + }; + } +} + +/** + * Represents the source from local assets. + */ +export class AssetSource extends Source { + private readonly props: AssetProps + constructor(props: AssetProps) { + super(); + this.props = props; + } + public bind(_scope: Construct): SourceConfig { + return { + imageRepository: { + imageConfiguration: this.props.imageConfiguration, + imageIdentifier: this.props.asset.imageUri, + imageRepositoryType: ImageRepositoryType.ECR, + }, + ecrRepository: this.props.asset.repository, + }; + } +} + +/** + * Describes the configuration that AWS App Runner uses to run an App Runner service + * using an image pulled from a source image repository. + * + * @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apprunner-service-imageconfiguration.html + */ +export interface ImageConfiguration { + /** + * The port that your application listens to in the container. + * + * @default 8080 + */ + readonly port?: number; + + /** + * Environment variables that are available to your running App Runner service. + * + * @default - no environment variables + */ + readonly environment?: { [key: string]: string }; + + /** + * An optional command that App Runner runs to start the application in the source image. + * If specified, this command overrides the Docker image’s default start command. + * + * @default - no start command + */ + readonly startCommand?: string; +} + +/** + * Describes a source image repository. + * + * @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apprunner-service-imagerepository.html + */ +export interface ImageRepository { + /** + * The identifier of the image. For `ECR_PUBLIC` imageRepositoryType, the identifier domain should + * always be `public.ecr.aws`. For `ECR`, the pattern should be + * `([0-9]{12}.dkr.ecr.[a-z\-]+-[0-9]{1}.amazonaws.com\/.*)`. + * + * @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apprunner-service-imagerepository.html for more details. + */ + readonly imageIdentifier: string; + + /** + * The type of the image repository. This reflects the repository provider and whether + * the repository is private or public. + */ + readonly imageRepositoryType: ImageRepositoryType; + + /** + * Configuration for running the identified image. + * @default - no image configuration will be passed. The default `port` will be 8080. + * @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apprunner-service-imageconfiguration.html#cfn-apprunner-service-imageconfiguration-port + */ + readonly imageConfiguration?: ImageConfiguration; +} + +/** + * Identifies a version of code that AWS App Runner refers to within a source code repository. + * + * @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apprunner-service-sourcecodeversion.html + */ +export interface SourceCodeVersion { + /** + * The type of version identifier. + */ + readonly type: string; + + /** + * A source code version. + */ + readonly value: string; +} + +/** + * Properties of the CodeRepository. + */ +export interface CodeRepositoryProps { + /** + * Configuration for building and running the service from a source code repository. + */ + readonly codeConfiguration: CodeConfiguration; + + /** + * The location of the repository that contains the source code. + */ + readonly repositoryUrl: string; + + /** + * The version that should be used within the source code repository. + */ + readonly sourceCodeVersion: SourceCodeVersion; + + /** + * The App Runner connection for GitHub. + */ + readonly connection: GitHubConnection; +} + +/** + * Properties of the AppRunner Service + */ +export interface ServiceProps { + /** + * The source of the repository for the service. + */ + readonly source: Source; + + /** + * The number of CPU units reserved for each instance of your App Runner service. + * + * @default Cpu.ONE_VCPU + */ + readonly cpu?: Cpu; + + /** + * The amount of memory reserved for each instance of your App Runner service. + * + * @default Memory.TWO_GB + */ + readonly memory?: Memory; + + /** + * The IAM role that grants the App Runner service access to a source repository. + * It's required for ECR image repositories (but not for ECR Public repositories). + * + * @default - generate a new access role. + */ + readonly accessRole?: iam.IRole; + + /** + * The IAM role that provides permissions to your App Runner service. + * These are permissions that your code needs when it calls any AWS APIs. + * + * @default - no instance role attached. + */ + readonly instanceRole?: iam.IRole; + + /** + * Name of the service. + * + * @default - auto-generated if undefined. + */ + readonly serviceName?: string; +} + +/** + * The source of the App Runner configuration. + */ +export enum ConfigurationSourceType { + /** + * App Runner reads configuration values from `the apprunner.yaml` file in the source code repository + * and ignores `configurationValues`. + */ + REPOSITORY = 'REPOSITORY', + + /** + * App Runner uses configuration values provided in `configurationValues` and ignores the `apprunner.yaml` + * file in the source code repository. + */ + API = 'API', +} + +/** + * Describes the configuration that AWS App Runner uses to build and run an App Runner service + * from a source code repository. + * + * @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apprunner-service-codeconfiguration.html + */ +export interface CodeConfiguration { + /** + * The basic configuration for building and running the App Runner service. + * Use it to quickly launch an App Runner service without providing a apprunner.yaml file in the + * source code repository (or ignoring the file if it exists). + * + * @default - not specified. Use `apprunner.yaml` instead. + */ + readonly configurationValues?: CodeConfigurationValues; + + /** + * The source of the App Runner configuration. + */ + readonly configurationSource: ConfigurationSourceType; +} + +/** + * Describes resources needed to authenticate access to some source repositories. + * The specific resource depends on the repository provider. + */ +interface AuthenticationConfiguration { + /** + * The Amazon Resource Name (ARN) of the IAM role that grants the App Runner service access to a + * source repository. It's required for ECR image repositories (but not for ECR Public repositories). + * + * @defult - no access role. + */ + readonly accessRoleArn?: string; + + /** + * The Amazon Resource Name (ARN) of the App Runner connection that enables the App Runner service + * to connect to a source repository. It's required for GitHub code repositories. + * + * @default - no connection. + */ + readonly connectionArn?: string; +} + +/** + * Describes the basic configuration needed for building and running an AWS App Runner service. + * This type doesn't support the full set of possible configuration options. Fur full configuration capabilities, + * use a `apprunner.yaml` file in the source code repository. + */ +export interface CodeConfigurationValues { + /** + * The command App Runner runs to build your application. + * + * @default - no build command. + */ + readonly buildCommand?: string; + + /** + * The port that your application listens to in the container. + * + * @default 8080 + */ + readonly port?: string; + + /** + * A runtime environment type for building and running an App Runner service. It represents + * a programming language runtime. + */ + readonly runtime: Runtime; + + /** + * The environment variables that are available to your running App Runner service. + * + * @default - no environment variables. + */ + readonly environment?: { [key: string]: string }; + + /** + * The command App Runner runs to start your application. + * + * @default - no start command. + */ + readonly startCommand?: string; +} + +/** + * Represents the App Runner connection that enables the App Runner service to connect + * to a source repository. It's required for GitHub code repositories. + */ +export class GitHubConnection { + /** + * Using existing App Runner connection by specifying the connection ARN. + * @param arn connection ARN + * @returns Connection + */ + public static fromConnectionArn(arn: string): GitHubConnection { + return new GitHubConnection(arn); + } + /** + * The ARN of the Connection for App Runner service to connect to the repository. + */ + public readonly connectionArn: string + constructor(arn: string) { + this.connectionArn = arn; + } +} + +/** + * Attributes for the App Runner Service + */ +export interface ServiceAttributes { + /** + * The name of the service. + */ + readonly serviceName: string; + + /** + * The ARN of the service. + */ + readonly serviceArn: string; + + /** + * The URL of the service. + */ + readonly serviceUrl: string; + + /** + * The status of the service. + */ + readonly serviceStatus: string; +} + +/** + * Represents the App Runner Service. + */ +export interface IService extends cdk.IResource { + /** + * The Name of the service. + */ + readonly serviceName: string; + + /** + * The ARN of the service. + */ + readonly serviceArn: string; +} + +/** + * The App Runner Service. + */ +export class Service extends cdk.Resource { + /** + * Import from service name. + */ + public static fromServiceName(scope: Construct, id: string, serviceName: string): IService { + class Import extends cdk.Resource { + public serviceName = serviceName; + public serviceArn = cdk.Stack.of(this).formatArn({ + resource: 'service', + service: 'apprunner', + resourceName: serviceName, + }) + } + return new Import(scope, id); + } + + /** + * Import from service attributes. + */ + public static fromServiceAttributes(scope: Construct, id: string, attrs: ServiceAttributes): IService { + const serviceArn = attrs.serviceArn; + const serviceName = attrs.serviceName; + const serviceUrl = attrs.serviceUrl; + const serviceStatus = attrs.serviceStatus; + + class Import extends cdk.Resource { + public readonly serviceArn = serviceArn + public readonly serviceName = serviceName + public readonly serviceUrl = serviceUrl + public readonly serviceStatus = serviceStatus + } + + return new Import(scope, id); + } + private readonly props: ServiceProps; + private accessRole?: iam.IRole; + private source: SourceConfig; + + /** + * The ARN of the Service. + * @attribute + */ + readonly serviceArn: string; + + /** + * The ID of the Service. + * @attribute + */ + readonly serviceId: string; + + /** + * The URL of the Service. + * @attribute + */ + readonly serviceUrl: string; + + /** + * The status of the Service. + * @attribute + */ + readonly serviceStatus: string; + + /** + * The name of the service. + * @attribute + */ + readonly serviceName: string; + + public constructor(scope: Construct, id: string, props: ServiceProps) { + super(scope, id); + + const source = props.source.bind(this); + this.source = source; + this.props = props; + + // generate an IAM role only when ImageRepositoryType is ECR and props.role is undefined + this.accessRole = (this.source.imageRepository?.imageRepositoryType == ImageRepositoryType.ECR) ? + this.props.accessRole ? this.props.accessRole : this.generateDefaultRole() : undefined; + + if (source.codeRepository?.codeConfiguration.configurationSource == ConfigurationSourceType.REPOSITORY && + source.codeRepository?.codeConfiguration.configurationValues) { + throw new Error('configurationValues cannot be provided if the ConfigurationSource is Repository'); + } + + const resource = new CfnService(this, 'Resource', { + instanceConfiguration: { + cpu: props.cpu?.unit, + memory: props.memory?.unit, + instanceRoleArn: props.instanceRole?.roleArn, + }, + sourceConfiguration: { + authenticationConfiguration: this.renderAuthenticationConfiguration(), + imageRepository: source.imageRepository ? this.renderImageRepository() : undefined, + codeRepository: source.codeRepository ? this.renderCodeConfiguration() : undefined, + }, + }); + + // grant required privileges for the role + if (source.ecrRepository && this.accessRole) { + source.ecrRepository.grantPull(this.accessRole); + } + + this.serviceArn = resource.attrServiceArn; + this.serviceId = resource.attrServiceId; + this.serviceUrl = resource.attrServiceUrl; + this.serviceStatus = resource.attrStatus; + this.serviceName = resource.ref; + } + private renderAuthenticationConfiguration(): AuthenticationConfiguration { + return { + accessRoleArn: this.accessRole?.roleArn, + connectionArn: this.source.codeRepository?.connection?.connectionArn, + }; + } + private renderCodeConfiguration() { + return { + codeConfiguration: { + configurationSource: this.source.codeRepository!.codeConfiguration.configurationSource, + // codeConfigurationValues will be ignored if configurationSource is REPOSITORY + codeConfigurationValues: this.source.codeRepository!.codeConfiguration.configurationValues ? + this.renderCodeConfigurationValues(this.source.codeRepository!.codeConfiguration.configurationValues) : undefined, + }, + repositoryUrl: this.source.codeRepository!.repositoryUrl, + sourceCodeVersion: this.source.codeRepository!.sourceCodeVersion, + }; + + } + private renderCodeConfigurationValues(props: CodeConfigurationValues): any { + return { + ...props, + runtime: props.runtime.name, + }; + } + private renderImageRepository(): any { + const repo = this.source.imageRepository!; + if (repo.imageConfiguration?.port) { + // convert port from type number to string + return Object.assign(repo, { + imageConfiguration: { + port: repo.imageConfiguration.port.toString(), + }, + }); + } else { + return repo; + } + } + + private generateDefaultRole(): iam.Role { + const accessRole = new iam.Role(this, 'AccessRole', { + assumedBy: new iam.ServicePrincipal('build.apprunner.amazonaws.com'), + }); + accessRole.addToPrincipalPolicy(new iam.PolicyStatement({ + actions: ['ecr:GetAuthorizationToken'], + resources: ['*'], + })); + this.accessRole = accessRole; + return accessRole; + } +} diff --git a/packages/@aws-cdk/aws-apprunner/package.json b/packages/@aws-cdk/aws-apprunner/package.json index ffbecdc004aa6..8b236cbfb01f5 100644 --- a/packages/@aws-cdk/aws-apprunner/package.json +++ b/packages/@aws-cdk/aws-apprunner/package.json @@ -58,7 +58,6 @@ }, "cdk-build": { "cloudformation": "AWS::AppRunner", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -77,23 +76,33 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", + "@aws-cdk/assert-internal": "0.0.0", "@aws-cdk/assertions": "0.0.0", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { - "@aws-cdk/core": "0.0.0" + "@aws-cdk/aws-ecr": "0.0.0", + "@aws-cdk/aws-ecr-assets": "0.0.0", + "@aws-cdk/aws-iam": "0.0.0", + "@aws-cdk/core": "0.0.0", + "constructs": "^3.3.69" }, "peerDependencies": { - "@aws-cdk/core": "0.0.0" + "@aws-cdk/aws-ecr": "0.0.0", + "@aws-cdk/aws-ecr-assets": "0.0.0", + "@aws-cdk/aws-iam": "0.0.0", + "@aws-cdk/core": "0.0.0", + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", - "maturity": "cfn-only", + "maturity": "experimental", "awscdkio": { "announce": false }, diff --git a/packages/@aws-cdk/aws-apprunner/test/docker.assets/Dockerfile b/packages/@aws-cdk/aws-apprunner/test/docker.assets/Dockerfile new file mode 100644 index 0000000000000..878fb18669506 --- /dev/null +++ b/packages/@aws-cdk/aws-apprunner/test/docker.assets/Dockerfile @@ -0,0 +1,2 @@ +# image from https://gallery.ecr.aws/aws-containers/hello-app-runner +FROM public.ecr.aws/aws-containers/hello-app-runner:latest diff --git a/packages/@aws-cdk/aws-apprunner/test/integ.service.expected.json b/packages/@aws-cdk/aws-apprunner/test/integ.service.expected.json new file mode 100644 index 0000000000000..ed37fa7666d4c --- /dev/null +++ b/packages/@aws-cdk/aws-apprunner/test/integ.service.expected.json @@ -0,0 +1,364 @@ +{ + "Resources": { + "Service1EDCC8134": { + "Type": "AWS::AppRunner::Service", + "Properties": { + "SourceConfiguration": { + "AuthenticationConfiguration": {}, + "ImageRepository": { + "ImageConfiguration": { + "Port": "8000" + }, + "ImageIdentifier": "public.ecr.aws/aws-containers/hello-app-runner:latest", + "ImageRepositoryType": "ECR_PUBLIC" + } + }, + "InstanceConfiguration": {} + } + }, + "Service2AccessRole759CA73D": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "build.apprunner.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "Service2AccessRoleDefaultPolicy08C28479": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "ecr:GetAuthorizationToken", + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": [ + "ecr:BatchCheckLayerAvailability", + "ecr:GetDownloadUrlForLayer", + "ecr:BatchGetImage" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":ecr:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":repository/nginx" + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "Service2AccessRoleDefaultPolicy08C28479", + "Roles": [ + { + "Ref": "Service2AccessRole759CA73D" + } + ] + } + }, + "Service2AB4D14D8": { + "Type": "AWS::AppRunner::Service", + "Properties": { + "SourceConfiguration": { + "AuthenticationConfiguration": { + "AccessRoleArn": { + "Fn::GetAtt": [ + "Service2AccessRole759CA73D", + "Arn" + ] + } + }, + "ImageRepository": { + "ImageConfiguration": { + "Port": "80" + }, + "ImageIdentifier": { + "Fn::Join": [ + "", + [ + { + "Ref": "AWS::AccountId" + }, + ".dkr.ecr.", + { + "Ref": "AWS::Region" + }, + ".", + { + "Ref": "AWS::URLSuffix" + }, + "/nginx:latest" + ] + ] + }, + "ImageRepositoryType": "ECR" + } + }, + "InstanceConfiguration": {} + } + }, + "Service3AccessRole3ACBAAA0": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "build.apprunner.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "Service3AccessRoleDefaultPolicy57B9744E": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "ecr:GetAuthorizationToken", + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": [ + "ecr:BatchCheckLayerAvailability", + "ecr:GetDownloadUrlForLayer", + "ecr:BatchGetImage" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":ecr:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":repository/aws-cdk/assets" + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "Service3AccessRoleDefaultPolicy57B9744E", + "Roles": [ + { + "Ref": "Service3AccessRole3ACBAAA0" + } + ] + } + }, + "Service342D067F2": { + "Type": "AWS::AppRunner::Service", + "Properties": { + "SourceConfiguration": { + "AuthenticationConfiguration": { + "AccessRoleArn": { + "Fn::GetAtt": [ + "Service3AccessRole3ACBAAA0", + "Arn" + ] + } + }, + "ImageRepository": { + "ImageConfiguration": { + "Port": "8000" + }, + "ImageIdentifier": { + "Fn::Join": [ + "", + [ + { + "Ref": "AWS::AccountId" + }, + ".dkr.ecr.", + { + "Ref": "AWS::Region" + }, + ".", + { + "Ref": "AWS::URLSuffix" + }, + "/aws-cdk/assets:77284835684772d19c95f4f5a37e7618d5f9efc40db9321d44ac039db457b967" + ] + ] + }, + "ImageRepositoryType": "ECR" + } + }, + "InstanceConfiguration": {} + } + }, + "Service429949929": { + "Type": "AWS::AppRunner::Service", + "Properties": { + "SourceConfiguration": { + "AuthenticationConfiguration": { + "ConnectionArn": "MOCK" + }, + "CodeRepository": { + "CodeConfiguration": { + "ConfigurationSource": "REPOSITORY" + }, + "RepositoryUrl": "https://github.com/aws-containers/hello-app-runner", + "SourceCodeVersion": { + "Type": "BRANCH", + "Value": "main" + } + } + }, + "InstanceConfiguration": {} + } + }, + "Service5AD92B5A5": { + "Type": "AWS::AppRunner::Service", + "Properties": { + "SourceConfiguration": { + "AuthenticationConfiguration": { + "ConnectionArn": "MOCK" + }, + "CodeRepository": { + "CodeConfiguration": { + "CodeConfigurationValues": { + "BuildCommand": "yum install -y pycairo && pip install -r requirements.txt", + "Port": "8000", + "Runtime": "PYTHON_3", + "StartCommand": "python app.py" + }, + "ConfigurationSource": "API" + }, + "RepositoryUrl": "https://github.com/aws-containers/hello-app-runner", + "SourceCodeVersion": { + "Type": "BRANCH", + "Value": "main" + } + } + }, + "InstanceConfiguration": {} + } + } + }, + "Outputs": { + "URL1": { + "Value": { + "Fn::Join": [ + "", + [ + "https://", + { + "Fn::GetAtt": [ + "Service1EDCC8134", + "ServiceUrl" + ] + } + ] + ] + } + }, + "URL2": { + "Value": { + "Fn::Join": [ + "", + [ + "https://", + { + "Fn::GetAtt": [ + "Service2AB4D14D8", + "ServiceUrl" + ] + } + ] + ] + } + }, + "URL3": { + "Value": { + "Fn::Join": [ + "", + [ + "https://", + { + "Fn::GetAtt": [ + "Service342D067F2", + "ServiceUrl" + ] + } + ] + ] + } + }, + "URL4": { + "Value": { + "Fn::Join": [ + "", + [ + "https://", + { + "Fn::GetAtt": [ + "Service429949929", + "ServiceUrl" + ] + } + ] + ] + } + }, + "URL5": { + "Value": { + "Fn::Join": [ + "", + [ + "https://", + { + "Fn::GetAtt": [ + "Service5AD92B5A5", + "ServiceUrl" + ] + } + ] + ] + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-apprunner/test/integ.service.ts b/packages/@aws-cdk/aws-apprunner/test/integ.service.ts new file mode 100644 index 0000000000000..2df2dab9301aa --- /dev/null +++ b/packages/@aws-cdk/aws-apprunner/test/integ.service.ts @@ -0,0 +1,71 @@ +import * as path from 'path'; +import * as ecr from '@aws-cdk/aws-ecr'; +import * as assets from '@aws-cdk/aws-ecr-assets'; +import * as cdk from '@aws-cdk/core'; +import { Service, Source, GitHubConnection, ConfigurationSourceType, Runtime } from '../lib'; + + +const app = new cdk.App(); + +const stack = new cdk.Stack(app, 'integ-apprunner'); + +// Scenario 1: Create the service from ECR public +const service1 = new Service(stack, 'Service1', { + source: Source.fromEcrPublic({ + imageConfiguration: { + port: 8000, + }, + imageIdentifier: 'public.ecr.aws/aws-containers/hello-app-runner:latest', + }), +}); +new cdk.CfnOutput(stack, 'URL1', { value: `https://${service1.serviceUrl}` }); + +// Scenario 2: Create the service from existing ECR repository, make sure you have `nginx` ECR repo in your account. +const service2 = new Service(stack, 'Service2', { + source: Source.fromEcr({ + imageConfiguration: { port: 80 }, + repository: ecr.Repository.fromRepositoryName(stack, 'NginxRepository', 'nginx'), + }), +}); +new cdk.CfnOutput(stack, 'URL2', { value: `https://${service2.serviceUrl}` }); + +// Scenario 3: Create the service from local code assets +const imageAsset = new assets.DockerImageAsset(stack, 'ImageAssets', { + directory: path.join(__dirname, './docker.assets'), +}); +const service3 = new Service(stack, 'Service3', { + source: Source.fromAsset({ + imageConfiguration: { port: 8000 }, + asset: imageAsset, + }), +}); +new cdk.CfnOutput(stack, 'URL3', { value: `https://${service3.serviceUrl}` }); + +// Scenario 4: Create the service from Github. Make sure you specify a valid connection ARN. +const connectionArn = stack.node.tryGetContext('CONNECTION_ARN') || 'MOCK'; +const service4 = new Service(stack, 'Service4', { + source: Source.fromGitHub({ + repositoryUrl: 'https://github.com/aws-containers/hello-app-runner', + branch: 'main', + configurationSource: ConfigurationSourceType.REPOSITORY, + connection: GitHubConnection.fromConnectionArn(connectionArn), + }), +}); +new cdk.CfnOutput(stack, 'URL4', { value: `https://${service4.serviceUrl}` }); + +// Scenario 5: Create the service from Github with configuration values override. +const service5 = new Service(stack, 'Service5', { + source: Source.fromGitHub({ + repositoryUrl: 'https://github.com/aws-containers/hello-app-runner', + branch: 'main', + configurationSource: ConfigurationSourceType.API, + codeConfigurationValues: { + runtime: Runtime.PYTHON_3, + port: '8000', + startCommand: 'python app.py', + buildCommand: 'yum install -y pycairo && pip install -r requirements.txt', + }, + connection: GitHubConnection.fromConnectionArn(connectionArn), + }), +}); +new cdk.CfnOutput(stack, 'URL5', { value: `https://${service5.serviceUrl}` }); diff --git a/packages/@aws-cdk/aws-apprunner/test/service.test.ts b/packages/@aws-cdk/aws-apprunner/test/service.test.ts new file mode 100644 index 0000000000000..a36cc97950119 --- /dev/null +++ b/packages/@aws-cdk/aws-apprunner/test/service.test.ts @@ -0,0 +1,419 @@ +import * as path from 'path'; +import { Template } from '@aws-cdk/assertions'; +import * as ecr from '@aws-cdk/aws-ecr'; +import * as ecr_assets from '@aws-cdk/aws-ecr-assets'; +import * as iam from '@aws-cdk/aws-iam'; +import * as cdk from '@aws-cdk/core'; +import { Service, GitHubConnection, Runtime, Source, Cpu, Memory, ConfigurationSourceType } from '../lib'; + +test('create a service with ECR Public(image repository type: ECR_PUBLIC)', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'demo-stack'); + // WHEN + new Service(stack, 'DemoService', { + source: Source.fromEcrPublic({ + imageConfiguration: { port: 8000 }, + imageIdentifier: 'public.ecr.aws/aws-containers/hello-app-runner:latest', + }), + }); + // we should have the service + Template.fromStack(stack).hasResourceProperties('AWS::AppRunner::Service', { + SourceConfiguration: { + AuthenticationConfiguration: {}, + ImageRepository: { + ImageConfiguration: { + Port: '8000', + }, + ImageIdentifier: 'public.ecr.aws/aws-containers/hello-app-runner:latest', + ImageRepositoryType: 'ECR_PUBLIC', + }, + }, + }); +}); + +test('create a service from existing ECR repository(image repository type: ECR)', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'demo-stack'); + // WHEN + new Service(stack, 'Service', { + source: Source.fromEcr({ + imageConfiguration: { port: 80 }, + repository: ecr.Repository.fromRepositoryName(stack, 'NginxRepository', 'nginx'), + }), + }); + + // THEN + // we should have an IAM role + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Role', { + AssumeRolePolicyDocument: { + Statement: [ + { + Action: 'sts:AssumeRole', + Effect: 'Allow', + Principal: { + Service: 'build.apprunner.amazonaws.com', + }, + }, + ], + Version: '2012-10-17', + }, + }); + // we should have the service + Template.fromStack(stack).hasResourceProperties('AWS::AppRunner::Service', { + SourceConfiguration: { + AuthenticationConfiguration: { + AccessRoleArn: { + 'Fn::GetAtt': [ + 'ServiceAccessRole4763579D', + 'Arn', + ], + }, + }, + ImageRepository: { + ImageConfiguration: { + Port: '80', + }, + ImageIdentifier: { + 'Fn::Join': [ + '', + [ + { + Ref: 'AWS::AccountId', + }, + '.dkr.ecr.', + { + Ref: 'AWS::Region', + }, + '.', + { + Ref: 'AWS::URLSuffix', + }, + '/nginx:latest', + ], + ], + }, + ImageRepositoryType: 'ECR', + }, + }, + }); +}); + +test('create a service with local assets(image repository type: ECR)', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'demo-stack'); + // WHEN + const dockerAsset = new ecr_assets.DockerImageAsset(stack, 'Assets', { + directory: path.join(__dirname, './docker.assets'), + }); + new Service(stack, 'DemoService', { + source: Source.fromAsset({ + imageConfiguration: { port: 8000 }, + asset: dockerAsset, + }), + }); + + // THEN + // we should have an IAM role + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Role', { + AssumeRolePolicyDocument: { + Statement: [ + { + Action: 'sts:AssumeRole', + Effect: 'Allow', + Principal: { + Service: 'build.apprunner.amazonaws.com', + }, + }, + ], + Version: '2012-10-17', + }, + }); + // we should have the service + Template.fromStack(stack).hasResourceProperties('AWS::AppRunner::Service', { + SourceConfiguration: { + AuthenticationConfiguration: { + AccessRoleArn: { + 'Fn::GetAtt': [ + 'DemoServiceAccessRoleE7F08742', + 'Arn', + ], + }, + }, + ImageRepository: { + ImageConfiguration: { + Port: '8000', + }, + ImageIdentifier: { + 'Fn::Join': [ + '', + [ + { + Ref: 'AWS::AccountId', + }, + '.dkr.ecr.', + { + Ref: 'AWS::Region', + }, + '.', + { + Ref: 'AWS::URLSuffix', + }, + '/aws-cdk/assets:e9db95c5eb5c683b56dbb8a1930ab8b028babb58b58058d72fa77071e38e66a4', + ], + ], + }, + ImageRepositoryType: 'ECR', + }, + }, + }); +}); + + +test('create a service with github repository', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'demo-stack'); + // WHEN + new Service(stack, 'DemoService', { + source: Source.fromGitHub({ + repositoryUrl: 'https://github.com/aws-containers/hello-app-runner', + branch: 'main', + configurationSource: ConfigurationSourceType.REPOSITORY, + connection: GitHubConnection.fromConnectionArn('MOCK'), + }), + }); + + // THEN + // we should have the service + Template.fromStack(stack).hasResourceProperties('AWS::AppRunner::Service', { + SourceConfiguration: { + AuthenticationConfiguration: { + ConnectionArn: 'MOCK', + }, + CodeRepository: { + CodeConfiguration: { + ConfigurationSource: 'REPOSITORY', + }, + RepositoryUrl: 'https://github.com/aws-containers/hello-app-runner', + SourceCodeVersion: { + Type: 'BRANCH', + Value: 'main', + }, + }, + }, + }); +}); + +test('create a service with github repository - undefined branch name is allowed', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'demo-stack'); + // WHEN + new Service(stack, 'DemoService', { + source: Source.fromGitHub({ + repositoryUrl: 'https://github.com/aws-containers/hello-app-runner', + configurationSource: ConfigurationSourceType.API, + codeConfigurationValues: { + runtime: Runtime.PYTHON_3, + port: '8000', + }, + connection: GitHubConnection.fromConnectionArn('MOCK'), + }), + }); + + // THEN + // we should have the service with the branch value as 'main' + Template.fromStack(stack).hasResourceProperties('AWS::AppRunner::Service', { + SourceConfiguration: { + AuthenticationConfiguration: { + ConnectionArn: 'MOCK', + }, + CodeRepository: { + CodeConfiguration: { + CodeConfigurationValues: { + Port: '8000', + Runtime: 'PYTHON_3', + }, + ConfigurationSource: 'API', + }, + RepositoryUrl: 'https://github.com/aws-containers/hello-app-runner', + SourceCodeVersion: { + Type: 'BRANCH', + Value: 'main', + }, + }, + }, + }); +}); + + +test('import from service name', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'demo-stack'); + // WHEN + const svc = Service.fromServiceName(stack, 'ImportService', 'ExistingService'); + // THEN + expect(svc).toHaveProperty('serviceName'); + expect(svc).toHaveProperty('serviceArn'); +}); + +test('import from service attributes', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'demo-stack'); + // WHEN + const svc = Service.fromServiceAttributes(stack, 'ImportService', { + serviceName: 'mock', + serviceArn: 'mock', + serviceStatus: 'mock', + serviceUrl: 'mock', + }); + // THEN + expect(svc).toHaveProperty('serviceName'); + expect(svc).toHaveProperty('serviceArn'); + expect(svc).toHaveProperty('serviceStatus'); + expect(svc).toHaveProperty('serviceUrl'); +}); + + +test('undefined imageConfiguration port is allowed', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'demo-stack'); + // WHEN + new Service(stack, 'Service', { + source: Source.fromEcrPublic({ + imageIdentifier: 'public.ecr.aws/aws-containers/hello-app-runner:latest', + }), + }); + + // THEN + // we should have the service + Template.fromStack(stack).hasResourceProperties('AWS::AppRunner::Service', { + SourceConfiguration: { + AuthenticationConfiguration: {}, + ImageRepository: { + ImageIdentifier: 'public.ecr.aws/aws-containers/hello-app-runner:latest', + ImageRepositoryType: 'ECR_PUBLIC', + }, + }, + }); +}); + +test('custom IAM access role and instance role are allowed', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'demo-stack'); + // WHEN + const dockerAsset = new ecr_assets.DockerImageAsset(stack, 'Assets', { + directory: path.join(__dirname, './docker.assets'), + }); + new Service(stack, 'DemoService', { + source: Source.fromAsset({ + asset: dockerAsset, + imageConfiguration: { port: 8000 }, + }), + accessRole: new iam.Role(stack, 'AccessRole', { + assumedBy: new iam.ServicePrincipal('build.apprunner.amazonaws.com'), + managedPolicies: [ + iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSAppRunnerServicePolicyForECRAccess'), + ], + }), + instanceRole: new iam.Role(stack, 'InstanceRole', { + assumedBy: new iam.ServicePrincipal('tasks.apprunner.amazonaws.com'), + }), + }); + // THEN + // we should have the service with the branch value as 'main' + Template.fromStack(stack).hasResourceProperties('AWS::AppRunner::Service', { + SourceConfiguration: { + AuthenticationConfiguration: { + AccessRoleArn: { + 'Fn::GetAtt': [ + 'AccessRoleEC309AE6', + 'Arn', + ], + }, + }, + ImageRepository: { + ImageConfiguration: { + Port: '8000', + }, + ImageIdentifier: { + 'Fn::Join': [ + '', + [ + { + Ref: 'AWS::AccountId', + }, + '.dkr.ecr.', + { + Ref: 'AWS::Region', + }, + '.', + { + Ref: 'AWS::URLSuffix', + }, + '/aws-cdk/assets:e9db95c5eb5c683b56dbb8a1930ab8b028babb58b58058d72fa77071e38e66a4', + ], + ], + }, + ImageRepositoryType: 'ECR', + }, + }, + InstanceConfiguration: { + InstanceRoleArn: { + 'Fn::GetAtt': [ + 'InstanceRole3CCE2F1D', + 'Arn', + ], + }, + }, + }); +}); + +test('cpu and memory properties are allowed', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'demo-stack'); + // WHEN + new Service(stack, 'DemoService', { + source: Source.fromEcrPublic({ + imageIdentifier: 'public.ecr.aws/aws-containers/hello-app-runner:latest', + }), + cpu: Cpu.ONE_VCPU, + memory: Memory.THREE_GB, + }); + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::AppRunner::Service', { + InstanceConfiguration: { + Cpu: '1 vCPU', + Memory: '3 GB', + }, + }); +}); + +test('custom cpu and memory units are allowed', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'demo-stack'); + // WHEN + new Service(stack, 'DemoService', { + source: Source.fromEcrPublic({ + imageIdentifier: 'public.ecr.aws/aws-containers/hello-app-runner:latest', + }), + cpu: Cpu.of('Some vCPU'), + memory: Memory.of('Some GB'), + }); + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::AppRunner::Service', { + InstanceConfiguration: { + Cpu: 'Some vCPU', + Memory: 'Some GB', + }, + }); +}); diff --git a/packages/@aws-cdk/aws-appstream/.eslintrc.js b/packages/@aws-cdk/aws-appstream/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-appstream/.eslintrc.js +++ b/packages/@aws-cdk/aws-appstream/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-appstream/jest.config.js b/packages/@aws-cdk/aws-appstream/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-appstream/jest.config.js +++ b/packages/@aws-cdk/aws-appstream/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-appstream/package.json b/packages/@aws-cdk/aws-appstream/package.json index 3605b0f0e9ccf..90e8f1938488c 100644 --- a/packages/@aws-cdk/aws-appstream/package.json +++ b/packages/@aws-cdk/aws-appstream/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::AppStream", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -74,11 +73,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-appsync/.eslintrc.js b/packages/@aws-cdk/aws-appsync/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-appsync/.eslintrc.js +++ b/packages/@aws-cdk/aws-appsync/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-appsync/README.md b/packages/@aws-cdk/aws-appsync/README.md index 0145beae621f6..a191b51a86483 100644 --- a/packages/@aws-cdk/aws-appsync/README.md +++ b/packages/@aws-cdk/aws-appsync/README.md @@ -28,7 +28,7 @@ APIs that use GraphQL. ### DynamoDB -Example of a GraphQL API with `AWS_IAM` authorization resolving into a DynamoDb +Example of a GraphQL API with `AWS_IAM` [authorization](#authorization) resolving into a DynamoDb backend data source. GraphQL schema file `schema.graphql`: @@ -345,6 +345,40 @@ If you don't specify `graphqlArn` in `fromXxxAttributes`, CDK will autogenerate the expected `arn` for the imported api, given the `apiId`. For creating data sources and resolvers, an `apiId` is sufficient. +## Authorization + +There are multiple authorization types available for GraphQL API to cater to different +access use cases. They are: + +- API Keys (`AuthorizationType.API_KEY`) +- Amazon Cognito User Pools (`AuthorizationType.USER_POOL`) +- OpenID Connect (`AuthorizationType.OPENID_CONNECT`) +- AWS Identity and Access Management (`AuthorizationType.AWS_IAM`) +- AWS Lambda (`AuthorizationType.AWS_LAMBDA`) + +These types can be used simultaneously in a single API, allowing different types of clients to +access data. When you specify an authorization type, you can also specify the corresponding +authorization mode to finish defining your authorization. For example, this is a GraphQL API +with AWS Lambda Authorization. + +```ts +authFunction = new lambda.Function(stack, 'auth-function', {}); + +new appsync.GraphqlApi(stack, 'api', { + name: 'api', + schema: appsync.Schema.fromAsset(path.join(__dirname, 'appsync.test.graphql')), + authorizationConfig: { + defaultAuthorization: { + authorizationType: appsync.AuthorizationType.LAMBDA, + lambdaAuthorizerConfig: { + handler: authFunction, + // can also specify `resultsCacheTtl` and `validationRegex`. + }, + }, + }, +}); +``` + ## Permissions When using `AWS_IAM` as the authorization type for GraphQL API, an IAM Role diff --git a/packages/@aws-cdk/aws-appsync/jest.config.js b/packages/@aws-cdk/aws-appsync/jest.config.js index ff8ca0285ed49..219d718579a52 100644 --- a/packages/@aws-cdk/aws-appsync/jest.config.js +++ b/packages/@aws-cdk/aws-appsync/jest.config.js @@ -1,4 +1,4 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = { ...baseConfig, coverageThreshold: { diff --git a/packages/@aws-cdk/aws-appsync/lib/graphqlapi.ts b/packages/@aws-cdk/aws-appsync/lib/graphqlapi.ts index 8b0252bed9eb4..93c9078e32358 100644 --- a/packages/@aws-cdk/aws-appsync/lib/graphqlapi.ts +++ b/packages/@aws-cdk/aws-appsync/lib/graphqlapi.ts @@ -1,5 +1,6 @@ import { IUserPool } from '@aws-cdk/aws-cognito'; import { ManagedPolicy, Role, IRole, ServicePrincipal, Grant, IGrantable } from '@aws-cdk/aws-iam'; +import { IFunction } from '@aws-cdk/aws-lambda'; import { CfnResource, Duration, Expiration, IResolvable, Stack } from '@aws-cdk/core'; import { Construct } from 'constructs'; import { CfnApiKey, CfnGraphQLApi, CfnGraphQLSchema } from './appsync.generated'; @@ -29,6 +30,10 @@ export enum AuthorizationType { * OpenID Connect authorization type */ OIDC = 'OPENID_CONNECT', + /** + * Lambda authorization type + */ + LAMBDA = 'AWS_LAMBDA', } /** @@ -58,6 +63,11 @@ export interface AuthorizationMode { * @default - none */ readonly openIdConnectConfig?: OpenIdConnectConfig; + /** + * If authorizationType is `AuthorizationType.LAMBDA`, this option is required. + * @default - none + */ + readonly lambdaAuthorizerConfig?: LambdaAuthorizerConfig; } /** @@ -150,6 +160,38 @@ export interface OpenIdConnectConfig { readonly oidcProvider: string; } +/** + * Configuration for Lambda authorization in AppSync. Note that you can only have a single AWS Lambda function configured to authorize your API. + */ +export interface LambdaAuthorizerConfig { + /** + * The authorizer lambda function. + * Note: This Lambda function must have the following resource-based policy assigned to it. + * When configuring Lambda authorizers in the console, this is done for you. + * To do so with the AWS CLI, run the following: + * + * `aws lambda add-permission --function-name "arn:aws:lambda:us-east-2:111122223333:function:my-function" --statement-id "appsync" --principal appsync.amazonaws.com --action lambda:InvokeFunction` + * + * @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appsync-graphqlapi-lambdaauthorizerconfig.html + */ + readonly handler: IFunction; + + /** + * How long the results are cached. + * Disable caching by setting this to 0. + * + * @default Duration.minutes(5) + */ + readonly resultsCacheTtl?: Duration; + + /** + * A regular expression for validation of tokens before the Lambda function is called. + * + * @default - no regex filter will be applied. + */ + readonly validationRegex?: string; +} + /** * Configuration of the API authorization modes. */ @@ -418,6 +460,7 @@ export class GraphqlApi extends GraphqlApiBase { logConfig: this.setupLogConfig(props.logConfig), openIdConnectConfig: this.setupOpenIdConnectConfig(defaultMode.openIdConnectConfig), userPoolConfig: this.setupUserPoolConfig(defaultMode.userPoolConfig), + lambdaAuthorizerConfig: this.setupLambdaAuthorizerConfig(defaultMode.lambdaAuthorizerConfig), additionalAuthenticationProviders: this.setupAdditionalAuthorizationModes(additionalModes), xrayEnabled: props.xrayEnabled, }); @@ -490,6 +533,9 @@ export class GraphqlApi extends GraphqlApiBase { } private validateAuthorizationProps(modes: AuthorizationMode[]) { + if (modes.filter((mode) => mode.authorizationType === AuthorizationType.LAMBDA).length > 1) { + throw new Error('You can only have a single AWS Lambda function configured to authorize your API.'); + } modes.map((mode) => { if (mode.authorizationType === AuthorizationType.OIDC && !mode.openIdConnectConfig) { throw new Error('Missing OIDC Configuration'); @@ -497,6 +543,9 @@ export class GraphqlApi extends GraphqlApiBase { if (mode.authorizationType === AuthorizationType.USER_POOL && !mode.userPoolConfig) { throw new Error('Missing User Pool Configuration'); } + if (mode.authorizationType === AuthorizationType.LAMBDA && !mode.lambdaAuthorizerConfig) { + throw new Error('Missing Lambda Configuration'); + } }); if (modes.filter((mode) => mode.authorizationType === AuthorizationType.API_KEY).length > 1) { throw new Error('You can\'t duplicate API_KEY configuration. See https://docs.aws.amazon.com/appsync/latest/devguide/security.html'); @@ -551,6 +600,15 @@ export class GraphqlApi extends GraphqlApiBase { }; } + private setupLambdaAuthorizerConfig(config?: LambdaAuthorizerConfig) { + if (!config) return undefined; + return { + authorizerResultTtlInSeconds: config.resultsCacheTtl?.toSeconds(), + authorizerUri: config.handler.functionArn, + identityValidationExpression: config.validationRegex, + }; + } + private setupAdditionalAuthorizationModes(modes?: AuthorizationMode[]) { if (!modes || modes.length === 0) return undefined; return modes.reduce((acc, mode) => [ @@ -558,6 +616,7 @@ export class GraphqlApi extends GraphqlApiBase { authenticationType: mode.authorizationType, userPoolConfig: this.setupUserPoolConfig(mode.userPoolConfig), openIdConnectConfig: this.setupOpenIdConnectConfig(mode.openIdConnectConfig), + lambdaAuthorizerConfig: this.setupLambdaAuthorizerConfig(mode.lambdaAuthorizerConfig), }, ], []); } diff --git a/packages/@aws-cdk/aws-appsync/package.json b/packages/@aws-cdk/aws-appsync/package.json index bc2dc7796af93..a471666ffe98d 100644 --- a/packages/@aws-cdk/aws-appsync/package.json +++ b/packages/@aws-cdk/aws-appsync/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::AppSync", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,23 +74,23 @@ "devDependencies": { "@aws-cdk/assertions": "0.0.0", "@aws-cdk/aws-stepfunctions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-cognito": "0.0.0", "@aws-cdk/aws-dynamodb": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/aws-elasticsearch": "0.0.0", - "@aws-cdk/aws-rds": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", - "@aws-cdk/aws-secretsmanager": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", + "@aws-cdk/aws-rds": "0.0.0", "@aws-cdk/aws-s3-assets": "0.0.0", + "@aws-cdk/aws-secretsmanager": "0.0.0", "@aws-cdk/core": "0.0.0", "constructs": "^3.3.69" }, @@ -103,10 +102,10 @@ "@aws-cdk/aws-elasticsearch": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", - "@aws-cdk/aws-s3-assets": "0.0.0", - "@aws-cdk/core": "0.0.0", "@aws-cdk/aws-rds": "0.0.0", + "@aws-cdk/aws-s3-assets": "0.0.0", "@aws-cdk/aws-secretsmanager": "0.0.0", + "@aws-cdk/core": "0.0.0", "constructs": "^3.3.69" }, "engines": { diff --git a/packages/@aws-cdk/aws-appsync/test/appsync-auth.test.ts b/packages/@aws-cdk/aws-appsync/test/appsync-auth.test.ts index a137e54b0423f..67f12ae4bc13a 100644 --- a/packages/@aws-cdk/aws-appsync/test/appsync-auth.test.ts +++ b/packages/@aws-cdk/aws-appsync/test/appsync-auth.test.ts @@ -1,6 +1,7 @@ import * as path from 'path'; import { Template } from '@aws-cdk/assertions'; import * as cognito from '@aws-cdk/aws-cognito'; +import * as lambda from '@aws-cdk/aws-lambda'; import * as cdk from '@aws-cdk/core'; import * as appsync from '../lib'; @@ -630,3 +631,206 @@ describe('AppSync OIDC Authorization', () => { }); }); }); + +describe('AppSync Lambda Authorization', () => { + let fn: lambda.Function; + beforeEach(() => { + fn = new lambda.Function(stack, 'auth-function', { + runtime: lambda.Runtime.NODEJS_12_X, + handler: 'index.handler', + code: lambda.Code.fromInline('/* lambda authentication code here.*/'), + }); + }); + + test('Lambda authorization configurable in default authorization has default configuration', () => { + // WHEN + new appsync.GraphqlApi(stack, 'api', { + name: 'api', + schema: appsync.Schema.fromAsset(path.join(__dirname, 'appsync.test.graphql')), + authorizationConfig: { + defaultAuthorization: { + authorizationType: appsync.AuthorizationType.LAMBDA, + lambdaAuthorizerConfig: { + handler: fn, + }, + }, + }, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::AppSync::GraphQLApi', { + AuthenticationType: 'AWS_LAMBDA', + LambdaAuthorizerConfig: { + AuthorizerUri: { + 'Fn::GetAtt': [ + 'authfunction96361832', + 'Arn', + ], + }, + }, + }); + }); + + test('Lambda authorization configurable in default authorization', () => { + // WHEN + new appsync.GraphqlApi(stack, 'api', { + name: 'api', + schema: appsync.Schema.fromAsset(path.join(__dirname, 'appsync.test.graphql')), + authorizationConfig: { + defaultAuthorization: { + authorizationType: appsync.AuthorizationType.LAMBDA, + lambdaAuthorizerConfig: { + handler: fn, + resultsCacheTtl: cdk.Duration.seconds(300), + validationRegex: 'custom-.*', + }, + }, + }, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::AppSync::GraphQLApi', { + AuthenticationType: 'AWS_LAMBDA', + LambdaAuthorizerConfig: { + AuthorizerUri: { + 'Fn::GetAtt': [ + 'authfunction96361832', + 'Arn', + ], + }, + AuthorizerResultTtlInSeconds: 300, + IdentityValidationExpression: 'custom-.*', + }, + }); + }); + + test('Lambda authorization configurable in additional authorization has default configuration', () => { + // WHEN + new appsync.GraphqlApi(stack, 'api', { + name: 'api', + schema: appsync.Schema.fromAsset(path.join(__dirname, 'appsync.test.graphql')), + authorizationConfig: { + additionalAuthorizationModes: [{ + authorizationType: appsync.AuthorizationType.LAMBDA, + lambdaAuthorizerConfig: { + handler: fn, + }, + }], + }, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::AppSync::GraphQLApi', { + AdditionalAuthenticationProviders: [{ + AuthenticationType: 'AWS_LAMBDA', + LambdaAuthorizerConfig: { + AuthorizerUri: { + 'Fn::GetAtt': [ + 'authfunction96361832', + 'Arn', + ], + }, + }, + }], + }); + }); + + test('Lambda authorization configurable in additional authorization', () => { + // WHEN + new appsync.GraphqlApi(stack, 'api', { + name: 'api', + schema: appsync.Schema.fromAsset(path.join(__dirname, 'appsync.test.graphql')), + authorizationConfig: { + additionalAuthorizationModes: [{ + authorizationType: appsync.AuthorizationType.LAMBDA, + lambdaAuthorizerConfig: { + handler: fn, + resultsCacheTtl: cdk.Duration.seconds(300), + validationRegex: 'custom-.*', + }, + }], + }, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::AppSync::GraphQLApi', { + AdditionalAuthenticationProviders: [{ + AuthenticationType: 'AWS_LAMBDA', + LambdaAuthorizerConfig: { + AuthorizerUri: { + 'Fn::GetAtt': [ + 'authfunction96361832', + 'Arn', + ], + }, + AuthorizerResultTtlInSeconds: 300, + IdentityValidationExpression: 'custom-.*', + }, + }], + }); + }); + + test('Lambda authorization throws with multiple lambda authorization', () => { + expect(() => new appsync.GraphqlApi(stack, 'api', { + name: 'api', + schema: appsync.Schema.fromAsset(path.join(__dirname, 'appsync.test.graphql')), + authorizationConfig: { + defaultAuthorization: { + authorizationType: appsync.AuthorizationType.LAMBDA, + lambdaAuthorizerConfig: { + handler: fn, + }, + }, + additionalAuthorizationModes: [ + { + authorizationType: appsync.AuthorizationType.LAMBDA, + lambdaAuthorizerConfig: { + handler: fn, + resultsCacheTtl: cdk.Duration.seconds(300), + validationRegex: 'custom-.*', + }, + }, + ], + }, + })).toThrow('You can only have a single AWS Lambda function configured to authorize your API.'); + + expect(() => new appsync.GraphqlApi(stack, 'api2', { + name: 'api', + schema: appsync.Schema.fromAsset(path.join(__dirname, 'appsync.test.graphql')), + authorizationConfig: { + defaultAuthorization: { authorizationType: appsync.AuthorizationType.IAM }, + additionalAuthorizationModes: [ + { + authorizationType: appsync.AuthorizationType.LAMBDA, + lambdaAuthorizerConfig: { + handler: fn, + resultsCacheTtl: cdk.Duration.seconds(300), + validationRegex: 'custom-.*', + }, + }, + { + authorizationType: appsync.AuthorizationType.LAMBDA, + lambdaAuthorizerConfig: { + handler: fn, + resultsCacheTtl: cdk.Duration.seconds(300), + validationRegex: 'custom-.*', + }, + }, + ], + }, + })).toThrow('You can only have a single AWS Lambda function configured to authorize your API.'); + }); + + test('throws if authorization type and mode do not match', () => { + expect(() => new appsync.GraphqlApi(stack, 'api', { + name: 'api', + schema: appsync.Schema.fromAsset(path.join(__dirname, 'appsync.test.graphql')), + authorizationConfig: { + defaultAuthorization: { + authorizationType: appsync.AuthorizationType.LAMBDA, + openIdConnectConfig: { oidcProvider: 'test' }, + }, + }, + })).toThrow('Missing Lambda Configuration'); + }); +}); \ No newline at end of file diff --git a/tools/individual-pkg-gen/.eslintrc.js b/packages/@aws-cdk/aws-aps/.eslintrc.js similarity index 56% rename from tools/individual-pkg-gen/.eslintrc.js rename to packages/@aws-cdk/aws-aps/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/tools/individual-pkg-gen/.eslintrc.js +++ b/packages/@aws-cdk/aws-aps/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-aps/.gitignore b/packages/@aws-cdk/aws-aps/.gitignore new file mode 100644 index 0000000000000..62ebc95d75ce6 --- /dev/null +++ b/packages/@aws-cdk/aws-aps/.gitignore @@ -0,0 +1,19 @@ +*.js +*.js.map +*.d.ts +tsconfig.json +node_modules +*.generated.ts +dist +.jsii + +.LAST_BUILD +.nyc_output +coverage +.nycrc +.LAST_PACKAGE +*.snk +nyc.config.js +!.eslintrc.js +!jest.config.js +junit.xml diff --git a/packages/@aws-cdk/aws-aps/.npmignore b/packages/@aws-cdk/aws-aps/.npmignore new file mode 100644 index 0000000000000..f931fede67c44 --- /dev/null +++ b/packages/@aws-cdk/aws-aps/.npmignore @@ -0,0 +1,29 @@ +# Don't include original .ts files when doing `npm pack` +*.ts +!*.d.ts +coverage +.nyc_output +*.tgz + +dist +.LAST_PACKAGE +.LAST_BUILD +!*.js + +# Include .jsii +!.jsii + +*.snk + +*.tsbuildinfo + +tsconfig.json + +.eslintrc.js +jest.config.js + +# exclude cdk artifacts +**/cdk.out +junit.xml +test/ +!*.lit.ts diff --git a/tools/cdk-build-tools/LICENSE b/packages/@aws-cdk/aws-aps/LICENSE similarity index 100% rename from tools/cdk-build-tools/LICENSE rename to packages/@aws-cdk/aws-aps/LICENSE diff --git a/tools/cdk-build-tools/NOTICE b/packages/@aws-cdk/aws-aps/NOTICE similarity index 100% rename from tools/cdk-build-tools/NOTICE rename to packages/@aws-cdk/aws-aps/NOTICE diff --git a/packages/@aws-cdk/aws-aps/README.md b/packages/@aws-cdk/aws-aps/README.md new file mode 100644 index 0000000000000..013603efa8143 --- /dev/null +++ b/packages/@aws-cdk/aws-aps/README.md @@ -0,0 +1,20 @@ +# AWS::APS Construct Library + + +--- + +![cfn-resources: Stable](https://img.shields.io/badge/cfn--resources-stable-success.svg?style=for-the-badge) + +> All classes with the `Cfn` prefix in this module ([CFN Resources]) are always stable and safe to use. +> +> [CFN Resources]: https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib + +--- + + + +This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. + +```ts +import aps = require('@aws-cdk/aws-aps'); +``` diff --git a/packages/@aws-cdk/aws-aps/jest.config.js b/packages/@aws-cdk/aws-aps/jest.config.js new file mode 100644 index 0000000000000..3a2fd93a1228a --- /dev/null +++ b/packages/@aws-cdk/aws-aps/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-aps/lib/index.ts b/packages/@aws-cdk/aws-aps/lib/index.ts new file mode 100644 index 0000000000000..76aef1a74fda7 --- /dev/null +++ b/packages/@aws-cdk/aws-aps/lib/index.ts @@ -0,0 +1,2 @@ +// AWS::APS CloudFormation Resources: +export * from './aps.generated'; diff --git a/packages/@aws-cdk/aws-aps/package.json b/packages/@aws-cdk/aws-aps/package.json new file mode 100644 index 0000000000000..2e69665a8fb54 --- /dev/null +++ b/packages/@aws-cdk/aws-aps/package.json @@ -0,0 +1,102 @@ +{ + "name": "@aws-cdk/aws-aps", + "version": "0.0.0", + "description": "The CDK Construct Library for AWS::APS", + "main": "lib/index.js", + "types": "lib/index.d.ts", + "jsii": { + "outdir": "dist", + "projectReferences": true, + "targets": { + "dotnet": { + "namespace": "Amazon.CDK.AWS.APS", + "packageId": "Amazon.CDK.AWS.APS", + "signAssembly": true, + "assemblyOriginatorKeyFile": "../../key.snk", + "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png" + }, + "java": { + "package": "software.amazon.awscdk.services.aps", + "maven": { + "groupId": "software.amazon.awscdk", + "artifactId": "aps" + } + }, + "python": { + "classifiers": [ + "Framework :: AWS CDK", + "Framework :: AWS CDK :: 1" + ], + "distName": "aws-cdk.aws-aps", + "module": "aws_cdk.aws_aps" + } + } + }, + "repository": { + "type": "git", + "url": "https://github.com/aws/aws-cdk.git", + "directory": "packages/@aws-cdk/aws-aps" + }, + "homepage": "https://github.com/aws/aws-cdk", + "scripts": { + "build": "cdk-build", + "watch": "cdk-watch", + "lint": "cdk-lint", + "test": "cdk-test", + "integ": "cdk-integ", + "pkglint": "pkglint -f", + "package": "cdk-package", + "awslint": "cdk-awslint", + "cfn2ts": "cfn2ts", + "build+test": "yarn build && yarn test", + "build+test+package": "yarn build+test && yarn package", + "compat": "cdk-compat", + "gen": "cfn2ts", + "rosetta:extract": "yarn --silent jsii-rosetta extract", + "build+extract": "yarn build && yarn rosetta:extract", + "build+test+extract": "yarn build+test && yarn rosetta:extract" + }, + "cdk-build": { + "cloudformation": "AWS::APS", + "env": { + "AWSLINT_BASE_CONSTRUCT": "true" + } + }, + "keywords": [ + "aws", + "cdk", + "constructs", + "AWS::APS", + "aws-aps" + ], + "author": { + "name": "Amazon Web Services", + "url": "https://aws.amazon.com", + "organization": true + }, + "license": "Apache-2.0", + "devDependencies": { + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" + }, + "dependencies": { + "@aws-cdk/core": "0.0.0" + }, + "peerDependencies": { + "@aws-cdk/core": "0.0.0" + }, + "engines": { + "node": ">= 10.13.0 <13 || >=13.7.0" + }, + "stability": "experimental", + "maturity": "cfn-only", + "awscdkio": { + "announce": false + }, + "publishConfig": { + "tag": "latest" + } +} diff --git a/packages/@aws-cdk/aws-apprunner/test/apprunner.test.ts b/packages/@aws-cdk/aws-aps/test/aps.test.ts similarity index 100% rename from packages/@aws-cdk/aws-apprunner/test/apprunner.test.ts rename to packages/@aws-cdk/aws-aps/test/aps.test.ts diff --git a/packages/@aws-cdk/aws-athena/.eslintrc.js b/packages/@aws-cdk/aws-athena/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-athena/.eslintrc.js +++ b/packages/@aws-cdk/aws-athena/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-athena/jest.config.js b/packages/@aws-cdk/aws-athena/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-athena/jest.config.js +++ b/packages/@aws-cdk/aws-athena/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-athena/package.json b/packages/@aws-cdk/aws-athena/package.json index 57bc9bfd3a677..468ce471247d7 100644 --- a/packages/@aws-cdk/aws-athena/package.json +++ b/packages/@aws-cdk/aws-athena/package.json @@ -32,7 +32,6 @@ }, "cdk-build": { "cloudformation": "AWS::Athena", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,13 +72,13 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "jest": "^26.6.3", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-auditmanager/.eslintrc.js b/packages/@aws-cdk/aws-auditmanager/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-auditmanager/.eslintrc.js +++ b/packages/@aws-cdk/aws-auditmanager/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-auditmanager/jest.config.js b/packages/@aws-cdk/aws-auditmanager/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-auditmanager/jest.config.js +++ b/packages/@aws-cdk/aws-auditmanager/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-auditmanager/package.json b/packages/@aws-cdk/aws-auditmanager/package.json index f667b4c12c375..a787fca8f6ec3 100644 --- a/packages/@aws-cdk/aws-auditmanager/package.json +++ b/packages/@aws-cdk/aws-auditmanager/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::AuditManager", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-autoscaling-common/.eslintrc.js b/packages/@aws-cdk/aws-autoscaling-common/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-autoscaling-common/.eslintrc.js +++ b/packages/@aws-cdk/aws-autoscaling-common/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-autoscaling-common/jest.config.js b/packages/@aws-cdk/aws-autoscaling-common/jest.config.js index cd664e1d069e5..34818e1593f6b 100644 --- a/packages/@aws-cdk/aws-autoscaling-common/jest.config.js +++ b/packages/@aws-cdk/aws-autoscaling-common/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +const baseConfig = require('../../../tools/@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-autoscaling-common/package.json b/packages/@aws-cdk/aws-autoscaling-common/package.json index bd150e90f21ee..2253a1669614f 100644 --- a/packages/@aws-cdk/aws-autoscaling-common/package.json +++ b/packages/@aws-cdk/aws-autoscaling-common/package.json @@ -64,13 +64,13 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "fast-check": "^2.17.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "fast-check": "^2.18.0", + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-iam": "0.0.0", @@ -115,8 +115,7 @@ "cdk-build": { "env": { "AWSLINT_BASE_CONSTRUCT": true - }, - "jest": true + } }, "publishConfig": { "tag": "latest" diff --git a/packages/@aws-cdk/aws-autoscaling-hooktargets/.eslintrc.js b/packages/@aws-cdk/aws-autoscaling-hooktargets/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-autoscaling-hooktargets/.eslintrc.js +++ b/packages/@aws-cdk/aws-autoscaling-hooktargets/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-autoscaling-hooktargets/jest.config.js b/packages/@aws-cdk/aws-autoscaling-hooktargets/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-autoscaling-hooktargets/jest.config.js +++ b/packages/@aws-cdk/aws-autoscaling-hooktargets/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-autoscaling-hooktargets/package.json b/packages/@aws-cdk/aws-autoscaling-hooktargets/package.json index 08a1b4120aee1..ac5aeabab06ca 100644 --- a/packages/@aws-cdk/aws-autoscaling-hooktargets/package.json +++ b/packages/@aws-cdk/aws-autoscaling-hooktargets/package.json @@ -64,14 +64,14 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", + "@aws-cdk/assert-internal": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24", + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-autoscaling": "0.0.0", @@ -105,7 +105,6 @@ }, "maturity": "stable", "cdk-build": { - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } diff --git a/packages/@aws-cdk/aws-autoscaling/.eslintrc.js b/packages/@aws-cdk/aws-autoscaling/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-autoscaling/.eslintrc.js +++ b/packages/@aws-cdk/aws-autoscaling/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-autoscaling/jest.config.js b/packages/@aws-cdk/aws-autoscaling/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-autoscaling/jest.config.js +++ b/packages/@aws-cdk/aws-autoscaling/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-autoscaling/package.json b/packages/@aws-cdk/aws-autoscaling/package.json index 67fb9d4e1dd7e..0a04e34718096 100644 --- a/packages/@aws-cdk/aws-autoscaling/package.json +++ b/packages/@aws-cdk/aws-autoscaling/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::AutoScaling", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,15 +72,15 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "@aws-cdk/cx-api": "0.0.0", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/cloud-assembly-schema": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "@aws-cdk/cx-api": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24", + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-autoscaling-common": "0.0.0", diff --git a/packages/@aws-cdk/aws-autoscalingplans/.eslintrc.js b/packages/@aws-cdk/aws-autoscalingplans/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-autoscalingplans/.eslintrc.js +++ b/packages/@aws-cdk/aws-autoscalingplans/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-autoscalingplans/jest.config.js b/packages/@aws-cdk/aws-autoscalingplans/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-autoscalingplans/jest.config.js +++ b/packages/@aws-cdk/aws-autoscalingplans/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-autoscalingplans/package.json b/packages/@aws-cdk/aws-autoscalingplans/package.json index 653b5457f3c97..cd0c974c03acf 100644 --- a/packages/@aws-cdk/aws-autoscalingplans/package.json +++ b/packages/@aws-cdk/aws-autoscalingplans/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::AutoScalingPlans", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,11 +72,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-backup/.eslintrc.js b/packages/@aws-cdk/aws-backup/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-backup/.eslintrc.js +++ b/packages/@aws-cdk/aws-backup/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-backup/README.md b/packages/@aws-cdk/aws-backup/README.md index 22b2398ba08ea..b59d5307f9d67 100644 --- a/packages/@aws-cdk/aws-backup/README.md +++ b/packages/@aws-cdk/aws-backup/README.md @@ -132,13 +132,18 @@ const vault = new backup.BackupVault(this, 'Vault', { }) ``` -Use the `blockRecoveryPointDeletion` property to add statements to the vault access policy that -prevents recovery point deletions in your vault: +Alternativately statements can be added to the vault policy using `addToAccessPolicy()`. + +Use the `blockRecoveryPointDeletion` property or the `blockRecoveryPointDeletion()` method to add +a statement to the vault access policy that prevents recovery point deletions in your vault: ```ts new backup.BackupVault(this, 'Vault', { blockRecoveryPointDeletion: true, }); + +const plan = backup.BackupPlan.dailyMonthly1YearRetention(this, 'Plan'); +plan.backupVault.blockRecoveryPointDeletion(); ``` By default access is not restricted. diff --git a/packages/@aws-cdk/aws-backup/jest.config.js b/packages/@aws-cdk/aws-backup/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-backup/jest.config.js +++ b/packages/@aws-cdk/aws-backup/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-backup/lib/vault.ts b/packages/@aws-cdk/aws-backup/lib/vault.ts index ac2c67a19dff3..5f4f0d05c6001 100644 --- a/packages/@aws-cdk/aws-backup/lib/vault.ts +++ b/packages/@aws-cdk/aws-backup/lib/vault.ts @@ -1,7 +1,7 @@ import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; import * as sns from '@aws-cdk/aws-sns'; -import { IResource, Names, RemovalPolicy, Resource, Stack } from '@aws-cdk/core'; +import { IResource, Lazy, Names, RemovalPolicy, Resource, Stack } from '@aws-cdk/core'; import { Construct } from 'constructs'; import { CfnBackupVault } from './backup.generated'; @@ -198,6 +198,8 @@ export class BackupVault extends BackupVaultBase { public readonly backupVaultName: string; public readonly backupVaultArn: string; + private readonly accessPolicy: iam.PolicyDocument; + constructor(scope: Construct, id: string, props: BackupVaultProps = {}) { super(scope, id); @@ -214,23 +216,14 @@ export class BackupVault extends BackupVaultBase { props.notificationTopic.grantPublish(new iam.ServicePrincipal('backup.amazonaws.com')); } - const accessPolicy = props.accessPolicy ?? new iam.PolicyDocument(); + this.accessPolicy = props.accessPolicy ?? new iam.PolicyDocument(); if (props.blockRecoveryPointDeletion) { - accessPolicy.addStatements(new iam.PolicyStatement({ - effect: iam.Effect.DENY, - actions: [ - 'backup:DeleteRecoveryPoint', - 'backup:UpdateRecoveryPointLifecycle', - ], - principals: [new iam.AnyPrincipal()], - resources: ['*'], - }), - ); + this.blockRecoveryPointDeletion(); } const vault = new CfnBackupVault(this, 'Resource', { backupVaultName: props.backupVaultName || this.uniqueVaultName(), - accessPolicy: accessPolicy.toJSON(), + accessPolicy: Lazy.any({ produce: () => this.accessPolicy.toJSON() }), encryptionKeyArn: props.encryptionKey && props.encryptionKey.keyArn, notifications, }); @@ -240,6 +233,29 @@ export class BackupVault extends BackupVaultBase { this.backupVaultArn = vault.attrBackupVaultArn; } + /** + * Adds a statement to the vault access policy + */ + public addToAccessPolicy(statement: iam.PolicyStatement) { + this.accessPolicy.addStatements(statement); + } + + /** + * Adds a statement to the vault access policy that prevents anyone + * from deleting a recovery point. + */ + public blockRecoveryPointDeletion() { + this.addToAccessPolicy(new iam.PolicyStatement({ + effect: iam.Effect.DENY, + actions: [ + 'backup:DeleteRecoveryPoint', + 'backup:UpdateRecoveryPointLifecycle', + ], + principals: [new iam.AnyPrincipal()], + resources: ['*'], + })); + } + private uniqueVaultName() { // Max length of 50 chars, get the last 50 chars const id = Names.uniqueId(this); diff --git a/packages/@aws-cdk/aws-backup/package.json b/packages/@aws-cdk/aws-backup/package.json index 78f771c99a2b7..fa3dd9c9f3693 100644 --- a/packages/@aws-cdk/aws-backup/package.json +++ b/packages/@aws-cdk/aws-backup/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::Backup", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -76,11 +75,11 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assertions": "0.0.0", - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/aws-dynamodb": "0.0.0", diff --git a/packages/@aws-cdk/aws-backup/test/vault.test.ts b/packages/@aws-cdk/aws-backup/test/vault.test.ts index 30b145f55d3ac..e72b039e75c63 100644 --- a/packages/@aws-cdk/aws-backup/test/vault.test.ts +++ b/packages/@aws-cdk/aws-backup/test/vault.test.ts @@ -138,6 +138,62 @@ test('merges statements from accessPolicy and blockRecoveryPointDeletion', () => }); }); +test('addToAccessPolicy()', () => { + // GIVEN + const vault = new BackupVault(stack, 'Vault'); + + // WHEN + vault.addToAccessPolicy(new iam.PolicyStatement({ + effect: iam.Effect.DENY, + principals: [new iam.ArnPrincipal('arn:aws:iam::123456789012:role/MyRole')], + actions: ['backup:StartRestoreJob'], + })); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Backup::BackupVault', { + AccessPolicy: { + Version: '2012-10-17', + Statement: [ + { + Action: 'backup:StartRestoreJob', + Effect: 'Deny', + Principal: { + AWS: 'arn:aws:iam::123456789012:role/MyRole', + }, + }, + ], + }, + }); +}); + +test('blockRecoveryPointDeletion()', () => { + // GIVEN + const vault = new BackupVault(stack, 'Vault'); + + // WHEN + vault.blockRecoveryPointDeletion(); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Backup::BackupVault', { + AccessPolicy: { + Version: '2012-10-17', + Statement: [ + { + Effect: 'Deny', + Principal: { + AWS: '*', + }, + Action: [ + 'backup:DeleteRecoveryPoint', + 'backup:UpdateRecoveryPointLifecycle', + ], + Resource: '*', + }, + ], + }, + }); +}); + test('with encryption key', () => { // GIVEN const encryptionKey = new kms.Key(stack, 'Key'); diff --git a/packages/@aws-cdk/aws-batch/.eslintrc.js b/packages/@aws-cdk/aws-batch/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-batch/.eslintrc.js +++ b/packages/@aws-cdk/aws-batch/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-batch/jest.config.js b/packages/@aws-cdk/aws-batch/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-batch/jest.config.js +++ b/packages/@aws-cdk/aws-batch/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-batch/package.json b/packages/@aws-cdk/aws-batch/package.json index bc9cbf389cd8c..1c385bf9b0d91 100644 --- a/packages/@aws-cdk/aws-batch/package.json +++ b/packages/@aws-cdk/aws-batch/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::Batch", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -74,32 +73,32 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { - "@aws-cdk/core": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/aws-ecr": "0.0.0", "@aws-cdk/aws-ecs": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-secretsmanager": "0.0.0", "@aws-cdk/aws-ssm": "0.0.0", + "@aws-cdk/core": "0.0.0", "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { - "@aws-cdk/core": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/aws-ecr": "0.0.0", "@aws-cdk/aws-ecs": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-secretsmanager": "0.0.0", "@aws-cdk/aws-ssm": "0.0.0", + "@aws-cdk/core": "0.0.0", "constructs": "^3.3.69" }, "engines": { diff --git a/packages/@aws-cdk/aws-budgets/.eslintrc.js b/packages/@aws-cdk/aws-budgets/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-budgets/.eslintrc.js +++ b/packages/@aws-cdk/aws-budgets/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-budgets/jest.config.js b/packages/@aws-cdk/aws-budgets/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-budgets/jest.config.js +++ b/packages/@aws-cdk/aws-budgets/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-budgets/package.json b/packages/@aws-cdk/aws-budgets/package.json index 37c92a04ef9cc..cabef6dd2e5f1 100644 --- a/packages/@aws-cdk/aws-budgets/package.json +++ b/packages/@aws-cdk/aws-budgets/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::Budgets", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,11 +72,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-cassandra/.eslintrc.js b/packages/@aws-cdk/aws-cassandra/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-cassandra/.eslintrc.js +++ b/packages/@aws-cdk/aws-cassandra/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-cassandra/jest.config.js b/packages/@aws-cdk/aws-cassandra/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-cassandra/jest.config.js +++ b/packages/@aws-cdk/aws-cassandra/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-cassandra/package.json b/packages/@aws-cdk/aws-cassandra/package.json index 1515c0f8cbebe..bf0aa5a1e3a1e 100644 --- a/packages/@aws-cdk/aws-cassandra/package.json +++ b/packages/@aws-cdk/aws-cassandra/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::Cassandra", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-ce/.eslintrc.js b/packages/@aws-cdk/aws-ce/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-ce/.eslintrc.js +++ b/packages/@aws-cdk/aws-ce/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-ce/jest.config.js b/packages/@aws-cdk/aws-ce/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-ce/jest.config.js +++ b/packages/@aws-cdk/aws-ce/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-ce/package.json b/packages/@aws-cdk/aws-ce/package.json index 8148d2c5f2dd2..088987329b0f8 100644 --- a/packages/@aws-cdk/aws-ce/package.json +++ b/packages/@aws-cdk/aws-ce/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::CE", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-certificatemanager/.eslintrc.js b/packages/@aws-cdk/aws-certificatemanager/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-certificatemanager/.eslintrc.js +++ b/packages/@aws-cdk/aws-certificatemanager/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-certificatemanager/jest.config.js b/packages/@aws-cdk/aws-certificatemanager/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-certificatemanager/jest.config.js +++ b/packages/@aws-cdk/aws-certificatemanager/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-certificatemanager/lambda-packages/dns_validated_certificate_handler/.eslintrc.js b/packages/@aws-cdk/aws-certificatemanager/lambda-packages/dns_validated_certificate_handler/.eslintrc.js index 2ab6719877209..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-certificatemanager/lambda-packages/dns_validated_certificate_handler/.eslintrc.js +++ b/packages/@aws-cdk/aws-certificatemanager/lambda-packages/dns_validated_certificate_handler/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; -module.exports = baseConfig; \ No newline at end of file +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-certificatemanager/lambda-packages/dns_validated_certificate_handler/package.json b/packages/@aws-cdk/aws-certificatemanager/lambda-packages/dns_validated_certificate_handler/package.json index 63784c4cf30ce..6c6198071796b 100644 --- a/packages/@aws-cdk/aws-certificatemanager/lambda-packages/dns_validated_certificate_handler/package.json +++ b/packages/@aws-cdk/aws-certificatemanager/lambda-packages/dns_validated_certificate_handler/package.json @@ -1,5 +1,5 @@ { - "name": "dns_validated_certificate_handler", + "name": "@aws-cdk/dns_validated_certificate_handler", "private": true, "version": "0.0.0", "description": "This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project.", @@ -29,21 +29,21 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/aws-lambda": "^8.10.79", + "@types/aws-lambda": "^8.10.84", "@types/sinon": "^9.0.11", - "cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", "aws-sdk": "^2.596.0", - "aws-sdk-mock": "^5.2.1", - "eslint": "^7.31.0", + "aws-sdk-mock": "^5.4.0", + "eslint": "^7.32.0", "eslint-config-standard": "^14.1.1", - "eslint-plugin-import": "^2.23.4", + "eslint-plugin-import": "^2.25.2", "eslint-plugin-node": "^11.1.0", "eslint-plugin-promise": "^4.3.1", "eslint-plugin-standard": "^4.1.0", "jest": "^26.6.3", "lambda-tester": "^3.6.0", "sinon": "^9.2.4", - "nock": "^13.1.1", + "nock": "^13.1.3", "ts-jest": "^26.5.6" } } diff --git a/packages/@aws-cdk/aws-certificatemanager/lib/dns-validated-certificate.ts b/packages/@aws-cdk/aws-certificatemanager/lib/dns-validated-certificate.ts index fff0ef7df7d7d..60c965e21a6ab 100644 --- a/packages/@aws-cdk/aws-certificatemanager/lib/dns-validated-certificate.ts +++ b/packages/@aws-cdk/aws-certificatemanager/lib/dns-validated-certificate.ts @@ -88,7 +88,7 @@ export class DnsValidatedCertificate extends CertificateBase implements ICertifi const requestorFunction = new lambda.Function(this, 'CertificateRequestorFunction', { code: lambda.Code.fromAsset(path.resolve(__dirname, '..', 'lambda-packages', 'dns_validated_certificate_handler', 'lib')), handler: 'index.certificateRequestHandler', - runtime: lambda.Runtime.NODEJS_14_X, + runtime: lambda.Runtime.NODEJS_12_X, timeout: cdk.Duration.minutes(15), role: props.customResourceRole, }); diff --git a/packages/@aws-cdk/aws-certificatemanager/package.json b/packages/@aws-cdk/aws-certificatemanager/package.json index f84f775f108de..990c09fc3aa55 100644 --- a/packages/@aws-cdk/aws-certificatemanager/package.json +++ b/packages/@aws-cdk/aws-certificatemanager/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::CertificateManager", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,11 +72,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/aws-cloudwatch": "0.0.0", @@ -89,12 +88,12 @@ }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { + "@aws-cdk/aws-cloudwatch": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/aws-route53": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.3.69", - "@aws-cdk/aws-cloudwatch": "0.0.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-certificatemanager/test/dns-validated-certificate.test.ts b/packages/@aws-cdk/aws-certificatemanager/test/dns-validated-certificate.test.ts index 1b0a667b52738..aadce823b74a0 100644 --- a/packages/@aws-cdk/aws-certificatemanager/test/dns-validated-certificate.test.ts +++ b/packages/@aws-cdk/aws-certificatemanager/test/dns-validated-certificate.test.ts @@ -31,7 +31,7 @@ test('creates CloudFormation Custom Resource', () => { }); expect(stack).toHaveResource('AWS::Lambda::Function', { Handler: 'index.certificateRequestHandler', - Runtime: 'nodejs14.x', + Runtime: 'nodejs12.x', Timeout: 900, }); expect(stack).toHaveResource('AWS::IAM::Policy', { diff --git a/packages/@aws-cdk/aws-chatbot/.eslintrc.js b/packages/@aws-cdk/aws-chatbot/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-chatbot/.eslintrc.js +++ b/packages/@aws-cdk/aws-chatbot/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-chatbot/README.md b/packages/@aws-cdk/aws-chatbot/README.md index d8242bf30bea2..5e871bb81db48 100644 --- a/packages/@aws-cdk/aws-chatbot/README.md +++ b/packages/@aws-cdk/aws-chatbot/README.md @@ -17,6 +17,7 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aw ```ts import * as chatbot from '@aws-cdk/aws-chatbot'; +import * as sns from '@aws-cdk/aws-sns'; const slackChannel = new chatbot.SlackChannelConfiguration(this, 'MySlackChannel', { slackChannelConfigurationName: 'YOUR_CHANNEL_NAME', @@ -31,6 +32,8 @@ slackChannel.addToRolePolicy(new iam.PolicyStatement({ ], resources: ['arn:aws:s3:::abc/xyz/123.txt'], })); + +slackChannel.addNotificationTopic(new sns.Topic(this, 'MyTopic')) ``` ## Log Group diff --git a/packages/@aws-cdk/aws-chatbot/jest.config.js b/packages/@aws-cdk/aws-chatbot/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-chatbot/jest.config.js +++ b/packages/@aws-cdk/aws-chatbot/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-chatbot/lib/slack-channel-configuration.ts b/packages/@aws-cdk/aws-chatbot/lib/slack-channel-configuration.ts index 690bb95c9bffd..d7d48f9efc9f2 100644 --- a/packages/@aws-cdk/aws-chatbot/lib/slack-channel-configuration.ts +++ b/packages/@aws-cdk/aws-chatbot/lib/slack-channel-configuration.ts @@ -239,7 +239,6 @@ export class SlackChannelConfiguration extends SlackChannelConfigurationBase { } else { this.slackChannelConfigurationName = resourceName.substring('slack-channel/'.length); } - } } @@ -268,6 +267,12 @@ export class SlackChannelConfiguration extends SlackChannelConfigurationBase { readonly grantPrincipal: iam.IPrincipal; + /** + * The SNS topic that deliver notifications to AWS Chatbot. + * @attribute + */ + private readonly notificationTopics: sns.ITopic[]; + constructor(scope: Construct, id: string, props: SlackChannelConfigurationProps) { super(scope, id, { physicalName: props.slackChannelConfigurationName, @@ -279,12 +284,14 @@ export class SlackChannelConfiguration extends SlackChannelConfigurationBase { this.grantPrincipal = this.role; + this.notificationTopics = props.notificationTopics ?? []; + const configuration = new CfnSlackChannelConfiguration(this, 'Resource', { configurationName: props.slackChannelConfigurationName, iamRoleArn: this.role.roleArn, slackWorkspaceId: props.slackWorkspaceId, slackChannelId: props.slackChannelId, - snsTopicArns: props.notificationTopics?.map(topic => topic.topicArn), + snsTopicArns: cdk.Lazy.list({ produce: () => this.notificationTopics.map(topic => topic.topicArn) }, { omitEmpty: true } ), loggingLevel: props.loggingLevel?.toString(), }); @@ -303,5 +310,13 @@ export class SlackChannelConfiguration extends SlackChannelConfigurationBase { this.slackChannelConfigurationArn = configuration.ref; this.slackChannelConfigurationName = props.slackChannelConfigurationName; } + + /** + * Adds a SNS topic that deliver notifications to AWS Chatbot. + * @param notificationTopic + */ + public addNotificationTopic(notificationTopic: sns.ITopic): void { + this.notificationTopics.push(notificationTopic); + } } diff --git a/packages/@aws-cdk/aws-chatbot/package.json b/packages/@aws-cdk/aws-chatbot/package.json index 9fcdfedfcda21..353033b0e9224 100644 --- a/packages/@aws-cdk/aws-chatbot/package.json +++ b/packages/@aws-cdk/aws-chatbot/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::Chatbot", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,16 +74,16 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { - "@aws-cdk/aws-codestarnotifications": "0.0.0", "@aws-cdk/aws-cloudwatch": "0.0.0", + "@aws-cdk/aws-codestarnotifications": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-sns": "0.0.0", @@ -92,8 +91,8 @@ "constructs": "^3.3.69" }, "peerDependencies": { - "@aws-cdk/aws-codestarnotifications": "0.0.0", "@aws-cdk/aws-cloudwatch": "0.0.0", + "@aws-cdk/aws-codestarnotifications": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-sns": "0.0.0", diff --git a/packages/@aws-cdk/aws-chatbot/test/slack-channel-configuration.test.ts b/packages/@aws-cdk/aws-chatbot/test/slack-channel-configuration.test.ts index 63bf61b46d21c..01aa5d88c2c5d 100644 --- a/packages/@aws-cdk/aws-chatbot/test/slack-channel-configuration.test.ts +++ b/packages/@aws-cdk/aws-chatbot/test/slack-channel-configuration.test.ts @@ -1,5 +1,5 @@ -import '@aws-cdk/assert-internal/jest'; import { ABSENT } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; import * as iam from '@aws-cdk/aws-iam'; import * as logs from '@aws-cdk/aws-logs'; @@ -99,6 +99,26 @@ describe('SlackChannelConfiguration', () => { }); }); + test('allows adding a Topic after creating the SlackChannel', () => { + const slackChannel = new chatbot.SlackChannelConfiguration(stack, 'MySlackChannel', { + slackWorkspaceId: 'ABC123', + slackChannelId: 'DEF456', + slackChannelConfigurationName: 'Test', + }); + + const topic = new sns.Topic(stack, 'MyTopic'); + slackChannel.addNotificationTopic(topic); + + expect(stack).toHaveResourceLike('AWS::Chatbot::SlackChannelConfiguration', { + ConfigurationName: 'Test', + SnsTopicArns: [ + { + Ref: 'MyTopic86869434', + }, + ], + }); + }); + test('created with existing role', () => { const role = iam.Role.fromRoleArn(stack, 'Role', 'arn:aws:iam:::role/test-role'); diff --git a/packages/@aws-cdk/aws-cloud9/.eslintrc.js b/packages/@aws-cdk/aws-cloud9/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-cloud9/.eslintrc.js +++ b/packages/@aws-cdk/aws-cloud9/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-cloud9/jest.config.js b/packages/@aws-cdk/aws-cloud9/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-cloud9/jest.config.js +++ b/packages/@aws-cdk/aws-cloud9/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-cloud9/package.json b/packages/@aws-cdk/aws-cloud9/package.json index 452002a0e5dde..82d3f7d1b25dd 100644 --- a/packages/@aws-cdk/aws-cloud9/package.json +++ b/packages/@aws-cdk/aws-cloud9/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::Cloud9", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,23 +74,23 @@ "devDependencies": { "@aws-cdk/assertions": "0.0.0", "@aws-cdk/aws-codecommit": "0.0.0", - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { - "@aws-cdk/core": "0.0.0", "@aws-cdk/aws-codecommit": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", + "@aws-cdk/core": "0.0.0", "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { - "@aws-cdk/core": "0.0.0", "@aws-cdk/aws-codecommit": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", + "@aws-cdk/core": "0.0.0", "constructs": "^3.3.69" }, "engines": { diff --git a/packages/@aws-cdk/aws-cloudformation/.eslintrc.js b/packages/@aws-cdk/aws-cloudformation/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-cloudformation/.eslintrc.js +++ b/packages/@aws-cdk/aws-cloudformation/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-cloudformation/.gitignore b/packages/@aws-cdk/aws-cloudformation/.gitignore index dcc1dc41e477f..dd44a9ab1feb0 100644 --- a/packages/@aws-cdk/aws-cloudformation/.gitignore +++ b/packages/@aws-cdk/aws-cloudformation/.gitignore @@ -15,4 +15,6 @@ nyc.config.js *.snk !.eslintrc.js -junit.xml \ No newline at end of file +junit.xml + +!jest.config.js \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cloudformation/.npmignore b/packages/@aws-cdk/aws-cloudformation/.npmignore index 9a032ae80868c..e8acf10a468a1 100644 --- a/packages/@aws-cdk/aws-cloudformation/.npmignore +++ b/packages/@aws-cdk/aws-cloudformation/.npmignore @@ -24,4 +24,5 @@ tsconfig.json **/cdk.out junit.xml test/ -!*.lit.ts \ No newline at end of file +!*.lit.ts +jest.config.js \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cloudformation/jest.config.js b/packages/@aws-cdk/aws-cloudformation/jest.config.js new file mode 100644 index 0000000000000..34818e1593f6b --- /dev/null +++ b/packages/@aws-cdk/aws-cloudformation/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/@aws-cdk/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-cloudformation/package.json b/packages/@aws-cdk/aws-cloudformation/package.json index b3d32b8636b09..3a8c455bf4557 100644 --- a/packages/@aws-cdk/aws-cloudformation/package.json +++ b/packages/@aws-cdk/aws-cloudformation/package.json @@ -69,19 +69,19 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", "@aws-cdk/aws-events": "0.0.0", "@aws-cdk/aws-s3-assets": "0.0.0", "@aws-cdk/aws-sns-subscriptions": "0.0.0", "@aws-cdk/aws-sqs": "0.0.0", "@aws-cdk/aws-ssm": "0.0.0", - "@types/aws-lambda": "^8.10.79", - "@types/nodeunit": "^0.0.32", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "nodeunit": "^0.11.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/aws-lambda": "^8.10.84", + "@types/jest": "^26.0.24", + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-iam": "0.0.0", diff --git a/packages/@aws-cdk/aws-cloudformation/test/deps.test.ts b/packages/@aws-cdk/aws-cloudformation/test/deps.test.ts new file mode 100644 index 0000000000000..50014ed1b10e4 --- /dev/null +++ b/packages/@aws-cdk/aws-cloudformation/test/deps.test.ts @@ -0,0 +1,339 @@ +import * as fs from 'fs'; +import * as path from 'path'; +import { ResourcePart } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; +import { App, CfnResource, Stack } from '@aws-cdk/core'; +import * as cxapi from '@aws-cdk/cx-api'; +import { NestedStack } from '../lib'; + +describe('resource dependencies', () => { + test('between two resources in a top-level stack', () => { + // GIVEN + const app = new App(); + const stack = new Stack(app, 'Stack'); + const r1 = new CfnResource(stack, 'r1', { type: 'r1' }); + const r2 = new CfnResource(stack, 'r2', { type: 'r2' }); + + // WHEN + r1.addDependsOn(r2); + + // THEN + expect(app.synth().getStackArtifact(stack.artifactId).template).toEqual({ + Resources: + { r1: { Type: 'r1', DependsOn: ['r2'] }, r2: { Type: 'r2' } }, + }); + }); + + // eslint-disable-next-line jest/valid-describe + describe('resource in nested stack depends on a resource in the parent stack', matrixForResourceDependencyTest((addDep) => { + // GIVEN + const parent = new Stack(undefined, 'root'); + const nested = new NestedStack(parent, 'Nested'); + const resourceInParent = new CfnResource(parent, 'ResourceInParent', { type: 'PARENT' }); + const resourceInNested = new CfnResource(nested, 'ResourceInNested', { type: 'NESTED' }); + + // WHEN + addDep(resourceInNested, resourceInParent); + + // THEN: the dependency needs to transfer from the resource within the + // nested stack to the nested stack resource itself so the nested stack + // will only be deployed the dependent resource + expect(parent).toHaveResource('AWS::CloudFormation::Stack', { DependsOn: ['ResourceInParent'] }, ResourcePart.CompleteDefinition); + expect(nested).toMatchTemplate({ Resources: { ResourceInNested: { Type: 'NESTED' } } }); // no DependsOn for the actual resource + })); + + // eslint-disable-next-line jest/valid-describe + describe('resource in nested stack depends on a resource in a grandparent stack', matrixForResourceDependencyTest((addDep) => { + // GIVEN + const grantparent = new Stack(undefined, 'Grandparent'); + const parent = new NestedStack(grantparent, 'Parent'); + const nested = new NestedStack(parent, 'Nested'); + const resourceInGrandparent = new CfnResource(grantparent, 'ResourceInGrandparent', { type: 'GRANDPARENT' }); + const resourceInNested = new CfnResource(nested, 'ResourceInNested', { type: 'NESTED' }); + + // WHEN + addDep(resourceInNested, resourceInGrandparent); + + // THEN: the dependency needs to transfer from the resource within the + // nested stack to the *parent* nested stack + expect(grantparent).toHaveResource('AWS::CloudFormation::Stack', { DependsOn: ['ResourceInGrandparent'] }, ResourcePart.CompleteDefinition); + expect(nested).toMatchTemplate({ Resources: { ResourceInNested: { Type: 'NESTED' } } }); // no DependsOn for the actual resource + })); + + // eslint-disable-next-line jest/valid-describe + describe('resource in parent stack depends on resource in nested stack', matrixForResourceDependencyTest((addDep) => { + // GIVEN + const parent = new Stack(undefined, 'root'); + const nested = new NestedStack(parent, 'Nested'); + const resourceInParent = new CfnResource(parent, 'ResourceInParent', { type: 'PARENT' }); + const resourceInNested = new CfnResource(nested, 'ResourceInNested', { type: 'NESTED' }); + + // WHEN + addDep(resourceInParent, resourceInNested); + + // THEN: resource in parent needs to depend on the nested stack + expect(parent).toHaveResource('PARENT', { + DependsOn: [parent.resolve(nested.nestedStackResource!.logicalId)], + }, ResourcePart.CompleteDefinition); + })); + + // eslint-disable-next-line jest/valid-describe + describe('resource in grantparent stack depends on resource in nested stack', matrixForResourceDependencyTest((addDep) => { + // GIVEN + const grandparent = new Stack(undefined, 'Grandparent'); + const parent = new NestedStack(grandparent, 'Parent'); + const nested = new NestedStack(parent, 'Nested'); + const resourceInGrandparent = new CfnResource(grandparent, 'ResourceInGrandparent', { type: 'GRANDPARENT' }); + const resourceInNested = new CfnResource(nested, 'ResourceInNested', { type: 'NESTED' }); + + // WHEN + addDep(resourceInGrandparent, resourceInNested); + + // THEN: resource in grantparent needs to depend on the top-level nested stack + expect(grandparent).toHaveResource('GRANDPARENT', { + DependsOn: [grandparent.resolve(parent.nestedStackResource!.logicalId)], + }, ResourcePart.CompleteDefinition); + })); + + // eslint-disable-next-line jest/valid-describe + describe('resource in sibling stack depends on a resource in nested stack', matrixForResourceDependencyTest((addDep) => { + // GIVEN + const app = new App(); + const stack1 = new Stack(app, 'Stack1'); + const nested1 = new NestedStack(stack1, 'Nested1'); + const resourceInNested1 = new CfnResource(nested1, 'ResourceInNested', { type: 'NESTED' }); + const stack2 = new Stack(app, 'Stack2'); + const resourceInStack2 = new CfnResource(stack2, 'ResourceInSibling', { type: 'SIBLING' }); + + // WHEN + addDep(resourceInStack2, resourceInNested1); + + // THEN: stack2 should depend on stack1 and no "DependsOn" inside templates + const assembly = app.synth(); + assertAssemblyDependency(assembly, stack1, []); + assertAssemblyDependency(assembly, stack2, ['Stack1']); + assertNoDependsOn(assembly, stack1); + assertNoDependsOn(assembly, stack2); + assertNoDependsOn(assembly, nested1); + })); + + // eslint-disable-next-line jest/valid-describe + describe('resource in nested stack depends on a resource in sibling stack', matrixForResourceDependencyTest((addDep) => { + // GIVEN + const app = new App(); + const stack1 = new Stack(app, 'Stack1'); + const nested1 = new NestedStack(stack1, 'Nested1'); + const resourceInNested1 = new CfnResource(nested1, 'ResourceInNested', { type: 'NESTED' }); + const stack2 = new Stack(app, 'Stack2'); + const resourceInStack2 = new CfnResource(stack2, 'ResourceInSibling', { type: 'SIBLING' }); + + // WHEN + addDep(resourceInNested1, resourceInStack2); + + // THEN: stack1 should depend on stack2 and no "DependsOn" inside templates + const assembly = app.synth(); + assertAssemblyDependency(assembly, stack1, ['Stack2']); + assertAssemblyDependency(assembly, stack2, []); + assertNoDependsOn(assembly, stack1); + assertNoDependsOn(assembly, stack2); + assertNoDependsOn(assembly, nested1); + })); + + // eslint-disable-next-line jest/valid-describe + describe('resource in nested stack depends on a resource in nested sibling stack', matrixForResourceDependencyTest((addDep) => { + // GIVEN + const app = new App(); + const stack = new Stack(app, 'Stack1'); + const nested1 = new NestedStack(stack, 'Nested1'); + const nested2 = new NestedStack(stack, 'Nested2'); + const resourceInNested1 = new CfnResource(nested1, 'ResourceInNested1', { type: 'NESTED1' }); + const resourceInNested2 = new CfnResource(nested2, 'ResourceInNested2', { type: 'NESTED2' }); + + // WHEN + addDep(resourceInNested1, resourceInNested2); + + // THEN: dependency transfered to nested stack resources + expect(stack).toHaveResource('AWS::CloudFormation::Stack', { + DependsOn: [stack.resolve(nested2.nestedStackResource!.logicalId)], + }, ResourcePart.CompleteDefinition); + + expect(stack).not.toHaveResource('AWS::CloudFormation::Stack', { + DependsOn: [stack.resolve(nested1.nestedStackResource!.logicalId)], + }, ResourcePart.CompleteDefinition); + })); +}); + +describe('stack dependencies', () => { + test('top level stack depends on itself', () => { + // GIVEN + const app = new App(); + const stack = new Stack(app, 'Stack'); + + // WHEN + stack.addDependency(stack); + + // THEN + const assembly = app.synth(); + assertAssemblyDependency(assembly, stack, []); + assertNoDependsOn(assembly, stack); + }); + + test('nested stack depends on itself', () => { + // GIVEN + const app = new App(); + const parent = new Stack(app, 'Parent'); + const nested = new NestedStack(parent, 'Nested'); + + // WHEN + nested.addDependency(nested); + + // THEN + assertNoDependsOn(app.synth(), parent); + }); + + test('nested stack cannot depend on any of its parents', () => { + // GIVEN + const root = new Stack(); + const nested1 = new NestedStack(root, 'Nested1'); + const nested2 = new NestedStack(nested1, 'Nested2'); + + // THEN + expect(() => nested1.addDependency(root)).toThrow(/Nested stack 'Default\/Nested1' cannot depend on a parent stack 'Default'/); + expect(() => nested2.addDependency(nested1)).toThrow(/Nested stack 'Default\/Nested1\/Nested2' cannot depend on a parent stack 'Default\/Nested1'/); + expect(() => nested2.addDependency(root)).toThrow(/Nested stack 'Default\/Nested1\/Nested2' cannot depend on a parent stack 'Default'/); + }); + + test('any parent stack is by definition dependent on the nested stack so dependency is ignored', () => { + // GIVEN + const root = new Stack(); + const nested1 = new NestedStack(root, 'Nested1'); + const nested2 = new NestedStack(nested1, 'Nested2'); + + // WHEN + root.addDependency(nested1); + root.addDependency(nested2); + nested1.addDependency(nested2); + }); + + test('sibling nested stacks transfer to resources', () => { + // GIVEN + const stack = new Stack(); + const nested1 = new NestedStack(stack, 'Nested1'); + const nested2 = new NestedStack(stack, 'Nested2'); + + // WHEN + nested1.addDependency(nested2); + + // THEN + expect(stack).toHaveResource('AWS::CloudFormation::Stack', { + DependsOn: [stack.resolve(nested2.nestedStackResource!.logicalId)], + }, ResourcePart.CompleteDefinition); + }); + + test('nested stack depends on a deeply nested stack', () => { + // GIVEN + const stack = new Stack(); + const nested1 = new NestedStack(stack, 'Nested1'); + const nested2 = new NestedStack(stack, 'Nested2'); + const nested21 = new NestedStack(nested2, 'Nested21'); + + // WHEN + nested1.addDependency(nested21); + + // THEN: transfered to a resource dep between the resources in the common stack + expect(stack).toHaveResource('AWS::CloudFormation::Stack', { + DependsOn: [stack.resolve(nested2.nestedStackResource!.logicalId)], + }, ResourcePart.CompleteDefinition); + }); + + test('deeply nested stack depends on a parent nested stack', () => { + // GIVEN + const stack = new Stack(); + const nested1 = new NestedStack(stack, 'Nested1'); + const nested2 = new NestedStack(stack, 'Nested2'); + const nested21 = new NestedStack(nested2, 'Nested21'); + + // WHEN + nested21.addDependency(nested1); + + // THEN: transfered to a resource dep between the resources in the common stack + expect(stack).toHaveResource('AWS::CloudFormation::Stack', { + DependsOn: [stack.resolve(nested1.nestedStackResource!.logicalId)], + }, ResourcePart.CompleteDefinition); + }); + + test('top-level stack depends on a nested stack within a sibling', () => { + // GIVEN + const app = new App(); + const stack1 = new Stack(app, 'Stack1'); + const nested1 = new NestedStack(stack1, 'Nested1'); + const stack2 = new Stack(app, 'Stack2'); + + // WHEN + stack2.addDependency(nested1); + + // THEN: assembly-level dependency between stack2 and stack1 + const assembly = app.synth(); + assertAssemblyDependency(assembly, stack2, ['Stack1']); + assertAssemblyDependency(assembly, stack1, []); + assertNoDependsOn(assembly, stack1); + assertNoDependsOn(assembly, stack2); + assertNoDependsOn(assembly, nested1); + }); + + test('nested stack within a sibling depends on top-level stack', () => { + // GIVEN + const app = new App(); + const stack1 = new Stack(app, 'Stack1'); + const nested1 = new NestedStack(stack1, 'Nested1'); + const stack2 = new Stack(app, 'Stack2'); + + // WHEN + nested1.addDependency(stack2); + + // THEN: assembly-level dependency between stack2 and stack1 + const assembly = app.synth(); + assertAssemblyDependency(assembly, stack2, []); + assertAssemblyDependency(assembly, stack1, ['Stack2']); + assertNoDependsOn(assembly, stack1); + assertNoDependsOn(assembly, stack2); + assertNoDependsOn(assembly, nested1); + }); +}); + +/** + * Given a test function which sets the stage and verifies a dependency scenario + * between two CloudFormation resources, returns two tests which exercise both + * "construct dependency" (i.e. node.addDependency) and "resource dependency" + * (i.e. resource.addDependsOn). + * + * @param testFunction The test function + */ +function matrixForResourceDependencyTest(testFunction: (addDep: (source: CfnResource, target: CfnResource) => void) => void) { + return () => { + test('construct dependency', () => { + testFunction((source, target) => source.node.addDependency(target)); + }); + test('resource dependency', () => { + testFunction((source, target) => source.addDependsOn(target)); + }); + }; +} + +function assertAssemblyDependency(assembly: cxapi.CloudAssembly, stack: Stack, expectedDeps: string[]) { + const stack1Art = assembly.getStackArtifact(stack.artifactId); + const stack1Deps = stack1Art.dependencies.map(x => x.id); + expect(stack1Deps).toEqual(expectedDeps); +} + +function assertNoDependsOn(assembly: cxapi.CloudAssembly, stack: Stack) { + let templateText; + if (!(stack instanceof NestedStack)) { + templateText = JSON.stringify(assembly.getStackArtifact(stack.artifactId).template); + } else { + templateText = fs.readFileSync(path.join(assembly.directory, stack.templateFile), 'utf-8'); + } + + // verify templates do not have any "DependsOn" + expect(templateText.includes('DependsOn')).toBeFalsy(); +} diff --git a/packages/@aws-cdk/aws-cloudformation/test/integ.core-custom-resources.ts b/packages/@aws-cdk/aws-cloudformation/test/integ.core-custom-resources.ts index bdd4ae31af241..0b3fe66814d63 100644 --- a/packages/@aws-cdk/aws-cloudformation/test/integ.core-custom-resources.ts +++ b/packages/@aws-cdk/aws-cloudformation/test/integ.core-custom-resources.ts @@ -13,7 +13,7 @@ import { App, CfnOutput, CustomResource, CustomResourceProvider, CustomResourceP // eslint-disable-next-line no-duplicate-imports, import/order import { Construct } from '@aws-cdk/core'; -/* eslint-disable cdk/no-core-construct */ +/* eslint-disable @aws-cdk/no-core-construct */ class TestStack extends Stack { constructor(scope: Construct, id: string) { diff --git a/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stack.ts b/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stack.ts index 77e008ac6872c..3b3a26346c2be 100644 --- a/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stack.ts +++ b/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stack.ts @@ -9,7 +9,7 @@ import * as cfn from '../lib'; // eslint-disable-next-line no-duplicate-imports, import/order import { Construct } from '@aws-cdk/core'; -/* eslint-disable cdk/no-core-construct */ +/* eslint-disable @aws-cdk/no-core-construct */ interface MyNestedStackProps { readonly subscriber?: sqs.Queue; diff --git a/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-assets.ts b/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-assets.ts index dd3a74360e934..996ef461b0d2c 100644 --- a/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-assets.ts +++ b/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-assets.ts @@ -8,7 +8,7 @@ import * as cfn from '../lib'; // eslint-disable-next-line no-duplicate-imports, import/order import { Construct } from '@aws-cdk/core'; -/* eslint-disable cdk/no-core-construct */ +/* eslint-disable @aws-cdk/no-core-construct */ class NestedStack extends cfn.NestedStack { constructor(scope: Construct, id: string) { diff --git a/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-multi.ts b/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-multi.ts index 67f11d0f31878..768f69cb93209 100644 --- a/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-multi.ts +++ b/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-multi.ts @@ -7,7 +7,7 @@ import * as cfn from '../lib'; // eslint-disable-next-line no-duplicate-imports, import/order import { Construct } from '@aws-cdk/core'; -/* eslint-disable cdk/no-core-construct */ +/* eslint-disable @aws-cdk/no-core-construct */ class YourNestedStack extends cfn.NestedStack { constructor(scope: Construct, id: string) { diff --git a/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-refs1.ts b/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-refs1.ts index 1240d8d39e5b3..11ab60d5c80cf 100644 --- a/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-refs1.ts +++ b/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-refs1.ts @@ -2,7 +2,7 @@ // nested stack references a resource from a non-nested non-parent stack -/* eslint-disable cdk/no-core-construct */ +/* eslint-disable @aws-cdk/no-core-construct */ import * as sns from '@aws-cdk/aws-sns'; import { App, Stack } from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-refs2.ts b/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-refs2.ts index 712de493fa9a3..03bfc0998a30e 100644 --- a/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-refs2.ts +++ b/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-refs2.ts @@ -9,7 +9,7 @@ import { Construct } from '@aws-cdk/core'; // non-nested non-parent stack consumes a resource from a nested stack -/* eslint-disable cdk/no-core-construct */ +/* eslint-disable @aws-cdk/no-core-construct */ class ProducerNestedStack extends cfn.NestedStack { public readonly topic: sns.Topic; diff --git a/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-refs3.ts b/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-refs3.ts index f44eb1b1f731a..3266d08e027f0 100644 --- a/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-refs3.ts +++ b/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-refs3.ts @@ -9,7 +9,7 @@ import { Construct } from '@aws-cdk/core'; // references between siblings -/* eslint-disable cdk/no-core-construct */ +/* eslint-disable @aws-cdk/no-core-construct */ class ProducerNestedStack extends cfn.NestedStack { public readonly topic: sns.Topic; diff --git a/packages/@aws-cdk/aws-cloudformation/test/integ.trivial-lambda-resource.ts b/packages/@aws-cdk/aws-cloudformation/test/integ.trivial-lambda-resource.ts index 5d2b63f9b88b0..e88b7113cb113 100644 --- a/packages/@aws-cdk/aws-cloudformation/test/integ.trivial-lambda-resource.ts +++ b/packages/@aws-cdk/aws-cloudformation/test/integ.trivial-lambda-resource.ts @@ -7,7 +7,7 @@ import { CustomResource, CustomResourceProvider } from '../lib'; // eslint-disable-next-line no-duplicate-imports, import/order import { Construct } from '@aws-cdk/core'; -/* eslint-disable cdk/no-core-construct */ +/* eslint-disable @aws-cdk/no-core-construct */ interface DemoResourceProps { /** diff --git a/packages/@aws-cdk/aws-cloudformation/test/nested-stack.test.ts b/packages/@aws-cdk/aws-cloudformation/test/nested-stack.test.ts new file mode 100644 index 0000000000000..90c39268ec7bb --- /dev/null +++ b/packages/@aws-cdk/aws-cloudformation/test/nested-stack.test.ts @@ -0,0 +1,1083 @@ +import * as fs from 'fs'; +import * as path from 'path'; +import { SynthUtils } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; +import * as s3_assets from '@aws-cdk/aws-s3-assets'; +import * as sns from '@aws-cdk/aws-sns'; +import { App, CfnParameter, CfnResource, ContextProvider, LegacyStackSynthesizer, Names, Stack } from '@aws-cdk/core'; +import { NestedStack } from '../lib/nested-stack'; + +// keep this import separate from other imports to reduce chance for merge conflicts with v2-main +// eslint-disable-next-line no-duplicate-imports, import/order +import { Construct } from '@aws-cdk/core'; + +/* eslint-disable @aws-cdk/no-core-construct */ +/* eslint-disable max-len */ + +test('fails if defined as a root', () => { + // THEN + expect(() => new NestedStack(undefined as any, 'boom')).toThrow(/Nested stacks cannot be defined as a root construct/); +}); + +test('fails if defined without a parent stack', () => { + // GIVEN + const app = new App(); + const group = new Construct(app, 'group'); + + // THEN + expect(() => new NestedStack(app, 'boom')).toThrow(/must be defined within scope of another non-nested stack/); + expect(() => new NestedStack(group, 'bam')).toThrow(/must be defined within scope of another non-nested stack/); +}); + +test('can be defined as a direct child or an indirect child of a Stack', () => { + // GIVEN + const parent = new Stack(); + + // THEN + expect(() => new NestedStack(parent, 'direct')).not.toThrow(); + expect(() => new NestedStack(new Construct(parent, 'group'), 'indirect')).not.toThrow(); +}); + +test('nested stack is not synthesized as a stack artifact into the assembly', () => { + // GIVEN + const app = new App(); + const parentStack = new Stack(app, 'parent-stack'); + new NestedStack(parentStack, 'nested-stack'); + + // WHEN + const assembly = app.synth(); + + // THEN + expect(assembly.artifacts.length).toEqual(2); +}); + +test('the template of the nested stack is synthesized into the cloud assembly', () => { + // GIVEN + const app = new App(); + const parent = new Stack(app, 'parent-stack'); + const nested = new NestedStack(parent, 'nested-stack'); + new CfnResource(nested, 'ResourceInNestedStack', { type: 'AWS::Resource::Nested' }); + + // WHEN + const assembly = app.synth(); + + // THEN + const template = JSON.parse(fs.readFileSync(path.join(assembly.directory, `${Names.uniqueId(nested)}.nested.template.json`), 'utf-8')); + expect(template).toEqual({ + Resources: { + ResourceInNestedStack: { + Type: 'AWS::Resource::Nested', + }, + }, + }); +}); + +test('file asset metadata is associated with the parent stack', () => { + // GIVEN + const app = new App(); + const parent = new Stack(app, 'parent-stack'); + const nested = new NestedStack(parent, 'nested-stack'); + new CfnResource(nested, 'ResourceInNestedStack', { type: 'AWS::Resource::Nested' }); + + // WHEN + const assembly = app.synth(); + + // THEN + expect(assembly.getStackByName(parent.stackName).assets).toEqual([{ + path: 'parentstacknestedstack844892C0.nested.template.json', + id: 'c639c0a5e7320758aa22589669ecebc98f185b711300b074f53998c8f9a45096', + packaging: 'file', + sourceHash: 'c639c0a5e7320758aa22589669ecebc98f185b711300b074f53998c8f9a45096', + s3BucketParameter: 'AssetParametersc639c0a5e7320758aa22589669ecebc98f185b711300b074f53998c8f9a45096S3BucketDA8C3345', + s3KeyParameter: 'AssetParametersc639c0a5e7320758aa22589669ecebc98f185b711300b074f53998c8f9a45096S3VersionKey09D03EE6', + artifactHashParameter: 'AssetParametersc639c0a5e7320758aa22589669ecebc98f185b711300b074f53998c8f9a45096ArtifactHash8DE450C7', + }]); +}); + +test('aws::cloudformation::stack is synthesized in the parent scope', () => { + // GIVEN + const app = new App(); + const parent = new Stack(app, 'parent-stack'); + + // WHEN + const nested = new NestedStack(parent, 'nested-stack'); + new CfnResource(nested, 'ResourceInNestedStack', { type: 'AWS::Resource::Nested' }); + + // THEN + const assembly = app.synth(); + + // assembly has one stack (the parent) + expect(assembly.stacks.length).toEqual(1); + + // but this stack has an asset that points to the synthesized template + expect(assembly.stacks[0].assets[0].path).toEqual('parentstacknestedstack844892C0.nested.template.json'); + + // the template includes our resource + const filePath = path.join(assembly.directory, assembly.stacks[0].assets[0].path); + expect(JSON.parse(fs.readFileSync(filePath).toString('utf-8'))).toEqual({ + Resources: { ResourceInNestedStack: { Type: 'AWS::Resource::Nested' } }, + }); + + // the parent template includes the parameters and the nested stack resource which points to the s3 url + expect(parent).toMatchTemplate({ + Resources: { + nestedstackNestedStacknestedstackNestedStackResource71CDD241: { + Type: 'AWS::CloudFormation::Stack', + DeletionPolicy: 'Delete', + UpdateReplacePolicy: 'Delete', + Properties: { + TemplateURL: { + 'Fn::Join': [ + '', + [ + 'https://s3.', + { + Ref: 'AWS::Region', + }, + '.', + { + Ref: 'AWS::URLSuffix', + }, + '/', + { + Ref: 'AssetParametersc639c0a5e7320758aa22589669ecebc98f185b711300b074f53998c8f9a45096S3BucketDA8C3345', + }, + '/', + { + 'Fn::Select': [ + 0, + { + 'Fn::Split': [ + '||', + { + Ref: 'AssetParametersc639c0a5e7320758aa22589669ecebc98f185b711300b074f53998c8f9a45096S3VersionKey09D03EE6', + }, + ], + }, + ], + }, + { + 'Fn::Select': [ + 1, + { + 'Fn::Split': [ + '||', + { + Ref: 'AssetParametersc639c0a5e7320758aa22589669ecebc98f185b711300b074f53998c8f9a45096S3VersionKey09D03EE6', + }, + ], + }, + ], + }, + ], + ], + }, + }, + }, + }, + Parameters: { + AssetParametersc639c0a5e7320758aa22589669ecebc98f185b711300b074f53998c8f9a45096S3BucketDA8C3345: { + Type: 'String', + Description: 'S3 bucket for asset "c639c0a5e7320758aa22589669ecebc98f185b711300b074f53998c8f9a45096"', + }, + AssetParametersc639c0a5e7320758aa22589669ecebc98f185b711300b074f53998c8f9a45096S3VersionKey09D03EE6: { + Type: 'String', + Description: 'S3 key for asset version "c639c0a5e7320758aa22589669ecebc98f185b711300b074f53998c8f9a45096"', + }, + AssetParametersc639c0a5e7320758aa22589669ecebc98f185b711300b074f53998c8f9a45096ArtifactHash8DE450C7: { + Type: 'String', + Description: 'Artifact hash for asset "c639c0a5e7320758aa22589669ecebc98f185b711300b074f53998c8f9a45096"', + }, + }, + }); +}); + +test('Stack.of()', () => { + class MyNestedStack extends NestedStack { + public readonly stackOfChild: Stack; + + constructor(scope: Construct, id: string) { + super(scope, id); + + const param = new CfnParameter(this, 'param', { type: 'String' }); + this.stackOfChild = Stack.of(param); + } + } + + const parent = new Stack(); + const nested = new MyNestedStack(parent, 'nested'); + + expect(nested.stackOfChild).toEqual(nested); + expect(Stack.of(nested)).toEqual(nested); +}); + +test('references within the nested stack are not reported as cross stack references', () => { + class MyNestedStack extends NestedStack { + constructor(scope: Construct, id: string) { + super(scope, id); + + const param = new CfnParameter(this, 'param', { type: 'String' }); + new CfnResource(this, 'resource', { + type: 'My::Resource', + properties: { + SomeProp: param.valueAsString, + }, + }); + } + } + + const app = new App(); + const parent = new Stack(app, 'parent'); + + new MyNestedStack(parent, 'nested'); + + // references are added during "prepare" + const assembly = app.synth(); + + expect(assembly.stacks.length).toEqual(1); + expect(assembly.stacks[0].dependencies).toEqual([]); +}); + +test('references to a resource from the parent stack in a nested stack is translated into a cfn parameter', () => { + // WHEN + class MyNestedStack extends NestedStack { + + constructor(scope: Construct, id: string, resourceFromParent: CfnResource) { + super(scope, id); + + new CfnResource(this, 'resource', { + type: 'AWS::Child::Resource', + properties: { + ReferenceToResourceInParentStack: resourceFromParent.ref, + }, + }); + + new CfnResource(this, 'resource2', { + type: 'My::Resource::2', + properties: { + Prop1: resourceFromParent.getAtt('Attr'), + Prop2: resourceFromParent.ref, + }, + }); + } + } + + const app = new App(); + const parentStack = new Stack(app, 'parent'); + + const resource = new CfnResource(parentStack, 'parent-resource', { type: 'AWS::Parent::Resource' }); + + const nested = new MyNestedStack(parentStack, 'nested', resource); + + // THEN + app.synth(); + + // nested template should use a parameter to reference the resource from the parent stack + expect(nested).toMatchTemplate({ + Resources: + { + resource: + { + Type: 'AWS::Child::Resource', + Properties: + { ReferenceToResourceInParentStack: { Ref: 'referencetoparentparentresourceD56EA8F7Ref' } }, + }, + resource2: + { + Type: 'My::Resource::2', + Properties: + { + Prop1: { Ref: 'referencetoparentparentresourceD56EA8F7Attr' }, + Prop2: { Ref: 'referencetoparentparentresourceD56EA8F7Ref' }, + }, + }, + }, + Parameters: + { + referencetoparentparentresourceD56EA8F7Ref: { Type: 'String' }, + referencetoparentparentresourceD56EA8F7Attr: { Type: 'String' }, + }, + }); + + // parent template should pass in the value through the parameter + expect(parentStack).toHaveResource('AWS::CloudFormation::Stack', { + Parameters: { + referencetoparentparentresourceD56EA8F7Ref: { + Ref: 'parentresource', + }, + referencetoparentparentresourceD56EA8F7Attr: { + 'Fn::GetAtt': [ + 'parentresource', + 'Attr', + ], + }, + }, + }); +}); + +test('references to a resource in the nested stack in the parent is translated into a cfn output', () => { + class MyNestedStack extends NestedStack { + public readonly resourceFromChild: CfnResource; + + constructor(scope: Construct, id: string) { + super(scope, id); + + this.resourceFromChild = new CfnResource(this, 'resource', { + type: 'AWS::Child::Resource', + }); + } + } + + const app = new App(); + const parentStack = new Stack(app, 'parent'); + + const nested = new MyNestedStack(parentStack, 'nested'); + + new CfnResource(parentStack, 'another-parent-resource', { + type: 'AWS::Parent::Resource', + properties: { + RefToResourceInNestedStack: nested.resourceFromChild.ref, + }, + }); + + // references are added during "prepare" + app.synth(); + + // nested template should use a parameter to reference the resource from the parent stack + expect(nested).toMatchTemplate({ + Resources: { + resource: { Type: 'AWS::Child::Resource' }, + }, + Outputs: { + parentnestedresource4D680677Ref: { Value: { Ref: 'resource' } }, + }, + }); + + // parent template should pass in the value through the parameter + expect(parentStack).toHaveResource('AWS::Parent::Resource', { + RefToResourceInNestedStack: { + 'Fn::GetAtt': [ + 'nestedNestedStacknestedNestedStackResource3DD143BF', + 'Outputs.parentnestedresource4D680677Ref', + ], + }, + }); +}); + +test('nested stack references a resource from another non-nested stack (not the parent)', () => { + // GIVEN + const app = new App(); + const stack1 = new Stack(app, 'Stack1'); + const stack2 = new Stack(app, 'Stack2'); + const nestedUnderStack1 = new NestedStack(stack1, 'NestedUnderStack1'); + const resourceInStack2 = new CfnResource(stack2, 'ResourceInStack2', { type: 'MyResource' }); + + // WHEN + new CfnResource(nestedUnderStack1, 'ResourceInNestedStack1', { + type: 'Nested::Resource', + properties: { + RefToSibling: resourceInStack2.getAtt('MyAttribute'), + }, + }); + + // THEN + const assembly = app.synth(); + + // producing stack should have an export + expect(stack2).toMatchTemplate({ + Resources: { + ResourceInStack2: { Type: 'MyResource' }, + }, + Outputs: { + ExportsOutputFnGetAttResourceInStack2MyAttributeC15F1009: { + Value: { 'Fn::GetAtt': ['ResourceInStack2', 'MyAttribute'] }, + Export: { Name: 'Stack2:ExportsOutputFnGetAttResourceInStack2MyAttributeC15F1009' }, + }, + }, + }); + + // nested stack uses Fn::ImportValue like normal + expect(nestedUnderStack1).toMatchTemplate({ + Resources: { + ResourceInNestedStack1: { + Type: 'Nested::Resource', + Properties: { + RefToSibling: { + 'Fn::ImportValue': 'Stack2:ExportsOutputFnGetAttResourceInStack2MyAttributeC15F1009', + }, + }, + }, + }, + }); + + // verify a depedency was established between the parents + const stack1Artifact = assembly.getStackByName(stack1.stackName); + const stack2Artifact = assembly.getStackByName(stack2.stackName); + expect(stack1Artifact.dependencies.length).toEqual(1); + expect(stack2Artifact.dependencies.length).toEqual(0); + expect(stack1Artifact.dependencies[0]).toEqual(stack2Artifact); +}); + +test('nested stack within a nested stack references a resource in a sibling top-level stack', () => { + // GIVEN + const app = new App(); + const consumerTopLevel = new Stack(app, 'ConsumerTopLevel'); + const consumerNested1 = new NestedStack(consumerTopLevel, 'ConsumerNested1'); + const consumerNested2 = new NestedStack(consumerNested1, 'ConsumerNested2'); + const producerTopLevel = new Stack(app, 'ProducerTopLevel'); + const producer = new CfnResource(producerTopLevel, 'Producer', { type: 'Producer' }); + + // WHEN + new CfnResource(consumerNested2, 'Consumer', { + type: 'Consumer', + properties: { + Ref: producer.ref, + }, + }); + + // THEN + const manifest = app.synth(); + const consumerDeps = manifest.getStackArtifact(consumerTopLevel.artifactId).dependencies.map(d => d.id); + expect(consumerDeps).toEqual(['ProducerTopLevel']); +}); + +test('another non-nested stack takes a reference on a resource within the nested stack (the parent exports)', () => { + // GIVEN + const app = new App(); + const stack1 = new Stack(app, 'Stack1'); + const stack2 = new Stack(app, 'Stack2'); + const nestedUnderStack1 = new NestedStack(stack1, 'NestedUnderStack1'); + const resourceInNestedStack = new CfnResource(nestedUnderStack1, 'ResourceInNestedStack', { type: 'MyResource' }); + + // WHEN + new CfnResource(stack2, 'ResourceInStack2', { + type: 'JustResource', + properties: { + RefToSibling: resourceInNestedStack.getAtt('MyAttribute'), + }, + }); + + // THEN + const assembly = app.synth(); + + // nested stack should output this value as if it was referenced by the parent (without the export) + expect(nestedUnderStack1).toMatchTemplate({ + Resources: { + ResourceInNestedStack: { + Type: 'MyResource', + }, + }, + Outputs: { + Stack1NestedUnderStack1ResourceInNestedStack6EE9DCD2MyAttribute: { + Value: { + 'Fn::GetAtt': [ + 'ResourceInNestedStack', + 'MyAttribute', + ], + }, + }, + }, + }); + + // parent stack (stack1) should export this value + expect(assembly.getStackByName(stack1.stackName).template.Outputs).toEqual({ + ExportsOutputFnGetAttNestedUnderStack1NestedStackNestedUnderStack1NestedStackResourceF616305BOutputsStack1NestedUnderStack1ResourceInNestedStack6EE9DCD2MyAttribute564EECF3: { + Value: { 'Fn::GetAtt': ['NestedUnderStack1NestedStackNestedUnderStack1NestedStackResourceF616305B', 'Outputs.Stack1NestedUnderStack1ResourceInNestedStack6EE9DCD2MyAttribute'] }, + Export: { Name: 'Stack1:ExportsOutputFnGetAttNestedUnderStack1NestedStackNestedUnderStack1NestedStackResourceF616305BOutputsStack1NestedUnderStack1ResourceInNestedStack6EE9DCD2MyAttribute564EECF3' }, + }, + }); + + // consuming stack should use ImportValue to import the value from the parent stack + expect(stack2).toMatchTemplate({ + Resources: { + ResourceInStack2: { + Type: 'JustResource', + Properties: { + RefToSibling: { + 'Fn::ImportValue': 'Stack1:ExportsOutputFnGetAttNestedUnderStack1NestedStackNestedUnderStack1NestedStackResourceF616305BOutputsStack1NestedUnderStack1ResourceInNestedStack6EE9DCD2MyAttribute564EECF3', + }, + }, + }, + }, + }); + + expect(assembly.stacks.length).toEqual(2); + const stack1Artifact = assembly.getStackByName(stack1.stackName); + const stack2Artifact = assembly.getStackByName(stack2.stackName); + expect(stack1Artifact.dependencies.length).toEqual(0); + expect(stack2Artifact.dependencies.length).toEqual(1); + expect(stack2Artifact.dependencies[0]).toEqual(stack1Artifact); +}); + +test('references between sibling nested stacks should output from one and getAtt from the other', () => { + // GIVEN + const app = new App(); + const parent = new Stack(app, 'Parent'); + const nested1 = new NestedStack(parent, 'Nested1'); + const nested2 = new NestedStack(parent, 'Nested2'); + const resource1 = new CfnResource(nested1, 'Resource1', { type: 'Resource1' }); + + // WHEN + new CfnResource(nested2, 'Resource2', { + type: 'Resource2', + properties: { + RefToResource1: resource1.ref, + }, + }); + + // THEN + app.synth(); + + // producing nested stack + expect(nested1).toMatchTemplate({ + Resources: { + Resource1: { + Type: 'Resource1', + }, + }, + Outputs: { + ParentNested1Resource15F3F0657Ref: { + Value: { + Ref: 'Resource1', + }, + }, + }, + }); + + // consuming nested stack + expect(nested2).toMatchTemplate({ + Resources: { + Resource2: { + Type: 'Resource2', + Properties: { + RefToResource1: { + Ref: 'referencetoParentNested1NestedStackNested1NestedStackResource9C05342COutputsParentNested1Resource15F3F0657Ref', + }, + }, + }, + }, + Parameters: { + referencetoParentNested1NestedStackNested1NestedStackResource9C05342COutputsParentNested1Resource15F3F0657Ref: { + Type: 'String', + }, + }, + }); + + // parent + expect(parent).toHaveResource('AWS::CloudFormation::Stack', { + Parameters: { + referencetoParentNested1NestedStackNested1NestedStackResource9C05342COutputsParentNested1Resource15F3F0657Ref: { + 'Fn::GetAtt': [ + 'Nested1NestedStackNested1NestedStackResourceCD0AD36B', + 'Outputs.ParentNested1Resource15F3F0657Ref', + ], + }, + }, + }); +}); + +test('stackId returns AWS::StackId when referenced from the context of the nested stack', () => { + // GIVEN + const parent = new Stack(); + const nested = new NestedStack(parent, 'NestedStack'); + + // WHEN + new CfnResource(nested, 'NestedResource', { + type: 'Nested::Resource', + properties: { MyStackId: nested.stackId }, + }); + + // THEN + expect(nested).toHaveResource('Nested::Resource', { + MyStackId: { Ref: 'AWS::StackId' }, + }); +}); + +test('stackId returns the REF of the CloudFormation::Stack resource when referenced from the parent stack', () => { + // GIVEN + const parent = new Stack(); + const nested = new NestedStack(parent, 'NestedStack'); + + // WHEN + new CfnResource(parent, 'ParentResource', { + type: 'Parent::Resource', + properties: { NestedStackId: nested.stackId }, + }); + + // THEN + expect(parent).toHaveResource('Parent::Resource', { + NestedStackId: { Ref: 'NestedStackNestedStackNestedStackNestedStackResourceB70834FD' }, + }); +}); + +test('stackName returns AWS::StackName when referenced from the context of the nested stack', () => { + // GIVEN + const parent = new Stack(); + const nested = new NestedStack(parent, 'NestedStack'); + + // WHEN + new CfnResource(nested, 'NestedResource', { + type: 'Nested::Resource', + properties: { MyStackName: nested.stackName }, + }); + + // THEN + expect(nested).toHaveResource('Nested::Resource', { + MyStackName: { Ref: 'AWS::StackName' }, + }); +}); + +test('stackName returns the REF of the CloudFormation::Stack resource when referenced from the parent stack', () => { + // GIVEN + const parent = new Stack(); + const nested = new NestedStack(parent, 'NestedStack'); + + // WHEN + new CfnResource(parent, 'ParentResource', { + type: 'Parent::Resource', + properties: { NestedStackName: nested.stackName }, + }); + + // THEN + expect(parent).toHaveResource('Parent::Resource', { + NestedStackName: { + 'Fn::Select': [ + 1, + { + 'Fn::Split': [ + '/', + { + Ref: 'NestedStackNestedStackNestedStackNestedStackResourceB70834FD', + }, + ], + }, + ], + }, + }); +}); + +test('"account", "region" and "environment" are all derived from the parent', () => { + // GIVEN + const app = new App(); + const parent = new Stack(app, 'ParentStack', { env: { account: '1234account', region: 'us-east-44' } }); + + // WHEN + const nested = new NestedStack(parent, 'NestedStack'); + + // THEN + expect(nested.environment).toEqual(parent.environment); + expect(nested.account).toEqual(parent.account); + expect(nested.region).toEqual(parent.region); +}); + +test('double-nested stack', () => { + // GIVEN + const app = new App(); + const parent = new Stack(app, 'stack'); + + // WHEN + const nested1 = new NestedStack(parent, 'Nested1'); + const nested2 = new NestedStack(nested1, 'Nested2'); + + new CfnResource(nested1, 'Resource1', { type: 'Resource::1' }); + new CfnResource(nested2, 'Resource2', { type: 'Resource::2' }); + + // THEN + const assembly = app.synth(); + + // nested2 is a "leaf", so it's just the resource + expect(nested2).toMatchTemplate({ + Resources: { + Resource2: { Type: 'Resource::2' }, + }, + }); + + const middleStackHash = '7c426f7299a739900279ac1ece040397c1913cdf786f5228677b289f4d5e4c48'; + const bucketSuffix = 'C706B101'; + const versionSuffix = '4B193AA5'; + const hashSuffix = 'E28F0693'; + + // nested1 wires the nested2 template through parameters, so we expect those + expect(nested1).toHaveResource('Resource::1'); + const nested2Template = SynthUtils.toCloudFormation(nested1); + expect(nested2Template.Parameters).toEqual({ + referencetostackAssetParameters8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235cS3BucketE8768F5CRef: { Type: 'String' }, + referencetostackAssetParameters8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235cS3VersionKey49DD83A2Ref: { Type: 'String' }, + }); + + // parent stack should have two sets of parameters. one for the first nested stack and the second + // for the second nested stack, passed in as parameters to the first + const template = SynthUtils.toCloudFormation(parent); + expect(template.Parameters).toEqual({ + AssetParameters8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235cS3BucketDE3B88D6: { Type: 'String', Description: 'S3 bucket for asset "8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235c"' }, + AssetParameters8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235cS3VersionKey3A62EFEA: { Type: 'String', Description: 'S3 key for asset version "8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235c"' }, + AssetParameters8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235cArtifactHash7DC546E0: { Type: 'String', Description: 'Artifact hash for asset "8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235c"' }, + [`AssetParameters${middleStackHash}S3Bucket${bucketSuffix}`]: { Type: 'String', Description: `S3 bucket for asset "${middleStackHash}"` }, + [`AssetParameters${middleStackHash}S3VersionKey${versionSuffix}`]: { Type: 'String', Description: `S3 key for asset version "${middleStackHash}"` }, + [`AssetParameters${middleStackHash}ArtifactHash${hashSuffix}`]: { Type: 'String', Description: `Artifact hash for asset "${middleStackHash}"` }, + }); + + // proxy asset params to nested stack + expect(parent).toHaveResource('AWS::CloudFormation::Stack', { + Parameters: { + referencetostackAssetParameters8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235cS3BucketE8768F5CRef: { Ref: 'AssetParameters8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235cS3BucketDE3B88D6' }, + referencetostackAssetParameters8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235cS3VersionKey49DD83A2Ref: { Ref: 'AssetParameters8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235cS3VersionKey3A62EFEA' }, + }, + }); + + // parent stack should have 2 assets + expect(assembly.getStackByName(parent.stackName).assets.length).toEqual(2); +}); + +test('reference resource in a double nested stack (#15155)', () => { + // GIVEN + const app = new App(); + const producerStack = new Stack(app, 'Producer'); + const nested2 = new NestedStack(new NestedStack(producerStack, 'Nested1'), 'Nested2'); + const producerResource = new CfnResource(nested2, 'Resource', { type: 'MyResource' }); + const consumerStack = new Stack(app, 'Consumer'); + + // WHEN + new CfnResource(consumerStack, 'ConsumingResource', { + type: 'YourResource', + properties: { RefToResource: producerResource.ref }, + }); + + // THEN + const casm = app.synth(); // before #15155 was fixed this threw an error + + const producerTemplate = casm.getStackArtifact(producerStack.artifactId).template; + const consumerTemplate = casm.getStackArtifact(consumerStack.artifactId).template; + + // check that the consuming resource references the expected export name + const outputName = 'ExportsOutputFnGetAttNested1NestedStackNested1NestedStackResourceCD0AD36BOutputsProducerNested1Nested2NestedStackNested2NestedStackResource1E6FA3C3OutputsProducerNested1Nested238A89CC5Ref2E9E52EA'; + const exportName = producerTemplate.Outputs[outputName].Export.Name; + const importName = consumerTemplate.Resources.ConsumingResource.Properties.RefToResource['Fn::ImportValue']; + expect(exportName).toEqual(importName); +}); + +test('assets within nested stacks are proxied from the parent', () => { + // GIVEN + const app = new App(); + const parent = new Stack(app, 'ParentStack'); + const nested = new NestedStack(parent, 'NestedStack'); + + // WHEN + const asset = new s3_assets.Asset(nested, 'asset', { + path: path.join(__dirname, 'asset-fixture.txt'), + }); + + new CfnResource(nested, 'NestedResource', { + type: 'Nested::Resource', + properties: { + AssetBucket: asset.s3BucketName, + AssetKey: asset.s3ObjectKey, + }, + }); + + // THEN + const assembly = app.synth(); + const template = SynthUtils.toCloudFormation(parent); + + // two sets of asset parameters: one for the nested stack itself and one as a proxy for the asset within the stack + expect(template.Parameters).toEqual({ + AssetParametersdb01ee2eb7adc7915e364dc410d861e569543f9be3761d535a68d5c2cc181281S3BucketC188F637: { Type: 'String', Description: 'S3 bucket for asset "db01ee2eb7adc7915e364dc410d861e569543f9be3761d535a68d5c2cc181281"' }, + AssetParametersdb01ee2eb7adc7915e364dc410d861e569543f9be3761d535a68d5c2cc181281S3VersionKeyC7F4DBF2: { Type: 'String', Description: 'S3 key for asset version "db01ee2eb7adc7915e364dc410d861e569543f9be3761d535a68d5c2cc181281"' }, + AssetParametersdb01ee2eb7adc7915e364dc410d861e569543f9be3761d535a68d5c2cc181281ArtifactHash373B14D2: { Type: 'String', Description: 'Artifact hash for asset "db01ee2eb7adc7915e364dc410d861e569543f9be3761d535a68d5c2cc181281"' }, + AssetParameters46b107d6db798ca46046b8669d057a4debcbdbaaddb6170400748c2f9e4f9d71S3Bucket3C4265E9: { Type: 'String', Description: 'S3 bucket for asset "46b107d6db798ca46046b8669d057a4debcbdbaaddb6170400748c2f9e4f9d71"' }, + AssetParameters46b107d6db798ca46046b8669d057a4debcbdbaaddb6170400748c2f9e4f9d71S3VersionKey8E981535: { Type: 'String', Description: 'S3 key for asset version "46b107d6db798ca46046b8669d057a4debcbdbaaddb6170400748c2f9e4f9d71"' }, + AssetParameters46b107d6db798ca46046b8669d057a4debcbdbaaddb6170400748c2f9e4f9d71ArtifactHash45A28583: { Type: 'String', Description: 'Artifact hash for asset "46b107d6db798ca46046b8669d057a4debcbdbaaddb6170400748c2f9e4f9d71"' }, + }); + + // asset proxy parameters are passed to the nested stack + expect(parent).toHaveResource('AWS::CloudFormation::Stack', { + Parameters: { + referencetoParentStackAssetParametersdb01ee2eb7adc7915e364dc410d861e569543f9be3761d535a68d5c2cc181281S3Bucket82C55B96Ref: { Ref: 'AssetParametersdb01ee2eb7adc7915e364dc410d861e569543f9be3761d535a68d5c2cc181281S3BucketC188F637' }, + referencetoParentStackAssetParametersdb01ee2eb7adc7915e364dc410d861e569543f9be3761d535a68d5c2cc181281S3VersionKeyA43C3CC6Ref: { Ref: 'AssetParametersdb01ee2eb7adc7915e364dc410d861e569543f9be3761d535a68d5c2cc181281S3VersionKeyC7F4DBF2' }, + }, + }); + + // parent stack should have 2 assets + expect(assembly.getStackByName(parent.stackName).assets.length).toEqual(2); +}); + +test('docker image assets are wired through the top-level stack', () => { + // GIVEN + const app = new App(); + const parent = new Stack(app, 'my-stack'); + const nested = new NestedStack(parent, 'nested-stack'); + + // WHEN + const location = nested.synthesizer.addDockerImageAsset({ + directoryName: 'my-image', + dockerBuildArgs: { key: 'value', boom: 'bam' }, + dockerBuildTarget: 'buildTarget', + sourceHash: 'hash-of-source', + }); + + // use the asset, so the parameters will be wired. + new sns.Topic(nested, 'MyTopic', { + displayName: `image location is ${location.imageUri}`, + }); + + // THEN + const asm = app.synth(); + expect(asm.getStackArtifact(parent.artifactId).assets).toEqual([ + { + repositoryName: 'aws-cdk/assets', + imageTag: 'hash-of-source', + id: 'hash-of-source', + packaging: 'container-image', + path: 'my-image', + sourceHash: 'hash-of-source', + buildArgs: { key: 'value', boom: 'bam' }, + target: 'buildTarget', + }, + { + path: 'mystacknestedstackFAE12FB5.nested.template.json', + id: 'fcdaee79eb79f37eca3a9b1cc0cc9ba150e4eea8c5d6d0c343cb6cd9dc68e2e5', + packaging: 'file', + sourceHash: 'fcdaee79eb79f37eca3a9b1cc0cc9ba150e4eea8c5d6d0c343cb6cd9dc68e2e5', + s3BucketParameter: 'AssetParametersfcdaee79eb79f37eca3a9b1cc0cc9ba150e4eea8c5d6d0c343cb6cd9dc68e2e5S3Bucket67A749F8', + s3KeyParameter: 'AssetParametersfcdaee79eb79f37eca3a9b1cc0cc9ba150e4eea8c5d6d0c343cb6cd9dc68e2e5S3VersionKeyE1E6A8D4', + artifactHashParameter: 'AssetParametersfcdaee79eb79f37eca3a9b1cc0cc9ba150e4eea8c5d6d0c343cb6cd9dc68e2e5ArtifactHash0AEDBE8A', + }, + ]); +}); + +test('metadata defined in nested stacks is reported at the parent stack level in the cloud assembly', () => { + // GIVEN + const app = new App({ stackTraces: false }); + const parent = new Stack(app, 'parent'); + const child = new Stack(parent, 'child'); + const nested = new NestedStack(child, 'nested'); + const resource = new CfnResource(nested, 'resource', { type: 'foo' }); + + // WHEN + resource.node.addMetadata('foo', 'bar'); + + // THEN: the first non-nested stack records the assembly metadata + const asm = app.synth(); + expect(asm.stacks.length).toEqual(2); // only one stack is defined as an artifact + expect(asm.getStackByName(parent.stackName).findMetadataByType('foo')).toEqual([]); + expect(asm.getStackByName(child.stackName).findMetadataByType('foo')).toEqual([ + { + path: '/parent/child/nested/resource', + type: 'foo', + data: 'bar', + }, + ]); +}); + +test('referencing attributes with period across stacks', () => { + // GIVEN + const parent = new Stack(); + const nested = new NestedStack(parent, 'nested'); + const consumed = new CfnResource(nested, 'resource-in-nested', { type: 'CONSUMED' }); + + // WHEN + new CfnResource(parent, 'resource-in-parent', { + type: 'CONSUMER', + properties: { + ConsumedAttribute: consumed.getAtt('Consumed.Attribute'), + }, + }); + + // THEN + expect(nested).toMatchTemplate({ + Resources: { + resourceinnested: { + Type: 'CONSUMED', + }, + }, + Outputs: { + nestedresourceinnested59B1F01CConsumedAttribute: { + Value: { + 'Fn::GetAtt': [ + 'resourceinnested', + 'Consumed.Attribute', + ], + }, + }, + }, + }); + + expect(parent).toHaveResource('CONSUMER', { + ConsumedAttribute: { + 'Fn::GetAtt': [ + 'nestedNestedStacknestedNestedStackResource3DD143BF', + 'Outputs.nestedresourceinnested59B1F01CConsumedAttribute', + ], + }, + }); +}); + +test('missing context in nested stack is reported if the context is not available', () => { + // GIVEN + const app = new App(); + const stack = new Stack(app, 'ParentStack', { env: { account: '1234account', region: 'us-east-44' } }); + const nestedStack = new NestedStack(stack, 'nested'); + const provider = 'availability-zones'; + const expectedKey = ContextProvider.getKey(nestedStack, { + provider, + }).key; + + // WHEN + ContextProvider.getValue(nestedStack, { + provider, + dummyValue: ['dummy1a', 'dummy1b', 'dummy1c'], + }); + + // THEN: missing context is reported in the cloud assembly + const asm = app.synth(); + const missing = asm.manifest.missing; + + expect(missing && missing.find(m => { + return (m.key === expectedKey); + })).toBeTruthy(); +}); + +test('3-level stacks: legacy synthesizer parameters are added to the middle-level stack', () => { + // GIVEN + const app = new App(); + const top = new Stack(app, 'stack', { + synthesizer: new LegacyStackSynthesizer(), + }); + const middle = new NestedStack(top, 'nested1'); + const bottom = new NestedStack(middle, 'nested2'); + + // WHEN + new CfnResource(bottom, 'Something', { + type: 'BottomLevel', + }); + + // THEN + const asm = app.synth(); + const middleTemplate = JSON.parse(fs.readFileSync(path.join(asm.directory, middle.templateFile), { encoding: 'utf-8' })); + + const hash = 'bc3c51e4d3545ee0a0069401e5a32c37b66d044b983f12de416ba1576ecaf0a4'; + expect(middleTemplate.Parameters ?? {}).toEqual({ + [`referencetostackAssetParameters${hash}S3BucketD7C30435Ref`]: { + Type: 'String', + }, + [`referencetostackAssetParameters${hash}S3VersionKeyB667DBE1Ref`]: { + Type: 'String', + }, + }); +}); + +test('references to a resource from a deeply nested stack', () => { + // GIVEN + const app = new App(); + const top = new Stack(app, 'stack'); + const topLevel = new CfnResource(top, 'toplevel', { type: 'TopLevel' }); + const nested1 = new NestedStack(top, 'nested1'); + const nested2 = new NestedStack(nested1, 'nested2'); + + // WHEN + new CfnResource(nested2, 'refToTopLevel', { + type: 'BottomLevel', + properties: { RefToTopLevel: topLevel.ref }, + }); + + // THEN + expect(top).toHaveResource('AWS::CloudFormation::Stack', { + Parameters: { + referencetostackAssetParameters842982bd421cce9742ba27151ef12ed699d44d22801f41e8029f63f2358a3f2fS3Bucket5DA5D2E7Ref: { + Ref: 'AssetParameters842982bd421cce9742ba27151ef12ed699d44d22801f41e8029f63f2358a3f2fS3BucketDD4D96B5', + }, + referencetostackAssetParameters842982bd421cce9742ba27151ef12ed699d44d22801f41e8029f63f2358a3f2fS3VersionKey8FBE5C12Ref: { + Ref: 'AssetParameters842982bd421cce9742ba27151ef12ed699d44d22801f41e8029f63f2358a3f2fS3VersionKey83E381F3', + }, + referencetostacktoplevelBB16BF13Ref: { + Ref: 'toplevel', + }, + }, + }); + + expect(nested1).toHaveResource('AWS::CloudFormation::Stack', { + Parameters: { + referencetostacktoplevelBB16BF13Ref: { + Ref: 'referencetostacktoplevelBB16BF13Ref', + }, + }, + }); + + expect(nested2).toMatchTemplate({ + Resources: { + refToTopLevel: { + Type: 'BottomLevel', + Properties: { + RefToTopLevel: { + Ref: 'referencetostacktoplevelBB16BF13Ref', + }, + }, + }, + }, + Parameters: { + referencetostacktoplevelBB16BF13Ref: { + Type: 'String', + }, + }, + }); +}); + +test('bottom nested stack consumes value from a top-level stack through a parameter in a middle nested stack', () => { + // GIVEN + const app = new App(); + const top = new Stack(app, 'Grandparent'); + const middle = new NestedStack(top, 'Parent'); + const bottom = new NestedStack(middle, 'Child'); + const resourceInGrandparent = new CfnResource(top, 'ResourceInGrandparent', { type: 'ResourceInGrandparent' }); + + // WHEN + new CfnResource(bottom, 'ResourceInChild', { + type: 'ResourceInChild', + properties: { + RefToGrandparent: resourceInGrandparent.ref, + }, + }); + + // THEN + + // this is the name allocated for the parameter that's propagated through + // the hierarchy. + const paramName = 'referencetoGrandparentResourceInGrandparent010E997ARef'; + + // child (bottom) references through a parameter. + expect(bottom).toMatchTemplate({ + Resources: { + ResourceInChild: { + Type: 'ResourceInChild', + Properties: { + RefToGrandparent: { Ref: paramName }, + }, + }, + }, + Parameters: { + [paramName]: { Type: 'String' }, + }, + }); + + // the parent (middle) sets the value of this parameter to be a reference to another parameter + expect(middle).toHaveResource('AWS::CloudFormation::Stack', { + Parameters: { + [paramName]: { Ref: paramName }, + }, + }); + + // grandparent (top) assigns the actual value to the parameter + expect(top).toHaveResource('AWS::CloudFormation::Stack', { + Parameters: { + [paramName]: { Ref: 'ResourceInGrandparent' }, + + // these are for the asset of the bottom nested stack + referencetoGrandparentAssetParameters3208f43b793a1dbe28ca02cf31fb975489071beb42c492b22dc3d32decc3b4b7S3Bucket06EEE58DRef: { + Ref: 'AssetParameters3208f43b793a1dbe28ca02cf31fb975489071beb42c492b22dc3d32decc3b4b7S3Bucket01877C2E', + }, + referencetoGrandparentAssetParameters3208f43b793a1dbe28ca02cf31fb975489071beb42c492b22dc3d32decc3b4b7S3VersionKeyD3B04909Ref: { + Ref: 'AssetParameters3208f43b793a1dbe28ca02cf31fb975489071beb42c492b22dc3d32decc3b4b7S3VersionKey5765F084', + }, + }, + }); +}); diff --git a/packages/@aws-cdk/aws-cloudformation/test/resource.test.ts b/packages/@aws-cdk/aws-cloudformation/test/resource.test.ts new file mode 100644 index 0000000000000..a3bd1944625ae --- /dev/null +++ b/packages/@aws-cdk/aws-cloudformation/test/resource.test.ts @@ -0,0 +1,220 @@ +import { ResourcePart } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; +import * as lambda from '@aws-cdk/aws-lambda'; +import * as sns from '@aws-cdk/aws-sns'; +import * as cdk from '@aws-cdk/core'; +import { CustomResource, CustomResourceProvider } from '../lib'; + +// keep this import separate from other imports to reduce chance for merge conflicts with v2-main +// eslint-disable-next-line no-duplicate-imports, import/order +import { Construct } from '@aws-cdk/core'; + +/* eslint-disable @aws-cdk/no-core-construct */ +/* eslint-disable quote-props */ + +describe('custom resources honor removalPolicy', () => { + test('unspecified (aka .Destroy)', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Test'); + + // WHEN + new TestCustomResource(stack, 'Custom'); + + // THEN + expect(stack).toHaveResource('AWS::CloudFormation::CustomResource', {}, ResourcePart.CompleteDefinition); + expect(app.synth().tryGetArtifact(stack.stackName)!.findMetadataByType('aws:cdk:protected').length).toEqual(0); + }); + + test('.Destroy', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Test'); + + // WHEN + new TestCustomResource(stack, 'Custom', { removalPolicy: cdk.RemovalPolicy.DESTROY }); + + // THEN + expect(stack).toHaveResource('AWS::CloudFormation::CustomResource', {}, ResourcePart.CompleteDefinition); + expect(app.synth().tryGetArtifact(stack.stackName)!.findMetadataByType('aws:cdk:protected').length).toEqual(0); + }); + + test('.Retain', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Test'); + + // WHEN + new TestCustomResource(stack, 'Custom', { removalPolicy: cdk.RemovalPolicy.RETAIN }); + + // THEN + expect(stack).toHaveResource('AWS::CloudFormation::CustomResource', { + DeletionPolicy: 'Retain', + UpdateReplacePolicy: 'Retain', + }, ResourcePart.CompleteDefinition); + }); +}); + +test('custom resource is added twice, lambda is added once', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Test'); + + // WHEN + new TestCustomResource(stack, 'Custom1'); + new TestCustomResource(stack, 'Custom2'); + + // THEN + expect(stack).toMatchTemplate({ + 'Resources': { + 'SingletonLambdaTestCustomResourceProviderServiceRole81FEAB5C': { + 'Type': 'AWS::IAM::Role', + 'Properties': { + 'AssumeRolePolicyDocument': { + 'Statement': [ + { + 'Action': 'sts:AssumeRole', + 'Effect': 'Allow', + 'Principal': { + 'Service': 'lambda.amazonaws.com', + }, + }, + ], + 'Version': '2012-10-17', + }, + 'ManagedPolicyArns': [ + { + 'Fn::Join': ['', [ + 'arn:', { 'Ref': 'AWS::Partition' }, ':iam::aws:policy/service-role/AWSLambdaBasicExecutionRole', + ]], + }, + ], + }, + }, + 'SingletonLambdaTestCustomResourceProviderA9255269': { + 'Type': 'AWS::Lambda::Function', + 'Properties': { + 'Code': { + 'ZipFile': 'def hello(): pass', + }, + 'Handler': 'index.hello', + 'Role': { + 'Fn::GetAtt': [ + 'SingletonLambdaTestCustomResourceProviderServiceRole81FEAB5C', + 'Arn', + ], + }, + 'Runtime': 'python2.7', + 'Timeout': 300, + }, + 'DependsOn': [ + 'SingletonLambdaTestCustomResourceProviderServiceRole81FEAB5C', + ], + }, + 'Custom1D319B237': { + 'Type': 'AWS::CloudFormation::CustomResource', + 'DeletionPolicy': 'Delete', + 'UpdateReplacePolicy': 'Delete', + 'Properties': { + 'ServiceToken': { + 'Fn::GetAtt': [ + 'SingletonLambdaTestCustomResourceProviderA9255269', + 'Arn', + ], + }, + }, + }, + 'Custom2DD5FB44D': { + 'Type': 'AWS::CloudFormation::CustomResource', + 'DeletionPolicy': 'Delete', + 'UpdateReplacePolicy': 'Delete', + 'Properties': { + 'ServiceToken': { + 'Fn::GetAtt': [ + 'SingletonLambdaTestCustomResourceProviderA9255269', + 'Arn', + ], + }, + }, + }, + }, + }); +}); + +test('custom resources can specify a resource type that starts with Custom::', () => { + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Test'); + new CustomResource(stack, 'MyCustomResource', { + resourceType: 'Custom::MyCustomResourceType', + provider: CustomResourceProvider.fromTopic(new sns.Topic(stack, 'Provider')), + }); + expect(stack).toHaveResource('Custom::MyCustomResourceType'); +}); + +describe('fails if custom resource type is invalid', () => { + test('does not start with "Custom::"', () => { + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Test'); + + expect(() => { + new CustomResource(stack, 'MyCustomResource', { + resourceType: 'NoCustom::MyCustomResourceType', + provider: CustomResourceProvider.fromTopic(new sns.Topic(stack, 'Provider')), + }); + }).toThrow(/Custom resource type must begin with "Custom::"/); + }); + + test('has invalid characters', () => { + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Test'); + + expect(() => { + new CustomResource(stack, 'MyCustomResource', { + resourceType: 'Custom::My Custom?ResourceType', + provider: CustomResourceProvider.fromTopic(new sns.Topic(stack, 'Provider')), + }); + }).toThrow(/Custom resource type name can only include alphanumeric characters and/); + }); + + test('is longer than 60 characters', () => { + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Test'); + + expect(() => { + new CustomResource(stack, 'MyCustomResource', { + resourceType: 'Custom::0123456789012345678901234567890123456789012345678901234567891', + provider: CustomResourceProvider.fromTopic(new sns.Topic(stack, 'Provider')), + }); + }).toThrow(/Custom resource type length > 60/); + }); +}); + +test('.ref returns the intrinsic reference (physical name)', () => { + // GIVEN + const stack = new cdk.Stack(); + const res = new TestCustomResource(stack, 'myResource'); + + // THEN + expect(stack.resolve(res.resource.ref)).toEqual({ Ref: 'myResourceC6A188A9' }); +}); + +class TestCustomResource extends Construct { + public readonly resource: CustomResource; + + constructor(scope: Construct, id: string, opts: { removalPolicy?: cdk.RemovalPolicy } = {}) { + super(scope, id); + + const singletonLambda = new lambda.SingletonFunction(this, 'Lambda', { + uuid: 'TestCustomResourceProvider', + code: new lambda.InlineCode('def hello(): pass'), + runtime: lambda.Runtime.PYTHON_2_7, + handler: 'index.hello', + timeout: cdk.Duration.minutes(5), + }); + + this.resource = new CustomResource(this, 'Resource', { + ...opts, + provider: CustomResourceProvider.fromLambda(singletonLambda), + }); + } +} diff --git a/packages/@aws-cdk/aws-cloudformation/test/test.deps.ts b/packages/@aws-cdk/aws-cloudformation/test/test.deps.ts deleted file mode 100644 index de239daffb9a8..0000000000000 --- a/packages/@aws-cdk/aws-cloudformation/test/test.deps.ts +++ /dev/null @@ -1,362 +0,0 @@ -import * as fs from 'fs'; -import * as path from 'path'; -import { expect, haveResource, ResourcePart } from '@aws-cdk/assert-internal'; -import { App, CfnResource, Stack } from '@aws-cdk/core'; -import * as cxapi from '@aws-cdk/cx-api'; -import { Test } from 'nodeunit'; -import { NestedStack } from '../lib'; - -export = { - - 'resource dependencies': { - - 'between two resources in a top-level stack'(test: Test) { - // GIVEN - const app = new App(); - const stack = new Stack(app, 'Stack'); - const r1 = new CfnResource(stack, 'r1', { type: 'r1' }); - const r2 = new CfnResource(stack, 'r2', { type: 'r2' }); - - // WHEN - r1.addDependsOn(r2); - - // THEN - test.deepEqual(app.synth().getStackArtifact(stack.artifactId).template, { - Resources: - { r1: { Type: 'r1', DependsOn: ['r2'] }, r2: { Type: 'r2' } }, - }); - - test.done(); - }, - - 'resource in nested stack depends on a resource in the parent stack': matrixForResourceDependencyTest((test, addDep) => { - // GIVEN - const parent = new Stack(undefined, 'root'); - const nested = new NestedStack(parent, 'Nested'); - const resourceInParent = new CfnResource(parent, 'ResourceInParent', { type: 'PARENT' }); - const resourceInNested = new CfnResource(nested, 'ResourceInNested', { type: 'NESTED' }); - - // WHEN - addDep(resourceInNested, resourceInParent); - - // THEN: the dependency needs to transfer from the resource within the - // nested stack to the nested stack resource itself so the nested stack - // will only be deployed the dependent resource - expect(parent).to(haveResource('AWS::CloudFormation::Stack', { DependsOn: ['ResourceInParent'] }, ResourcePart.CompleteDefinition)); - expect(nested).toMatch({ Resources: { ResourceInNested: { Type: 'NESTED' } } }); // no DependsOn for the actual resource - test.done(); - }), - - 'resource in nested stack depends on a resource in a grandparent stack': matrixForResourceDependencyTest((test, addDep) => { - // GIVEN - const grantparent = new Stack(undefined, 'Grandparent'); - const parent = new NestedStack(grantparent, 'Parent'); - const nested = new NestedStack(parent, 'Nested'); - const resourceInGrandparent = new CfnResource(grantparent, 'ResourceInGrandparent', { type: 'GRANDPARENT' }); - const resourceInNested = new CfnResource(nested, 'ResourceInNested', { type: 'NESTED' }); - - // WHEN - addDep(resourceInNested, resourceInGrandparent); - - // THEN: the dependency needs to transfer from the resource within the - // nested stack to the *parent* nested stack - expect(grantparent).to(haveResource('AWS::CloudFormation::Stack', { DependsOn: ['ResourceInGrandparent'] }, ResourcePart.CompleteDefinition)); - expect(nested).toMatch({ Resources: { ResourceInNested: { Type: 'NESTED' } } }); // no DependsOn for the actual resource - test.done(); - }), - - 'resource in parent stack depends on resource in nested stack': matrixForResourceDependencyTest((test, addDep) => { - // GIVEN - const parent = new Stack(undefined, 'root'); - const nested = new NestedStack(parent, 'Nested'); - const resourceInParent = new CfnResource(parent, 'ResourceInParent', { type: 'PARENT' }); - const resourceInNested = new CfnResource(nested, 'ResourceInNested', { type: 'NESTED' }); - - // WHEN - addDep(resourceInParent, resourceInNested); - - // THEN: resource in parent needs to depend on the nested stack - expect(parent).to(haveResource('PARENT', { - DependsOn: [parent.resolve(nested.nestedStackResource!.logicalId)], - }, ResourcePart.CompleteDefinition)); - test.done(); - }), - - 'resource in grantparent stack depends on resource in nested stack': matrixForResourceDependencyTest((test, addDep) => { - // GIVEN - const grandparent = new Stack(undefined, 'Grandparent'); - const parent = new NestedStack(grandparent, 'Parent'); - const nested = new NestedStack(parent, 'Nested'); - const resourceInGrandparent = new CfnResource(grandparent, 'ResourceInGrandparent', { type: 'GRANDPARENT' }); - const resourceInNested = new CfnResource(nested, 'ResourceInNested', { type: 'NESTED' }); - - // WHEN - addDep(resourceInGrandparent, resourceInNested); - - // THEN: resource in grantparent needs to depend on the top-level nested stack - expect(grandparent).to(haveResource('GRANDPARENT', { - DependsOn: [grandparent.resolve(parent.nestedStackResource!.logicalId)], - }, ResourcePart.CompleteDefinition)); - - test.done(); - }), - - 'resource in sibling stack depends on a resource in nested stack': matrixForResourceDependencyTest((test, addDep) => { - // GIVEN - const app = new App(); - const stack1 = new Stack(app, 'Stack1'); - const nested1 = new NestedStack(stack1, 'Nested1'); - const resourceInNested1 = new CfnResource(nested1, 'ResourceInNested', { type: 'NESTED' }); - const stack2 = new Stack(app, 'Stack2'); - const resourceInStack2 = new CfnResource(stack2, 'ResourceInSibling', { type: 'SIBLING' }); - - // WHEN - addDep(resourceInStack2, resourceInNested1); - - // THEN: stack2 should depend on stack1 and no "DependsOn" inside templates - const assembly = app.synth(); - assertAssemblyDependency(test, assembly, stack1, []); - assertAssemblyDependency(test, assembly, stack2, ['Stack1']); - assertNoDependsOn(test, assembly, stack1); - assertNoDependsOn(test, assembly, stack2); - assertNoDependsOn(test, assembly, nested1); - test.done(); - }), - - 'resource in nested stack depends on a resource in sibling stack': matrixForResourceDependencyTest((test, addDep) => { - // GIVEN - const app = new App(); - const stack1 = new Stack(app, 'Stack1'); - const nested1 = new NestedStack(stack1, 'Nested1'); - const resourceInNested1 = new CfnResource(nested1, 'ResourceInNested', { type: 'NESTED' }); - const stack2 = new Stack(app, 'Stack2'); - const resourceInStack2 = new CfnResource(stack2, 'ResourceInSibling', { type: 'SIBLING' }); - - // WHEN - addDep(resourceInNested1, resourceInStack2); - - // THEN: stack1 should depend on stack2 and no "DependsOn" inside templates - const assembly = app.synth(); - assertAssemblyDependency(test, assembly, stack1, ['Stack2']); - assertAssemblyDependency(test, assembly, stack2, []); - assertNoDependsOn(test, assembly, stack1); - assertNoDependsOn(test, assembly, stack2); - assertNoDependsOn(test, assembly, nested1); - test.done(); - }), - - 'resource in nested stack depends on a resource in nested sibling stack': matrixForResourceDependencyTest((test, addDep) => { - // GIVEN - const app = new App(); - const stack = new Stack(app, 'Stack1'); - const nested1 = new NestedStack(stack, 'Nested1'); - const nested2 = new NestedStack(stack, 'Nested2'); - const resourceInNested1 = new CfnResource(nested1, 'ResourceInNested1', { type: 'NESTED1' }); - const resourceInNested2 = new CfnResource(nested2, 'ResourceInNested2', { type: 'NESTED2' }); - - // WHEN - addDep(resourceInNested1, resourceInNested2); - - // THEN: dependency transfered to nested stack resources - expect(stack).to(haveResource('AWS::CloudFormation::Stack', { - DependsOn: [stack.resolve(nested2.nestedStackResource!.logicalId)], - }, ResourcePart.CompleteDefinition)); - - expect(stack).notTo(haveResource('AWS::CloudFormation::Stack', { - DependsOn: [stack.resolve(nested1.nestedStackResource!.logicalId)], - }, ResourcePart.CompleteDefinition)); - - test.done(); - }), - - }, - - 'stack dependencies': { - - 'top level stack depends on itself'(test: Test) { - // GIVEN - const app = new App(); - const stack = new Stack(app, 'Stack'); - - // WHEN - stack.addDependency(stack); - - // THEN - const assembly = app.synth(); - assertAssemblyDependency(test, assembly, stack, []); - assertNoDependsOn(test, assembly, stack); - test.done(); - }, - - 'nested stack depends on itself'(test: Test) { - // GIVEN - const app = new App(); - const parent = new Stack(app, 'Parent'); - const nested = new NestedStack(parent, 'Nested'); - - // WHEN - nested.addDependency(nested); - - // THEN - assertNoDependsOn(test, app.synth(), parent); - test.done(); - }, - - 'nested stack cannot depend on any of its parents'(test: Test) { - // GIVEN - const root = new Stack(); - const nested1 = new NestedStack(root, 'Nested1'); - const nested2 = new NestedStack(nested1, 'Nested2'); - - // THEN - test.throws(() => nested1.addDependency(root), /Nested stack 'Default\/Nested1' cannot depend on a parent stack 'Default'/); - test.throws(() => nested2.addDependency(nested1), /Nested stack 'Default\/Nested1\/Nested2' cannot depend on a parent stack 'Default\/Nested1'/); - test.throws(() => nested2.addDependency(root), /Nested stack 'Default\/Nested1\/Nested2' cannot depend on a parent stack 'Default'/); - test.done(); - }, - - 'any parent stack is by definition dependent on the nested stack so dependency is ignored'(test: Test) { - // GIVEN - const root = new Stack(); - const nested1 = new NestedStack(root, 'Nested1'); - const nested2 = new NestedStack(nested1, 'Nested2'); - - // WHEN - root.addDependency(nested1); - root.addDependency(nested2); - nested1.addDependency(nested2); - - // THEN - test.done(); - }, - - 'sibling nested stacks transfer to resources'(test: Test) { - // GIVEN - const stack = new Stack(); - const nested1 = new NestedStack(stack, 'Nested1'); - const nested2 = new NestedStack(stack, 'Nested2'); - - // WHEN - nested1.addDependency(nested2); - - // THEN - expect(stack).to(haveResource('AWS::CloudFormation::Stack', { - DependsOn: [stack.resolve(nested2.nestedStackResource!.logicalId)], - }, ResourcePart.CompleteDefinition)); - test.done(); - }, - - 'nested stack depends on a deeply nested stack'(test: Test) { - // GIVEN - const stack = new Stack(); - const nested1 = new NestedStack(stack, 'Nested1'); - const nested2 = new NestedStack(stack, 'Nested2'); - const nested21 = new NestedStack(nested2, 'Nested21'); - - // WHEN - nested1.addDependency(nested21); - - // THEN: transfered to a resource dep between the resources in the common stack - expect(stack).to(haveResource('AWS::CloudFormation::Stack', { - DependsOn: [stack.resolve(nested2.nestedStackResource!.logicalId)], - }, ResourcePart.CompleteDefinition)); - test.done(); - }, - - 'deeply nested stack depends on a parent nested stack'(test: Test) { - // GIVEN - const stack = new Stack(); - const nested1 = new NestedStack(stack, 'Nested1'); - const nested2 = new NestedStack(stack, 'Nested2'); - const nested21 = new NestedStack(nested2, 'Nested21'); - - // WHEN - nested21.addDependency(nested1); - - // THEN: transfered to a resource dep between the resources in the common stack - expect(stack).to(haveResource('AWS::CloudFormation::Stack', { - DependsOn: [stack.resolve(nested1.nestedStackResource!.logicalId)], - }, ResourcePart.CompleteDefinition)); - test.done(); - }, - - 'top-level stack depends on a nested stack within a sibling'(test: Test) { - // GIVEN - const app = new App(); - const stack1 = new Stack(app, 'Stack1'); - const nested1 = new NestedStack(stack1, 'Nested1'); - const stack2 = new Stack(app, 'Stack2'); - - // WHEN - stack2.addDependency(nested1); - - // THEN: assembly-level dependency between stack2 and stack1 - const assembly = app.synth(); - assertAssemblyDependency(test, assembly, stack2, ['Stack1']); - assertAssemblyDependency(test, assembly, stack1, []); - assertNoDependsOn(test, assembly, stack1); - assertNoDependsOn(test, assembly, stack2); - assertNoDependsOn(test, assembly, nested1); - test.done(); - }, - - 'nested stack within a sibling depends on top-level stack'(test: Test) { - // GIVEN - const app = new App(); - const stack1 = new Stack(app, 'Stack1'); - const nested1 = new NestedStack(stack1, 'Nested1'); - const stack2 = new Stack(app, 'Stack2'); - - // WHEN - nested1.addDependency(stack2); - - // THEN: assembly-level dependency between stack2 and stack1 - const assembly = app.synth(); - assertAssemblyDependency(test, assembly, stack2, []); - assertAssemblyDependency(test, assembly, stack1, ['Stack2']); - assertNoDependsOn(test, assembly, stack1); - assertNoDependsOn(test, assembly, stack2); - assertNoDependsOn(test, assembly, nested1); - test.done(); - }, - - }, - -}; - -/** - * Given a test function which sets the stage and verifies a dependency scenario - * between two CloudFormation resources, returns two tests which exercise both - * "construct dependency" (i.e. node.addDependency) and "resource dependency" - * (i.e. resource.addDependsOn). - * - * @param testFunction The test function - */ -function matrixForResourceDependencyTest(testFunction: (test: Test, addDep: (source: CfnResource, target: CfnResource) => void) => void) { - return { - 'construct dependency'(test: Test) { - testFunction(test, (source, target) => source.node.addDependency(target)); - }, - 'resource dependency'(test: Test) { - testFunction(test, (source, target) => source.addDependsOn(target)); - }, - }; -} - -function assertAssemblyDependency(test: Test, assembly: cxapi.CloudAssembly, stack: Stack, expectedDeps: string[]) { - const stack1Art = assembly.getStackArtifact(stack.artifactId); - const stack1Deps = stack1Art.dependencies.map(x => x.id); - test.deepEqual(stack1Deps, expectedDeps); -} - -function assertNoDependsOn(test: Test, assembly: cxapi.CloudAssembly, stack: Stack) { - let templateText; - if (!(stack instanceof NestedStack)) { - templateText = JSON.stringify(assembly.getStackArtifact(stack.artifactId).template); - } else { - templateText = fs.readFileSync(path.join(assembly.directory, stack.templateFile), 'utf-8'); - } - - // verify templates do not have any "DependsOn" - test.ok(!templateText.includes('DependsOn')); -} diff --git a/packages/@aws-cdk/aws-cloudformation/test/test.nested-stack.ts b/packages/@aws-cdk/aws-cloudformation/test/test.nested-stack.ts deleted file mode 100644 index 29358708b0796..0000000000000 --- a/packages/@aws-cdk/aws-cloudformation/test/test.nested-stack.ts +++ /dev/null @@ -1,1127 +0,0 @@ -import * as fs from 'fs'; -import * as path from 'path'; -import { expect, haveResource, matchTemplate, SynthUtils } from '@aws-cdk/assert-internal'; -import * as s3_assets from '@aws-cdk/aws-s3-assets'; -import * as sns from '@aws-cdk/aws-sns'; -import { App, CfnParameter, CfnResource, ContextProvider, LegacyStackSynthesizer, Names, Stack } from '@aws-cdk/core'; -import { Test } from 'nodeunit'; -import { NestedStack } from '../lib/nested-stack'; - -// keep this import separate from other imports to reduce chance for merge conflicts with v2-main -// eslint-disable-next-line no-duplicate-imports, import/order -import { Construct } from '@aws-cdk/core'; - -/* eslint-disable cdk/no-core-construct */ -/* eslint-disable max-len */ - -export = { - 'fails if defined as a root'(test: Test) { - // THEN - test.throws(() => new NestedStack(undefined as any, 'boom'), /Nested stacks cannot be defined as a root construct/); - test.done(); - }, - - 'fails if defined without a parent stack'(test: Test) { - // GIVEN - const app = new App(); - const group = new Construct(app, 'group'); - - // THEN - test.throws(() => new NestedStack(app, 'boom'), /must be defined within scope of another non-nested stack/); - test.throws(() => new NestedStack(group, 'bam'), /must be defined within scope of another non-nested stack/); - test.done(); - }, - - 'can be defined as a direct child or an indirect child of a Stack'(test: Test) { - // GIVEN - const parent = new Stack(); - - // THEN - new NestedStack(parent, 'direct'); - new NestedStack(new Construct(parent, 'group'), 'indirect'); - test.done(); - }, - - 'nested stack is not synthesized as a stack artifact into the assembly'(test: Test) { - // GIVEN - const app = new App(); - const parentStack = new Stack(app, 'parent-stack'); - new NestedStack(parentStack, 'nested-stack'); - - // WHEN - const assembly = app.synth(); - - // THEN - test.deepEqual(assembly.artifacts.length, 2); - test.done(); - }, - - 'the template of the nested stack is synthesized into the cloud assembly'(test: Test) { - // GIVEN - const app = new App(); - const parent = new Stack(app, 'parent-stack'); - const nested = new NestedStack(parent, 'nested-stack'); - new CfnResource(nested, 'ResourceInNestedStack', { type: 'AWS::Resource::Nested' }); - - // WHEN - const assembly = app.synth(); - - // THEN - const template = JSON.parse(fs.readFileSync(path.join(assembly.directory, `${Names.uniqueId(nested)}.nested.template.json`), 'utf-8')); - test.deepEqual(template, { - Resources: { - ResourceInNestedStack: { - Type: 'AWS::Resource::Nested', - }, - }, - }); - test.done(); - }, - - 'file asset metadata is associated with the parent stack'(test: Test) { - // GIVEN - const app = new App(); - const parent = new Stack(app, 'parent-stack'); - const nested = new NestedStack(parent, 'nested-stack'); - new CfnResource(nested, 'ResourceInNestedStack', { type: 'AWS::Resource::Nested' }); - - // WHEN - const assembly = app.synth(); - - // THEN - test.deepEqual(assembly.getStackByName(parent.stackName).assets, [{ - path: 'parentstacknestedstack844892C0.nested.template.json', - id: 'c639c0a5e7320758aa22589669ecebc98f185b711300b074f53998c8f9a45096', - packaging: 'file', - sourceHash: 'c639c0a5e7320758aa22589669ecebc98f185b711300b074f53998c8f9a45096', - s3BucketParameter: 'AssetParametersc639c0a5e7320758aa22589669ecebc98f185b711300b074f53998c8f9a45096S3BucketDA8C3345', - s3KeyParameter: 'AssetParametersc639c0a5e7320758aa22589669ecebc98f185b711300b074f53998c8f9a45096S3VersionKey09D03EE6', - artifactHashParameter: 'AssetParametersc639c0a5e7320758aa22589669ecebc98f185b711300b074f53998c8f9a45096ArtifactHash8DE450C7', - }]); - test.done(); - }, - - 'aws::cloudformation::stack is synthesized in the parent scope'(test: Test) { - // GIVEN - const app = new App(); - const parent = new Stack(app, 'parent-stack'); - - // WHEN - const nested = new NestedStack(parent, 'nested-stack'); - new CfnResource(nested, 'ResourceInNestedStack', { type: 'AWS::Resource::Nested' }); - - // THEN - const assembly = app.synth(); - - // assembly has one stack (the parent) - test.deepEqual(assembly.stacks.length, 1); - - // but this stack has an asset that points to the synthesized template - test.deepEqual(assembly.stacks[0].assets[0].path, 'parentstacknestedstack844892C0.nested.template.json'); - - // the template includes our resource - const filePath = path.join(assembly.directory, assembly.stacks[0].assets[0].path); - test.deepEqual(JSON.parse(fs.readFileSync(filePath).toString('utf-8')), { - Resources: { ResourceInNestedStack: { Type: 'AWS::Resource::Nested' } }, - }); - - // the parent template includes the parameters and the nested stack resource which points to the s3 url - expect(parent).toMatch({ - Resources: { - nestedstackNestedStacknestedstackNestedStackResource71CDD241: { - Type: 'AWS::CloudFormation::Stack', - DeletionPolicy: 'Delete', - UpdateReplacePolicy: 'Delete', - Properties: { - TemplateURL: { - 'Fn::Join': [ - '', - [ - 'https://s3.', - { - Ref: 'AWS::Region', - }, - '.', - { - Ref: 'AWS::URLSuffix', - }, - '/', - { - Ref: 'AssetParametersc639c0a5e7320758aa22589669ecebc98f185b711300b074f53998c8f9a45096S3BucketDA8C3345', - }, - '/', - { - 'Fn::Select': [ - 0, - { - 'Fn::Split': [ - '||', - { - Ref: 'AssetParametersc639c0a5e7320758aa22589669ecebc98f185b711300b074f53998c8f9a45096S3VersionKey09D03EE6', - }, - ], - }, - ], - }, - { - 'Fn::Select': [ - 1, - { - 'Fn::Split': [ - '||', - { - Ref: 'AssetParametersc639c0a5e7320758aa22589669ecebc98f185b711300b074f53998c8f9a45096S3VersionKey09D03EE6', - }, - ], - }, - ], - }, - ], - ], - }, - }, - }, - }, - Parameters: { - AssetParametersc639c0a5e7320758aa22589669ecebc98f185b711300b074f53998c8f9a45096S3BucketDA8C3345: { - Type: 'String', - Description: 'S3 bucket for asset "c639c0a5e7320758aa22589669ecebc98f185b711300b074f53998c8f9a45096"', - }, - AssetParametersc639c0a5e7320758aa22589669ecebc98f185b711300b074f53998c8f9a45096S3VersionKey09D03EE6: { - Type: 'String', - Description: 'S3 key for asset version "c639c0a5e7320758aa22589669ecebc98f185b711300b074f53998c8f9a45096"', - }, - AssetParametersc639c0a5e7320758aa22589669ecebc98f185b711300b074f53998c8f9a45096ArtifactHash8DE450C7: { - Type: 'String', - Description: 'Artifact hash for asset "c639c0a5e7320758aa22589669ecebc98f185b711300b074f53998c8f9a45096"', - }, - }, - }); - test.done(); - }, - - 'Stack.of()'(test: Test) { - class MyNestedStack extends NestedStack { - public readonly stackOfChild: Stack; - - constructor(scope: Construct, id: string) { - super(scope, id); - - const param = new CfnParameter(this, 'param', { type: 'String' }); - this.stackOfChild = Stack.of(param); - } - } - - const parent = new Stack(); - const nested = new MyNestedStack(parent, 'nested'); - - test.ok(nested.stackOfChild === nested); - test.ok(Stack.of(nested) === nested); - test.done(); - }, - - 'references within the nested stack are not reported as cross stack references'(test: Test) { - class MyNestedStack extends NestedStack { - constructor(scope: Construct, id: string) { - super(scope, id); - - const param = new CfnParameter(this, 'param', { type: 'String' }); - new CfnResource(this, 'resource', { - type: 'My::Resource', - properties: { - SomeProp: param.valueAsString, - }, - }); - } - } - - const app = new App(); - const parent = new Stack(app, 'parent'); - - new MyNestedStack(parent, 'nested'); - - // references are added during "prepare" - const assembly = app.synth(); - - test.deepEqual(assembly.stacks.length, 1); - test.deepEqual(assembly.stacks[0].dependencies, []); - test.done(); - }, - - 'references to a resource from the parent stack in a nested stack is translated into a cfn parameter'(test: Test) { - // WHEN - class MyNestedStack extends NestedStack { - - constructor(scope: Construct, id: string, resourceFromParent: CfnResource) { - super(scope, id); - - new CfnResource(this, 'resource', { - type: 'AWS::Child::Resource', - properties: { - ReferenceToResourceInParentStack: resourceFromParent.ref, - }, - }); - - new CfnResource(this, 'resource2', { - type: 'My::Resource::2', - properties: { - Prop1: resourceFromParent.getAtt('Attr'), - Prop2: resourceFromParent.ref, - }, - }); - } - } - - const app = new App(); - const parentStack = new Stack(app, 'parent'); - - const resource = new CfnResource(parentStack, 'parent-resource', { type: 'AWS::Parent::Resource' }); - - const nested = new MyNestedStack(parentStack, 'nested', resource); - - // THEN - app.synth(); - - // nested template should use a parameter to reference the resource from the parent stack - expect(nested).toMatch({ - Resources: - { - resource: - { - Type: 'AWS::Child::Resource', - Properties: - { ReferenceToResourceInParentStack: { Ref: 'referencetoparentparentresourceD56EA8F7Ref' } }, - }, - resource2: - { - Type: 'My::Resource::2', - Properties: - { - Prop1: { Ref: 'referencetoparentparentresourceD56EA8F7Attr' }, - Prop2: { Ref: 'referencetoparentparentresourceD56EA8F7Ref' }, - }, - }, - }, - Parameters: - { - referencetoparentparentresourceD56EA8F7Ref: { Type: 'String' }, - referencetoparentparentresourceD56EA8F7Attr: { Type: 'String' }, - }, - }); - - // parent template should pass in the value through the parameter - expect(parentStack).to(haveResource('AWS::CloudFormation::Stack', { - Parameters: { - referencetoparentparentresourceD56EA8F7Ref: { - Ref: 'parentresource', - }, - referencetoparentparentresourceD56EA8F7Attr: { - 'Fn::GetAtt': [ - 'parentresource', - 'Attr', - ], - }, - }, - })); - - test.done(); - }, - - 'references to a resource in the nested stack in the parent is translated into a cfn output'(test: Test) { - class MyNestedStack extends NestedStack { - public readonly resourceFromChild: CfnResource; - - constructor(scope: Construct, id: string) { - super(scope, id); - - this.resourceFromChild = new CfnResource(this, 'resource', { - type: 'AWS::Child::Resource', - }); - } - } - - const app = new App(); - const parentStack = new Stack(app, 'parent'); - - const nested = new MyNestedStack(parentStack, 'nested'); - - new CfnResource(parentStack, 'another-parent-resource', { - type: 'AWS::Parent::Resource', - properties: { - RefToResourceInNestedStack: nested.resourceFromChild.ref, - }, - }); - - // references are added during "prepare" - app.synth(); - - // nested template should use a parameter to reference the resource from the parent stack - expect(nested).toMatch({ - Resources: { - resource: { Type: 'AWS::Child::Resource' }, - }, - Outputs: { - parentnestedresource4D680677Ref: { Value: { Ref: 'resource' } }, - }, - }); - - // parent template should pass in the value through the parameter - expect(parentStack).to(haveResource('AWS::Parent::Resource', { - RefToResourceInNestedStack: { - 'Fn::GetAtt': [ - 'nestedNestedStacknestedNestedStackResource3DD143BF', - 'Outputs.parentnestedresource4D680677Ref', - ], - }, - })); - - test.done(); - }, - - 'nested stack references a resource from another non-nested stack (not the parent)'(test: Test) { - // GIVEN - const app = new App(); - const stack1 = new Stack(app, 'Stack1'); - const stack2 = new Stack(app, 'Stack2'); - const nestedUnderStack1 = new NestedStack(stack1, 'NestedUnderStack1'); - const resourceInStack2 = new CfnResource(stack2, 'ResourceInStack2', { type: 'MyResource' }); - - // WHEN - new CfnResource(nestedUnderStack1, 'ResourceInNestedStack1', { - type: 'Nested::Resource', - properties: { - RefToSibling: resourceInStack2.getAtt('MyAttribute'), - }, - }); - - // THEN - const assembly = app.synth(); - - // producing stack should have an export - expect(stack2).toMatch({ - Resources: { - ResourceInStack2: { Type: 'MyResource' }, - }, - Outputs: { - ExportsOutputFnGetAttResourceInStack2MyAttributeC15F1009: { - Value: { 'Fn::GetAtt': ['ResourceInStack2', 'MyAttribute'] }, - Export: { Name: 'Stack2:ExportsOutputFnGetAttResourceInStack2MyAttributeC15F1009' }, - }, - }, - }); - - // nested stack uses Fn::ImportValue like normal - expect(nestedUnderStack1).toMatch({ - Resources: { - ResourceInNestedStack1: { - Type: 'Nested::Resource', - Properties: { - RefToSibling: { - 'Fn::ImportValue': 'Stack2:ExportsOutputFnGetAttResourceInStack2MyAttributeC15F1009', - }, - }, - }, - }, - }); - - // verify a depedency was established between the parents - const stack1Artifact = assembly.getStackByName(stack1.stackName); - const stack2Artifact = assembly.getStackByName(stack2.stackName); - test.deepEqual(stack1Artifact.dependencies.length, 1); - test.deepEqual(stack2Artifact.dependencies.length, 0); - test.same(stack1Artifact.dependencies[0], stack2Artifact); - test.done(); - }, - - 'nested stack within a nested stack references a resource in a sibling top-level stack'(test: Test) { - // GIVEN - const app = new App(); - const consumerTopLevel = new Stack(app, 'ConsumerTopLevel'); - const consumerNested1 = new NestedStack(consumerTopLevel, 'ConsumerNested1'); - const consumerNested2 = new NestedStack(consumerNested1, 'ConsumerNested2'); - const producerTopLevel = new Stack(app, 'ProducerTopLevel'); - const producer = new CfnResource(producerTopLevel, 'Producer', { type: 'Producer' }); - - // WHEN - new CfnResource(consumerNested2, 'Consumer', { - type: 'Consumer', - properties: { - Ref: producer.ref, - }, - }); - - // THEN - const manifest = app.synth(); - const consumerDeps = manifest.getStackArtifact(consumerTopLevel.artifactId).dependencies.map(d => d.id); - test.deepEqual(consumerDeps, ['ProducerTopLevel']); - test.done(); - }, - - 'another non-nested stack takes a reference on a resource within the nested stack (the parent exports)'(test: Test) { - // GIVEN - const app = new App(); - const stack1 = new Stack(app, 'Stack1'); - const stack2 = new Stack(app, 'Stack2'); - const nestedUnderStack1 = new NestedStack(stack1, 'NestedUnderStack1'); - const resourceInNestedStack = new CfnResource(nestedUnderStack1, 'ResourceInNestedStack', { type: 'MyResource' }); - - // WHEN - new CfnResource(stack2, 'ResourceInStack2', { - type: 'JustResource', - properties: { - RefToSibling: resourceInNestedStack.getAtt('MyAttribute'), - }, - }); - - // THEN - const assembly = app.synth(); - - // nested stack should output this value as if it was referenced by the parent (without the export) - expect(nestedUnderStack1).toMatch({ - Resources: { - ResourceInNestedStack: { - Type: 'MyResource', - }, - }, - Outputs: { - Stack1NestedUnderStack1ResourceInNestedStack6EE9DCD2MyAttribute: { - Value: { - 'Fn::GetAtt': [ - 'ResourceInNestedStack', - 'MyAttribute', - ], - }, - }, - }, - }); - - // parent stack (stack1) should export this value - test.deepEqual(assembly.getStackByName(stack1.stackName).template.Outputs, { - ExportsOutputFnGetAttNestedUnderStack1NestedStackNestedUnderStack1NestedStackResourceF616305BOutputsStack1NestedUnderStack1ResourceInNestedStack6EE9DCD2MyAttribute564EECF3: { - Value: { 'Fn::GetAtt': ['NestedUnderStack1NestedStackNestedUnderStack1NestedStackResourceF616305B', 'Outputs.Stack1NestedUnderStack1ResourceInNestedStack6EE9DCD2MyAttribute'] }, - Export: { Name: 'Stack1:ExportsOutputFnGetAttNestedUnderStack1NestedStackNestedUnderStack1NestedStackResourceF616305BOutputsStack1NestedUnderStack1ResourceInNestedStack6EE9DCD2MyAttribute564EECF3' }, - }, - }); - - // consuming stack should use ImportValue to import the value from the parent stack - expect(stack2).toMatch({ - Resources: { - ResourceInStack2: { - Type: 'JustResource', - Properties: { - RefToSibling: { - 'Fn::ImportValue': 'Stack1:ExportsOutputFnGetAttNestedUnderStack1NestedStackNestedUnderStack1NestedStackResourceF616305BOutputsStack1NestedUnderStack1ResourceInNestedStack6EE9DCD2MyAttribute564EECF3', - }, - }, - }, - }, - }); - - test.deepEqual(assembly.stacks.length, 2); - const stack1Artifact = assembly.getStackByName(stack1.stackName); - const stack2Artifact = assembly.getStackByName(stack2.stackName); - test.deepEqual(stack1Artifact.dependencies.length, 0); - test.deepEqual(stack2Artifact.dependencies.length, 1); - test.same(stack2Artifact.dependencies[0], stack1Artifact); - test.done(); - }, - - 'references between sibling nested stacks should output from one and getAtt from the other'(test: Test) { - // GIVEN - const app = new App(); - const parent = new Stack(app, 'Parent'); - const nested1 = new NestedStack(parent, 'Nested1'); - const nested2 = new NestedStack(parent, 'Nested2'); - const resource1 = new CfnResource(nested1, 'Resource1', { type: 'Resource1' }); - - // WHEN - new CfnResource(nested2, 'Resource2', { - type: 'Resource2', - properties: { - RefToResource1: resource1.ref, - }, - }); - - // THEN - app.synth(); - - // producing nested stack - expect(nested1).toMatch({ - Resources: { - Resource1: { - Type: 'Resource1', - }, - }, - Outputs: { - ParentNested1Resource15F3F0657Ref: { - Value: { - Ref: 'Resource1', - }, - }, - }, - }); - - // consuming nested stack - expect(nested2).toMatch({ - Resources: { - Resource2: { - Type: 'Resource2', - Properties: { - RefToResource1: { - Ref: 'referencetoParentNested1NestedStackNested1NestedStackResource9C05342COutputsParentNested1Resource15F3F0657Ref', - }, - }, - }, - }, - Parameters: { - referencetoParentNested1NestedStackNested1NestedStackResource9C05342COutputsParentNested1Resource15F3F0657Ref: { - Type: 'String', - }, - }, - }); - - // parent - expect(parent).to(haveResource('AWS::CloudFormation::Stack', { - Parameters: { - referencetoParentNested1NestedStackNested1NestedStackResource9C05342COutputsParentNested1Resource15F3F0657Ref: { - 'Fn::GetAtt': [ - 'Nested1NestedStackNested1NestedStackResourceCD0AD36B', - 'Outputs.ParentNested1Resource15F3F0657Ref', - ], - }, - }, - })); - - test.done(); - }, - - 'stackId returns AWS::StackId when referenced from the context of the nested stack'(test: Test) { - // GIVEN - const parent = new Stack(); - const nested = new NestedStack(parent, 'NestedStack'); - - // WHEN - new CfnResource(nested, 'NestedResource', { - type: 'Nested::Resource', - properties: { MyStackId: nested.stackId }, - }); - - // THEN - expect(nested).to(haveResource('Nested::Resource', { - MyStackId: { Ref: 'AWS::StackId' }, - })); - - test.done(); - }, - - 'stackId returns the REF of the CloudFormation::Stack resource when referenced from the parent stack'(test: Test) { - // GIVEN - const parent = new Stack(); - const nested = new NestedStack(parent, 'NestedStack'); - - // WHEN - new CfnResource(parent, 'ParentResource', { - type: 'Parent::Resource', - properties: { NestedStackId: nested.stackId }, - }); - - // THEN - expect(parent).to(haveResource('Parent::Resource', { - NestedStackId: { Ref: 'NestedStackNestedStackNestedStackNestedStackResourceB70834FD' }, - })); - - test.done(); - }, - - 'stackName returns AWS::StackName when referenced from the context of the nested stack'(test: Test) { - // GIVEN - const parent = new Stack(); - const nested = new NestedStack(parent, 'NestedStack'); - - // WHEN - new CfnResource(nested, 'NestedResource', { - type: 'Nested::Resource', - properties: { MyStackName: nested.stackName }, - }); - - // THEN - expect(nested).to(haveResource('Nested::Resource', { - MyStackName: { Ref: 'AWS::StackName' }, - })); - - test.done(); - }, - - 'stackName returns the REF of the CloudFormation::Stack resource when referenced from the parent stack'(test: Test) { - // GIVEN - const parent = new Stack(); - const nested = new NestedStack(parent, 'NestedStack'); - - // WHEN - new CfnResource(parent, 'ParentResource', { - type: 'Parent::Resource', - properties: { NestedStackName: nested.stackName }, - }); - - // THEN - expect(parent).to(haveResource('Parent::Resource', { - NestedStackName: { - 'Fn::Select': [ - 1, - { - 'Fn::Split': [ - '/', - { - Ref: 'NestedStackNestedStackNestedStackNestedStackResourceB70834FD', - }, - ], - }, - ], - }, - })); - - test.done(); - }, - - '"account", "region" and "environment" are all derived from the parent'(test: Test) { - // GIVEN - const app = new App(); - const parent = new Stack(app, 'ParentStack', { env: { account: '1234account', region: 'us-east-44' } }); - - // WHEN - const nested = new NestedStack(parent, 'NestedStack'); - - // THEN - test.deepEqual(nested.environment, parent.environment); - test.deepEqual(nested.account, parent.account); - test.deepEqual(nested.region, parent.region); - test.done(); - }, - - 'double-nested stack'(test: Test) { - // GIVEN - const app = new App(); - const parent = new Stack(app, 'stack'); - - // WHEN - const nested1 = new NestedStack(parent, 'Nested1'); - const nested2 = new NestedStack(nested1, 'Nested2'); - - new CfnResource(nested1, 'Resource1', { type: 'Resource::1' }); - new CfnResource(nested2, 'Resource2', { type: 'Resource::2' }); - - // THEN - const assembly = app.synth(); - - // nested2 is a "leaf", so it's just the resource - expect(nested2).toMatch({ - Resources: { - Resource2: { Type: 'Resource::2' }, - }, - }); - - const middleStackHash = '7c426f7299a739900279ac1ece040397c1913cdf786f5228677b289f4d5e4c48'; - const bucketSuffix = 'C706B101'; - const versionSuffix = '4B193AA5'; - const hashSuffix = 'E28F0693'; - - // nested1 wires the nested2 template through parameters, so we expect those - expect(nested1).to(haveResource('Resource::1')); - const nested2Template = SynthUtils.toCloudFormation(nested1); - test.deepEqual(nested2Template.Parameters, { - referencetostackAssetParameters8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235cS3BucketE8768F5CRef: { Type: 'String' }, - referencetostackAssetParameters8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235cS3VersionKey49DD83A2Ref: { Type: 'String' }, - }); - - // parent stack should have two sets of parameters. one for the first nested stack and the second - // for the second nested stack, passed in as parameters to the first - const template = SynthUtils.toCloudFormation(parent); - test.deepEqual(template.Parameters, { - AssetParameters8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235cS3BucketDE3B88D6: { Type: 'String', Description: 'S3 bucket for asset "8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235c"' }, - AssetParameters8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235cS3VersionKey3A62EFEA: { Type: 'String', Description: 'S3 key for asset version "8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235c"' }, - AssetParameters8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235cArtifactHash7DC546E0: { Type: 'String', Description: 'Artifact hash for asset "8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235c"' }, - [`AssetParameters${middleStackHash}S3Bucket${bucketSuffix}`]: { Type: 'String', Description: `S3 bucket for asset "${middleStackHash}"` }, - [`AssetParameters${middleStackHash}S3VersionKey${versionSuffix}`]: { Type: 'String', Description: `S3 key for asset version "${middleStackHash}"` }, - [`AssetParameters${middleStackHash}ArtifactHash${hashSuffix}`]: { Type: 'String', Description: `Artifact hash for asset "${middleStackHash}"` }, - }); - - // proxy asset params to nested stack - expect(parent).to(haveResource('AWS::CloudFormation::Stack', { - Parameters: { - referencetostackAssetParameters8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235cS3BucketE8768F5CRef: { Ref: 'AssetParameters8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235cS3BucketDE3B88D6' }, - referencetostackAssetParameters8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235cS3VersionKey49DD83A2Ref: { Ref: 'AssetParameters8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235cS3VersionKey3A62EFEA' }, - }, - })); - - // parent stack should have 2 assets - test.deepEqual(assembly.getStackByName(parent.stackName).assets.length, 2); - test.done(); - }, - - 'reference resource in a double nested stack (#15155)'(test: Test) { - // GIVEN - const app = new App(); - const producerStack = new Stack(app, 'Producer'); - const nested2 = new NestedStack(new NestedStack(producerStack, 'Nested1'), 'Nested2'); - const producerResource = new CfnResource(nested2, 'Resource', { type: 'MyResource' }); - const consumerStack = new Stack(app, 'Consumer'); - - // WHEN - new CfnResource(consumerStack, 'ConsumingResource', { - type: 'YourResource', - properties: { RefToResource: producerResource.ref }, - }); - - // THEN - const casm = app.synth(); // before #15155 was fixed this threw an error - - const producerTemplate = casm.getStackArtifact(producerStack.artifactId).template; - const consumerTemplate = casm.getStackArtifact(consumerStack.artifactId).template; - - // check that the consuming resource references the expected export name - const outputName = 'ExportsOutputFnGetAttNested1NestedStackNested1NestedStackResourceCD0AD36BOutputsProducerNested1Nested2NestedStackNested2NestedStackResource1E6FA3C3OutputsProducerNested1Nested238A89CC5Ref2E9E52EA'; - const exportName = producerTemplate.Outputs[outputName].Export.Name; - const importName = consumerTemplate.Resources.ConsumingResource.Properties.RefToResource['Fn::ImportValue']; - test.equal(exportName, importName); - - test.done(); - }, - - 'assets within nested stacks are proxied from the parent'(test: Test) { - // GIVEN - const app = new App(); - const parent = new Stack(app, 'ParentStack'); - const nested = new NestedStack(parent, 'NestedStack'); - - // WHEN - const asset = new s3_assets.Asset(nested, 'asset', { - path: path.join(__dirname, 'asset-fixture.txt'), - }); - - new CfnResource(nested, 'NestedResource', { - type: 'Nested::Resource', - properties: { - AssetBucket: asset.s3BucketName, - AssetKey: asset.s3ObjectKey, - }, - }); - - // THEN - const assembly = app.synth(); - const template = SynthUtils.toCloudFormation(parent); - - // two sets of asset parameters: one for the nested stack itself and one as a proxy for the asset within the stack - test.deepEqual(template.Parameters, { - AssetParametersdb01ee2eb7adc7915e364dc410d861e569543f9be3761d535a68d5c2cc181281S3BucketC188F637: { Type: 'String', Description: 'S3 bucket for asset "db01ee2eb7adc7915e364dc410d861e569543f9be3761d535a68d5c2cc181281"' }, - AssetParametersdb01ee2eb7adc7915e364dc410d861e569543f9be3761d535a68d5c2cc181281S3VersionKeyC7F4DBF2: { Type: 'String', Description: 'S3 key for asset version "db01ee2eb7adc7915e364dc410d861e569543f9be3761d535a68d5c2cc181281"' }, - AssetParametersdb01ee2eb7adc7915e364dc410d861e569543f9be3761d535a68d5c2cc181281ArtifactHash373B14D2: { Type: 'String', Description: 'Artifact hash for asset "db01ee2eb7adc7915e364dc410d861e569543f9be3761d535a68d5c2cc181281"' }, - AssetParameters46b107d6db798ca46046b8669d057a4debcbdbaaddb6170400748c2f9e4f9d71S3Bucket3C4265E9: { Type: 'String', Description: 'S3 bucket for asset "46b107d6db798ca46046b8669d057a4debcbdbaaddb6170400748c2f9e4f9d71"' }, - AssetParameters46b107d6db798ca46046b8669d057a4debcbdbaaddb6170400748c2f9e4f9d71S3VersionKey8E981535: { Type: 'String', Description: 'S3 key for asset version "46b107d6db798ca46046b8669d057a4debcbdbaaddb6170400748c2f9e4f9d71"' }, - AssetParameters46b107d6db798ca46046b8669d057a4debcbdbaaddb6170400748c2f9e4f9d71ArtifactHash45A28583: { Type: 'String', Description: 'Artifact hash for asset "46b107d6db798ca46046b8669d057a4debcbdbaaddb6170400748c2f9e4f9d71"' }, - }); - - // asset proxy parameters are passed to the nested stack - expect(parent).to(haveResource('AWS::CloudFormation::Stack', { - Parameters: { - referencetoParentStackAssetParametersdb01ee2eb7adc7915e364dc410d861e569543f9be3761d535a68d5c2cc181281S3Bucket82C55B96Ref: { Ref: 'AssetParametersdb01ee2eb7adc7915e364dc410d861e569543f9be3761d535a68d5c2cc181281S3BucketC188F637' }, - referencetoParentStackAssetParametersdb01ee2eb7adc7915e364dc410d861e569543f9be3761d535a68d5c2cc181281S3VersionKeyA43C3CC6Ref: { Ref: 'AssetParametersdb01ee2eb7adc7915e364dc410d861e569543f9be3761d535a68d5c2cc181281S3VersionKeyC7F4DBF2' }, - }, - })); - - // parent stack should have 2 assets - test.deepEqual(assembly.getStackByName(parent.stackName).assets.length, 2); - test.done(); - }, - - 'docker image assets are wired through the top-level stack'(test: Test) { - // GIVEN - const app = new App(); - const parent = new Stack(app, 'my-stack'); - const nested = new NestedStack(parent, 'nested-stack'); - - // WHEN - const location = nested.synthesizer.addDockerImageAsset({ - directoryName: 'my-image', - dockerBuildArgs: { key: 'value', boom: 'bam' }, - dockerBuildTarget: 'buildTarget', - sourceHash: 'hash-of-source', - }); - - // use the asset, so the parameters will be wired. - new sns.Topic(nested, 'MyTopic', { - displayName: `image location is ${location.imageUri}`, - }); - - // THEN - const asm = app.synth(); - test.deepEqual(asm.getStackArtifact(parent.artifactId).assets, [ - { - repositoryName: 'aws-cdk/assets', - imageTag: 'hash-of-source', - id: 'hash-of-source', - packaging: 'container-image', - path: 'my-image', - sourceHash: 'hash-of-source', - buildArgs: { key: 'value', boom: 'bam' }, - target: 'buildTarget', - }, - { - path: 'mystacknestedstackFAE12FB5.nested.template.json', - id: 'fcdaee79eb79f37eca3a9b1cc0cc9ba150e4eea8c5d6d0c343cb6cd9dc68e2e5', - packaging: 'file', - sourceHash: 'fcdaee79eb79f37eca3a9b1cc0cc9ba150e4eea8c5d6d0c343cb6cd9dc68e2e5', - s3BucketParameter: 'AssetParametersfcdaee79eb79f37eca3a9b1cc0cc9ba150e4eea8c5d6d0c343cb6cd9dc68e2e5S3Bucket67A749F8', - s3KeyParameter: 'AssetParametersfcdaee79eb79f37eca3a9b1cc0cc9ba150e4eea8c5d6d0c343cb6cd9dc68e2e5S3VersionKeyE1E6A8D4', - artifactHashParameter: 'AssetParametersfcdaee79eb79f37eca3a9b1cc0cc9ba150e4eea8c5d6d0c343cb6cd9dc68e2e5ArtifactHash0AEDBE8A', - }, - ]); - - test.done(); - }, - - 'metadata defined in nested stacks is reported at the parent stack level in the cloud assembly'(test: Test) { - // GIVEN - const app = new App({ stackTraces: false }); - const parent = new Stack(app, 'parent'); - const child = new Stack(parent, 'child'); - const nested = new NestedStack(child, 'nested'); - const resource = new CfnResource(nested, 'resource', { type: 'foo' }); - - // WHEN - resource.node.addMetadata('foo', 'bar'); - - // THEN: the first non-nested stack records the assembly metadata - const asm = app.synth(); - test.deepEqual(asm.stacks.length, 2); // only one stack is defined as an artifact - test.deepEqual(asm.getStackByName(parent.stackName).findMetadataByType('foo'), []); - test.deepEqual(asm.getStackByName(child.stackName).findMetadataByType('foo'), [ - { - path: '/parent/child/nested/resource', - type: 'foo', - data: 'bar', - }, - ]); - test.done(); - }, - - 'referencing attributes with period across stacks'(test: Test) { - // GIVEN - const parent = new Stack(); - const nested = new NestedStack(parent, 'nested'); - const consumed = new CfnResource(nested, 'resource-in-nested', { type: 'CONSUMED' }); - - // WHEN - new CfnResource(parent, 'resource-in-parent', { - type: 'CONSUMER', - properties: { - ConsumedAttribute: consumed.getAtt('Consumed.Attribute'), - }, - }); - - // THEN - expect(nested).toMatch({ - Resources: { - resourceinnested: { - Type: 'CONSUMED', - }, - }, - Outputs: { - nestedresourceinnested59B1F01CConsumedAttribute: { - Value: { - 'Fn::GetAtt': [ - 'resourceinnested', - 'Consumed.Attribute', - ], - }, - }, - }, - }); - expect(parent).to(haveResource('CONSUMER', { - ConsumedAttribute: { - 'Fn::GetAtt': [ - 'nestedNestedStacknestedNestedStackResource3DD143BF', - 'Outputs.nestedresourceinnested59B1F01CConsumedAttribute', - ], - }, - })); - - test.done(); - }, - - 'missing context in nested stack is reported if the context is not available'(test: Test) { - // GIVEN - const app = new App(); - const stack = new Stack(app, 'ParentStack', { env: { account: '1234account', region: 'us-east-44' } }); - const nestedStack = new NestedStack(stack, 'nested'); - const provider = 'availability-zones'; - const expectedKey = ContextProvider.getKey(nestedStack, { - provider, - }).key; - - // WHEN - ContextProvider.getValue(nestedStack, { - provider, - dummyValue: ['dummy1a', 'dummy1b', 'dummy1c'], - }); - - // THEN: missing context is reported in the cloud assembly - const asm = app.synth(); - const missing = asm.manifest.missing; - - test.ok(missing && missing.find(m => { - return (m.key === expectedKey); - })); - - test.done(); - }, - - '3-level stacks: legacy synthesizer parameters are added to the middle-level stack'(test: Test) { - // GIVEN - const app = new App(); - const top = new Stack(app, 'stack', { - synthesizer: new LegacyStackSynthesizer(), - }); - const middle = new NestedStack(top, 'nested1'); - const bottom = new NestedStack(middle, 'nested2'); - - // WHEN - new CfnResource(bottom, 'Something', { - type: 'BottomLevel', - }); - - // THEN - const asm = app.synth(); - const middleTemplate = JSON.parse(fs.readFileSync(path.join(asm.directory, middle.templateFile), { encoding: 'utf-8' })); - - const hash = 'bc3c51e4d3545ee0a0069401e5a32c37b66d044b983f12de416ba1576ecaf0a4'; - test.deepEqual(middleTemplate.Parameters ?? {}, { - [`referencetostackAssetParameters${hash}S3BucketD7C30435Ref`]: { - Type: 'String', - }, - [`referencetostackAssetParameters${hash}S3VersionKeyB667DBE1Ref`]: { - Type: 'String', - }, - }); - - test.done(); - }, - - 'references to a resource from a deeply nested stack'(test: Test) { - // GIVEN - const app = new App(); - const top = new Stack(app, 'stack'); - const topLevel = new CfnResource(top, 'toplevel', { type: 'TopLevel' }); - const nested1 = new NestedStack(top, 'nested1'); - const nested2 = new NestedStack(nested1, 'nested2'); - - // WHEN - new CfnResource(nested2, 'refToTopLevel', { - type: 'BottomLevel', - properties: { RefToTopLevel: topLevel.ref }, - }); - - // THEN - expect(top).to(haveResource('AWS::CloudFormation::Stack', { - Parameters: { - referencetostackAssetParameters842982bd421cce9742ba27151ef12ed699d44d22801f41e8029f63f2358a3f2fS3Bucket5DA5D2E7Ref: { - Ref: 'AssetParameters842982bd421cce9742ba27151ef12ed699d44d22801f41e8029f63f2358a3f2fS3BucketDD4D96B5', - }, - referencetostackAssetParameters842982bd421cce9742ba27151ef12ed699d44d22801f41e8029f63f2358a3f2fS3VersionKey8FBE5C12Ref: { - Ref: 'AssetParameters842982bd421cce9742ba27151ef12ed699d44d22801f41e8029f63f2358a3f2fS3VersionKey83E381F3', - }, - referencetostacktoplevelBB16BF13Ref: { - Ref: 'toplevel', - }, - }, - })); - - expect(nested1).to(haveResource('AWS::CloudFormation::Stack', { - Parameters: { - referencetostacktoplevelBB16BF13Ref: { - Ref: 'referencetostacktoplevelBB16BF13Ref', - }, - }, - })); - - expect(nested2).to(matchTemplate({ - Resources: { - refToTopLevel: { - Type: 'BottomLevel', - Properties: { - RefToTopLevel: { - Ref: 'referencetostacktoplevelBB16BF13Ref', - }, - }, - }, - }, - Parameters: { - referencetostacktoplevelBB16BF13Ref: { - Type: 'String', - }, - }, - })); - test.done(); - }, - - 'bottom nested stack consumes value from a top-level stack through a parameter in a middle nested stack'(test: Test) { - // GIVEN - const app = new App(); - const top = new Stack(app, 'Grandparent'); - const middle = new NestedStack(top, 'Parent'); - const bottom = new NestedStack(middle, 'Child'); - const resourceInGrandparent = new CfnResource(top, 'ResourceInGrandparent', { type: 'ResourceInGrandparent' }); - - // WHEN - new CfnResource(bottom, 'ResourceInChild', { - type: 'ResourceInChild', - properties: { - RefToGrandparent: resourceInGrandparent.ref, - }, - }); - - // THEN - - // this is the name allocated for the parameter that's propagated through - // the hierarchy. - const paramName = 'referencetoGrandparentResourceInGrandparent010E997ARef'; - - // child (bottom) references through a parameter. - expect(bottom).toMatch({ - Resources: { - ResourceInChild: { - Type: 'ResourceInChild', - Properties: { - RefToGrandparent: { Ref: paramName }, - }, - }, - }, - Parameters: { - [paramName]: { Type: 'String' }, - }, - }); - - // the parent (middle) sets the value of this parameter to be a reference to another parameter - expect(middle).to(haveResource('AWS::CloudFormation::Stack', { - Parameters: { - [paramName]: { Ref: paramName }, - }, - })); - - // grandparent (top) assigns the actual value to the parameter - expect(top).to(haveResource('AWS::CloudFormation::Stack', { - Parameters: { - [paramName]: { Ref: 'ResourceInGrandparent' }, - - // these are for the asset of the bottom nested stack - referencetoGrandparentAssetParameters3208f43b793a1dbe28ca02cf31fb975489071beb42c492b22dc3d32decc3b4b7S3Bucket06EEE58DRef: { - Ref: 'AssetParameters3208f43b793a1dbe28ca02cf31fb975489071beb42c492b22dc3d32decc3b4b7S3Bucket01877C2E', - }, - referencetoGrandparentAssetParameters3208f43b793a1dbe28ca02cf31fb975489071beb42c492b22dc3d32decc3b4b7S3VersionKeyD3B04909Ref: { - Ref: 'AssetParameters3208f43b793a1dbe28ca02cf31fb975489071beb42c492b22dc3d32decc3b4b7S3VersionKey5765F084', - }, - }, - })); - - test.done(); - }, -}; diff --git a/packages/@aws-cdk/aws-cloudformation/test/test.resource.ts b/packages/@aws-cdk/aws-cloudformation/test/test.resource.ts deleted file mode 100644 index 387aa45240e92..0000000000000 --- a/packages/@aws-cdk/aws-cloudformation/test/test.resource.ts +++ /dev/null @@ -1,238 +0,0 @@ -import { expect, haveResource, ResourcePart } from '@aws-cdk/assert-internal'; -import * as lambda from '@aws-cdk/aws-lambda'; -import * as sns from '@aws-cdk/aws-sns'; -import * as cdk from '@aws-cdk/core'; -import { Test, testCase } from 'nodeunit'; -import { CustomResource, CustomResourceProvider } from '../lib'; - -// keep this import separate from other imports to reduce chance for merge conflicts with v2-main -// eslint-disable-next-line no-duplicate-imports, import/order -import { Construct } from '@aws-cdk/core'; - -/* eslint-disable cdk/no-core-construct */ -/* eslint-disable quote-props */ - -export = testCase({ - 'custom resources honor removalPolicy': { - 'unspecified (aka .Destroy)'(test: Test) { - // GIVEN - const app = new cdk.App(); - const stack = new cdk.Stack(app, 'Test'); - - // WHEN - new TestCustomResource(stack, 'Custom'); - - // THEN - expect(stack).to(haveResource('AWS::CloudFormation::CustomResource', {}, ResourcePart.CompleteDefinition)); - test.equal(app.synth().tryGetArtifact(stack.stackName)!.findMetadataByType('aws:cdk:protected').length, 0); - - test.done(); - }, - - '.Destroy'(test: Test) { - // GIVEN - const app = new cdk.App(); - const stack = new cdk.Stack(app, 'Test'); - - // WHEN - new TestCustomResource(stack, 'Custom', { removalPolicy: cdk.RemovalPolicy.DESTROY }); - - // THEN - expect(stack).to(haveResource('AWS::CloudFormation::CustomResource', {}, ResourcePart.CompleteDefinition)); - test.equal(app.synth().tryGetArtifact(stack.stackName)!.findMetadataByType('aws:cdk:protected').length, 0); - - test.done(); - }, - - '.Retain'(test: Test) { - // GIVEN - const app = new cdk.App(); - const stack = new cdk.Stack(app, 'Test'); - - // WHEN - new TestCustomResource(stack, 'Custom', { removalPolicy: cdk.RemovalPolicy.RETAIN }); - - // THEN - expect(stack).to(haveResource('AWS::CloudFormation::CustomResource', { - DeletionPolicy: 'Retain', - UpdateReplacePolicy: 'Retain', - }, ResourcePart.CompleteDefinition)); - - test.done(); - }, - }, - - 'custom resource is added twice, lambda is added once'(test: Test) { - // GIVEN - const app = new cdk.App(); - const stack = new cdk.Stack(app, 'Test'); - - // WHEN - new TestCustomResource(stack, 'Custom1'); - new TestCustomResource(stack, 'Custom2'); - - // THEN - expect(stack).toMatch({ - 'Resources': { - 'SingletonLambdaTestCustomResourceProviderServiceRole81FEAB5C': { - 'Type': 'AWS::IAM::Role', - 'Properties': { - 'AssumeRolePolicyDocument': { - 'Statement': [ - { - 'Action': 'sts:AssumeRole', - 'Effect': 'Allow', - 'Principal': { - 'Service': 'lambda.amazonaws.com', - }, - }, - ], - 'Version': '2012-10-17', - }, - 'ManagedPolicyArns': [ - { - 'Fn::Join': ['', [ - 'arn:', { 'Ref': 'AWS::Partition' }, ':iam::aws:policy/service-role/AWSLambdaBasicExecutionRole', - ]], - }, - ], - }, - }, - 'SingletonLambdaTestCustomResourceProviderA9255269': { - 'Type': 'AWS::Lambda::Function', - 'Properties': { - 'Code': { - 'ZipFile': 'def hello(): pass', - }, - 'Handler': 'index.hello', - 'Role': { - 'Fn::GetAtt': [ - 'SingletonLambdaTestCustomResourceProviderServiceRole81FEAB5C', - 'Arn', - ], - }, - 'Runtime': 'python2.7', - 'Timeout': 300, - }, - 'DependsOn': [ - 'SingletonLambdaTestCustomResourceProviderServiceRole81FEAB5C', - ], - }, - 'Custom1D319B237': { - 'Type': 'AWS::CloudFormation::CustomResource', - 'DeletionPolicy': 'Delete', - 'UpdateReplacePolicy': 'Delete', - 'Properties': { - 'ServiceToken': { - 'Fn::GetAtt': [ - 'SingletonLambdaTestCustomResourceProviderA9255269', - 'Arn', - ], - }, - }, - }, - 'Custom2DD5FB44D': { - 'Type': 'AWS::CloudFormation::CustomResource', - 'DeletionPolicy': 'Delete', - 'UpdateReplacePolicy': 'Delete', - 'Properties': { - 'ServiceToken': { - 'Fn::GetAtt': [ - 'SingletonLambdaTestCustomResourceProviderA9255269', - 'Arn', - ], - }, - }, - }, - }, - }); - test.done(); - }, - - 'custom resources can specify a resource type that starts with Custom::'(test: Test) { - const app = new cdk.App(); - const stack = new cdk.Stack(app, 'Test'); - new CustomResource(stack, 'MyCustomResource', { - resourceType: 'Custom::MyCustomResourceType', - provider: CustomResourceProvider.fromTopic(new sns.Topic(stack, 'Provider')), - }); - expect(stack).to(haveResource('Custom::MyCustomResourceType')); - test.done(); - }, - - 'fails if custom resource type is invalid': { - 'does not start with "Custom::"'(test: Test) { - const app = new cdk.App(); - const stack = new cdk.Stack(app, 'Test'); - - test.throws(() => { - new CustomResource(stack, 'MyCustomResource', { - resourceType: 'NoCustom::MyCustomResourceType', - provider: CustomResourceProvider.fromTopic(new sns.Topic(stack, 'Provider')), - }); - }, /Custom resource type must begin with "Custom::"/); - - test.done(); - }, - - 'has invalid characters'(test: Test) { - const app = new cdk.App(); - const stack = new cdk.Stack(app, 'Test'); - - test.throws(() => { - new CustomResource(stack, 'MyCustomResource', { - resourceType: 'Custom::My Custom?ResourceType', - provider: CustomResourceProvider.fromTopic(new sns.Topic(stack, 'Provider')), - }); - }, /Custom resource type name can only include alphanumeric characters and/); - - test.done(); - }, - - 'is longer than 60 characters'(test: Test) { - const app = new cdk.App(); - const stack = new cdk.Stack(app, 'Test'); - - test.throws(() => { - new CustomResource(stack, 'MyCustomResource', { - resourceType: 'Custom::0123456789012345678901234567890123456789012345678901234567891', - provider: CustomResourceProvider.fromTopic(new sns.Topic(stack, 'Provider')), - }); - }, /Custom resource type length > 60/); - - test.done(); - }, - - }, - - '.ref returns the intrinsic reference (physical name)'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const res = new TestCustomResource(stack, 'myResource'); - - // THEN - test.deepEqual(stack.resolve(res.resource.ref), { Ref: 'myResourceC6A188A9' }); - test.done(); - }, -}); - -class TestCustomResource extends Construct { - public readonly resource: CustomResource; - - constructor(scope: Construct, id: string, opts: { removalPolicy?: cdk.RemovalPolicy } = {}) { - super(scope, id); - - const singletonLambda = new lambda.SingletonFunction(this, 'Lambda', { - uuid: 'TestCustomResourceProvider', - code: new lambda.InlineCode('def hello(): pass'), - runtime: lambda.Runtime.PYTHON_2_7, - handler: 'index.hello', - timeout: cdk.Duration.minutes(5), - }); - - this.resource = new CustomResource(this, 'Resource', { - ...opts, - provider: CustomResourceProvider.fromLambda(singletonLambda), - }); - } -} diff --git a/packages/@aws-cdk/aws-cloudfront-origins/.eslintrc.js b/packages/@aws-cdk/aws-cloudfront-origins/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-cloudfront-origins/.eslintrc.js +++ b/packages/@aws-cdk/aws-cloudfront-origins/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-cloudfront-origins/jest.config.js b/packages/@aws-cdk/aws-cloudfront-origins/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-cloudfront-origins/jest.config.js +++ b/packages/@aws-cdk/aws-cloudfront-origins/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-cloudfront-origins/package.json b/packages/@aws-cdk/aws-cloudfront-origins/package.json index e7ef1eb01a94d..9c4476de80fbb 100644 --- a/packages/@aws-cdk/aws-cloudfront-origins/package.json +++ b/packages/@aws-cdk/aws-cloudfront-origins/package.json @@ -52,7 +52,6 @@ "build+test+extract": "yarn build+test && yarn rosetta:extract" }, "cdk-build": { - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -71,13 +70,13 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", + "@aws-cdk/assert-internal": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", - "aws-sdk": "^2.848.0", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24", + "aws-sdk": "^2.848.0" }, "dependencies": { "@aws-cdk/aws-cloudfront": "0.0.0", @@ -89,12 +88,12 @@ }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { - "@aws-cdk/core": "0.0.0", - "constructs": "^3.3.69", "@aws-cdk/aws-cloudfront": "0.0.0", "@aws-cdk/aws-elasticloadbalancingv2": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", - "@aws-cdk/aws-s3": "0.0.0" + "@aws-cdk/aws-s3": "0.0.0", + "@aws-cdk/core": "0.0.0", + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-cloudfront/.eslintrc.js b/packages/@aws-cdk/aws-cloudfront/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-cloudfront/.eslintrc.js +++ b/packages/@aws-cdk/aws-cloudfront/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-cloudfront/jest.config.js b/packages/@aws-cdk/aws-cloudfront/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-cloudfront/jest.config.js +++ b/packages/@aws-cdk/aws-cloudfront/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-cloudfront/lib/experimental/edge-function.ts b/packages/@aws-cdk/aws-cloudfront/lib/experimental/edge-function.ts index a45bc0ce6db97..4a3974c2af632 100644 --- a/packages/@aws-cdk/aws-cloudfront/lib/experimental/edge-function.ts +++ b/packages/@aws-cdk/aws-cloudfront/lib/experimental/edge-function.ts @@ -148,7 +148,9 @@ export class EdgeFunction extends Resource implements lambda.IVersion { if (Token.isUnresolved(this.env.region)) { throw new Error('stacks which use EdgeFunctions must have an explicitly set region'); } - const parameterName = `${parameterNamePrefix}/${this.env.region}/${this.node.path}`; + // SSM parameter names must only contain letters, numbers, ., _, -, or /. + const sanitizedPath = this.node.path.replace(/[^\/\w.-]/g, '_'); + const parameterName = `${parameterNamePrefix}/${this.env.region}/${sanitizedPath}`; const functionStack = this.edgeStack(props.stackId); const edgeFunction = new lambda.Function(functionStack, id, props); diff --git a/packages/@aws-cdk/aws-cloudfront/lib/web-distribution.ts b/packages/@aws-cdk/aws-cloudfront/lib/web-distribution.ts index 29a63fd681bb3..ab2fbbd44b03c 100644 --- a/packages/@aws-cdk/aws-cloudfront/lib/web-distribution.ts +++ b/packages/@aws-cdk/aws-cloudfront/lib/web-distribution.ts @@ -454,6 +454,12 @@ export interface Behavior { */ readonly functionAssociations?: FunctionAssociation[]; + /** + * The viewer policy for this behavior. + * + * @default - the distribution wide viewer protocol policy will be used + */ + readonly viewerProtocolPolicy?: ViewerProtocolPolicy; } export interface LambdaFunctionAssociation { @@ -992,7 +998,7 @@ export class CloudFrontWebDistribution extends cdk.Resource implements IDistribu trustedKeyGroups: input.trustedKeyGroups?.map(key => key.keyGroupId), trustedSigners: input.trustedSigners, targetOriginId: input.targetOriginId, - viewerProtocolPolicy: protoPolicy || ViewerProtocolPolicy.REDIRECT_TO_HTTPS, + viewerProtocolPolicy: input.viewerProtocolPolicy || protoPolicy || ViewerProtocolPolicy.REDIRECT_TO_HTTPS, }; if (!input.isDefaultBehavior) { toReturn = Object.assign(toReturn, { pathPattern: input.pathPattern }); diff --git a/packages/@aws-cdk/aws-cloudfront/package.json b/packages/@aws-cdk/aws-cloudfront/package.json index 36d4ce40952f5..e2b1305049227 100644 --- a/packages/@aws-cdk/aws-cloudfront/package.json +++ b/packages/@aws-cdk/aws-cloudfront/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::CloudFront", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,19 +72,18 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", "aws-sdk": "^2.848.0", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-certificatemanager": "0.0.0", "@aws-cdk/aws-cloudwatch": "0.0.0", - "@aws-cdk/cx-api": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", @@ -93,13 +91,13 @@ "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/aws-ssm": "0.0.0", "@aws-cdk/core": "0.0.0", + "@aws-cdk/cx-api": "0.0.0", "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { "@aws-cdk/aws-certificatemanager": "0.0.0", "@aws-cdk/aws-cloudwatch": "0.0.0", - "@aws-cdk/cx-api": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", @@ -107,6 +105,7 @@ "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/aws-ssm": "0.0.0", "@aws-cdk/core": "0.0.0", + "@aws-cdk/cx-api": "0.0.0", "constructs": "^3.3.69" }, "engines": { diff --git a/packages/@aws-cdk/aws-cloudfront/test/distribution.test.ts b/packages/@aws-cdk/aws-cloudfront/test/distribution.test.ts index 930557098851c..470be56acf0d5 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/distribution.test.ts +++ b/packages/@aws-cdk/aws-cloudfront/test/distribution.test.ts @@ -5,7 +5,7 @@ import * as lambda from '@aws-cdk/aws-lambda'; import * as s3 from '@aws-cdk/aws-s3'; import { App, Duration, Stack } from '@aws-cdk/core'; import { CLOUDFRONT_DEFAULT_SECURITY_POLICY_TLS_V1_2_2021 } from '@aws-cdk/cx-api'; -import { testFutureBehavior, testLegacyBehavior } from 'cdk-build-tools/lib/feature-flag'; +import { testFutureBehavior, testLegacyBehavior } from '@aws-cdk/cdk-build-tools/lib/feature-flag'; import { CfnDistribution, Distribution, @@ -126,7 +126,7 @@ test('ensure comment prop is not greater than max lenght', () => { const origin = defaultOrigin(); new Distribution(stack, 'MyDist', { defaultBehavior: { origin }, - comment: `Adding a comment longer than 128 characters should be trimmed and added the + comment: `Adding a comment longer than 128 characters should be trimmed and added the\x20 ellipsis so a user would know there was more to read and everything beyond this point should not show up`, }); @@ -138,7 +138,7 @@ ellipsis so a user would know there was more to read and everything beyond this TargetOriginId: 'StackMyDistOrigin1D6D5E535', ViewerProtocolPolicy: 'allow-all', }, - Comment: `Adding a comment longer than 128 characters should be trimmed and added the + Comment: `Adding a comment longer than 128 characters should be trimmed and added the\x20 ellipsis so a user would know there was more to ...`, Enabled: true, HttpVersion: 'http2', diff --git a/packages/@aws-cdk/aws-cloudfront/test/experimental/edge-function.test.ts b/packages/@aws-cdk/aws-cloudfront/test/experimental/edge-function.test.ts index 4a22798eb48a1..55d6f3689103c 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/experimental/edge-function.test.ts +++ b/packages/@aws-cdk/aws-cloudfront/test/experimental/edge-function.test.ts @@ -298,6 +298,16 @@ test('cross-region stack supports new-style synthesis with assets', () => { expect(() => app.synth()).not.toThrow(); }); +test('SSM parameter name is sanitized to remove disallowed characters', () => { + new cloudfront.experimental.EdgeFunction(stack, 'My Bad#Fn$Name-With.Bonus', defaultEdgeFunctionProps()); + + const fnStack = getFnStack(); + + expect(fnStack).toHaveResourceLike('AWS::SSM::Parameter', { + Name: '/cdk/EdgeFunctionArn/testregion/Stack/My_Bad_Fn_Name-With.Bonus', + }); +}); + function defaultEdgeFunctionProps(stackId?: string) { return { code: lambda.Code.fromInline('foo'), diff --git a/packages/@aws-cdk/aws-cloudfront/test/test-origin.ts b/packages/@aws-cdk/aws-cloudfront/test/test-origin.ts index 1c6d3762add4f..4f35bcba4394c 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/test-origin.ts +++ b/packages/@aws-cdk/aws-cloudfront/test/test-origin.ts @@ -14,7 +14,7 @@ export class TestOrigin extends OriginBase { export class TestOriginGroup implements IOrigin { constructor(private readonly primaryDomainName: string, private readonly secondaryDomainName: string) { } - /* eslint-disable cdk/no-core-construct */ + /* eslint-disable @aws-cdk/no-core-construct */ public bind(scope: Construct, options: OriginBindOptions): OriginBindConfig { const primaryOrigin = new TestOrigin(this.primaryDomainName); const secondaryOrigin = new TestOrigin(this.secondaryDomainName); diff --git a/packages/@aws-cdk/aws-cloudfront/test/web-distribution.test.ts b/packages/@aws-cdk/aws-cloudfront/test/web-distribution.test.ts index 9e40e24e3fe42..600750bc4deca 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/web-distribution.test.ts +++ b/packages/@aws-cdk/aws-cloudfront/test/web-distribution.test.ts @@ -605,6 +605,109 @@ added the ellipsis so a user would know there was more to ...`, }); + test('distribution with ViewerProtocolPolicy overridden in Behavior', () => { + const stack = new cdk.Stack(); + const sourceBucket = new s3.Bucket(stack, 'Bucket'); + + new CloudFrontWebDistribution(stack, 'AnAmazingWebsiteProbably', { + viewerProtocolPolicy: ViewerProtocolPolicy.ALLOW_ALL, + originConfigs: [ + { + s3OriginSource: { + s3BucketSource: sourceBucket, + }, + behaviors: [ + { + isDefaultBehavior: true, + }, + { + pathPattern: '/test/*', + viewerProtocolPolicy: ViewerProtocolPolicy.REDIRECT_TO_HTTPS, + }, + ], + }, + ], + }); + + expect(stack).toMatchTemplate({ + 'Resources': { + 'Bucket83908E77': { + 'Type': 'AWS::S3::Bucket', + 'DeletionPolicy': 'Retain', + 'UpdateReplacePolicy': 'Retain', + }, + 'AnAmazingWebsiteProbablyCFDistribution47E3983B': { + 'Type': 'AWS::CloudFront::Distribution', + 'Properties': { + 'DistributionConfig': { + 'CacheBehaviors': [ + { + 'AllowedMethods': [ + 'GET', + 'HEAD', + ], + 'CachedMethods': [ + 'GET', + 'HEAD', + ], + 'Compress': true, + 'ForwardedValues': { + 'Cookies': { + 'Forward': 'none', + }, + 'QueryString': false, + }, + 'PathPattern': '/test/*', + 'TargetOriginId': 'origin1', + 'ViewerProtocolPolicy': 'redirect-to-https', + }, + ], + 'DefaultRootObject': 'index.html', + 'Origins': [ + { + 'ConnectionAttempts': 3, + 'ConnectionTimeout': 10, + 'DomainName': { + 'Fn::GetAtt': [ + 'Bucket83908E77', + 'RegionalDomainName', + ], + }, + 'Id': 'origin1', + 'S3OriginConfig': {}, + }, + ], + 'ViewerCertificate': { + 'CloudFrontDefaultCertificate': true, + }, + 'PriceClass': 'PriceClass_100', + 'DefaultCacheBehavior': { + 'AllowedMethods': [ + 'GET', + 'HEAD', + ], + 'CachedMethods': [ + 'GET', + 'HEAD', + ], + 'TargetOriginId': 'origin1', + 'ViewerProtocolPolicy': 'allow-all', + 'ForwardedValues': { + 'QueryString': false, + 'Cookies': { 'Forward': 'none' }, + }, + 'Compress': true, + }, + 'Enabled': true, + 'IPV6Enabled': true, + 'HttpVersion': 'http2', + }, + }, + }, + }, + }); + }); + test('distribution with disabled compression', () => { const stack = new cdk.Stack(); const sourceBucket = new s3.Bucket(stack, 'Bucket'); diff --git a/packages/@aws-cdk/aws-cloudtrail/.eslintrc.js b/packages/@aws-cdk/aws-cloudtrail/.eslintrc.js index ced30c8435282..92484d9f02ab4 100644 --- a/packages/@aws-cdk/aws-cloudtrail/.eslintrc.js +++ b/packages/@aws-cdk/aws-cloudtrail/.eslintrc.js @@ -1,4 +1,4 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-cloudtrail/jest.config.js b/packages/@aws-cdk/aws-cloudtrail/jest.config.js index b2dbd8ec76f4f..da69fabe154d9 100644 --- a/packages/@aws-cdk/aws-cloudtrail/jest.config.js +++ b/packages/@aws-cdk/aws-cloudtrail/jest.config.js @@ -1,4 +1,4 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = { ...baseConfig, coverageThreshold: { diff --git a/packages/@aws-cdk/aws-cloudtrail/package.json b/packages/@aws-cdk/aws-cloudtrail/package.json index 526442259cddb..c7d55ac99bf69 100644 --- a/packages/@aws-cdk/aws-cloudtrail/package.json +++ b/packages/@aws-cdk/aws-cloudtrail/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::CloudTrail", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,15 +72,15 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", "aws-sdk": "^2.848.0", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", "colors": "^1.4.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-events": "0.0.0", diff --git a/packages/@aws-cdk/aws-cloudwatch-actions/.eslintrc.js b/packages/@aws-cdk/aws-cloudwatch-actions/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-cloudwatch-actions/.eslintrc.js +++ b/packages/@aws-cdk/aws-cloudwatch-actions/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-cloudwatch-actions/jest.config.js b/packages/@aws-cdk/aws-cloudwatch-actions/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-cloudwatch-actions/jest.config.js +++ b/packages/@aws-cdk/aws-cloudwatch-actions/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-cloudwatch-actions/package.json b/packages/@aws-cdk/aws-cloudwatch-actions/package.json index 0869c60941c8f..0b687b88aee14 100644 --- a/packages/@aws-cdk/aws-cloudwatch-actions/package.json +++ b/packages/@aws-cdk/aws-cloudwatch-actions/package.json @@ -64,14 +64,14 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", + "@aws-cdk/assert-internal": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24", + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-applicationautoscaling": "0.0.0", @@ -101,7 +101,6 @@ }, "maturity": "stable", "cdk-build": { - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } diff --git a/packages/@aws-cdk/aws-cloudwatch/.eslintrc.js b/packages/@aws-cdk/aws-cloudwatch/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-cloudwatch/.eslintrc.js +++ b/packages/@aws-cdk/aws-cloudwatch/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-cloudwatch/README.md b/packages/@aws-cdk/aws-cloudwatch/README.md index bdcf58e61024f..450fc8ca9821a 100644 --- a/packages/@aws-cdk/aws-cloudwatch/README.md +++ b/packages/@aws-cdk/aws-cloudwatch/README.md @@ -43,7 +43,7 @@ const metric = new Metric({ dimensionsMap: { HostedZoneId: hostedZone.hostedZoneId } -}) +}); ``` ### Instantiating a new Metric object @@ -73,7 +73,7 @@ const allProblems = new MathExpression({ errors: myConstruct.metricErrors(), faults: myConstruct.metricFaults(), } -}) +}); ``` You can use `MathExpression` objects like any other metric, including using @@ -86,9 +86,25 @@ const problemPercentage = new MathExpression({ problems: allProblems, invocations: myConstruct.metricInvocations() } -}) +}); +``` + +### Search Expressions + +Math expressions also support search expressions. For example, the following +search expression returns all CPUUtilization metrics that it finds, with the +graph showing the Average statistic with an aggregation period of 5 minutes: + +```ts +const cpuUtilization = new MathExpression({ + expression: "SEARCH('{AWS/EC2,InstanceId} MetricName=\"CPUUtilization\"', 'Average', 300)" +}); ``` +Cross-account and cross-region search expressions are also supported. Use +the `searchAccount` and `searchRegion` properties to specify the account +and/or region to evaluate the search expression against. + ### Aggregation To graph or alarm on metrics you must aggregate them first, using a function diff --git a/packages/@aws-cdk/aws-cloudwatch/jest.config.js b/packages/@aws-cdk/aws-cloudwatch/jest.config.js index cd664e1d069e5..34818e1593f6b 100644 --- a/packages/@aws-cdk/aws-cloudwatch/jest.config.js +++ b/packages/@aws-cdk/aws-cloudwatch/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +const baseConfig = require('../../../tools/@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-cloudwatch/lib/alarm.ts b/packages/@aws-cdk/aws-cloudwatch/lib/alarm.ts index e0692478c8457..9169e155bd696 100644 --- a/packages/@aws-cdk/aws-cloudwatch/lib/alarm.ts +++ b/packages/@aws-cdk/aws-cloudwatch/lib/alarm.ts @@ -257,8 +257,7 @@ export class Alarm extends AlarmBase { return dispatchMetric(metric, { withStat(stat, conf) { self.validateMetricStat(stat, metric); - const canRenderAsLegacyMetric = conf.renderingProperties?.label == undefined && - (stat.account == undefined || Stack.of(self).account == stat.account); + const canRenderAsLegacyMetric = conf.renderingProperties?.label == undefined && !self.requiresAccountId(stat); // Do this to disturb existing templates as little as possible if (canRenderAsLegacyMetric) { return dropUndefined({ @@ -286,7 +285,7 @@ export class Alarm extends AlarmBase { unit: stat.unitFilter, }, id: 'm1', - accountId: stat.account, + accountId: self.requiresAccountId(stat) ? stat.account : undefined, label: conf.renderingProperties?.label, returnData: true, } as CfnAlarm.MetricDataQueryProperty, @@ -321,7 +320,7 @@ export class Alarm extends AlarmBase { unit: stat.unitFilter, }, id: entry.id || uniqueMetricId(), - accountId: stat.account, + accountId: self.requiresAccountId(stat) ? stat.account : undefined, label: conf.renderingProperties?.label, returnData: entry.tag ? undefined : false, // entry.tag evaluates to true if the metric is the math expression the alarm is based on. }; @@ -334,6 +333,8 @@ export class Alarm extends AlarmBase { assertSubmetricsCount(expr); } + self.validateMetricExpression(expr); + return { expression: expr.expression, id: entry.id || uniqueMetricId(), @@ -358,6 +359,42 @@ export class Alarm extends AlarmBase { throw new Error(`Cannot create an Alarm in region '${stack.region}' based on metric '${metric}' in '${stat.region}'`); } } + + /** + * Validates that the expression config does not specify searchAccount or searchRegion props + * as search expressions are not supported by Alarms. + */ + private validateMetricExpression(expr: MetricExpressionConfig) { + if (expr.searchAccount !== undefined || expr.searchRegion !== undefined) { + throw new Error('Cannot create an Alarm based on a MathExpression which specifies a searchAccount or searchRegion'); + } + } + + /** + * Determine if the accountId property should be included in the metric. + */ + private requiresAccountId(stat: MetricStatConfig): boolean { + const stackAccount = Stack.of(this).account; + + // if stat.account is undefined, it's by definition in the same account + if (stat.account === undefined) { + return false; + } + + // if this is a region-agnostic stack, we can't assume anything about stat.account + // and therefore we assume its a cross-account call + if (Token.isUnresolved(stackAccount)) { + return true; + } + + // ok, we can compare the two concrete values directly - if they are the same we + // can omit the account ID from the metric. + if (stackAccount === stat.account) { + return false; + } + + return true; + } } function definitelyDifferent(x: string | undefined, y: string) { diff --git a/packages/@aws-cdk/aws-cloudwatch/lib/metric-types.ts b/packages/@aws-cdk/aws-cloudwatch/lib/metric-types.ts index 296400ee7f910..e8506fde53140 100644 --- a/packages/@aws-cdk/aws-cloudwatch/lib/metric-types.ts +++ b/packages/@aws-cdk/aws-cloudwatch/lib/metric-types.ts @@ -322,6 +322,20 @@ export interface MetricExpressionConfig { * How many seconds to aggregate over */ readonly period: number; + + /** + * Account to evaluate search expressions within. + * + * @default - Deployment account. + */ + readonly searchAccount?: string; + + /** + * Region to evaluate search expressions within. + * + * @default - Deployment region. + */ + readonly searchRegion?: string; } /** diff --git a/packages/@aws-cdk/aws-cloudwatch/lib/metric.ts b/packages/@aws-cdk/aws-cloudwatch/lib/metric.ts index cf4051f74ffd4..d306978c93733 100644 --- a/packages/@aws-cdk/aws-cloudwatch/lib/metric.ts +++ b/packages/@aws-cdk/aws-cloudwatch/lib/metric.ts @@ -149,6 +149,26 @@ export interface MathExpressionOptions { * @default Duration.minutes(5) */ readonly period?: cdk.Duration; + + /** + * Account to evaluate search expressions within. + * + * Specifying a searchAccount has no effect to the account used + * for metrics within the expression (passed via usingMetrics). + * + * @default - Deployment account. + */ + readonly searchAccount?: string; + + /** + * Region to evaluate search expressions within. + * + * Specifying a searchRegion has no effect to the region used + * for metrics within the expression (passed via usingMetrics). + * + * @default - Deployment region. + */ + readonly searchRegion?: string; } /** @@ -157,6 +177,9 @@ export interface MathExpressionOptions { export interface MathExpressionProps extends MathExpressionOptions { /** * The expression defining the metric. + * + * When an expression contains a SEARCH function, it cannot be used + * within an Alarm. */ readonly expression: string; @@ -165,8 +188,10 @@ export interface MathExpressionProps extends MathExpressionOptions { * * The key is the identifier that represents the given metric in the * expression, and the value is the actual Metric object. + * + * @default - Empty map. */ - readonly usingMetrics: Record; + readonly usingMetrics?: Record; } /** @@ -451,6 +476,10 @@ function asString(x?: unknown): string | undefined { * It makes sense to embed this in here, so that compound constructs can attach * that metadata to metrics they expose. * + * MathExpression can also be used for search expressions. In this case, + * it also optionally accepts a searchRegion and searchAccount property for cross-environment + * search expressions. + * * This class does not represent a resource, so hence is not a construct. Instead, * MathExpression is an abstraction that makes it easy to specify metrics for use in both * alarms and graphs. @@ -482,14 +511,26 @@ export class MathExpression implements IMetric { */ public readonly period: cdk.Duration; + /** + * Account to evaluate search expressions within. + */ + public readonly searchAccount?: string; + + /** + * Region to evaluate search expressions within. + */ + public readonly searchRegion?: string; + constructor(props: MathExpressionProps) { this.period = props.period || cdk.Duration.minutes(5); this.expression = props.expression; - this.usingMetrics = changeAllPeriods(props.usingMetrics, this.period); + this.usingMetrics = changeAllPeriods(props.usingMetrics ?? {}, this.period); this.label = props.label; this.color = props.color; + this.searchAccount = props.searchAccount; + this.searchRegion = props.searchRegion; - const invalidVariableNames = Object.keys(props.usingMetrics).filter(x => !validVariableName(x)); + const invalidVariableNames = Object.keys(this.usingMetrics).filter(x => !validVariableName(x)); if (invalidVariableNames.length > 0) { throw new Error(`Invalid variable names in expression: ${invalidVariableNames}. Must start with lowercase letter and only contain alphanumerics.`); } @@ -508,7 +549,9 @@ export class MathExpression implements IMetric { // Short-circuit creating a new object if there would be no effective change if ((props.label === undefined || props.label === this.label) && (props.color === undefined || props.color === this.color) - && (props.period === undefined || props.period.toSeconds() === this.period.toSeconds())) { + && (props.period === undefined || props.period.toSeconds() === this.period.toSeconds()) + && (props.searchAccount === undefined || props.searchAccount === this.searchAccount) + && (props.searchRegion === undefined || props.searchRegion === this.searchRegion)) { return this; } @@ -518,6 +561,8 @@ export class MathExpression implements IMetric { label: ifUndefined(props.label, this.label), color: ifUndefined(props.color, this.color), period: ifUndefined(props.period, this.period), + searchAccount: ifUndefined(props.searchAccount, this.searchAccount), + searchRegion: ifUndefined(props.searchRegion, this.searchRegion), }); } @@ -541,6 +586,8 @@ export class MathExpression implements IMetric { period: this.period.toSeconds(), expression: this.expression, usingMetrics: this.usingMetrics, + searchAccount: this.searchAccount, + searchRegion: this.searchRegion, }, renderingProperties: { label: this.label, diff --git a/packages/@aws-cdk/aws-cloudwatch/lib/private/metric-util.ts b/packages/@aws-cdk/aws-cloudwatch/lib/private/metric-util.ts index 589e3d99ad474..8988148c16b3b 100644 --- a/packages/@aws-cdk/aws-cloudwatch/lib/private/metric-util.ts +++ b/packages/@aws-cdk/aws-cloudwatch/lib/private/metric-util.ts @@ -25,6 +25,12 @@ export function metricKey(metric: IMetric): string { parts.push(id); parts.push(metricKey(conf.mathExpression.usingMetrics[id])); } + if (conf.mathExpression.searchRegion) { + parts.push(conf.mathExpression.searchRegion); + } + if (conf.mathExpression.searchAccount) { + parts.push(conf.mathExpression.searchAccount); + } } if (conf.metricStat) { parts.push(conf.metricStat.namespace); diff --git a/packages/@aws-cdk/aws-cloudwatch/lib/private/rendering.ts b/packages/@aws-cdk/aws-cloudwatch/lib/private/rendering.ts index 8553d9ad5c486..9223695a96c67 100644 --- a/packages/@aws-cdk/aws-cloudwatch/lib/private/rendering.ts +++ b/packages/@aws-cdk/aws-cloudwatch/lib/private/rendering.ts @@ -55,6 +55,8 @@ function metricGraphJson(metric: IMetric, yAxis?: string, id?: string) { withExpression(expr) { options.expression = expr.expression; + if (expr.searchAccount) { options.accountId = accountIfDifferentFromStack(expr.searchAccount); } + if (expr.searchRegion) { options.region = regionIfDifferentFromStack(expr.searchRegion); } if (expr.period && expr.period !== 300) { options.period = expr.period; } }, }); diff --git a/packages/@aws-cdk/aws-cloudwatch/package.json b/packages/@aws-cdk/aws-cloudwatch/package.json index 683ca79bde154..9e5d8892953a1 100644 --- a/packages/@aws-cdk/aws-cloudwatch/package.json +++ b/packages/@aws-cdk/aws-cloudwatch/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::CloudWatch", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -74,12 +73,12 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-iam": "0.0.0", diff --git a/packages/@aws-cdk/aws-cloudwatch/test/alarm.test.ts b/packages/@aws-cdk/aws-cloudwatch/test/alarm.test.ts index c2381d2891a86..dcde88284aadd 100644 --- a/packages/@aws-cdk/aws-cloudwatch/test/alarm.test.ts +++ b/packages/@aws-cdk/aws-cloudwatch/test/alarm.test.ts @@ -9,9 +9,7 @@ const testMetric = new Metric({ }); describe('Alarm', () => { - test('alarm does not accept a math expression with more than 10 metrics', () => { - const stack = new Stack(); const usingMetrics: Record = {}; @@ -30,19 +28,15 @@ describe('Alarm', () => { }); expect(() => { - new Alarm(stack, 'Alarm', { metric: math, threshold: 1000, evaluationPeriods: 3, }); - }).toThrow(/Alarms on math expressions cannot contain more than 10 individual metrics/); - - }); - test('non ec2 instance related alarm does not accept EC2 action', () => { + test('non ec2 instance related alarm does not accept EC2 action', () => { const stack = new Stack(); const alarm = new Alarm(stack, 'Alarm', { metric: testMetric, @@ -53,8 +47,8 @@ describe('Alarm', () => { expect(() => { alarm.addAlarmAction(new Ec2TestAlarmAction('arn:aws:automate:us-east-1:ec2:reboot')); }).toThrow(/EC2 alarm actions requires an EC2 Per-Instance Metric. \(.+ does not have an 'InstanceId' dimension\)/); - }); + test('can make simple alarm', () => { // GIVEN const stack = new Stack(); @@ -76,8 +70,6 @@ describe('Alarm', () => { Statistic: 'Average', Threshold: 1000, }); - - }); test('override metric period in Alarm', () => { @@ -102,8 +94,6 @@ describe('Alarm', () => { Statistic: 'Average', Threshold: 1000, }); - - }); test('override statistic Alarm', () => { @@ -126,11 +116,9 @@ describe('Alarm', () => { Namespace: 'CDK/Test', Period: 300, Statistic: 'Maximum', - ExtendedStatistic: Match.absentProperty(), + ExtendedStatistic: Match.absent(), Threshold: 1000, }); - - }); test('can use percentile in Alarm', () => { @@ -152,12 +140,10 @@ describe('Alarm', () => { MetricName: 'Metric', Namespace: 'CDK/Test', Period: 300, - Statistic: Match.absentProperty(), + Statistic: Match.absent(), ExtendedStatistic: 'p99', Threshold: 1000, }); - - }); test('can set DatapointsToAlarm', () => { @@ -183,8 +169,6 @@ describe('Alarm', () => { Statistic: 'Average', Threshold: 1000, }); - - }); test('can add actions to alarms', () => { @@ -208,8 +192,6 @@ describe('Alarm', () => { InsufficientDataActions: ['B'], OKActions: ['C'], }); - - }); test('can make alarm directly from metric', () => { @@ -234,8 +216,6 @@ describe('Alarm', () => { Statistic: 'Minimum', Threshold: 1000, }); - - }); test('can use percentile string to make alarm', () => { @@ -253,8 +233,6 @@ describe('Alarm', () => { Template.fromStack(stack).hasResourceProperties('AWS::CloudWatch::Alarm', { ExtendedStatistic: 'p99.9', }); - - }); test('can use a generic string for extended statistic to make alarm', () => { @@ -270,12 +248,10 @@ describe('Alarm', () => { // THEN Template.fromStack(stack).hasResourceProperties('AWS::CloudWatch::Alarm', { - Statistic: Match.absentProperty(), + Statistic: Match.absent(), ExtendedStatistic: 'tm99.9999999999', }); - }); - }); class TestAlarmAction implements IAlarmAction { diff --git a/packages/@aws-cdk/aws-cloudwatch/test/cross-environment.test.ts b/packages/@aws-cdk/aws-cloudwatch/test/cross-environment.test.ts index 50278d9a83d54..61b006e9d8f89 100644 --- a/packages/@aws-cdk/aws-cloudwatch/test/cross-environment.test.ts +++ b/packages/@aws-cdk/aws-cloudwatch/test/cross-environment.test.ts @@ -1,4 +1,4 @@ -import { Template } from '@aws-cdk/assertions'; +import { Match, Template } from '@aws-cdk/assertions'; import { Duration, Stack } from '@aws-cdk/core'; import { Alarm, GraphWidget, IWidget, MathExpression, Metric } from '../lib'; @@ -7,11 +7,13 @@ const a = new Metric({ namespace: 'Test', metricName: 'ACount' }); let stack1: Stack; let stack2: Stack; let stack3: Stack; +let stack4: Stack; describe('cross environment', () => { beforeEach(() => { stack1 = new Stack(undefined, undefined, { env: { region: 'pluto', account: '1234' } }); stack2 = new Stack(undefined, undefined, { env: { region: 'mars', account: '5678' } }); stack3 = new Stack(undefined, undefined, { env: { region: 'pluto', account: '0000' } }); + stack4 = new Stack(undefined, undefined); }); describe('in graphs', () => { @@ -78,6 +80,35 @@ describe('cross environment', () => { }); + + test('math expressions with explicit account and region will render in environment agnostic stack', () => { + // GIVEN + const expression = 'SEARCH(\'MetricName="ACount"\', \'Sum\', 300)'; + + const b = new MathExpression({ + expression, + usingMetrics: {}, + label: 'Test label', + searchAccount: '5678', + searchRegion: 'mars', + }); + + const graph = new GraphWidget({ + left: [ + b, + ], + }); + + // THEN + graphMetricsAre(new Stack(), graph, [ + [{ + expression, + accountId: '5678', + region: 'mars', + label: 'Test label', + }], + ]); + }); }); describe('in alarms', () => { @@ -95,12 +126,10 @@ describe('cross environment', () => { Namespace: 'Test', Period: 300, }); - - }); test('metric attached to stack1 will throw in stack2', () => { - // Cross-region/cross-account metrics are supported in Dashboards but not in Alarms + // Cross-region metrics are supported in Dashboards but not in Alarms // GIVEN expect(() => { @@ -110,8 +139,6 @@ describe('cross environment', () => { metric: a.attachTo(stack1), }); }).toThrow(/Cannot create an Alarm in region 'mars' based on metric 'ACount' in 'pluto'/); - - }); test('metric attached to stack3 will render in stack1', () => { @@ -178,12 +205,49 @@ describe('cross environment', () => { }); }); + test('metric from same account as stack will not have accountId', () => { + // GIVEN + + // including label property will force Alarm configuration to "modern" config. + const b = new Metric({ + namespace: 'Test', + metricName: 'ACount', + label: 'my-label', + }); + + new Alarm(stack1, 'Alarm', { + threshold: 1, + evaluationPeriods: 1, + metric: b, + }); + + // THEN + Template.fromStack(stack1).hasResourceProperties('AWS::CloudWatch::Alarm', { + Metrics: [ + { + AccountId: Match.absent(), + Id: 'm1', + Label: 'my-label', + MetricStat: { + Metric: { + MetricName: 'ACount', + Namespace: 'Test', + }, + Period: 300, + Stat: 'Average', + }, + ReturnData: true, + }, + ], + }); + }); + test('math expression can render in a different account', () => { // GIVEN const b = new Metric({ namespace: 'Test', metricName: 'ACount', - account: '1234', + account: '5678', }); const c = new MathExpression({ @@ -219,7 +283,7 @@ describe('cross environment', () => { ReturnData: false, }, { - AccountId: '1234', + AccountId: '5678', Id: 'b', MetricStat: { Metric: { @@ -234,6 +298,214 @@ describe('cross environment', () => { ], }); }); + + test('math expression from same account as stack will not have accountId', () => { + // GIVEN + const b = new Metric({ + namespace: 'Test', + metricName: 'ACount', + account: '1234', + }); + + const c = new MathExpression({ + expression: 'a + b', + usingMetrics: { a: a.attachTo(stack1), b }, + period: Duration.minutes(1), + }); + + new Alarm(stack1, 'Alarm', { + threshold: 1, + evaluationPeriods: 1, + metric: c, + }); + + // THEN + Template.fromStack(stack1).hasResourceProperties('AWS::CloudWatch::Alarm', { + Metrics: [ + { + Expression: 'a + b', + Id: 'expr_1', + }, + { + AccountId: Match.absent(), + Id: 'a', + MetricStat: { + Metric: { + MetricName: 'ACount', + Namespace: 'Test', + }, + Period: 60, + Stat: 'Average', + }, + ReturnData: false, + }, + { + AccountId: Match.absent(), + Id: 'b', + MetricStat: { + Metric: { + MetricName: 'ACount', + Namespace: 'Test', + }, + Period: 60, + Stat: 'Average', + }, + ReturnData: false, + }, + ], + }); + }); + + test('math expression with different searchAccount will throw', () => { + // GIVEN + const b = new Metric({ + namespace: 'Test', + metricName: 'ACount', + account: '1234', + }); + + const c = new MathExpression({ + expression: 'a + b', + usingMetrics: { a: a.attachTo(stack3), b }, + period: Duration.minutes(1), + searchAccount: '5678', + }); + + // THEN + expect(() => { + new Alarm(stack1, 'Alarm', { + threshold: 1, + evaluationPeriods: 1, + metric: c, + }); + }).toThrow(/Cannot create an Alarm based on a MathExpression which specifies a searchAccount or searchRegion/); + }); + + test('math expression with different searchRegion will throw', () => { + // GIVEN + const b = new Metric({ + namespace: 'Test', + metricName: 'ACount', + account: '1234', + }); + + const c = new MathExpression({ + expression: 'a + b', + usingMetrics: { a: a.attachTo(stack3), b }, + period: Duration.minutes(1), + searchRegion: 'mars', + }); + + // THEN + expect(() => { + new Alarm(stack1, 'Alarm', { + threshold: 1, + evaluationPeriods: 1, + metric: c, + }); + }).toThrow(/Cannot create an Alarm based on a MathExpression which specifies a searchAccount or searchRegion/); + }); + + describe('accountId requirements', () => { + test('metric account is not defined', () => { + const metric = new Metric({ + namespace: 'Test', + metricName: 'ACount', + }); + + new Alarm(stack4, 'Alarm', { + threshold: 1, + evaluationPeriods: 1, + metric, + }); + + // Alarm will be defined as legacy alarm. + Template.fromStack(stack4).hasResourceProperties('AWS::CloudWatch::Alarm', { + Threshold: 1, + EvaluationPeriods: 1, + MetricName: 'ACount', + Namespace: 'Test', + }); + }); + + test('metric account is defined and stack account is token', () => { + const metric = new Metric({ + namespace: 'Test', + metricName: 'ACount', + account: '123456789', + }); + + new Alarm(stack4, 'Alarm', { + threshold: 1, + evaluationPeriods: 1, + metric, + }); + + // Alarm will be defined as modern alarm. + Template.fromStack(stack4).hasResourceProperties('AWS::CloudWatch::Alarm', { + Metrics: Match.anyValue(), + }); + }); + + test('metric account is attached to stack account', () => { + const metric = new Metric({ + namespace: 'Test', + metricName: 'ACount', + }); + + new Alarm(stack4, 'Alarm', { + threshold: 1, + evaluationPeriods: 1, + metric: metric.attachTo(stack4), + }); + + // Alarm will be defined as legacy alarm. + Template.fromStack(stack4).hasResourceProperties('AWS::CloudWatch::Alarm', { + Threshold: 1, + EvaluationPeriods: 1, + MetricName: 'ACount', + Namespace: 'Test', + }); + }); + + test('metric account === stack account, but both are tokens', () => { + const metric = new Metric({ + namespace: 'Test', + metricName: 'ACount', + account: stack4.account, + }); + + new Alarm(stack4, 'Alarm', { + threshold: 1, + evaluationPeriods: 1, + metric, + }); + + // Alarm will be defined as modern alarm, since there is no way of knowing that the two tokens are equal. + Template.fromStack(stack4).hasResourceProperties('AWS::CloudWatch::Alarm', { + Metrics: Match.anyValue(), + }); + }); + + test('metric account !== stack account', () => { + const metric = new Metric({ + namespace: 'Test', + metricName: 'ACount', + account: '123456789', + }); + + new Alarm(stack1, 'Alarm', { + threshold: 1, + evaluationPeriods: 1, + metric, + }); + + // Alarm will be defined as modern alarm. + Template.fromStack(stack1).hasResourceProperties('AWS::CloudWatch::Alarm', { + Metrics: Match.anyValue(), + }); + }); + }); }); }); diff --git a/packages/@aws-cdk/aws-codeartifact/.eslintrc.js b/packages/@aws-cdk/aws-codeartifact/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-codeartifact/.eslintrc.js +++ b/packages/@aws-cdk/aws-codeartifact/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-codeartifact/jest.config.js b/packages/@aws-cdk/aws-codeartifact/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-codeartifact/jest.config.js +++ b/packages/@aws-cdk/aws-codeartifact/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-codeartifact/package.json b/packages/@aws-cdk/aws-codeartifact/package.json index 3dc1f03908775..3d2410610103b 100644 --- a/packages/@aws-cdk/aws-codeartifact/package.json +++ b/packages/@aws-cdk/aws-codeartifact/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::CodeArtifact", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-codebuild/.eslintrc.js b/packages/@aws-cdk/aws-codebuild/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-codebuild/.eslintrc.js +++ b/packages/@aws-cdk/aws-codebuild/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-codebuild/.gitignore b/packages/@aws-cdk/aws-codebuild/.gitignore index dcc1dc41e477f..17a41566f0002 100644 --- a/packages/@aws-cdk/aws-codebuild/.gitignore +++ b/packages/@aws-cdk/aws-codebuild/.gitignore @@ -15,4 +15,5 @@ nyc.config.js *.snk !.eslintrc.js -junit.xml \ No newline at end of file +junit.xml +!jest.config.js \ No newline at end of file diff --git a/packages/@aws-cdk/aws-codebuild/.npmignore b/packages/@aws-cdk/aws-codebuild/.npmignore index 9a032ae80868c..e8acf10a468a1 100644 --- a/packages/@aws-cdk/aws-codebuild/.npmignore +++ b/packages/@aws-cdk/aws-codebuild/.npmignore @@ -24,4 +24,5 @@ tsconfig.json **/cdk.out junit.xml test/ -!*.lit.ts \ No newline at end of file +!*.lit.ts +jest.config.js \ No newline at end of file diff --git a/packages/@aws-cdk/aws-codebuild/jest.config.js b/packages/@aws-cdk/aws-codebuild/jest.config.js new file mode 100644 index 0000000000000..34818e1593f6b --- /dev/null +++ b/packages/@aws-cdk/aws-codebuild/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/@aws-cdk/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-codebuild/lib/project.ts b/packages/@aws-cdk/aws-codebuild/lib/project.ts index fdd2e1295f6bb..186c58f84138f 100644 --- a/packages/@aws-cdk/aws-codebuild/lib/project.ts +++ b/packages/@aws-cdk/aws-codebuild/lib/project.ts @@ -1656,8 +1656,9 @@ class ArmBuildImage implements IBuildImage { public validate(buildEnvironment: BuildEnvironment): string[] { const ret = []; if (buildEnvironment.computeType && + buildEnvironment.computeType !== ComputeType.SMALL && buildEnvironment.computeType !== ComputeType.LARGE) { - ret.push(`ARM images only support ComputeType '${ComputeType.LARGE}' - ` + + ret.push(`ARM images only support ComputeTypes '${ComputeType.SMALL}' and '${ComputeType.LARGE}' - ` + `'${buildEnvironment.computeType}' was given`); } return ret; @@ -1724,6 +1725,8 @@ export class LinuxBuildImage implements IBuildImage { public static readonly AMAZON_LINUX_2_3 = LinuxBuildImage.codeBuildImage('aws/codebuild/amazonlinux2-x86_64-standard:3.0'); public static readonly AMAZON_LINUX_2_ARM: IBuildImage = new ArmBuildImage('aws/codebuild/amazonlinux2-aarch64-standard:1.0'); + /** Image "aws/codebuild/amazonlinux2-aarch64-standard:2.0". */ + public static readonly AMAZON_LINUX_2_ARM_2: IBuildImage = new ArmBuildImage('aws/codebuild/amazonlinux2-aarch64-standard:2.0'); /** @deprecated Use {@link STANDARD_2_0} and specify runtime in buildspec runtime-versions section */ public static readonly UBUNTU_14_04_BASE = LinuxBuildImage.codeBuildImage('aws/codebuild/ubuntu-base:14.04'); diff --git a/packages/@aws-cdk/aws-codebuild/package.json b/packages/@aws-cdk/aws-codebuild/package.json index e7591a3ab4fbb..9b54a075fce61 100644 --- a/packages/@aws-cdk/aws-codebuild/package.json +++ b/packages/@aws-cdk/aws-codebuild/package.json @@ -76,16 +76,16 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", "@aws-cdk/aws-sns": "0.0.0", "@aws-cdk/aws-sqs": "0.0.0", - "@types/nodeunit": "^0.0.32", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24", "aws-sdk": "^2.848.0", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "nodeunit": "^0.11.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-cloudwatch": "0.0.0", diff --git a/packages/@aws-cdk/aws-codebuild/test/build-spec.test.ts b/packages/@aws-cdk/aws-codebuild/test/build-spec.test.ts new file mode 100644 index 0000000000000..e250a2c7fd6c4 --- /dev/null +++ b/packages/@aws-cdk/aws-codebuild/test/build-spec.test.ts @@ -0,0 +1,409 @@ +// import * as cdk from '@aws-cdk/core'; +import * as codebuild from '../lib'; + +/* eslint-disable quote-props */ +/* eslint-disable quotes */ + +describe('Test BuildSpec merge', () => { + test('merge two simple specs', () => { + const lhs = codebuild.BuildSpec.fromObject({ + phases: { + pre_build: { + commands: [ + 'install', + ], + }, + }, + }); + const rhs = codebuild.BuildSpec.fromObject({ + phases: { + build: { + commands: 'build', + }, + }, + }); + + const merged = codebuild.mergeBuildSpecs(lhs, rhs); + + expect((merged as any).spec).toEqual({ + phases: { + pre_build: { + commands: [ + 'install', + ], + }, + build: { + commands: [ + 'build', + ], + }, + }, + }); + }); + + test('merge command lists', () => { + const lhs = codebuild.BuildSpec.fromObject({ + phases: { + build: { + commands: [ + 'build1', + ], + }, + }, + }); + const rhs = codebuild.BuildSpec.fromObject({ + phases: { + build: { + commands: 'build2', + }, + }, + }); + + const merged = codebuild.mergeBuildSpecs(lhs, rhs); + + expect((merged as any).spec).toEqual({ + phases: { + build: { + commands: [ + 'build1', + 'build2', + ], + }, + }, + }); + }); + + test('do not merge artifacts', () => { + const lhs = codebuild.BuildSpec.fromObject({ + phases: { + build: { + commands: [ + 'build1', + ], + }, + }, + artifacts: { + 'base-directory': 'subdir/cdk.out', + }, + }); + const rhs = codebuild.BuildSpec.fromObject({ + phases: { + build: { + commands: [ + 'build2', + ], + }, + }, + artifacts: { + 'base-directory': 'subdir/cdk.out', + }, + }); + + expect(() => { + codebuild.mergeBuildSpecs(lhs, rhs); + }).toThrow(); + }); + + test('merge complex example', () => { + const cdkSpec = codebuild.BuildSpec.fromObject({ + env: { + 'variables': { + NPM_TOKEN: 'supersecret', + }, + }, + phases: { + pre_build: { + commands: [ + 'install1', + ], + }, + build: { + commands: [ + 'build1', + 'test1', + 'cdk synth', + ], + }, + }, + }); + const userSpec = codebuild.BuildSpec.fromObject({ + version: 0.2, + env: { + 'variables': { + JAVA_HOME: '/usr/lib/jvm/java-8-openjdk-amd64', + }, + 'parameter-store': { + LOGIN_PASSWORD: '/CodeBuild/dockerLoginPassword', + }, + }, + phases: { + install: { + commands: [ + 'echo Entered the install phase...', + 'apt-get update -y', + 'apt-get install -y maven', + ], + finally: [ + 'echo This always runs even if the update or install command fails', + ], + }, + pre_build: { + commands: [ + 'echo Entered the pre_build phase...', + 'docker login -u User -p $LOGIN_PASSWORD', + ], + finally: [ + 'echo This always runs even if the login command fails', + ], + }, + build: { + commands: [ + 'echo Entered the build phase...', + 'echo Build started on `date`', + 'mvn install', + ], + finally: [ + 'echo This always runs even if the install command fails', + ], + }, + post_build: { + commands: [ + 'echo Entered the post_build phase...', + 'echo Build completed on `date`', + ], + }, + }, + reports: { + 'arn:aws:codebuild:your-region:your-aws-account-id:report-group/report-group-name-1': { + 'files': [ + '**/*', + ], + 'base-directory': 'target/tests/reports', + 'discard-paths': 'no', + }, + 'reportGroupCucumberJson': { + 'files': [ + 'cucumber/target/cucumber-tests.xml', + ], + 'discard-paths': 'yes', + 'file-format': 'CUCUMBERJSON', + }, + }, + artifacts: { + 'files': [ + 'target/messageUtil-1.0.jar', + ], + 'discard-paths': 'yes', + 'secondary-artifacts': { + artifact1: { + 'files': [ + 'target/artifact-1.0.jar', + ], + 'discard-paths': 'yes', + }, + artifact2: { + 'files': [ + 'target/artifact-2.0.jar', + ], + 'discard-paths': 'yes', + }, + }, + }, + cache: { + paths: [ + '/root/.m2/**/*', + ], + }, + }); + + const merged = codebuild.mergeBuildSpecs(userSpec, cdkSpec); + + expect((merged as any).spec).toEqual({ + version: 0.2, + env: { + 'variables': { + JAVA_HOME: '/usr/lib/jvm/java-8-openjdk-amd64', + NPM_TOKEN: 'supersecret', + }, + 'parameter-store': { + LOGIN_PASSWORD: '/CodeBuild/dockerLoginPassword', + }, + }, + phases: { + install: { + commands: [ + 'echo Entered the install phase...', + 'apt-get update -y', + 'apt-get install -y maven', + ], + finally: [ + 'echo This always runs even if the update or install command fails', + ], + }, + pre_build: { + commands: [ + 'echo Entered the pre_build phase...', + 'docker login -u User -p $LOGIN_PASSWORD', + 'install1', + ], + finally: [ + 'echo This always runs even if the login command fails', + ], + }, + build: { + commands: [ + 'echo Entered the build phase...', + 'echo Build started on `date`', + 'mvn install', + 'build1', + 'test1', + 'cdk synth', + ], + finally: [ + 'echo This always runs even if the install command fails', + ], + }, + post_build: { + commands: [ + 'echo Entered the post_build phase...', + 'echo Build completed on `date`', + ], + }, + }, + reports: { + 'arn:aws:codebuild:your-region:your-aws-account-id:report-group/report-group-name-1': { + 'files': [ + '**/*', + ], + 'base-directory': 'target/tests/reports', + 'discard-paths': 'no', + }, + 'reportGroupCucumberJson': { + 'files': [ + 'cucumber/target/cucumber-tests.xml', + ], + 'discard-paths': 'yes', + 'file-format': 'CUCUMBERJSON', + }, + }, + artifacts: { + 'files': [ + 'target/messageUtil-1.0.jar', + ], + 'discard-paths': 'yes', + 'secondary-artifacts': { + artifact1: { + 'files': [ + 'target/artifact-1.0.jar', + ], + 'discard-paths': 'yes', + }, + artifact2: { + 'files': [ + 'target/artifact-2.0.jar', + ], + 'discard-paths': 'yes', + }, + }, + }, + cache: { + paths: [ + '/root/.m2/**/*', + ], + }, + }); + }); + + test('override duplicate reports', () => { + const lhs = codebuild.BuildSpec.fromObject({ + phases: { + pre_build: { + commands: [ + 'install', + ], + }, + }, + reports: { + 'report1': { + 'files': [ + 'report1/a', + ], + 'discard-paths': 'no', + 'base-directory': 'target/tests/reports', + }, + 'report2': { + 'files': [ + 'cucumber/target/cucumber-tests.xml', + ], + 'discard-paths': 'yes', + 'file-format': 'CUCUMBERJSON', + }, + }, + }); + const rhs = codebuild.BuildSpec.fromObject({ + phases: { + build: { + commands: [ + 'build', + ], + }, + }, + reports: { + 'report1': { + 'files': [ + 'report1/b', + 'report1/b2', + ], + 'base-directory': 'target/tests/reportsB', + }, + 'report3': { + 'files': [ + 'cucumber/target/cucumber-tests.xml', + ], + 'discard-paths': 'yes', + 'file-format': 'CUCUMBERJSON', + }, + }, + }); + + const merged = codebuild.mergeBuildSpecs(lhs, rhs); + + expect((merged as any).spec).toEqual({ + phases: { + pre_build: { + commands: [ + 'install', + ], + }, + build: { + commands: [ + 'build', + ], + }, + }, + reports: { + 'report1': { + 'files': [ + 'report1/b', + 'report1/b2', + ], + 'base-directory': 'target/tests/reportsB', + }, + 'report2': { + 'files': [ + 'cucumber/target/cucumber-tests.xml', + ], + 'discard-paths': 'yes', + 'file-format': 'CUCUMBERJSON', + }, + 'report3': { + 'files': [ + 'cucumber/target/cucumber-tests.xml', + ], + 'discard-paths': 'yes', + 'file-format': 'CUCUMBERJSON', + }, + }, + }); + }); +}); diff --git a/packages/@aws-cdk/aws-codebuild/test/codebuild.test.ts b/packages/@aws-cdk/aws-codebuild/test/codebuild.test.ts new file mode 100644 index 0000000000000..f5bb3eacda8d1 --- /dev/null +++ b/packages/@aws-cdk/aws-codebuild/test/codebuild.test.ts @@ -0,0 +1,1908 @@ +import { ABSENT, SynthUtils } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; +import * as codecommit from '@aws-cdk/aws-codecommit'; +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as kms from '@aws-cdk/aws-kms'; +import * as s3 from '@aws-cdk/aws-s3'; +import * as cdk from '@aws-cdk/core'; +import * as codebuild from '../lib'; +import { CodePipelineSource } from '../lib/codepipeline-source'; +import { NoSource } from '../lib/no-source'; + +/* eslint-disable quote-props */ + +describe('default properties', () => { + test('with CodePipeline source', () => { + const stack = new cdk.Stack(); + + new codebuild.PipelineProject(stack, 'MyProject'); + + expect(stack).toMatchTemplate({ + 'Resources': { + 'MyProjectRole9BBE5233': { + 'Type': 'AWS::IAM::Role', + 'Properties': { + 'AssumeRolePolicyDocument': { + 'Statement': [ + { + 'Action': 'sts:AssumeRole', + 'Effect': 'Allow', + 'Principal': { + 'Service': 'codebuild.amazonaws.com', + }, + }, + ], + 'Version': '2012-10-17', + }, + }, + }, + 'MyProjectRoleDefaultPolicyB19B7C29': { + 'Type': 'AWS::IAM::Policy', + 'Properties': { + 'PolicyDocument': { + 'Statement': [ + { + 'Action': [ + 'logs:CreateLogGroup', + 'logs:CreateLogStream', + 'logs:PutLogEvents', + ], + 'Effect': 'Allow', + 'Resource': [ + { + 'Fn::Join': [ + '', + [ + 'arn:', + { + 'Ref': 'AWS::Partition', + }, + ':logs:', + { + 'Ref': 'AWS::Region', + }, + ':', + { + 'Ref': 'AWS::AccountId', + }, + ':log-group:/aws/codebuild/', + { + 'Ref': 'MyProject39F7B0AE', + }, + ], + ], + }, + { + 'Fn::Join': [ + '', + [ + 'arn:', + { + 'Ref': 'AWS::Partition', + }, + ':logs:', + { + 'Ref': 'AWS::Region', + }, + ':', + { + 'Ref': 'AWS::AccountId', + }, + ':log-group:/aws/codebuild/', + { + 'Ref': 'MyProject39F7B0AE', + }, + ':*', + ], + ], + }, + ], + }, + { + 'Action': [ + 'codebuild:CreateReportGroup', + 'codebuild:CreateReport', + 'codebuild:UpdateReport', + 'codebuild:BatchPutTestCases', + 'codebuild:BatchPutCodeCoverages', + ], + 'Effect': 'Allow', + 'Resource': { + 'Fn::Join': ['', [ + 'arn:', + { 'Ref': 'AWS::Partition' }, + ':codebuild:', + { 'Ref': 'AWS::Region' }, + ':', + { 'Ref': 'AWS::AccountId' }, + ':report-group/', + { 'Ref': 'MyProject39F7B0AE' }, + '-*', + ]], + }, + }, + ], + 'Version': '2012-10-17', + }, + 'PolicyName': 'MyProjectRoleDefaultPolicyB19B7C29', + 'Roles': [ + { + 'Ref': 'MyProjectRole9BBE5233', + }, + ], + }, + }, + 'MyProject39F7B0AE': { + 'Type': 'AWS::CodeBuild::Project', + 'Properties': { + 'Source': { + 'Type': 'CODEPIPELINE', + }, + 'Artifacts': { + 'Type': 'CODEPIPELINE', + }, + 'ServiceRole': { + 'Fn::GetAtt': [ + 'MyProjectRole9BBE5233', + 'Arn', + ], + }, + 'Environment': { + 'Type': 'LINUX_CONTAINER', + 'PrivilegedMode': false, + 'Image': 'aws/codebuild/standard:1.0', + 'ImagePullCredentialsType': 'CODEBUILD', + 'ComputeType': 'BUILD_GENERAL1_SMALL', + }, + 'EncryptionKey': 'alias/aws/s3', + }, + }, + }, + }); + }); + + test('with CodeCommit source', () => { + const stack = new cdk.Stack(); + + const repo = new codecommit.Repository(stack, 'MyRepo', { + repositoryName: 'hello-cdk', + }); + + const source = codebuild.Source.codeCommit({ repository: repo, cloneDepth: 2 }); + + new codebuild.Project(stack, 'MyProject', { + source, + }); + + expect(stack).toMatchTemplate({ + 'Resources': { + 'MyRepoF4F48043': { + 'Type': 'AWS::CodeCommit::Repository', + 'Properties': { + 'RepositoryName': 'hello-cdk', + }, + }, + 'MyProjectRole9BBE5233': { + 'Type': 'AWS::IAM::Role', + 'Properties': { + 'AssumeRolePolicyDocument': { + 'Statement': [ + { + 'Action': 'sts:AssumeRole', + 'Effect': 'Allow', + 'Principal': { + 'Service': 'codebuild.amazonaws.com', + }, + }, + ], + 'Version': '2012-10-17', + }, + }, + }, + 'MyProjectRoleDefaultPolicyB19B7C29': { + 'Type': 'AWS::IAM::Policy', + 'Properties': { + 'PolicyDocument': { + 'Statement': [ + { + 'Action': 'codecommit:GitPull', + 'Effect': 'Allow', + 'Resource': { + 'Fn::GetAtt': [ + 'MyRepoF4F48043', + 'Arn', + ], + }, + }, + { + 'Action': [ + 'logs:CreateLogGroup', + 'logs:CreateLogStream', + 'logs:PutLogEvents', + ], + 'Effect': 'Allow', + 'Resource': [ + { + 'Fn::Join': [ + '', + [ + 'arn:', + { + 'Ref': 'AWS::Partition', + }, + ':logs:', + { + 'Ref': 'AWS::Region', + }, + ':', + { + 'Ref': 'AWS::AccountId', + }, + ':log-group:/aws/codebuild/', + { + 'Ref': 'MyProject39F7B0AE', + }, + ], + ], + }, + { + 'Fn::Join': [ + '', + [ + 'arn:', + { + 'Ref': 'AWS::Partition', + }, + ':logs:', + { + 'Ref': 'AWS::Region', + }, + ':', + { + 'Ref': 'AWS::AccountId', + }, + ':log-group:/aws/codebuild/', + { + 'Ref': 'MyProject39F7B0AE', + }, + ':*', + ], + ], + }, + ], + }, + { + 'Action': [ + 'codebuild:CreateReportGroup', + 'codebuild:CreateReport', + 'codebuild:UpdateReport', + 'codebuild:BatchPutTestCases', + 'codebuild:BatchPutCodeCoverages', + ], + 'Effect': 'Allow', + 'Resource': { + 'Fn::Join': ['', [ + 'arn:', + { 'Ref': 'AWS::Partition' }, + ':codebuild:', + { 'Ref': 'AWS::Region' }, + ':', + { 'Ref': 'AWS::AccountId' }, + ':report-group/', + { 'Ref': 'MyProject39F7B0AE' }, + '-*', + ]], + }, + }, + ], + 'Version': '2012-10-17', + }, + 'PolicyName': 'MyProjectRoleDefaultPolicyB19B7C29', + 'Roles': [ + { + 'Ref': 'MyProjectRole9BBE5233', + }, + ], + }, + }, + 'MyProject39F7B0AE': { + 'Type': 'AWS::CodeBuild::Project', + 'Properties': { + 'Artifacts': { + 'Type': 'NO_ARTIFACTS', + }, + 'Environment': { + 'ComputeType': 'BUILD_GENERAL1_SMALL', + 'Image': 'aws/codebuild/standard:1.0', + 'ImagePullCredentialsType': 'CODEBUILD', + 'PrivilegedMode': false, + 'Type': 'LINUX_CONTAINER', + }, + 'ServiceRole': { + 'Fn::GetAtt': [ + 'MyProjectRole9BBE5233', + 'Arn', + ], + }, + 'Source': { + 'Location': { + 'Fn::GetAtt': [ + 'MyRepoF4F48043', + 'CloneUrlHttp', + ], + }, + 'GitCloneDepth': 2, + 'Type': 'CODECOMMIT', + }, + 'EncryptionKey': 'alias/aws/s3', + }, + }, + }, + }); + }); + + test('with S3Bucket source', () => { + const stack = new cdk.Stack(); + const bucket = new s3.Bucket(stack, 'MyBucket'); + + new codebuild.Project(stack, 'MyProject', { + source: codebuild.Source.s3({ + bucket, + path: 'path/to/source.zip', + }), + environment: { + buildImage: codebuild.WindowsBuildImage.WINDOWS_BASE_2_0, + }, + }); + + expect(stack).toMatchTemplate({ + 'Resources': { + 'MyBucketF68F3FF0': { + 'Type': 'AWS::S3::Bucket', + 'DeletionPolicy': 'Retain', + 'UpdateReplacePolicy': 'Retain', + }, + 'MyProjectRole9BBE5233': { + 'Type': 'AWS::IAM::Role', + 'Properties': { + 'AssumeRolePolicyDocument': { + 'Statement': [ + { + 'Action': 'sts:AssumeRole', + 'Effect': 'Allow', + 'Principal': { + 'Service': 'codebuild.amazonaws.com', + }, + }, + ], + 'Version': '2012-10-17', + }, + }, + }, + 'MyProjectRoleDefaultPolicyB19B7C29': { + 'Type': 'AWS::IAM::Policy', + 'Properties': { + 'PolicyDocument': { + 'Statement': [ + { + 'Action': [ + 's3:GetObject*', + 's3:GetBucket*', + 's3:List*', + ], + 'Effect': 'Allow', + 'Resource': [ + { + 'Fn::GetAtt': [ + 'MyBucketF68F3FF0', + 'Arn', + ], + }, + { + 'Fn::Join': [ + '', + [ + { + 'Fn::GetAtt': [ + 'MyBucketF68F3FF0', + 'Arn', + ], + }, + '/path/to/source.zip', + ], + ], + }, + ], + }, + { + 'Action': [ + 'logs:CreateLogGroup', + 'logs:CreateLogStream', + 'logs:PutLogEvents', + ], + 'Effect': 'Allow', + 'Resource': [ + { + 'Fn::Join': [ + '', + [ + 'arn:', + { + 'Ref': 'AWS::Partition', + }, + ':logs:', + { + 'Ref': 'AWS::Region', + }, + ':', + { + 'Ref': 'AWS::AccountId', + }, + ':log-group:/aws/codebuild/', + { + 'Ref': 'MyProject39F7B0AE', + }, + ], + ], + }, + { + 'Fn::Join': [ + '', + [ + 'arn:', + { + 'Ref': 'AWS::Partition', + }, + ':logs:', + { + 'Ref': 'AWS::Region', + }, + ':', + { + 'Ref': 'AWS::AccountId', + }, + ':log-group:/aws/codebuild/', + { + 'Ref': 'MyProject39F7B0AE', + }, + ':*', + ], + ], + }, + ], + }, + { + 'Action': [ + 'codebuild:CreateReportGroup', + 'codebuild:CreateReport', + 'codebuild:UpdateReport', + 'codebuild:BatchPutTestCases', + 'codebuild:BatchPutCodeCoverages', + ], + 'Effect': 'Allow', + 'Resource': { + 'Fn::Join': ['', [ + 'arn:', + { 'Ref': 'AWS::Partition' }, + ':codebuild:', + { 'Ref': 'AWS::Region' }, + ':', + { 'Ref': 'AWS::AccountId' }, + ':report-group/', + { 'Ref': 'MyProject39F7B0AE' }, + '-*', + ]], + }, + }, + ], + 'Version': '2012-10-17', + }, + 'PolicyName': 'MyProjectRoleDefaultPolicyB19B7C29', + 'Roles': [ + { + 'Ref': 'MyProjectRole9BBE5233', + }, + ], + }, + }, + 'MyProject39F7B0AE': { + 'Type': 'AWS::CodeBuild::Project', + 'Properties': { + 'Artifacts': { + 'Type': 'NO_ARTIFACTS', + }, + 'Environment': { + 'ComputeType': 'BUILD_GENERAL1_MEDIUM', + 'Image': 'aws/codebuild/windows-base:2.0', + 'ImagePullCredentialsType': 'CODEBUILD', + 'PrivilegedMode': false, + 'Type': 'WINDOWS_CONTAINER', + }, + 'ServiceRole': { + 'Fn::GetAtt': [ + 'MyProjectRole9BBE5233', + 'Arn', + ], + }, + 'Source': { + 'Location': { + 'Fn::Join': [ + '', + [ + { + 'Ref': 'MyBucketF68F3FF0', + }, + '/path/to/source.zip', + ], + ], + }, + 'Type': 'S3', + }, + 'EncryptionKey': 'alias/aws/s3', + }, + }, + }, + }); + }); + + test('with GitHub source', () => { + const stack = new cdk.Stack(); + + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.gitHub({ + owner: 'testowner', + repo: 'testrepo', + cloneDepth: 3, + fetchSubmodules: true, + webhook: true, + reportBuildStatus: false, + webhookFilters: [ + codebuild.FilterGroup.inEventOf(codebuild.EventAction.PUSH).andTagIsNot('stable'), + codebuild.FilterGroup.inEventOf(codebuild.EventAction.PULL_REQUEST_REOPENED).andBaseBranchIs('master'), + ], + }), + }); + + expect(stack).toHaveResource('AWS::CodeBuild::Project', { + Source: { + Type: 'GITHUB', + Location: 'https://github.com/testowner/testrepo.git', + ReportBuildStatus: false, + GitCloneDepth: 3, + GitSubmodulesConfig: { + FetchSubmodules: true, + }, + }, + }); + + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + Triggers: { + Webhook: true, + FilterGroups: [ + [ + { Type: 'EVENT', Pattern: 'PUSH' }, + { Type: 'HEAD_REF', Pattern: 'refs/tags/stable', ExcludeMatchedPattern: true }, + ], + [ + { Type: 'EVENT', Pattern: 'PULL_REQUEST_REOPENED' }, + { Type: 'BASE_REF', Pattern: 'refs/heads/master' }, + ], + ], + }, + }); + }); + + test('with GitHubEnterprise source', () => { + const stack = new cdk.Stack(); + + const pushFilterGroup = codebuild.FilterGroup.inEventOf(codebuild.EventAction.PUSH); + new codebuild.Project(stack, 'MyProject', { + source: codebuild.Source.gitHubEnterprise({ + httpsCloneUrl: 'https://github.testcompany.com/testowner/testrepo', + ignoreSslErrors: true, + cloneDepth: 4, + webhook: true, + reportBuildStatus: false, + webhookFilters: [ + pushFilterGroup.andBranchIs('master'), + pushFilterGroup.andBranchIs('develop'), + pushFilterGroup.andFilePathIs('ReadMe.md'), + ], + }), + }); + + expect(stack).toHaveResource('AWS::CodeBuild::Project', { + Source: { + Type: 'GITHUB_ENTERPRISE', + InsecureSsl: true, + GitCloneDepth: 4, + ReportBuildStatus: false, + Location: 'https://github.testcompany.com/testowner/testrepo', + }, + }); + + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + Triggers: { + Webhook: true, + FilterGroups: [ + [ + { Type: 'EVENT', Pattern: 'PUSH' }, + { Type: 'HEAD_REF', Pattern: 'refs/heads/master' }, + ], + [ + { Type: 'EVENT', Pattern: 'PUSH' }, + { Type: 'HEAD_REF', Pattern: 'refs/heads/develop' }, + ], + [ + { Type: 'EVENT', Pattern: 'PUSH' }, + { Type: 'FILE_PATH', Pattern: 'ReadMe.md' }, + ], + ], + }, + }); + }); + + test('with Bitbucket source', () => { + const stack = new cdk.Stack(); + + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.bitBucket({ + owner: 'testowner', + repo: 'testrepo', + cloneDepth: 5, + reportBuildStatus: false, + webhookFilters: [ + codebuild.FilterGroup.inEventOf( + codebuild.EventAction.PULL_REQUEST_CREATED, + codebuild.EventAction.PULL_REQUEST_UPDATED, + codebuild.EventAction.PULL_REQUEST_MERGED, + ).andTagIs('v.*'), + // duplicate event actions are fine + codebuild.FilterGroup.inEventOf(codebuild.EventAction.PUSH, codebuild.EventAction.PUSH).andActorAccountIsNot('aws-cdk-dev'), + ], + }), + }); + + expect(stack).toHaveResource('AWS::CodeBuild::Project', { + Source: { + Type: 'BITBUCKET', + Location: 'https://bitbucket.org/testowner/testrepo.git', + GitCloneDepth: 5, + ReportBuildStatus: false, + }, + }); + + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + Triggers: { + Webhook: true, + FilterGroups: [ + [ + { Type: 'EVENT', Pattern: 'PULL_REQUEST_CREATED, PULL_REQUEST_UPDATED, PULL_REQUEST_MERGED' }, + { Type: 'HEAD_REF', Pattern: 'refs/tags/v.*' }, + ], + [ + { Type: 'EVENT', Pattern: 'PUSH' }, + { Type: 'ACTOR_ACCOUNT_ID', Pattern: 'aws-cdk-dev', ExcludeMatchedPattern: true }, + ], + ], + }, + }); + }); + + test('with webhookTriggersBatchBuild option', () => { + const stack = new cdk.Stack(); + + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.gitHub({ + owner: 'testowner', + repo: 'testrepo', + webhook: true, + webhookTriggersBatchBuild: true, + }), + }); + + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + Triggers: { + Webhook: true, + BuildType: 'BUILD_BATCH', + }, + BuildBatchConfig: { + ServiceRole: { + 'Fn::GetAtt': [ + 'ProjectBatchServiceRoleF97A1CFB', + 'Arn', + ], + }, + }, + }); + + expect(stack).toHaveResourceLike('AWS::IAM::Role', { + AssumeRolePolicyDocument: { + Statement: [ + { + Action: 'sts:AssumeRole', + Effect: 'Allow', + Principal: { + Service: 'codebuild.amazonaws.com', + }, + }, + ], + Version: '2012-10-17', + }, + }); + + expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [ + { + Action: [ + 'codebuild:StartBuild', + 'codebuild:StopBuild', + 'codebuild:RetryBuild', + ], + Effect: 'Allow', + Resource: { + 'Fn::GetAtt': [ + 'ProjectC78D97AD', + 'Arn', + ], + }, + }, + ], + Version: '2012-10-17', + }, + }); + }); + + test('fail creating a Project when webhook false and webhookTriggersBatchBuild option', () => { + [false, undefined].forEach((webhook) => { + const stack = new cdk.Stack(); + + expect(() => { + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.gitHub({ + owner: 'testowner', + repo: 'testrepo', + webhook, + webhookTriggersBatchBuild: true, + }), + }); + }).toThrow(/`webhookTriggersBatchBuild` cannot be used when `webhook` is `false`/); + }); + }); + + test('fail creating a Project when no build spec is given', () => { + const stack = new cdk.Stack(); + + expect(() => { + new codebuild.Project(stack, 'MyProject', { + }); + }).toThrow(/buildSpec/); + }); + + test('with VPC configuration', () => { + const stack = new cdk.Stack(); + + const bucket = new s3.Bucket(stack, 'MyBucket'); + const vpc = new ec2.Vpc(stack, 'MyVPC'); + const securityGroup = new ec2.SecurityGroup(stack, 'SecurityGroup1', { + securityGroupName: 'Bob', + vpc, + allowAllOutbound: true, + description: 'Example', + }); + const project = new codebuild.Project(stack, 'MyProject', { + source: codebuild.Source.s3({ + bucket, + path: 'path/to/source.zip', + }), + vpc, + securityGroups: [securityGroup], + }); + + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + 'VpcConfig': { + 'SecurityGroupIds': [ + { + 'Fn::GetAtt': [ + 'SecurityGroup1F554B36F', + 'GroupId', + ], + }, + ], + 'Subnets': [ + { + 'Ref': 'MyVPCPrivateSubnet1Subnet641543F4', + }, + { + 'Ref': 'MyVPCPrivateSubnet2SubnetA420D3F0', + }, + ], + 'VpcId': { + 'Ref': 'MyVPCAFB07A31', + }, + }, + }); + + expect(project.connections).toBeDefined(); + }); + + test('without VPC configuration but security group identified', () => { + const stack = new cdk.Stack(); + + const bucket = new s3.Bucket(stack, 'MyBucket'); + const vpc = new ec2.Vpc(stack, 'MyVPC'); + const securityGroup = new ec2.SecurityGroup(stack, 'SecurityGroup1', { + securityGroupName: 'Bob', + vpc, + allowAllOutbound: true, + description: 'Example', + }); + + expect(() => + new codebuild.Project(stack, 'MyProject', { + source: codebuild.Source.s3({ + bucket, + path: 'path/to/source.zip', + }), + securityGroups: [securityGroup], + }), + ).toThrow(/Cannot configure 'securityGroup' or 'allowAllOutbound' without configuring a VPC/); + }); + + test('with VPC configuration but allowAllOutbound identified', () => { + const stack = new cdk.Stack(); + const bucket = new s3.Bucket(stack, 'MyBucket'); + const vpc = new ec2.Vpc(stack, 'MyVPC'); + const securityGroup = new ec2.SecurityGroup(stack, 'SecurityGroup1', { + securityGroupName: 'Bob', + vpc, + allowAllOutbound: true, + description: 'Example', + }); + + expect(() => + new codebuild.Project(stack, 'MyProject', { + source: codebuild.Source.s3({ + bucket, + path: 'path/to/source.zip', + }), + vpc, + allowAllOutbound: true, + securityGroups: [securityGroup], + }), + ).toThrow(/Configure 'allowAllOutbound' directly on the supplied SecurityGroup/); + }); + + test('without passing a VPC cannot access the connections property', () => { + const stack = new cdk.Stack(); + + const project = new codebuild.PipelineProject(stack, 'MyProject'); + + expect(() => project.connections).toThrow( + /Only VPC-associated Projects have security groups to manage. Supply the "vpc" parameter when creating the Project/); + }); + + test('no KMS Key defaults to default S3 managed key', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new codebuild.PipelineProject(stack, 'MyProject'); + + // THEN + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + EncryptionKey: 'alias/aws/s3', + }); + }); + + test('with a KMS Key adds decrypt permissions to the CodeBuild Role', () => { + const stack = new cdk.Stack(); + + const key = new kms.Key(stack, 'MyKey'); + + new codebuild.PipelineProject(stack, 'MyProject', { + encryptionKey: key, + grantReportGroupPermissions: false, + }); + + expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': [ + {}, // CloudWatch logs + { + 'Action': [ + 'kms:Decrypt', + 'kms:Encrypt', + 'kms:ReEncrypt*', + 'kms:GenerateDataKey*', + ], + 'Effect': 'Allow', + 'Resource': { + 'Fn::GetAtt': [ + 'MyKey6AB29FA6', + 'Arn', + ], + }, + }, + ], + }, + 'Roles': [ + { + 'Ref': 'MyProjectRole9BBE5233', + }, + ], + }); + }); +}); + +test('using timeout and path in S3 artifacts sets it correctly', () => { + const stack = new cdk.Stack(); + const bucket = new s3.Bucket(stack, 'Bucket'); + new codebuild.Project(stack, 'Project', { + buildSpec: codebuild.BuildSpec.fromObject({ + version: '0.2', + }), + artifacts: codebuild.Artifacts.s3({ + path: 'some/path', + name: 'some_name', + bucket, + }), + timeout: cdk.Duration.minutes(123), + }); + + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + 'Artifacts': { + 'Path': 'some/path', + 'Name': 'some_name', + 'Type': 'S3', + }, + 'TimeoutInMinutes': 123, + }); +}); + +describe('secondary sources', () => { + test('require providing an identifier when creating a Project', () => { + const stack = new cdk.Stack(); + + expect(() => { + new codebuild.Project(stack, 'MyProject', { + buildSpec: codebuild.BuildSpec.fromObject({ + version: '0.2', + }), + secondarySources: [ + codebuild.Source.s3({ + bucket: new s3.Bucket(stack, 'MyBucket'), + path: 'path', + }), + ], + }); + }).toThrow(/identifier/); + }); + + test('are not allowed for a Project with CodePipeline as Source', () => { + const stack = new cdk.Stack(); + const project = new codebuild.PipelineProject(stack, 'MyProject'); + + project.addSecondarySource(codebuild.Source.s3({ + bucket: new s3.Bucket(stack, 'MyBucket'), + path: 'some/path', + identifier: 'id', + })); + + expect(() => SynthUtils.synthesize(stack)).toThrow(/secondary sources/); + }); + + test('added with an identifer after the Project has been created are rendered in the template', () => { + const stack = new cdk.Stack(); + const bucket = new s3.Bucket(stack, 'MyBucket'); + const project = new codebuild.Project(stack, 'MyProject', { + source: codebuild.Source.s3({ + bucket, + path: 'some/path', + }), + }); + + project.addSecondarySource(codebuild.Source.s3({ + bucket, + path: 'another/path', + identifier: 'source1', + })); + + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + 'SecondarySources': [ + { + 'SourceIdentifier': 'source1', + 'Type': 'S3', + }, + ], + }); + }); +}); + +describe('secondary source versions', () => { + test('allow secondary source versions', () => { + const stack = new cdk.Stack(); + const bucket = new s3.Bucket(stack, 'MyBucket'); + const project = new codebuild.Project(stack, 'MyProject', { + source: codebuild.Source.s3({ + bucket, + path: 'some/path', + }), + }); + + project.addSecondarySource(codebuild.Source.s3({ + bucket, + path: 'another/path', + identifier: 'source1', + version: 'someversion', + })); + + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + 'SecondarySources': [ + { + 'SourceIdentifier': 'source1', + 'Type': 'S3', + }, + ], + 'SecondarySourceVersions': [ + { + 'SourceIdentifier': 'source1', + 'SourceVersion': 'someversion', + }, + ], + }); + }); + + test('allow not to specify secondary source versions', () => { + const stack = new cdk.Stack(); + const bucket = new s3.Bucket(stack, 'MyBucket'); + const project = new codebuild.Project(stack, 'MyProject', { + source: codebuild.Source.s3({ + bucket, + path: 'some/path', + }), + }); + + project.addSecondarySource(codebuild.Source.s3({ + bucket, + path: 'another/path', + identifier: 'source1', + })); + + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + 'SecondarySources': [ + { + 'SourceIdentifier': 'source1', + 'Type': 'S3', + }, + ], + }); + }); +}); + +describe('fileSystemLocations', () => { + test('create fileSystemLocation and validate attributes', () => { + const stack = new cdk.Stack(); + new codebuild.Project(stack, 'MyProject', { + buildSpec: codebuild.BuildSpec.fromObject({ + version: '0.2', + }), + fileSystemLocations: [codebuild.FileSystemLocation.efs({ + identifier: 'myidentifier2', + location: 'myclodation.mydnsroot.com:/loc', + mountPoint: '/media', + mountOptions: 'opts', + })], + }); + + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + 'FileSystemLocations': [ + { + 'Identifier': 'myidentifier2', + 'MountPoint': '/media', + 'MountOptions': 'opts', + 'Location': 'myclodation.mydnsroot.com:/loc', + 'Type': 'EFS', + }, + ], + }); + }); + + test('Multiple fileSystemLocation created', () => { + const stack = new cdk.Stack(); + const project = new codebuild.Project(stack, 'MyProject', { + buildSpec: codebuild.BuildSpec.fromObject({ + version: '0.2', + }), + }); + project.addFileSystemLocation(codebuild.FileSystemLocation.efs({ + identifier: 'myidentifier3', + location: 'myclodation.mydnsroot.com:/loc', + mountPoint: '/media', + mountOptions: 'opts', + })); + + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + 'FileSystemLocations': [ + { + 'Identifier': 'myidentifier3', + 'MountPoint': '/media', + 'MountOptions': 'opts', + 'Location': 'myclodation.mydnsroot.com:/loc', + 'Type': 'EFS', + }, + ], + }); + }); +}); + +describe('secondary artifacts', () => { + test('require providing an identifier when creating a Project', () => { + const stack = new cdk.Stack(); + + expect(() => { + new codebuild.Project(stack, 'MyProject', { + buildSpec: codebuild.BuildSpec.fromObject({ + version: '0.2', + }), + secondaryArtifacts: [ + codebuild.Artifacts.s3({ + bucket: new s3.Bucket(stack, 'MyBucket'), + path: 'some/path', + name: 'name', + }), + ], + }); + }).toThrow(/identifier/); + }); + + test('are not allowed for a Project with CodePipeline as Source', () => { + const stack = new cdk.Stack(); + const project = new codebuild.PipelineProject(stack, 'MyProject'); + + project.addSecondaryArtifact(codebuild.Artifacts.s3({ + bucket: new s3.Bucket(stack, 'MyBucket'), + path: 'some/path', + name: 'name', + identifier: 'id', + })); + + expect(() => SynthUtils.synthesize(stack)).toThrow(/secondary artifacts/); + }); + + test('added with an identifier after the Project has been created are rendered in the template', () => { + const stack = new cdk.Stack(); + const bucket = new s3.Bucket(stack, 'MyBucket'); + const project = new codebuild.Project(stack, 'MyProject', { + source: codebuild.Source.s3({ + bucket, + path: 'some/path', + }), + }); + + project.addSecondaryArtifact(codebuild.Artifacts.s3({ + bucket, + path: 'another/path', + name: 'name', + identifier: 'artifact1', + })); + + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + 'SecondaryArtifacts': [ + { + 'ArtifactIdentifier': 'artifact1', + 'Type': 'S3', + }, + ], + }); + }); + + test('disabledEncryption is set', () => { + const stack = new cdk.Stack(); + const bucket = new s3.Bucket(stack, 'MyBucket'); + const project = new codebuild.Project(stack, 'MyProject', { + source: codebuild.Source.s3({ + bucket, + path: 'some/path', + }), + }); + + project.addSecondaryArtifact(codebuild.Artifacts.s3({ + bucket, + path: 'another/path', + name: 'name', + identifier: 'artifact1', + encryption: false, + })); + + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + 'SecondaryArtifacts': [ + { + 'ArtifactIdentifier': 'artifact1', + 'EncryptionDisabled': true, + }, + ], + }); + }); +}); + +describe('artifacts', () => { + describe('CodePipeline', () => { + test('both source and artifacs are set to CodePipeline', () => { + const stack = new cdk.Stack(); + + new codebuild.PipelineProject(stack, 'MyProject'); + + expect(stack).toHaveResource('AWS::CodeBuild::Project', { + 'Source': { + 'Type': 'CODEPIPELINE', + }, + 'Artifacts': { + 'Type': 'CODEPIPELINE', + }, + 'ServiceRole': { + 'Fn::GetAtt': [ + 'MyProjectRole9BBE5233', + 'Arn', + ], + }, + 'Environment': { + 'Type': 'LINUX_CONTAINER', + 'PrivilegedMode': false, + 'Image': 'aws/codebuild/standard:1.0', + 'ImagePullCredentialsType': 'CODEBUILD', + 'ComputeType': 'BUILD_GENERAL1_SMALL', + }, + }); + }); + }); + + describe('S3', () => { + test('name is not set so use buildspec', () => { + const stack = new cdk.Stack(); + const bucket = new s3.Bucket(stack, 'MyBucket'); + new codebuild.Project(stack, 'MyProject', { + source: codebuild.Source.s3({ + bucket, + path: 'some/path', + }), + artifacts: codebuild.Artifacts.s3({ + bucket, + path: 'another/path', + identifier: 'artifact1', + }), + }); + + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + 'Artifacts': { + 'Name': ABSENT, + 'ArtifactIdentifier': 'artifact1', + 'OverrideArtifactName': true, + }, + }); + }); + + test('name is set so use it', () => { + const stack = new cdk.Stack(); + const bucket = new s3.Bucket(stack, 'MyBucket'); + new codebuild.Project(stack, 'MyProject', { + source: codebuild.Source.s3({ + bucket, + path: 'some/path', + }), + artifacts: codebuild.Artifacts.s3({ + bucket, + path: 'another/path', + name: 'specificname', + identifier: 'artifact1', + }), + }); + + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + 'Artifacts': { + 'ArtifactIdentifier': 'artifact1', + 'Name': 'specificname', + 'OverrideArtifactName': ABSENT, + }, + }); + }); + }); +}); + +test('events', () => { + const stack = new cdk.Stack(); + const project = new codebuild.Project(stack, 'MyProject', { + source: codebuild.Source.s3({ + bucket: new s3.Bucket(stack, 'MyBucket'), + path: 'path', + }), + }); + + project.onBuildFailed('OnBuildFailed', { target: { bind: () => ({ arn: 'ARN', id: 'ID' }) } }); + project.onBuildSucceeded('OnBuildSucceeded', { target: { bind: () => ({ arn: 'ARN', id: 'ID' }) } }); + project.onPhaseChange('OnPhaseChange', { target: { bind: () => ({ arn: 'ARN', id: 'ID' }) } }); + project.onStateChange('OnStateChange', { target: { bind: () => ({ arn: 'ARN', id: 'ID' }) } }); + project.onBuildStarted('OnBuildStarted', { target: { bind: () => ({ arn: 'ARN', id: 'ID' }) } }); + + expect(stack).toHaveResource('AWS::Events::Rule', { + 'EventPattern': { + 'source': [ + 'aws.codebuild', + ], + 'detail-type': [ + 'CodeBuild Build State Change', + ], + 'detail': { + 'project-name': [ + { + 'Ref': 'MyProject39F7B0AE', + }, + ], + 'build-status': [ + 'FAILED', + ], + }, + }, + 'State': 'ENABLED', + }); + + expect(stack).toHaveResource('AWS::Events::Rule', { + 'EventPattern': { + 'source': [ + 'aws.codebuild', + ], + 'detail-type': [ + 'CodeBuild Build State Change', + ], + 'detail': { + 'project-name': [ + { + 'Ref': 'MyProject39F7B0AE', + }, + ], + 'build-status': [ + 'SUCCEEDED', + ], + }, + }, + 'State': 'ENABLED', + }); + + expect(stack).toHaveResource('AWS::Events::Rule', { + 'EventPattern': { + 'source': [ + 'aws.codebuild', + ], + 'detail-type': [ + 'CodeBuild Build Phase Change', + ], + 'detail': { + 'project-name': [ + { + 'Ref': 'MyProject39F7B0AE', + }, + ], + }, + }, + 'State': 'ENABLED', + }); + + expect(stack).toHaveResource('AWS::Events::Rule', { + 'EventPattern': { + 'source': [ + 'aws.codebuild', + ], + 'detail-type': [ + 'CodeBuild Build State Change', + ], + 'detail': { + 'project-name': [ + { + 'Ref': 'MyProject39F7B0AE', + }, + ], + }, + }, + 'State': 'ENABLED', + }); + + expect(stack).toHaveResource('AWS::Events::Rule', { + 'EventPattern': { + 'source': [ + 'aws.codebuild', + ], + 'detail-type': [ + 'CodeBuild Build State Change', + ], + 'detail': { + 'project-name': [ + { + 'Ref': 'MyProject39F7B0AE', + }, + ], + 'build-status': [ + 'IN_PROGRESS', + ], + }, + }, + 'State': 'ENABLED', + }); +}); + +test('environment variables can be overridden at the project level', () => { + const stack = new cdk.Stack(); + + new codebuild.PipelineProject(stack, 'Project', { + environment: { + environmentVariables: { + FOO: { value: '1234' }, + BAR: { value: `111${cdk.Token.asString({ twotwotwo: '222' })}`, type: codebuild.BuildEnvironmentVariableType.PARAMETER_STORE }, + }, + }, + environmentVariables: { + GOO: { value: 'ABC' }, + FOO: { value: 'OVERRIDE!' }, + }, + }); + + expect(stack).toHaveResource('AWS::CodeBuild::Project', { + 'Source': { + 'Type': 'CODEPIPELINE', + }, + 'Artifacts': { + 'Type': 'CODEPIPELINE', + }, + 'ServiceRole': { + 'Fn::GetAtt': [ + 'ProjectRole4CCB274E', + 'Arn', + ], + }, + 'Environment': { + 'Type': 'LINUX_CONTAINER', + 'EnvironmentVariables': [ + { + 'Type': 'PLAINTEXT', + 'Value': 'OVERRIDE!', + 'Name': 'FOO', + }, + { + 'Type': 'PARAMETER_STORE', + 'Value': { + 'Fn::Join': [ + '', + [ + '111', + { twotwotwo: '222' }, + ], + ], + }, + 'Name': 'BAR', + }, + { + 'Type': 'PLAINTEXT', + 'Value': 'ABC', + 'Name': 'GOO', + }, + ], + 'PrivilegedMode': false, + 'Image': 'aws/codebuild/standard:1.0', + 'ImagePullCredentialsType': 'CODEBUILD', + 'ComputeType': 'BUILD_GENERAL1_SMALL', + }, + }); +}); + +test('.metricXxx() methods can be used to obtain Metrics for CodeBuild projects', () => { + const stack = new cdk.Stack(); + + const project = new codebuild.Project(stack, 'MyBuildProject', { + source: codebuild.Source.s3({ + bucket: new s3.Bucket(stack, 'MyBucket'), + path: 'path', + }), + }); + + const metricBuilds = project.metricBuilds(); + expect(metricBuilds.dimensions!.ProjectName).toEqual(project.projectName); + expect(metricBuilds.namespace).toEqual('AWS/CodeBuild'); + expect(metricBuilds.statistic).toEqual('Sum'); + expect(metricBuilds.metricName).toEqual('Builds'); + + const metricDuration = project.metricDuration({ label: 'hello' }); + + expect(metricDuration.metricName).toEqual('Duration'); + expect(metricDuration.label).toEqual('hello'); + + expect(project.metricFailedBuilds().metricName).toEqual('FailedBuilds'); + expect(project.metricSucceededBuilds().metricName).toEqual('SucceededBuilds'); +}); + +test('using ComputeType.Small with a Windows image fails validation', () => { + const stack = new cdk.Stack(); + const invalidEnvironment: codebuild.BuildEnvironment = { + buildImage: codebuild.WindowsBuildImage.WINDOWS_BASE_2_0, + computeType: codebuild.ComputeType.SMALL, + }; + + expect(() => { + new codebuild.Project(stack, 'MyProject', { + source: codebuild.Source.s3({ + bucket: new s3.Bucket(stack, 'MyBucket'), + path: 'path', + }), + environment: invalidEnvironment, + }); + }).toThrow(/Windows images do not support the Small ComputeType/); +}); + +test('fromCodebuildImage', () => { + const stack = new cdk.Stack(); + new codebuild.PipelineProject(stack, 'Project', { + environment: { + buildImage: codebuild.LinuxBuildImage.fromCodeBuildImageId('aws/codebuild/standard:4.0'), + }, + }); + + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + 'Environment': { + 'Image': 'aws/codebuild/standard:4.0', + }, + }); +}); + +describe('Windows2019 image', () => { + describe('WIN_SERVER_CORE_2016_BASE', () => { + test('has type WINDOWS_SERVER_2019_CONTAINER and default ComputeType MEDIUM', () => { + const stack = new cdk.Stack(); + new codebuild.PipelineProject(stack, 'Project', { + environment: { + buildImage: codebuild.WindowsBuildImage.WIN_SERVER_CORE_2019_BASE, + }, + }); + + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + 'Environment': { + 'Type': 'WINDOWS_SERVER_2019_CONTAINER', + 'ComputeType': 'BUILD_GENERAL1_MEDIUM', + }, + }); + }); + }); +}); + +describe('ARM image', () => { + describe('AMAZON_LINUX_2_ARM', () => { + test('has type ARM_CONTAINER and default ComputeType LARGE', () => { + const stack = new cdk.Stack(); + new codebuild.PipelineProject(stack, 'Project', { + environment: { + buildImage: codebuild.LinuxBuildImage.AMAZON_LINUX_2_ARM, + }, + }); + + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + 'Environment': { + 'Type': 'ARM_CONTAINER', + 'ComputeType': 'BUILD_GENERAL1_LARGE', + }, + }); + }); + + test('can be used with ComputeType SMALL', () => { + const stack = new cdk.Stack(); + new codebuild.PipelineProject(stack, 'Project', { + environment: { + computeType: codebuild.ComputeType.SMALL, + buildImage: codebuild.LinuxBuildImage.AMAZON_LINUX_2_ARM, + }, + }); + + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + 'Environment': { + 'Type': 'ARM_CONTAINER', + 'ComputeType': 'BUILD_GENERAL1_SMALL', + }, + }); + }); + + test('cannot be used in conjunction with ComputeType MEDIUM', () => { + const stack = new cdk.Stack(); + + expect(() => { + new codebuild.PipelineProject(stack, 'Project', { + environment: { + buildImage: codebuild.LinuxBuildImage.AMAZON_LINUX_2_ARM, + computeType: codebuild.ComputeType.MEDIUM, + }, + }); + }).toThrow(/ARM images only support ComputeTypes 'BUILD_GENERAL1_SMALL' and 'BUILD_GENERAL1_LARGE' - 'BUILD_GENERAL1_MEDIUM' was given/); + }); + + test('can be used with ComputeType LARGE', () => { + const stack = new cdk.Stack(); + new codebuild.PipelineProject(stack, 'Project', { + environment: { + computeType: codebuild.ComputeType.LARGE, + buildImage: codebuild.LinuxBuildImage.AMAZON_LINUX_2_ARM, + }, + }); + + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + 'Environment': { + 'Type': 'ARM_CONTAINER', + 'ComputeType': 'BUILD_GENERAL1_LARGE', + }, + }); + }); + + test('cannot be used in conjunction with ComputeType X2_LARGE', () => { + const stack = new cdk.Stack(); + + expect(() => { + new codebuild.PipelineProject(stack, 'Project', { + environment: { + buildImage: codebuild.LinuxBuildImage.AMAZON_LINUX_2_ARM, + computeType: codebuild.ComputeType.X2_LARGE, + }, + }); + }).toThrow(/ARM images only support ComputeTypes 'BUILD_GENERAL1_SMALL' and 'BUILD_GENERAL1_LARGE' - 'BUILD_GENERAL1_2XLARGE' was given/); + }); + }); +}); + +test('badge support test', () => { + const stack = new cdk.Stack(); + + interface BadgeValidationTestCase { + source: codebuild.Source, + allowsBadge: boolean + } + + const repo = new codecommit.Repository(stack, 'MyRepo', { + repositoryName: 'hello-cdk', + }); + const bucket = new s3.Bucket(stack, 'MyBucket'); + + const cases: BadgeValidationTestCase[] = [ + { source: new NoSource(), allowsBadge: false }, + { source: new CodePipelineSource(), allowsBadge: false }, + { source: codebuild.Source.codeCommit({ repository: repo }), allowsBadge: true }, + { source: codebuild.Source.s3({ bucket, path: 'path/to/source.zip' }), allowsBadge: false }, + { source: codebuild.Source.gitHub({ owner: 'awslabs', repo: 'aws-cdk' }), allowsBadge: true }, + { source: codebuild.Source.gitHubEnterprise({ httpsCloneUrl: 'url' }), allowsBadge: true }, + { source: codebuild.Source.bitBucket({ owner: 'awslabs', repo: 'aws-cdk' }), allowsBadge: true }, + ]; + + cases.forEach(testCase => { + const source = testCase.source; + const validationBlock = () => { new codebuild.Project(stack, `MyProject-${source.type}`, { source, badge: true }); }; + if (testCase.allowsBadge) { + expect(validationBlock).not.toThrow(); + } else { + expect(validationBlock).toThrow(/Badge is not supported for source type /); + } + }); +}); + +describe('webhook Filters', () => { + test('a Group cannot be created with an empty set of event actions', () => { + expect(() => { + codebuild.FilterGroup.inEventOf(); + }).toThrow(/A filter group must contain at least one event action/); + }); + + test('cannot have base ref conditions if the Group contains the PUSH action', () => { + const filterGroup = codebuild.FilterGroup.inEventOf(codebuild.EventAction.PULL_REQUEST_CREATED, + codebuild.EventAction.PUSH); + + expect(() => { + filterGroup.andBaseRefIs('.*'); + }).toThrow(/A base reference condition cannot be added if a Group contains a PUSH event action/); + }); + + test('cannot be used when webhook is false', () => { + const stack = new cdk.Stack(); + + expect(() => { + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.bitBucket({ + owner: 'owner', + repo: 'repo', + webhook: false, + webhookFilters: [ + codebuild.FilterGroup.inEventOf(codebuild.EventAction.PUSH), + ], + }), + }); + }).toThrow(/`webhookFilters` cannot be used when `webhook` is `false`/); + }); + + test('can have FILE_PATH filters if the Group contains PUSH and PR_CREATED events', () => { + codebuild.FilterGroup.inEventOf( + codebuild.EventAction.PULL_REQUEST_CREATED, + codebuild.EventAction.PUSH) + .andFilePathIsNot('.*\\.java'); + }); + + test('BitBucket sources do not support the PULL_REQUEST_REOPENED event action', () => { + const stack = new cdk.Stack(); + + expect(() => { + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.bitBucket({ + owner: 'owner', + repo: 'repo', + webhookFilters: [ + codebuild.FilterGroup.inEventOf(codebuild.EventAction.PULL_REQUEST_REOPENED), + ], + }), + }); + }).toThrow(/BitBucket sources do not support the PULL_REQUEST_REOPENED webhook event action/); + }); + + test('BitBucket sources support file path conditions', () => { + const stack = new cdk.Stack(); + const filterGroup = codebuild.FilterGroup.inEventOf(codebuild.EventAction.PUSH).andFilePathIs('.*'); + + expect(() => { + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.bitBucket({ + owner: 'owner', + repo: 'repo', + webhookFilters: [filterGroup], + }), + }); + }).not.toThrow(); + }); + + test('GitHub Enterprise Server sources do not support FILE_PATH filters on PR events', () => { + const stack = new cdk.Stack(); + const pullFilterGroup = codebuild.FilterGroup.inEventOf( + codebuild.EventAction.PULL_REQUEST_CREATED, + codebuild.EventAction.PULL_REQUEST_MERGED, + codebuild.EventAction.PULL_REQUEST_REOPENED, + codebuild.EventAction.PULL_REQUEST_UPDATED, + ); + + expect(() => { + new codebuild.Project(stack, 'MyFilePathProject', { + source: codebuild.Source.gitHubEnterprise({ + httpsCloneUrl: 'https://github.testcompany.com/testowner/testrepo', + webhookFilters: [ + pullFilterGroup.andFilePathIs('ReadMe.md'), + ], + }), + }); + }).toThrow(/FILE_PATH filters cannot be used with GitHub Enterprise Server pull request events/); + }); + + describe('COMMIT_MESSAGE Filter', () => { + test('GitHub Enterprise Server sources do not support COMMIT_MESSAGE filters on PR events', () => { + const stack = new cdk.Stack(); + const pullFilterGroup = codebuild.FilterGroup.inEventOf( + codebuild.EventAction.PULL_REQUEST_CREATED, + codebuild.EventAction.PULL_REQUEST_MERGED, + codebuild.EventAction.PULL_REQUEST_REOPENED, + codebuild.EventAction.PULL_REQUEST_UPDATED, + ); + + expect(() => { + new codebuild.Project(stack, 'MyProject', { + source: codebuild.Source.gitHubEnterprise({ + httpsCloneUrl: 'https://github.testcompany.com/testowner/testrepo', + webhookFilters: [ + pullFilterGroup.andCommitMessageIs('the commit message'), + ], + }), + }); + }).toThrow(/COMMIT_MESSAGE filters cannot be used with GitHub Enterprise Server pull request events/); + }); + + test('GitHub Enterprise Server sources support COMMIT_MESSAGE filters on PUSH events', () => { + const stack = new cdk.Stack(); + const pushFilterGroup = codebuild.FilterGroup.inEventOf(codebuild.EventAction.PUSH); + + expect(() => { + new codebuild.Project(stack, 'MyProject', { + source: codebuild.Source.gitHubEnterprise({ + httpsCloneUrl: 'https://github.testcompany.com/testowner/testrepo', + webhookFilters: [ + pushFilterGroup.andCommitMessageIs('the commit message'), + ], + }), + }); + }).not.toThrow(); + }); + + test('BitBucket and GitHub sources support a COMMIT_MESSAGE filter', () => { + const stack = new cdk.Stack(); + const filterGroup = codebuild + .FilterGroup + .inEventOf(codebuild.EventAction.PUSH, codebuild.EventAction.PULL_REQUEST_CREATED) + .andCommitMessageIs('the commit message'); + + expect(() => { + new codebuild.Project(stack, 'BitBucket Project', { + source: codebuild.Source.bitBucket({ + owner: 'owner', + repo: 'repo', + webhookFilters: [filterGroup], + }), + }); + new codebuild.Project(stack, 'GitHub Project', { + source: codebuild.Source.gitHub({ + owner: 'owner', + repo: 'repo', + webhookFilters: [filterGroup], + }), + }); + }).not.toThrow(); + }); + }); +}); + +test('enableBatchBuilds()', () => { + const stack = new cdk.Stack(); + + const project = new codebuild.Project(stack, 'Project', { + source: codebuild.Source.gitHub({ + owner: 'testowner', + repo: 'testrepo', + }), + }); + + const returnVal = project.enableBatchBuilds(); + if (!returnVal?.role) { + throw new Error('Expecting return value with role'); + } + + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + BuildBatchConfig: { + ServiceRole: { + 'Fn::GetAtt': [ + 'ProjectBatchServiceRoleF97A1CFB', + 'Arn', + ], + }, + }, + }); + + expect(stack).toHaveResourceLike('AWS::IAM::Role', { + AssumeRolePolicyDocument: { + Statement: [ + { + Action: 'sts:AssumeRole', + Effect: 'Allow', + Principal: { + Service: 'codebuild.amazonaws.com', + }, + }, + ], + Version: '2012-10-17', + }, + }); + + expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [ + { + Action: [ + 'codebuild:StartBuild', + 'codebuild:StopBuild', + 'codebuild:RetryBuild', + ], + Effect: 'Allow', + Resource: { + 'Fn::GetAtt': [ + 'ProjectC78D97AD', + 'Arn', + ], + }, + }, + ], + Version: '2012-10-17', + }, + }); +}); diff --git a/packages/@aws-cdk/aws-codebuild/test/linux-gpu-build-image.test.ts b/packages/@aws-cdk/aws-codebuild/test/linux-gpu-build-image.test.ts new file mode 100644 index 0000000000000..7e32ab033c68c --- /dev/null +++ b/packages/@aws-cdk/aws-codebuild/test/linux-gpu-build-image.test.ts @@ -0,0 +1,61 @@ +import { arrayWith, objectLike } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; +import * as cdk from '@aws-cdk/core'; +import * as codebuild from '../lib'; + +describe('Linux GPU build image', () => { + describe('AWS Deep Learning Container images', () => { + test('allows passing the account that the repository of the image is hosted in', () => { + const stack = new cdk.Stack(); + + new codebuild.Project(stack, 'Project', { + buildSpec: codebuild.BuildSpec.fromObject({ + version: '0.2', + phases: { + build: { commands: ['ls'] }, + }, + }), + environment: { + buildImage: codebuild.LinuxGpuBuildImage.awsDeepLearningContainersImage( + 'my-repo', 'my-tag', '123456789012'), + }, + }); + + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + Environment: { + ComputeType: 'BUILD_GENERAL1_LARGE', + Image: { + 'Fn::Join': ['', [ + '123456789012.dkr.ecr.', + { Ref: 'AWS::Region' }, + '.', + { Ref: 'AWS::URLSuffix' }, + '/my-repo:my-tag', + ]], + }, + }, + }); + + expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + PolicyDocument: { + Statement: arrayWith(objectLike({ + Action: [ + 'ecr:BatchCheckLayerAvailability', + 'ecr:GetDownloadUrlForLayer', + 'ecr:BatchGetImage', + ], + Resource: { + 'Fn::Join': ['', [ + 'arn:', + { Ref: 'AWS::Partition' }, + ':ecr:', + { Ref: 'AWS::Region' }, + ':123456789012:repository/my-repo', + ]], + }, + })), + }, + }); + }); + }); +}); diff --git a/packages/@aws-cdk/aws-codebuild/test/notification-rule.test.ts b/packages/@aws-cdk/aws-codebuild/test/notification-rule.test.ts new file mode 100644 index 0000000000000..45d6a65d76ce4 --- /dev/null +++ b/packages/@aws-cdk/aws-codebuild/test/notification-rule.test.ts @@ -0,0 +1,70 @@ +import '@aws-cdk/assert-internal/jest'; +import * as sns from '@aws-cdk/aws-sns'; +import * as cdk from '@aws-cdk/core'; +import * as codebuild from '../lib'; + +test('notifications rule', () => { + const stack = new cdk.Stack(); + const project = new codebuild.Project(stack, 'MyCodebuildProject', { + buildSpec: codebuild.BuildSpec.fromObject({ + version: '0.2', + phases: { + build: { + commands: [ + 'echo "Hello, CodeBuild!"', + ], + }, + }, + }), + }); + + const target = new sns.Topic(stack, 'MyTopic'); + + project.notifyOnBuildSucceeded('NotifyOnBuildSucceeded', target); + + project.notifyOnBuildFailed('NotifyOnBuildFailed', target); + + expect(stack).toHaveResource('AWS::CodeStarNotifications::NotificationRule', { + Name: 'MyCodebuildProjectNotifyOnBuildSucceeded77719592', + DetailType: 'FULL', + EventTypeIds: [ + 'codebuild-project-build-state-succeeded', + ], + Resource: { + 'Fn::GetAtt': [ + 'MyCodebuildProjectB0479580', + 'Arn', + ], + }, + Targets: [ + { + TargetAddress: { + Ref: 'MyTopic86869434', + }, + TargetType: 'SNS', + }, + ], + }); + + expect(stack).toHaveResource('AWS::CodeStarNotifications::NotificationRule', { + Name: 'MyCodebuildProjectNotifyOnBuildFailedF680E310', + DetailType: 'FULL', + EventTypeIds: [ + 'codebuild-project-build-state-failed', + ], + Resource: { + 'Fn::GetAtt': [ + 'MyCodebuildProjectB0479580', + 'Arn', + ], + }, + Targets: [ + { + TargetAddress: { + Ref: 'MyTopic86869434', + }, + TargetType: 'SNS', + }, + ], + }); +}); diff --git a/packages/@aws-cdk/aws-codebuild/test/project.test.ts b/packages/@aws-cdk/aws-codebuild/test/project.test.ts new file mode 100644 index 0000000000000..08fbe3e8f8768 --- /dev/null +++ b/packages/@aws-cdk/aws-codebuild/test/project.test.ts @@ -0,0 +1,1780 @@ +import { objectLike, ResourcePart, arrayWith } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as iam from '@aws-cdk/aws-iam'; +import * as logs from '@aws-cdk/aws-logs'; +import * as s3 from '@aws-cdk/aws-s3'; +import * as secretsmanager from '@aws-cdk/aws-secretsmanager'; +import * as cdk from '@aws-cdk/core'; +import * as codebuild from '../lib'; + +/* eslint-disable quote-props */ + +test('can use filename as buildspec', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.s3({ + bucket: new s3.Bucket(stack, 'Bucket'), + path: 'path', + }), + buildSpec: codebuild.BuildSpec.fromSourceFilename('hello.yml'), + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + Source: { + BuildSpec: 'hello.yml', + }, + }); +}); + +test('can use buildspec literal', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new codebuild.Project(stack, 'Project', { + buildSpec: codebuild.BuildSpec.fromObject({ phases: ['say hi'] }), + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + Source: { + BuildSpec: '{\n "phases": [\n "say hi"\n ]\n}', + }, + }); +}); + +test('can use yamlbuildspec literal', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new codebuild.Project(stack, 'Project', { + buildSpec: codebuild.BuildSpec.fromObjectToYaml({ + text: 'text', + decimal: 10, + list: ['say hi'], + obj: { + text: 'text', + decimal: 10, + list: ['say hi'], + }, + }), + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + Source: { + BuildSpec: 'text: text\ndecimal: 10\nlist:\n - say hi\nobj:\n text: text\n decimal: 10\n list:\n - say hi\n', + }, + }); +}); + +test('must supply buildspec when using nosource', () => { + // GIVEN + const stack = new cdk.Stack(); + + expect(() => { + new codebuild.Project(stack, 'Project', { + }); + }).toThrow(/you need to provide a concrete buildSpec/); +}); + +test('must supply literal buildspec when using nosource', () => { + // GIVEN + const stack = new cdk.Stack(); + + expect(() => { + new codebuild.Project(stack, 'Project', { + buildSpec: codebuild.BuildSpec.fromSourceFilename('bla.yml'), + }); + }).toThrow(/you need to provide a concrete buildSpec/); +}); + +describe('GitHub source', () => { + test('has reportBuildStatus on by default', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.gitHub({ + owner: 'testowner', + repo: 'testrepo', + cloneDepth: 3, + }), + }); + + // THEN + expect(stack).toHaveResource('AWS::CodeBuild::Project', { + Source: { + Type: 'GITHUB', + Location: 'https://github.com/testowner/testrepo.git', + ReportBuildStatus: true, + GitCloneDepth: 3, + }, + }); + }); + + test('can set a branch as the SourceVersion', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.gitHub({ + owner: 'testowner', + repo: 'testrepo', + branchOrRef: 'testbranch', + }), + }); + + // THEN + expect(stack).toHaveResource('AWS::CodeBuild::Project', { + SourceVersion: 'testbranch', + }); + }); + + test('can explicitly set reportBuildStatus to false', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.gitHub({ + owner: 'testowner', + repo: 'testrepo', + reportBuildStatus: false, + }), + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + Source: { + ReportBuildStatus: false, + }, + }); + }); + + test('can explicitly set webhook to true', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.gitHub({ + owner: 'testowner', + repo: 'testrepo', + webhook: true, + }), + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + Triggers: { + Webhook: true, + }, + }); + }); + + test('can be added to a CodePipeline', () => { + const stack = new cdk.Stack(); + const project = new codebuild.Project(stack, 'Project', { + source: codebuild.Source.gitHub({ + owner: 'testowner', + repo: 'testrepo', + }), + }); + + expect(() => { + project.bindToCodePipeline(project, { + artifactBucket: new s3.Bucket(stack, 'Bucket'), + }); + }).not.toThrow(); // no exception + }); + + test('can provide credentials to use with the source', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new codebuild.GitHubSourceCredentials(stack, 'GitHubSourceCredentials', { + accessToken: cdk.SecretValue.plainText('my-access-token'), + }); + + // THEN + expect(stack).toHaveResource('AWS::CodeBuild::SourceCredential', { + 'ServerType': 'GITHUB', + 'AuthType': 'PERSONAL_ACCESS_TOKEN', + 'Token': 'my-access-token', + }); + }); +}); + +describe('GitHub Enterprise source', () => { + test('can use branchOrRef to set the source version', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.gitHubEnterprise({ + httpsCloneUrl: 'https://mygithub-enterprise.com/myuser/myrepo', + branchOrRef: 'testbranch', + }), + }); + + // THEN + expect(stack).toHaveResource('AWS::CodeBuild::Project', { + SourceVersion: 'testbranch', + }); + }); + + test('can provide credentials to use with the source', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new codebuild.GitHubEnterpriseSourceCredentials(stack, 'GitHubEnterpriseSourceCredentials', { + accessToken: cdk.SecretValue.plainText('my-access-token'), + }); + + // THEN + expect(stack).toHaveResource('AWS::CodeBuild::SourceCredential', { + 'ServerType': 'GITHUB_ENTERPRISE', + 'AuthType': 'PERSONAL_ACCESS_TOKEN', + 'Token': 'my-access-token', + }); + }); +}); + +describe('BitBucket source', () => { + test('can use branchOrRef to set the source version', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.bitBucket({ + owner: 'testowner', + repo: 'testrepo', + branchOrRef: 'testbranch', + }), + }); + + // THEN + expect(stack).toHaveResource('AWS::CodeBuild::Project', { + SourceVersion: 'testbranch', + }); + }); + + test('can provide credentials to use with the source', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new codebuild.BitBucketSourceCredentials(stack, 'BitBucketSourceCredentials', { + username: cdk.SecretValue.plainText('my-username'), + password: cdk.SecretValue.plainText('password'), + }); + + // THEN + expect(stack).toHaveResource('AWS::CodeBuild::SourceCredential', { + 'ServerType': 'BITBUCKET', + 'AuthType': 'BASIC_AUTH', + 'Username': 'my-username', + 'Token': 'password', + }); + }); +}); + +test('project with s3 cache bucket', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.s3({ + bucket: new s3.Bucket(stack, 'SourceBucket'), + path: 'path', + }), + cache: codebuild.Cache.bucket(new s3.Bucket(stack, 'Bucket'), { + prefix: 'cache-prefix', + }), + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + Cache: { + Type: 'S3', + Location: { + 'Fn::Join': [ + '/', + [ + { + 'Ref': 'Bucket83908E77', + }, + 'cache-prefix', + ], + ], + }, + }, + }); +}); + +test('s3 codebuild project with sourceVersion', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.s3({ + bucket: new s3.Bucket(stack, 'Bucket'), + path: 'path', + version: 's3version', + }), + cache: codebuild.Cache.local(codebuild.LocalCacheMode.CUSTOM, codebuild.LocalCacheMode.DOCKER_LAYER, + codebuild.LocalCacheMode.SOURCE), + }); + + // THEN + expect(stack).toHaveResource('AWS::CodeBuild::Project', { + SourceVersion: 's3version', + }); +}); + +test('project with local cache modes', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.s3({ + bucket: new s3.Bucket(stack, 'Bucket'), + path: 'path', + }), + cache: codebuild.Cache.local(codebuild.LocalCacheMode.CUSTOM, codebuild.LocalCacheMode.DOCKER_LAYER, + codebuild.LocalCacheMode.SOURCE), + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + Cache: { + Type: 'LOCAL', + Modes: [ + 'LOCAL_CUSTOM_CACHE', + 'LOCAL_DOCKER_LAYER_CACHE', + 'LOCAL_SOURCE_CACHE', + ], + }, + }); +}); + +test('project by default has no cache modes', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.s3({ + bucket: new s3.Bucket(stack, 'Bucket'), + path: 'path', + }), + }); + + // THEN + expect(stack).not.toHaveResourceLike('AWS::CodeBuild::Project', { + Cache: {}, + }); +}); + +test('if a role is shared between projects in a VPC, the VPC Policy is only attached once', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'Vpc'); + const role = new iam.Role(stack, 'Role', { + assumedBy: new iam.ServicePrincipal('codebuild.amazonaws.com'), + }); + const source = codebuild.Source.gitHubEnterprise({ + httpsCloneUrl: 'https://mygithub-enterprise.com/myuser/myrepo', + }); + + // WHEN + new codebuild.Project(stack, 'Project1', { source, role, vpc, projectName: 'P1' }); + new codebuild.Project(stack, 'Project2', { source, role, vpc, projectName: 'P2' }); + + // THEN + // - 1 is for `ec2:CreateNetworkInterfacePermission`, deduplicated as they're part of a single policy + // - 1 is for `ec2:CreateNetworkInterface`, this is the separate Policy we're deduplicating + // We would have found 3 if the deduplication didn't work. + expect(stack).toCountResources('AWS::IAM::Policy', 2); + + // THEN - both Projects have a DependsOn on the same policy + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + Properties: { Name: 'P1' }, + DependsOn: ['Project1PolicyDocumentF9761562'], + }, ResourcePart.CompleteDefinition); + + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + Properties: { Name: 'P1' }, + DependsOn: ['Project1PolicyDocumentF9761562'], + }, ResourcePart.CompleteDefinition); +}); + +test('can use an imported Role for a Project within a VPC', () => { + const stack = new cdk.Stack(); + + const importedRole = iam.Role.fromRoleArn(stack, 'Role', 'arn:aws:iam::1234567890:role/service-role/codebuild-bruiser-service-role'); + const vpc = new ec2.Vpc(stack, 'Vpc'); + + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.gitHubEnterprise({ + httpsCloneUrl: 'https://mygithub-enterprise.com/myuser/myrepo', + }), + role: importedRole, + vpc, + }); + + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + // no need to do any assertions + }); +}); + +test('can use an imported Role with mutable = false for a Project within a VPC', () => { + const stack = new cdk.Stack(); + + const importedRole = iam.Role.fromRoleArn(stack, 'Role', + 'arn:aws:iam::1234567890:role/service-role/codebuild-bruiser-service-role', { + mutable: false, + }); + const vpc = new ec2.Vpc(stack, 'Vpc'); + + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.gitHubEnterprise({ + httpsCloneUrl: 'https://mygithub-enterprise.com/myuser/myrepo', + }), + role: importedRole, + vpc, + }); + + expect(stack).toCountResources('AWS::IAM::Policy', 0); + + // Check that the CodeBuild project does not have a DependsOn + expect(stack).toHaveResource('AWS::CodeBuild::Project', (res: any) => { + if (res.DependsOn && res.DependsOn.length > 0) { + throw new Error(`CodeBuild project should have no DependsOn, but got: ${JSON.stringify(res, undefined, 2)}`); + } + return true; + }, ResourcePart.CompleteDefinition); +}); + +test('can use an ImmutableRole for a Project within a VPC', () => { + const stack = new cdk.Stack(); + + const role = new iam.Role(stack, 'Role', { + assumedBy: new iam.ServicePrincipal('codebuild.amazonaws.com'), + }); + + const vpc = new ec2.Vpc(stack, 'Vpc'); + + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.gitHubEnterprise({ + httpsCloneUrl: 'https://mygithub-enterprise.com/myuser/myrepo', + }), + role: role.withoutPolicyUpdates(), + vpc, + }); + + expect(stack).toCountResources('AWS::IAM::Policy', 0); + + // Check that the CodeBuild project does not have a DependsOn + expect(stack).toHaveResource('AWS::CodeBuild::Project', (res: any) => { + if (res.DependsOn && res.DependsOn.length > 0) { + throw new Error(`CodeBuild project should have no DependsOn, but got: ${JSON.stringify(res, undefined, 2)}`); + } + return true; + }, ResourcePart.CompleteDefinition); +}); + +test('metric method generates a valid CloudWatch metric', () => { + const stack = new cdk.Stack(); + + const project = new codebuild.Project(stack, 'Project', { + source: codebuild.Source.gitHubEnterprise({ + httpsCloneUrl: 'https://mygithub-enterprise.com/myuser/myrepo', + }), + }); + + const metric = project.metric('Builds'); + expect(metric.metricName).toEqual('Builds'); + expect(metric.period.toSeconds()).toEqual(cdk.Duration.minutes(5).toSeconds()); + expect(metric.statistic).toEqual('Average'); +}); + +describe('CodeBuild test reports group', () => { + test('adds the appropriate permissions when reportGroup.grantWrite() is called', () => { + const stack = new cdk.Stack(); + + const reportGroup = new codebuild.ReportGroup(stack, 'ReportGroup'); + + const project = new codebuild.Project(stack, 'Project', { + buildSpec: codebuild.BuildSpec.fromObject({ + version: '0.2', + reports: { + [reportGroup.reportGroupArn]: { + files: '**/*', + }, + }, + }), + grantReportGroupPermissions: false, + }); + reportGroup.grantWrite(project); + + expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': [ + {}, + { + 'Action': [ + 'codebuild:CreateReport', + 'codebuild:UpdateReport', + 'codebuild:BatchPutTestCases', + ], + 'Resource': { + 'Fn::GetAtt': [ + 'ReportGroup8A84C76D', + 'Arn', + ], + }, + }, + ], + }, + }); + }); +}); + +describe('Environment', () => { + test('build image - can use secret to access build image', () => { + // GIVEN + const stack = new cdk.Stack(); + const secret = new secretsmanager.Secret(stack, 'Secret'); + + // WHEN + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.s3({ + bucket: new s3.Bucket(stack, 'Bucket'), + path: 'path', + }), + environment: { + buildImage: codebuild.LinuxBuildImage.fromDockerRegistry('myimage', { secretsManagerCredentials: secret }), + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + Environment: objectLike({ + RegistryCredential: { + CredentialProvider: 'SECRETS_MANAGER', + Credential: { 'Ref': 'SecretA720EF05' }, + }, + }), + }); + }); + + test('build image - can use imported secret by name', () => { + // GIVEN + const stack = new cdk.Stack(); + const secret = secretsmanager.Secret.fromSecretNameV2(stack, 'Secret', 'MySecretName'); + + // WHEN + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.s3({ + bucket: new s3.Bucket(stack, 'Bucket'), + path: 'path', + }), + environment: { + buildImage: codebuild.LinuxBuildImage.fromDockerRegistry('myimage', { secretsManagerCredentials: secret }), + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + Environment: objectLike({ + RegistryCredential: { + CredentialProvider: 'SECRETS_MANAGER', + Credential: 'MySecretName', + }, + }), + }); + }); + + test('logs config - cloudWatch', () => { + // GIVEN + const stack = new cdk.Stack(); + const logGroup = logs.LogGroup.fromLogGroupName(stack, 'LogGroup', 'MyLogGroupName'); + + // WHEN + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.s3({ + bucket: new s3.Bucket(stack, 'Bucket'), + path: 'path', + }), + logging: { + cloudWatch: { + logGroup, + prefix: '/my-logs', + }, + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + LogsConfig: objectLike({ + CloudWatchLogs: { + GroupName: 'MyLogGroupName', + Status: 'ENABLED', + StreamName: '/my-logs', + }, + }), + }); + }); + + test('logs config - cloudWatch disabled', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.s3({ + bucket: new s3.Bucket(stack, 'Bucket'), + path: 'path', + }), + logging: { + cloudWatch: { + enabled: false, + }, + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + LogsConfig: objectLike({ + CloudWatchLogs: { + Status: 'DISABLED', + }, + }), + }); + }); + + test('logs config - s3', () => { + // GIVEN + const stack = new cdk.Stack(); + const bucket = s3.Bucket.fromBucketName(stack, 'LogBucket', 'MyBucketName'); + + // WHEN + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.s3({ + bucket: new s3.Bucket(stack, 'Bucket'), + path: 'path', + }), + logging: { + s3: { + bucket, + prefix: 'my-logs', + }, + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + LogsConfig: objectLike({ + S3Logs: { + Location: 'MyBucketName/my-logs', + Status: 'ENABLED', + }, + }), + }); + }); + + test('logs config - cloudWatch and s3', () => { + // GIVEN + const stack = new cdk.Stack(); + const bucket = s3.Bucket.fromBucketName(stack, 'LogBucket2', 'MyBucketName'); + const logGroup = logs.LogGroup.fromLogGroupName(stack, 'LogGroup2', 'MyLogGroupName'); + + // WHEN + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.s3({ + bucket: new s3.Bucket(stack, 'Bucket'), + path: 'path', + }), + logging: { + cloudWatch: { + logGroup, + }, + s3: { + bucket, + }, + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + LogsConfig: objectLike({ + CloudWatchLogs: { + GroupName: 'MyLogGroupName', + Status: 'ENABLED', + }, + S3Logs: { + Location: 'MyBucketName', + Status: 'ENABLED', + }, + }), + }); + }); + + test('certificate arn', () => { + // GIVEN + const stack = new cdk.Stack(); + const bucket = s3.Bucket.fromBucketName(stack, 'Bucket', 'my-bucket'); // (stack, 'Bucket'); + + // WHEN + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.s3({ + bucket, + path: 'path', + }), + environment: { + certificate: { + bucket, + objectKey: 'path', + }, + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + Environment: objectLike({ + Certificate: { + 'Fn::Join': ['', [ + 'arn:', + { 'Ref': 'AWS::Partition' }, + ':s3:::my-bucket/path', + ]], + }, + }), + }); + }); +}); + +describe('EnvironmentVariables', () => { + describe('from SSM', () => { + test('can use environment variables', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.s3({ + bucket: new s3.Bucket(stack, 'Bucket'), + path: 'path', + }), + environment: { + buildImage: codebuild.LinuxBuildImage.fromDockerRegistry('myimage'), + }, + environmentVariables: { + 'ENV_VAR1': { + type: codebuild.BuildEnvironmentVariableType.PARAMETER_STORE, + value: '/params/param1', + }, + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + Environment: objectLike({ + EnvironmentVariables: [{ + Name: 'ENV_VAR1', + Type: 'PARAMETER_STORE', + Value: '/params/param1', + }], + }), + }); + }); + + test('grants the correct read permissions', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.s3({ + bucket: new s3.Bucket(stack, 'Bucket'), + path: 'path', + }), + environment: { + buildImage: codebuild.LinuxBuildImage.fromDockerRegistry('myimage'), + }, + environmentVariables: { + 'ENV_VAR1': { + type: codebuild.BuildEnvironmentVariableType.PARAMETER_STORE, + value: '/params/param1', + }, + 'ENV_VAR2': { + type: codebuild.BuildEnvironmentVariableType.PARAMETER_STORE, + value: 'params/param2', + }, + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': arrayWith(objectLike({ + 'Action': 'ssm:GetParameters', + 'Effect': 'Allow', + 'Resource': [{ + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':ssm:', + { + Ref: 'AWS::Region', + }, + ':', + { + Ref: 'AWS::AccountId', + }, + ':parameter/params/param1', + ], + ], + }, + { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':ssm:', + { + Ref: 'AWS::Region', + }, + ':', + { + Ref: 'AWS::AccountId', + }, + ':parameter/params/param2', + ], + ], + }], + })), + }, + }); + }); + + test('does not grant read permissions when variables are not from parameter store', () => { + + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.s3({ + bucket: new s3.Bucket(stack, 'Bucket'), + path: 'path', + }), + environment: { + buildImage: codebuild.LinuxBuildImage.fromDockerRegistry('myimage'), + }, + environmentVariables: { + 'ENV_VAR1': { + type: codebuild.BuildEnvironmentVariableType.PLAINTEXT, + value: 'var1-value', + }, + }, + }); + + // THEN + expect(stack).not.toHaveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': arrayWith(objectLike({ + 'Action': 'ssm:GetParameters', + 'Effect': 'Allow', + })), + }, + }); + }); + }); + + describe('from SecretsManager', () => { + test('can be provided as a verbatim secret name', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new codebuild.PipelineProject(stack, 'Project', { + environmentVariables: { + 'ENV_VAR1': { + type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, + value: 'my-secret', + }, + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + 'Environment': { + 'EnvironmentVariables': [ + { + 'Name': 'ENV_VAR1', + 'Type': 'SECRETS_MANAGER', + 'Value': 'my-secret', + }, + ], + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': arrayWith({ + 'Action': 'secretsmanager:GetSecretValue', + 'Effect': 'Allow', + 'Resource': { + 'Fn::Join': ['', [ + 'arn:', + { Ref: 'AWS::Partition' }, + ':secretsmanager:', + { Ref: 'AWS::Region' }, + ':', + { Ref: 'AWS::AccountId' }, + ':secret:my-secret-??????', + ]], + }, + }), + }, + }); + }); + + test('can be provided as a verbatim secret name followed by a JSON key', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new codebuild.PipelineProject(stack, 'Project', { + environmentVariables: { + 'ENV_VAR1': { + type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, + value: 'my-secret:json-key', + }, + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + 'Environment': { + 'EnvironmentVariables': [ + { + 'Name': 'ENV_VAR1', + 'Type': 'SECRETS_MANAGER', + 'Value': 'my-secret:json-key', + }, + ], + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': arrayWith({ + 'Action': 'secretsmanager:GetSecretValue', + 'Effect': 'Allow', + 'Resource': { + 'Fn::Join': ['', [ + 'arn:', + { Ref: 'AWS::Partition' }, + ':secretsmanager:', + { Ref: 'AWS::Region' }, + ':', + { Ref: 'AWS::AccountId' }, + ':secret:my-secret-??????', + ]], + }, + }), + }, + }); + }); + + test('can be provided as a verbatim full secret ARN followed by a JSON key', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new codebuild.PipelineProject(stack, 'Project', { + environmentVariables: { + 'ENV_VAR1': { + type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, + value: 'arn:aws:secretsmanager:us-west-2:123456789012:secret:my-secret-123456:json-key', + }, + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + 'Environment': { + 'EnvironmentVariables': [ + { + 'Name': 'ENV_VAR1', + 'Type': 'SECRETS_MANAGER', + 'Value': 'arn:aws:secretsmanager:us-west-2:123456789012:secret:my-secret-123456:json-key', + }, + ], + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': arrayWith({ + 'Action': 'secretsmanager:GetSecretValue', + 'Effect': 'Allow', + 'Resource': 'arn:aws:secretsmanager:us-west-2:123456789012:secret:my-secret-123456*', + }), + }, + }); + + // THEN + expect(stack).not.toHaveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': arrayWith({ + 'Action': 'kms:Decrypt', + 'Effect': 'Allow', + 'Resource': 'arn:aws:kms:us-west-2:123456789012:key/*', + }), + }, + }); + }); + + test('can be provided as a verbatim partial secret ARN', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new codebuild.PipelineProject(stack, 'Project', { + environmentVariables: { + 'ENV_VAR1': { + type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, + value: 'arn:aws:secretsmanager:us-west-2:123456789012:secret:mysecret', + }, + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + 'Environment': { + 'EnvironmentVariables': [ + { + 'Name': 'ENV_VAR1', + 'Type': 'SECRETS_MANAGER', + 'Value': 'arn:aws:secretsmanager:us-west-2:123456789012:secret:mysecret', + }, + ], + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': arrayWith({ + 'Action': 'secretsmanager:GetSecretValue', + 'Effect': 'Allow', + 'Resource': 'arn:aws:secretsmanager:us-west-2:123456789012:secret:mysecret*', + }), + }, + }); + + // THEN + expect(stack).not.toHaveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': arrayWith({ + 'Action': 'kms:Decrypt', + 'Effect': 'Allow', + 'Resource': 'arn:aws:kms:us-west-2:123456789012:key/*', + }), + }, + }); + }); + + test("when provided as a verbatim partial secret ARN from another account, adds permission to decrypt keys in the Secret's account", () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'ProjectStack', { + env: { account: '123456789012' }, + }); + + // WHEN + new codebuild.PipelineProject(stack, 'Project', { + environmentVariables: { + 'ENV_VAR1': { + type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, + value: 'arn:aws:secretsmanager:us-west-2:901234567890:secret:mysecret', + }, + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': arrayWith({ + 'Action': 'kms:Decrypt', + 'Effect': 'Allow', + 'Resource': 'arn:aws:kms:us-west-2:901234567890:key/*', + }), + }, + }); + }); + + test('when two secrets from another account are provided as verbatim partial secret ARNs, adds only one permission for decrypting', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'ProjectStack', { + env: { account: '123456789012' }, + }); + + // WHEN + new codebuild.PipelineProject(stack, 'Project', { + environmentVariables: { + 'ENV_VAR1': { + type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, + value: 'arn:aws:secretsmanager:us-west-2:901234567890:secret:mysecret', + }, + 'ENV_VAR2': { + type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, + value: 'arn:aws:secretsmanager:us-west-2:901234567890:secret:other-secret', + }, + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': arrayWith({ + 'Action': 'kms:Decrypt', + 'Effect': 'Allow', + 'Resource': 'arn:aws:kms:us-west-2:901234567890:key/*', + }), + }, + }); + }); + + test('can be provided as the ARN attribute of a new Secret', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + const secret = new secretsmanager.Secret(stack, 'Secret'); + new codebuild.PipelineProject(stack, 'Project', { + environmentVariables: { + 'ENV_VAR1': { + type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, + value: secret.secretArn, + }, + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + 'Environment': { + 'EnvironmentVariables': [ + { + 'Name': 'ENV_VAR1', + 'Type': 'SECRETS_MANAGER', + 'Value': { 'Ref': 'SecretA720EF05' }, + }, + ], + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': arrayWith({ + 'Action': 'secretsmanager:GetSecretValue', + 'Effect': 'Allow', + 'Resource': { 'Ref': 'SecretA720EF05' }, + }), + }, + }); + }); + + test('when the same new secret is provided with different JSON keys, only adds the resource once', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + const secret = new secretsmanager.Secret(stack, 'Secret'); + new codebuild.PipelineProject(stack, 'Project', { + environmentVariables: { + 'ENV_VAR1': { + type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, + value: `${secret.secretArn}:json-key1`, + }, + 'ENV_VAR2': { + type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, + value: `${secret.secretArn}:json-key2`, + }, + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + 'Environment': { + 'EnvironmentVariables': [ + { + 'Name': 'ENV_VAR1', + 'Type': 'SECRETS_MANAGER', + 'Value': { 'Fn::Join': ['', [{ 'Ref': 'SecretA720EF05' }, ':json-key1']] }, + }, + { + 'Name': 'ENV_VAR2', + 'Type': 'SECRETS_MANAGER', + 'Value': { 'Fn::Join': ['', [{ 'Ref': 'SecretA720EF05' }, ':json-key2']] }, + }, + ], + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': arrayWith({ + 'Action': 'secretsmanager:GetSecretValue', + 'Effect': 'Allow', + 'Resource': { 'Ref': 'SecretA720EF05' }, + }), + }, + }); + }); + + test('can be provided as the ARN attribute of a new Secret, followed by a JSON key', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + const secret = new secretsmanager.Secret(stack, 'Secret'); + new codebuild.PipelineProject(stack, 'Project', { + environmentVariables: { + 'ENV_VAR1': { + type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, + value: `${secret.secretArn}:json-key:version-stage`, + }, + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + 'Environment': { + 'EnvironmentVariables': [ + { + 'Name': 'ENV_VAR1', + 'Type': 'SECRETS_MANAGER', + 'Value': { + 'Fn::Join': ['', [ + { 'Ref': 'SecretA720EF05' }, + ':json-key:version-stage', + ]], + }, + }, + ], + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': arrayWith({ + 'Action': 'secretsmanager:GetSecretValue', + 'Effect': 'Allow', + 'Resource': { 'Ref': 'SecretA720EF05' }, + }), + }, + }); + }); + + test('can be provided as the name attribute of a Secret imported by name', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + const secret = secretsmanager.Secret.fromSecretNameV2(stack, 'Secret', 'mysecret'); + new codebuild.PipelineProject(stack, 'Project', { + environmentVariables: { + 'ENV_VAR1': { + type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, + value: secret.secretName, + }, + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + 'Environment': { + 'EnvironmentVariables': [ + { + 'Name': 'ENV_VAR1', + 'Type': 'SECRETS_MANAGER', + 'Value': 'mysecret', + }, + ], + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': arrayWith({ + 'Action': 'secretsmanager:GetSecretValue', + 'Effect': 'Allow', + 'Resource': { + 'Fn::Join': ['', [ + 'arn:', + { 'Ref': 'AWS::Partition' }, + ':secretsmanager:', + { 'Ref': 'AWS::Region' }, + ':', + { 'Ref': 'AWS::AccountId' }, + ':secret:mysecret-??????', + ]], + }, + }), + }, + }); + }); + + test('can be provided as the ARN attribute of a Secret imported by partial ARN, followed by a JSON key', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + const secret = secretsmanager.Secret.fromSecretPartialArn(stack, 'Secret', + 'arn:aws:secretsmanager:us-west-2:123456789012:secret:mysecret'); + new codebuild.PipelineProject(stack, 'Project', { + environmentVariables: { + 'ENV_VAR1': { + type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, + value: `${secret.secretArn}:json-key`, + }, + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + 'Environment': { + 'EnvironmentVariables': [ + { + 'Name': 'ENV_VAR1', + 'Type': 'SECRETS_MANAGER', + 'Value': 'arn:aws:secretsmanager:us-west-2:123456789012:secret:mysecret:json-key', + }, + ], + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': arrayWith({ + 'Action': 'secretsmanager:GetSecretValue', + 'Effect': 'Allow', + 'Resource': 'arn:aws:secretsmanager:us-west-2:123456789012:secret:mysecret*', + }), + }, + }); + }); + + test('can be provided as the ARN attribute of a Secret imported by complete ARN, followed by a JSON key', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + const secret = secretsmanager.Secret.fromSecretCompleteArn(stack, 'Secret', + 'arn:aws:secretsmanager:us-west-2:123456789012:secret:mysecret-123456'); + new codebuild.PipelineProject(stack, 'Project', { + environmentVariables: { + 'ENV_VAR1': { + type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, + value: `${secret.secretArn}:json-key`, + }, + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + 'Environment': { + 'EnvironmentVariables': [ + { + 'Name': 'ENV_VAR1', + 'Type': 'SECRETS_MANAGER', + 'Value': 'arn:aws:secretsmanager:us-west-2:123456789012:secret:mysecret-123456:json-key', + }, + ], + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': arrayWith({ + 'Action': 'secretsmanager:GetSecretValue', + 'Effect': 'Allow', + 'Resource': 'arn:aws:secretsmanager:us-west-2:123456789012:secret:mysecret-123456*', + }), + }, + }); + }); + + test('can be provided as a SecretArn of a new Secret, with its physical name set, created in a different account', () => { + // GIVEN + const app = new cdk.App(); + const secretStack = new cdk.Stack(app, 'SecretStack', { + env: { account: '012345678912' }, + }); + const stack = new cdk.Stack(app, 'ProjectStack', { + env: { account: '123456789012' }, + }); + + // WHEN + const secret = new secretsmanager.Secret(secretStack, 'Secret', { secretName: 'secret-name' }); + new codebuild.PipelineProject(stack, 'Project', { + environmentVariables: { + 'ENV_VAR1': { + type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, + value: secret.secretArn, + }, + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + 'Environment': { + 'EnvironmentVariables': [ + { + 'Name': 'ENV_VAR1', + 'Type': 'SECRETS_MANAGER', + 'Value': { + 'Fn::Join': ['', [ + 'arn:', + { 'Ref': 'AWS::Partition' }, + ':secretsmanager:', + { 'Ref': 'AWS::Region' }, + ':012345678912:secret:secret-name', + ]], + }, + }, + ], + }, + }); + + expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': arrayWith({ + 'Action': 'secretsmanager:GetSecretValue', + 'Effect': 'Allow', + 'Resource': { + 'Fn::Join': ['', [ + 'arn:', + { 'Ref': 'AWS::Partition' }, + ':secretsmanager:', + { 'Ref': 'AWS::Region' }, + ':012345678912:secret:secret-name-??????', + ]], + }, + }), + }, + }); + + expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': arrayWith({ + 'Action': 'kms:Decrypt', + 'Effect': 'Allow', + 'Resource': { + 'Fn::Join': ['', [ + 'arn:', + { 'Ref': 'AWS::Partition' }, + ':kms:', + { 'Ref': 'AWS::Region' }, + ':012345678912:key/*', + ]], + }, + }), + }, + }); + }); + + test('can be provided as a SecretArn of a Secret imported by name in a different account', () => { + // GIVEN + const app = new cdk.App(); + const secretStack = new cdk.Stack(app, 'SecretStack', { + env: { account: '012345678912' }, + }); + const stack = new cdk.Stack(app, 'ProjectStack', { + env: { account: '123456789012' }, + }); + + // WHEN + const secret = secretsmanager.Secret.fromSecretNameV2(secretStack, 'Secret', 'secret-name'); + new codebuild.PipelineProject(stack, 'Project', { + environmentVariables: { + 'ENV_VAR1': { + type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, + value: `${secret.secretArn}:json-key`, + }, + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + 'Environment': { + 'EnvironmentVariables': [ + { + 'Name': 'ENV_VAR1', + 'Type': 'SECRETS_MANAGER', + 'Value': { + 'Fn::Join': ['', [ + 'arn:', + { 'Ref': 'AWS::Partition' }, + ':secretsmanager:', + { 'Ref': 'AWS::Region' }, + ':012345678912:secret:secret-name:json-key', + ]], + }, + }, + ], + }, + }); + + expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': arrayWith({ + 'Action': 'secretsmanager:GetSecretValue', + 'Effect': 'Allow', + 'Resource': { + 'Fn::Join': ['', [ + 'arn:', + { 'Ref': 'AWS::Partition' }, + ':secretsmanager:', + { 'Ref': 'AWS::Region' }, + ':012345678912:secret:secret-name*', + ]], + }, + }), + }, + }); + + expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': arrayWith({ + 'Action': 'kms:Decrypt', + 'Effect': 'Allow', + 'Resource': { + 'Fn::Join': ['', [ + 'arn:', + { 'Ref': 'AWS::Partition' }, + ':kms:', + { 'Ref': 'AWS::Region' }, + ':012345678912:key/*', + ]], + }, + }), + }, + }); + }); + + test('can be provided as a SecretArn of a Secret imported by complete ARN from a different account', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'ProjectStack', { + env: { account: '123456789012' }, + }); + const secretArn = 'arn:aws:secretsmanager:us-west-2:901234567890:secret:mysecret-123456'; + + // WHEN + const secret = secretsmanager.Secret.fromSecretCompleteArn(stack, 'Secret', secretArn); + new codebuild.PipelineProject(stack, 'Project', { + environmentVariables: { + 'ENV_VAR1': { + type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, + value: secret.secretArn, + }, + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + 'Environment': { + 'EnvironmentVariables': [ + { + 'Name': 'ENV_VAR1', + 'Type': 'SECRETS_MANAGER', + 'Value': secretArn, + }, + ], + }, + }); + + expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': arrayWith({ + 'Action': 'secretsmanager:GetSecretValue', + 'Effect': 'Allow', + 'Resource': `${secretArn}*`, + }), + }, + }); + + expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': arrayWith({ + 'Action': 'kms:Decrypt', + 'Effect': 'Allow', + 'Resource': 'arn:aws:kms:us-west-2:901234567890:key/*', + }), + }, + }); + }); + + test('should fail when the parsed Arn does not contain a secret name', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + expect(() => { + new codebuild.PipelineProject(stack, 'Project', { + environmentVariables: { + 'ENV_VAR1': { + type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, + value: 'arn:aws:secretsmanager:us-west-2:123456789012:secret', + }, + }, + }); + }).toThrow(/SecretManager ARN is missing the name of the secret:/); + }); + }); + + test('should fail creating when using a secret value in a plaintext variable', () => { + // GIVEN + const stack = new cdk.Stack(); + + // THEN + expect(() => { + new codebuild.PipelineProject(stack, 'Project', { + environmentVariables: { + 'a': { + value: `a_${cdk.SecretValue.secretsManager('my-secret')}_b`, + }, + }, + }); + }).toThrow(/Plaintext environment variable 'a' contains a secret value!/); + }); + + test("should allow opting out of the 'secret value in a plaintext variable' validation", () => { + // GIVEN + const stack = new cdk.Stack(); + + // THEN + expect(() => { + new codebuild.PipelineProject(stack, 'Project', { + environmentVariables: { + 'b': { + value: cdk.SecretValue.secretsManager('my-secret'), + }, + }, + checkSecretsInPlainTextEnvVariables: false, + }); + }).not.toThrow(); + }); +}); + +describe('Timeouts', () => { + test('can add queued timeout', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.s3({ + bucket: new s3.Bucket(stack, 'Bucket'), + path: 'path', + }), + queuedTimeout: cdk.Duration.minutes(30), + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + QueuedTimeoutInMinutes: 30, + }); + }); + + test('can override build timeout', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.s3({ + bucket: new s3.Bucket(stack, 'Bucket'), + path: 'path', + }), + timeout: cdk.Duration.minutes(30), + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + TimeoutInMinutes: 30, + }); + }); +}); + +describe('Maximum concurrency', () => { + test('can limit maximum concurrency', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.s3({ + bucket: new s3.Bucket(stack, 'Bucket'), + path: 'path', + }), + concurrentBuildLimit: 1, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + ConcurrentBuildLimit: 1, + }); + }); +}); + +describe('can be imported', () => { + test('by ARN', () => { + const stack = new cdk.Stack(); + const project = codebuild.Project.fromProjectArn(stack, 'Project', + 'arn:aws:codebuild:us-west-2:123456789012:project/My-Project'); + + expect(project.projectName).toEqual('My-Project'); + expect(project.env.account).toEqual('123456789012'); + expect(project.env.region).toEqual('us-west-2'); + }); +}); diff --git a/packages/@aws-cdk/aws-codebuild/test/report-group.test.ts b/packages/@aws-cdk/aws-codebuild/test/report-group.test.ts new file mode 100644 index 0000000000000..4459ef4672f0c --- /dev/null +++ b/packages/@aws-cdk/aws-codebuild/test/report-group.test.ts @@ -0,0 +1,146 @@ +import { ABSENT, ResourcePart } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; +import * as iam from '@aws-cdk/aws-iam'; +import * as kms from '@aws-cdk/aws-kms'; +import * as s3 from '@aws-cdk/aws-s3'; +import * as cdk from '@aws-cdk/core'; +import * as codebuild from '../lib'; + +/* eslint-disable quote-props */ +/* eslint-disable quotes */ + +describe('Test Reports Groups', () => { + test('get created with type=TEST and exportConfig=NO_EXPORT by default', () => { + const stack = new cdk.Stack(); + + new codebuild.ReportGroup(stack, 'ReportGroup'); + + expect(stack).toHaveResourceLike('AWS::CodeBuild::ReportGroup', { + "Type": "TEST", + "ExportConfig": { + "ExportConfigType": "NO_EXPORT", + "S3Destination": ABSENT, + }, + }); + }); + + test('can be created with name', () => { + const stack = new cdk.Stack(); + + new codebuild.ReportGroup(stack, 'ReportGroup', { + reportGroupName: 'my-report-group', + }); + + expect(stack).toHaveResourceLike('AWS::CodeBuild::ReportGroup', { + "Name": 'my-report-group', + }); + }); + + test('can be imported by name', () => { + const stack = new cdk.Stack(); + + const reportGroup = codebuild.ReportGroup.fromReportGroupName(stack, + 'ReportGroup', 'my-report-group'); + + const role = new iam.Role(stack, 'Role', { + assumedBy: new iam.AnyPrincipal(), + }); + role.addToPolicy(new iam.PolicyStatement({ + actions: ['codebuild:*'], + resources: [reportGroup.reportGroupArn], + })); + + expect(reportGroup.reportGroupName).toEqual('my-report-group'); + expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + "PolicyDocument": { + "Statement": [ + { + "Action": "codebuild:*", + "Resource": { + "Fn::Join": ["", [ + "arn:", + { "Ref": "AWS::Partition" }, + ":codebuild:", + { "Ref": "AWS::Region" }, + ":", + { "Ref": "AWS::AccountId" }, + ":report-group/my-report-group", + ]], + }, + }, + ], + }, + }); + }); + + test('specify exportConfig=S3 when providing an exportBucket', () => { + const stack = new cdk.Stack(); + + new codebuild.ReportGroup(stack, 'ReportGroup', { + exportBucket: s3.Bucket.fromBucketName(stack, 'Bucket', 'my-bucket'), + }); + + expect(stack).toHaveResourceLike('AWS::CodeBuild::ReportGroup', { + "Type": "TEST", + "ExportConfig": { + "ExportConfigType": "S3", + "S3Destination": { + "Bucket": "my-bucket", + "EncryptionKey": ABSENT, + "EncryptionDisabled": ABSENT, + "Packaging": ABSENT, + }, + }, + }); + }); + + test('specify encryptionKey in ExportConfig.S3Destination if exportBucket has a Key', () => { + const stack = new cdk.Stack(); + + new codebuild.ReportGroup(stack, 'ReportGroup', { + exportBucket: s3.Bucket.fromBucketAttributes(stack, 'Bucket', { + bucketName: 'my-bucket', + encryptionKey: kms.Key.fromKeyArn(stack, 'Key', + 'arn:aws:kms:us-east-1:123456789012:key/my-key'), + }), + zipExport: true, + }); + + expect(stack).toHaveResourceLike('AWS::CodeBuild::ReportGroup', { + "Type": "TEST", + "ExportConfig": { + "ExportConfigType": "S3", + "S3Destination": { + "Bucket": "my-bucket", + "EncryptionDisabled": false, + "EncryptionKey": "arn:aws:kms:us-east-1:123456789012:key/my-key", + "Packaging": "ZIP", + }, + }, + }); + }); + + test('get created with RemovalPolicy.RETAIN by default', () => { + const stack = new cdk.Stack(); + + new codebuild.ReportGroup(stack, 'ReportGroup'); + + expect(stack).toHaveResourceLike('AWS::CodeBuild::ReportGroup', { + "DeletionPolicy": "Retain", + "UpdateReplacePolicy": "Retain", + }, ResourcePart.CompleteDefinition); + }); + + test('can be created with RemovalPolicy.DESTROY', () => { + const stack = new cdk.Stack(); + + new codebuild.ReportGroup(stack, 'ReportGroup', { + removalPolicy: cdk.RemovalPolicy.DESTROY, + }); + + expect(stack).toHaveResourceLike('AWS::CodeBuild::ReportGroup', { + "DeletionPolicy": "Delete", + "UpdateReplacePolicy": "Delete", + }, ResourcePart.CompleteDefinition); + }); +}); diff --git a/packages/@aws-cdk/aws-codebuild/test/test.build-spec.ts b/packages/@aws-cdk/aws-codebuild/test/test.build-spec.ts deleted file mode 100644 index ad625d39c2087..0000000000000 --- a/packages/@aws-cdk/aws-codebuild/test/test.build-spec.ts +++ /dev/null @@ -1,421 +0,0 @@ -// import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; -import * as codebuild from '../lib'; - -/* eslint-disable quote-props */ -/* eslint-disable quotes */ - -export = { - 'Test BuildSpec merge': { - 'merge two simple specs'(test: Test) { - const lhs = codebuild.BuildSpec.fromObject({ - phases: { - pre_build: { - commands: [ - 'install', - ], - }, - }, - }); - const rhs = codebuild.BuildSpec.fromObject({ - phases: { - build: { - commands: 'build', - }, - }, - }); - - const merged = codebuild.mergeBuildSpecs(lhs, rhs); - - test.deepEqual((merged as any).spec, { - phases: { - pre_build: { - commands: [ - 'install', - ], - }, - build: { - commands: [ - 'build', - ], - }, - }, - }); - - test.done(); - }, - - 'merge command lists'(test: Test) { - const lhs = codebuild.BuildSpec.fromObject({ - phases: { - build: { - commands: [ - 'build1', - ], - }, - }, - }); - const rhs = codebuild.BuildSpec.fromObject({ - phases: { - build: { - commands: 'build2', - }, - }, - }); - - const merged = codebuild.mergeBuildSpecs(lhs, rhs); - - test.deepEqual((merged as any).spec, { - phases: { - build: { - commands: [ - 'build1', - 'build2', - ], - }, - }, - }); - - test.done(); - }, - - 'do not merge artifacts'(test: Test) { - const lhs = codebuild.BuildSpec.fromObject({ - phases: { - build: { - commands: [ - 'build1', - ], - }, - }, - artifacts: { - 'base-directory': 'subdir/cdk.out', - }, - }); - const rhs = codebuild.BuildSpec.fromObject({ - phases: { - build: { - commands: [ - 'build2', - ], - }, - }, - artifacts: { - 'base-directory': 'subdir/cdk.out', - }, - }); - - test.throws(() => { - codebuild.mergeBuildSpecs(lhs, rhs); - }); - test.done(); - }, - - 'merge complex example'(test: Test) { - const cdkSpec = codebuild.BuildSpec.fromObject({ - env: { - 'variables': { - NPM_TOKEN: 'supersecret', - }, - }, - phases: { - pre_build: { - commands: [ - 'install1', - ], - }, - build: { - commands: [ - 'build1', - 'test1', - 'cdk synth', - ], - }, - }, - }); - const userSpec = codebuild.BuildSpec.fromObject({ - version: 0.2, - env: { - 'variables': { - JAVA_HOME: '/usr/lib/jvm/java-8-openjdk-amd64', - }, - 'parameter-store': { - LOGIN_PASSWORD: '/CodeBuild/dockerLoginPassword', - }, - }, - phases: { - install: { - commands: [ - 'echo Entered the install phase...', - 'apt-get update -y', - 'apt-get install -y maven', - ], - finally: [ - 'echo This always runs even if the update or install command fails', - ], - }, - pre_build: { - commands: [ - 'echo Entered the pre_build phase...', - 'docker login -u User -p $LOGIN_PASSWORD', - ], - finally: [ - 'echo This always runs even if the login command fails', - ], - }, - build: { - commands: [ - 'echo Entered the build phase...', - 'echo Build started on `date`', - 'mvn install', - ], - finally: [ - 'echo This always runs even if the install command fails', - ], - }, - post_build: { - commands: [ - 'echo Entered the post_build phase...', - 'echo Build completed on `date`', - ], - }, - }, - reports: { - 'arn:aws:codebuild:your-region:your-aws-account-id:report-group/report-group-name-1': { - 'files': [ - '**/*', - ], - 'base-directory': 'target/tests/reports', - 'discard-paths': 'no', - }, - 'reportGroupCucumberJson': { - 'files': [ - 'cucumber/target/cucumber-tests.xml', - ], - 'discard-paths': 'yes', - 'file-format': 'CUCUMBERJSON', - }, - }, - artifacts: { - 'files': [ - 'target/messageUtil-1.0.jar', - ], - 'discard-paths': 'yes', - 'secondary-artifacts': { - artifact1: { - 'files': [ - 'target/artifact-1.0.jar', - ], - 'discard-paths': 'yes', - }, - artifact2: { - 'files': [ - 'target/artifact-2.0.jar', - ], - 'discard-paths': 'yes', - }, - }, - }, - cache: { - paths: [ - '/root/.m2/**/*', - ], - }, - }); - - const merged = codebuild.mergeBuildSpecs(userSpec, cdkSpec); - - test.deepEqual((merged as any).spec, { - version: 0.2, - env: { - 'variables': { - JAVA_HOME: '/usr/lib/jvm/java-8-openjdk-amd64', - NPM_TOKEN: 'supersecret', - }, - 'parameter-store': { - LOGIN_PASSWORD: '/CodeBuild/dockerLoginPassword', - }, - }, - phases: { - install: { - commands: [ - 'echo Entered the install phase...', - 'apt-get update -y', - 'apt-get install -y maven', - ], - finally: [ - 'echo This always runs even if the update or install command fails', - ], - }, - pre_build: { - commands: [ - 'echo Entered the pre_build phase...', - 'docker login -u User -p $LOGIN_PASSWORD', - 'install1', - ], - finally: [ - 'echo This always runs even if the login command fails', - ], - }, - build: { - commands: [ - 'echo Entered the build phase...', - 'echo Build started on `date`', - 'mvn install', - 'build1', - 'test1', - 'cdk synth', - ], - finally: [ - 'echo This always runs even if the install command fails', - ], - }, - post_build: { - commands: [ - 'echo Entered the post_build phase...', - 'echo Build completed on `date`', - ], - }, - }, - reports: { - 'arn:aws:codebuild:your-region:your-aws-account-id:report-group/report-group-name-1': { - 'files': [ - '**/*', - ], - 'base-directory': 'target/tests/reports', - 'discard-paths': 'no', - }, - 'reportGroupCucumberJson': { - 'files': [ - 'cucumber/target/cucumber-tests.xml', - ], - 'discard-paths': 'yes', - 'file-format': 'CUCUMBERJSON', - }, - }, - artifacts: { - 'files': [ - 'target/messageUtil-1.0.jar', - ], - 'discard-paths': 'yes', - 'secondary-artifacts': { - artifact1: { - 'files': [ - 'target/artifact-1.0.jar', - ], - 'discard-paths': 'yes', - }, - artifact2: { - 'files': [ - 'target/artifact-2.0.jar', - ], - 'discard-paths': 'yes', - }, - }, - }, - cache: { - paths: [ - '/root/.m2/**/*', - ], - }, - }); - - test.done(); - }, - - 'override duplicate reports'(test: Test) { - const lhs = codebuild.BuildSpec.fromObject({ - phases: { - pre_build: { - commands: [ - 'install', - ], - }, - }, - reports: { - 'report1': { - 'files': [ - 'report1/a', - ], - 'discard-paths': 'no', - 'base-directory': 'target/tests/reports', - }, - 'report2': { - 'files': [ - 'cucumber/target/cucumber-tests.xml', - ], - 'discard-paths': 'yes', - 'file-format': 'CUCUMBERJSON', - }, - }, - }); - const rhs = codebuild.BuildSpec.fromObject({ - phases: { - build: { - commands: [ - 'build', - ], - }, - }, - reports: { - 'report1': { - 'files': [ - 'report1/b', - 'report1/b2', - ], - 'base-directory': 'target/tests/reportsB', - }, - 'report3': { - 'files': [ - 'cucumber/target/cucumber-tests.xml', - ], - 'discard-paths': 'yes', - 'file-format': 'CUCUMBERJSON', - }, - }, - }); - - const merged = codebuild.mergeBuildSpecs(lhs, rhs); - - test.deepEqual((merged as any).spec, { - phases: { - pre_build: { - commands: [ - 'install', - ], - }, - build: { - commands: [ - 'build', - ], - }, - }, - reports: { - 'report1': { - 'files': [ - 'report1/b', - 'report1/b2', - ], - 'base-directory': 'target/tests/reportsB', - }, - 'report2': { - 'files': [ - 'cucumber/target/cucumber-tests.xml', - ], - 'discard-paths': 'yes', - 'file-format': 'CUCUMBERJSON', - }, - 'report3': { - 'files': [ - 'cucumber/target/cucumber-tests.xml', - ], - 'discard-paths': 'yes', - 'file-format': 'CUCUMBERJSON', - }, - }, - }); - - test.done(); - }, - }, -}; diff --git a/packages/@aws-cdk/aws-codebuild/test/test.codebuild.ts b/packages/@aws-cdk/aws-codebuild/test/test.codebuild.ts deleted file mode 100644 index b287b7de0b2b2..0000000000000 --- a/packages/@aws-cdk/aws-codebuild/test/test.codebuild.ts +++ /dev/null @@ -1,1972 +0,0 @@ -import { ABSENT, expect, haveResource, haveResourceLike } from '@aws-cdk/assert-internal'; -import * as codecommit from '@aws-cdk/aws-codecommit'; -import * as ec2 from '@aws-cdk/aws-ec2'; -import * as kms from '@aws-cdk/aws-kms'; -import * as s3 from '@aws-cdk/aws-s3'; -import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; -import * as codebuild from '../lib'; -import { CodePipelineSource } from '../lib/codepipeline-source'; -import { NoSource } from '../lib/no-source'; - -/* eslint-disable quote-props */ - -export = { - 'default properties': { - 'with CodePipeline source'(test: Test) { - const stack = new cdk.Stack(); - - new codebuild.PipelineProject(stack, 'MyProject'); - - expect(stack).toMatch({ - 'Resources': { - 'MyProjectRole9BBE5233': { - 'Type': 'AWS::IAM::Role', - 'Properties': { - 'AssumeRolePolicyDocument': { - 'Statement': [ - { - 'Action': 'sts:AssumeRole', - 'Effect': 'Allow', - 'Principal': { - 'Service': 'codebuild.amazonaws.com', - }, - }, - ], - 'Version': '2012-10-17', - }, - }, - }, - 'MyProjectRoleDefaultPolicyB19B7C29': { - 'Type': 'AWS::IAM::Policy', - 'Properties': { - 'PolicyDocument': { - 'Statement': [ - { - 'Action': [ - 'logs:CreateLogGroup', - 'logs:CreateLogStream', - 'logs:PutLogEvents', - ], - 'Effect': 'Allow', - 'Resource': [ - { - 'Fn::Join': [ - '', - [ - 'arn:', - { - 'Ref': 'AWS::Partition', - }, - ':logs:', - { - 'Ref': 'AWS::Region', - }, - ':', - { - 'Ref': 'AWS::AccountId', - }, - ':log-group:/aws/codebuild/', - { - 'Ref': 'MyProject39F7B0AE', - }, - ], - ], - }, - { - 'Fn::Join': [ - '', - [ - 'arn:', - { - 'Ref': 'AWS::Partition', - }, - ':logs:', - { - 'Ref': 'AWS::Region', - }, - ':', - { - 'Ref': 'AWS::AccountId', - }, - ':log-group:/aws/codebuild/', - { - 'Ref': 'MyProject39F7B0AE', - }, - ':*', - ], - ], - }, - ], - }, - { - 'Action': [ - 'codebuild:CreateReportGroup', - 'codebuild:CreateReport', - 'codebuild:UpdateReport', - 'codebuild:BatchPutTestCases', - 'codebuild:BatchPutCodeCoverages', - ], - 'Effect': 'Allow', - 'Resource': { - 'Fn::Join': ['', [ - 'arn:', - { 'Ref': 'AWS::Partition' }, - ':codebuild:', - { 'Ref': 'AWS::Region' }, - ':', - { 'Ref': 'AWS::AccountId' }, - ':report-group/', - { 'Ref': 'MyProject39F7B0AE' }, - '-*', - ]], - }, - }, - ], - 'Version': '2012-10-17', - }, - 'PolicyName': 'MyProjectRoleDefaultPolicyB19B7C29', - 'Roles': [ - { - 'Ref': 'MyProjectRole9BBE5233', - }, - ], - }, - }, - 'MyProject39F7B0AE': { - 'Type': 'AWS::CodeBuild::Project', - 'Properties': { - 'Source': { - 'Type': 'CODEPIPELINE', - }, - 'Artifacts': { - 'Type': 'CODEPIPELINE', - }, - 'ServiceRole': { - 'Fn::GetAtt': [ - 'MyProjectRole9BBE5233', - 'Arn', - ], - }, - 'Environment': { - 'Type': 'LINUX_CONTAINER', - 'PrivilegedMode': false, - 'Image': 'aws/codebuild/standard:1.0', - 'ImagePullCredentialsType': 'CODEBUILD', - 'ComputeType': 'BUILD_GENERAL1_SMALL', - }, - 'EncryptionKey': 'alias/aws/s3', - }, - }, - }, - }); - - test.done(); - }, - 'with CodeCommit source'(test: Test) { - const stack = new cdk.Stack(); - - const repo = new codecommit.Repository(stack, 'MyRepo', { - repositoryName: 'hello-cdk', - }); - - const source = codebuild.Source.codeCommit({ repository: repo, cloneDepth: 2 }); - - new codebuild.Project(stack, 'MyProject', { - source, - }); - - expect(stack).toMatch({ - 'Resources': { - 'MyRepoF4F48043': { - 'Type': 'AWS::CodeCommit::Repository', - 'Properties': { - 'RepositoryName': 'hello-cdk', - }, - }, - 'MyProjectRole9BBE5233': { - 'Type': 'AWS::IAM::Role', - 'Properties': { - 'AssumeRolePolicyDocument': { - 'Statement': [ - { - 'Action': 'sts:AssumeRole', - 'Effect': 'Allow', - 'Principal': { - 'Service': 'codebuild.amazonaws.com', - }, - }, - ], - 'Version': '2012-10-17', - }, - }, - }, - 'MyProjectRoleDefaultPolicyB19B7C29': { - 'Type': 'AWS::IAM::Policy', - 'Properties': { - 'PolicyDocument': { - 'Statement': [ - { - 'Action': 'codecommit:GitPull', - 'Effect': 'Allow', - 'Resource': { - 'Fn::GetAtt': [ - 'MyRepoF4F48043', - 'Arn', - ], - }, - }, - { - 'Action': [ - 'logs:CreateLogGroup', - 'logs:CreateLogStream', - 'logs:PutLogEvents', - ], - 'Effect': 'Allow', - 'Resource': [ - { - 'Fn::Join': [ - '', - [ - 'arn:', - { - 'Ref': 'AWS::Partition', - }, - ':logs:', - { - 'Ref': 'AWS::Region', - }, - ':', - { - 'Ref': 'AWS::AccountId', - }, - ':log-group:/aws/codebuild/', - { - 'Ref': 'MyProject39F7B0AE', - }, - ], - ], - }, - { - 'Fn::Join': [ - '', - [ - 'arn:', - { - 'Ref': 'AWS::Partition', - }, - ':logs:', - { - 'Ref': 'AWS::Region', - }, - ':', - { - 'Ref': 'AWS::AccountId', - }, - ':log-group:/aws/codebuild/', - { - 'Ref': 'MyProject39F7B0AE', - }, - ':*', - ], - ], - }, - ], - }, - { - 'Action': [ - 'codebuild:CreateReportGroup', - 'codebuild:CreateReport', - 'codebuild:UpdateReport', - 'codebuild:BatchPutTestCases', - 'codebuild:BatchPutCodeCoverages', - ], - 'Effect': 'Allow', - 'Resource': { - 'Fn::Join': ['', [ - 'arn:', - { 'Ref': 'AWS::Partition' }, - ':codebuild:', - { 'Ref': 'AWS::Region' }, - ':', - { 'Ref': 'AWS::AccountId' }, - ':report-group/', - { 'Ref': 'MyProject39F7B0AE' }, - '-*', - ]], - }, - }, - ], - 'Version': '2012-10-17', - }, - 'PolicyName': 'MyProjectRoleDefaultPolicyB19B7C29', - 'Roles': [ - { - 'Ref': 'MyProjectRole9BBE5233', - }, - ], - }, - }, - 'MyProject39F7B0AE': { - 'Type': 'AWS::CodeBuild::Project', - 'Properties': { - 'Artifacts': { - 'Type': 'NO_ARTIFACTS', - }, - 'Environment': { - 'ComputeType': 'BUILD_GENERAL1_SMALL', - 'Image': 'aws/codebuild/standard:1.0', - 'ImagePullCredentialsType': 'CODEBUILD', - 'PrivilegedMode': false, - 'Type': 'LINUX_CONTAINER', - }, - 'ServiceRole': { - 'Fn::GetAtt': [ - 'MyProjectRole9BBE5233', - 'Arn', - ], - }, - 'Source': { - 'Location': { - 'Fn::GetAtt': [ - 'MyRepoF4F48043', - 'CloneUrlHttp', - ], - }, - 'GitCloneDepth': 2, - 'Type': 'CODECOMMIT', - }, - 'EncryptionKey': 'alias/aws/s3', - }, - }, - }, - }); - test.done(); - }, - 'with S3Bucket source'(test: Test) { - const stack = new cdk.Stack(); - const bucket = new s3.Bucket(stack, 'MyBucket'); - - new codebuild.Project(stack, 'MyProject', { - source: codebuild.Source.s3({ - bucket, - path: 'path/to/source.zip', - }), - environment: { - buildImage: codebuild.WindowsBuildImage.WINDOWS_BASE_2_0, - }, - }); - - expect(stack).toMatch({ - 'Resources': { - 'MyBucketF68F3FF0': { - 'Type': 'AWS::S3::Bucket', - 'DeletionPolicy': 'Retain', - 'UpdateReplacePolicy': 'Retain', - }, - 'MyProjectRole9BBE5233': { - 'Type': 'AWS::IAM::Role', - 'Properties': { - 'AssumeRolePolicyDocument': { - 'Statement': [ - { - 'Action': 'sts:AssumeRole', - 'Effect': 'Allow', - 'Principal': { - 'Service': 'codebuild.amazonaws.com', - }, - }, - ], - 'Version': '2012-10-17', - }, - }, - }, - 'MyProjectRoleDefaultPolicyB19B7C29': { - 'Type': 'AWS::IAM::Policy', - 'Properties': { - 'PolicyDocument': { - 'Statement': [ - { - 'Action': [ - 's3:GetObject*', - 's3:GetBucket*', - 's3:List*', - ], - 'Effect': 'Allow', - 'Resource': [ - { - 'Fn::GetAtt': [ - 'MyBucketF68F3FF0', - 'Arn', - ], - }, - { - 'Fn::Join': [ - '', - [ - { - 'Fn::GetAtt': [ - 'MyBucketF68F3FF0', - 'Arn', - ], - }, - '/path/to/source.zip', - ], - ], - }, - ], - }, - { - 'Action': [ - 'logs:CreateLogGroup', - 'logs:CreateLogStream', - 'logs:PutLogEvents', - ], - 'Effect': 'Allow', - 'Resource': [ - { - 'Fn::Join': [ - '', - [ - 'arn:', - { - 'Ref': 'AWS::Partition', - }, - ':logs:', - { - 'Ref': 'AWS::Region', - }, - ':', - { - 'Ref': 'AWS::AccountId', - }, - ':log-group:/aws/codebuild/', - { - 'Ref': 'MyProject39F7B0AE', - }, - ], - ], - }, - { - 'Fn::Join': [ - '', - [ - 'arn:', - { - 'Ref': 'AWS::Partition', - }, - ':logs:', - { - 'Ref': 'AWS::Region', - }, - ':', - { - 'Ref': 'AWS::AccountId', - }, - ':log-group:/aws/codebuild/', - { - 'Ref': 'MyProject39F7B0AE', - }, - ':*', - ], - ], - }, - ], - }, - { - 'Action': [ - 'codebuild:CreateReportGroup', - 'codebuild:CreateReport', - 'codebuild:UpdateReport', - 'codebuild:BatchPutTestCases', - 'codebuild:BatchPutCodeCoverages', - ], - 'Effect': 'Allow', - 'Resource': { - 'Fn::Join': ['', [ - 'arn:', - { 'Ref': 'AWS::Partition' }, - ':codebuild:', - { 'Ref': 'AWS::Region' }, - ':', - { 'Ref': 'AWS::AccountId' }, - ':report-group/', - { 'Ref': 'MyProject39F7B0AE' }, - '-*', - ]], - }, - }, - ], - 'Version': '2012-10-17', - }, - 'PolicyName': 'MyProjectRoleDefaultPolicyB19B7C29', - 'Roles': [ - { - 'Ref': 'MyProjectRole9BBE5233', - }, - ], - }, - }, - 'MyProject39F7B0AE': { - 'Type': 'AWS::CodeBuild::Project', - 'Properties': { - 'Artifacts': { - 'Type': 'NO_ARTIFACTS', - }, - 'Environment': { - 'ComputeType': 'BUILD_GENERAL1_MEDIUM', - 'Image': 'aws/codebuild/windows-base:2.0', - 'ImagePullCredentialsType': 'CODEBUILD', - 'PrivilegedMode': false, - 'Type': 'WINDOWS_CONTAINER', - }, - 'ServiceRole': { - 'Fn::GetAtt': [ - 'MyProjectRole9BBE5233', - 'Arn', - ], - }, - 'Source': { - 'Location': { - 'Fn::Join': [ - '', - [ - { - 'Ref': 'MyBucketF68F3FF0', - }, - '/path/to/source.zip', - ], - ], - }, - 'Type': 'S3', - }, - 'EncryptionKey': 'alias/aws/s3', - }, - }, - }, - }); - test.done(); - }, - 'with GitHub source'(test: Test) { - const stack = new cdk.Stack(); - - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.gitHub({ - owner: 'testowner', - repo: 'testrepo', - cloneDepth: 3, - fetchSubmodules: true, - webhook: true, - reportBuildStatus: false, - webhookFilters: [ - codebuild.FilterGroup.inEventOf(codebuild.EventAction.PUSH).andTagIsNot('stable'), - codebuild.FilterGroup.inEventOf(codebuild.EventAction.PULL_REQUEST_REOPENED).andBaseBranchIs('master'), - ], - }), - }); - - expect(stack).to(haveResource('AWS::CodeBuild::Project', { - Source: { - Type: 'GITHUB', - Location: 'https://github.com/testowner/testrepo.git', - ReportBuildStatus: false, - GitCloneDepth: 3, - GitSubmodulesConfig: { - FetchSubmodules: true, - }, - }, - })); - - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - Triggers: { - Webhook: true, - FilterGroups: [ - [ - { Type: 'EVENT', Pattern: 'PUSH' }, - { Type: 'HEAD_REF', Pattern: 'refs/tags/stable', ExcludeMatchedPattern: true }, - ], - [ - { Type: 'EVENT', Pattern: 'PULL_REQUEST_REOPENED' }, - { Type: 'BASE_REF', Pattern: 'refs/heads/master' }, - ], - ], - }, - })); - - test.done(); - }, - 'with GitHubEnterprise source'(test: Test) { - const stack = new cdk.Stack(); - - const pushFilterGroup = codebuild.FilterGroup.inEventOf(codebuild.EventAction.PUSH); - new codebuild.Project(stack, 'MyProject', { - source: codebuild.Source.gitHubEnterprise({ - httpsCloneUrl: 'https://github.testcompany.com/testowner/testrepo', - ignoreSslErrors: true, - cloneDepth: 4, - webhook: true, - reportBuildStatus: false, - webhookFilters: [ - pushFilterGroup.andBranchIs('master'), - pushFilterGroup.andBranchIs('develop'), - pushFilterGroup.andFilePathIs('ReadMe.md'), - ], - }), - }); - - expect(stack).to(haveResource('AWS::CodeBuild::Project', { - Source: { - Type: 'GITHUB_ENTERPRISE', - InsecureSsl: true, - GitCloneDepth: 4, - ReportBuildStatus: false, - Location: 'https://github.testcompany.com/testowner/testrepo', - }, - })); - - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - Triggers: { - Webhook: true, - FilterGroups: [ - [ - { Type: 'EVENT', Pattern: 'PUSH' }, - { Type: 'HEAD_REF', Pattern: 'refs/heads/master' }, - ], - [ - { Type: 'EVENT', Pattern: 'PUSH' }, - { Type: 'HEAD_REF', Pattern: 'refs/heads/develop' }, - ], - [ - { Type: 'EVENT', Pattern: 'PUSH' }, - { Type: 'FILE_PATH', Pattern: 'ReadMe.md' }, - ], - ], - }, - })); - - test.done(); - }, - 'with Bitbucket source'(test: Test) { - const stack = new cdk.Stack(); - - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.bitBucket({ - owner: 'testowner', - repo: 'testrepo', - cloneDepth: 5, - reportBuildStatus: false, - webhookFilters: [ - codebuild.FilterGroup.inEventOf( - codebuild.EventAction.PULL_REQUEST_CREATED, - codebuild.EventAction.PULL_REQUEST_UPDATED, - codebuild.EventAction.PULL_REQUEST_MERGED, - ).andTagIs('v.*'), - // duplicate event actions are fine - codebuild.FilterGroup.inEventOf(codebuild.EventAction.PUSH, codebuild.EventAction.PUSH).andActorAccountIsNot('aws-cdk-dev'), - ], - }), - }); - - expect(stack).to(haveResource('AWS::CodeBuild::Project', { - Source: { - Type: 'BITBUCKET', - Location: 'https://bitbucket.org/testowner/testrepo.git', - GitCloneDepth: 5, - ReportBuildStatus: false, - }, - })); - - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - Triggers: { - Webhook: true, - FilterGroups: [ - [ - { Type: 'EVENT', Pattern: 'PULL_REQUEST_CREATED, PULL_REQUEST_UPDATED, PULL_REQUEST_MERGED' }, - { Type: 'HEAD_REF', Pattern: 'refs/tags/v.*' }, - ], - [ - { Type: 'EVENT', Pattern: 'PUSH' }, - { Type: 'ACTOR_ACCOUNT_ID', Pattern: 'aws-cdk-dev', ExcludeMatchedPattern: true }, - ], - ], - }, - })); - - test.done(); - }, - - 'with webhookTriggersBatchBuild option'(test: Test) { - const stack = new cdk.Stack(); - - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.gitHub({ - owner: 'testowner', - repo: 'testrepo', - webhook: true, - webhookTriggersBatchBuild: true, - }), - }); - - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - Triggers: { - Webhook: true, - BuildType: 'BUILD_BATCH', - }, - BuildBatchConfig: { - ServiceRole: { - 'Fn::GetAtt': [ - 'ProjectBatchServiceRoleF97A1CFB', - 'Arn', - ], - }, - }, - })); - - expect(stack).to(haveResourceLike('AWS::IAM::Role', { - AssumeRolePolicyDocument: { - Statement: [ - { - Action: 'sts:AssumeRole', - Effect: 'Allow', - Principal: { - Service: 'codebuild.amazonaws.com', - }, - }, - ], - Version: '2012-10-17', - }, - })); - - expect(stack).to(haveResourceLike('AWS::IAM::Policy', { - PolicyDocument: { - Statement: [ - { - Action: [ - 'codebuild:StartBuild', - 'codebuild:StopBuild', - 'codebuild:RetryBuild', - ], - Effect: 'Allow', - Resource: { - 'Fn::GetAtt': [ - 'ProjectC78D97AD', - 'Arn', - ], - }, - }, - ], - Version: '2012-10-17', - }, - })); - - test.done(); - }, - - 'fail creating a Project when webhook false and webhookTriggersBatchBuild option'(test: Test) { - [false, undefined].forEach((webhook) => { - const stack = new cdk.Stack(); - - test.throws(() => { - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.gitHub({ - owner: 'testowner', - repo: 'testrepo', - webhook, - webhookTriggersBatchBuild: true, - }), - }); - }, /`webhookTriggersBatchBuild` cannot be used when `webhook` is `false`/); - }); - - test.done(); - }, - - 'fail creating a Project when no build spec is given'(test: Test) { - const stack = new cdk.Stack(); - - test.throws(() => { - new codebuild.Project(stack, 'MyProject', { - }); - }, /buildSpec/); - - test.done(); - }, - 'with VPC configuration'(test: Test) { - const stack = new cdk.Stack(); - - const bucket = new s3.Bucket(stack, 'MyBucket'); - const vpc = new ec2.Vpc(stack, 'MyVPC'); - const securityGroup = new ec2.SecurityGroup(stack, 'SecurityGroup1', { - securityGroupName: 'Bob', - vpc, - allowAllOutbound: true, - description: 'Example', - }); - const project = new codebuild.Project(stack, 'MyProject', { - source: codebuild.Source.s3({ - bucket, - path: 'path/to/source.zip', - }), - vpc, - securityGroups: [securityGroup], - }); - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - 'VpcConfig': { - 'SecurityGroupIds': [ - { - 'Fn::GetAtt': [ - 'SecurityGroup1F554B36F', - 'GroupId', - ], - }, - ], - 'Subnets': [ - { - 'Ref': 'MyVPCPrivateSubnet1Subnet641543F4', - }, - { - 'Ref': 'MyVPCPrivateSubnet2SubnetA420D3F0', - }, - ], - 'VpcId': { - 'Ref': 'MyVPCAFB07A31', - }, - }, - })); - - test.notEqual(project.connections, undefined); - - test.done(); - }, - 'without VPC configuration but security group identified'(test: Test) { - const stack = new cdk.Stack(); - - const bucket = new s3.Bucket(stack, 'MyBucket'); - const vpc = new ec2.Vpc(stack, 'MyVPC'); - const securityGroup = new ec2.SecurityGroup(stack, 'SecurityGroup1', { - securityGroupName: 'Bob', - vpc, - allowAllOutbound: true, - description: 'Example', - }); - - test.throws(() => - new codebuild.Project(stack, 'MyProject', { - source: codebuild.Source.s3({ - bucket, - path: 'path/to/source.zip', - }), - securityGroups: [securityGroup], - }) - , /Cannot configure 'securityGroup' or 'allowAllOutbound' without configuring a VPC/); - test.done(); - }, - 'with VPC configuration but allowAllOutbound identified'(test: Test) { - const stack = new cdk.Stack(); - const bucket = new s3.Bucket(stack, 'MyBucket'); - const vpc = new ec2.Vpc(stack, 'MyVPC'); - const securityGroup = new ec2.SecurityGroup(stack, 'SecurityGroup1', { - securityGroupName: 'Bob', - vpc, - allowAllOutbound: true, - description: 'Example', - }); - test.throws(() => - new codebuild.Project(stack, 'MyProject', { - source: codebuild.Source.s3({ - bucket, - path: 'path/to/source.zip', - }), - vpc, - allowAllOutbound: true, - securityGroups: [securityGroup], - }) - , /Configure 'allowAllOutbound' directly on the supplied SecurityGroup/); - test.done(); - }, - - 'without passing a VPC cannot access the connections property'(test: Test) { - const stack = new cdk.Stack(); - - const project = new codebuild.PipelineProject(stack, 'MyProject'); - - test.throws(() => project.connections, - /Only VPC-associated Projects have security groups to manage. Supply the "vpc" parameter when creating the Project/); - - test.done(); - }, - - 'no KMS Key defaults to default S3 managed key'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new codebuild.PipelineProject(stack, 'MyProject'); - - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - EncryptionKey: 'alias/aws/s3', - })); - - test.done(); - }, - - 'with a KMS Key adds decrypt permissions to the CodeBuild Role'(test: Test) { - const stack = new cdk.Stack(); - - const key = new kms.Key(stack, 'MyKey'); - - new codebuild.PipelineProject(stack, 'MyProject', { - encryptionKey: key, - grantReportGroupPermissions: false, - }); - - expect(stack).to(haveResourceLike('AWS::IAM::Policy', { - 'PolicyDocument': { - 'Statement': [ - {}, // CloudWatch logs - { - 'Action': [ - 'kms:Decrypt', - 'kms:Encrypt', - 'kms:ReEncrypt*', - 'kms:GenerateDataKey*', - ], - 'Effect': 'Allow', - 'Resource': { - 'Fn::GetAtt': [ - 'MyKey6AB29FA6', - 'Arn', - ], - }, - }, - ], - }, - 'Roles': [ - { - 'Ref': 'MyProjectRole9BBE5233', - }, - ], - })); - - test.done(); - }, - }, - - 'using timeout and path in S3 artifacts sets it correctly'(test: Test) { - const stack = new cdk.Stack(); - const bucket = new s3.Bucket(stack, 'Bucket'); - new codebuild.Project(stack, 'Project', { - buildSpec: codebuild.BuildSpec.fromObject({ - version: '0.2', - }), - artifacts: codebuild.Artifacts.s3({ - path: 'some/path', - name: 'some_name', - bucket, - }), - timeout: cdk.Duration.minutes(123), - }); - - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - 'Artifacts': { - 'Path': 'some/path', - 'Name': 'some_name', - 'Type': 'S3', - }, - 'TimeoutInMinutes': 123, - })); - - test.done(); - }, - - 'secondary sources': { - 'require providing an identifier when creating a Project'(test: Test) { - const stack = new cdk.Stack(); - - test.throws(() => { - new codebuild.Project(stack, 'MyProject', { - buildSpec: codebuild.BuildSpec.fromObject({ - version: '0.2', - }), - secondarySources: [ - codebuild.Source.s3({ - bucket: new s3.Bucket(stack, 'MyBucket'), - path: 'path', - }), - ], - }); - }, /identifier/); - - test.done(); - }, - - 'are not allowed for a Project with CodePipeline as Source'(test: Test) { - const stack = new cdk.Stack(); - const project = new codebuild.PipelineProject(stack, 'MyProject'); - - project.addSecondarySource(codebuild.Source.s3({ - bucket: new s3.Bucket(stack, 'MyBucket'), - path: 'some/path', - identifier: 'id', - })); - - test.throws(() => { - expect(stack); - }, /secondary sources/); - - test.done(); - }, - - 'added with an identifer after the Project has been created are rendered in the template'(test: Test) { - const stack = new cdk.Stack(); - const bucket = new s3.Bucket(stack, 'MyBucket'); - const project = new codebuild.Project(stack, 'MyProject', { - source: codebuild.Source.s3({ - bucket, - path: 'some/path', - }), - }); - - project.addSecondarySource(codebuild.Source.s3({ - bucket, - path: 'another/path', - identifier: 'source1', - })); - - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - 'SecondarySources': [ - { - 'SourceIdentifier': 'source1', - 'Type': 'S3', - }, - ], - })); - - test.done(); - }, - }, - - 'secondary source versions': { - 'allow secondary source versions'(test: Test) { - const stack = new cdk.Stack(); - const bucket = new s3.Bucket(stack, 'MyBucket'); - const project = new codebuild.Project(stack, 'MyProject', { - source: codebuild.Source.s3({ - bucket, - path: 'some/path', - }), - }); - - project.addSecondarySource(codebuild.Source.s3({ - bucket, - path: 'another/path', - identifier: 'source1', - version: 'someversion', - })); - - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - 'SecondarySources': [ - { - 'SourceIdentifier': 'source1', - 'Type': 'S3', - }, - ], - 'SecondarySourceVersions': [ - { - 'SourceIdentifier': 'source1', - 'SourceVersion': 'someversion', - }, - ], - })); - - test.done(); - }, - - 'allow not to specify secondary source versions'(test: Test) { - const stack = new cdk.Stack(); - const bucket = new s3.Bucket(stack, 'MyBucket'); - const project = new codebuild.Project(stack, 'MyProject', { - source: codebuild.Source.s3({ - bucket, - path: 'some/path', - }), - }); - - project.addSecondarySource(codebuild.Source.s3({ - bucket, - path: 'another/path', - identifier: 'source1', - })); - - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - 'SecondarySources': [ - { - 'SourceIdentifier': 'source1', - 'Type': 'S3', - }, - ], - })); - - test.done(); - }, - }, - - 'fileSystemLocations': { - 'create fileSystemLocation and validate attributes'(test: Test) { - const stack = new cdk.Stack(); - new codebuild.Project(stack, 'MyProject', { - buildSpec: codebuild.BuildSpec.fromObject({ - version: '0.2', - }), - fileSystemLocations: [codebuild.FileSystemLocation.efs({ - identifier: 'myidentifier2', - location: 'myclodation.mydnsroot.com:/loc', - mountPoint: '/media', - mountOptions: 'opts', - })], - }); - - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - 'FileSystemLocations': [ - { - 'Identifier': 'myidentifier2', - 'MountPoint': '/media', - 'MountOptions': 'opts', - 'Location': 'myclodation.mydnsroot.com:/loc', - 'Type': 'EFS', - }, - ], - })); - - test.done(); - }, - 'Multiple fileSystemLocation created'(test: Test) { - const stack = new cdk.Stack(); - const project = new codebuild.Project(stack, 'MyProject', { - buildSpec: codebuild.BuildSpec.fromObject({ - version: '0.2', - }), - }); - project.addFileSystemLocation(codebuild.FileSystemLocation.efs({ - identifier: 'myidentifier3', - location: 'myclodation.mydnsroot.com:/loc', - mountPoint: '/media', - mountOptions: 'opts', - })); - - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - 'FileSystemLocations': [ - { - 'Identifier': 'myidentifier3', - 'MountPoint': '/media', - 'MountOptions': 'opts', - 'Location': 'myclodation.mydnsroot.com:/loc', - 'Type': 'EFS', - }, - ], - })); - - test.done(); - }, - }, - - 'secondary artifacts': { - 'require providing an identifier when creating a Project'(test: Test) { - const stack = new cdk.Stack(); - - test.throws(() => { - new codebuild.Project(stack, 'MyProject', { - buildSpec: codebuild.BuildSpec.fromObject({ - version: '0.2', - }), - secondaryArtifacts: [ - codebuild.Artifacts.s3({ - bucket: new s3.Bucket(stack, 'MyBucket'), - path: 'some/path', - name: 'name', - }), - ], - }); - }, /identifier/); - - test.done(); - }, - - 'are not allowed for a Project with CodePipeline as Source'(test: Test) { - const stack = new cdk.Stack(); - const project = new codebuild.PipelineProject(stack, 'MyProject'); - - project.addSecondaryArtifact(codebuild.Artifacts.s3({ - bucket: new s3.Bucket(stack, 'MyBucket'), - path: 'some/path', - name: 'name', - identifier: 'id', - })); - - test.throws(() => { - expect(stack); - }, /secondary artifacts/); - - test.done(); - }, - - 'added with an identifier after the Project has been created are rendered in the template'(test: Test) { - const stack = new cdk.Stack(); - const bucket = new s3.Bucket(stack, 'MyBucket'); - const project = new codebuild.Project(stack, 'MyProject', { - source: codebuild.Source.s3({ - bucket, - path: 'some/path', - }), - }); - - project.addSecondaryArtifact(codebuild.Artifacts.s3({ - bucket, - path: 'another/path', - name: 'name', - identifier: 'artifact1', - })); - - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - 'SecondaryArtifacts': [ - { - 'ArtifactIdentifier': 'artifact1', - 'Type': 'S3', - }, - ], - })); - - test.done(); - }, - - 'disabledEncryption is set'(test: Test) { - const stack = new cdk.Stack(); - const bucket = new s3.Bucket(stack, 'MyBucket'); - const project = new codebuild.Project(stack, 'MyProject', { - source: codebuild.Source.s3({ - bucket, - path: 'some/path', - }), - }); - - project.addSecondaryArtifact(codebuild.Artifacts.s3({ - bucket, - path: 'another/path', - name: 'name', - identifier: 'artifact1', - encryption: false, - })); - - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - 'SecondaryArtifacts': [ - { - 'ArtifactIdentifier': 'artifact1', - 'EncryptionDisabled': true, - }, - ], - })); - - test.done(); - }, - }, - - 'artifacts': { - 'CodePipeline': { - 'both source and artifacs are set to CodePipeline'(test: Test) { - const stack = new cdk.Stack(); - - new codebuild.PipelineProject(stack, 'MyProject'); - - expect(stack).to(haveResource('AWS::CodeBuild::Project', { - 'Source': { - 'Type': 'CODEPIPELINE', - }, - 'Artifacts': { - 'Type': 'CODEPIPELINE', - }, - 'ServiceRole': { - 'Fn::GetAtt': [ - 'MyProjectRole9BBE5233', - 'Arn', - ], - }, - 'Environment': { - 'Type': 'LINUX_CONTAINER', - 'PrivilegedMode': false, - 'Image': 'aws/codebuild/standard:1.0', - 'ImagePullCredentialsType': 'CODEBUILD', - 'ComputeType': 'BUILD_GENERAL1_SMALL', - }, - })); - - test.done(); - }, - }, - 'S3': { - 'name is not set so use buildspec'(test: Test) { - const stack = new cdk.Stack(); - const bucket = new s3.Bucket(stack, 'MyBucket'); - new codebuild.Project(stack, 'MyProject', { - source: codebuild.Source.s3({ - bucket, - path: 'some/path', - }), - artifacts: codebuild.Artifacts.s3({ - bucket, - path: 'another/path', - identifier: 'artifact1', - }), - }); - - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - 'Artifacts': { - 'Name': ABSENT, - 'ArtifactIdentifier': 'artifact1', - 'OverrideArtifactName': true, - }, - })); - - test.done(); - }, - 'name is set so use it'(test: Test) { - const stack = new cdk.Stack(); - const bucket = new s3.Bucket(stack, 'MyBucket'); - new codebuild.Project(stack, 'MyProject', { - source: codebuild.Source.s3({ - bucket, - path: 'some/path', - }), - artifacts: codebuild.Artifacts.s3({ - bucket, - path: 'another/path', - name: 'specificname', - identifier: 'artifact1', - }), - }); - - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - 'Artifacts': { - 'ArtifactIdentifier': 'artifact1', - 'Name': 'specificname', - 'OverrideArtifactName': ABSENT, - }, - })); - - test.done(); - }, - }, - }, - - 'events'(test: Test) { - const stack = new cdk.Stack(); - const project = new codebuild.Project(stack, 'MyProject', { - source: codebuild.Source.s3({ - bucket: new s3.Bucket(stack, 'MyBucket'), - path: 'path', - }), - }); - - project.onBuildFailed('OnBuildFailed', { target: { bind: () => ({ arn: 'ARN', id: 'ID' }) } }); - project.onBuildSucceeded('OnBuildSucceeded', { target: { bind: () => ({ arn: 'ARN', id: 'ID' }) } }); - project.onPhaseChange('OnPhaseChange', { target: { bind: () => ({ arn: 'ARN', id: 'ID' }) } }); - project.onStateChange('OnStateChange', { target: { bind: () => ({ arn: 'ARN', id: 'ID' }) } }); - project.onBuildStarted('OnBuildStarted', { target: { bind: () => ({ arn: 'ARN', id: 'ID' }) } }); - - expect(stack).to(haveResource('AWS::Events::Rule', { - 'EventPattern': { - 'source': [ - 'aws.codebuild', - ], - 'detail-type': [ - 'CodeBuild Build State Change', - ], - 'detail': { - 'project-name': [ - { - 'Ref': 'MyProject39F7B0AE', - }, - ], - 'build-status': [ - 'FAILED', - ], - }, - }, - 'State': 'ENABLED', - })); - - expect(stack).to(haveResource('AWS::Events::Rule', { - 'EventPattern': { - 'source': [ - 'aws.codebuild', - ], - 'detail-type': [ - 'CodeBuild Build State Change', - ], - 'detail': { - 'project-name': [ - { - 'Ref': 'MyProject39F7B0AE', - }, - ], - 'build-status': [ - 'SUCCEEDED', - ], - }, - }, - 'State': 'ENABLED', - })); - - expect(stack).to(haveResource('AWS::Events::Rule', { - 'EventPattern': { - 'source': [ - 'aws.codebuild', - ], - 'detail-type': [ - 'CodeBuild Build Phase Change', - ], - 'detail': { - 'project-name': [ - { - 'Ref': 'MyProject39F7B0AE', - }, - ], - }, - }, - 'State': 'ENABLED', - })); - - expect(stack).to(haveResource('AWS::Events::Rule', { - 'EventPattern': { - 'source': [ - 'aws.codebuild', - ], - 'detail-type': [ - 'CodeBuild Build State Change', - ], - 'detail': { - 'project-name': [ - { - 'Ref': 'MyProject39F7B0AE', - }, - ], - }, - }, - 'State': 'ENABLED', - })); - - expect(stack).to(haveResource('AWS::Events::Rule', { - 'EventPattern': { - 'source': [ - 'aws.codebuild', - ], - 'detail-type': [ - 'CodeBuild Build State Change', - ], - 'detail': { - 'project-name': [ - { - 'Ref': 'MyProject39F7B0AE', - }, - ], - 'build-status': [ - 'IN_PROGRESS', - ], - }, - }, - 'State': 'ENABLED', - })); - - test.done(); - }, - - 'environment variables can be overridden at the project level'(test: Test) { - const stack = new cdk.Stack(); - - new codebuild.PipelineProject(stack, 'Project', { - environment: { - environmentVariables: { - FOO: { value: '1234' }, - BAR: { value: `111${cdk.Token.asString({ twotwotwo: '222' })}`, type: codebuild.BuildEnvironmentVariableType.PARAMETER_STORE }, - }, - }, - environmentVariables: { - GOO: { value: 'ABC' }, - FOO: { value: 'OVERRIDE!' }, - }, - }); - - expect(stack).to(haveResource('AWS::CodeBuild::Project', { - 'Source': { - 'Type': 'CODEPIPELINE', - }, - 'Artifacts': { - 'Type': 'CODEPIPELINE', - }, - 'ServiceRole': { - 'Fn::GetAtt': [ - 'ProjectRole4CCB274E', - 'Arn', - ], - }, - 'Environment': { - 'Type': 'LINUX_CONTAINER', - 'EnvironmentVariables': [ - { - 'Type': 'PLAINTEXT', - 'Value': 'OVERRIDE!', - 'Name': 'FOO', - }, - { - 'Type': 'PARAMETER_STORE', - 'Value': { - 'Fn::Join': [ - '', - [ - '111', - { twotwotwo: '222' }, - ], - ], - }, - 'Name': 'BAR', - }, - { - 'Type': 'PLAINTEXT', - 'Value': 'ABC', - 'Name': 'GOO', - }, - ], - 'PrivilegedMode': false, - 'Image': 'aws/codebuild/standard:1.0', - 'ImagePullCredentialsType': 'CODEBUILD', - 'ComputeType': 'BUILD_GENERAL1_SMALL', - }, - })); - - test.done(); - }, - - '.metricXxx() methods can be used to obtain Metrics for CodeBuild projects'(test: Test) { - const stack = new cdk.Stack(); - - const project = new codebuild.Project(stack, 'MyBuildProject', { - source: codebuild.Source.s3({ - bucket: new s3.Bucket(stack, 'MyBucket'), - path: 'path', - }), - }); - - const metricBuilds = project.metricBuilds(); - test.same(metricBuilds.dimensions!.ProjectName, project.projectName); - test.deepEqual(metricBuilds.namespace, 'AWS/CodeBuild'); - test.deepEqual(metricBuilds.statistic, 'Sum', 'default stat is SUM'); - test.deepEqual(metricBuilds.metricName, 'Builds'); - - const metricDuration = project.metricDuration({ label: 'hello' }); - - test.deepEqual(metricDuration.metricName, 'Duration'); - test.deepEqual(metricDuration.label, 'hello'); - - test.deepEqual(project.metricFailedBuilds().metricName, 'FailedBuilds'); - test.deepEqual(project.metricSucceededBuilds().metricName, 'SucceededBuilds'); - - test.done(); - }, - - 'using ComputeType.Small with a Windows image fails validation'(test: Test) { - const stack = new cdk.Stack(); - const invalidEnvironment: codebuild.BuildEnvironment = { - buildImage: codebuild.WindowsBuildImage.WINDOWS_BASE_2_0, - computeType: codebuild.ComputeType.SMALL, - }; - - test.throws(() => { - new codebuild.Project(stack, 'MyProject', { - source: codebuild.Source.s3({ - bucket: new s3.Bucket(stack, 'MyBucket'), - path: 'path', - }), - environment: invalidEnvironment, - }); - }, /Windows images do not support the Small ComputeType/); - - test.done(); - }, - - 'fromCodebuildImage'(test: Test) { - const stack = new cdk.Stack(); - new codebuild.PipelineProject(stack, 'Project', { - environment: { - buildImage: codebuild.LinuxBuildImage.fromCodeBuildImageId('aws/codebuild/standard:4.0'), - }, - }); - - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - 'Environment': { - 'Image': 'aws/codebuild/standard:4.0', - }, - })); - - test.done(); - }, - - 'Windows2019 image': { - 'WIN_SERVER_CORE_2016_BASE': { - 'has type WINDOWS_SERVER_2019_CONTAINER and default ComputeType MEDIUM'(test: Test) { - const stack = new cdk.Stack(); - new codebuild.PipelineProject(stack, 'Project', { - environment: { - buildImage: codebuild.WindowsBuildImage.WIN_SERVER_CORE_2019_BASE, - }, - }); - - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - 'Environment': { - 'Type': 'WINDOWS_SERVER_2019_CONTAINER', - 'ComputeType': 'BUILD_GENERAL1_MEDIUM', - }, - })); - - test.done(); - }, - }, - }, - - 'ARM image': { - 'AMAZON_LINUX_2_ARM': { - 'has type ARM_CONTAINER and default ComputeType LARGE'(test: Test) { - const stack = new cdk.Stack(); - new codebuild.PipelineProject(stack, 'Project', { - environment: { - buildImage: codebuild.LinuxBuildImage.AMAZON_LINUX_2_ARM, - }, - }); - - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - 'Environment': { - 'Type': 'ARM_CONTAINER', - 'ComputeType': 'BUILD_GENERAL1_LARGE', - }, - })); - - test.done(); - }, - - 'cannot be used in conjunction with ComputeType SMALL'(test: Test) { - const stack = new cdk.Stack(); - - test.throws(() => { - new codebuild.PipelineProject(stack, 'Project', { - environment: { - buildImage: codebuild.LinuxBuildImage.AMAZON_LINUX_2_ARM, - computeType: codebuild.ComputeType.SMALL, - }, - }); - }, /ARM images only support ComputeType 'BUILD_GENERAL1_LARGE' - 'BUILD_GENERAL1_SMALL' was given/); - - test.done(); - }, - - 'cannot be used in conjunction with ComputeType MEDIUM'(test: Test) { - const stack = new cdk.Stack(); - - test.throws(() => { - new codebuild.PipelineProject(stack, 'Project', { - environment: { - buildImage: codebuild.LinuxBuildImage.AMAZON_LINUX_2_ARM, - computeType: codebuild.ComputeType.MEDIUM, - }, - }); - }, /ARM images only support ComputeType 'BUILD_GENERAL1_LARGE' - 'BUILD_GENERAL1_MEDIUM' was given/); - - test.done(); - }, - - 'cannot be used in conjunction with ComputeType X2_LARGE'(test: Test) { - const stack = new cdk.Stack(); - - test.throws(() => { - new codebuild.PipelineProject(stack, 'Project', { - environment: { - buildImage: codebuild.LinuxBuildImage.AMAZON_LINUX_2_ARM, - computeType: codebuild.ComputeType.X2_LARGE, - }, - }); - }, /ARM images only support ComputeType 'BUILD_GENERAL1_LARGE' - 'BUILD_GENERAL1_2XLARGE' was given/); - - test.done(); - }, - }, - }, - - 'badge support test'(test: Test) { - const stack = new cdk.Stack(); - - interface BadgeValidationTestCase { - source: codebuild.Source, - allowsBadge: boolean - } - - const repo = new codecommit.Repository(stack, 'MyRepo', { - repositoryName: 'hello-cdk', - }); - const bucket = new s3.Bucket(stack, 'MyBucket'); - - const cases: BadgeValidationTestCase[] = [ - { source: new NoSource(), allowsBadge: false }, - { source: new CodePipelineSource(), allowsBadge: false }, - { source: codebuild.Source.codeCommit({ repository: repo }), allowsBadge: true }, - { source: codebuild.Source.s3({ bucket, path: 'path/to/source.zip' }), allowsBadge: false }, - { source: codebuild.Source.gitHub({ owner: 'awslabs', repo: 'aws-cdk' }), allowsBadge: true }, - { source: codebuild.Source.gitHubEnterprise({ httpsCloneUrl: 'url' }), allowsBadge: true }, - { source: codebuild.Source.bitBucket({ owner: 'awslabs', repo: 'aws-cdk' }), allowsBadge: true }, - ]; - - cases.forEach(testCase => { - const source = testCase.source; - const validationBlock = () => { new codebuild.Project(stack, `MyProject-${source.type}`, { source, badge: true }); }; - if (testCase.allowsBadge) { - test.doesNotThrow(validationBlock); - } else { - test.throws(validationBlock, /Badge is not supported for source type /); - } - }); - - test.done(); - }, - - 'webhook Filters': { - 'a Group cannot be created with an empty set of event actions'(test: Test) { - test.throws(() => { - codebuild.FilterGroup.inEventOf(); - }, /A filter group must contain at least one event action/); - - test.done(); - }, - - 'cannot have base ref conditions if the Group contains the PUSH action'(test: Test) { - const filterGroup = codebuild.FilterGroup.inEventOf(codebuild.EventAction.PULL_REQUEST_CREATED, - codebuild.EventAction.PUSH); - - test.throws(() => { - filterGroup.andBaseRefIs('.*'); - }, /A base reference condition cannot be added if a Group contains a PUSH event action/); - - test.done(); - }, - - 'cannot be used when webhook is false'(test: Test) { - const stack = new cdk.Stack(); - - test.throws(() => { - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.bitBucket({ - owner: 'owner', - repo: 'repo', - webhook: false, - webhookFilters: [ - codebuild.FilterGroup.inEventOf(codebuild.EventAction.PUSH), - ], - }), - }); - }, /`webhookFilters` cannot be used when `webhook` is `false`/); - - test.done(); - }, - - 'can have FILE_PATH filters if the Group contains PUSH and PR_CREATED events'(test: Test) { - codebuild.FilterGroup.inEventOf( - codebuild.EventAction.PULL_REQUEST_CREATED, - codebuild.EventAction.PUSH) - .andFilePathIsNot('.*\\.java'); - - test.done(); - }, - - 'BitBucket sources do not support the PULL_REQUEST_REOPENED event action'(test: Test) { - const stack = new cdk.Stack(); - - test.throws(() => { - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.bitBucket({ - owner: 'owner', - repo: 'repo', - webhookFilters: [ - codebuild.FilterGroup.inEventOf(codebuild.EventAction.PULL_REQUEST_REOPENED), - ], - }), - }); - }, /BitBucket sources do not support the PULL_REQUEST_REOPENED webhook event action/); - - test.done(); - }, - - 'BitBucket sources support file path conditions'(test: Test) { - const stack = new cdk.Stack(); - const filterGroup = codebuild.FilterGroup.inEventOf(codebuild.EventAction.PUSH).andFilePathIs('.*'); - - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.bitBucket({ - owner: 'owner', - repo: 'repo', - webhookFilters: [filterGroup], - }), - }); - - test.done(); - }, - - 'GitHub Enterprise Server sources do not support FILE_PATH filters on PR events'(test: Test) { - const stack = new cdk.Stack(); - const pullFilterGroup = codebuild.FilterGroup.inEventOf( - codebuild.EventAction.PULL_REQUEST_CREATED, - codebuild.EventAction.PULL_REQUEST_MERGED, - codebuild.EventAction.PULL_REQUEST_REOPENED, - codebuild.EventAction.PULL_REQUEST_UPDATED, - ); - - test.throws(() => { - new codebuild.Project(stack, 'MyFilePathProject', { - source: codebuild.Source.gitHubEnterprise({ - httpsCloneUrl: 'https://github.testcompany.com/testowner/testrepo', - webhookFilters: [ - pullFilterGroup.andFilePathIs('ReadMe.md'), - ], - }), - }); - }, /FILE_PATH filters cannot be used with GitHub Enterprise Server pull request events/); - test.done(); - }, - - 'COMMIT_MESSAGE Filter': { - 'GitHub Enterprise Server sources do not support COMMIT_MESSAGE filters on PR events'(test: Test) { - const stack = new cdk.Stack(); - const pullFilterGroup = codebuild.FilterGroup.inEventOf( - codebuild.EventAction.PULL_REQUEST_CREATED, - codebuild.EventAction.PULL_REQUEST_MERGED, - codebuild.EventAction.PULL_REQUEST_REOPENED, - codebuild.EventAction.PULL_REQUEST_UPDATED, - ); - - test.throws(() => { - new codebuild.Project(stack, 'MyProject', { - source: codebuild.Source.gitHubEnterprise({ - httpsCloneUrl: 'https://github.testcompany.com/testowner/testrepo', - webhookFilters: [ - pullFilterGroup.andCommitMessageIs('the commit message'), - ], - }), - }); - }, /COMMIT_MESSAGE filters cannot be used with GitHub Enterprise Server pull request events/); - test.done(); - }, - 'GitHub Enterprise Server sources support COMMIT_MESSAGE filters on PUSH events'(test: Test) { - const stack = new cdk.Stack(); - const pushFilterGroup = codebuild.FilterGroup.inEventOf(codebuild.EventAction.PUSH); - - test.doesNotThrow(() => { - new codebuild.Project(stack, 'MyProject', { - source: codebuild.Source.gitHubEnterprise({ - httpsCloneUrl: 'https://github.testcompany.com/testowner/testrepo', - webhookFilters: [ - pushFilterGroup.andCommitMessageIs('the commit message'), - ], - }), - }); - }); - test.done(); - }, - 'BitBucket and GitHub sources support a COMMIT_MESSAGE filter'(test: Test) { - const stack = new cdk.Stack(); - const filterGroup = codebuild - .FilterGroup - .inEventOf(codebuild.EventAction.PUSH, codebuild.EventAction.PULL_REQUEST_CREATED) - .andCommitMessageIs('the commit message'); - - test.doesNotThrow(() => { - new codebuild.Project(stack, 'BitBucket Project', { - source: codebuild.Source.bitBucket({ - owner: 'owner', - repo: 'repo', - webhookFilters: [filterGroup], - }), - }); - new codebuild.Project(stack, 'GitHub Project', { - source: codebuild.Source.gitHub({ - owner: 'owner', - repo: 'repo', - webhookFilters: [filterGroup], - }), - }); - }); - test.done(); - }, - }, - }, - - 'enableBatchBuilds()'(test: Test) { - const stack = new cdk.Stack(); - - const project = new codebuild.Project(stack, 'Project', { - source: codebuild.Source.gitHub({ - owner: 'testowner', - repo: 'testrepo', - }), - }); - - const returnVal = project.enableBatchBuilds(); - if (!returnVal?.role) { - throw new Error('Expecting return value with role'); - } - - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - BuildBatchConfig: { - ServiceRole: { - 'Fn::GetAtt': [ - 'ProjectBatchServiceRoleF97A1CFB', - 'Arn', - ], - }, - }, - })); - - expect(stack).to(haveResourceLike('AWS::IAM::Role', { - AssumeRolePolicyDocument: { - Statement: [ - { - Action: 'sts:AssumeRole', - Effect: 'Allow', - Principal: { - Service: 'codebuild.amazonaws.com', - }, - }, - ], - Version: '2012-10-17', - }, - })); - - expect(stack).to(haveResourceLike('AWS::IAM::Policy', { - PolicyDocument: { - Statement: [ - { - Action: [ - 'codebuild:StartBuild', - 'codebuild:StopBuild', - 'codebuild:RetryBuild', - ], - Effect: 'Allow', - Resource: { - 'Fn::GetAtt': [ - 'ProjectC78D97AD', - 'Arn', - ], - }, - }, - ], - Version: '2012-10-17', - }, - })); - - test.done(); - }, -}; diff --git a/packages/@aws-cdk/aws-codebuild/test/test.linux-gpu-build-image.ts b/packages/@aws-cdk/aws-codebuild/test/test.linux-gpu-build-image.ts deleted file mode 100644 index 60d3b17ca3043..0000000000000 --- a/packages/@aws-cdk/aws-codebuild/test/test.linux-gpu-build-image.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { arrayWith, expect, haveResourceLike, objectLike } from '@aws-cdk/assert-internal'; -import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; -import * as codebuild from '../lib'; - -export = { - 'Linux GPU build image': { - 'AWS Deep Learning Container images': { - 'allows passing the account that the repository of the image is hosted in'(test: Test) { - const stack = new cdk.Stack(); - - new codebuild.Project(stack, 'Project', { - buildSpec: codebuild.BuildSpec.fromObject({ - version: '0.2', - phases: { - build: { commands: ['ls'] }, - }, - }), - environment: { - buildImage: codebuild.LinuxGpuBuildImage.awsDeepLearningContainersImage( - 'my-repo', 'my-tag', '123456789012'), - }, - }); - - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - Environment: { - ComputeType: 'BUILD_GENERAL1_LARGE', - Image: { - 'Fn::Join': ['', [ - '123456789012.dkr.ecr.', - { Ref: 'AWS::Region' }, - '.', - { Ref: 'AWS::URLSuffix' }, - '/my-repo:my-tag', - ]], - }, - }, - })); - - expect(stack).to(haveResourceLike('AWS::IAM::Policy', { - PolicyDocument: { - Statement: arrayWith(objectLike({ - Action: [ - 'ecr:BatchCheckLayerAvailability', - 'ecr:GetDownloadUrlForLayer', - 'ecr:BatchGetImage', - ], - Resource: { - 'Fn::Join': ['', [ - 'arn:', - { Ref: 'AWS::Partition' }, - ':ecr:', - { Ref: 'AWS::Region' }, - ':123456789012:repository/my-repo', - ]], - }, - })), - }, - })); - - test.done(); - }, - }, - }, -}; diff --git a/packages/@aws-cdk/aws-codebuild/test/test.notification-rule.ts b/packages/@aws-cdk/aws-codebuild/test/test.notification-rule.ts deleted file mode 100644 index 4ebb4eed3578e..0000000000000 --- a/packages/@aws-cdk/aws-codebuild/test/test.notification-rule.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { expect, haveResource } from '@aws-cdk/assert-internal'; -import * as sns from '@aws-cdk/aws-sns'; -import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; -import * as codebuild from '../lib'; - -export = { - 'notifications rule'(test: Test) { - const stack = new cdk.Stack(); - const project = new codebuild.Project(stack, 'MyCodebuildProject', { - buildSpec: codebuild.BuildSpec.fromObject({ - version: '0.2', - phases: { - build: { - commands: [ - 'echo "Hello, CodeBuild!"', - ], - }, - }, - }), - }); - - const target = new sns.Topic(stack, 'MyTopic'); - - project.notifyOnBuildSucceeded('NotifyOnBuildSucceeded', target); - - project.notifyOnBuildFailed('NotifyOnBuildFailed', target); - - expect(stack).to(haveResource('AWS::CodeStarNotifications::NotificationRule', { - Name: 'MyCodebuildProjectNotifyOnBuildSucceeded77719592', - DetailType: 'FULL', - EventTypeIds: [ - 'codebuild-project-build-state-succeeded', - ], - Resource: { - 'Fn::GetAtt': [ - 'MyCodebuildProjectB0479580', - 'Arn', - ], - }, - Targets: [ - { - TargetAddress: { - Ref: 'MyTopic86869434', - }, - TargetType: 'SNS', - }, - ], - })); - - expect(stack).to(haveResource('AWS::CodeStarNotifications::NotificationRule', { - Name: 'MyCodebuildProjectNotifyOnBuildFailedF680E310', - DetailType: 'FULL', - EventTypeIds: [ - 'codebuild-project-build-state-failed', - ], - Resource: { - 'Fn::GetAtt': [ - 'MyCodebuildProjectB0479580', - 'Arn', - ], - }, - Targets: [ - { - TargetAddress: { - Ref: 'MyTopic86869434', - }, - TargetType: 'SNS', - }, - ], - })); - - test.done(); - }, -}; diff --git a/packages/@aws-cdk/aws-codebuild/test/test.project.ts b/packages/@aws-cdk/aws-codebuild/test/test.project.ts deleted file mode 100644 index 2b778c9d843cb..0000000000000 --- a/packages/@aws-cdk/aws-codebuild/test/test.project.ts +++ /dev/null @@ -1,1893 +0,0 @@ -import { countResources, expect, haveResource, haveResourceLike, objectLike, not, ResourcePart, arrayWith } from '@aws-cdk/assert-internal'; -import * as ec2 from '@aws-cdk/aws-ec2'; -import * as iam from '@aws-cdk/aws-iam'; -import * as logs from '@aws-cdk/aws-logs'; -import * as s3 from '@aws-cdk/aws-s3'; -import * as secretsmanager from '@aws-cdk/aws-secretsmanager'; -import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; -import * as codebuild from '../lib'; - -/* eslint-disable quote-props */ - -export = { - 'can use filename as buildspec'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.s3({ - bucket: new s3.Bucket(stack, 'Bucket'), - path: 'path', - }), - buildSpec: codebuild.BuildSpec.fromSourceFilename('hello.yml'), - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - Source: { - BuildSpec: 'hello.yml', - }, - })); - - test.done(); - }, - - 'can use buildspec literal'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new codebuild.Project(stack, 'Project', { - buildSpec: codebuild.BuildSpec.fromObject({ phases: ['say hi'] }), - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - Source: { - BuildSpec: '{\n "phases": [\n "say hi"\n ]\n}', - }, - })); - - test.done(); - }, - - 'can use yamlbuildspec literal'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new codebuild.Project(stack, 'Project', { - buildSpec: codebuild.BuildSpec.fromObjectToYaml({ - text: 'text', - decimal: 10, - list: ['say hi'], - obj: { - text: 'text', - decimal: 10, - list: ['say hi'], - }, - }), - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - Source: { - BuildSpec: 'text: text\ndecimal: 10\nlist:\n - say hi\nobj:\n text: text\n decimal: 10\n list:\n - say hi\n', - }, - })); - - test.done(); - }, - - 'must supply buildspec when using nosource'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - test.throws(() => { - new codebuild.Project(stack, 'Project', { - }); - }, /you need to provide a concrete buildSpec/); - - test.done(); - }, - - 'must supply literal buildspec when using nosource'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - test.throws(() => { - new codebuild.Project(stack, 'Project', { - buildSpec: codebuild.BuildSpec.fromSourceFilename('bla.yml'), - }); - }, /you need to provide a concrete buildSpec/); - - test.done(); - }, - - 'GitHub source': { - 'has reportBuildStatus on by default'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.gitHub({ - owner: 'testowner', - repo: 'testrepo', - cloneDepth: 3, - }), - }); - - // THEN - expect(stack).to(haveResource('AWS::CodeBuild::Project', { - Source: { - Type: 'GITHUB', - Location: 'https://github.com/testowner/testrepo.git', - ReportBuildStatus: true, - GitCloneDepth: 3, - }, - })); - - test.done(); - }, - - 'can set a branch as the SourceVersion'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.gitHub({ - owner: 'testowner', - repo: 'testrepo', - branchOrRef: 'testbranch', - }), - }); - - // THEN - expect(stack).to(haveResource('AWS::CodeBuild::Project', { - SourceVersion: 'testbranch', - })); - - test.done(); - }, - - 'can explicitly set reportBuildStatus to false'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.gitHub({ - owner: 'testowner', - repo: 'testrepo', - reportBuildStatus: false, - }), - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - Source: { - ReportBuildStatus: false, - }, - })); - - test.done(); - }, - - 'can explicitly set webhook to true'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.gitHub({ - owner: 'testowner', - repo: 'testrepo', - webhook: true, - }), - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - Triggers: { - Webhook: true, - }, - })); - - test.done(); - }, - - 'can be added to a CodePipeline'(test: Test) { - const stack = new cdk.Stack(); - const project = new codebuild.Project(stack, 'Project', { - source: codebuild.Source.gitHub({ - owner: 'testowner', - repo: 'testrepo', - }), - }); - - project.bindToCodePipeline(project, { - artifactBucket: new s3.Bucket(stack, 'Bucket'), - }); // no exception - - test.done(); - }, - - 'can provide credentials to use with the source'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new codebuild.GitHubSourceCredentials(stack, 'GitHubSourceCredentials', { - accessToken: cdk.SecretValue.plainText('my-access-token'), - }); - - // THEN - expect(stack).to(haveResource('AWS::CodeBuild::SourceCredential', { - 'ServerType': 'GITHUB', - 'AuthType': 'PERSONAL_ACCESS_TOKEN', - 'Token': 'my-access-token', - })); - - test.done(); - }, - }, - - 'GitHub Enterprise source': { - 'can use branchOrRef to set the source version'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.gitHubEnterprise({ - httpsCloneUrl: 'https://mygithub-enterprise.com/myuser/myrepo', - branchOrRef: 'testbranch', - }), - }); - - // THEN - expect(stack).to(haveResource('AWS::CodeBuild::Project', { - SourceVersion: 'testbranch', - })); - - test.done(); - }, - - 'can provide credentials to use with the source'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new codebuild.GitHubEnterpriseSourceCredentials(stack, 'GitHubEnterpriseSourceCredentials', { - accessToken: cdk.SecretValue.plainText('my-access-token'), - }); - - // THEN - expect(stack).to(haveResource('AWS::CodeBuild::SourceCredential', { - 'ServerType': 'GITHUB_ENTERPRISE', - 'AuthType': 'PERSONAL_ACCESS_TOKEN', - 'Token': 'my-access-token', - })); - - test.done(); - }, - }, - - 'BitBucket source': { - 'can use branchOrRef to set the source version'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.bitBucket({ - owner: 'testowner', - repo: 'testrepo', - branchOrRef: 'testbranch', - }), - }); - - // THEN - expect(stack).to(haveResource('AWS::CodeBuild::Project', { - SourceVersion: 'testbranch', - })); - - test.done(); - }, - - 'can provide credentials to use with the source'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new codebuild.BitBucketSourceCredentials(stack, 'BitBucketSourceCredentials', { - username: cdk.SecretValue.plainText('my-username'), - password: cdk.SecretValue.plainText('password'), - }); - - // THEN - expect(stack).to(haveResource('AWS::CodeBuild::SourceCredential', { - 'ServerType': 'BITBUCKET', - 'AuthType': 'BASIC_AUTH', - 'Username': 'my-username', - 'Token': 'password', - })); - - test.done(); - }, - }, - - 'project with s3 cache bucket'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.s3({ - bucket: new s3.Bucket(stack, 'SourceBucket'), - path: 'path', - }), - cache: codebuild.Cache.bucket(new s3.Bucket(stack, 'Bucket'), { - prefix: 'cache-prefix', - }), - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - Cache: { - Type: 'S3', - Location: { - 'Fn::Join': [ - '/', - [ - { - 'Ref': 'Bucket83908E77', - }, - 'cache-prefix', - ], - ], - }, - }, - })); - - test.done(); - }, - - 's3 codebuild project with sourceVersion'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.s3({ - bucket: new s3.Bucket(stack, 'Bucket'), - path: 'path', - version: 's3version', - }), - cache: codebuild.Cache.local(codebuild.LocalCacheMode.CUSTOM, codebuild.LocalCacheMode.DOCKER_LAYER, - codebuild.LocalCacheMode.SOURCE), - }); - - // THEN - expect(stack).to(haveResource('AWS::CodeBuild::Project', { - SourceVersion: 's3version', - })); - - test.done(); - }, - - 'project with local cache modes'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.s3({ - bucket: new s3.Bucket(stack, 'Bucket'), - path: 'path', - }), - cache: codebuild.Cache.local(codebuild.LocalCacheMode.CUSTOM, codebuild.LocalCacheMode.DOCKER_LAYER, - codebuild.LocalCacheMode.SOURCE), - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - Cache: { - Type: 'LOCAL', - Modes: [ - 'LOCAL_CUSTOM_CACHE', - 'LOCAL_DOCKER_LAYER_CACHE', - 'LOCAL_SOURCE_CACHE', - ], - }, - })); - - test.done(); - }, - - 'project by default has no cache modes'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.s3({ - bucket: new s3.Bucket(stack, 'Bucket'), - path: 'path', - }), - }); - - // THEN - expect(stack).to(not(haveResourceLike('AWS::CodeBuild::Project', { - Cache: {}, - }))); - - test.done(); - }, - - 'if a role is shared between projects in a VPC, the VPC Policy is only attached once'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'Vpc'); - const role = new iam.Role(stack, 'Role', { - assumedBy: new iam.ServicePrincipal('codebuild.amazonaws.com'), - }); - const source = codebuild.Source.gitHubEnterprise({ - httpsCloneUrl: 'https://mygithub-enterprise.com/myuser/myrepo', - }); - - // WHEN - new codebuild.Project(stack, 'Project1', { source, role, vpc, projectName: 'P1' }); - new codebuild.Project(stack, 'Project2', { source, role, vpc, projectName: 'P2' }); - - // THEN - // - 1 is for `ec2:CreateNetworkInterfacePermission`, deduplicated as they're part of a single policy - // - 1 is for `ec2:CreateNetworkInterface`, this is the separate Policy we're deduplicating - // We would have found 3 if the deduplication didn't work. - expect(stack).to(countResources('AWS::IAM::Policy', 2)); - - // THEN - both Projects have a DependsOn on the same policy - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - Properties: { Name: 'P1' }, - DependsOn: ['Project1PolicyDocumentF9761562'], - }, ResourcePart.CompleteDefinition)); - - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - Properties: { Name: 'P1' }, - DependsOn: ['Project1PolicyDocumentF9761562'], - }, ResourcePart.CompleteDefinition)); - - test.done(); - }, - - 'can use an imported Role for a Project within a VPC'(test: Test) { - const stack = new cdk.Stack(); - - const importedRole = iam.Role.fromRoleArn(stack, 'Role', 'arn:aws:iam::1234567890:role/service-role/codebuild-bruiser-service-role'); - const vpc = new ec2.Vpc(stack, 'Vpc'); - - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.gitHubEnterprise({ - httpsCloneUrl: 'https://mygithub-enterprise.com/myuser/myrepo', - }), - role: importedRole, - vpc, - }); - - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - // no need to do any assertions - })); - - test.done(); - }, - - 'can use an imported Role with mutable = false for a Project within a VPC'(test: Test) { - const stack = new cdk.Stack(); - - const importedRole = iam.Role.fromRoleArn(stack, 'Role', - 'arn:aws:iam::1234567890:role/service-role/codebuild-bruiser-service-role', { - mutable: false, - }); - const vpc = new ec2.Vpc(stack, 'Vpc'); - - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.gitHubEnterprise({ - httpsCloneUrl: 'https://mygithub-enterprise.com/myuser/myrepo', - }), - role: importedRole, - vpc, - }); - - expect(stack).to(countResources('AWS::IAM::Policy', 0)); - - // Check that the CodeBuild project does not have a DependsOn - expect(stack).to(haveResource('AWS::CodeBuild::Project', (res: any) => { - if (res.DependsOn && res.DependsOn.length > 0) { - throw new Error(`CodeBuild project should have no DependsOn, but got: ${JSON.stringify(res, undefined, 2)}`); - } - return true; - }, ResourcePart.CompleteDefinition)); - - test.done(); - }, - - 'can use an ImmutableRole for a Project within a VPC'(test: Test) { - const stack = new cdk.Stack(); - - const role = new iam.Role(stack, 'Role', { - assumedBy: new iam.ServicePrincipal('codebuild.amazonaws.com'), - }); - - const vpc = new ec2.Vpc(stack, 'Vpc'); - - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.gitHubEnterprise({ - httpsCloneUrl: 'https://mygithub-enterprise.com/myuser/myrepo', - }), - role: role.withoutPolicyUpdates(), - vpc, - }); - - expect(stack).to(countResources('AWS::IAM::Policy', 0)); - - // Check that the CodeBuild project does not have a DependsOn - expect(stack).to(haveResource('AWS::CodeBuild::Project', (res: any) => { - if (res.DependsOn && res.DependsOn.length > 0) { - throw new Error(`CodeBuild project should have no DependsOn, but got: ${JSON.stringify(res, undefined, 2)}`); - } - return true; - }, ResourcePart.CompleteDefinition)); - - test.done(); - }, - - 'metric method generates a valid CloudWatch metric'(test: Test) { - const stack = new cdk.Stack(); - - const project = new codebuild.Project(stack, 'Project', { - source: codebuild.Source.gitHubEnterprise({ - httpsCloneUrl: 'https://mygithub-enterprise.com/myuser/myrepo', - }), - }); - - const metric = project.metric('Builds'); - test.equal(metric.metricName, 'Builds'); - test.equal(metric.period.toSeconds(), cdk.Duration.minutes(5).toSeconds()); - test.equal(metric.statistic, 'Average'); - - test.done(); - }, - - 'CodeBuild test reports group': { - 'adds the appropriate permissions when reportGroup.grantWrite() is called'(test: Test) { - const stack = new cdk.Stack(); - - const reportGroup = new codebuild.ReportGroup(stack, 'ReportGroup'); - - const project = new codebuild.Project(stack, 'Project', { - buildSpec: codebuild.BuildSpec.fromObject({ - version: '0.2', - reports: { - [reportGroup.reportGroupArn]: { - files: '**/*', - }, - }, - }), - grantReportGroupPermissions: false, - }); - reportGroup.grantWrite(project); - - expect(stack).to(haveResourceLike('AWS::IAM::Policy', { - 'PolicyDocument': { - 'Statement': [ - {}, - { - 'Action': [ - 'codebuild:CreateReport', - 'codebuild:UpdateReport', - 'codebuild:BatchPutTestCases', - ], - 'Resource': { - 'Fn::GetAtt': [ - 'ReportGroup8A84C76D', - 'Arn', - ], - }, - }, - ], - }, - })); - - test.done(); - }, - }, - - 'Environment': { - 'build image - can use secret to access build image'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const secret = new secretsmanager.Secret(stack, 'Secret'); - - // WHEN - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.s3({ - bucket: new s3.Bucket(stack, 'Bucket'), - path: 'path', - }), - environment: { - buildImage: codebuild.LinuxBuildImage.fromDockerRegistry('myimage', { secretsManagerCredentials: secret }), - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - Environment: objectLike({ - RegistryCredential: { - CredentialProvider: 'SECRETS_MANAGER', - Credential: { 'Ref': 'SecretA720EF05' }, - }, - }), - })); - - test.done(); - }, - - 'build image - can use imported secret by name'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const secret = secretsmanager.Secret.fromSecretNameV2(stack, 'Secret', 'MySecretName'); - - // WHEN - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.s3({ - bucket: new s3.Bucket(stack, 'Bucket'), - path: 'path', - }), - environment: { - buildImage: codebuild.LinuxBuildImage.fromDockerRegistry('myimage', { secretsManagerCredentials: secret }), - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - Environment: objectLike({ - RegistryCredential: { - CredentialProvider: 'SECRETS_MANAGER', - Credential: 'MySecretName', - }, - }), - })); - - test.done(); - }, - - 'logs config - cloudWatch'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const logGroup = logs.LogGroup.fromLogGroupName(stack, 'LogGroup', 'MyLogGroupName'); - - // WHEN - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.s3({ - bucket: new s3.Bucket(stack, 'Bucket'), - path: 'path', - }), - logging: { - cloudWatch: { - logGroup, - prefix: '/my-logs', - }, - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - LogsConfig: objectLike({ - CloudWatchLogs: { - GroupName: 'MyLogGroupName', - Status: 'ENABLED', - StreamName: '/my-logs', - }, - }), - })); - - test.done(); - }, - - 'logs config - cloudWatch disabled'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.s3({ - bucket: new s3.Bucket(stack, 'Bucket'), - path: 'path', - }), - logging: { - cloudWatch: { - enabled: false, - }, - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - LogsConfig: objectLike({ - CloudWatchLogs: { - Status: 'DISABLED', - }, - }), - })); - - test.done(); - }, - - 'logs config - s3'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const bucket = s3.Bucket.fromBucketName(stack, 'LogBucket', 'MyBucketName'); - - // WHEN - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.s3({ - bucket: new s3.Bucket(stack, 'Bucket'), - path: 'path', - }), - logging: { - s3: { - bucket, - prefix: 'my-logs', - }, - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - LogsConfig: objectLike({ - S3Logs: { - Location: 'MyBucketName/my-logs', - Status: 'ENABLED', - }, - }), - })); - - test.done(); - }, - - 'logs config - cloudWatch and s3'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const bucket = s3.Bucket.fromBucketName(stack, 'LogBucket2', 'MyBucketName'); - const logGroup = logs.LogGroup.fromLogGroupName(stack, 'LogGroup2', 'MyLogGroupName'); - - // WHEN - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.s3({ - bucket: new s3.Bucket(stack, 'Bucket'), - path: 'path', - }), - logging: { - cloudWatch: { - logGroup, - }, - s3: { - bucket, - }, - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - LogsConfig: objectLike({ - CloudWatchLogs: { - GroupName: 'MyLogGroupName', - Status: 'ENABLED', - }, - S3Logs: { - Location: 'MyBucketName', - Status: 'ENABLED', - }, - }), - })); - - test.done(); - }, - - 'certificate arn'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const bucket = s3.Bucket.fromBucketName(stack, 'Bucket', 'my-bucket'); // (stack, 'Bucket'); - - // WHEN - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.s3({ - bucket, - path: 'path', - }), - environment: { - certificate: { - bucket, - objectKey: 'path', - }, - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - Environment: objectLike({ - Certificate: { - 'Fn::Join': ['', [ - 'arn:', - { 'Ref': 'AWS::Partition' }, - ':s3:::my-bucket/path', - ]], - }, - }), - })); - - test.done(); - }, - }, - - 'EnvironmentVariables': { - 'from SSM': { - 'can use environment variables'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.s3({ - bucket: new s3.Bucket(stack, 'Bucket'), - path: 'path', - }), - environment: { - buildImage: codebuild.LinuxBuildImage.fromDockerRegistry('myimage'), - }, - environmentVariables: { - 'ENV_VAR1': { - type: codebuild.BuildEnvironmentVariableType.PARAMETER_STORE, - value: '/params/param1', - }, - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - Environment: objectLike({ - EnvironmentVariables: [{ - Name: 'ENV_VAR1', - Type: 'PARAMETER_STORE', - Value: '/params/param1', - }], - }), - })); - - test.done(); - }, - - 'grants the correct read permissions'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.s3({ - bucket: new s3.Bucket(stack, 'Bucket'), - path: 'path', - }), - environment: { - buildImage: codebuild.LinuxBuildImage.fromDockerRegistry('myimage'), - }, - environmentVariables: { - 'ENV_VAR1': { - type: codebuild.BuildEnvironmentVariableType.PARAMETER_STORE, - value: '/params/param1', - }, - 'ENV_VAR2': { - type: codebuild.BuildEnvironmentVariableType.PARAMETER_STORE, - value: 'params/param2', - }, - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::IAM::Policy', { - 'PolicyDocument': { - 'Statement': arrayWith(objectLike({ - 'Action': 'ssm:GetParameters', - 'Effect': 'Allow', - 'Resource': [{ - 'Fn::Join': [ - '', - [ - 'arn:', - { - Ref: 'AWS::Partition', - }, - ':ssm:', - { - Ref: 'AWS::Region', - }, - ':', - { - Ref: 'AWS::AccountId', - }, - ':parameter/params/param1', - ], - ], - }, - { - 'Fn::Join': [ - '', - [ - 'arn:', - { - Ref: 'AWS::Partition', - }, - ':ssm:', - { - Ref: 'AWS::Region', - }, - ':', - { - Ref: 'AWS::AccountId', - }, - ':parameter/params/param2', - ], - ], - }], - })), - }, - })); - - - test.done(); - }, - - 'does not grant read permissions when variables are not from parameter store'(test: Test) { - - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.s3({ - bucket: new s3.Bucket(stack, 'Bucket'), - path: 'path', - }), - environment: { - buildImage: codebuild.LinuxBuildImage.fromDockerRegistry('myimage'), - }, - environmentVariables: { - 'ENV_VAR1': { - type: codebuild.BuildEnvironmentVariableType.PLAINTEXT, - value: 'var1-value', - }, - }, - }); - - // THEN - expect(stack).notTo(haveResourceLike('AWS::IAM::Policy', { - 'PolicyDocument': { - 'Statement': arrayWith(objectLike({ - 'Action': 'ssm:GetParameters', - 'Effect': 'Allow', - })), - }, - })); - - test.done(); - }, - }, - - 'from SecretsManager': { - 'can be provided as a verbatim secret name'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new codebuild.PipelineProject(stack, 'Project', { - environmentVariables: { - 'ENV_VAR1': { - type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, - value: 'my-secret', - }, - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - 'Environment': { - 'EnvironmentVariables': [ - { - 'Name': 'ENV_VAR1', - 'Type': 'SECRETS_MANAGER', - 'Value': 'my-secret', - }, - ], - }, - })); - - // THEN - expect(stack).to(haveResourceLike('AWS::IAM::Policy', { - 'PolicyDocument': { - 'Statement': arrayWith({ - 'Action': 'secretsmanager:GetSecretValue', - 'Effect': 'Allow', - 'Resource': { - 'Fn::Join': ['', [ - 'arn:', - { Ref: 'AWS::Partition' }, - ':secretsmanager:', - { Ref: 'AWS::Region' }, - ':', - { Ref: 'AWS::AccountId' }, - ':secret:my-secret-??????', - ]], - }, - }), - }, - })); - - test.done(); - }, - - 'can be provided as a verbatim secret name followed by a JSON key'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new codebuild.PipelineProject(stack, 'Project', { - environmentVariables: { - 'ENV_VAR1': { - type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, - value: 'my-secret:json-key', - }, - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - 'Environment': { - 'EnvironmentVariables': [ - { - 'Name': 'ENV_VAR1', - 'Type': 'SECRETS_MANAGER', - 'Value': 'my-secret:json-key', - }, - ], - }, - })); - - // THEN - expect(stack).to(haveResourceLike('AWS::IAM::Policy', { - 'PolicyDocument': { - 'Statement': arrayWith({ - 'Action': 'secretsmanager:GetSecretValue', - 'Effect': 'Allow', - 'Resource': { - 'Fn::Join': ['', [ - 'arn:', - { Ref: 'AWS::Partition' }, - ':secretsmanager:', - { Ref: 'AWS::Region' }, - ':', - { Ref: 'AWS::AccountId' }, - ':secret:my-secret-??????', - ]], - }, - }), - }, - })); - - test.done(); - }, - - 'can be provided as a verbatim full secret ARN followed by a JSON key'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new codebuild.PipelineProject(stack, 'Project', { - environmentVariables: { - 'ENV_VAR1': { - type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, - value: 'arn:aws:secretsmanager:us-west-2:123456789012:secret:my-secret-123456:json-key', - }, - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - 'Environment': { - 'EnvironmentVariables': [ - { - 'Name': 'ENV_VAR1', - 'Type': 'SECRETS_MANAGER', - 'Value': 'arn:aws:secretsmanager:us-west-2:123456789012:secret:my-secret-123456:json-key', - }, - ], - }, - })); - - // THEN - expect(stack).to(haveResourceLike('AWS::IAM::Policy', { - 'PolicyDocument': { - 'Statement': arrayWith({ - 'Action': 'secretsmanager:GetSecretValue', - 'Effect': 'Allow', - 'Resource': 'arn:aws:secretsmanager:us-west-2:123456789012:secret:my-secret-123456*', - }), - }, - })); - - // THEN - expect(stack).to(not(haveResourceLike('AWS::IAM::Policy', { - 'PolicyDocument': { - 'Statement': arrayWith({ - 'Action': 'kms:Decrypt', - 'Effect': 'Allow', - 'Resource': 'arn:aws:kms:us-west-2:123456789012:key/*', - }), - }, - }))); - - test.done(); - }, - - 'can be provided as a verbatim partial secret ARN'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new codebuild.PipelineProject(stack, 'Project', { - environmentVariables: { - 'ENV_VAR1': { - type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, - value: 'arn:aws:secretsmanager:us-west-2:123456789012:secret:mysecret', - }, - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - 'Environment': { - 'EnvironmentVariables': [ - { - 'Name': 'ENV_VAR1', - 'Type': 'SECRETS_MANAGER', - 'Value': 'arn:aws:secretsmanager:us-west-2:123456789012:secret:mysecret', - }, - ], - }, - })); - - // THEN - expect(stack).to(haveResourceLike('AWS::IAM::Policy', { - 'PolicyDocument': { - 'Statement': arrayWith({ - 'Action': 'secretsmanager:GetSecretValue', - 'Effect': 'Allow', - 'Resource': 'arn:aws:secretsmanager:us-west-2:123456789012:secret:mysecret*', - }), - }, - })); - - // THEN - expect(stack).to(not(haveResourceLike('AWS::IAM::Policy', { - 'PolicyDocument': { - 'Statement': arrayWith({ - 'Action': 'kms:Decrypt', - 'Effect': 'Allow', - 'Resource': 'arn:aws:kms:us-west-2:123456789012:key/*', - }), - }, - }))); - - test.done(); - }, - - "when provided as a verbatim partial secret ARN from another account, adds permission to decrypt keys in the Secret's account"(test: Test) { - // GIVEN - const app = new cdk.App(); - const stack = new cdk.Stack(app, 'ProjectStack', { - env: { account: '123456789012' }, - }); - - // WHEN - new codebuild.PipelineProject(stack, 'Project', { - environmentVariables: { - 'ENV_VAR1': { - type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, - value: 'arn:aws:secretsmanager:us-west-2:901234567890:secret:mysecret', - }, - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::IAM::Policy', { - 'PolicyDocument': { - 'Statement': arrayWith({ - 'Action': 'kms:Decrypt', - 'Effect': 'Allow', - 'Resource': 'arn:aws:kms:us-west-2:901234567890:key/*', - }), - }, - })); - - test.done(); - }, - - 'when two secrets from another account are provided as verbatim partial secret ARNs, adds only one permission for decrypting'(test: Test) { - // GIVEN - const app = new cdk.App(); - const stack = new cdk.Stack(app, 'ProjectStack', { - env: { account: '123456789012' }, - }); - - // WHEN - new codebuild.PipelineProject(stack, 'Project', { - environmentVariables: { - 'ENV_VAR1': { - type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, - value: 'arn:aws:secretsmanager:us-west-2:901234567890:secret:mysecret', - }, - 'ENV_VAR2': { - type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, - value: 'arn:aws:secretsmanager:us-west-2:901234567890:secret:other-secret', - }, - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::IAM::Policy', { - 'PolicyDocument': { - 'Statement': arrayWith({ - 'Action': 'kms:Decrypt', - 'Effect': 'Allow', - 'Resource': 'arn:aws:kms:us-west-2:901234567890:key/*', - }), - }, - })); - - test.done(); - }, - - 'can be provided as the ARN attribute of a new Secret'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - const secret = new secretsmanager.Secret(stack, 'Secret'); - new codebuild.PipelineProject(stack, 'Project', { - environmentVariables: { - 'ENV_VAR1': { - type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, - value: secret.secretArn, - }, - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - 'Environment': { - 'EnvironmentVariables': [ - { - 'Name': 'ENV_VAR1', - 'Type': 'SECRETS_MANAGER', - 'Value': { 'Ref': 'SecretA720EF05' }, - }, - ], - }, - })); - - // THEN - expect(stack).to(haveResourceLike('AWS::IAM::Policy', { - 'PolicyDocument': { - 'Statement': arrayWith({ - 'Action': 'secretsmanager:GetSecretValue', - 'Effect': 'Allow', - 'Resource': { 'Ref': 'SecretA720EF05' }, - }), - }, - })); - - test.done(); - }, - - 'when the same new secret is provided with different JSON keys, only adds the resource once'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - const secret = new secretsmanager.Secret(stack, 'Secret'); - new codebuild.PipelineProject(stack, 'Project', { - environmentVariables: { - 'ENV_VAR1': { - type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, - value: `${secret.secretArn}:json-key1`, - }, - 'ENV_VAR2': { - type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, - value: `${secret.secretArn}:json-key2`, - }, - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - 'Environment': { - 'EnvironmentVariables': [ - { - 'Name': 'ENV_VAR1', - 'Type': 'SECRETS_MANAGER', - 'Value': { 'Fn::Join': ['', [{ 'Ref': 'SecretA720EF05' }, ':json-key1']] }, - }, - { - 'Name': 'ENV_VAR2', - 'Type': 'SECRETS_MANAGER', - 'Value': { 'Fn::Join': ['', [{ 'Ref': 'SecretA720EF05' }, ':json-key2']] }, - }, - ], - }, - })); - - // THEN - expect(stack).to(haveResourceLike('AWS::IAM::Policy', { - 'PolicyDocument': { - 'Statement': arrayWith({ - 'Action': 'secretsmanager:GetSecretValue', - 'Effect': 'Allow', - 'Resource': { 'Ref': 'SecretA720EF05' }, - }), - }, - })); - - test.done(); - }, - - 'can be provided as the ARN attribute of a new Secret, followed by a JSON key'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - const secret = new secretsmanager.Secret(stack, 'Secret'); - new codebuild.PipelineProject(stack, 'Project', { - environmentVariables: { - 'ENV_VAR1': { - type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, - value: `${secret.secretArn}:json-key:version-stage`, - }, - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - 'Environment': { - 'EnvironmentVariables': [ - { - 'Name': 'ENV_VAR1', - 'Type': 'SECRETS_MANAGER', - 'Value': { - 'Fn::Join': ['', [ - { 'Ref': 'SecretA720EF05' }, - ':json-key:version-stage', - ]], - }, - }, - ], - }, - })); - - // THEN - expect(stack).to(haveResourceLike('AWS::IAM::Policy', { - 'PolicyDocument': { - 'Statement': arrayWith({ - 'Action': 'secretsmanager:GetSecretValue', - 'Effect': 'Allow', - 'Resource': { 'Ref': 'SecretA720EF05' }, - }), - }, - })); - - test.done(); - }, - - 'can be provided as the name attribute of a Secret imported by name'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - const secret = secretsmanager.Secret.fromSecretNameV2(stack, 'Secret', 'mysecret'); - new codebuild.PipelineProject(stack, 'Project', { - environmentVariables: { - 'ENV_VAR1': { - type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, - value: secret.secretName, - }, - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - 'Environment': { - 'EnvironmentVariables': [ - { - 'Name': 'ENV_VAR1', - 'Type': 'SECRETS_MANAGER', - 'Value': 'mysecret', - }, - ], - }, - })); - - // THEN - expect(stack).to(haveResourceLike('AWS::IAM::Policy', { - 'PolicyDocument': { - 'Statement': arrayWith({ - 'Action': 'secretsmanager:GetSecretValue', - 'Effect': 'Allow', - 'Resource': { - 'Fn::Join': ['', [ - 'arn:', - { 'Ref': 'AWS::Partition' }, - ':secretsmanager:', - { 'Ref': 'AWS::Region' }, - ':', - { 'Ref': 'AWS::AccountId' }, - ':secret:mysecret-??????', - ]], - }, - }), - }, - })); - - test.done(); - }, - - 'can be provided as the ARN attribute of a Secret imported by partial ARN, followed by a JSON key'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - const secret = secretsmanager.Secret.fromSecretPartialArn(stack, 'Secret', - 'arn:aws:secretsmanager:us-west-2:123456789012:secret:mysecret'); - new codebuild.PipelineProject(stack, 'Project', { - environmentVariables: { - 'ENV_VAR1': { - type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, - value: `${secret.secretArn}:json-key`, - }, - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - 'Environment': { - 'EnvironmentVariables': [ - { - 'Name': 'ENV_VAR1', - 'Type': 'SECRETS_MANAGER', - 'Value': 'arn:aws:secretsmanager:us-west-2:123456789012:secret:mysecret:json-key', - }, - ], - }, - })); - - // THEN - expect(stack).to(haveResourceLike('AWS::IAM::Policy', { - 'PolicyDocument': { - 'Statement': arrayWith({ - 'Action': 'secretsmanager:GetSecretValue', - 'Effect': 'Allow', - 'Resource': 'arn:aws:secretsmanager:us-west-2:123456789012:secret:mysecret*', - }), - }, - })); - - test.done(); - }, - - 'can be provided as the ARN attribute of a Secret imported by complete ARN, followed by a JSON key'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - const secret = secretsmanager.Secret.fromSecretCompleteArn(stack, 'Secret', - 'arn:aws:secretsmanager:us-west-2:123456789012:secret:mysecret-123456'); - new codebuild.PipelineProject(stack, 'Project', { - environmentVariables: { - 'ENV_VAR1': { - type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, - value: `${secret.secretArn}:json-key`, - }, - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - 'Environment': { - 'EnvironmentVariables': [ - { - 'Name': 'ENV_VAR1', - 'Type': 'SECRETS_MANAGER', - 'Value': 'arn:aws:secretsmanager:us-west-2:123456789012:secret:mysecret-123456:json-key', - }, - ], - }, - })); - - // THEN - expect(stack).to(haveResourceLike('AWS::IAM::Policy', { - 'PolicyDocument': { - 'Statement': arrayWith({ - 'Action': 'secretsmanager:GetSecretValue', - 'Effect': 'Allow', - 'Resource': 'arn:aws:secretsmanager:us-west-2:123456789012:secret:mysecret-123456*', - }), - }, - })); - - test.done(); - }, - - 'can be provided as a SecretArn of a new Secret, with its physical name set, created in a different account'(test: Test) { - // GIVEN - const app = new cdk.App(); - const secretStack = new cdk.Stack(app, 'SecretStack', { - env: { account: '012345678912' }, - }); - const stack = new cdk.Stack(app, 'ProjectStack', { - env: { account: '123456789012' }, - }); - - // WHEN - const secret = new secretsmanager.Secret(secretStack, 'Secret', { secretName: 'secret-name' }); - new codebuild.PipelineProject(stack, 'Project', { - environmentVariables: { - 'ENV_VAR1': { - type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, - value: secret.secretArn, - }, - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - 'Environment': { - 'EnvironmentVariables': [ - { - 'Name': 'ENV_VAR1', - 'Type': 'SECRETS_MANAGER', - 'Value': { - 'Fn::Join': ['', [ - 'arn:', - { 'Ref': 'AWS::Partition' }, - ':secretsmanager:', - { 'Ref': 'AWS::Region' }, - ':012345678912:secret:secret-name', - ]], - }, - }, - ], - }, - })); - - expect(stack).to(haveResourceLike('AWS::IAM::Policy', { - 'PolicyDocument': { - 'Statement': arrayWith({ - 'Action': 'secretsmanager:GetSecretValue', - 'Effect': 'Allow', - 'Resource': { - 'Fn::Join': ['', [ - 'arn:', - { 'Ref': 'AWS::Partition' }, - ':secretsmanager:', - { 'Ref': 'AWS::Region' }, - ':012345678912:secret:secret-name-??????', - ]], - }, - }), - }, - })); - - expect(stack).to(haveResourceLike('AWS::IAM::Policy', { - 'PolicyDocument': { - 'Statement': arrayWith({ - 'Action': 'kms:Decrypt', - 'Effect': 'Allow', - 'Resource': { - 'Fn::Join': ['', [ - 'arn:', - { 'Ref': 'AWS::Partition' }, - ':kms:', - { 'Ref': 'AWS::Region' }, - ':012345678912:key/*', - ]], - }, - }), - }, - })); - - test.done(); - }, - - 'can be provided as a SecretArn of a Secret imported by name in a different account'(test: Test) { - // GIVEN - const app = new cdk.App(); - const secretStack = new cdk.Stack(app, 'SecretStack', { - env: { account: '012345678912' }, - }); - const stack = new cdk.Stack(app, 'ProjectStack', { - env: { account: '123456789012' }, - }); - - // WHEN - const secret = secretsmanager.Secret.fromSecretNameV2(secretStack, 'Secret', 'secret-name'); - new codebuild.PipelineProject(stack, 'Project', { - environmentVariables: { - 'ENV_VAR1': { - type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, - value: `${secret.secretArn}:json-key`, - }, - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - 'Environment': { - 'EnvironmentVariables': [ - { - 'Name': 'ENV_VAR1', - 'Type': 'SECRETS_MANAGER', - 'Value': { - 'Fn::Join': ['', [ - 'arn:', - { 'Ref': 'AWS::Partition' }, - ':secretsmanager:', - { 'Ref': 'AWS::Region' }, - ':012345678912:secret:secret-name:json-key', - ]], - }, - }, - ], - }, - })); - - expect(stack).to(haveResourceLike('AWS::IAM::Policy', { - 'PolicyDocument': { - 'Statement': arrayWith({ - 'Action': 'secretsmanager:GetSecretValue', - 'Effect': 'Allow', - 'Resource': { - 'Fn::Join': ['', [ - 'arn:', - { 'Ref': 'AWS::Partition' }, - ':secretsmanager:', - { 'Ref': 'AWS::Region' }, - ':012345678912:secret:secret-name*', - ]], - }, - }), - }, - })); - - expect(stack).to(haveResourceLike('AWS::IAM::Policy', { - 'PolicyDocument': { - 'Statement': arrayWith({ - 'Action': 'kms:Decrypt', - 'Effect': 'Allow', - 'Resource': { - 'Fn::Join': ['', [ - 'arn:', - { 'Ref': 'AWS::Partition' }, - ':kms:', - { 'Ref': 'AWS::Region' }, - ':012345678912:key/*', - ]], - }, - }), - }, - })); - - test.done(); - }, - - 'can be provided as a SecretArn of a Secret imported by complete ARN from a different account'(test: Test) { - // GIVEN - const app = new cdk.App(); - const stack = new cdk.Stack(app, 'ProjectStack', { - env: { account: '123456789012' }, - }); - const secretArn = 'arn:aws:secretsmanager:us-west-2:901234567890:secret:mysecret-123456'; - - // WHEN - const secret = secretsmanager.Secret.fromSecretCompleteArn(stack, 'Secret', secretArn); - new codebuild.PipelineProject(stack, 'Project', { - environmentVariables: { - 'ENV_VAR1': { - type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, - value: secret.secretArn, - }, - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - 'Environment': { - 'EnvironmentVariables': [ - { - 'Name': 'ENV_VAR1', - 'Type': 'SECRETS_MANAGER', - 'Value': secretArn, - }, - ], - }, - })); - - expect(stack).to(haveResourceLike('AWS::IAM::Policy', { - 'PolicyDocument': { - 'Statement': arrayWith({ - 'Action': 'secretsmanager:GetSecretValue', - 'Effect': 'Allow', - 'Resource': `${secretArn}*`, - }), - }, - })); - - expect(stack).to(haveResourceLike('AWS::IAM::Policy', { - 'PolicyDocument': { - 'Statement': arrayWith({ - 'Action': 'kms:Decrypt', - 'Effect': 'Allow', - 'Resource': 'arn:aws:kms:us-west-2:901234567890:key/*', - }), - }, - })); - - test.done(); - }, - - 'should fail when the parsed Arn does not contain a secret name'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - test.throws(() => { - new codebuild.PipelineProject(stack, 'Project', { - environmentVariables: { - 'ENV_VAR1': { - type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, - value: 'arn:aws:secretsmanager:us-west-2:123456789012:secret', - }, - }, - }); - }, /SecretManager ARN is missing the name of the secret:/); - - test.done(); - }, - }, - - 'should fail creating when using a secret value in a plaintext variable'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // THEN - test.throws(() => { - new codebuild.PipelineProject(stack, 'Project', { - environmentVariables: { - 'a': { - value: `a_${cdk.SecretValue.secretsManager('my-secret')}_b`, - }, - }, - }); - }, /Plaintext environment variable 'a' contains a secret value!/); - - test.done(); - }, - - "should allow opting out of the 'secret value in a plaintext variable' validation"(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // THEN - new codebuild.PipelineProject(stack, 'Project', { - environmentVariables: { - 'b': { - value: cdk.SecretValue.secretsManager('my-secret'), - }, - }, - checkSecretsInPlainTextEnvVariables: false, - }); - - test.done(); - }, - }, - - 'Timeouts': { - 'can add queued timeout'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.s3({ - bucket: new s3.Bucket(stack, 'Bucket'), - path: 'path', - }), - queuedTimeout: cdk.Duration.minutes(30), - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - QueuedTimeoutInMinutes: 30, - })); - - test.done(); - }, - - 'can override build timeout'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.s3({ - bucket: new s3.Bucket(stack, 'Bucket'), - path: 'path', - }), - timeout: cdk.Duration.minutes(30), - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - TimeoutInMinutes: 30, - })); - - test.done(); - }, - }, - - 'Maximum concurrency': { - 'can limit maximum concurrency'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.s3({ - bucket: new s3.Bucket(stack, 'Bucket'), - path: 'path', - }), - concurrentBuildLimit: 1, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - ConcurrentBuildLimit: 1, - })); - - test.done(); - }, - }, - - 'can be imported': { - 'by ARN'(test: Test) { - const stack = new cdk.Stack(); - const project = codebuild.Project.fromProjectArn(stack, 'Project', - 'arn:aws:codebuild:us-west-2:123456789012:project/My-Project'); - - test.equal(project.projectName, 'My-Project'); - test.equal(project.env.account, '123456789012'); - test.equal(project.env.region, 'us-west-2'); - - test.done(); - }, - }, -}; diff --git a/packages/@aws-cdk/aws-codebuild/test/test.report-group.ts b/packages/@aws-cdk/aws-codebuild/test/test.report-group.ts deleted file mode 100644 index 9ea5441aeb5df..0000000000000 --- a/packages/@aws-cdk/aws-codebuild/test/test.report-group.ts +++ /dev/null @@ -1,162 +0,0 @@ -import { ABSENT, expect, haveResourceLike, ResourcePart } from '@aws-cdk/assert-internal'; -import * as iam from '@aws-cdk/aws-iam'; -import * as kms from '@aws-cdk/aws-kms'; -import * as s3 from '@aws-cdk/aws-s3'; -import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; -import * as codebuild from '../lib'; - -/* eslint-disable quote-props */ -/* eslint-disable quotes */ - -export = { - 'Test Reports Groups': { - 'get created with type=TEST and exportConfig=NO_EXPORT by default'(test: Test) { - const stack = new cdk.Stack(); - - new codebuild.ReportGroup(stack, 'ReportGroup'); - - expect(stack).to(haveResourceLike('AWS::CodeBuild::ReportGroup', { - "Type": "TEST", - "ExportConfig": { - "ExportConfigType": "NO_EXPORT", - "S3Destination": ABSENT, - }, - })); - - test.done(); - }, - - 'can be created with name' (test: Test) { - const stack = new cdk.Stack(); - - new codebuild.ReportGroup(stack, 'ReportGroup', { - reportGroupName: 'my-report-group', - }); - - expect(stack).to(haveResourceLike('AWS::CodeBuild::ReportGroup', { - "Name": 'my-report-group', - })); - - test.done(); - }, - - 'can be imported by name'(test: Test) { - const stack = new cdk.Stack(); - - const reportGroup = codebuild.ReportGroup.fromReportGroupName(stack, - 'ReportGroup', 'my-report-group'); - - const role = new iam.Role(stack, 'Role', { - assumedBy: new iam.AnyPrincipal(), - }); - role.addToPolicy(new iam.PolicyStatement({ - actions: ['codebuild:*'], - resources: [reportGroup.reportGroupArn], - })); - - test.equal(reportGroup.reportGroupName, 'my-report-group'); - expect(stack).to(haveResourceLike('AWS::IAM::Policy', { - "PolicyDocument": { - "Statement": [ - { - "Action": "codebuild:*", - "Resource": { - "Fn::Join": ["", [ - "arn:", - { "Ref": "AWS::Partition" }, - ":codebuild:", - { "Ref": "AWS::Region" }, - ":", - { "Ref": "AWS::AccountId" }, - ":report-group/my-report-group", - ]], - }, - }, - ], - }, - })); - - test.done(); - }, - - 'specify exportConfig=S3 when providing an exportBucket'(test: Test) { - const stack = new cdk.Stack(); - - new codebuild.ReportGroup(stack, 'ReportGroup', { - exportBucket: s3.Bucket.fromBucketName(stack, 'Bucket', 'my-bucket'), - }); - - expect(stack).to(haveResourceLike('AWS::CodeBuild::ReportGroup', { - "Type": "TEST", - "ExportConfig": { - "ExportConfigType": "S3", - "S3Destination": { - "Bucket": "my-bucket", - "EncryptionKey": ABSENT, - "EncryptionDisabled": ABSENT, - "Packaging": ABSENT, - }, - }, - })); - - test.done(); - }, - - 'specify encryptionKey in ExportConfig.S3Destination if exportBucket has a Key'(test: Test) { - const stack = new cdk.Stack(); - - new codebuild.ReportGroup(stack, 'ReportGroup', { - exportBucket: s3.Bucket.fromBucketAttributes(stack, 'Bucket', { - bucketName: 'my-bucket', - encryptionKey: kms.Key.fromKeyArn(stack, 'Key', - 'arn:aws:kms:us-east-1:123456789012:key/my-key'), - }), - zipExport: true, - }); - - expect(stack).to(haveResourceLike('AWS::CodeBuild::ReportGroup', { - "Type": "TEST", - "ExportConfig": { - "ExportConfigType": "S3", - "S3Destination": { - "Bucket": "my-bucket", - "EncryptionDisabled": false, - "EncryptionKey": "arn:aws:kms:us-east-1:123456789012:key/my-key", - "Packaging": "ZIP", - }, - }, - })); - - test.done(); - }, - - 'get created with RemovalPolicy.RETAIN by default'(test: Test) { - const stack = new cdk.Stack(); - - new codebuild.ReportGroup(stack, 'ReportGroup'); - - expect(stack).to(haveResourceLike('AWS::CodeBuild::ReportGroup', { - "DeletionPolicy": "Retain", - "UpdateReplacePolicy": "Retain", - }, ResourcePart.CompleteDefinition)); - - test.done(); - }, - - 'can be created with RemovalPolicy.DESTROY'(test: Test) { - const stack = new cdk.Stack(); - - new codebuild.ReportGroup(stack, 'ReportGroup', { - removalPolicy: cdk.RemovalPolicy.DESTROY, - }); - - expect(stack).to(haveResourceLike('AWS::CodeBuild::ReportGroup', { - "DeletionPolicy": "Delete", - "UpdateReplacePolicy": "Delete", - }, ResourcePart.CompleteDefinition)); - - test.done(); - }, - }, -}; diff --git a/packages/@aws-cdk/aws-codebuild/test/test.untrusted-code-boundary.ts b/packages/@aws-cdk/aws-codebuild/test/test.untrusted-code-boundary.ts deleted file mode 100644 index e806e48b58edb..0000000000000 --- a/packages/@aws-cdk/aws-codebuild/test/test.untrusted-code-boundary.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { expect, haveResourceLike, arrayWith } from '@aws-cdk/assert-internal'; -import * as iam from '@aws-cdk/aws-iam'; -import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; -import * as codebuild from '../lib'; - -export = { - 'can attach permissions boundary to Project'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - const project = new codebuild.Project(stack, 'Project', { - source: codebuild.Source.gitHub({ owner: 'a', repo: 'b' }), - }); - iam.PermissionsBoundary.of(project).apply(new codebuild.UntrustedCodeBoundaryPolicy(stack, 'Boundary')); - - // THEN - expect(stack).to(haveResourceLike('AWS::IAM::Role', { - PermissionsBoundary: { Ref: 'BoundaryEA298153' }, - })); - - test.done(); - }, - - 'can add additional statements Boundary'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - const project = new codebuild.Project(stack, 'Project', { - source: codebuild.Source.gitHub({ owner: 'a', repo: 'b' }), - }); - iam.PermissionsBoundary.of(project).apply(new codebuild.UntrustedCodeBoundaryPolicy(stack, 'Boundary', { - additionalStatements: [ - new iam.PolicyStatement({ - actions: ['a:a'], - resources: ['b'], - }), - ], - })); - - // THEN - expect(stack).to(haveResourceLike('AWS::IAM::ManagedPolicy', { - PolicyDocument: { - Statement: arrayWith({ - Effect: 'Allow', - Action: 'a:a', - Resource: 'b', - }), - }, - })); - - test.done(); - }, -}; \ No newline at end of file diff --git a/packages/@aws-cdk/aws-codebuild/test/untrusted-code-boundary.test.ts b/packages/@aws-cdk/aws-codebuild/test/untrusted-code-boundary.test.ts new file mode 100644 index 0000000000000..89933d11a7ab8 --- /dev/null +++ b/packages/@aws-cdk/aws-codebuild/test/untrusted-code-boundary.test.ts @@ -0,0 +1,50 @@ +import { arrayWith } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; +import * as iam from '@aws-cdk/aws-iam'; +import * as cdk from '@aws-cdk/core'; +import * as codebuild from '../lib'; + +test('can attach permissions boundary to Project', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + const project = new codebuild.Project(stack, 'Project', { + source: codebuild.Source.gitHub({ owner: 'a', repo: 'b' }), + }); + iam.PermissionsBoundary.of(project).apply(new codebuild.UntrustedCodeBoundaryPolicy(stack, 'Boundary')); + + // THEN + expect(stack).toHaveResourceLike('AWS::IAM::Role', { + PermissionsBoundary: { Ref: 'BoundaryEA298153' }, + }); +}); + +test('can add additional statements Boundary', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + const project = new codebuild.Project(stack, 'Project', { + source: codebuild.Source.gitHub({ owner: 'a', repo: 'b' }), + }); + iam.PermissionsBoundary.of(project).apply(new codebuild.UntrustedCodeBoundaryPolicy(stack, 'Boundary', { + additionalStatements: [ + new iam.PolicyStatement({ + actions: ['a:a'], + resources: ['b'], + }), + ], + })); + + // THEN + expect(stack).toHaveResourceLike('AWS::IAM::ManagedPolicy', { + PolicyDocument: { + Statement: arrayWith({ + Effect: 'Allow', + Action: 'a:a', + Resource: 'b', + }), + }, + }); +}); \ No newline at end of file diff --git a/packages/@aws-cdk/aws-codecommit/.eslintrc.js b/packages/@aws-cdk/aws-codecommit/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-codecommit/.eslintrc.js +++ b/packages/@aws-cdk/aws-codecommit/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-codecommit/jest.config.js b/packages/@aws-cdk/aws-codecommit/jest.config.js index c61850f59dabb..7c2e6abe4d7ed 100644 --- a/packages/@aws-cdk/aws-codecommit/jest.config.js +++ b/packages/@aws-cdk/aws-codecommit/jest.config.js @@ -1,4 +1,4 @@ -const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +const baseConfig = require('../../../tools/@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = { ...baseConfig, coverageThreshold: { diff --git a/packages/@aws-cdk/aws-codecommit/package.json b/packages/@aws-cdk/aws-codecommit/package.json index 3bb2b8b4279a9..d5041d7e5711b 100644 --- a/packages/@aws-cdk/aws-codecommit/package.json +++ b/packages/@aws-cdk/aws-codecommit/package.json @@ -57,8 +57,7 @@ "cloudformation": "AWS::CodeCommit", "env": { "AWSLINT_BASE_CONSTRUCT": true - }, - "jest": true + } }, "nyc": { "statements": 30, @@ -78,15 +77,15 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", "@aws-cdk/aws-sns": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", "aws-sdk": "^2.848.0", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-codestarnotifications": "0.0.0", diff --git a/packages/@aws-cdk/aws-codedeploy/.eslintrc.js b/packages/@aws-cdk/aws-codedeploy/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-codedeploy/.eslintrc.js +++ b/packages/@aws-cdk/aws-codedeploy/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-codedeploy/jest.config.js b/packages/@aws-cdk/aws-codedeploy/jest.config.js index f5d5c4c8ad18f..34818e1593f6b 100644 --- a/packages/@aws-cdk/aws-codedeploy/jest.config.js +++ b/packages/@aws-cdk/aws-codedeploy/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); -module.exports = baseConfig; \ No newline at end of file +const baseConfig = require('../../../tools/@aws-cdk/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-codedeploy/package.json b/packages/@aws-cdk/aws-codedeploy/package.json index ac67fc09875c2..f8279b5c21e57 100644 --- a/packages/@aws-cdk/aws-codedeploy/package.json +++ b/packages/@aws-cdk/aws-codedeploy/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::CodeDeploy", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -76,13 +75,13 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-autoscaling": "0.0.0", diff --git a/packages/@aws-cdk/aws-codeguruprofiler/.eslintrc.js b/packages/@aws-cdk/aws-codeguruprofiler/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-codeguruprofiler/.eslintrc.js +++ b/packages/@aws-cdk/aws-codeguruprofiler/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-codeguruprofiler/jest.config.js b/packages/@aws-cdk/aws-codeguruprofiler/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-codeguruprofiler/jest.config.js +++ b/packages/@aws-cdk/aws-codeguruprofiler/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-codeguruprofiler/package.json b/packages/@aws-cdk/aws-codeguruprofiler/package.json index 1c72b538d5056..247e4696080fe 100644 --- a/packages/@aws-cdk/aws-codeguruprofiler/package.json +++ b/packages/@aws-cdk/aws-codeguruprofiler/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::CodeGuruProfiler", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,12 +74,12 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/aws-iam": "0.0.0", @@ -88,8 +87,8 @@ "constructs": "^3.3.69" }, "peerDependencies": { - "@aws-cdk/core": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", + "@aws-cdk/core": "0.0.0", "constructs": "^3.3.69" }, "engines": { diff --git a/packages/@aws-cdk/aws-codegurureviewer/.eslintrc.js b/packages/@aws-cdk/aws-codegurureviewer/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-codegurureviewer/.eslintrc.js +++ b/packages/@aws-cdk/aws-codegurureviewer/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-codegurureviewer/jest.config.js b/packages/@aws-cdk/aws-codegurureviewer/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-codegurureviewer/jest.config.js +++ b/packages/@aws-cdk/aws-codegurureviewer/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-codegurureviewer/package.json b/packages/@aws-cdk/aws-codegurureviewer/package.json index c0619789ea414..1ea8076d375ee 100644 --- a/packages/@aws-cdk/aws-codegurureviewer/package.json +++ b/packages/@aws-cdk/aws-codegurureviewer/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::CodeGuruReviewer", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-codepipeline-actions/.eslintrc.js b/packages/@aws-cdk/aws-codepipeline-actions/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/.eslintrc.js +++ b/packages/@aws-cdk/aws-codepipeline-actions/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-codepipeline-actions/README.md b/packages/@aws-cdk/aws-codepipeline-actions/README.md index e57381c517c1f..05860cfe20233 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/README.md +++ b/packages/@aws-cdk/aws-codepipeline-actions/README.md @@ -11,7 +11,7 @@ This package contains Actions that can be used in a CodePipeline. -```ts +```ts nofixture import * as codepipeline from '@aws-cdk/aws-codepipeline'; import * as codepipeline_actions from '@aws-cdk/aws-codepipeline-actions'; ``` @@ -23,10 +23,8 @@ import * as codepipeline_actions from '@aws-cdk/aws-codepipeline-actions'; To use a CodeCommit Repository in a CodePipeline: ```ts -import * as codecommit from '@aws-cdk/aws-codecommit'; - const repo = new codecommit.Repository(this, 'Repo', { - // ... + repositoryName: 'MyRepo', }); const pipeline = new codepipeline.Pipeline(this, 'MyPipeline', { @@ -49,6 +47,7 @@ You can specify the role object in eventRole property. ```ts const eventRole = iam.Role.fromRoleArn(this, 'Event-role', 'roleArn'); +declare const repo: codecommit.Repository; const sourceAction = new codepipeline_actions.CodeCommitSourceAction({ actionName: 'CodeCommit', repository: repo, @@ -61,6 +60,8 @@ If you want to clone the entire CodeCommit repository (only available for CodeBu you can set the `codeBuildCloneOutput` property to `true`: ```ts +declare const project: codebuild.PipelineProject; +declare const repo: codecommit.Repository; const sourceOutput = new codepipeline.Artifact(); const sourceAction = new codepipeline_actions.CodeCommitSourceAction({ actionName: 'CodeCommit', @@ -80,15 +81,22 @@ const buildAction = new codepipeline_actions.CodeBuildAction({ The CodeCommit source action emits variables: ```ts +declare const project: codebuild.PipelineProject; +declare const repo: codecommit.Repository; +const sourceOutput = new codepipeline.Artifact(); const sourceAction = new codepipeline_actions.CodeCommitSourceAction({ - // ... + actionName: 'CodeCommit', + repository: repo, + output: sourceOutput, variablesNamespace: 'MyNamespace', // optional - by default, a name will be generated for you }); // later: new codepipeline_actions.CodeBuildAction({ - // ... + actionName: 'CodeBuild', + project, + input: sourceOutput, environmentVariables: { COMMIT_ID: { value: sourceAction.variables.commitId, @@ -107,20 +115,21 @@ If you want to use a GitHub repository as the source, you must create: with the value of the **GitHub Access Token**. Pick whatever name you want (for example `my-github-token`). This token can be stored either as Plaintext or as a Secret key/value. If you stored the token as Plaintext, - set `cdk.SecretValue.secretsManager('my-github-token')` as the value of `oauthToken`. + set `SecretValue.secretsManager('my-github-token')` as the value of `oauthToken`. If you stored it as a Secret key/value, - you must set `cdk.SecretValue.secretsManager('my-github-token', { jsonField : 'my-github-token' })` as the value of `oauthToken`. + you must set `SecretValue.secretsManager('my-github-token', { jsonField : 'my-github-token' })` as the value of `oauthToken`. To use GitHub as the source of a CodePipeline: ```ts // Read the secret from Secrets Manager +const pipeline = new codepipeline.Pipeline(this, 'MyPipeline'); const sourceOutput = new codepipeline.Artifact(); const sourceAction = new codepipeline_actions.GitHubSourceAction({ actionName: 'GitHub_Source', owner: 'awslabs', repo: 'aws-cdk', - oauthToken: cdk.SecretValue.secretsManager('my-github-token'), + oauthToken: SecretValue.secretsManager('my-github-token'), output: sourceOutput, branch: 'develop', // default: 'master' }); @@ -133,15 +142,24 @@ pipeline.addStage({ The GitHub source action emits variables: ```ts +declare const sourceOutput: codepipeline.Artifact; +declare const project: codebuild.PipelineProject; + const sourceAction = new codepipeline_actions.GitHubSourceAction({ - // ... + actionName: 'Github_Source', + output: sourceOutput, + owner: 'my-owner', + repo: 'my-repo', + oauthToken: SecretValue.secretsManager('my-github-token'), variablesNamespace: 'MyNamespace', // optional - by default, a name will be generated for you }); // later: new codepipeline_actions.CodeBuildAction({ - // ... + actionName: 'CodeBuild', + project, + input: sourceOutput, environmentVariables: { COMMIT_URL: { value: sourceAction.variables.commitUrl, @@ -185,8 +203,6 @@ You can also use the `CodeStarConnectionsSourceAction` to connect to GitHub, in To use an S3 Bucket as a source in CodePipeline: ```ts -import * as s3 from '@aws-cdk/aws-s3'; - const sourceBucket = new s3.Bucket(this, 'MyBucket', { versioned: true, // a Bucket used as a source in CodePipeline must be versioned }); @@ -229,6 +245,8 @@ You can do it through the CDK: ```ts import * as cloudtrail from '@aws-cdk/aws-cloudtrail'; +declare const sourceBucket: s3.Bucket; +const sourceOutput = new codepipeline.Artifact(); const key = 'some/key.zip'; const trail = new cloudtrail.Trail(this, 'CloudTrail'); trail.addS3EventSelector([{ @@ -249,15 +267,23 @@ const sourceAction = new codepipeline_actions.S3SourceAction({ The S3 source action emits variables: ```ts +const key = 'some/key.zip'; +declare const sourceBucket: s3.Bucket; +const sourceOutput = new codepipeline.Artifact(); const sourceAction = new codepipeline_actions.S3SourceAction({ - // ... + actionName: 'S3Source', + bucketKey: key, + bucket: sourceBucket, + output: sourceOutput, variablesNamespace: 'MyNamespace', // optional - by default, a name will be generated for you }); // later: - +declare const project: codebuild.PipelineProject; new codepipeline_actions.CodeBuildAction({ - // ... + actionName: 'CodeBuild', + project, + input: sourceOutput, environmentVariables: { VERSION_ID: { value: sourceAction.variables.versionId, @@ -273,6 +299,7 @@ To use an ECR Repository as a source in a Pipeline: ```ts import * as ecr from '@aws-cdk/aws-ecr'; +declare const ecrRepository: ecr.Repository; const pipeline = new codepipeline.Pipeline(this, 'MyPipeline'); const sourceOutput = new codepipeline.Artifact(); const sourceAction = new codepipeline_actions.EcrSourceAction({ @@ -290,15 +317,23 @@ pipeline.addStage({ The ECR source action emits variables: ```ts +import * as ecr from '@aws-cdk/aws-ecr'; + +const sourceOutput = new codepipeline.Artifact(); +declare const ecrRepository: ecr.Repository; const sourceAction = new codepipeline_actions.EcrSourceAction({ - // ... + actionName: 'Source', + output: sourceOutput, + repository: ecrRepository, variablesNamespace: 'MyNamespace', // optional - by default, a name will be generated for you }); // later: - +declare const project: codebuild.PipelineProject; new codepipeline_actions.CodeBuildAction({ - // ... + actionName: 'CodeBuild', + project, + input: sourceOutput, environmentVariables: { IMAGE_URI: { value: sourceAction.variables.imageUri, @@ -314,9 +349,7 @@ new codepipeline_actions.CodeBuildAction({ Example of a CodeBuild Project used in a Pipeline, alongside CodeCommit: ```ts -import * as codebuild from '@aws-cdk/aws-codebuild'; -import * as codecommit from '@aws-cdk/aws-codecommit'; - +declare const project: codebuild.PipelineProject; const repository = new codecommit.Repository(this, 'MyRepository', { repositoryName: 'MyRepository', }); @@ -356,6 +389,8 @@ if you want a `Test` Action instead, override the `type` property: ```ts +declare const project: codebuild.PipelineProject; +const sourceOutput = new codepipeline.Artifact(); const testAction = new codepipeline_actions.CodeBuildAction({ actionName: 'IntegrationTest', project, @@ -373,12 +408,14 @@ properties of the `Project` class, you need to use the `extraInputs` and Actions. Example: ```ts +declare const repository1: codecommit.Repository; const sourceOutput1 = new codepipeline.Artifact(); const sourceAction1 = new codepipeline_actions.CodeCommitSourceAction({ actionName: 'Source1', repository: repository1, output: sourceOutput1, }); +declare const repository2: codecommit.Repository; const sourceOutput2 = new codepipeline.Artifact('source2'); const sourceAction2 = new codepipeline_actions.CodeCommitSourceAction({ actionName: 'Source2', @@ -386,6 +423,7 @@ const sourceAction2 = new codepipeline_actions.CodeCommitSourceAction({ output: sourceOutput2, }); +declare const project: codebuild.PipelineProject; const buildAction = new codepipeline_actions.CodeBuildAction({ actionName: 'Build', project, @@ -447,6 +485,7 @@ in the 'exported-variables' subsection of the 'env' section. Example: ```ts +const sourceOutput = new codepipeline.Artifact(); const buildAction = new codepipeline_actions.CodeBuildAction({ actionName: 'Build1', input: sourceOutput, @@ -469,9 +508,11 @@ const buildAction = new codepipeline_actions.CodeBuildAction({ }); // later: - +declare const project: codebuild.PipelineProject; new codepipeline_actions.CodeBuildAction({ - // ... + actionName: 'CodeBuild', + project, + input: sourceOutput, environmentVariables: { MyVar: { value: buildAction.variable('MY_VAR'), @@ -498,7 +539,7 @@ or outside the CDK (in the CodePipeline AWS Console, for example), you can import it: ```ts -const jenkinsProvider = codepipeline_actions.JenkinsProvider.import(this, 'JenkinsProvider', { +const jenkinsProvider = codepipeline_actions.JenkinsProvider.fromJenkinsProviderAttributes(this, 'JenkinsProvider', { providerName: 'MyJenkinsProvider', serverUrl: 'http://my-jenkins.com:8080', version: '2', // optional, default: '1' @@ -514,6 +555,7 @@ With a `JenkinsProvider`, we can create a Jenkins Action: ```ts +declare const jenkinsProvider: codepipeline_actions.JenkinsProvider; const buildAction = new codepipeline_actions.JenkinsAction({ actionName: 'JenkinsBuild', jenkinsProvider: jenkinsProvider, @@ -566,8 +608,12 @@ If you want to update stacks in a different account, pass the `account` property when creating the action: ```ts +const sourceOutput = new codepipeline.Artifact(); new codepipeline_actions.CloudFormationCreateUpdateStackAction({ - // ... + actionName: 'CloudFormationCreateUpdate', + stackName: 'MyStackName', + adminPermissions: true, + templatePath: sourceOutput.atPath('template.yaml'), account: '123456789012', }); ``` @@ -584,15 +630,20 @@ and the action will operate in the same account the role belongs to: import { PhysicalName } from '@aws-cdk/core'; // in stack for account 123456789012... +declare const otherAccountStack: Stack; const actionRole = new iam.Role(otherAccountStack, 'ActionRole', { - assumedBy: new iam.AccountPrincipal(pipelineAccount), + assumedBy: new iam.AccountPrincipal('123456789012'), // the role has to have a physical name set roleName: PhysicalName.GENERATE_IF_NEEDED, }); // in the pipeline stack... +const sourceOutput = new codepipeline.Artifact(); new codepipeline_actions.CloudFormationCreateUpdateStackAction({ - // ... + actionName: 'CloudFormationCreateUpdate', + stackName: 'MyStackName', + adminPermissions: true, + templatePath: sourceOutput.atPath('template.yaml'), role: actionRole, // this action will be cross-account as well }); ``` @@ -604,14 +655,13 @@ new codepipeline_actions.CloudFormationCreateUpdateStackAction({ To use CodeDeploy for EC2/on-premise deployments in a Pipeline: ```ts -import * as codedeploy from '@aws-cdk/aws-codedeploy'; - const pipeline = new codepipeline.Pipeline(this, 'MyPipeline', { pipelineName: 'MyPipeline', }); // add the source and build Stages to the Pipeline... - +const buildOutput = new codepipeline.Artifact(); +declare const deploymentGroup: codedeploy.ServerDeploymentGroup; const deployAction = new codepipeline_actions.CodeDeployServerDeployAction({ actionName: 'CodeDeploy', input: buildOutput, @@ -629,19 +679,19 @@ To use CodeDeploy for blue-green Lambda deployments in a Pipeline: ```ts const lambdaCode = lambda.Code.fromCfnParameters(); -const func = new lambda.Function(lambdaStack, 'Lambda', { +const func = new lambda.Function(this, 'Lambda', { code: lambdaCode, handler: 'index.handler', runtime: lambda.Runtime.NODEJS_12_X, }); // used to make sure each CDK synthesis produces a different Version const version = func.addVersion('NewVersion'); -const alias = new lambda.Alias(lambdaStack, 'LambdaAlias', { +const alias = new lambda.Alias(this, 'LambdaAlias', { aliasName: 'Prod', version, }); -new codedeploy.LambdaDeploymentGroup(lambdaStack, 'DeploymentGroup', { +new codedeploy.LambdaDeploymentGroup(this, 'DeploymentGroup', { alias, deploymentConfig: codedeploy.LambdaDeploymentConfig.LINEAR_10PERCENT_EVERY_1MINUTE, }); @@ -658,6 +708,11 @@ CodePipeline can deploy an ECS service. The deploy Action receives one input Artifact which contains the [image definition file]: ```ts +import * as ecs from '@aws-cdk/aws-ecs'; + +declare const service: ecs.FargateService; +const pipeline = new codepipeline.Pipeline(this, 'MyPipeline'); +const buildOutput = new codepipeline.Artifact(); const deployStage = pipeline.addStage({ stageName: 'Deploy', actions: [ @@ -672,7 +727,7 @@ const deployStage = pipeline.addStage({ // use the `imageFile` property, // and leave out the `input` property imageFile: buildOutput.atPath('imageDef.json'), - deploymentTimeout: cdk.Duration.minutes(60), // optional, default is 60 minutes + deploymentTimeout: Duration.minutes(60), // optional, default is 60 minutes }), ], }); @@ -697,12 +752,12 @@ Here's an example: To use an S3 Bucket as a deployment target in CodePipeline: ```ts -const targetBucket = new s3.Bucket(this, 'MyBucket', {}); +const sourceOutput = new codepipeline.Artifact(); +const targetBucket = new s3.Bucket(this, 'MyBucket'); const pipeline = new codepipeline.Pipeline(this, 'MyPipeline'); const deployAction = new codepipeline_actions.S3DeployAction({ actionName: 'S3Deploy', - stage: deployStage, bucket: targetBucket, input: sourceOutput, }); @@ -720,9 +775,8 @@ and use the AWS CLI to invalidate the cache: ```ts // Create a Cloudfront Web Distribution -const distribution = new cloudfront.Distribution(this, `Distribution`, { - // ... -}); +import * as cloudfront from '@aws-cdk/aws-cloudfront'; +declare const distribution: cloudfront.Distribution; // Create the build project that will invalidate the cache const invalidateBuildProject = new codebuild.PipelineProject(this, `InvalidateProject`, { @@ -752,19 +806,21 @@ invalidateBuildProject.addToRolePolicy(new iam.PolicyStatement({ })); // Create the pipeline (here only the S3 deploy and Invalidate cache build) +const deployBucket = new s3.Bucket(this, 'DeployBucket'); +const deployInput = new codepipeline.Artifact(); new codepipeline.Pipeline(this, 'Pipeline', { stages: [ // ... { stageName: 'Deploy', actions: [ - new codepipelineActions.S3DeployAction({ + new codepipeline_actions.S3DeployAction({ actionName: 'S3Deploy', bucket: deployBucket, input: deployInput, runOrder: 1, }), - new codepipelineActions.CodeBuildAction({ + new codepipeline_actions.CodeBuildAction({ actionName: 'InvalidateCache', project: invalidateBuildProject, input: deployInput, @@ -782,11 +838,12 @@ You can deploy to Alexa using CodePipeline with the following Action: ```ts // Read the secrets from ParameterStore -const clientId = cdk.SecretValue.secretsManager('AlexaClientId'); -const clientSecret = cdk.SecretValue.secretsManager('AlexaClientSecret'); -const refreshToken = cdk.SecretValue.secretsManager('AlexaRefreshToken'); +const clientId = SecretValue.secretsManager('AlexaClientId'); +const clientSecret = SecretValue.secretsManager('AlexaClientSecret'); +const refreshToken = SecretValue.secretsManager('AlexaRefreshToken'); // Add deploy action +const sourceOutput = new codepipeline.Artifact(); new codepipeline_actions.AlexaSkillDeployAction({ actionName: 'DeploySkill', runOrder: 1, @@ -801,20 +858,22 @@ new codepipeline_actions.AlexaSkillDeployAction({ If you need manifest overrides you can specify them as `parameterOverridesArtifact` in the action: ```ts -import * as cloudformation from '@aws-cdk/aws-cloudformation'; - // Deploy some CFN change set and store output const executeOutput = new codepipeline.Artifact('CloudFormation'); const executeChangeSetAction = new codepipeline_actions.CloudFormationExecuteChangeSetAction({ actionName: 'ExecuteChangesTest', runOrder: 2, - stackName, - changeSetName, + stackName: 'MyStack', + changeSetName: 'MyChangeSet', outputFileName: 'overrides.json', output: executeOutput, }); // Provide CFN output as manifest overrides +const clientId = SecretValue.secretsManager('AlexaClientId'); +const clientSecret = SecretValue.secretsManager('AlexaClientSecret'); +const refreshToken = SecretValue.secretsManager('AlexaRefreshToken'); +const sourceOutput = new codepipeline.Artifact(); new codepipeline_actions.AlexaSkillDeployAction({ actionName: 'DeploySkill', runOrder: 1, @@ -832,11 +891,11 @@ new codepipeline_actions.AlexaSkillDeployAction({ You can deploy a CloudFormation template to an existing Service Catalog product with the following Action: ```ts +const cdkBuildOutput = new codepipeline.Artifact(); const serviceCatalogDeployAction = new codepipeline_actions.ServiceCatalogDeployActionBeta1({ actionName: 'ServiceCatalogDeploy', templatePath: cdkBuildOutput.atPath("Sample.template.json"), productVersionName: "Version - " + Date.now.toString, - productType: "CLOUD_FORMATION_TEMPLATE", productVersionDescription: "This is a version from the pipeline with a new description.", productId: "prod-XXXXXXXX", }); @@ -849,6 +908,10 @@ const serviceCatalogDeployAction = new codepipeline_actions.ServiceCatalogDeploy This package contains an Action that stops the Pipeline until someone manually clicks the approve button: ```ts +import * as sns from '@aws-cdk/aws-sns'; + +const pipeline = new codepipeline.Pipeline(this, 'MyPipeline'); +const approveStage = pipeline.addStage({ stageName: 'Approve' }); const manualApprovalAction = new codepipeline_actions.ManualApprovalAction({ actionName: 'Approve', notificationTopic: new sns.Topic(this, 'Topic'), // optional @@ -871,12 +934,14 @@ If you want to grant a principal permissions to approve the changes, you can invoke the method `grantManualApproval` passing it a `IGrantable`: ```ts +const pipeline = new codepipeline.Pipeline(this, 'MyPipeline'); +const approveStage = pipeline.addStage({ stageName: 'Approve' }); const manualApprovalAction = new codepipeline_actions.ManualApprovalAction({ actionName: 'Approve', }); approveStage.addAction(manualApprovalAction); -const role = iam.Role.fromRoleArn(this, 'Admin', Arn.format({ service: 'iam', resource: 'role', resourceName: 'Admin' }, stack)); +const role = iam.Role.fromRoleArn(this, 'Admin', Arn.format({ service: 'iam', resource: 'role', resourceName: 'Admin' }, this)); manualApprovalAction.grantManualApproval(role); ``` @@ -885,8 +950,7 @@ manualApprovalAction.grantManualApproval(role); This module contains an Action that allows you to invoke a Lambda function in a Pipeline: ```ts -import * as lambda from '@aws-cdk/aws-lambda'; - +declare const fn: lambda.Function; const pipeline = new codepipeline.Pipeline(this, 'MyPipeline'); const lambdaAction = new codepipeline_actions.LambdaInvokeAction({ actionName: 'Lambda', @@ -902,7 +966,9 @@ The Lambda Action can have up to 5 inputs, and up to 5 outputs: ```ts - +declare const fn: lambda.Function; +const sourceOutput = new codepipeline.Artifact(); +const buildOutput = new codepipeline.Artifact(); const lambdaAction = new codepipeline_actions.LambdaInvokeAction({ actionName: 'Lambda', inputs: [ @@ -913,7 +979,26 @@ const lambdaAction = new codepipeline_actions.LambdaInvokeAction({ new codepipeline.Artifact('Out1'), new codepipeline.Artifact('Out2'), ], - lambda: fn + lambda: fn, +}); +``` + +The Lambda Action supports custom user parameters that pipeline +will pass to the Lambda function: + +```ts +import * as lambda from '@aws-cdk/aws-lambda'; + +const pipeline = new codepipeline.Pipeline(this, 'MyPipeline'); +const lambdaAction = new codepipeline_actions.LambdaInvokeAction({ + actionName: 'Lambda', + lambda: fn, + userParameters: { + foo: 'bar', + baz: 'qux', + }, + // OR + userParametersString: 'my-parameter-string', }); ``` @@ -924,8 +1009,6 @@ API with the `outputVariables` property filled with the map of variables Example: ```ts -import * as lambda from '@aws-cdk/aws-lambda'; - const lambdaInvokeAction = new codepipeline_actions.LambdaInvokeAction({ actionName: 'Lambda', lambda: new lambda.Function(this, 'Func', { @@ -949,9 +1032,12 @@ const lambdaInvokeAction = new codepipeline_actions.LambdaInvokeAction({ }); // later: - +declare const project: codebuild.PipelineProject; +const sourceOutput = new codepipeline.Artifact(); new codepipeline_actions.CodeBuildAction({ - // ... + actionName: 'CodeBuild', + project, + input: sourceOutput, environmentVariables: { MyVar: { value: lambdaInvokeAction.variable('MY_VAR'), @@ -968,14 +1054,13 @@ on how to write a Lambda function invoked from CodePipeline. This module contains an Action that allows you to invoke a Step Function in a Pipeline: ```ts -import * as stepfunction from '@aws-cdk/aws-stepfunctions'; - +import * as stepfunctions from '@aws-cdk/aws-stepfunctions'; const pipeline = new codepipeline.Pipeline(this, 'MyPipeline'); -const startState = new stepfunction.Pass(stack, 'StartState'); -const simpleStateMachine = new stepfunction.StateMachine(stack, 'SimpleStateMachine', { +const startState = new stepfunctions.Pass(this, 'StartState'); +const simpleStateMachine = new stepfunctions.StateMachine(this, 'SimpleStateMachine', { definition: startState, }); -const stepFunctionAction = new codepipeline_actions.StepFunctionsInvokeAction({ +const stepFunctionAction = new codepipeline_actions.StepFunctionInvokeAction({ actionName: 'Invoke', stateMachine: simpleStateMachine, stateMachineInput: codepipeline_actions.StateMachineInput.literal({ IsHelloWorldExample: true }), @@ -990,15 +1075,15 @@ The `StateMachineInput` can be created with one of 2 static factory methods: `literal`, which takes an arbitrary map as its only argument, or `filePath`: ```ts -import * as stepfunction from '@aws-cdk/aws-stepfunctions'; +import * as stepfunctions from '@aws-cdk/aws-stepfunctions'; const pipeline = new codepipeline.Pipeline(this, 'MyPipeline'); const inputArtifact = new codepipeline.Artifact(); -const startState = new stepfunction.Pass(stack, 'StartState'); -const simpleStateMachine = new stepfunction.StateMachine(stack, 'SimpleStateMachine', { +const startState = new stepfunctions.Pass(this, 'StartState'); +const simpleStateMachine = new stepfunctions.StateMachine(this, 'SimpleStateMachine', { definition: startState, }); -const stepFunctionAction = new codepipeline_actions.StepFunctionsInvokeAction({ +const stepFunctionAction = new codepipeline_actions.StepFunctionInvokeAction({ actionName: 'Invoke', stateMachine: simpleStateMachine, stateMachineInput: codepipeline_actions.StateMachineInput.filePath(inputArtifact.atPath('assets/input.json')), diff --git a/packages/@aws-cdk/aws-codepipeline-actions/jest.config.js b/packages/@aws-cdk/aws-codepipeline-actions/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/jest.config.js +++ b/packages/@aws-cdk/aws-codepipeline-actions/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-codepipeline-actions/lib/lambda/invoke-action.ts b/packages/@aws-cdk/aws-codepipeline-actions/lib/lambda/invoke-action.ts index f8a49d977f6b4..8740d8fafb9ff 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/lib/lambda/invoke-action.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/lib/lambda/invoke-action.ts @@ -38,10 +38,24 @@ export interface LambdaInvokeActionProps extends codepipeline.CommonAwsActionPro * A set of key-value pairs that will be accessible to the invoked Lambda * inside the event that the Pipeline will call it with. * + * Only one of `userParameters` or `userParametersString` can be specified. + * * @see https://docs.aws.amazon.com/codepipeline/latest/userguide/actions-invoke-lambda-function.html#actions-invoke-lambda-function-json-event-example + * @default - no user parameters will be passed */ readonly userParameters?: { [key: string]: any }; + /** + * The string representation of the user parameters that will be + * accessible to the invoked Lambda inside the event + * that the Pipeline will call it with. + * + * Only one of `userParametersString` or `userParameters` can be specified. + * + * @default - no user parameters will be passed + */ + readonly userParametersString?: string; + /** * The lambda function to invoke. */ @@ -71,6 +85,10 @@ export class LambdaInvokeAction extends Action { }); this.props = props; + + if (props.userParameters && props.userParametersString) { + throw new Error('Only one of userParameters or userParametersString can be specified'); + } } /** @@ -121,7 +139,7 @@ export class LambdaInvokeAction extends Action { return { configuration: { FunctionName: this.props.lambda.functionName, - UserParameters: Stack.of(scope).toJsonString(this.props.userParameters), + UserParameters: this.props.userParametersString ?? Stack.of(scope).toJsonString(this.props.userParameters), }, }; } diff --git a/packages/@aws-cdk/aws-codepipeline-actions/package.json b/packages/@aws-cdk/aws-codepipeline-actions/package.json index e2409aa86db6a..6f08ecc470c28 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/package.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/package.json @@ -68,17 +68,17 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", + "@aws-cdk/assert-internal": "0.0.0", "@aws-cdk/aws-cloudtrail": "0.0.0", "@aws-cdk/aws-codestarnotifications": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cx-api": "0.0.0", - "@types/lodash": "^4.14.171", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24", + "@types/lodash": "^4.14.175", "jest": "^26.6.3", - "lodash": "^4.17.21", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "lodash": "^4.17.21" }, "dependencies": { "@aws-cdk/aws-cloudformation": "0.0.0", @@ -180,7 +180,6 @@ }, "maturity": "stable", "cdk-build": { - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } diff --git a/packages/@aws-cdk/aws-codepipeline-actions/rosetta/default.ts-fixture b/packages/@aws-cdk/aws-codepipeline-actions/rosetta/default.ts-fixture new file mode 100644 index 0000000000000..aba6086a1683e --- /dev/null +++ b/packages/@aws-cdk/aws-codepipeline-actions/rosetta/default.ts-fixture @@ -0,0 +1,17 @@ +// Fixture with packages imported, but nothing else +import { Arn, Construct, Duration, SecretValue, Stack } from '@aws-cdk/core'; +import codebuild = require('@aws-cdk/aws-codebuild'); +import codedeploy = require('@aws-cdk/aws-codedeploy'); +import codepipeline = require('@aws-cdk/aws-codepipeline'); +import codepipeline_actions = require('@aws-cdk/aws-codepipeline-actions'); +import codecommit = require('@aws-cdk/aws-codecommit'); +import iam = require('@aws-cdk/aws-iam'); +import lambda = require('@aws-cdk/aws-lambda'); +import s3 = require('@aws-cdk/aws-s3'); + +class Fixture extends Stack { + constructor(scope: Construct, id: string) { + super(scope, id); + /// here + } +} diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.cfn-template-from-repo.lit.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.cfn-template-from-repo.lit.expected.json index 2ce8cf8f817bf..6d5734f005c70 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.cfn-template-from-repo.lit.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.cfn-template-from-repo.lit.expected.json @@ -792,4 +792,4 @@ } } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.lambda-deployed-through-codepipeline.lit.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.lambda-deployed-through-codepipeline.lit.expected.json index 3605965c27ac5..b15857e14cbcd 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.lambda-deployed-through-codepipeline.lit.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.lambda-deployed-through-codepipeline.lit.expected.json @@ -1622,4 +1622,4 @@ } } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.lambda-deployed-through-codepipeline.lit.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.lambda-deployed-through-codepipeline.lit.ts index e631dd6b10c1b..3f9a337333915 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.lambda-deployed-through-codepipeline.lit.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.lambda-deployed-through-codepipeline.lit.ts @@ -124,9 +124,7 @@ pipeline.addStage({ templatePath: cdkBuildOutput.atPath('LambdaStack.template.yaml'), stackName: 'LambdaStackDeployedName', adminPermissions: true, - parameterOverrides: { - ...lambdaCode.assign(lambdaBuildOutput.s3Location), - }, + parameterOverrides: lambdaCode.assign(lambdaBuildOutput.s3Location), extraInputs: [ lambdaBuildOutput, ], diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.lambda-pipeline.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.lambda-pipeline.expected.json index 8f55220a1be97..b925c611a0591 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.lambda-pipeline.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.lambda-pipeline.expected.json @@ -788,4 +788,4 @@ ] } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-alexa-deploy.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-alexa-deploy.expected.json index 74f20ae6271dc..db1378dc62f7c 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-alexa-deploy.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-alexa-deploy.expected.json @@ -393,4 +393,4 @@ } } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-cfn.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-cfn.expected.json index 52df200d381a2..47d57c1301cb4 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-cfn.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-cfn.expected.json @@ -731,4 +731,4 @@ } } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-commit-build.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-commit-build.expected.json index 6292ae43e5811..500a552492eab 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-commit-build.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-commit-build.expected.json @@ -815,4 +815,4 @@ } } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-commit.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-commit.expected.json index fe71ea09ade8d..5bd2974d1ceb8 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-commit.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-commit.expected.json @@ -545,4 +545,4 @@ } } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-events.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-events.expected.json index 7506be08efa70..e50f2326bfa19 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-events.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-events.expected.json @@ -842,4 +842,4 @@ } } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-stepfunctions.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-stepfunctions.expected.json index 142c2c1d92e45..03e04ca5348b1 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-stepfunctions.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-stepfunctions.expected.json @@ -540,4 +540,4 @@ "DeletionPolicy": "Retain" } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/lambda/lambda-invoke-action.test.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/lambda/lambda-invoke-action.test.ts index c3dce7754f70a..41d1b13563235 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/lambda/lambda-invoke-action.test.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/lambda/lambda-invoke-action.test.ts @@ -3,9 +3,9 @@ import * as codepipeline from '@aws-cdk/aws-codepipeline'; import * as lambda from '@aws-cdk/aws-lambda'; import * as s3 from '@aws-cdk/aws-s3'; import * as sns from '@aws-cdk/aws-sns'; +import { testFutureBehavior } from '@aws-cdk/cdk-build-tools/lib/feature-flag'; import { App, Aws, Lazy, SecretValue, Stack, Token } from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; -import { testFutureBehavior } from 'cdk-build-tools/lib/feature-flag'; import * as cpactions from '../../lib'; /* eslint-disable quote-props */ @@ -100,6 +100,36 @@ describe('', () => { }); + test('properly assings userParametersString to UserParameters', () => { + const stack = stackIncludingLambdaInvokeCodePipeline({ + userParamsString: '**/*.template.json', + }); + + expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + 'Stages': [ + {}, + { + 'Actions': [ + { + 'Configuration': { + 'UserParameters': '**/*.template.json', + }, + }, + ], + }, + ], + }); + }); + + test('throws if both userParameters and userParametersString are supplied', () => { + expect(() => stackIncludingLambdaInvokeCodePipeline({ + userParams: { + key: Token.asString(null), + }, + userParamsString: '**/*.template.json', + })).toThrow(/Only one of userParameters or userParametersString can be specified/); + }); + test("assigns the Action's Role with read permissions to the Bucket if it has only inputs", () => { const stack = stackIncludingLambdaInvokeCodePipeline({ lambdaInput: new codepipeline.Artifact(), @@ -302,6 +332,7 @@ describe('', () => { interface HelperProps { readonly userParams?: { [key: string]: any }; + readonly userParamsString?: string; readonly lambdaInput?: codepipeline.Artifact; readonly lambdaOutput?: codepipeline.Artifact; } @@ -334,6 +365,7 @@ function stackIncludingLambdaInvokeCodePipeline(props: HelperProps, app?: App) { runtime: lambda.Runtime.NODEJS_10_X, }), userParameters: props.userParams, + userParametersString: props.userParamsString, inputs: props.lambdaInput ? [props.lambdaInput] : undefined, outputs: props.lambdaOutput ? [props.lambdaOutput] : undefined, }), diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/s3/s3-deploy-action.test.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/s3/s3-deploy-action.test.ts index aa8095678043a..580a4dc688e19 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/s3/s3-deploy-action.test.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/s3/s3-deploy-action.test.ts @@ -3,7 +3,7 @@ import * as codepipeline from '@aws-cdk/aws-codepipeline'; import * as s3 from '@aws-cdk/aws-s3'; import { App, Duration, SecretValue, Stack } from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; -import { testFutureBehavior } from 'cdk-build-tools/lib/feature-flag'; +import { testFutureBehavior } from '@aws-cdk/cdk-build-tools/lib/feature-flag'; import * as cpactions from '../../lib'; /* eslint-disable quote-props */ diff --git a/packages/@aws-cdk/aws-codepipeline/.eslintrc.js b/packages/@aws-cdk/aws-codepipeline/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-codepipeline/.eslintrc.js +++ b/packages/@aws-cdk/aws-codepipeline/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-codepipeline/README.md b/packages/@aws-cdk/aws-codepipeline/README.md index f3f61014cdaa4..23f86b9293e92 100644 --- a/packages/@aws-cdk/aws-codepipeline/README.md +++ b/packages/@aws-cdk/aws-codepipeline/README.md @@ -45,6 +45,17 @@ const pipeline = new codepipeline.Pipeline(this, 'MyFirstPipeline', { }); ``` +If you want to enable key rotation for the generated KMS keys, +you can configure it by passing `enableKeyRotation: true` when creating the pipeline. +Note that key rotation will incur an additional cost of **$1/month**. + +```ts +const pipeline = new codepipeline.Pipeline(this, 'MyFirstPipeline', { + // ... + enableKeyRotation: true, +}); +``` + ## Stages You can provide Stages when creating the Pipeline: diff --git a/packages/@aws-cdk/aws-codepipeline/jest.config.js b/packages/@aws-cdk/aws-codepipeline/jest.config.js index ac8c47076506a..6a8dc8ed67646 100644 --- a/packages/@aws-cdk/aws-codepipeline/jest.config.js +++ b/packages/@aws-cdk/aws-codepipeline/jest.config.js @@ -1,4 +1,4 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = { ...baseConfig, coverageThreshold: { diff --git a/packages/@aws-cdk/aws-codepipeline/lib/pipeline.ts b/packages/@aws-cdk/aws-codepipeline/lib/pipeline.ts index 65b7e84abbf61..f453b0c5748ae 100644 --- a/packages/@aws-cdk/aws-codepipeline/lib/pipeline.ts +++ b/packages/@aws-cdk/aws-codepipeline/lib/pipeline.ts @@ -111,7 +111,7 @@ export interface PipelineProps { readonly stages?: StageProps[]; /** - * Create KMS keys for cross-account deployments + * Create KMS keys for cross-account deployments. * * This controls whether the pipeline is enabled for cross-account deployments. * @@ -126,6 +126,16 @@ export interface PipelineProps { * @default true */ readonly crossAccountKeys?: boolean; + + /** + * Enable KMS key rotation for the generated KMS keys. + * + * By default KMS key rotation is disabled, but will add an additional $1/month + * for each year the key exists when enabled. + * + * @default - false (key rotation is disabled) + */ + readonly enableKeyRotation?: boolean; } abstract class PipelineBase extends Resource implements IPipeline { @@ -317,6 +327,7 @@ export class Pipeline extends PipelineBase { private readonly _crossRegionSupport: { [region: string]: CrossRegionSupport } = {}; private readonly _crossAccountSupport: { [account: string]: Stack } = {}; private readonly crossAccountKeys: boolean; + private readonly enableKeyRotation?: boolean; constructor(scope: Construct, id: string, props: PipelineProps = {}) { super(scope, id, { @@ -330,9 +341,14 @@ export class Pipeline extends PipelineBase { throw new Error('Only one of artifactBucket and crossRegionReplicationBuckets can be specified!'); } - // @deprecated(v2): switch to default false this.crossAccountKeys = props.crossAccountKeys ?? true; + this.enableKeyRotation = props.enableKeyRotation; + + // Cross account keys must be set for key rotation to be enabled + if (this.enableKeyRotation && !this.crossAccountKeys) { + throw new Error("Setting 'enableKeyRotation' to true also requires 'crossAccountKeys' to be enabled"); + } // If a bucket has been provided, use it - otherwise, create a bucket. let propsBucket = this.getArtifactBucketFromProps(props); @@ -345,6 +361,7 @@ export class Pipeline extends PipelineBase { // remove the key - there is a grace period of a few days before it's gone for good, // that should be enough for any emergency access to the bucket artifacts removalPolicy: RemovalPolicy.DESTROY, + enableKeyRotation: this.enableKeyRotation, }); // add an alias to make finding the key in the console easier new kms.Alias(this, 'ArtifactsBucketEncryptionKeyAlias', { @@ -573,8 +590,7 @@ export class Pipeline extends PipelineBase { return crossRegionSupport; } - private createSupportResourcesForRegion(otherStack: Stack | undefined, actionRegion: string): - CrossRegionSupport { + private createSupportResourcesForRegion(otherStack: Stack | undefined, actionRegion: string): CrossRegionSupport { // if we have a stack from the resource passed - use that! if (otherStack) { // check if the stack doesn't have this magic construct already @@ -583,6 +599,7 @@ export class Pipeline extends PipelineBase { if (!crossRegionSupportConstruct) { crossRegionSupportConstruct = new CrossRegionSupportConstruct(otherStack, id, { createKmsKey: this.crossAccountKeys, + enableKeyRotation: this.enableKeyRotation, }); } @@ -609,6 +626,7 @@ export class Pipeline extends PipelineBase { account: pipelineAccount, synthesizer: this.getCrossRegionSupportSynthesizer(), createKmsKey: this.crossAccountKeys, + enableKeyRotation: this.enableKeyRotation, }); } diff --git a/packages/@aws-cdk/aws-codepipeline/lib/private/cross-region-support-stack.ts b/packages/@aws-cdk/aws-codepipeline/lib/private/cross-region-support-stack.ts index e52e6c7f68a40..8072bf422dbc4 100644 --- a/packages/@aws-cdk/aws-codepipeline/lib/private/cross-region-support-stack.ts +++ b/packages/@aws-cdk/aws-codepipeline/lib/private/cross-region-support-stack.ts @@ -44,6 +44,13 @@ export interface CrossRegionSupportConstructProps { * @default true */ readonly createKmsKey?: boolean; + + /** + * Enables KMS key rotation for cross-account keys. + * + * @default - false (key rotation is disabled) + */ + readonly enableKeyRotation?: boolean; } export class CrossRegionSupportConstruct extends Construct { @@ -58,6 +65,7 @@ export class CrossRegionSupportConstruct extends Construct { if (createKmsKey) { const encryptionKey = new kms.Key(this, 'CrossRegionCodePipelineReplicationBucketEncryptionKey', { removalPolicy: cdk.RemovalPolicy.DESTROY, + enableKeyRotation: props.enableKeyRotation, }); encryptionAlias = new AliasWithShorterGeneratedName(this, 'CrossRegionCodePipelineReplicationBucketEncryptionAlias', { targetKey: encryptionKey, @@ -106,6 +114,13 @@ export interface CrossRegionSupportStackProps { * @default true */ readonly createKmsKey?: boolean; + + /** + * Enables KMS key rotation for cross-account keys. + * + * @default - false (key rotation is disabled) + */ + readonly enableKeyRotation?: boolean; } /** @@ -130,6 +145,7 @@ export class CrossRegionSupportStack extends cdk.Stack { const crossRegionSupportConstruct = new CrossRegionSupportConstruct(this, 'Default', { createKmsKey: props.createKmsKey, + enableKeyRotation: props.enableKeyRotation, }); this.replicationBucket = crossRegionSupportConstruct.replicationBucket; } diff --git a/packages/@aws-cdk/aws-codepipeline/package.json b/packages/@aws-cdk/aws-codepipeline/package.json index 0f6ff83649093..5f242010eae8b 100644 --- a/packages/@aws-cdk/aws-codepipeline/package.json +++ b/packages/@aws-cdk/aws-codepipeline/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::CodePipeline", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -78,15 +77,14 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/cx-api": "0.0.0", - "@types/nodeunit": "^0.0.32", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24", + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-codestarnotifications": "0.0.0", diff --git a/packages/@aws-cdk/aws-codepipeline/test/artifacts.test.ts b/packages/@aws-cdk/aws-codepipeline/test/artifacts.test.ts index 5009f5fbdefd0..cf4f733d811be 100644 --- a/packages/@aws-cdk/aws-codepipeline/test/artifacts.test.ts +++ b/packages/@aws-cdk/aws-codepipeline/test/artifacts.test.ts @@ -282,9 +282,9 @@ describe('artifacts', () => { }); }); -/* eslint-disable cdk/no-core-construct */ +/* eslint-disable @aws-cdk/no-core-construct */ function validate(construct: cdk.IConstruct): cdk.ValidationError[] { cdk.ConstructNode.prepare(construct.node); return cdk.ConstructNode.validate(construct.node); } -/* eslint-enable cdk/no-core-construct */ +/* eslint-enable @aws-cdk/no-core-construct */ diff --git a/packages/@aws-cdk/aws-codepipeline/test/pipeline.test.ts b/packages/@aws-cdk/aws-codepipeline/test/pipeline.test.ts index 5a45459030ee7..d25f89ad915a0 100644 --- a/packages/@aws-cdk/aws-codepipeline/test/pipeline.test.ts +++ b/packages/@aws-cdk/aws-codepipeline/test/pipeline.test.ts @@ -389,6 +389,41 @@ describe('', () => { }); + + test('does not allow enabling key rotation if cross account keys have been disabled', () => { + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'PipelineStack'); + + expect(() => { + new codepipeline.Pipeline(stack, 'Pipeline', { + crossAccountKeys: false, + enableKeyRotation: true, + }); + }).toThrow("Setting 'enableKeyRotation' to true also requires 'crossAccountKeys' to be enabled"); + }); + + test("enabling key rotation sets 'EnableKeyRotation' to 'true' in the main generated KMS key", () => { + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'PipelineStack'); + const sourceOutput = new codepipeline.Artifact(); + new codepipeline.Pipeline(stack, 'Pipeline', { + enableKeyRotation: true, + stages: [ + { + stageName: 'Source', + actions: [new FakeSourceAction({ actionName: 'Source', output: sourceOutput })], + }, + { + stageName: 'Build', + actions: [new FakeBuildAction({ actionName: 'Build', input: sourceOutput })], + }, + ], + }); + + expect(stack).toHaveResourceLike('AWS::KMS::Key', { + 'EnableKeyRotation': true, + }); + }); }); }); }); diff --git a/packages/@aws-cdk/aws-codestar/.eslintrc.js b/packages/@aws-cdk/aws-codestar/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-codestar/.eslintrc.js +++ b/packages/@aws-cdk/aws-codestar/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-codestar/jest.config.js b/packages/@aws-cdk/aws-codestar/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-codestar/jest.config.js +++ b/packages/@aws-cdk/aws-codestar/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-codestar/package.json b/packages/@aws-cdk/aws-codestar/package.json index 7740100ab9d29..40edf4f9fe7a6 100644 --- a/packages/@aws-cdk/aws-codestar/package.json +++ b/packages/@aws-cdk/aws-codestar/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::CodeStar", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -76,11 +75,11 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assertions": "0.0.0", - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/aws-s3": "0.0.0", diff --git a/packages/@aws-cdk/aws-codestarconnections/.eslintrc.js b/packages/@aws-cdk/aws-codestarconnections/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-codestarconnections/.eslintrc.js +++ b/packages/@aws-cdk/aws-codestarconnections/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-codestarconnections/jest.config.js b/packages/@aws-cdk/aws-codestarconnections/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-codestarconnections/jest.config.js +++ b/packages/@aws-cdk/aws-codestarconnections/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-codestarconnections/package.json b/packages/@aws-cdk/aws-codestarconnections/package.json index 76e45df893762..4c60595599eb8 100644 --- a/packages/@aws-cdk/aws-codestarconnections/package.json +++ b/packages/@aws-cdk/aws-codestarconnections/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::CodeStarConnections", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-codestarnotifications/.eslintrc.js b/packages/@aws-cdk/aws-codestarnotifications/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-codestarnotifications/.eslintrc.js +++ b/packages/@aws-cdk/aws-codestarnotifications/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-codestarnotifications/jest.config.js b/packages/@aws-cdk/aws-codestarnotifications/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-codestarnotifications/jest.config.js +++ b/packages/@aws-cdk/aws-codestarnotifications/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-codestarnotifications/package.json b/packages/@aws-cdk/aws-codestarnotifications/package.json index 81460dd341e68..ec43414e43e45 100644 --- a/packages/@aws-cdk/aws-codestarnotifications/package.json +++ b/packages/@aws-cdk/aws-codestarnotifications/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::CodeStarNotifications", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,12 +74,12 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-cognito/.eslintrc.js b/packages/@aws-cdk/aws-cognito/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-cognito/.eslintrc.js +++ b/packages/@aws-cdk/aws-cognito/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-cognito/README.md b/packages/@aws-cdk/aws-cognito/README.md index b015607589652..2315662f49d10 100644 --- a/packages/@aws-cdk/aws-cognito/README.md +++ b/packages/@aws-cdk/aws-cognito/README.md @@ -108,7 +108,7 @@ new cognito.UserPool(this, 'myuserpool', { userInvitation: { emailSubject: 'Invite to join our awesome app!', emailBody: 'Hello {username}, you have been invited to join our awesome app! Your temporary password is {####}', - smsMessage: 'Your temporary password for our awesome app is {####}' + smsMessage: 'Hello {username}, your temporary password for our awesome app is {####}' } }); ``` diff --git a/packages/@aws-cdk/aws-cognito/jest.config.js b/packages/@aws-cdk/aws-cognito/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-cognito/jest.config.js +++ b/packages/@aws-cdk/aws-cognito/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-cognito/package.json b/packages/@aws-cdk/aws-cognito/package.json index 56cd465f17680..8b280b238a8d4 100644 --- a/packages/@aws-cdk/aws-cognito/package.json +++ b/packages/@aws-cdk/aws-cognito/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::Cognito", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,14 +72,14 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", "@types/punycode": "^2.1.0", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-certificatemanager": "0.0.0", diff --git a/packages/@aws-cdk/aws-cognito/test/user-pool-client.test.ts b/packages/@aws-cdk/aws-cognito/test/user-pool-client.test.ts index d6fc81f28c43c..2d2a72d48f767 100644 --- a/packages/@aws-cdk/aws-cognito/test/user-pool-client.test.ts +++ b/packages/@aws-cdk/aws-cognito/test/user-pool-client.test.ts @@ -63,7 +63,7 @@ describe('User Pool Client', () => { // THEN Template.fromStack(stack).hasResourceProperties('AWS::Cognito::UserPoolClient', { - ExplicitAuthFlows: Match.absentProperty(), + ExplicitAuthFlows: Match.absent(), }); }); @@ -179,7 +179,7 @@ describe('User Pool Client', () => { Template.fromStack(stack).hasResourceProperties('AWS::Cognito::UserPoolClient', { AllowedOAuthFlows: ['client_credentials'], - CallbackURLs: Match.absentProperty(), + CallbackURLs: Match.absent(), }); Template.fromStack(stack).hasResourceProperties('AWS::Cognito::UserPoolClient', { @@ -206,7 +206,7 @@ describe('User Pool Client', () => { // THEN Template.fromStack(stack).hasResourceProperties('AWS::Cognito::UserPoolClient', { - CallbackURLs: Match.absentProperty(), + CallbackURLs: Match.absent(), }); }); @@ -447,7 +447,7 @@ describe('User Pool Client', () => { // THEN Template.fromStack(stack).hasResourceProperties('AWS::Cognito::UserPoolClient', { UserPoolId: stack.resolve(pool.userPoolId), - PreventUserExistenceErrors: Match.absentProperty(), + PreventUserExistenceErrors: Match.absent(), }); }); @@ -515,8 +515,8 @@ describe('User Pool Client', () => { // THEN Template.fromStack(stack).hasResourceProperties('AWS::Cognito::UserPoolClient', { ClientName: 'OAuthDisabled', - AllowedOAuthFlows: Match.absentProperty(), - AllowedOAuthScopes: Match.absentProperty(), + AllowedOAuthFlows: Match.absent(), + AllowedOAuthScopes: Match.absent(), AllowedOAuthFlowsUserPoolClient: false, }); Template.fromStack(stack).hasResourceProperties('AWS::Cognito::UserPoolClient', { @@ -551,7 +551,7 @@ describe('User Pool Client', () => { // THEN Template.fromStack(stack).hasResourceProperties('AWS::Cognito::UserPoolClient', { - EnableTokenRevocation: Match.absentProperty(), + EnableTokenRevocation: Match.absent(), }); }); @@ -632,42 +632,42 @@ describe('User Pool Client', () => { Template.fromStack(stack).hasResourceProperties('AWS::Cognito::UserPoolClient', { ClientName: 'Client2', AccessTokenValidity: 60, - IdTokenValidity: Match.absentProperty(), - RefreshTokenValidity: Match.absentProperty(), + IdTokenValidity: Match.absent(), + RefreshTokenValidity: Match.absent(), TokenValidityUnits: { AccessToken: 'minutes', - IdToken: Match.absentProperty(), - RefreshToken: Match.absentProperty(), + IdToken: Match.absent(), + RefreshToken: Match.absent(), }, }); Template.fromStack(stack).hasResourceProperties('AWS::Cognito::UserPoolClient', { ClientName: 'Client3', - AccessTokenValidity: Match.absentProperty(), + AccessTokenValidity: Match.absent(), IdTokenValidity: 60, - RefreshTokenValidity: Match.absentProperty(), + RefreshTokenValidity: Match.absent(), TokenValidityUnits: { - AccessToken: Match.absentProperty(), + AccessToken: Match.absent(), IdToken: 'minutes', - RefreshToken: Match.absentProperty(), + RefreshToken: Match.absent(), }, }); Template.fromStack(stack).hasResourceProperties('AWS::Cognito::UserPoolClient', { ClientName: 'Client4', - AccessTokenValidity: Match.absentProperty(), - IdTokenValidity: Match.absentProperty(), + AccessTokenValidity: Match.absent(), + IdTokenValidity: Match.absent(), RefreshTokenValidity: 43200, TokenValidityUnits: { - AccessToken: Match.absentProperty(), - IdToken: Match.absentProperty(), + AccessToken: Match.absent(), + IdToken: Match.absent(), RefreshToken: 'minutes', }, }); Template.fromStack(stack).hasResourceProperties('AWS::Cognito::UserPoolClient', { ClientName: 'Client5', - TokenValidityUnits: Match.absentProperty(), - IdTokenValidity: Match.absentProperty(), - RefreshTokenValidity: Match.absentProperty(), - AccessTokenValidity: Match.absentProperty(), + TokenValidityUnits: Match.absent(), + IdTokenValidity: Match.absent(), + RefreshTokenValidity: Match.absent(), + AccessTokenValidity: Match.absent(), }); }); @@ -886,8 +886,8 @@ describe('User Pool Client', () => { // EXPECT Template.fromStack(stack).hasResourceProperties('AWS::Cognito::UserPoolClient', { - ReadAttributes: Match.absentProperty(), - WriteAttributes: Match.absentProperty(), + ReadAttributes: Match.absent(), + WriteAttributes: Match.absent(), }); }); diff --git a/packages/@aws-cdk/aws-cognito/test/user-pool.test.ts b/packages/@aws-cdk/aws-cognito/test/user-pool.test.ts index 0c61312222355..7b132803da2d6 100644 --- a/packages/@aws-cdk/aws-cognito/test/user-pool.test.ts +++ b/packages/@aws-cdk/aws-cognito/test/user-pool.test.ts @@ -17,7 +17,7 @@ describe('User Pool', () => { Template.fromStack(stack).hasResourceProperties('AWS::Cognito::UserPool', { AdminCreateUserConfig: { AllowAdminCreateUserOnly: true, - InviteMessageTemplate: Match.absentProperty(), + InviteMessageTemplate: Match.absent(), }, EmailVerificationMessage: 'The verification code to your new account is {####}', EmailVerificationSubject: 'Verify your new account', @@ -28,9 +28,9 @@ describe('User Pool', () => { EmailSubject: 'Verify your new account', SmsMessage: 'The verification code to your new account is {####}', }, - SmsAuthenticationMessage: Match.absentProperty(), - SmsConfiguration: Match.absentProperty(), - lambdaTriggers: Match.absentProperty(), + SmsAuthenticationMessage: Match.absent(), + SmsConfiguration: Match.absent(), + lambdaTriggers: Match.absent(), }); Template.fromStack(stack).hasResource('AWS::Cognito::UserPool', { @@ -68,8 +68,8 @@ describe('User Pool', () => { // THEN Template.fromStack(stack).hasResourceProperties('AWS::Cognito::UserPool', { - EmailVerificationMessage: Match.absentProperty(), - EmailVerificationSubject: Match.absentProperty(), + EmailVerificationMessage: Match.absent(), + EmailVerificationSubject: Match.absent(), SmsVerificationMessage: 'The verification code to your new account is {####}', VerificationMessageTemplate: { DefaultEmailOption: 'CONFIRM_WITH_LINK', @@ -415,8 +415,8 @@ describe('User Pool', () => { // THEN Template.fromStack(stack).hasResourceProperties('AWS::Cognito::UserPool', { - UsernameAttributes: Match.absentProperty(), - AliasAttributes: Match.absentProperty(), + UsernameAttributes: Match.absent(), + AliasAttributes: Match.absent(), }); }); @@ -438,7 +438,7 @@ describe('User Pool', () => { // THEN Template.fromStack(stack).hasResourceProperties('AWS::Cognito::UserPool', { - UsernameAttributes: Match.absentProperty(), + UsernameAttributes: Match.absent(), AliasAttributes: ['email'], }); }); @@ -455,7 +455,7 @@ describe('User Pool', () => { // THEN Template.fromStack(stack).hasResourceProperties('AWS::Cognito::UserPool', { UsernameAttributes: ['email', 'phone_number'], - AliasAttributes: Match.absentProperty(), + AliasAttributes: Match.absent(), }); }); @@ -526,7 +526,7 @@ describe('User Pool', () => { // THEN Template.fromStack(stack).hasResourceProperties('AWS::Cognito::UserPool', { - UsernameConfiguration: Match.absentProperty(), + UsernameConfiguration: Match.absent(), }); }); @@ -638,7 +638,7 @@ describe('User Pool', () => { // THEN Template.fromStack(stack).hasResourceProperties('AWS::Cognito::UserPool', { UserPoolName: 'Pool', - Schema: Match.absentProperty(), + Schema: Match.absent(), }); }); @@ -687,14 +687,14 @@ describe('User Pool', () => { { Name: 'custom-string-attr', AttributeDataType: 'String', - StringAttributeConstraints: Match.absentProperty(), - NumberAttributeConstraints: Match.absentProperty(), + StringAttributeConstraints: Match.absent(), + NumberAttributeConstraints: Match.absent(), }, { Name: 'custom-number-attr', AttributeDataType: 'Number', - StringAttributeConstraints: Match.absentProperty(), - NumberAttributeConstraints: Match.absentProperty(), + StringAttributeConstraints: Match.absent(), + NumberAttributeConstraints: Match.absent(), }, ], }); @@ -759,13 +759,13 @@ describe('User Pool', () => { // THEN Template.fromStack(stack).hasResourceProperties('AWS::Cognito::UserPool', { UserPoolName: 'Pool1', - MfaConfiguration: Match.absentProperty(), - EnabledMfas: Match.absentProperty(), + MfaConfiguration: Match.absent(), + EnabledMfas: Match.absent(), }); Template.fromStack(stack).hasResourceProperties('AWS::Cognito::UserPool', { UserPoolName: 'Pool2', MfaConfiguration: 'OFF', - EnabledMfas: Match.absentProperty(), + EnabledMfas: Match.absent(), }); }); @@ -1120,7 +1120,7 @@ describe('User Pool', () => { // THEN Template.fromStack(stack).hasResourceProperties('AWS::Cognito::UserPool', { - AccountRecoverySetting: Match.absentProperty(), + AccountRecoverySetting: Match.absent(), }); }); @@ -1153,7 +1153,7 @@ describe('User Pool', () => { // THEN Template.fromStack(stack).hasResourceProperties('AWS::Cognito::UserPool', { - SmsConfiguration: Match.absentProperty(), + SmsConfiguration: Match.absent(), }); }); @@ -1245,7 +1245,7 @@ describe('User Pool', () => { // THEN Template.fromStack(stack).hasResourceProperties('AWS::Cognito::UserPool', { - SmsConfiguration: Match.absentProperty(), + SmsConfiguration: Match.absent(), }); }); @@ -1267,7 +1267,7 @@ describe('User Pool', () => { // THEN Template.fromStack(stack).hasResourceProperties('AWS::Cognito::UserPool', { - SmsConfiguration: Match.absentProperty(), + SmsConfiguration: Match.absent(), }); }); @@ -1351,7 +1351,7 @@ describe('User Pool', () => { // THEN Template.fromStack(stack).hasResourceProperties('AWS::Cognito::UserPool', { - SmsConfiguration: Match.absentProperty(), + SmsConfiguration: Match.absent(), }); }); diff --git a/packages/@aws-cdk/aws-config/.eslintrc.js b/packages/@aws-cdk/aws-config/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-config/.eslintrc.js +++ b/packages/@aws-cdk/aws-config/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-config/jest.config.js b/packages/@aws-cdk/aws-config/jest.config.js index f5d5c4c8ad18f..34818e1593f6b 100644 --- a/packages/@aws-cdk/aws-config/jest.config.js +++ b/packages/@aws-cdk/aws-config/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); -module.exports = baseConfig; \ No newline at end of file +const baseConfig = require('../../../tools/@aws-cdk/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-config/lib/rule.ts b/packages/@aws-cdk/aws-config/lib/rule.ts index 05ecebe7d93e5..e1ac4d107ec9e 100644 --- a/packages/@aws-cdk/aws-config/lib/rule.ts +++ b/packages/@aws-cdk/aws-config/lib/rule.ts @@ -355,6 +355,7 @@ export class CustomRule extends RuleNew { props.lambdaFunction.addPermission('Permission', { principal: new iam.ServicePrincipal('config.amazonaws.com'), + sourceAccount: this.env.account, }); if (props.lambdaFunction.role) { diff --git a/packages/@aws-cdk/aws-config/package.json b/packages/@aws-cdk/aws-config/package.json index ee4205b4d9241..1f6458201763a 100644 --- a/packages/@aws-cdk/aws-config/package.json +++ b/packages/@aws-cdk/aws-config/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::Config", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,14 +72,14 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", "@aws-cdk/aws-events-targets": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-events": "0.0.0", diff --git a/packages/@aws-cdk/aws-config/test/integ.rule.lit.expected.json b/packages/@aws-cdk/aws-config/test/integ.rule.lit.expected.json index 234f54351bcd1..172382853b95f 100644 --- a/packages/@aws-cdk/aws-config/test/integ.rule.lit.expected.json +++ b/packages/@aws-cdk/aws-config/test/integ.rule.lit.expected.json @@ -72,7 +72,10 @@ "Arn" ] }, - "Principal": "config.amazonaws.com" + "Principal": "config.amazonaws.com", + "SourceAccount": { + "Ref": "AWS::AccountId" + } } }, "Custom8166710A": { @@ -221,4 +224,4 @@ } } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-config/test/integ.scoped-rule.expected.json b/packages/@aws-cdk/aws-config/test/integ.scoped-rule.expected.json index 99d314d0c45af..fced1ede4a8f5 100644 --- a/packages/@aws-cdk/aws-config/test/integ.scoped-rule.expected.json +++ b/packages/@aws-cdk/aws-config/test/integ.scoped-rule.expected.json @@ -72,7 +72,10 @@ "Arn" ] }, - "Principal": "config.amazonaws.com" + "Principal": "config.amazonaws.com", + "SourceAccount": { + "Ref": "AWS::AccountId" + } } }, "Custom8166710A": { @@ -106,4 +109,4 @@ ] } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-config/test/rule.test.ts b/packages/@aws-cdk/aws-config/test/rule.test.ts index 77599b8d95308..259727982a330 100644 --- a/packages/@aws-cdk/aws-config/test/rule.test.ts +++ b/packages/@aws-cdk/aws-config/test/rule.test.ts @@ -101,6 +101,9 @@ describe('rule', () => { expect(stack).toHaveResource('AWS::Lambda::Permission', { Principal: 'config.amazonaws.com', + SourceAccount: { + Ref: 'AWS::AccountId', + }, }); expect(stack).toHaveResource('AWS::IAM::Role', { diff --git a/packages/@aws-cdk/aws-connect/.eslintrc.js b/packages/@aws-cdk/aws-connect/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-connect/.eslintrc.js +++ b/packages/@aws-cdk/aws-connect/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-connect/jest.config.js b/packages/@aws-cdk/aws-connect/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-connect/jest.config.js +++ b/packages/@aws-cdk/aws-connect/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-connect/package.json b/packages/@aws-cdk/aws-connect/package.json index 93d08397cf375..d1ec993751e42 100644 --- a/packages/@aws-cdk/aws-connect/package.json +++ b/packages/@aws-cdk/aws-connect/package.json @@ -58,7 +58,6 @@ }, "cdk-build": { "cloudformation": "AWS::Connect", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -77,11 +76,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", "@aws-cdk/assertions": "0.0.0", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-cur/.eslintrc.js b/packages/@aws-cdk/aws-cur/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-cur/.eslintrc.js +++ b/packages/@aws-cdk/aws-cur/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-cur/jest.config.js b/packages/@aws-cdk/aws-cur/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-cur/jest.config.js +++ b/packages/@aws-cdk/aws-cur/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-cur/package.json b/packages/@aws-cdk/aws-cur/package.json index 8969e73dc4399..73ce922bae440 100644 --- a/packages/@aws-cdk/aws-cur/package.json +++ b/packages/@aws-cdk/aws-cur/package.json @@ -58,7 +58,6 @@ }, "cdk-build": { "cloudformation": "AWS::CUR", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -77,11 +76,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", "@aws-cdk/assertions": "0.0.0", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-customerprofiles/.eslintrc.js b/packages/@aws-cdk/aws-customerprofiles/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-customerprofiles/.eslintrc.js +++ b/packages/@aws-cdk/aws-customerprofiles/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-customerprofiles/jest.config.js b/packages/@aws-cdk/aws-customerprofiles/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-customerprofiles/jest.config.js +++ b/packages/@aws-cdk/aws-customerprofiles/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-customerprofiles/package.json b/packages/@aws-cdk/aws-customerprofiles/package.json index 36ccdda69b39d..b05870683b8bf 100644 --- a/packages/@aws-cdk/aws-customerprofiles/package.json +++ b/packages/@aws-cdk/aws-customerprofiles/package.json @@ -58,7 +58,6 @@ }, "cdk-build": { "cloudformation": "AWS::CustomerProfiles", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -78,10 +77,10 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assertions": "0.0.0", - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-databrew/.eslintrc.js b/packages/@aws-cdk/aws-databrew/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-databrew/.eslintrc.js +++ b/packages/@aws-cdk/aws-databrew/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-databrew/jest.config.js b/packages/@aws-cdk/aws-databrew/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-databrew/jest.config.js +++ b/packages/@aws-cdk/aws-databrew/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-databrew/package.json b/packages/@aws-cdk/aws-databrew/package.json index bf710a7394d74..9c9ae300c4044 100644 --- a/packages/@aws-cdk/aws-databrew/package.json +++ b/packages/@aws-cdk/aws-databrew/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::DataBrew", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-datapipeline/.eslintrc.js b/packages/@aws-cdk/aws-datapipeline/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-datapipeline/.eslintrc.js +++ b/packages/@aws-cdk/aws-datapipeline/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-datapipeline/jest.config.js b/packages/@aws-cdk/aws-datapipeline/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-datapipeline/jest.config.js +++ b/packages/@aws-cdk/aws-datapipeline/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-datapipeline/package.json b/packages/@aws-cdk/aws-datapipeline/package.json index b0c4cf9bf3218..9c4e850b6f90c 100644 --- a/packages/@aws-cdk/aws-datapipeline/package.json +++ b/packages/@aws-cdk/aws-datapipeline/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::DataPipeline", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,11 +72,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-datasync/.eslintrc.js b/packages/@aws-cdk/aws-datasync/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-datasync/.eslintrc.js +++ b/packages/@aws-cdk/aws-datasync/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-datasync/jest.config.js b/packages/@aws-cdk/aws-datasync/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-datasync/jest.config.js +++ b/packages/@aws-cdk/aws-datasync/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-datasync/package.json b/packages/@aws-cdk/aws-datasync/package.json index 3ec205f0d6ee1..80db2e21342e6 100644 --- a/packages/@aws-cdk/aws-datasync/package.json +++ b/packages/@aws-cdk/aws-datasync/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::DataSync", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-dax/.eslintrc.js b/packages/@aws-cdk/aws-dax/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-dax/.eslintrc.js +++ b/packages/@aws-cdk/aws-dax/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-dax/jest.config.js b/packages/@aws-cdk/aws-dax/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-dax/jest.config.js +++ b/packages/@aws-cdk/aws-dax/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-dax/package.json b/packages/@aws-cdk/aws-dax/package.json index 82d88fd70d8d1..e7cc80850e2a6 100644 --- a/packages/@aws-cdk/aws-dax/package.json +++ b/packages/@aws-cdk/aws-dax/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::DAX", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,11 +72,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-detective/.eslintrc.js b/packages/@aws-cdk/aws-detective/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-detective/.eslintrc.js +++ b/packages/@aws-cdk/aws-detective/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-detective/jest.config.js b/packages/@aws-cdk/aws-detective/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-detective/jest.config.js +++ b/packages/@aws-cdk/aws-detective/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-detective/package.json b/packages/@aws-cdk/aws-detective/package.json index 3955b883cb2bf..4e7eb64080103 100644 --- a/packages/@aws-cdk/aws-detective/package.json +++ b/packages/@aws-cdk/aws-detective/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::Detective", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-devopsguru/.eslintrc.js b/packages/@aws-cdk/aws-devopsguru/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-devopsguru/.eslintrc.js +++ b/packages/@aws-cdk/aws-devopsguru/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-devopsguru/jest.config.js b/packages/@aws-cdk/aws-devopsguru/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-devopsguru/jest.config.js +++ b/packages/@aws-cdk/aws-devopsguru/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-devopsguru/package.json b/packages/@aws-cdk/aws-devopsguru/package.json index 9c9ff7fdb0228..0434c473a8862 100644 --- a/packages/@aws-cdk/aws-devopsguru/package.json +++ b/packages/@aws-cdk/aws-devopsguru/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::DevOpsGuru", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-directoryservice/.eslintrc.js b/packages/@aws-cdk/aws-directoryservice/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-directoryservice/.eslintrc.js +++ b/packages/@aws-cdk/aws-directoryservice/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-directoryservice/jest.config.js b/packages/@aws-cdk/aws-directoryservice/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-directoryservice/jest.config.js +++ b/packages/@aws-cdk/aws-directoryservice/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-directoryservice/package.json b/packages/@aws-cdk/aws-directoryservice/package.json index 1396430e3a34a..0f5d849fd4b1f 100644 --- a/packages/@aws-cdk/aws-directoryservice/package.json +++ b/packages/@aws-cdk/aws-directoryservice/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::DirectoryService", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,11 +72,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-dlm/.eslintrc.js b/packages/@aws-cdk/aws-dlm/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-dlm/.eslintrc.js +++ b/packages/@aws-cdk/aws-dlm/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-dlm/jest.config.js b/packages/@aws-cdk/aws-dlm/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-dlm/jest.config.js +++ b/packages/@aws-cdk/aws-dlm/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-dlm/package.json b/packages/@aws-cdk/aws-dlm/package.json index 84fd44d939683..d8baae91ee532 100644 --- a/packages/@aws-cdk/aws-dlm/package.json +++ b/packages/@aws-cdk/aws-dlm/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::DLM", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -74,11 +73,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-dms/.eslintrc.js b/packages/@aws-cdk/aws-dms/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-dms/.eslintrc.js +++ b/packages/@aws-cdk/aws-dms/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-dms/jest.config.js b/packages/@aws-cdk/aws-dms/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-dms/jest.config.js +++ b/packages/@aws-cdk/aws-dms/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-dms/package.json b/packages/@aws-cdk/aws-dms/package.json index d1ba735745e55..366911bc7129c 100644 --- a/packages/@aws-cdk/aws-dms/package.json +++ b/packages/@aws-cdk/aws-dms/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::DMS", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,11 +72,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-docdb/.eslintrc.js b/packages/@aws-cdk/aws-docdb/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-docdb/.eslintrc.js +++ b/packages/@aws-cdk/aws-docdb/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-docdb/jest.config.js b/packages/@aws-cdk/aws-docdb/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-docdb/jest.config.js +++ b/packages/@aws-cdk/aws-docdb/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-docdb/package.json b/packages/@aws-cdk/aws-docdb/package.json index 472f2a229215c..cc8a7bb9802a3 100644 --- a/packages/@aws-cdk/aws-docdb/package.json +++ b/packages/@aws-cdk/aws-docdb/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::DocDB", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,24 +74,24 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { - "@aws-cdk/aws-efs": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", + "@aws-cdk/aws-efs": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/aws-secretsmanager": "0.0.0", "@aws-cdk/core": "0.0.0", "constructs": "^3.3.69" }, "peerDependencies": { - "@aws-cdk/aws-efs": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", + "@aws-cdk/aws-efs": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/aws-secretsmanager": "0.0.0", "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-dynamodb-global/.eslintrc.js b/packages/@aws-cdk/aws-dynamodb-global/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-dynamodb-global/.eslintrc.js +++ b/packages/@aws-cdk/aws-dynamodb-global/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-dynamodb-global/jest.config.js b/packages/@aws-cdk/aws-dynamodb-global/jest.config.js index f5d5c4c8ad18f..34818e1593f6b 100644 --- a/packages/@aws-cdk/aws-dynamodb-global/jest.config.js +++ b/packages/@aws-cdk/aws-dynamodb-global/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); -module.exports = baseConfig; \ No newline at end of file +const baseConfig = require('../../../tools/@aws-cdk/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-dynamodb-global/lambda-packages/aws-global-table-coordinator/package.json b/packages/@aws-cdk/aws-dynamodb-global/lambda-packages/aws-global-table-coordinator/package.json index 130fed06d99c7..8e4e5cd1e6ff8 100644 --- a/packages/@aws-cdk/aws-dynamodb-global/lambda-packages/aws-global-table-coordinator/package.json +++ b/packages/@aws-cdk/aws-dynamodb-global/lambda-packages/aws-global-table-coordinator/package.json @@ -1,5 +1,5 @@ { - "name": "aws-global-lambda-coordinator", + "name": "@aws-cdk/aws-global-lambda-coordinator", "private": true, "version": "0.0.0", "description": "This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project.", @@ -30,15 +30,15 @@ "license": "Apache-2.0", "devDependencies": { "aws-sdk": "^2.596.0", - "aws-sdk-mock": "^5.2.1", - "eslint": "^7.31.0", + "aws-sdk-mock": "^5.4.0", + "eslint": "^7.32.0", "eslint-config-standard": "^14.1.1", - "eslint-plugin-import": "^2.23.4", + "eslint-plugin-import": "^2.25.2", "eslint-plugin-node": "^11.1.0", "eslint-plugin-promise": "^4.3.1", "eslint-plugin-standard": "^4.1.0", "jest": "^26.6.3", "lambda-tester": "^3.6.0", - "nock": "^13.1.1" + "nock": "^13.1.3" } } diff --git a/packages/@aws-cdk/aws-dynamodb-global/lib/global-table-coordinator.ts b/packages/@aws-cdk/aws-dynamodb-global/lib/global-table-coordinator.ts index 924c84b9237f1..8605e36fda54b 100644 --- a/packages/@aws-cdk/aws-dynamodb-global/lib/global-table-coordinator.ts +++ b/packages/@aws-cdk/aws-dynamodb-global/lib/global-table-coordinator.ts @@ -19,7 +19,7 @@ export class GlobalTableCoordinator extends cdk.Stack { code: lambda.Code.fromAsset(path.resolve(__dirname, '../', 'lambda-packages', 'aws-global-table-coordinator', 'lib')), description: 'Lambda to make DynamoDB a global table', handler: 'index.handler', - runtime: lambda.Runtime.NODEJS_14_X, + runtime: lambda.Runtime.NODEJS_12_X, timeout: cdk.Duration.minutes(5), uuid: 'D38B65A6-6B54-4FB6-9BAD-9CD40A6DAC12', }); diff --git a/packages/@aws-cdk/aws-dynamodb-global/package.json b/packages/@aws-cdk/aws-dynamodb-global/package.json index 4f55047bb9b95..4c0f401086469 100644 --- a/packages/@aws-cdk/aws-dynamodb-global/package.json +++ b/packages/@aws-cdk/aws-dynamodb-global/package.json @@ -41,9 +41,6 @@ }, "projectReferences": true }, - "cdk-build": { - "jest": true - }, "keywords": [ "aws", "cdk", @@ -59,12 +56,12 @@ "constructs": "^3.3.69" }, "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "jest": "^26.6.3" }, "peerDependencies": { "@aws-cdk/aws-dynamodb": "0.0.0", diff --git a/packages/@aws-cdk/aws-dynamodb-global/test/integ.dynamodb.global.expected.json b/packages/@aws-cdk/aws-dynamodb-global/test/integ.dynamodb.global.expected.json index b4dfc40358bd1..3aab4c4f3a64b 100644 --- a/packages/@aws-cdk/aws-dynamodb-global/test/integ.dynamodb.global.expected.json +++ b/packages/@aws-cdk/aws-dynamodb-global/test/integ.dynamodb.global.expected.json @@ -202,10 +202,9 @@ "Arn" ] }, - "Runtime": "nodejs14.x", "Description": "Lambda to make DynamoDB a global table", "Handler": "index.handler", - "Runtime": "nodejs14.x", + "Runtime": "nodejs12.x", "Timeout": 300 }, "DependsOn": [ diff --git a/packages/@aws-cdk/aws-dynamodb/.eslintrc.js b/packages/@aws-cdk/aws-dynamodb/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-dynamodb/.eslintrc.js +++ b/packages/@aws-cdk/aws-dynamodb/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-dynamodb/jest.config.js b/packages/@aws-cdk/aws-dynamodb/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-dynamodb/jest.config.js +++ b/packages/@aws-cdk/aws-dynamodb/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-dynamodb/lib/replica-handler/index.ts b/packages/@aws-cdk/aws-dynamodb/lib/replica-handler/index.ts index 1554dcc84004d..38109b1a4a614 100644 --- a/packages/@aws-cdk/aws-dynamodb/lib/replica-handler/index.ts +++ b/packages/@aws-cdk/aws-dynamodb/lib/replica-handler/index.ts @@ -49,12 +49,13 @@ export async function isCompleteHandler(event: IsCompleteRequest): Promise r.RegionName === event.ResourceProperties.Region); const replicaActive = !!(regionReplica?.ReplicaStatus === 'ACTIVE'); + const skipReplicationCompletedWait = event.ResourceProperties.SkipReplicationCompletedWait ?? false; switch (event.RequestType) { case 'Create': case 'Update': // Complete when replica is reported as ACTIVE - return { IsComplete: tableActive && replicaActive }; + return { IsComplete: tableActive && (replicaActive || skipReplicationCompletedWait) }; case 'Delete': // Complete when replica is gone return { IsComplete: tableActive && regionReplica === undefined }; diff --git a/packages/@aws-cdk/aws-dynamodb/lib/table.ts b/packages/@aws-cdk/aws-dynamodb/lib/table.ts index a2b1aae5ee2eb..10a7472be3c0d 100644 --- a/packages/@aws-cdk/aws-dynamodb/lib/table.ts +++ b/packages/@aws-cdk/aws-dynamodb/lib/table.ts @@ -231,6 +231,22 @@ export interface TableOptions extends SchemaOptions { */ readonly replicationTimeout?: Duration; + /** + * Indicates whether CloudFormation stack waits for replication to finish. + * If set to false, the CloudFormation resource will mark the resource as + * created and replication will be completed asynchronously. This property is + * ignored if replicationRegions property is not set. + * + * DO NOT UNSET this property if adding/removing multiple replicationRegions + * in one deployment, as CloudFormation only supports one region replication + * at a time. CDK overcomes this limitation by waiting for replication to + * finish before starting new replicationRegion. + * + * @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-dynamodb-globaltable.html#cfn-dynamodb-globaltable-replicas + * @default true + */ + readonly waitForReplicationToFinish?: boolean; + /** * Whether CloudWatch contributor insights is enabled. * @@ -1152,7 +1168,7 @@ export class Table extends TableBase { } if (props.replicationRegions && props.replicationRegions.length > 0) { - this.createReplicaTables(props.replicationRegions, props.replicationTimeout); + this.createReplicaTables(props.replicationRegions, props.replicationTimeout, props.waitForReplicationToFinish); } } @@ -1494,7 +1510,7 @@ export class Table extends TableBase { * * @param regions regions where to create tables */ - private createReplicaTables(regions: string[], timeout?: Duration) { + private createReplicaTables(regions: string[], timeout?: Duration, waitForReplicationToFinish?: boolean) { const stack = Stack.of(this); if (!Token.isUnresolved(stack.region) && regions.includes(stack.region)) { @@ -1524,6 +1540,7 @@ export class Table extends TableBase { properties: { TableName: this.tableName, Region: region, + SkipReplicationCompletedWait: waitForReplicationToFinish === undefined ? undefined : !waitForReplicationToFinish, }, }); currentRegion.node.addDependency( diff --git a/packages/@aws-cdk/aws-dynamodb/package.json b/packages/@aws-cdk/aws-dynamodb/package.json index e6d4627e3455e..ba59f3f99b223 100644 --- a/packages/@aws-cdk/aws-dynamodb/package.json +++ b/packages/@aws-cdk/aws-dynamodb/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::DynamoDB", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,19 +72,19 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/aws-lambda": "^8.10.79", + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/aws-lambda": "^8.10.84", "@types/jest": "^26.0.24", "@types/sinon": "^9.0.11", "aws-sdk": "^2.848.0", - "aws-sdk-mock": "^5.2.1", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", + "aws-sdk-mock": "^5.4.0", "jest": "^26.6.3", - "pkglint": "0.0.0", "sinon": "^9.2.4", - "ts-jest": "^26.5.6", - "@aws-cdk/assert-internal": "0.0.0" + "ts-jest": "^26.5.6" }, "dependencies": { "@aws-cdk/aws-applicationautoscaling": "0.0.0", diff --git a/packages/@aws-cdk/aws-dynamodb/test/dynamodb.test.ts b/packages/@aws-cdk/aws-dynamodb/test/dynamodb.test.ts index 9ca717c46b8da..a095bff84ca25 100644 --- a/packages/@aws-cdk/aws-dynamodb/test/dynamodb.test.ts +++ b/packages/@aws-cdk/aws-dynamodb/test/dynamodb.test.ts @@ -6,7 +6,7 @@ import * as kinesis from '@aws-cdk/aws-kinesis'; import * as kms from '@aws-cdk/aws-kms'; import { App, Aws, CfnDeletionPolicy, ConstructNode, Duration, PhysicalName, RemovalPolicy, Resource, Stack, Tags } from '@aws-cdk/core'; import * as cr from '@aws-cdk/custom-resources'; -import { testLegacyBehavior } from 'cdk-build-tools/lib/feature-flag'; +import { testLegacyBehavior } from '@aws-cdk/cdk-build-tools/lib/feature-flag'; import { Construct } from 'constructs'; import { Attribute, @@ -2438,6 +2438,60 @@ describe('global', () => { }); }); + test('create replicas without waiting to finish replication', () => { + // GIVEN + const stack = new Stack(); + + // WHEN + new Table(stack, 'Table', { + partitionKey: { + name: 'id', + type: AttributeType.STRING, + }, + replicationRegions: [ + 'eu-west-2', + 'eu-central-1', + ], + waitForReplicationToFinish: false, + }); + + // THEN + expect(stack).toHaveResource('Custom::DynamoDBReplica', { + Properties: { + TableName: { + Ref: 'TableCD117FA1', + }, + Region: 'eu-west-2', + SkipReplicationCompletedWait: true, + }, + Condition: 'TableStackRegionNotEqualseuwest2A03859E7', + }, ResourcePart.CompleteDefinition); + + expect(stack).toHaveResource('Custom::DynamoDBReplica', { + Properties: { + TableName: { + Ref: 'TableCD117FA1', + }, + Region: 'eu-central-1', + SkipReplicationCompletedWait: true, + }, + Condition: 'TableStackRegionNotEqualseucentral199D46FC0', + }, ResourcePart.CompleteDefinition); + + expect(SynthUtils.toCloudFormation(stack).Conditions).toEqual({ + TableStackRegionNotEqualseuwest2A03859E7: { + 'Fn::Not': [ + { 'Fn::Equals': ['eu-west-2', { Ref: 'AWS::Region' }] }, + ], + }, + TableStackRegionNotEqualseucentral199D46FC0: { + 'Fn::Not': [ + { 'Fn::Equals': ['eu-central-1', { Ref: 'AWS::Region' }] }, + ], + }, + }); + }); + test('grantReadData', () => { const stack = new Stack(); const table = new Table(stack, 'Table', { diff --git a/packages/@aws-cdk/aws-ec2/.eslintrc.js b/packages/@aws-cdk/aws-ec2/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-ec2/.eslintrc.js +++ b/packages/@aws-cdk/aws-ec2/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-ec2/jest.config.js b/packages/@aws-cdk/aws-ec2/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-ec2/jest.config.js +++ b/packages/@aws-cdk/aws-ec2/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-ec2/lib/cfn-init.ts b/packages/@aws-cdk/aws-ec2/lib/cfn-init.ts index 78b3345743347..860e37001dd68 100644 --- a/packages/@aws-cdk/aws-ec2/lib/cfn-init.ts +++ b/packages/@aws-cdk/aws-ec2/lib/cfn-init.ts @@ -125,14 +125,19 @@ export class CloudFormationInit { // To identify the resources that have the metadata and where the signal // needs to be sent, we need { region, stackName, logicalId } let resourceLocator = `--region ${Aws.REGION} --stack ${Aws.STACK_NAME} --resource ${attachedResource.logicalId}`; + const signalResource = attachOptions.signalResource?.logicalId ?? attachedResource.logicalId; + let notifyResourceLocator = `--region ${Aws.REGION} --stack ${Aws.STACK_NAME} --resource ${signalResource}`; // If specified in attachOptions, include arguments in cfn-init/cfn-signal commands if (attachOptions.includeUrl) { resourceLocator = `${resourceLocator} --url https://cloudformation.${Aws.REGION}.${Aws.URL_SUFFIX}`; + notifyResourceLocator = `${notifyResourceLocator} --url https://cloudformation.${Aws.REGION}.${Aws.URL_SUFFIX}`; } if (attachOptions.includeRole) { - resourceLocator = `${resourceLocator} --role ${attachOptions.instanceRole}`; + resourceLocator = `${resourceLocator} --role ${attachOptions.instanceRole.roleName}`; + notifyResourceLocator = `${notifyResourceLocator} --role ${attachOptions.instanceRole.roleName}`; } + const configSets = (attachOptions.configSets ?? ['default']).join(','); const printLog = attachOptions.printLog ?? true; @@ -143,22 +148,26 @@ export class CloudFormationInit { if (attachOptions.platform === OperatingSystemType.WINDOWS) { const errCode = attachOptions.ignoreFailures ? '0' : '$LASTEXITCODE'; - attachOptions.userData.addCommands(...[ - `cfn-init.exe -v ${resourceLocator} -c ${configSets}`, - `cfn-signal.exe -e ${errCode} ${resourceLocator}`, - ...printLog ? ['type C:\\cfn\\log\\cfn-init.log'] : [], - ]); + attachOptions.userData.addCommands( + ...[ + `cfn-init.exe -v ${resourceLocator} -c ${configSets}`, + `cfn-signal.exe -e ${errCode} ${notifyResourceLocator}`, + ...(printLog ? ['type C:\\cfn\\log\\cfn-init.log'] : []), + ], + ); } else { const errCode = attachOptions.ignoreFailures ? '0' : '$?'; - attachOptions.userData.addCommands(...[ - // Run a subshell without 'errexit', so we can signal using the exit code of cfn-init - '(', - ' set +e', - ` /opt/aws/bin/cfn-init -v ${resourceLocator} -c ${configSets}`, - ` /opt/aws/bin/cfn-signal -e ${errCode} ${resourceLocator}`, - ...printLog ? [' cat /var/log/cfn-init.log >&2'] : [], - ')', - ]); + attachOptions.userData.addCommands( + ...[ + // Run a subshell without 'errexit', so we can signal using the exit code of cfn-init + '(', + ' set +e', + ` /opt/aws/bin/cfn-init -v ${resourceLocator} -c ${configSets}`, + ` /opt/aws/bin/cfn-signal -e ${errCode} ${notifyResourceLocator}`, + ...(printLog ? [' cat /var/log/cfn-init.log >&2'] : []), + ')', + ], + ); } } @@ -428,4 +437,13 @@ export interface AttachInitOptions { * @default false */ readonly ignoreFailures?: boolean; + + /** + * When provided, signals this resource instead of the attached resource + * + * You can use this to support signaling LaunchTemplate while attaching AutoScalingGroup + * + * @default - if this property is undefined cfn-signal signals the attached resource + */ + readonly signalResource?: CfnResource; } diff --git a/packages/@aws-cdk/aws-ec2/lib/instance-types.ts b/packages/@aws-cdk/aws-ec2/lib/instance-types.ts index 013f7d3389f3c..1b778fee66e6e 100644 --- a/packages/@aws-cdk/aws-ec2/lib/instance-types.ts +++ b/packages/@aws-cdk/aws-ec2/lib/instance-types.ts @@ -372,6 +372,16 @@ export enum InstanceClass { */ X1E = 'x1e', + /** + * Memory-intensive instances, 2nd generation with Graviton2 processors and local NVME drive + */ + MEMORY_INTENSIVE_2_GRAVITON2_NVME_DRIVE = 'x2gd', + + /** + * Memory-intensive instances, 2nd generation with Graviton2 processors and local NVME drive + */ + X2GD = 'x2gd', + /** * Instances with customizable hardware acceleration, 1st generation */ diff --git a/packages/@aws-cdk/aws-ec2/lib/machine-image.ts b/packages/@aws-cdk/aws-ec2/lib/machine-image.ts index c7340af1d47e5..731d9ea8d0c43 100644 --- a/packages/@aws-cdk/aws-ec2/lib/machine-image.ts +++ b/packages/@aws-cdk/aws-ec2/lib/machine-image.ts @@ -149,10 +149,12 @@ export interface MachineImageConfig { * on the instance if you are using this image. * * The AMI ID is selected using the values published to the SSM parameter store. - * - * @deprecated Use `MachineImage.fromSsmParameter()` instead */ export class GenericSSMParameterImage implements IMachineImage { + // FIXME: this class ought to be `@deprecated` and removed from v2, but that + // is causing build failure right now. Ref: https://github.com/aws/jsii/issues/3025 + // @-deprecated Use `MachineImage.fromSsmParameter()` instead + /** * Name of the SSM parameter we're looking up */ @@ -679,4 +681,4 @@ function lookupImage(scope: Construct, cachedInContext: boolean | undefined, par return cachedInContext ? ssm.StringParameter.valueFromLookup(scope, parameterName) : ssm.StringParameter.valueForTypedStringParameter(scope, parameterName, ssm.ParameterType.AWS_EC2_IMAGE_ID); -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-ec2/lib/security-group.ts b/packages/@aws-cdk/aws-ec2/lib/security-group.ts index 90613e3904475..2c01da7aef943 100644 --- a/packages/@aws-cdk/aws-ec2/lib/security-group.ts +++ b/packages/@aws-cdk/aws-ec2/lib/security-group.ts @@ -382,6 +382,7 @@ export class SecurityGroup extends SecurityGroupBase { * An attribute that represents the security group name. * * @attribute + * @deprecated returns the security group ID, rather than the name. */ public readonly securityGroupName: string; diff --git a/packages/@aws-cdk/aws-ec2/package.json b/packages/@aws-cdk/aws-ec2/package.json index 6bb38a38ece94..b7ea820e221b5 100644 --- a/packages/@aws-cdk/aws-ec2/package.json +++ b/packages/@aws-cdk/aws-ec2/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::EC2", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -73,16 +72,16 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/aws-lambda": "^8.10.79", - "@types/jest": "^26.0.24", - "@aws-cdk/cx-api": "0.0.0", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/cloud-assembly-schema": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "@aws-cdk/cx-api": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/aws-lambda": "^8.10.84", + "@types/jest": "^26.0.24", + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-cloudwatch": "0.0.0", @@ -107,9 +106,9 @@ "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/aws-s3-assets": "0.0.0", "@aws-cdk/aws-ssm": "0.0.0", + "@aws-cdk/cloud-assembly-schema": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/cx-api": "0.0.0", - "@aws-cdk/cloud-assembly-schema": "0.0.0", "@aws-cdk/region-info": "0.0.0", "constructs": "^3.3.69" }, diff --git a/packages/@aws-cdk/aws-ec2/test/cfn-init.test.ts b/packages/@aws-cdk/aws-ec2/test/cfn-init.test.ts index e2539b71ac223..37d4fe2d72d28 100644 --- a/packages/@aws-cdk/aws-ec2/test/cfn-init.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/cfn-init.test.ts @@ -14,6 +14,7 @@ let stack: Stack; let instanceRole: iam.Role; let resource: CfnResource; let linuxUserData: ec2.UserData; +let signalResource: CfnResource; function resetState() { resetStateWithSynthesizer(); @@ -31,6 +32,9 @@ function resetStateWithSynthesizer(customSynthesizer?: IStackSynthesizer) { resource = new CfnResource(stack, 'Resource', { type: 'CDK::Test::Resource', }); + signalResource = new CfnResource(stack, 'SignalResource', { + type: 'CDK::Test::Resource', + }); linuxUserData = ec2.UserData.forLinux(); }; @@ -135,11 +139,7 @@ describe('userdata', () => { ); }); - test('linux userdata contains right commands', () => { - // WHEN - simpleInit.attach(resource, linuxOptions()); - - // THEN + function linuxUserDataTest(signalLogicalId: string) { const lines = linuxUserData.render().split('\n'); expectLine(lines, cmdArg('cfn-init', `--region ${Aws.REGION}`)); expectLine(lines, cmdArg('cfn-init', `--stack ${Aws.STACK_NAME}`)); @@ -147,10 +147,46 @@ describe('userdata', () => { expectLine(lines, cmdArg('cfn-init', '-c default')); expectLine(lines, cmdArg('cfn-signal', `--region ${Aws.REGION}`)); expectLine(lines, cmdArg('cfn-signal', `--stack ${Aws.STACK_NAME}`)); - expectLine(lines, cmdArg('cfn-signal', `--resource ${resource.logicalId}`)); + expectLine(lines, cmdArg('cfn-signal', `--resource ${signalLogicalId}`)); expectLine(lines, cmdArg('cfn-signal', '-e $?')); expectLine(lines, cmdArg('cat', 'cfn-init.log')); expectLine(lines, /fingerprint/); + } + + function windowsUserDataTest( + windowsUserData: ec2.UserData, + signalLogicalId: string, + ) { + const lines = windowsUserData.render().split('\n'); + expectLine(lines, cmdArg('cfn-init', `--region ${Aws.REGION}`)); + expectLine(lines, cmdArg('cfn-init', `--stack ${Aws.STACK_NAME}`)); + expectLine(lines, cmdArg('cfn-init', `--resource ${resource.logicalId}`)); + expectLine(lines, cmdArg('cfn-init', '-c default')); + expectLine(lines, cmdArg('cfn-signal', `--region ${Aws.REGION}`)); + expectLine(lines, cmdArg('cfn-signal', `--stack ${Aws.STACK_NAME}`)); + expectLine(lines, cmdArg('cfn-signal', `--resource ${signalLogicalId}`)); + expectLine(lines, cmdArg('cfn-signal', '-e $LASTEXITCODE')); + expectLine(lines, cmdArg('type', 'cfn-init.log')); + expectLine(lines, /fingerprint/); + } + + test('linux userdata contains right commands', () => { + // WHEN + simpleInit.attach(resource, linuxOptions()); + + // THEN + linuxUserDataTest(resource.logicalId); + }); + + test('linux userdata contains right commands with different signal resource', () => { + // WHEN + simpleInit.attach(resource, { + ...linuxOptions(), + signalResource, + }); + + // THEN + linuxUserDataTest(signalResource.logicalId); }); test('linux userdata contains right commands when url and role included', () => { @@ -168,13 +204,13 @@ describe('userdata', () => { expectLine(lines, cmdArg('cfn-init', `--region ${Aws.REGION}`)); expectLine(lines, cmdArg('cfn-init', `--stack ${Aws.STACK_NAME}`)); expectLine(lines, cmdArg('cfn-init', `--resource ${resource.logicalId}`)); - expectLine(lines, cmdArg('cfn-init', `--role ${instanceRole}`)); + expectLine(lines, cmdArg('cfn-init', `--role ${instanceRole.roleName}`)); expectLine(lines, cmdArg('cfn-init', `--url https://cloudformation.${Aws.REGION}.${Aws.URL_SUFFIX}`)); expectLine(lines, cmdArg('cfn-init', '-c default')); expectLine(lines, cmdArg('cfn-signal', `--region ${Aws.REGION}`)); expectLine(lines, cmdArg('cfn-signal', `--stack ${Aws.STACK_NAME}`)); expectLine(lines, cmdArg('cfn-signal', `--resource ${resource.logicalId}`)); - expectLine(lines, cmdArg('cfn-init', `--role ${instanceRole}`)); + expectLine(lines, cmdArg('cfn-init', `--role ${instanceRole.roleName}`)); expectLine(lines, cmdArg('cfn-init', `--url https://cloudformation.${Aws.REGION}.${Aws.URL_SUFFIX}`)); expectLine(lines, cmdArg('cfn-signal', '-e $?')); expectLine(lines, cmdArg('cat', 'cfn-init.log')); @@ -192,17 +228,22 @@ describe('userdata', () => { }); // THEN - const lines = windowsUserData.render().split('\n'); - expectLine(lines, cmdArg('cfn-init', `--region ${Aws.REGION}`)); - expectLine(lines, cmdArg('cfn-init', `--stack ${Aws.STACK_NAME}`)); - expectLine(lines, cmdArg('cfn-init', `--resource ${resource.logicalId}`)); - expectLine(lines, cmdArg('cfn-init', '-c default')); - expectLine(lines, cmdArg('cfn-signal', `--region ${Aws.REGION}`)); - expectLine(lines, cmdArg('cfn-signal', `--stack ${Aws.STACK_NAME}`)); - expectLine(lines, cmdArg('cfn-signal', `--resource ${resource.logicalId}`)); - expectLine(lines, cmdArg('cfn-signal', '-e $LASTEXITCODE')); - expectLine(lines, cmdArg('type', 'cfn-init.log')); - expectLine(lines, /fingerprint/); + windowsUserDataTest(windowsUserData, resource.logicalId); + }); + + test('Windows userdata contains right commands with different signal resource', () => { + // WHEN + const windowsUserData = ec2.UserData.forWindows(); + + simpleInit.attach(resource, { + platform: ec2.OperatingSystemType.WINDOWS, + instanceRole, + userData: windowsUserData, + signalResource, + }); + + // THEN + windowsUserDataTest(windowsUserData, signalResource.logicalId); }); test('ignoreFailures disables result code reporting', () => { diff --git a/packages/@aws-cdk/aws-ec2/test/volume.test.ts b/packages/@aws-cdk/aws-ec2/test/volume.test.ts index d33acadc3f8dc..4ac7874c701d2 100644 --- a/packages/@aws-cdk/aws-ec2/test/volume.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/volume.test.ts @@ -10,7 +10,7 @@ import { import * as kms from '@aws-cdk/aws-kms'; import * as cdk from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; -import { testFutureBehavior, testLegacyBehavior } from 'cdk-build-tools/lib/feature-flag'; +import { testFutureBehavior, testLegacyBehavior } from '@aws-cdk/cdk-build-tools/lib/feature-flag'; import { AmazonLinuxGeneration, EbsDeviceVolumeType, diff --git a/packages/@aws-cdk/aws-ecr-assets/.eslintrc.js b/packages/@aws-cdk/aws-ecr-assets/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-ecr-assets/.eslintrc.js +++ b/packages/@aws-cdk/aws-ecr-assets/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-ecr-assets/README.md b/packages/@aws-cdk/aws-ecr-assets/README.md index f5993097418ac..b106c952007b8 100644 --- a/packages/@aws-cdk/aws-ecr-assets/README.md +++ b/packages/@aws-cdk/aws-ecr-assets/README.md @@ -14,8 +14,8 @@ This module allows bundling Docker images as assets. ## Images from Dockerfile Images are built from a local Docker context directory (with a `Dockerfile`), -uploaded to ECR by the CDK toolkit and/or your app's CI-CD pipeline, and can be -naturally referenced in your CDK app. +uploaded to Amazon Elastic Container Registry (ECR) by the CDK toolkit +and/or your app's CI/CD pipeline, and can be naturally referenced in your CDK app. ```ts import { DockerImageAsset } from '@aws-cdk/aws-ecr-assets'; @@ -28,7 +28,7 @@ const asset = new DockerImageAsset(this, 'MyBuildImage', { The directory `my-image` must include a `Dockerfile`. This will instruct the toolkit to build a Docker image from `my-image`, push it -to an AWS ECR repository and wire the name of the repository as CloudFormation +to an Amazon ECR repository and wire the name of the repository as CloudFormation parameters to your stack. By default, all files in the given directory will be copied into the docker @@ -50,13 +50,18 @@ Use `asset.imageUri` to reference the image. It includes both the ECR image URL and tag. You can optionally pass build args to the `docker build` command by specifying -the `buildArgs` property: +the `buildArgs` property. It is recommended to skip hashing of `buildArgs` for +values that can change between different machines to maintain a consistent +asset hash. ```ts const asset = new DockerImageAsset(this, 'MyBuildImage', { directory: path.join(__dirname, 'my-image'), buildArgs: { HTTP_PROXY: 'http://10.20.30.2:1234' + }, + invalidation: { + buildArgs: false } }); ``` @@ -85,7 +90,7 @@ const asset = new TarballImageAsset(this, 'MyBuildImage', { ``` This will instruct the toolkit to add the tarball as a file asset. During deployment it will load the container image -from `local-image.tar`, push it to an AWS ECR repository and wire the name of the repository as CloudFormation parameters +from `local-image.tar`, push it to an Amazon ECR repository and wire the name of the repository as CloudFormation parameters to your stack. ## Publishing images to ECR repositories diff --git a/packages/@aws-cdk/aws-ecr-assets/jest.config.js b/packages/@aws-cdk/aws-ecr-assets/jest.config.js index 12d0151b1bb3b..45db604d94785 100644 --- a/packages/@aws-cdk/aws-ecr-assets/jest.config.js +++ b/packages/@aws-cdk/aws-ecr-assets/jest.config.js @@ -1,4 +1,4 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = { ...baseConfig, coverageThreshold: { diff --git a/packages/@aws-cdk/aws-ecr-assets/lib/image-asset.ts b/packages/@aws-cdk/aws-ecr-assets/lib/image-asset.ts index 7003fc6931826..e579baf55ac41 100644 --- a/packages/@aws-cdk/aws-ecr-assets/lib/image-asset.ts +++ b/packages/@aws-cdk/aws-ecr-assets/lib/image-asset.ts @@ -12,6 +12,46 @@ import { FingerprintOptions, FollowMode, IAsset } from '@aws-cdk/assets'; // eslint-disable-next-line no-duplicate-imports, import/order import { Construct as CoreConstruct } from '@aws-cdk/core'; +/** + * Options to control invalidation of `DockerImageAsset` asset hashes + */ +export interface DockerImageAssetInvalidationOptions { + /** + * Use `extraHash` while calculating the asset hash + * + * @default true + */ + readonly extraHash?: boolean; + + /** + * Use `buildArgs` while calculating the asset hash + * + * @default true + */ + readonly buildArgs?: boolean; + + /** + * Use `target` while calculating the asset hash + * + * @default true + */ + readonly target?: boolean; + + /** + * Use `file` while calculating the asset hash + * + * @default true + */ + readonly file?: boolean; + + /** + * Use `repositoryName` while calculating the asset hash + * + * @default true + */ + readonly repositoryName?: boolean; +} + /** * Options for DockerImageAsset */ @@ -54,6 +94,13 @@ export interface DockerImageAssetOptions extends FingerprintOptions, FileFingerp * @default 'Dockerfile' */ readonly file?: string; + + /** + * Options to control which parameters are used to invalidate the asset hash. + * + * @default - hash all parameters + */ + readonly invalidation?: DockerImageAssetInvalidationOptions; } /** @@ -150,11 +197,11 @@ export class DockerImageAsset extends CoreConstruct implements IAsset { // include build context in "extra" so it will impact the hash const extraHash: { [field: string]: any } = {}; - if (props.extraHash) { extraHash.user = props.extraHash; } - if (props.buildArgs) { extraHash.buildArgs = props.buildArgs; } - if (props.target) { extraHash.target = props.target; } - if (props.file) { extraHash.file = props.file; } - if (props.repositoryName) { extraHash.repositoryName = props.repositoryName; } + if (props.invalidation?.extraHash !== false && props.extraHash) { extraHash.user = props.extraHash; } + if (props.invalidation?.buildArgs !== false && props.buildArgs) { extraHash.buildArgs = props.buildArgs; } + if (props.invalidation?.target !== false && props.target) { extraHash.target = props.target; } + if (props.invalidation?.file !== false && props.file) { extraHash.file = props.file; } + if (props.invalidation?.repositoryName !== false && props.repositoryName) { extraHash.repositoryName = props.repositoryName; } // add "salt" to the hash in order to invalidate the image in the upgrade to // 1.21.0 which removes the AdoptedRepository resource (and will cause the diff --git a/packages/@aws-cdk/aws-ecr-assets/package.json b/packages/@aws-cdk/aws-ecr-assets/package.json index 44f7a2d4ffa7c..b6b407041eda6 100644 --- a/packages/@aws-cdk/aws-ecr-assets/package.json +++ b/packages/@aws-cdk/aws-ecr-assets/package.json @@ -65,32 +65,32 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cloud-assembly-schema": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", "@types/proxyquire": "^1.3.28", "aws-cdk": "0.0.0", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", "jest": "^26.6.3", - "pkglint": "0.0.0", - "proxyquire": "^2.1.3", - "@aws-cdk/cloud-assembly-schema": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "proxyquire": "^2.1.3" }, "dependencies": { + "@aws-cdk/assets": "0.0.0", "@aws-cdk/aws-ecr": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/core": "0.0.0", - "@aws-cdk/assets": "0.0.0", "@aws-cdk/cx-api": "0.0.0", - "minimatch": "^3.0.4", - "constructs": "^3.3.69" + "constructs": "^3.3.69", + "minimatch": "^3.0.4" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { + "@aws-cdk/assets": "0.0.0", "@aws-cdk/aws-ecr": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", - "@aws-cdk/assets": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/cx-api": "0.0.0", @@ -111,7 +111,6 @@ "announce": false }, "cdk-build": { - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } diff --git a/packages/@aws-cdk/aws-ecr-assets/test/image-asset.test.ts b/packages/@aws-cdk/aws-ecr-assets/test/image-asset.test.ts index e156209458878..e08ef41d2d868 100644 --- a/packages/@aws-cdk/aws-ecr-assets/test/image-asset.test.ts +++ b/packages/@aws-cdk/aws-ecr-assets/test/image-asset.test.ts @@ -5,7 +5,7 @@ import * as iam from '@aws-cdk/aws-iam'; import * as cxschema from '@aws-cdk/cloud-assembly-schema'; import { App, DefaultStackSynthesizer, IgnoreMode, Lazy, LegacyStackSynthesizer, Stack, Stage } from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; -import { testFutureBehavior } from 'cdk-build-tools/lib/feature-flag'; +import { testFutureBehavior } from '@aws-cdk/cdk-build-tools/lib/feature-flag'; import { DockerImageAsset } from '../lib'; /* eslint-disable quote-props */ @@ -55,6 +55,65 @@ describe('image asset', () => { }); + testFutureBehavior('with hash options', flags, App, (app) => { + // WHEN + const stack = new Stack(app); + new DockerImageAsset(stack, 'Image1', { + directory: path.join(__dirname, 'demo-image'), + buildArgs: { + a: 'b', + }, + invalidation: { + buildArgs: false, + }, + }); + new DockerImageAsset(stack, 'Image2', { + directory: path.join(__dirname, 'demo-image'), + buildArgs: { + a: 'c', + }, + invalidation: { + buildArgs: false, + }, + }); + new DockerImageAsset(stack, 'Image3', { + directory: path.join(__dirname, 'demo-image'), + buildArgs: { + a: 'b', + }, + }); + + // THEN + const asm = app.synth(); + const artifact = asm.getStackArtifact(stack.artifactId); + expect(artifact.template).toEqual({}); + expect(artifact.assets).toEqual([ + { + 'buildArgs': { + 'a': 'b', + }, + repositoryName: 'aws-cdk/assets', + imageTag: '8c1d9ca9f5d37b1c4870c13a9f855301bb42c1848dbcdd5edc8fe2c6c7261d48', + id: '8c1d9ca9f5d37b1c4870c13a9f855301bb42c1848dbcdd5edc8fe2c6c7261d48', + packaging: 'container-image', + path: 'asset.8c1d9ca9f5d37b1c4870c13a9f855301bb42c1848dbcdd5edc8fe2c6c7261d48', + sourceHash: '8c1d9ca9f5d37b1c4870c13a9f855301bb42c1848dbcdd5edc8fe2c6c7261d48', + }, + { + 'buildArgs': { + 'a': 'b', + }, + 'id': 'd4bbfde4749763cef9707486f81ce1e95d25cedaf4cc34cfcdab7232ec1948ff', + 'imageTag': 'd4bbfde4749763cef9707486f81ce1e95d25cedaf4cc34cfcdab7232ec1948ff', + 'packaging': 'container-image', + 'path': 'asset.d4bbfde4749763cef9707486f81ce1e95d25cedaf4cc34cfcdab7232ec1948ff', + 'repositoryName': 'aws-cdk/assets', + 'sourceHash': 'd4bbfde4749763cef9707486f81ce1e95d25cedaf4cc34cfcdab7232ec1948ff', + }, + ]); + + }); + testFutureBehavior('with target', flags, App, (app) => { // WHEN const stack = new Stack(app); diff --git a/packages/@aws-cdk/aws-ecr-assets/test/tarball-asset.test.ts b/packages/@aws-cdk/aws-ecr-assets/test/tarball-asset.test.ts index 20d7517e23915..77e22f20dca9d 100644 --- a/packages/@aws-cdk/aws-ecr-assets/test/tarball-asset.test.ts +++ b/packages/@aws-cdk/aws-ecr-assets/test/tarball-asset.test.ts @@ -5,7 +5,7 @@ import * as iam from '@aws-cdk/aws-iam'; import * as cxschema from '@aws-cdk/cloud-assembly-schema'; import { App, Stack } from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; -import { testFutureBehavior } from 'cdk-build-tools/lib/feature-flag'; +import { testFutureBehavior } from '@aws-cdk/cdk-build-tools/lib/feature-flag'; import { TarballImageAsset } from '../lib'; /* eslint-disable quote-props */ diff --git a/packages/@aws-cdk/aws-ecr/.eslintrc.js b/packages/@aws-cdk/aws-ecr/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-ecr/.eslintrc.js +++ b/packages/@aws-cdk/aws-ecr/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-ecr/jest.config.js b/packages/@aws-cdk/aws-ecr/jest.config.js index 07a010c639ba8..f4f042f9d2c29 100644 --- a/packages/@aws-cdk/aws-ecr/jest.config.js +++ b/packages/@aws-cdk/aws-ecr/jest.config.js @@ -1,4 +1,4 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = { ...baseConfig, coverageThreshold: { diff --git a/packages/@aws-cdk/aws-ecr/package.json b/packages/@aws-cdk/aws-ecr/package.json index d2eecfc93b1ba..1884a03470d31 100644 --- a/packages/@aws-cdk/aws-ecr/package.json +++ b/packages/@aws-cdk/aws-ecr/package.json @@ -57,8 +57,7 @@ "cloudformation": "AWS::ECR", "env": { "AWSLINT_BASE_CONSTRUCT": true - }, - "jest": true + } }, "nyc": { "lines": 78, @@ -78,11 +77,11 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert-internal": "0.0.0", - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/aws-events": "0.0.0", diff --git a/packages/@aws-cdk/aws-ecs-patterns/.eslintrc.js b/packages/@aws-cdk/aws-ecs-patterns/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/.eslintrc.js +++ b/packages/@aws-cdk/aws-ecs-patterns/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-ecs-patterns/.gitignore b/packages/@aws-cdk/aws-ecs-patterns/.gitignore index dcc1dc41e477f..17a41566f0002 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/.gitignore +++ b/packages/@aws-cdk/aws-ecs-patterns/.gitignore @@ -15,4 +15,5 @@ nyc.config.js *.snk !.eslintrc.js -junit.xml \ No newline at end of file +junit.xml +!jest.config.js \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ecs-patterns/.npmignore b/packages/@aws-cdk/aws-ecs-patterns/.npmignore index 9a032ae80868c..e8acf10a468a1 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/.npmignore +++ b/packages/@aws-cdk/aws-ecs-patterns/.npmignore @@ -24,4 +24,5 @@ tsconfig.json **/cdk.out junit.xml test/ -!*.lit.ts \ No newline at end of file +!*.lit.ts +jest.config.js \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ecs-patterns/jest.config.js b/packages/@aws-cdk/aws-ecs-patterns/jest.config.js new file mode 100644 index 0000000000000..34818e1593f6b --- /dev/null +++ b/packages/@aws-cdk/aws-ecs-patterns/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/@aws-cdk/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/base/queue-processing-service-base.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/base/queue-processing-service-base.ts index 2c293dc3173de..67634b3cc95e0 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/base/queue-processing-service-base.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/base/queue-processing-service-base.ts @@ -320,14 +320,14 @@ export abstract class QueueProcessingServiceBase extends CoreConstruct { // Determine the desired task count (minimum) and maximum scaling capacity if (!this.node.tryGetContext(cxapi.ECS_REMOVE_DEFAULT_DESIRED_COUNT)) { - this.minCapacity = props.minScalingCapacity || this.desiredCount; + this.minCapacity = props.minScalingCapacity ?? this.desiredCount; this.maxCapacity = props.maxScalingCapacity || (2 * this.desiredCount); } else { if (props.desiredTaskCount != null) { - this.minCapacity = props.minScalingCapacity || this.desiredCount; + this.minCapacity = props.minScalingCapacity ?? this.desiredCount; this.maxCapacity = props.maxScalingCapacity || (2 * this.desiredCount); } else { - this.minCapacity = props.minScalingCapacity || 1; + this.minCapacity = props.minScalingCapacity ?? 1; this.maxCapacity = props.maxScalingCapacity || 2; } } diff --git a/packages/@aws-cdk/aws-ecs-patterns/package.json b/packages/@aws-cdk/aws-ecs-patterns/package.json index c9d3b46b8f8b2..4e776d3b82cce 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/package.json +++ b/packages/@aws-cdk/aws-ecs-patterns/package.json @@ -65,14 +65,13 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/nodeunit": "^0.0.32", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "nodeunit": "^0.11.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24", + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-applicationautoscaling": "0.0.0", diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/l3s-v2.test.ts b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/l3s-v2.test.ts new file mode 100644 index 0000000000000..575ab92b40cfb --- /dev/null +++ b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/l3s-v2.test.ts @@ -0,0 +1,1481 @@ +import { SynthUtils } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; +import { Certificate } from '@aws-cdk/aws-certificatemanager'; +import { InstanceType, Vpc } from '@aws-cdk/aws-ec2'; +import { AwsLogDriver, Cluster, ContainerImage, Ec2TaskDefinition, PropagatedTagSource, Protocol } from '@aws-cdk/aws-ecs'; +import { ApplicationProtocol, SslPolicy } from '@aws-cdk/aws-elasticloadbalancingv2'; +import { CompositePrincipal, Role, ServicePrincipal } from '@aws-cdk/aws-iam'; +import { PublicHostedZone } from '@aws-cdk/aws-route53'; +import { NamespaceType } from '@aws-cdk/aws-servicediscovery'; +import { Duration, Stack } from '@aws-cdk/core'; +import { ApplicationMultipleTargetGroupsEc2Service, NetworkMultipleTargetGroupsEc2Service } from '../../lib'; + +describe('When Application Load Balancer', () => { + test('test ECS ALB construct with default settings', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); + + // WHEN + new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { + cluster, + memoryLimitMiB: 1024, + taskImageOptions: { + image: ContainerImage.fromRegistry('test'), + }, + }); + + // THEN - stack contains a load balancer, a service, and a target group. + expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::LoadBalancer'); + + expect(stack).toHaveResource('AWS::ECS::Service', { + DesiredCount: 1, + LaunchType: 'EC2', + }); + + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Image: 'test', + LogConfiguration: { + LogDriver: 'awslogs', + Options: { + 'awslogs-group': { + Ref: 'ServiceTaskDefwebLogGroup2A898F61', + }, + 'awslogs-stream-prefix': 'Service', + 'awslogs-region': { + Ref: 'AWS::Region', + }, + }, + }, + Memory: 1024, + Name: 'web', + PortMappings: [ + { + ContainerPort: 80, + HostPort: 0, + Protocol: 'tcp', + }, + ], + }, + ], + NetworkMode: 'bridge', + RequiresCompatibilities: [ + 'EC2', + ], + }); + }); + + test('test ECS ALB construct with all settings', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); + const zone = new PublicHostedZone(stack, 'HostedZone', { zoneName: 'example.com' }); + + // WHEN + new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { + cluster, + memoryLimitMiB: 1024, + taskImageOptions: { + image: ContainerImage.fromRegistry('test'), + containerName: 'myContainer', + containerPorts: [80, 90], + enableLogging: false, + environment: { + TEST_ENVIRONMENT_VARIABLE1: 'test environment variable 1 value', + TEST_ENVIRONMENT_VARIABLE2: 'test environment variable 2 value', + }, + logDriver: new AwsLogDriver({ + streamPrefix: 'TestStream', + }), + family: 'Ec2TaskDef', + executionRole: new Role(stack, 'ExecutionRole', { + path: '/', + assumedBy: new CompositePrincipal( + new ServicePrincipal('ecs.amazonaws.com'), + new ServicePrincipal('ecs-tasks.amazonaws.com'), + ), + }), + taskRole: new Role(stack, 'TaskRole', { + assumedBy: new ServicePrincipal('ecs-tasks.amazonaws.com'), + }), + dockerLabels: { label1: 'labelValue1', label2: 'labelValue2' }, + }, + cpu: 256, + desiredCount: 3, + enableECSManagedTags: true, + healthCheckGracePeriod: Duration.millis(2000), + loadBalancers: [ + { + name: 'lb', + domainName: 'api.example.com', + domainZone: zone, + publicLoadBalancer: false, + listeners: [ + { + name: 'listener', + protocol: ApplicationProtocol.HTTPS, + certificate: Certificate.fromCertificateArn(stack, 'Cert', 'helloworld'), + sslPolicy: SslPolicy.TLS12_EXT, + }, + ], + }, + ], + propagateTags: PropagatedTagSource.SERVICE, + memoryReservationMiB: 1024, + serviceName: 'myService', + targetGroups: [ + { + containerPort: 80, + listener: 'listener', + }, + { + containerPort: 90, + listener: 'listener', + pathPattern: 'a/b/c', + priority: 10, + protocol: Protocol.TCP, + }, + ], + }); + + // THEN + expect(stack).toHaveResource('AWS::ECS::Service', { + DesiredCount: 3, + LaunchType: 'EC2', + EnableECSManagedTags: true, + HealthCheckGracePeriodSeconds: 2, + LoadBalancers: [ + { + ContainerName: 'myContainer', + ContainerPort: 80, + TargetGroupArn: { + Ref: 'ServicelblistenerECSTargetGroupmyContainer80GroupAD83584A', + }, + }, + { + ContainerName: 'myContainer', + ContainerPort: 90, + TargetGroupArn: { + Ref: 'ServicelblistenerECSTargetGroupmyContainer90GroupF5A6D3A0', + }, + }, + ], + PropagateTags: 'SERVICE', + ServiceName: 'myService', + }); + + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Cpu: 256, + Environment: [ + { + Name: 'TEST_ENVIRONMENT_VARIABLE1', + Value: 'test environment variable 1 value', + }, + { + Name: 'TEST_ENVIRONMENT_VARIABLE2', + Value: 'test environment variable 2 value', + }, + ], + Essential: true, + Image: 'test', + LogConfiguration: { + LogDriver: 'awslogs', + Options: { + 'awslogs-group': { + Ref: 'ServiceTaskDefmyContainerLogGroup0A87368B', + }, + 'awslogs-stream-prefix': 'TestStream', + 'awslogs-region': { + Ref: 'AWS::Region', + }, + }, + }, + Memory: 1024, + MemoryReservation: 1024, + Name: 'myContainer', + PortMappings: [ + { + ContainerPort: 80, + HostPort: 0, + Protocol: 'tcp', + }, + { + ContainerPort: 90, + HostPort: 0, + Protocol: 'tcp', + }, + ], + DockerLabels: { + label1: 'labelValue1', + label2: 'labelValue2', + }, + }, + ], + ExecutionRoleArn: { + 'Fn::GetAtt': [ + 'ExecutionRole605A040B', + 'Arn', + ], + }, + Family: 'ServiceTaskDef79D79521', + NetworkMode: 'bridge', + RequiresCompatibilities: [ + 'EC2', + ], + TaskRoleArn: { + 'Fn::GetAtt': [ + 'TaskRole30FC0FBB', + 'Arn', + ], + }, + }); + + expect(stack).toHaveResourceLike('AWS::ElasticLoadBalancingV2::Listener', { + Port: 443, + Protocol: 'HTTPS', + Certificates: [{ + CertificateArn: 'helloworld', + }], + SslPolicy: SslPolicy.TLS12_EXT, + }); + }); + + test('set vpc instead of cluster', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + + // WHEN + new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { + vpc, + memoryLimitMiB: 1024, + taskImageOptions: { + image: ContainerImage.fromRegistry('test'), + }, + }); + + // THEN - stack does not contain a LaunchConfiguration + const template = SynthUtils.synthesize(stack, { skipValidation: true }); + expect(template).not.toHaveResource('AWS::AutoScaling::LaunchConfiguration'); + expect(() => SynthUtils.synthesize(stack)).toThrow(); + }); + + test('able to pass pre-defined task definition', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); + + const taskDefinition = new Ec2TaskDefinition(stack, 'Ec2TaskDef'); + const container = taskDefinition.addContainer('web', { + image: ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + memoryLimitMiB: 512, + }); + container.addPortMappings({ + containerPort: 80, + }); + + // WHEN + new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { + cluster, + taskDefinition, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Essential: true, + Image: 'amazon/amazon-ecs-sample', + Memory: 512, + Name: 'web', + PortMappings: [ + { + ContainerPort: 80, + HostPort: 0, + Protocol: 'tcp', + }, + ], + }, + ], + Family: 'Ec2TaskDef', + NetworkMode: 'bridge', + RequiresCompatibilities: [ + 'EC2', + ], + }); + }); + + test('able to output correct load balancer DNS and URLs for each protocol type', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); + const zone = new PublicHostedZone(stack, 'HostedZone', { zoneName: 'example.com' }); + + // WHEN + new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { + cluster, + memoryLimitMiB: 1024, + taskImageOptions: { + image: ContainerImage.fromRegistry('test'), + }, + loadBalancers: [ + { + name: 'lb1', + domainName: 'api.example.com', + domainZone: zone, + listeners: [ + { + name: 'listener1', + protocol: ApplicationProtocol.HTTPS, + certificate: Certificate.fromCertificateArn(stack, 'Cert', 'helloworld'), + }, + { + name: 'listener2', + protocol: ApplicationProtocol.HTTP, + }, + ], + }, + { + name: 'lb3', + listeners: [ + { + name: 'listener3', + protocol: ApplicationProtocol.HTTP, + }, + ], + }, + ], + targetGroups: [ + { + containerPort: 80, + listener: 'listener1', + }, + { + containerPort: 90, + listener: 'listener2', + }, + { + containerPort: 70, + listener: 'listener3', + }, + ], + }); + + // THEN + const template = SynthUtils.synthesize(stack).template.Outputs; + expect(template).toEqual({ + ServiceLoadBalancerDNSlb175E78BFE: { + Value: { + 'Fn::GetAtt': [ + 'Servicelb152C7F4F9', + 'DNSName', + ], + }, + }, + ServiceServiceURLlb1https5C0C4079: { + Value: { + 'Fn::Join': [ + '', + [ + 'https://', + { + Ref: 'ServiceDNSlb12BA1FAD3', + }, + ], + ], + }, + }, + ServiceServiceURLlb1http65F0546A: { + Value: { + 'Fn::Join': [ + '', + [ + 'http://', + { + Ref: 'ServiceDNSlb12BA1FAD3', + }, + ], + ], + }, + }, + ServiceLoadBalancerDNSlb32F273F27: { + Value: { + 'Fn::GetAtt': [ + 'Servicelb3A583D5E7', + 'DNSName', + ], + }, + }, + ServiceServiceURLlb3http40F9CADC: { + Value: { + 'Fn::Join': [ + '', + [ + 'http://', + { + 'Fn::GetAtt': [ + 'Servicelb3A583D5E7', + 'DNSName', + ], + }, + ], + ], + }, + }, + }); + }); + + test('errors if no essential container in pre-defined task definition', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); + + const taskDefinition = new Ec2TaskDefinition(stack, 'Ec2TaskDef'); + + // THEN + expect(() => { + new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { + cluster, + taskDefinition, + }); + }).toThrow(/At least one essential container must be specified/); + }); + + test('set default load balancer, listener, target group correctly', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const zone = new PublicHostedZone(stack, 'HostedZone', { zoneName: 'example.com' }); + + // WHEN + const ecsService = new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { + vpc, + memoryLimitMiB: 1024, + taskImageOptions: { + image: ContainerImage.fromRegistry('test'), + }, + loadBalancers: [ + { + name: 'lb1', + listeners: [ + { + name: 'listener1', + }, + ], + }, + { + name: 'lb2', + domainName: 'api.example.com', + domainZone: zone, + listeners: [ + { + name: 'listener2', + }, + { + name: 'listener3', + protocol: ApplicationProtocol.HTTPS, + certificate: Certificate.fromCertificateArn(stack, 'Cert', 'helloworld'), + }, + ], + }, + ], + targetGroups: [ + { + containerPort: 80, + }, + { + containerPort: 90, + }, + ], + }); + + // THEN + expect(ecsService.loadBalancer.node.id).toEqual('lb1'); + expect(ecsService.listener.node.id).toEqual('listener1'); + expect(ecsService.targetGroup.node.id).toEqual('ECSTargetGroupweb80Group'); + }); + + test('setting vpc and cluster throws error', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new Cluster(stack, 'Cluster', { vpc }); + + // WHEN + expect(() => new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { + cluster, + vpc, + taskImageOptions: { + image: ContainerImage.fromRegistry('/aws/aws-example-app'), + }, + })).toThrow(/You can only specify either vpc or cluster. Alternatively, you can leave both blank/); + }); + + test('creates AWS Cloud Map service for Private DNS namespace', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'MyVpc', {}); + const cluster = new Cluster(stack, 'EcsCluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); + + // WHEN + cluster.addDefaultCloudMapNamespace({ + name: 'foo.com', + type: NamespaceType.DNS_PRIVATE, + }); + + new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { + cluster, + taskImageOptions: { + image: ContainerImage.fromRegistry('hello'), + }, + cloudMapOptions: { + name: 'myApp', + }, + memoryLimitMiB: 512, + }); + + // THEN + expect(stack).toHaveResource('AWS::ECS::Service', { + ServiceRegistries: [ + { + ContainerName: 'web', + ContainerPort: 80, + RegistryArn: { + 'Fn::GetAtt': [ + 'ServiceCloudmapServiceDE76B29D', + 'Arn', + ], + }, + }, + ], + }); + + expect(stack).toHaveResource('AWS::ServiceDiscovery::Service', { + DnsConfig: { + DnsRecords: [ + { + TTL: 60, + Type: 'SRV', + }, + ], + NamespaceId: { + 'Fn::GetAtt': [ + 'EcsClusterDefaultServiceDiscoveryNamespaceB0971B2F', + 'Id', + ], + }, + RoutingPolicy: 'MULTIVALUE', + }, + HealthCheckCustomConfig: { + FailureThreshold: 1, + }, + Name: 'myApp', + NamespaceId: { + 'Fn::GetAtt': [ + 'EcsClusterDefaultServiceDiscoveryNamespaceB0971B2F', + 'Id', + ], + }, + }); + }); + + test('errors when setting both taskDefinition and taskImageOptions', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); + + const taskDefinition = new Ec2TaskDefinition(stack, 'Ec2TaskDef'); + taskDefinition.addContainer('test', { + image: ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + memoryLimitMiB: 512, + }); + + // THEN + expect(() => { + new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { + cluster, + taskImageOptions: { + image: ContainerImage.fromRegistry('test'), + }, + taskDefinition, + }); + }).toThrow(/You must specify only one of TaskDefinition or TaskImageOptions./); + }); + + test('errors when setting neither taskDefinition nor taskImageOptions', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); + + // THEN + expect(() => { + new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { + cluster, + }); + }).toThrow(/You must specify one of: taskDefinition or image/); + }); + + test('errors when setting domainName but not domainZone', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); + + // THEN + expect(() => { + new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { + cluster, + taskImageOptions: { + image: ContainerImage.fromRegistry('test'), + }, + loadBalancers: [ + { + name: 'lb1', + domainName: 'api.example.com', + listeners: [ + { + name: 'listener1', + }, + ], + }, + ], + }); + }).toThrow(/A Route53 hosted domain zone name is required to configure the specified domain name/); + }); + + test('errors when loadBalancers is empty', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new Cluster(stack, 'Cluster', { vpc }); + + // THEN + expect(() => { + new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { + cluster, + taskImageOptions: { + image: ContainerImage.fromRegistry('test'), + }, + loadBalancers: [], + }); + }).toThrow(/At least one load balancer must be specified/); + }); + + test('errors when targetGroups is empty', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new Cluster(stack, 'Cluster', { vpc }); + + // THEN + expect(() => { + new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { + cluster, + taskImageOptions: { + image: ContainerImage.fromRegistry('test'), + }, + targetGroups: [], + }); + }).toThrow(/At least one target group should be specified/); + }); + + test('errors when no listener specified', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new Cluster(stack, 'Cluster', { vpc }); + + // THEN + expect(() => { + new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { + cluster, + taskImageOptions: { + image: ContainerImage.fromRegistry('test'), + }, + loadBalancers: [ + { + name: 'lb', + listeners: [], + }, + ], + }); + }).toThrow(/At least one listener must be specified/); + }); + + test('errors when setting both HTTP protocol and certificate', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new Cluster(stack, 'Cluster', { vpc }); + + // THEN + expect(() => { + new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { + cluster, + taskImageOptions: { + image: ContainerImage.fromRegistry('test'), + }, + loadBalancers: [ + { + name: 'lb', + listeners: [ + { + name: 'listener', + protocol: ApplicationProtocol.HTTP, + certificate: Certificate.fromCertificateArn(stack, 'Cert', 'helloworld'), + }, + ], + }, + ], + }); + }).toThrow(/The HTTPS protocol must be used when a certificate is given/); + }); + + test('errors when setting HTTPS protocol but not domain name', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new Cluster(stack, 'Cluster', { vpc }); + + // THEN + expect(() => { + new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { + cluster, + taskImageOptions: { + image: ContainerImage.fromRegistry('test'), + }, + loadBalancers: [ + { + name: 'lb', + listeners: [ + { + name: 'listener', + protocol: ApplicationProtocol.HTTPS, + }, + ], + }, + ], + }); + }).toThrow(/A domain name and zone is required when using the HTTPS protocol/); + }); + + test('errors when listener is not defined but used in creating target groups', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new Cluster(stack, 'Cluster', { vpc }); + + // THEN + expect(() => { + new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { + cluster, + taskImageOptions: { + image: ContainerImage.fromRegistry('test'), + }, + loadBalancers: [ + { + name: 'lb', + listeners: [ + { + name: 'listener1', + }, + ], + }, + ], + targetGroups: [ + { + containerPort: 80, + listener: 'listener2', + }, + ], + }); + }).toThrow(/Listener listener2 is not defined. Did you define listener with name listener2?/); + }); + + test('errors if desiredTaskCount is 0', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); + + // THEN + expect(() => + new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { + cluster, + memoryLimitMiB: 1024, + taskImageOptions: { + image: ContainerImage.fromRegistry('test'), + }, + desiredCount: 0, + })).toThrow(/You must specify a desiredCount greater than 0/); + }); +}); + +describe('When Network Load Balancer', () => { + test('test ECS NLB construct with default settings', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); + + // WHEN + new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { + cluster, + memoryLimitMiB: 256, + taskImageOptions: { + image: ContainerImage.fromRegistry('test'), + }, + }); + + // THEN - stack contains a load balancer and a service + expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::LoadBalancer'); + + expect(stack).toHaveResource('AWS::ECS::Service', { + DesiredCount: 1, + LaunchType: 'EC2', + }); + + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Essential: true, + Image: 'test', + LogConfiguration: { + LogDriver: 'awslogs', + Options: { + 'awslogs-group': { + Ref: 'ServiceTaskDefwebLogGroup2A898F61', + }, + 'awslogs-stream-prefix': 'Service', + 'awslogs-region': { + Ref: 'AWS::Region', + }, + }, + }, + Memory: 256, + Name: 'web', + PortMappings: [ + { + ContainerPort: 80, + HostPort: 0, + Protocol: 'tcp', + }, + ], + }, + ], + ExecutionRoleArn: { + 'Fn::GetAtt': [ + 'ServiceTaskDefExecutionRole919F7BE3', + 'Arn', + ], + }, + Family: 'ServiceTaskDef79D79521', + NetworkMode: 'bridge', + RequiresCompatibilities: [ + 'EC2', + ], + TaskRoleArn: { + 'Fn::GetAtt': [ + 'ServiceTaskDefTaskRole0CFE2F57', + 'Arn', + ], + }, + }); + }); + + test('test ECS NLB construct with all settings', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); + const zone = new PublicHostedZone(stack, 'HostedZone', { zoneName: 'example.com' }); + + // WHEN + new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { + cluster, + memoryLimitMiB: 256, + taskImageOptions: { + image: ContainerImage.fromRegistry('test'), + containerName: 'myContainer', + containerPorts: [80, 90], + enableLogging: false, + environment: { + TEST_ENVIRONMENT_VARIABLE1: 'test environment variable 1 value', + TEST_ENVIRONMENT_VARIABLE2: 'test environment variable 2 value', + }, + logDriver: new AwsLogDriver({ + streamPrefix: 'TestStream', + }), + family: 'Ec2TaskDef', + executionRole: new Role(stack, 'ExecutionRole', { + path: '/', + assumedBy: new CompositePrincipal( + new ServicePrincipal('ecs.amazonaws.com'), + new ServicePrincipal('ecs-tasks.amazonaws.com'), + ), + }), + taskRole: new Role(stack, 'TaskRole', { + assumedBy: new ServicePrincipal('ecs-tasks.amazonaws.com'), + }), + dockerLabels: { label1: 'labelValue1', label2: 'labelValue2' }, + }, + cpu: 256, + desiredCount: 3, + enableECSManagedTags: true, + healthCheckGracePeriod: Duration.millis(2000), + loadBalancers: [ + { + name: 'lb1', + domainName: 'api.example.com', + domainZone: zone, + publicLoadBalancer: false, + listeners: [ + { + name: 'listener1', + }, + ], + }, + { + name: 'lb2', + listeners: [ + { + name: 'listener2', + port: 81, + }, + ], + }, + ], + propagateTags: PropagatedTagSource.SERVICE, + memoryReservationMiB: 256, + serviceName: 'myService', + targetGroups: [ + { + containerPort: 80, + listener: 'listener1', + }, + { + containerPort: 90, + listener: 'listener2', + }, + ], + }); + + // THEN + expect(stack).toHaveResource('AWS::ECS::Service', { + DesiredCount: 3, + EnableECSManagedTags: true, + HealthCheckGracePeriodSeconds: 2, + LaunchType: 'EC2', + LoadBalancers: [ + { + ContainerName: 'myContainer', + ContainerPort: 80, + TargetGroupArn: { + Ref: 'Servicelb1listener1ECSTargetGroupmyContainer80Group43098F8B', + }, + }, + { + ContainerName: 'myContainer', + ContainerPort: 90, + TargetGroupArn: { + Ref: 'Servicelb2listener2ECSTargetGroupmyContainer90GroupDEB417E4', + }, + }, + ], + PropagateTags: 'SERVICE', + SchedulingStrategy: 'REPLICA', + ServiceName: 'myService', + }); + + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Cpu: 256, + Environment: [ + { + Name: 'TEST_ENVIRONMENT_VARIABLE1', + Value: 'test environment variable 1 value', + }, + { + Name: 'TEST_ENVIRONMENT_VARIABLE2', + Value: 'test environment variable 2 value', + }, + ], + Essential: true, + Image: 'test', + LogConfiguration: { + LogDriver: 'awslogs', + Options: { + 'awslogs-group': { + Ref: 'ServiceTaskDefmyContainerLogGroup0A87368B', + }, + 'awslogs-stream-prefix': 'TestStream', + 'awslogs-region': { + Ref: 'AWS::Region', + }, + }, + }, + Memory: 256, + MemoryReservation: 256, + Name: 'myContainer', + PortMappings: [ + { + ContainerPort: 80, + HostPort: 0, + Protocol: 'tcp', + }, + { + ContainerPort: 90, + HostPort: 0, + Protocol: 'tcp', + }, + ], + DockerLabels: { + label1: 'labelValue1', + label2: 'labelValue2', + }, + }, + ], + ExecutionRoleArn: { + 'Fn::GetAtt': [ + 'ExecutionRole605A040B', + 'Arn', + ], + }, + Family: 'ServiceTaskDef79D79521', + NetworkMode: 'bridge', + RequiresCompatibilities: [ + 'EC2', + ], + TaskRoleArn: { + 'Fn::GetAtt': [ + 'TaskRole30FC0FBB', + 'Arn', + ], + }, + }); + }); + + test('set vpc instead of cluster', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + + // WHEN + new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { + vpc, + memoryLimitMiB: 256, + taskImageOptions: { + image: ContainerImage.fromRegistry('test'), + }, + }); + + // THEN - stack does not contain a LaunchConfiguration + const template = SynthUtils.synthesize(stack, { skipValidation: true }); + expect(template).not.toHaveResource('AWS::AutoScaling::LaunchConfiguration'); + expect(() => SynthUtils.synthesize(stack)).toThrow(); + }); + + test('able to pass pre-defined task definition', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); + + const taskDefinition = new Ec2TaskDefinition(stack, 'Ec2TaskDef'); + const container = taskDefinition.addContainer('web', { + image: ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + memoryLimitMiB: 512, + }); + container.addPortMappings({ + containerPort: 80, + }); + + // WHEN + new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { + cluster, + taskDefinition, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Essential: true, + Image: 'amazon/amazon-ecs-sample', + Memory: 512, + Name: 'web', + PortMappings: [ + { + ContainerPort: 80, + HostPort: 0, + Protocol: 'tcp', + }, + ], + }, + ], + Family: 'Ec2TaskDef', + NetworkMode: 'bridge', + RequiresCompatibilities: [ + 'EC2', + ], + }); + }); + + test('errors if no essential container in pre-defined task definition', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); + + const taskDefinition = new Ec2TaskDefinition(stack, 'Ec2TaskDef'); + + // THEN + expect(() => { + new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { + cluster, + taskDefinition, + }); + }).toThrow(/At least one essential container must be specified/); + }); + + test('set default load balancer, listener, target group correctly', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const zone = new PublicHostedZone(stack, 'HostedZone', { zoneName: 'example.com' }); + + // WHEN + const ecsService = new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { + vpc, + memoryLimitMiB: 1024, + taskImageOptions: { + image: ContainerImage.fromRegistry('test'), + }, + loadBalancers: [ + { + name: 'lb1', + listeners: [ + { + name: 'listener1', + }, + ], + }, + { + name: 'lb2', + domainName: 'api.example.com', + domainZone: zone, + listeners: [ + { + name: 'listener2', + }, + { + name: 'listener3', + }, + ], + }, + ], + targetGroups: [ + { + containerPort: 80, + }, + { + containerPort: 90, + }, + ], + }); + + // THEN + expect(ecsService.loadBalancer.node.id).toEqual('lb1'); + expect(ecsService.listener.node.id).toEqual('listener1'); + expect(ecsService.targetGroup.node.id).toEqual('ECSTargetGroupweb80Group'); + }); + + test('setting vpc and cluster throws error', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new Cluster(stack, 'Cluster', { vpc }); + + // WHEN + expect(() => new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { + cluster, + vpc, + taskImageOptions: { + image: ContainerImage.fromRegistry('/aws/aws-example-app'), + }, + })).toThrow(/You can only specify either vpc or cluster. Alternatively, you can leave both blank/); + }); + + test('creates AWS Cloud Map service for Private DNS namespace', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'MyVpc', {}); + const cluster = new Cluster(stack, 'EcsCluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); + + // WHEN + cluster.addDefaultCloudMapNamespace({ + name: 'foo.com', + type: NamespaceType.DNS_PRIVATE, + }); + + new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { + cluster, + taskImageOptions: { + image: ContainerImage.fromRegistry('hello'), + }, + cloudMapOptions: { + name: 'myApp', + }, + memoryLimitMiB: 512, + }); + + // THEN + expect(stack).toHaveResource('AWS::ECS::Service', { + ServiceRegistries: [ + { + ContainerName: 'web', + ContainerPort: 80, + RegistryArn: { + 'Fn::GetAtt': [ + 'ServiceCloudmapServiceDE76B29D', + 'Arn', + ], + }, + }, + ], + }); + + expect(stack).toHaveResource('AWS::ServiceDiscovery::Service', { + DnsConfig: { + DnsRecords: [ + { + TTL: 60, + Type: 'SRV', + }, + ], + NamespaceId: { + 'Fn::GetAtt': [ + 'EcsClusterDefaultServiceDiscoveryNamespaceB0971B2F', + 'Id', + ], + }, + RoutingPolicy: 'MULTIVALUE', + }, + HealthCheckCustomConfig: { + FailureThreshold: 1, + }, + Name: 'myApp', + NamespaceId: { + 'Fn::GetAtt': [ + 'EcsClusterDefaultServiceDiscoveryNamespaceB0971B2F', + 'Id', + ], + }, + }); + }); + + test('errors when setting both taskDefinition and taskImageOptions', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); + + const taskDefinition = new Ec2TaskDefinition(stack, 'Ec2TaskDef'); + taskDefinition.addContainer('test', { + image: ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + memoryLimitMiB: 512, + }); + + // THEN + expect(() => { + new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { + cluster, + taskImageOptions: { + image: ContainerImage.fromRegistry('test'), + }, + taskDefinition, + }); + }).toThrow(/You must specify only one of TaskDefinition or TaskImageOptions./); + }); + + test('errors when setting neither taskDefinition nor taskImageOptions', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); + + // THEN + expect(() => { + new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { + cluster, + }); + }).toThrow(/You must specify one of: taskDefinition or image/); + }); + + test('errors when setting domainName but not domainZone', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); + + // THEN + expect(() => { + new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { + cluster, + taskImageOptions: { + image: ContainerImage.fromRegistry('test'), + }, + loadBalancers: [ + { + name: 'lb1', + domainName: 'api.example.com', + listeners: [{ + name: 'listener1', + }], + }, + ], + }); + }).toThrow(/A Route53 hosted domain zone name is required to configure the specified domain name/); + }); + + test('errors when loadBalancers is empty', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new Cluster(stack, 'Cluster', { vpc }); + + // THEN + expect(() => { + new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { + cluster, + taskImageOptions: { + image: ContainerImage.fromRegistry('test'), + }, + loadBalancers: [], + }); + }).toThrow(/At least one load balancer must be specified/); + }); + + test('errors when targetGroups is empty', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new Cluster(stack, 'Cluster', { vpc }); + + // THEN + expect(() => { + new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { + cluster, + taskImageOptions: { + image: ContainerImage.fromRegistry('test'), + }, + targetGroups: [], + }); + }).toThrow(/At least one target group should be specified/); + }); + + test('errors when no listener specified', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new Cluster(stack, 'Cluster', { vpc }); + + // THEN + expect(() => { + new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { + cluster, + taskImageOptions: { + image: ContainerImage.fromRegistry('test'), + }, + loadBalancers: [ + { + name: 'lb', + listeners: [], + }, + ], + }); + }).toThrow(/At least one listener must be specified/); + }); + + test('errors when listener is not defined but used in creating target groups', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new Cluster(stack, 'Cluster', { vpc }); + + // THEN + expect(() => { + new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { + cluster, + taskImageOptions: { + image: ContainerImage.fromRegistry('test'), + }, + loadBalancers: [ + { + name: 'lb', + listeners: [ + { + name: 'listener1', + }, + ], + }, + ], + targetGroups: [ + { + containerPort: 80, + listener: 'listener2', + }, + ], + }); + }).toThrow(/Listener listener2 is not defined. Did you define listener with name listener2?/); + }); + + test('errors if desiredTaskCount is 0', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); + + // THEN + expect(() => + new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { + cluster, + memoryLimitMiB: 1024, + taskImageOptions: { + image: ContainerImage.fromRegistry('test'), + }, + desiredCount: 0, + })).toThrow(/You must specify a desiredCount greater than 0/); + }); +}); diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/l3s.test.ts b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/l3s.test.ts new file mode 100644 index 0000000000000..6248c9c4d14dd --- /dev/null +++ b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/l3s.test.ts @@ -0,0 +1,1338 @@ +import { ABSENT, arrayWith, objectLike, SynthUtils } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; +import { Certificate } from '@aws-cdk/aws-certificatemanager'; +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as ecs from '@aws-cdk/aws-ecs'; +import { ApplicationLoadBalancer, ApplicationProtocol, ApplicationProtocolVersion, NetworkLoadBalancer, SslPolicy } from '@aws-cdk/aws-elasticloadbalancingv2'; +import { PublicHostedZone } from '@aws-cdk/aws-route53'; +import * as cloudmap from '@aws-cdk/aws-servicediscovery'; +import * as cdk from '@aws-cdk/core'; +import * as cxapi from '@aws-cdk/cx-api'; +import * as ecsPatterns from '../../lib'; + +test('test ECS loadbalanced construct', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedEc2Service(stack, 'Service', { + cluster, + memoryLimitMiB: 1024, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('test'), + environment: { + TEST_ENVIRONMENT_VARIABLE1: 'test environment variable 1 value', + TEST_ENVIRONMENT_VARIABLE2: 'test environment variable 2 value', + }, + dockerLabels: { label1: 'labelValue1', label2: 'labelValue2' }, + }, + desiredCount: 2, + }); + + // THEN - stack contains a load balancer and a service + expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::LoadBalancer'); + + expect(stack).toHaveResource('AWS::ECS::Service', { + DesiredCount: 2, + LaunchType: 'EC2', + }); + + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Environment: [ + { + Name: 'TEST_ENVIRONMENT_VARIABLE1', + Value: 'test environment variable 1 value', + }, + { + Name: 'TEST_ENVIRONMENT_VARIABLE2', + Value: 'test environment variable 2 value', + }, + ], + Memory: 1024, + DockerLabels: { + label1: 'labelValue1', + label2: 'labelValue2', + }, + }, + ], + }); +}); + +test('ApplicationLoadBalancedEc2Service desiredCount can be undefined when feature flag is set', () => { + // GIVEN + const stack = new cdk.Stack(); + stack.node.setContext(cxapi.ECS_REMOVE_DEFAULT_DESIRED_COUNT, true); + + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedEc2Service(stack, 'Service', { + cluster, + memoryLimitMiB: 1024, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('test'), + }, + }); + + expect(stack).toHaveResource('AWS::ECS::Service', { + DesiredCount: ABSENT, + }); +}); + +test('ApplicationLoadBalancedFargateService desiredCount can be undefined when feature flag is set', () => { + // GIVEN + const stack = new cdk.Stack(); + stack.node.setContext(cxapi.ECS_REMOVE_DEFAULT_DESIRED_COUNT, true); + + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('test'), + }, + }); + + expect(stack).toHaveResource('AWS::ECS::Service', { + DesiredCount: ABSENT, + }); +}); + +test('NetworkLoadBalancedEc2Service desiredCount can be undefined when feature flag is set', () => { + // GIVEN + const stack = new cdk.Stack(); + stack.node.setContext(cxapi.ECS_REMOVE_DEFAULT_DESIRED_COUNT, true); + + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); + + // WHEN + new ecsPatterns.NetworkLoadBalancedEc2Service(stack, 'Service', { + cluster, + memoryLimitMiB: 1024, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('test'), + }, + }); + + expect(stack).toHaveResource('AWS::ECS::Service', { + DesiredCount: ABSENT, + }); +}); + +test('NetworkLoadBalancedFargateService desiredCount can be undefined when feature flag is set', () => { + // GIVEN + const stack = new cdk.Stack(); + stack.node.setContext(cxapi.ECS_REMOVE_DEFAULT_DESIRED_COUNT, true); + + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('test'), + }, + }); + + expect(stack).toHaveResource('AWS::ECS::Service', { + DesiredCount: ABSENT, + }); +}); + +test('set vpc instead of cluster', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedEc2Service(stack, 'Service', { + vpc, + memoryLimitMiB: 1024, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('test'), + environment: { + TEST_ENVIRONMENT_VARIABLE1: 'test environment variable 1 value', + TEST_ENVIRONMENT_VARIABLE2: 'test environment variable 2 value', + }, + }, + desiredCount: 2, + }); + + // THEN - stack does not contain a LaunchConfiguration\ + const template = SynthUtils.synthesize(stack, { skipValidation: true }); + expect(template).not.toHaveResource('AWS::AutoScaling::LaunchConfiguration'); + expect(() => SynthUtils.synthesize(stack)).toThrow(); +}); + +test('setting vpc and cluster throws error', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + expect(() => new ecsPatterns.NetworkLoadBalancedEc2Service(stack, 'Service', { + cluster, + vpc, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), + }, + })).toThrow(); +}); + +test('test ECS loadbalanced construct with memoryReservationMiB', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedEc2Service(stack, 'Service', { + cluster, + memoryReservationMiB: 1024, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('test'), + }, + }); + + // THEN - stack contains a load balancer and a service + expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::LoadBalancer'); + + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + MemoryReservation: 1024, + }, + ], + }); +}); + +test('creates AWS Cloud Map service for Private DNS namespace with application load balanced ec2 service', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'MyVpc', {}); + const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); + + // WHEN + cluster.addDefaultCloudMapNamespace({ + name: 'foo.com', + type: cloudmap.NamespaceType.DNS_PRIVATE, + }); + + new ecsPatterns.ApplicationLoadBalancedEc2Service(stack, 'Service', { + cluster, + taskImageOptions: { + containerPort: 8000, + image: ecs.ContainerImage.fromRegistry('hello'), + }, + cloudMapOptions: { + name: 'myApp', + }, + memoryLimitMiB: 512, + }); + + // THEN + expect(stack).toHaveResource('AWS::ECS::Service', { + ServiceRegistries: [ + { + ContainerName: 'web', + ContainerPort: 8000, + RegistryArn: { + 'Fn::GetAtt': [ + 'ServiceCloudmapServiceDE76B29D', + 'Arn', + ], + }, + }, + ], + }); + + expect(stack).toHaveResource('AWS::ServiceDiscovery::Service', { + DnsConfig: { + DnsRecords: [ + { + TTL: 60, + Type: 'SRV', + }, + ], + NamespaceId: { + 'Fn::GetAtt': [ + 'EcsClusterDefaultServiceDiscoveryNamespaceB0971B2F', + 'Id', + ], + }, + RoutingPolicy: 'MULTIVALUE', + }, + HealthCheckCustomConfig: { + FailureThreshold: 1, + }, + Name: 'myApp', + NamespaceId: { + 'Fn::GetAtt': [ + 'EcsClusterDefaultServiceDiscoveryNamespaceB0971B2F', + 'Id', + ], + }, + }); +}); + +test('creates AWS Cloud Map service for Private DNS namespace with network load balanced fargate service', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'MyVpc', {}); + const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); + + // WHEN + cluster.addDefaultCloudMapNamespace({ + name: 'foo.com', + type: cloudmap.NamespaceType.DNS_PRIVATE, + }); + + new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + containerPort: 8000, + image: ecs.ContainerImage.fromRegistry('hello'), + }, + cloudMapOptions: { + name: 'myApp', + }, + memoryLimitMiB: 512, + }); + + // THEN + expect(stack).toHaveResource('AWS::ECS::Service', { + ServiceRegistries: [ + { + RegistryArn: { + 'Fn::GetAtt': [ + 'ServiceCloudmapServiceDE76B29D', + 'Arn', + ], + }, + }, + ], + }); + + expect(stack).toHaveResource('AWS::ServiceDiscovery::Service', { + DnsConfig: { + DnsRecords: [ + { + TTL: 60, + Type: 'A', + }, + ], + NamespaceId: { + 'Fn::GetAtt': [ + 'EcsClusterDefaultServiceDiscoveryNamespaceB0971B2F', + 'Id', + ], + }, + RoutingPolicy: 'MULTIVALUE', + }, + HealthCheckCustomConfig: { + FailureThreshold: 1, + }, + Name: 'myApp', + NamespaceId: { + 'Fn::GetAtt': [ + 'EcsClusterDefaultServiceDiscoveryNamespaceB0971B2F', + 'Id', + ], + }, + }); +}); + +test('test Fargate loadbalanced construct', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('test'), + environment: { + TEST_ENVIRONMENT_VARIABLE1: 'test environment variable 1 value', + TEST_ENVIRONMENT_VARIABLE2: 'test environment variable 2 value', + }, + dockerLabels: { label1: 'labelValue1', label2: 'labelValue2' }, + }, + desiredCount: 2, + }); + + // THEN - stack contains a load balancer and a service + expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::LoadBalancer'); + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Environment: [ + { + Name: 'TEST_ENVIRONMENT_VARIABLE1', + Value: 'test environment variable 1 value', + }, + { + Name: 'TEST_ENVIRONMENT_VARIABLE2', + Value: 'test environment variable 2 value', + }, + ], + LogConfiguration: { + LogDriver: 'awslogs', + Options: { + 'awslogs-group': { Ref: 'ServiceTaskDefwebLogGroup2A898F61' }, + 'awslogs-stream-prefix': 'Service', + 'awslogs-region': { Ref: 'AWS::Region' }, + }, + }, + DockerLabels: { + label1: 'labelValue1', + label2: 'labelValue2', + }, + }, + ], + }); + + expect(stack).toHaveResource('AWS::ECS::Service', { + DesiredCount: 2, + LaunchType: 'FARGATE', + }); + + expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::Listener', { + Port: 80, + Protocol: 'HTTP', + }); +}); + +test('test Fargate loadbalanced construct opting out of log driver creation', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('test'), + enableLogging: false, + environment: { + TEST_ENVIRONMENT_VARIABLE1: 'test environment variable 1 value', + TEST_ENVIRONMENT_VARIABLE2: 'test environment variable 2 value', + }, + }, + desiredCount: 2, + }); + + // THEN - stack contains a load balancer and a service + expect(stack).not.toHaveResource('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Environment: [ + { + Name: 'TEST_ENVIRONMENT_VARIABLE1', + Value: 'test environment variable 1 value', + }, + { + Name: 'TEST_ENVIRONMENT_VARIABLE2', + Value: 'test environment variable 2 value', + }, + ], + LogConfiguration: { + LogDriver: 'awslogs', + Options: { + 'awslogs-group': { Ref: 'ServiceTaskDefwebLogGroup2A898F61' }, + 'awslogs-stream-prefix': 'Service', + 'awslogs-region': { Ref: 'AWS::Region' }, + }, + }, + }, + ], + }); +}); + +test('test Fargate loadbalanced construct with TLS', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + const zone = new PublicHostedZone(stack, 'HostedZone', { zoneName: 'example.com' }); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('test'), + }, + domainName: 'api.example.com', + domainZone: zone, + certificate: Certificate.fromCertificateArn(stack, 'Cert', 'helloworld'), + sslPolicy: SslPolicy.TLS12_EXT, + }); + + // THEN - stack contains a load balancer and a service + expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::LoadBalancer'); + + expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::Listener', { + Port: 443, + Protocol: 'HTTPS', + Certificates: [{ + CertificateArn: 'helloworld', + }], + SslPolicy: SslPolicy.TLS12_EXT, + }); + + expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::TargetGroup', { + Port: 80, + Protocol: 'HTTP', + TargetType: 'ip', + VpcId: { + Ref: 'VPCB9E5F0B4', + }, + }); + + expect(stack).toHaveResource('AWS::ECS::Service', { + DesiredCount: 1, + LaunchType: 'FARGATE', + }); + + expect(stack).toHaveResource('AWS::Route53::RecordSet', { + Name: 'api.example.com.', + HostedZoneId: { + Ref: 'HostedZoneDB99F866', + }, + Type: 'A', + AliasTarget: { + HostedZoneId: { 'Fn::GetAtt': ['ServiceLBE9A1ADBC', 'CanonicalHostedZoneID'] }, + DNSName: { 'Fn::Join': ['', ['dualstack.', { 'Fn::GetAtt': ['ServiceLBE9A1ADBC', 'DNSName'] }]] }, + }, + }); +}); + +test('test Fargateloadbalanced construct with TLS and default certificate', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + const zone = new PublicHostedZone(stack, 'HostedZone', { zoneName: 'example.com' }); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('test'), + }, + domainName: 'api.example.com', + domainZone: zone, + protocol: ApplicationProtocol.HTTPS, + }); + + // THEN - stack contains a load balancer, a service, and a certificate + expect(stack).toHaveResource('AWS::CertificateManager::Certificate', { + DomainName: 'api.example.com', + DomainValidationOptions: [ + { + DomainName: 'api.example.com', + HostedZoneId: { + Ref: 'HostedZoneDB99F866', + }, + }, + ], + ValidationMethod: 'DNS', + }); + + expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::LoadBalancer'); + + expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::Listener', { + Port: 443, + Protocol: 'HTTPS', + Certificates: [{ + CertificateArn: { + Ref: 'ServiceCertificateA7C65FE6', + }, + }], + }); + + expect(stack).toHaveResource('AWS::ECS::Service', { + DesiredCount: 1, + LaunchType: 'FARGATE', + }); + + expect(stack).toHaveResource('AWS::Route53::RecordSet', { + Name: 'api.example.com.', + HostedZoneId: { + Ref: 'HostedZoneDB99F866', + }, + Type: 'A', + AliasTarget: { + HostedZoneId: { 'Fn::GetAtt': ['ServiceLBE9A1ADBC', 'CanonicalHostedZoneID'] }, + DNSName: { 'Fn::Join': ['', ['dualstack.', { 'Fn::GetAtt': ['ServiceLBE9A1ADBC', 'DNSName'] }]] }, + }, + }); +}); + +test('errors when setting domainName but not domainZone', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // THEN + expect(() => { + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('test'), + }, + domainName: 'api.example.com', + }); + }).toThrow(); +}); + +test('errors when setting both HTTP protocol and certificate', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // THEN + expect(() => { + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('test'), + }, + protocol: ApplicationProtocol.HTTP, + certificate: Certificate.fromCertificateArn(stack, 'Cert', 'helloworld'), + }); + }).toThrow(); +}); + +test('errors when setting both HTTP protocol and redirectHTTP', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // THEN + expect(() => { + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('test'), + }, + protocol: ApplicationProtocol.HTTP, + redirectHTTP: true, + }); + }).toThrow(); +}); + +test('does not throw errors when not setting HTTPS protocol but certificate for redirectHTTP', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + const zone = new PublicHostedZone(stack, 'HostedZone', { zoneName: 'example.com' }); + + // THEN + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('test'), + }, + domainName: 'api.example.com', + domainZone: zone, + redirectHTTP: true, + certificate: Certificate.fromCertificateArn(stack, 'Cert', 'helloworld'), + }); +}); + +test('errors when setting HTTPS protocol but not domain name', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // THEN + expect(() => { + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('test'), + }, + protocol: ApplicationProtocol.HTTPS, + }); + }).toThrow(); +}); + +test('test Fargate loadbalanced construct with optional log driver input', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('test'), + enableLogging: false, + environment: { + TEST_ENVIRONMENT_VARIABLE1: 'test environment variable 1 value', + TEST_ENVIRONMENT_VARIABLE2: 'test environment variable 2 value', + }, + logDriver: new ecs.AwsLogDriver({ + streamPrefix: 'TestStream', + }), + }, + desiredCount: 2, + }); + + // THEN - stack contains a load balancer and a service + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Environment: [ + { + Name: 'TEST_ENVIRONMENT_VARIABLE1', + Value: 'test environment variable 1 value', + }, + { + Name: 'TEST_ENVIRONMENT_VARIABLE2', + Value: 'test environment variable 2 value', + }, + ], + LogConfiguration: { + LogDriver: 'awslogs', + Options: { + 'awslogs-group': { Ref: 'ServiceTaskDefwebLogGroup2A898F61' }, + 'awslogs-stream-prefix': 'TestStream', + 'awslogs-region': { Ref: 'AWS::Region' }, + }, + }, + }, + ], + }); +}); + +test('test Fargate loadbalanced construct with logging enabled', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('test'), + enableLogging: true, + environment: { + TEST_ENVIRONMENT_VARIABLE1: 'test environment variable 1 value', + TEST_ENVIRONMENT_VARIABLE2: 'test environment variable 2 value', + }, + }, + desiredCount: 2, + }); + + // THEN - stack contains a load balancer and a service + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Environment: [ + { + Name: 'TEST_ENVIRONMENT_VARIABLE1', + Value: 'test environment variable 1 value', + }, + { + Name: 'TEST_ENVIRONMENT_VARIABLE2', + Value: 'test environment variable 2 value', + }, + ], + LogConfiguration: { + LogDriver: 'awslogs', + Options: { + 'awslogs-group': { Ref: 'ServiceTaskDefwebLogGroup2A898F61' }, + 'awslogs-stream-prefix': 'Service', + 'awslogs-region': { Ref: 'AWS::Region' }, + }, + }, + }, + ], + }); +}); + +test('test Fargate loadbalanced construct with both image and taskDefinition provided', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'Ec2TaskDef'); + taskDefinition.addContainer('web', { + image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + memoryLimitMiB: 512, + }); + + // WHEN + expect(() => new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('test'), + enableLogging: true, + environment: { + TEST_ENVIRONMENT_VARIABLE1: 'test environment variable 1 value', + TEST_ENVIRONMENT_VARIABLE2: 'test environment variable 2 value', + }, + }, + desiredCount: 2, + taskDefinition, + })).toThrow(); +}); + +test('test Fargate application loadbalanced construct with taskDefinition provided', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + const taskDefinition = new ecs.FargateTaskDefinition(stack, 'FargateTaskDef'); + const container = taskDefinition.addContainer('passedTaskDef', { + image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + memoryLimitMiB: 512, + }); + container.addPortMappings({ + containerPort: 80, + }); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { + cluster, + taskDefinition, + desiredCount: 2, + memoryLimitMiB: 1024, + }); + + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Image: 'amazon/amazon-ecs-sample', + Memory: 512, + Name: 'passedTaskDef', + PortMappings: [ + { + ContainerPort: 80, + Protocol: 'tcp', + }, + ], + }, + ], + }); +}); + +test('ALB - throws if desiredTaskCount is 0', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); + + // THEN + expect(() => + new ecsPatterns.ApplicationLoadBalancedEc2Service(stack, 'Service', { + cluster, + memoryLimitMiB: 1024, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('test'), + }, + desiredCount: 0, + }), + ).toThrow(/You must specify a desiredCount greater than 0/); +}); + +test('NLB - throws if desiredTaskCount is 0', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); + + // THEN + expect(() => + new ecsPatterns.NetworkLoadBalancedEc2Service(stack, 'Service', { + cluster, + memoryLimitMiB: 1024, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('test'), + }, + desiredCount: 0, + }), + ).toThrow(/You must specify a desiredCount greater than 0/); +}); + +test('ALBFargate - having *HealthyPercent properties', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'ALB123Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + }, + minHealthyPercent: 100, + maxHealthyPercent: 200, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ECS::Service', { + DeploymentConfiguration: { + MinimumHealthyPercent: 100, + MaximumPercent: 200, + }, + }); +}); + +test('NLBFargate - having *HealthyPercent properties', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'Service', { + cluster, + memoryLimitMiB: 1024, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + }, + desiredCount: 1, + minHealthyPercent: 100, + maxHealthyPercent: 200, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ECS::Service', { + DeploymentConfiguration: { + MinimumHealthyPercent: 100, + MaximumPercent: 200, + }, + }); +}); + +test('ALB - having *HealthyPercent properties', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedEc2Service(stack, 'Service', { + cluster, + memoryLimitMiB: 1024, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + }, + desiredCount: 1, + minHealthyPercent: 100, + maxHealthyPercent: 200, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ECS::Service', { + DeploymentConfiguration: { + MinimumHealthyPercent: 100, + MaximumPercent: 200, + }, + }); +}); + +test('ALB - includes provided protocol version properties', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); + const zone = new PublicHostedZone(stack, 'HostedZone', { zoneName: 'example.com' }); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedEc2Service(stack, 'Service', { + cluster, + memoryLimitMiB: 1024, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + }, + desiredCount: 1, + domainName: 'api.example.com', + domainZone: zone, + protocol: ApplicationProtocol.HTTPS, + protocolVersion: ApplicationProtocolVersion.GRPC, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ElasticLoadBalancingV2::TargetGroup', { + ProtocolVersion: 'GRPC', + }); +}); + +test('NLB - having *HealthyPercent properties', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); + + // WHEN + new ecsPatterns.NetworkLoadBalancedEc2Service(stack, 'Service', { + cluster, + memoryLimitMiB: 1024, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + }, + desiredCount: 1, + minHealthyPercent: 100, + maxHealthyPercent: 200, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ECS::Service', { + DeploymentConfiguration: { + MinimumHealthyPercent: 100, + MaximumPercent: 200, + }, + }); +}); + +test('ALB - having deployment controller', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedEc2Service(stack, 'Service', { + cluster, + memoryLimitMiB: 1024, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + }, + deploymentController: { + type: ecs.DeploymentControllerType.CODE_DEPLOY, + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ECS::Service', { + DeploymentController: { + Type: 'CODE_DEPLOY', + }, + }); +}); + +test('NLB - having deployment controller', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); + + // WHEN + new ecsPatterns.NetworkLoadBalancedEc2Service(stack, 'Service', { + cluster, + memoryLimitMiB: 1024, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + }, + deploymentController: { + type: ecs.DeploymentControllerType.CODE_DEPLOY, + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ECS::Service', { + DeploymentController: { + Type: 'CODE_DEPLOY', + }, + }); +}); + +test('ALB with circuit breaker', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedEc2Service(stack, 'Service', { + cluster, + memoryLimitMiB: 1024, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + }, + circuitBreaker: { rollback: true }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ECS::Service', { + DeploymentConfiguration: { + DeploymentCircuitBreaker: { + Enable: true, + Rollback: true, + }, + }, + DeploymentController: { + Type: 'ECS', + }, + }); +}); + +test('NLB with circuit breaker', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); + + // WHEN + new ecsPatterns.NetworkLoadBalancedEc2Service(stack, 'Service', { + cluster, + memoryLimitMiB: 1024, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + }, + circuitBreaker: { rollback: true }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ECS::Service', { + DeploymentConfiguration: { + DeploymentCircuitBreaker: { + Enable: true, + Rollback: true, + }, + }, + DeploymentController: { + Type: 'ECS', + }, + }); +}); + +test('NetworkLoadbalancedEC2Service accepts previously created load balancer', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'Vpc'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc, clusterName: 'MyCluster' }); + cluster.addCapacity('Capacity', { instanceType: new ec2.InstanceType('t2.micro') }); + const nlb = new NetworkLoadBalancer(stack, 'NLB', { vpc }); + const taskDef = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); + const container = taskDef.addContainer('Container', { + image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + memoryLimitMiB: 1024, + }); + container.addPortMappings({ containerPort: 80 }); + + // WHEN + new ecsPatterns.NetworkLoadBalancedEc2Service(stack, 'Service', { + cluster, + loadBalancer: nlb, + taskDefinition: taskDef, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ECS::Service', { + LaunchType: 'EC2', + }); + expect(stack).toHaveResourceLike('AWS::ElasticLoadBalancingV2::LoadBalancer', { + Type: 'network', + }); +}); + +test('NetworkLoadBalancedEC2Service accepts imported load balancer', () => { + // GIVEN + const stack = new cdk.Stack(); + const nlbArn = 'arn:aws:elasticloadbalancing:us-west-2:123456789012:loadbalancer/app/my-load-balancer/50dc6c495c0c9188'; + const vpc = new ec2.Vpc(stack, 'Vpc'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc, clusterName: 'MyCluster' }); + cluster.addCapacity('Capacity', { instanceType: new ec2.InstanceType('t2.micro') }); + const nlb = NetworkLoadBalancer.fromNetworkLoadBalancerAttributes(stack, 'NLB', { + loadBalancerArn: nlbArn, + vpc, + }); + const taskDef = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); + const container = taskDef.addContainer('Container', { + image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + memoryLimitMiB: 1024, + }); + container.addPortMappings({ + containerPort: 80, + }); + + // WHEN + new ecsPatterns.NetworkLoadBalancedEc2Service(stack, 'Service', { + cluster, + loadBalancer: nlb, + desiredCount: 1, + taskDefinition: taskDef, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ECS::Service', { + LaunchType: 'EC2', + LoadBalancers: [{ ContainerName: 'Container', ContainerPort: 80 }], + }); + expect(stack).toHaveResourceLike('AWS::ElasticLoadBalancingV2::TargetGroup'); + expect(stack).toHaveResourceLike('AWS::ElasticLoadBalancingV2::Listener', { + LoadBalancerArn: nlb.loadBalancerArn, + Port: 80, + }); +}); + +test('ApplicationLoadBalancedEC2Service accepts previously created load balancer', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'Vpc'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc, clusterName: 'MyCluster' }); + cluster.addCapacity('Capacity', { instanceType: new ec2.InstanceType('t2.micro') }); + const sg = new ec2.SecurityGroup(stack, 'SG', { vpc }); + const alb = new ApplicationLoadBalancer(stack, 'NLB', { + vpc, + securityGroup: sg, + }); + const taskDef = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); + const container = taskDef.addContainer('Container', { + image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + memoryLimitMiB: 1024, + }); + container.addPortMappings({ containerPort: 80 }); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedEc2Service(stack, 'Service', { + cluster, + loadBalancer: alb, + taskDefinition: taskDef, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ECS::Service', { + LaunchType: 'EC2', + }); + expect(stack).toHaveResourceLike('AWS::ElasticLoadBalancingV2::LoadBalancer', { + Type: 'application', + }); +}); + +test('ApplicationLoadBalancedEC2Service accepts imported load balancer', () => { + // GIVEN + const stack = new cdk.Stack(); + const albArn = 'arn:aws:elasticloadbalancing:us-west-2:123456789012:loadbalancer/app/my-load-balancer/50dc6c495c0c9188'; + const vpc = new ec2.Vpc(stack, 'Vpc'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc, clusterName: 'MyCluster' }); + cluster.addCapacity('Capacity', { instanceType: new ec2.InstanceType('t2.micro') }); + const sg = new ec2.SecurityGroup(stack, 'SG', { vpc }); + const alb = ApplicationLoadBalancer.fromApplicationLoadBalancerAttributes(stack, 'ALB', { + loadBalancerArn: albArn, + vpc, + securityGroupId: sg.securityGroupId, + loadBalancerDnsName: 'MyName', + }); + const taskDef = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); + const container = taskDef.addContainer('Container', { + image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + memoryLimitMiB: 1024, + }); + container.addPortMappings({ + containerPort: 80, + }); + // WHEN + new ecsPatterns.ApplicationLoadBalancedEc2Service(stack, 'Service', { + cluster, + loadBalancer: alb, + taskDefinition: taskDef, + }); + // THEN + expect(stack).toHaveResourceLike('AWS::ECS::Service', { + LaunchType: 'EC2', + LoadBalancers: [{ ContainerName: 'Container', ContainerPort: 80 }], + }); + expect(stack).toHaveResourceLike('AWS::ElasticLoadBalancingV2::TargetGroup'); + expect(stack).toHaveResourceLike('AWS::ElasticLoadBalancingV2::Listener', { + LoadBalancerArn: alb.loadBalancerArn, + Port: 80, + }); +}); + +test('test ECS loadbalanced construct default/open security group', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedEc2Service(stack, 'Service', { + cluster, + memoryReservationMiB: 1024, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('test'), + }, + }); + + // THEN - Stack contains no ingress security group rules + expect(stack).toHaveResourceLike('AWS::EC2::SecurityGroup', { + SecurityGroupIngress: [{ + CidrIp: '0.0.0.0/0', + FromPort: 80, + IpProtocol: 'tcp', + ToPort: 80, + }], + }); +}); + +test('test ECS loadbalanced construct closed security group', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); + const zone = new PublicHostedZone(stack, 'HostedZone', { zoneName: 'example.com' }); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedEc2Service(stack, 'Service', { + cluster, + memoryReservationMiB: 1024, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('test'), + }, + domainName: 'api.example.com', + domainZone: zone, + certificate: Certificate.fromCertificateArn(stack, 'Cert', 'helloworld'), + openListener: false, + redirectHTTP: true, + }); + + // THEN - Stack contains no ingress security group rules + expect(stack).not.toHaveResourceLike('AWS::EC2::SecurityGroup', { + SecurityGroupIngress: arrayWith(objectLike({})), + }); +}); diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/queue-processing-ecs-service.test.ts b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/queue-processing-ecs-service.test.ts new file mode 100644 index 0000000000000..60e6a7d0f6969 --- /dev/null +++ b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/queue-processing-ecs-service.test.ts @@ -0,0 +1,379 @@ +import { ABSENT } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; +import * as autoscaling from '@aws-cdk/aws-autoscaling'; +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as ecs from '@aws-cdk/aws-ecs'; +import * as sqs from '@aws-cdk/aws-sqs'; +import * as cdk from '@aws-cdk/core'; +import * as cxapi from '@aws-cdk/cx-api'; +import * as ecsPatterns from '../../lib'; + +test('test ECS queue worker service construct - with only required props', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); + + // WHEN + new ecsPatterns.QueueProcessingEc2Service(stack, 'Service', { + cluster, + memoryLimitMiB: 512, + image: ecs.ContainerImage.fromRegistry('test'), + }); + + // THEN - QueueWorker is of EC2 launch type, an SQS queue is created and all default properties are set. + expect(stack).toHaveResource('AWS::ECS::Service', { + DesiredCount: 1, + LaunchType: 'EC2', + }); + + expect(stack).toHaveResource('AWS::SQS::Queue', { + RedrivePolicy: { + deadLetterTargetArn: { + 'Fn::GetAtt': [ + 'ServiceEcsProcessingDeadLetterQueue4A89196E', + 'Arn', + ], + }, + maxReceiveCount: 3, + }, + }); + + expect(stack).toHaveResource('AWS::SQS::Queue', { + MessageRetentionPeriod: 1209600, + }); + + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Environment: [ + { + Name: 'QUEUE_NAME', + Value: { + 'Fn::GetAtt': [ + 'ServiceEcsProcessingQueueC266885C', + 'QueueName', + ], + }, + }, + ], + LogConfiguration: { + LogDriver: 'awslogs', + Options: { + 'awslogs-group': { + Ref: 'ServiceQueueProcessingTaskDefQueueProcessingContainerLogGroupD52338D1', + }, + 'awslogs-stream-prefix': 'Service', + 'awslogs-region': { + Ref: 'AWS::Region', + }, + }, + }, + Essential: true, + Image: 'test', + Memory: 512, + }, + ], + Family: 'ServiceQueueProcessingTaskDef83DB34F1', + }); +}); + +test('test ECS queue worker service construct - with remove default desiredCount feature flag', () => { + // GIVEN + const stack = new cdk.Stack(); + stack.node.setContext(cxapi.ECS_REMOVE_DEFAULT_DESIRED_COUNT, true); + + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); + + // WHEN + new ecsPatterns.QueueProcessingEc2Service(stack, 'Service', { + cluster, + memoryLimitMiB: 512, + image: ecs.ContainerImage.fromRegistry('test'), + }); + + // THEN - QueueWorker is of EC2 launch type, and desiredCount is not defined on the Ec2Service. + expect(stack).toHaveResource('AWS::ECS::Service', { + DesiredCount: ABSENT, + LaunchType: 'EC2', + }); +}); + +test('test ECS queue worker service construct - with optional props for queues', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); + + // WHEN + new ecsPatterns.QueueProcessingEc2Service(stack, 'Service', { + cluster, + memoryLimitMiB: 512, + image: ecs.ContainerImage.fromRegistry('test'), + maxReceiveCount: 42, + retentionPeriod: cdk.Duration.days(7), + visibilityTimeout: cdk.Duration.minutes(5), + }); + + // THEN - QueueWorker is of EC2 launch type, an SQS queue is created and all default properties are set. + expect(stack).toHaveResource('AWS::ECS::Service', { + DesiredCount: 1, + LaunchType: 'EC2', + }); + + expect(stack).toHaveResource('AWS::SQS::Queue', { + RedrivePolicy: { + deadLetterTargetArn: { + 'Fn::GetAtt': [ + 'ServiceEcsProcessingDeadLetterQueue4A89196E', + 'Arn', + ], + }, + maxReceiveCount: 42, + }, + VisibilityTimeout: 300, + }); + + expect(stack).toHaveResource('AWS::SQS::Queue', { + MessageRetentionPeriod: 604800, + }); + + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Environment: [ + { + Name: 'QUEUE_NAME', + Value: { + 'Fn::GetAtt': [ + 'ServiceEcsProcessingQueueC266885C', + 'QueueName', + ], + }, + }, + ], + LogConfiguration: { + LogDriver: 'awslogs', + Options: { + 'awslogs-group': { + Ref: 'ServiceQueueProcessingTaskDefQueueProcessingContainerLogGroupD52338D1', + }, + 'awslogs-stream-prefix': 'Service', + 'awslogs-region': { + Ref: 'AWS::Region', + }, + }, + }, + Essential: true, + Image: 'test', + Memory: 512, + }, + ], + Family: 'ServiceQueueProcessingTaskDef83DB34F1', + }); +}); + +test('test ECS queue worker service construct - with optional props', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); + const queue = new sqs.Queue(stack, 'ecs-test-queue', { + queueName: 'ecs-test-sqs-queue', + }); + + // WHEN + new ecsPatterns.QueueProcessingEc2Service(stack, 'Service', { + cluster, + memoryLimitMiB: 1024, + image: ecs.ContainerImage.fromRegistry('test'), + command: ['-c', '4', 'amazon.com'], + enableLogging: false, + desiredTaskCount: 2, + environment: { + TEST_ENVIRONMENT_VARIABLE1: 'test environment variable 1 value', + TEST_ENVIRONMENT_VARIABLE2: 'test environment variable 2 value', + }, + queue, + maxScalingCapacity: 5, + minHealthyPercent: 60, + maxHealthyPercent: 150, + serviceName: 'ecs-test-service', + family: 'ecs-task-family', + circuitBreaker: { rollback: true }, + gpuCount: 256, + }); + + // THEN - QueueWorker is of EC2 launch type, an SQS queue is created and all optional properties are set. + expect(stack).toHaveResource('AWS::ECS::Service', { + DesiredCount: 2, + DeploymentConfiguration: { + MinimumHealthyPercent: 60, + MaximumPercent: 150, + DeploymentCircuitBreaker: { + Enable: true, + Rollback: true, + }, + }, + LaunchType: 'EC2', + ServiceName: 'ecs-test-service', + DeploymentController: { + Type: 'ECS', + }, + }); + + expect(stack).toHaveResource('AWS::SQS::Queue', { + QueueName: 'ecs-test-sqs-queue', + }); + + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Command: [ + '-c', + '4', + 'amazon.com', + ], + Environment: [ + { + Name: 'TEST_ENVIRONMENT_VARIABLE1', + Value: 'test environment variable 1 value', + }, + { + Name: 'TEST_ENVIRONMENT_VARIABLE2', + Value: 'test environment variable 2 value', + }, + { + Name: 'QUEUE_NAME', + Value: { + 'Fn::GetAtt': [ + 'ecstestqueueD1FDA34B', + 'QueueName', + ], + }, + }, + ], + Image: 'test', + Memory: 1024, + ResourceRequirements: [ + { + Type: 'GPU', + Value: '256', + }, + ], + }, + ], + Family: 'ecs-task-family', + }); +}); + +test('can set desiredTaskCount to 0', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); + + // WHEN + new ecsPatterns.QueueProcessingEc2Service(stack, 'Service', { + cluster, + desiredTaskCount: 0, + maxScalingCapacity: 2, + memoryLimitMiB: 512, + image: ecs.ContainerImage.fromRegistry('test'), + }); + + // THEN - QueueWorker is of EC2 launch type, an SQS queue is created and all default properties are set. + expect(stack).toHaveResource('AWS::ECS::Service', { + DesiredCount: 0, + LaunchType: 'EC2', + }); +}); + +test('throws if desiredTaskCount and maxScalingCapacity are 0', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); + + // THEN + expect(() => + new ecsPatterns.QueueProcessingEc2Service(stack, 'Service', { + cluster, + desiredTaskCount: 0, + memoryLimitMiB: 512, + image: ecs.ContainerImage.fromRegistry('test'), + }), + ).toThrow(/maxScalingCapacity must be set and greater than 0 if desiredCount is 0/); +}); + +test('can set custom containerName', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); + + // WHEN + new ecsPatterns.QueueProcessingEc2Service(stack, 'Service', { + cluster, + memoryLimitMiB: 512, + image: ecs.ContainerImage.fromRegistry('test'), + containerName: 'my-container', + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Name: 'my-container', + }, + ], + }); +}); + +test('can set capacity provider strategies', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + const autoScalingGroup = new autoscaling.AutoScalingGroup(stack, 'asg', { + vpc, + instanceType: new ec2.InstanceType('bogus'), + machineImage: ecs.EcsOptimizedImage.amazonLinux2(), + }); + const capacityProvider = new ecs.AsgCapacityProvider(stack, 'provider', { + autoScalingGroup, + }); + cluster.addAsgCapacityProvider(capacityProvider); + + // WHEN + new ecsPatterns.QueueProcessingEc2Service(stack, 'Service', { + cluster, + image: ecs.ContainerImage.fromRegistry('test'), + memoryLimitMiB: 512, + capacityProviderStrategies: [ + { + capacityProvider: capacityProvider.capacityProviderName, + }, + ], + }); + + // THEN + expect(stack).toHaveResource('AWS::ECS::Service', { + LaunchType: ABSENT, + CapacityProviderStrategy: [ + { + CapacityProvider: { + Ref: 'providerD3FF4D3A', + }, + }, + ], + }); +}); diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/scheduled-ecs-task.test.ts b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/scheduled-ecs-task.test.ts new file mode 100644 index 0000000000000..745d6a17460bc --- /dev/null +++ b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/scheduled-ecs-task.test.ts @@ -0,0 +1,325 @@ +import '@aws-cdk/assert-internal/jest'; +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as ecs from '@aws-cdk/aws-ecs'; +import * as events from '@aws-cdk/aws-events'; +import * as cdk from '@aws-cdk/core'; +import { ScheduledEc2Task } from '../../lib'; + +test('Can create a scheduled Ec2 Task - with only required props', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 1 }); + const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { + instanceType: new ec2.InstanceType('t2.micro'), + }); + + new ScheduledEc2Task(stack, 'ScheduledEc2Task', { + cluster, + scheduledEc2TaskImageOptions: { + image: ecs.ContainerImage.fromRegistry('henk'), + memoryLimitMiB: 512, + }, + schedule: events.Schedule.expression('rate(1 minute)'), + }); + + // THEN + expect(stack).toHaveResource('AWS::Events::Rule', { + State: 'ENABLED', + Targets: [ + { + Arn: { 'Fn::GetAtt': ['EcsCluster97242B84', 'Arn'] }, + EcsParameters: { + TaskCount: 1, + TaskDefinitionArn: { Ref: 'ScheduledEc2TaskScheduledTaskDef56328BA4' }, + }, + Id: 'Target0', + Input: '{}', + RoleArn: { 'Fn::GetAtt': ['ScheduledEc2TaskScheduledTaskDefEventsRole64113C5F', 'Arn'] }, + }, + ], + }); + + expect(stack).toHaveResource('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Essential: true, + Image: 'henk', + LogConfiguration: { + LogDriver: 'awslogs', + Options: { + 'awslogs-group': { + Ref: 'ScheduledEc2TaskScheduledTaskDefScheduledContainerLogGroupA85E11E6', + }, + 'awslogs-stream-prefix': 'ScheduledEc2Task', + 'awslogs-region': { + Ref: 'AWS::Region', + }, + }, + }, + Memory: 512, + Name: 'ScheduledContainer', + }, + ], + }); +}); + +test('Can create a scheduled Ec2 Task - with optional props', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 1 }); + const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); + + cluster.addCapacity('DefaultAutoScalingGroup', { + instanceType: new ec2.InstanceType('t2.micro'), + }); + + new ScheduledEc2Task(stack, 'ScheduledEc2Task', { + cluster, + enabled: false, + scheduledEc2TaskImageOptions: { + image: ecs.ContainerImage.fromRegistry('henk'), + memoryLimitMiB: 512, + cpu: 2, + environment: { TRIGGER: 'CloudWatch Events' }, + }, + desiredTaskCount: 2, + schedule: events.Schedule.expression('rate(1 minute)'), + ruleName: 'sample-scheduled-task-rule', + }); + + // THEN + expect(stack).toHaveResource('AWS::Events::Rule', { + Name: 'sample-scheduled-task-rule', + State: 'DISABLED', + Targets: [ + { + Arn: { 'Fn::GetAtt': ['EcsCluster97242B84', 'Arn'] }, + EcsParameters: { + TaskCount: 2, + TaskDefinitionArn: { Ref: 'ScheduledEc2TaskScheduledTaskDef56328BA4' }, + }, + Id: 'Target0', + Input: '{}', + RoleArn: { 'Fn::GetAtt': ['ScheduledEc2TaskScheduledTaskDefEventsRole64113C5F', 'Arn'] }, + }, + ], + }); + + expect(stack).toHaveResource('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Cpu: 2, + Environment: [ + { + Name: 'TRIGGER', + Value: 'CloudWatch Events', + }, + ], + Essential: true, + Image: 'henk', + LogConfiguration: { + LogDriver: 'awslogs', + Options: { + 'awslogs-group': { + Ref: 'ScheduledEc2TaskScheduledTaskDefScheduledContainerLogGroupA85E11E6', + }, + 'awslogs-stream-prefix': 'ScheduledEc2Task', + 'awslogs-region': { + Ref: 'AWS::Region', + }, + }, + }, + Memory: 512, + Name: 'ScheduledContainer', + }, + ], + }); +}); + +test('Scheduled ECS Task - with securityGroups defined', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 1 }); + const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); + const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'Ec2TaskDef', { + networkMode: ecs.NetworkMode.AWS_VPC, + }); + const sg = new ec2.SecurityGroup(stack, 'MySG', { vpc }); + + new ScheduledEc2Task(stack, 'ScheduledEc2Task', { + cluster, + scheduledEc2TaskDefinitionOptions: { + taskDefinition, + }, + schedule: events.Schedule.expression('rate(1 minute)'), + securityGroups: [sg], + }); + + // THEN + expect(stack).toHaveResource('AWS::Events::Rule', { + Targets: [ + { + Arn: { 'Fn::GetAtt': ['EcsCluster97242B84', 'Arn'] }, + EcsParameters: { + LaunchType: 'EC2', + NetworkConfiguration: { + AwsVpcConfiguration: { + AssignPublicIp: 'DISABLED', + SecurityGroups: [{ + 'Fn::GetAtt': [ + 'MySG94FE69A8', + 'GroupId', + ], + }], + Subnets: [ + { + Ref: 'VpcPrivateSubnet1Subnet536B997A', + }, + ], + }, + }, + TaskCount: 1, + TaskDefinitionArn: { Ref: 'Ec2TaskDef0226F28C' }, + }, + Id: 'Target0', + Input: '{}', + RoleArn: { 'Fn::GetAtt': ['Ec2TaskDefEventsRoleA0756175', 'Arn'] }, + }, + ], + }); +}); + +test('Scheduled Ec2 Task - with MemoryReservation defined', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 1 }); + const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { + instanceType: new ec2.InstanceType('t2.micro'), + }); + + new ScheduledEc2Task(stack, 'ScheduledEc2Task', { + cluster, + scheduledEc2TaskImageOptions: { + image: ecs.ContainerImage.fromRegistry('henk'), + memoryReservationMiB: 512, + }, + schedule: events.Schedule.expression('rate(1 minute)'), + }); + + // THEN + expect(stack).toHaveResource('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Essential: true, + Image: 'henk', + LogConfiguration: { + LogDriver: 'awslogs', + Options: { + 'awslogs-group': { + Ref: 'ScheduledEc2TaskScheduledTaskDefScheduledContainerLogGroupA85E11E6', + }, + 'awslogs-stream-prefix': 'ScheduledEc2Task', + 'awslogs-region': { + Ref: 'AWS::Region', + }, + }, + }, + MemoryReservation: 512, + Name: 'ScheduledContainer', + }, + ], + }); +}); + +test('Scheduled Ec2 Task - with Command defined', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 1 }); + const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { + instanceType: new ec2.InstanceType('t2.micro'), + }); + + new ScheduledEc2Task(stack, 'ScheduledEc2Task', { + cluster, + scheduledEc2TaskImageOptions: { + image: ecs.ContainerImage.fromRegistry('henk'), + memoryReservationMiB: 512, + command: ['-c', '4', 'amazon.com'], + }, + schedule: events.Schedule.expression('rate(1 minute)'), + }); + + // THEN + expect(stack).toHaveResource('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Command: [ + '-c', + '4', + 'amazon.com', + ], + Essential: true, + Image: 'henk', + LogConfiguration: { + LogDriver: 'awslogs', + Options: { + 'awslogs-group': { + Ref: 'ScheduledEc2TaskScheduledTaskDefScheduledContainerLogGroupA85E11E6', + }, + 'awslogs-stream-prefix': 'ScheduledEc2Task', + 'awslogs-region': { + Ref: 'AWS::Region', + }, + }, + }, + MemoryReservation: 512, + Name: 'ScheduledContainer', + }, + ], + }); +}); + +test('throws if desiredTaskCount is 0', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 1 }); + const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { + instanceType: new ec2.InstanceType('t2.micro'), + }); + + // THEN + expect(() => + new ScheduledEc2Task(stack, 'ScheduledEc2Task', { + cluster, + scheduledEc2TaskImageOptions: { + image: ecs.ContainerImage.fromRegistry('henk'), + memoryLimitMiB: 512, + }, + schedule: events.Schedule.expression('rate(1 minute)'), + desiredTaskCount: 0, + }), + ).toThrow(/You must specify a desiredTaskCount greater than 0/); +}); + +test('Scheduled Ec2 Task - exposes ECS Task', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 1 }); + const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); + + const scheduledEc2Task = new ScheduledEc2Task(stack, 'ScheduledEc2Task', { + cluster, + scheduledEc2TaskImageOptions: { + image: ecs.ContainerImage.fromRegistry('henk'), + memoryLimitMiB: 512, + }, + schedule: events.Schedule.expression('rate(1 minute)'), + }); + + // THEN + expect(scheduledEc2Task.task).toBeDefined(); +}); diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.l3s-v2.ts b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.l3s-v2.ts deleted file mode 100644 index 5c3c5889c62b6..0000000000000 --- a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.l3s-v2.ts +++ /dev/null @@ -1,1555 +0,0 @@ -import { expect, haveResource, haveResourceLike, SynthUtils } from '@aws-cdk/assert-internal'; -import { Certificate } from '@aws-cdk/aws-certificatemanager'; -import { InstanceType, Vpc } from '@aws-cdk/aws-ec2'; -import { AwsLogDriver, Cluster, ContainerImage, Ec2TaskDefinition, PropagatedTagSource, Protocol } from '@aws-cdk/aws-ecs'; -import { ApplicationProtocol, SslPolicy } from '@aws-cdk/aws-elasticloadbalancingv2'; -import { CompositePrincipal, Role, ServicePrincipal } from '@aws-cdk/aws-iam'; -import { PublicHostedZone } from '@aws-cdk/aws-route53'; -import { NamespaceType } from '@aws-cdk/aws-servicediscovery'; -import { Duration, Stack } from '@aws-cdk/core'; -import { Test } from 'nodeunit'; -import { ApplicationMultipleTargetGroupsEc2Service, NetworkMultipleTargetGroupsEc2Service } from '../../lib'; - -export = { - 'When Application Load Balancer': { - 'test ECS ALB construct with default settings'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); - - // WHEN - new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { - cluster, - memoryLimitMiB: 1024, - taskImageOptions: { - image: ContainerImage.fromRegistry('test'), - }, - }); - - // THEN - stack contains a load balancer, a service, and a target group. - expect(stack).to(haveResource('AWS::ElasticLoadBalancingV2::LoadBalancer')); - - expect(stack).to(haveResource('AWS::ECS::Service', { - DesiredCount: 1, - LaunchType: 'EC2', - })); - - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Image: 'test', - LogConfiguration: { - LogDriver: 'awslogs', - Options: { - 'awslogs-group': { - Ref: 'ServiceTaskDefwebLogGroup2A898F61', - }, - 'awslogs-stream-prefix': 'Service', - 'awslogs-region': { - Ref: 'AWS::Region', - }, - }, - }, - Memory: 1024, - Name: 'web', - PortMappings: [ - { - ContainerPort: 80, - HostPort: 0, - Protocol: 'tcp', - }, - ], - }, - ], - NetworkMode: 'bridge', - RequiresCompatibilities: [ - 'EC2', - ], - })); - - test.done(); - }, - - 'test ECS ALB construct with all settings'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); - const zone = new PublicHostedZone(stack, 'HostedZone', { zoneName: 'example.com' }); - - // WHEN - new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { - cluster, - memoryLimitMiB: 1024, - taskImageOptions: { - image: ContainerImage.fromRegistry('test'), - containerName: 'myContainer', - containerPorts: [80, 90], - enableLogging: false, - environment: { - TEST_ENVIRONMENT_VARIABLE1: 'test environment variable 1 value', - TEST_ENVIRONMENT_VARIABLE2: 'test environment variable 2 value', - }, - logDriver: new AwsLogDriver({ - streamPrefix: 'TestStream', - }), - family: 'Ec2TaskDef', - executionRole: new Role(stack, 'ExecutionRole', { - path: '/', - assumedBy: new CompositePrincipal( - new ServicePrincipal('ecs.amazonaws.com'), - new ServicePrincipal('ecs-tasks.amazonaws.com'), - ), - }), - taskRole: new Role(stack, 'TaskRole', { - assumedBy: new ServicePrincipal('ecs-tasks.amazonaws.com'), - }), - dockerLabels: { label1: 'labelValue1', label2: 'labelValue2' }, - }, - cpu: 256, - desiredCount: 3, - enableECSManagedTags: true, - healthCheckGracePeriod: Duration.millis(2000), - loadBalancers: [ - { - name: 'lb', - domainName: 'api.example.com', - domainZone: zone, - publicLoadBalancer: false, - listeners: [ - { - name: 'listener', - protocol: ApplicationProtocol.HTTPS, - certificate: Certificate.fromCertificateArn(stack, 'Cert', 'helloworld'), - sslPolicy: SslPolicy.TLS12_EXT, - }, - ], - }, - ], - propagateTags: PropagatedTagSource.SERVICE, - memoryReservationMiB: 1024, - serviceName: 'myService', - targetGroups: [ - { - containerPort: 80, - listener: 'listener', - }, - { - containerPort: 90, - listener: 'listener', - pathPattern: 'a/b/c', - priority: 10, - protocol: Protocol.TCP, - }, - ], - }); - - // THEN - expect(stack).to(haveResource('AWS::ECS::Service', { - DesiredCount: 3, - LaunchType: 'EC2', - EnableECSManagedTags: true, - HealthCheckGracePeriodSeconds: 2, - LoadBalancers: [ - { - ContainerName: 'myContainer', - ContainerPort: 80, - TargetGroupArn: { - Ref: 'ServicelblistenerECSTargetGroupmyContainer80GroupAD83584A', - }, - }, - { - ContainerName: 'myContainer', - ContainerPort: 90, - TargetGroupArn: { - Ref: 'ServicelblistenerECSTargetGroupmyContainer90GroupF5A6D3A0', - }, - }, - ], - PropagateTags: 'SERVICE', - ServiceName: 'myService', - })); - - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Cpu: 256, - Environment: [ - { - Name: 'TEST_ENVIRONMENT_VARIABLE1', - Value: 'test environment variable 1 value', - }, - { - Name: 'TEST_ENVIRONMENT_VARIABLE2', - Value: 'test environment variable 2 value', - }, - ], - Essential: true, - Image: 'test', - LogConfiguration: { - LogDriver: 'awslogs', - Options: { - 'awslogs-group': { - Ref: 'ServiceTaskDefmyContainerLogGroup0A87368B', - }, - 'awslogs-stream-prefix': 'TestStream', - 'awslogs-region': { - Ref: 'AWS::Region', - }, - }, - }, - Memory: 1024, - MemoryReservation: 1024, - Name: 'myContainer', - PortMappings: [ - { - ContainerPort: 80, - HostPort: 0, - Protocol: 'tcp', - }, - { - ContainerPort: 90, - HostPort: 0, - Protocol: 'tcp', - }, - ], - DockerLabels: { - label1: 'labelValue1', - label2: 'labelValue2', - }, - }, - ], - ExecutionRoleArn: { - 'Fn::GetAtt': [ - 'ExecutionRole605A040B', - 'Arn', - ], - }, - Family: 'ServiceTaskDef79D79521', - NetworkMode: 'bridge', - RequiresCompatibilities: [ - 'EC2', - ], - TaskRoleArn: { - 'Fn::GetAtt': [ - 'TaskRole30FC0FBB', - 'Arn', - ], - }, - })); - - expect(stack).to(haveResourceLike('AWS::ElasticLoadBalancingV2::Listener', { - Port: 443, - Protocol: 'HTTPS', - Certificates: [{ - CertificateArn: 'helloworld', - }], - SslPolicy: SslPolicy.TLS12_EXT, - })); - - test.done(); - }, - - 'set vpc instead of cluster'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - - // WHEN - new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { - vpc, - memoryLimitMiB: 1024, - taskImageOptions: { - image: ContainerImage.fromRegistry('test'), - }, - }); - - // THEN - stack does not contain a LaunchConfiguration - expect(stack, true).notTo(haveResource('AWS::AutoScaling::LaunchConfiguration')); - - test.throws(() => expect(stack)); - - test.done(); - }, - - 'able to pass pre-defined task definition'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); - - const taskDefinition = new Ec2TaskDefinition(stack, 'Ec2TaskDef'); - const container = taskDefinition.addContainer('web', { - image: ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), - memoryLimitMiB: 512, - }); - container.addPortMappings({ - containerPort: 80, - }); - - // WHEN - new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { - cluster, - taskDefinition, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Essential: true, - Image: 'amazon/amazon-ecs-sample', - Memory: 512, - Name: 'web', - PortMappings: [ - { - ContainerPort: 80, - HostPort: 0, - Protocol: 'tcp', - }, - ], - }, - ], - Family: 'Ec2TaskDef', - NetworkMode: 'bridge', - RequiresCompatibilities: [ - 'EC2', - ], - })); - - test.done(); - }, - - 'able to output correct load balancer DNS and URLs for each protocol type'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); - const zone = new PublicHostedZone(stack, 'HostedZone', { zoneName: 'example.com' }); - - // WHEN - new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { - cluster, - memoryLimitMiB: 1024, - taskImageOptions: { - image: ContainerImage.fromRegistry('test'), - }, - loadBalancers: [ - { - name: 'lb1', - domainName: 'api.example.com', - domainZone: zone, - listeners: [ - { - name: 'listener1', - protocol: ApplicationProtocol.HTTPS, - certificate: Certificate.fromCertificateArn(stack, 'Cert', 'helloworld'), - }, - { - name: 'listener2', - protocol: ApplicationProtocol.HTTP, - }, - ], - }, - { - name: 'lb3', - listeners: [ - { - name: 'listener3', - protocol: ApplicationProtocol.HTTP, - }, - ], - }, - ], - targetGroups: [ - { - containerPort: 80, - listener: 'listener1', - }, - { - containerPort: 90, - listener: 'listener2', - }, - { - containerPort: 70, - listener: 'listener3', - }, - ], - }); - - // THEN - const template = SynthUtils.synthesize(stack).template.Outputs; - test.deepEqual(template, { - ServiceLoadBalancerDNSlb175E78BFE: { - Value: { - 'Fn::GetAtt': [ - 'Servicelb152C7F4F9', - 'DNSName', - ], - }, - }, - ServiceServiceURLlb1https5C0C4079: { - Value: { - 'Fn::Join': [ - '', - [ - 'https://', - { - Ref: 'ServiceDNSlb12BA1FAD3', - }, - ], - ], - }, - }, - ServiceServiceURLlb1http65F0546A: { - Value: { - 'Fn::Join': [ - '', - [ - 'http://', - { - Ref: 'ServiceDNSlb12BA1FAD3', - }, - ], - ], - }, - }, - ServiceLoadBalancerDNSlb32F273F27: { - Value: { - 'Fn::GetAtt': [ - 'Servicelb3A583D5E7', - 'DNSName', - ], - }, - }, - ServiceServiceURLlb3http40F9CADC: { - Value: { - 'Fn::Join': [ - '', - [ - 'http://', - { - 'Fn::GetAtt': [ - 'Servicelb3A583D5E7', - 'DNSName', - ], - }, - ], - ], - }, - }, - }); - - test.done(); - }, - - 'errors if no essential container in pre-defined task definition'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); - - const taskDefinition = new Ec2TaskDefinition(stack, 'Ec2TaskDef'); - - // THEN - test.throws(() => { - new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { - cluster, - taskDefinition, - }); - }, /At least one essential container must be specified/); - - test.done(); - }, - - 'set default load balancer, listener, target group correctly'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const zone = new PublicHostedZone(stack, 'HostedZone', { zoneName: 'example.com' }); - - // WHEN - const ecsService = new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { - vpc, - memoryLimitMiB: 1024, - taskImageOptions: { - image: ContainerImage.fromRegistry('test'), - }, - loadBalancers: [ - { - name: 'lb1', - listeners: [ - { - name: 'listener1', - }, - ], - }, - { - name: 'lb2', - domainName: 'api.example.com', - domainZone: zone, - listeners: [ - { - name: 'listener2', - }, - { - name: 'listener3', - protocol: ApplicationProtocol.HTTPS, - certificate: Certificate.fromCertificateArn(stack, 'Cert', 'helloworld'), - }, - ], - }, - ], - targetGroups: [ - { - containerPort: 80, - }, - { - containerPort: 90, - }, - ], - }); - - // THEN - test.equal(ecsService.loadBalancer.node.id, 'lb1'); - test.equal(ecsService.listener.node.id, 'listener1'); - test.equal(ecsService.targetGroup.node.id, 'ECSTargetGroupweb80Group'); - - test.done(); - }, - - 'setting vpc and cluster throws error'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); - - // WHEN - test.throws(() => new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { - cluster, - vpc, - taskImageOptions: { - image: ContainerImage.fromRegistry('/aws/aws-example-app'), - }, - }), /You can only specify either vpc or cluster. Alternatively, you can leave both blank/); - - test.done(); - }, - - 'creates AWS Cloud Map service for Private DNS namespace'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'MyVpc', {}); - const cluster = new Cluster(stack, 'EcsCluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); - - // WHEN - cluster.addDefaultCloudMapNamespace({ - name: 'foo.com', - type: NamespaceType.DNS_PRIVATE, - }); - - new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { - cluster, - taskImageOptions: { - image: ContainerImage.fromRegistry('hello'), - }, - cloudMapOptions: { - name: 'myApp', - }, - memoryLimitMiB: 512, - }); - - // THEN - expect(stack).to(haveResource('AWS::ECS::Service', { - ServiceRegistries: [ - { - ContainerName: 'web', - ContainerPort: 80, - RegistryArn: { - 'Fn::GetAtt': [ - 'ServiceCloudmapServiceDE76B29D', - 'Arn', - ], - }, - }, - ], - })); - - expect(stack).to(haveResource('AWS::ServiceDiscovery::Service', { - DnsConfig: { - DnsRecords: [ - { - TTL: 60, - Type: 'SRV', - }, - ], - NamespaceId: { - 'Fn::GetAtt': [ - 'EcsClusterDefaultServiceDiscoveryNamespaceB0971B2F', - 'Id', - ], - }, - RoutingPolicy: 'MULTIVALUE', - }, - HealthCheckCustomConfig: { - FailureThreshold: 1, - }, - Name: 'myApp', - NamespaceId: { - 'Fn::GetAtt': [ - 'EcsClusterDefaultServiceDiscoveryNamespaceB0971B2F', - 'Id', - ], - }, - })); - - test.done(); - }, - - 'errors when setting both taskDefinition and taskImageOptions'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); - - const taskDefinition = new Ec2TaskDefinition(stack, 'Ec2TaskDef'); - taskDefinition.addContainer('test', { - image: ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), - memoryLimitMiB: 512, - }); - - // THEN - test.throws(() => { - new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { - cluster, - taskImageOptions: { - image: ContainerImage.fromRegistry('test'), - }, - taskDefinition, - }); - }, /You must specify only one of TaskDefinition or TaskImageOptions./); - - test.done(); - }, - - 'errors when setting neither taskDefinition nor taskImageOptions'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); - - // THEN - test.throws(() => { - new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { - cluster, - }); - }, /You must specify one of: taskDefinition or image/); - - test.done(); - }, - - 'errors when setting domainName but not domainZone'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); - - // THEN - test.throws(() => { - new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { - cluster, - taskImageOptions: { - image: ContainerImage.fromRegistry('test'), - }, - loadBalancers: [ - { - name: 'lb1', - domainName: 'api.example.com', - listeners: [ - { - name: 'listener1', - }, - ], - }, - ], - }); - }, /A Route53 hosted domain zone name is required to configure the specified domain name/); - - test.done(); - }, - - 'errors when loadBalancers is empty'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); - - // THEN - test.throws(() => { - new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { - cluster, - taskImageOptions: { - image: ContainerImage.fromRegistry('test'), - }, - loadBalancers: [], - }); - }, /At least one load balancer must be specified/); - - test.done(); - }, - - 'errors when targetGroups is empty'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); - - // THEN - test.throws(() => { - new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { - cluster, - taskImageOptions: { - image: ContainerImage.fromRegistry('test'), - }, - targetGroups: [], - }); - }, /At least one target group should be specified/); - - test.done(); - }, - - 'errors when no listener specified'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); - - // THEN - test.throws(() => { - new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { - cluster, - taskImageOptions: { - image: ContainerImage.fromRegistry('test'), - }, - loadBalancers: [ - { - name: 'lb', - listeners: [], - }, - ], - }); - }, /At least one listener must be specified/); - - test.done(); - }, - - 'errors when setting both HTTP protocol and certificate'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); - - // THEN - test.throws(() => { - new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { - cluster, - taskImageOptions: { - image: ContainerImage.fromRegistry('test'), - }, - loadBalancers: [ - { - name: 'lb', - listeners: [ - { - name: 'listener', - protocol: ApplicationProtocol.HTTP, - certificate: Certificate.fromCertificateArn(stack, 'Cert', 'helloworld'), - }, - ], - }, - ], - }); - }, /The HTTPS protocol must be used when a certificate is given/); - - test.done(); - }, - - 'errors when setting HTTPS protocol but not domain name'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); - - // THEN - test.throws(() => { - new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { - cluster, - taskImageOptions: { - image: ContainerImage.fromRegistry('test'), - }, - loadBalancers: [ - { - name: 'lb', - listeners: [ - { - name: 'listener', - protocol: ApplicationProtocol.HTTPS, - }, - ], - }, - ], - }); - }, /A domain name and zone is required when using the HTTPS protocol/); - - test.done(); - }, - - 'errors when listener is not defined but used in creating target groups'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); - - // THEN - test.throws(() => { - new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { - cluster, - taskImageOptions: { - image: ContainerImage.fromRegistry('test'), - }, - loadBalancers: [ - { - name: 'lb', - listeners: [ - { - name: 'listener1', - }, - ], - }, - ], - targetGroups: [ - { - containerPort: 80, - listener: 'listener2', - }, - ], - }); - }, /Listener listener2 is not defined. Did you define listener with name listener2?/); - - test.done(); - }, - - 'errors if desiredTaskCount is 0'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); - - // THEN - test.throws(() => - new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { - cluster, - memoryLimitMiB: 1024, - taskImageOptions: { - image: ContainerImage.fromRegistry('test'), - }, - desiredCount: 0, - }) - , /You must specify a desiredCount greater than 0/); - - test.done(); - }, - }, - - 'When Network Load Balancer': { - 'test ECS NLB construct with default settings'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); - - // WHEN - new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { - cluster, - memoryLimitMiB: 256, - taskImageOptions: { - image: ContainerImage.fromRegistry('test'), - }, - }); - - // THEN - stack contains a load balancer and a service - expect(stack).to(haveResource('AWS::ElasticLoadBalancingV2::LoadBalancer')); - - expect(stack).to(haveResource('AWS::ECS::Service', { - DesiredCount: 1, - LaunchType: 'EC2', - })); - - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Essential: true, - Image: 'test', - LogConfiguration: { - LogDriver: 'awslogs', - Options: { - 'awslogs-group': { - Ref: 'ServiceTaskDefwebLogGroup2A898F61', - }, - 'awslogs-stream-prefix': 'Service', - 'awslogs-region': { - Ref: 'AWS::Region', - }, - }, - }, - Memory: 256, - Name: 'web', - PortMappings: [ - { - ContainerPort: 80, - HostPort: 0, - Protocol: 'tcp', - }, - ], - }, - ], - ExecutionRoleArn: { - 'Fn::GetAtt': [ - 'ServiceTaskDefExecutionRole919F7BE3', - 'Arn', - ], - }, - Family: 'ServiceTaskDef79D79521', - NetworkMode: 'bridge', - RequiresCompatibilities: [ - 'EC2', - ], - TaskRoleArn: { - 'Fn::GetAtt': [ - 'ServiceTaskDefTaskRole0CFE2F57', - 'Arn', - ], - }, - })); - - test.done(); - }, - - 'test ECS NLB construct with all settings'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); - const zone = new PublicHostedZone(stack, 'HostedZone', { zoneName: 'example.com' }); - - // WHEN - new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { - cluster, - memoryLimitMiB: 256, - taskImageOptions: { - image: ContainerImage.fromRegistry('test'), - containerName: 'myContainer', - containerPorts: [80, 90], - enableLogging: false, - environment: { - TEST_ENVIRONMENT_VARIABLE1: 'test environment variable 1 value', - TEST_ENVIRONMENT_VARIABLE2: 'test environment variable 2 value', - }, - logDriver: new AwsLogDriver({ - streamPrefix: 'TestStream', - }), - family: 'Ec2TaskDef', - executionRole: new Role(stack, 'ExecutionRole', { - path: '/', - assumedBy: new CompositePrincipal( - new ServicePrincipal('ecs.amazonaws.com'), - new ServicePrincipal('ecs-tasks.amazonaws.com'), - ), - }), - taskRole: new Role(stack, 'TaskRole', { - assumedBy: new ServicePrincipal('ecs-tasks.amazonaws.com'), - }), - dockerLabels: { label1: 'labelValue1', label2: 'labelValue2' }, - }, - cpu: 256, - desiredCount: 3, - enableECSManagedTags: true, - healthCheckGracePeriod: Duration.millis(2000), - loadBalancers: [ - { - name: 'lb1', - domainName: 'api.example.com', - domainZone: zone, - publicLoadBalancer: false, - listeners: [ - { - name: 'listener1', - }, - ], - }, - { - name: 'lb2', - listeners: [ - { - name: 'listener2', - port: 81, - }, - ], - }, - ], - propagateTags: PropagatedTagSource.SERVICE, - memoryReservationMiB: 256, - serviceName: 'myService', - targetGroups: [ - { - containerPort: 80, - listener: 'listener1', - }, - { - containerPort: 90, - listener: 'listener2', - }, - ], - }); - - // THEN - expect(stack).to(haveResource('AWS::ECS::Service', { - DesiredCount: 3, - EnableECSManagedTags: true, - HealthCheckGracePeriodSeconds: 2, - LaunchType: 'EC2', - LoadBalancers: [ - { - ContainerName: 'myContainer', - ContainerPort: 80, - TargetGroupArn: { - Ref: 'Servicelb1listener1ECSTargetGroupmyContainer80Group43098F8B', - }, - }, - { - ContainerName: 'myContainer', - ContainerPort: 90, - TargetGroupArn: { - Ref: 'Servicelb2listener2ECSTargetGroupmyContainer90GroupDEB417E4', - }, - }, - ], - PropagateTags: 'SERVICE', - SchedulingStrategy: 'REPLICA', - ServiceName: 'myService', - })); - - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Cpu: 256, - Environment: [ - { - Name: 'TEST_ENVIRONMENT_VARIABLE1', - Value: 'test environment variable 1 value', - }, - { - Name: 'TEST_ENVIRONMENT_VARIABLE2', - Value: 'test environment variable 2 value', - }, - ], - Essential: true, - Image: 'test', - LogConfiguration: { - LogDriver: 'awslogs', - Options: { - 'awslogs-group': { - Ref: 'ServiceTaskDefmyContainerLogGroup0A87368B', - }, - 'awslogs-stream-prefix': 'TestStream', - 'awslogs-region': { - Ref: 'AWS::Region', - }, - }, - }, - Memory: 256, - MemoryReservation: 256, - Name: 'myContainer', - PortMappings: [ - { - ContainerPort: 80, - HostPort: 0, - Protocol: 'tcp', - }, - { - ContainerPort: 90, - HostPort: 0, - Protocol: 'tcp', - }, - ], - DockerLabels: { - label1: 'labelValue1', - label2: 'labelValue2', - }, - }, - ], - ExecutionRoleArn: { - 'Fn::GetAtt': [ - 'ExecutionRole605A040B', - 'Arn', - ], - }, - Family: 'ServiceTaskDef79D79521', - NetworkMode: 'bridge', - RequiresCompatibilities: [ - 'EC2', - ], - TaskRoleArn: { - 'Fn::GetAtt': [ - 'TaskRole30FC0FBB', - 'Arn', - ], - }, - })); - - test.done(); - }, - - 'set vpc instead of cluster'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - - // WHEN - new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { - vpc, - memoryLimitMiB: 256, - taskImageOptions: { - image: ContainerImage.fromRegistry('test'), - }, - }); - - // THEN - stack does not contain a LaunchConfiguration - expect(stack, true).notTo(haveResource('AWS::AutoScaling::LaunchConfiguration')); - - test.throws(() => expect(stack)); - - test.done(); - }, - - 'able to pass pre-defined task definition'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); - - const taskDefinition = new Ec2TaskDefinition(stack, 'Ec2TaskDef'); - const container = taskDefinition.addContainer('web', { - image: ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), - memoryLimitMiB: 512, - }); - container.addPortMappings({ - containerPort: 80, - }); - - // WHEN - new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { - cluster, - taskDefinition, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Essential: true, - Image: 'amazon/amazon-ecs-sample', - Memory: 512, - Name: 'web', - PortMappings: [ - { - ContainerPort: 80, - HostPort: 0, - Protocol: 'tcp', - }, - ], - }, - ], - Family: 'Ec2TaskDef', - NetworkMode: 'bridge', - RequiresCompatibilities: [ - 'EC2', - ], - })); - - test.done(); - }, - - 'errors if no essential container in pre-defined task definition'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); - - const taskDefinition = new Ec2TaskDefinition(stack, 'Ec2TaskDef'); - - // THEN - test.throws(() => { - new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { - cluster, - taskDefinition, - }); - }, /At least one essential container must be specified/); - - test.done(); - }, - - 'set default load balancer, listener, target group correctly'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const zone = new PublicHostedZone(stack, 'HostedZone', { zoneName: 'example.com' }); - - // WHEN - const ecsService = new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { - vpc, - memoryLimitMiB: 1024, - taskImageOptions: { - image: ContainerImage.fromRegistry('test'), - }, - loadBalancers: [ - { - name: 'lb1', - listeners: [ - { - name: 'listener1', - }, - ], - }, - { - name: 'lb2', - domainName: 'api.example.com', - domainZone: zone, - listeners: [ - { - name: 'listener2', - }, - { - name: 'listener3', - }, - ], - }, - ], - targetGroups: [ - { - containerPort: 80, - }, - { - containerPort: 90, - }, - ], - }); - - // THEN - test.equal(ecsService.loadBalancer.node.id, 'lb1'); - test.equal(ecsService.listener.node.id, 'listener1'); - test.equal(ecsService.targetGroup.node.id, 'ECSTargetGroupweb80Group'); - - test.done(); - }, - - 'setting vpc and cluster throws error'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); - - // WHEN - test.throws(() => new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { - cluster, - vpc, - taskImageOptions: { - image: ContainerImage.fromRegistry('/aws/aws-example-app'), - }, - }), /You can only specify either vpc or cluster. Alternatively, you can leave both blank/); - - test.done(); - }, - - 'creates AWS Cloud Map service for Private DNS namespace'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'MyVpc', {}); - const cluster = new Cluster(stack, 'EcsCluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); - - // WHEN - cluster.addDefaultCloudMapNamespace({ - name: 'foo.com', - type: NamespaceType.DNS_PRIVATE, - }); - - new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { - cluster, - taskImageOptions: { - image: ContainerImage.fromRegistry('hello'), - }, - cloudMapOptions: { - name: 'myApp', - }, - memoryLimitMiB: 512, - }); - - // THEN - expect(stack).to(haveResource('AWS::ECS::Service', { - ServiceRegistries: [ - { - ContainerName: 'web', - ContainerPort: 80, - RegistryArn: { - 'Fn::GetAtt': [ - 'ServiceCloudmapServiceDE76B29D', - 'Arn', - ], - }, - }, - ], - })); - - expect(stack).to(haveResource('AWS::ServiceDiscovery::Service', { - DnsConfig: { - DnsRecords: [ - { - TTL: 60, - Type: 'SRV', - }, - ], - NamespaceId: { - 'Fn::GetAtt': [ - 'EcsClusterDefaultServiceDiscoveryNamespaceB0971B2F', - 'Id', - ], - }, - RoutingPolicy: 'MULTIVALUE', - }, - HealthCheckCustomConfig: { - FailureThreshold: 1, - }, - Name: 'myApp', - NamespaceId: { - 'Fn::GetAtt': [ - 'EcsClusterDefaultServiceDiscoveryNamespaceB0971B2F', - 'Id', - ], - }, - })); - - test.done(); - }, - - 'errors when setting both taskDefinition and taskImageOptions'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); - - const taskDefinition = new Ec2TaskDefinition(stack, 'Ec2TaskDef'); - taskDefinition.addContainer('test', { - image: ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), - memoryLimitMiB: 512, - }); - - // THEN - test.throws(() => { - new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { - cluster, - taskImageOptions: { - image: ContainerImage.fromRegistry('test'), - }, - taskDefinition, - }); - }, /You must specify only one of TaskDefinition or TaskImageOptions./); - - test.done(); - }, - - 'errors when setting neither taskDefinition nor taskImageOptions'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); - - // THEN - test.throws(() => { - new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { - cluster, - }); - }, /You must specify one of: taskDefinition or image/); - - test.done(); - }, - - 'errors when setting domainName but not domainZone'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); - - // THEN - test.throws(() => { - new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { - cluster, - taskImageOptions: { - image: ContainerImage.fromRegistry('test'), - }, - loadBalancers: [ - { - name: 'lb1', - domainName: 'api.example.com', - listeners: [{ - name: 'listener1', - }], - }, - ], - }); - }, /A Route53 hosted domain zone name is required to configure the specified domain name/); - - test.done(); - }, - - 'errors when loadBalancers is empty'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); - - // THEN - test.throws(() => { - new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { - cluster, - taskImageOptions: { - image: ContainerImage.fromRegistry('test'), - }, - loadBalancers: [], - }); - }, /At least one load balancer must be specified/); - - test.done(); - }, - - 'errors when targetGroups is empty'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); - - // THEN - test.throws(() => { - new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { - cluster, - taskImageOptions: { - image: ContainerImage.fromRegistry('test'), - }, - targetGroups: [], - }); - }, /At least one target group should be specified/); - - test.done(); - }, - - 'errors when no listener specified'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); - - // THEN - test.throws(() => { - new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { - cluster, - taskImageOptions: { - image: ContainerImage.fromRegistry('test'), - }, - loadBalancers: [ - { - name: 'lb', - listeners: [], - }, - ], - }); - }, /At least one listener must be specified/); - - test.done(); - }, - - 'errors when listener is not defined but used in creating target groups'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); - - // THEN - test.throws(() => { - new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { - cluster, - taskImageOptions: { - image: ContainerImage.fromRegistry('test'), - }, - loadBalancers: [ - { - name: 'lb', - listeners: [ - { - name: 'listener1', - }, - ], - }, - ], - targetGroups: [ - { - containerPort: 80, - listener: 'listener2', - }, - ], - }); - }, /Listener listener2 is not defined. Did you define listener with name listener2?/); - - test.done(); - }, - - 'errors if desiredTaskCount is 0'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); - - // THEN - test.throws(() => - new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { - cluster, - memoryLimitMiB: 1024, - taskImageOptions: { - image: ContainerImage.fromRegistry('test'), - }, - desiredCount: 0, - }) - , /You must specify a desiredCount greater than 0/); - - test.done(); - }, - }, -}; diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.l3s.ts b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.l3s.ts deleted file mode 100644 index 8e2f527fbe509..0000000000000 --- a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.l3s.ts +++ /dev/null @@ -1,1416 +0,0 @@ -import { ABSENT, arrayWith, expect, haveResource, haveResourceLike, objectLike } from '@aws-cdk/assert-internal'; -import { Certificate } from '@aws-cdk/aws-certificatemanager'; -import * as ec2 from '@aws-cdk/aws-ec2'; -import * as ecs from '@aws-cdk/aws-ecs'; -import { ApplicationLoadBalancer, ApplicationProtocol, ApplicationProtocolVersion, NetworkLoadBalancer, SslPolicy } from '@aws-cdk/aws-elasticloadbalancingv2'; -import { PublicHostedZone } from '@aws-cdk/aws-route53'; -import * as cloudmap from '@aws-cdk/aws-servicediscovery'; -import * as cdk from '@aws-cdk/core'; -import * as cxapi from '@aws-cdk/cx-api'; -import { Test } from 'nodeunit'; -import * as ecsPatterns from '../../lib'; - -export = { - 'test ECS loadbalanced construct'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedEc2Service(stack, 'Service', { - cluster, - memoryLimitMiB: 1024, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('test'), - environment: { - TEST_ENVIRONMENT_VARIABLE1: 'test environment variable 1 value', - TEST_ENVIRONMENT_VARIABLE2: 'test environment variable 2 value', - }, - dockerLabels: { label1: 'labelValue1', label2: 'labelValue2' }, - }, - desiredCount: 2, - }); - - // THEN - stack contains a load balancer and a service - expect(stack).to(haveResource('AWS::ElasticLoadBalancingV2::LoadBalancer')); - - expect(stack).to(haveResource('AWS::ECS::Service', { - DesiredCount: 2, - LaunchType: 'EC2', - })); - - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Environment: [ - { - Name: 'TEST_ENVIRONMENT_VARIABLE1', - Value: 'test environment variable 1 value', - }, - { - Name: 'TEST_ENVIRONMENT_VARIABLE2', - Value: 'test environment variable 2 value', - }, - ], - Memory: 1024, - DockerLabels: { - label1: 'labelValue1', - label2: 'labelValue2', - }, - }, - ], - })); - - test.done(); - }, - - 'ApplicationLoadBalancedEc2Service desiredCount can be undefined when feature flag is set'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - stack.node.setContext(cxapi.ECS_REMOVE_DEFAULT_DESIRED_COUNT, true); - - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedEc2Service(stack, 'Service', { - cluster, - memoryLimitMiB: 1024, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('test'), - }, - }); - - expect(stack).to(haveResource('AWS::ECS::Service', { - DesiredCount: ABSENT, - })); - - test.done(); - }, - - 'ApplicationLoadBalancedFargateService desiredCount can be undefined when feature flag is set'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - stack.node.setContext(cxapi.ECS_REMOVE_DEFAULT_DESIRED_COUNT, true); - - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('test'), - }, - }); - - expect(stack).to(haveResource('AWS::ECS::Service', { - DesiredCount: ABSENT, - })); - - test.done(); - }, - - 'NetworkLoadBalancedEc2Service desiredCount can be undefined when feature flag is set'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - stack.node.setContext(cxapi.ECS_REMOVE_DEFAULT_DESIRED_COUNT, true); - - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); - - // WHEN - new ecsPatterns.NetworkLoadBalancedEc2Service(stack, 'Service', { - cluster, - memoryLimitMiB: 1024, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('test'), - }, - }); - - expect(stack).to(haveResource('AWS::ECS::Service', { - DesiredCount: ABSENT, - })); - - test.done(); - }, - - 'NetworkLoadBalancedFargateService desiredCount can be undefined when feature flag is set'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - stack.node.setContext(cxapi.ECS_REMOVE_DEFAULT_DESIRED_COUNT, true); - - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('test'), - }, - }); - - expect(stack).to(haveResource('AWS::ECS::Service', { - DesiredCount: ABSENT, - })); - - test.done(); - }, - - 'set vpc instead of cluster'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedEc2Service(stack, 'Service', { - vpc, - memoryLimitMiB: 1024, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('test'), - environment: { - TEST_ENVIRONMENT_VARIABLE1: 'test environment variable 1 value', - TEST_ENVIRONMENT_VARIABLE2: 'test environment variable 2 value', - }, - }, - desiredCount: 2, - }); - - // THEN - stack does not contain a LaunchConfiguration - expect(stack, true).notTo(haveResource('AWS::AutoScaling::LaunchConfiguration')); - - test.throws(() => expect(stack)); - - test.done(); - }, - - 'setting vpc and cluster throws error'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - test.throws(() => new ecsPatterns.NetworkLoadBalancedEc2Service(stack, 'Service', { - cluster, - vpc, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), - }, - })); - - test.done(); - }, - - 'test ECS loadbalanced construct with memoryReservationMiB'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedEc2Service(stack, 'Service', { - cluster, - memoryReservationMiB: 1024, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('test'), - }, - }); - - // THEN - stack contains a load balancer and a service - expect(stack).to(haveResource('AWS::ElasticLoadBalancingV2::LoadBalancer')); - - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - MemoryReservation: 1024, - }, - ], - })); - - test.done(); - }, - - 'creates AWS Cloud Map service for Private DNS namespace with application load balanced ec2 service'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'MyVpc', {}); - const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); - - // WHEN - cluster.addDefaultCloudMapNamespace({ - name: 'foo.com', - type: cloudmap.NamespaceType.DNS_PRIVATE, - }); - - new ecsPatterns.ApplicationLoadBalancedEc2Service(stack, 'Service', { - cluster, - taskImageOptions: { - containerPort: 8000, - image: ecs.ContainerImage.fromRegistry('hello'), - }, - cloudMapOptions: { - name: 'myApp', - }, - memoryLimitMiB: 512, - }); - - // THEN - expect(stack).to(haveResource('AWS::ECS::Service', { - ServiceRegistries: [ - { - ContainerName: 'web', - ContainerPort: 8000, - RegistryArn: { - 'Fn::GetAtt': [ - 'ServiceCloudmapServiceDE76B29D', - 'Arn', - ], - }, - }, - ], - })); - - expect(stack).to(haveResource('AWS::ServiceDiscovery::Service', { - DnsConfig: { - DnsRecords: [ - { - TTL: 60, - Type: 'SRV', - }, - ], - NamespaceId: { - 'Fn::GetAtt': [ - 'EcsClusterDefaultServiceDiscoveryNamespaceB0971B2F', - 'Id', - ], - }, - RoutingPolicy: 'MULTIVALUE', - }, - HealthCheckCustomConfig: { - FailureThreshold: 1, - }, - Name: 'myApp', - NamespaceId: { - 'Fn::GetAtt': [ - 'EcsClusterDefaultServiceDiscoveryNamespaceB0971B2F', - 'Id', - ], - }, - })); - - test.done(); - }, - - 'creates AWS Cloud Map service for Private DNS namespace with network load balanced fargate service'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'MyVpc', {}); - const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); - - // WHEN - cluster.addDefaultCloudMapNamespace({ - name: 'foo.com', - type: cloudmap.NamespaceType.DNS_PRIVATE, - }); - - new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - containerPort: 8000, - image: ecs.ContainerImage.fromRegistry('hello'), - }, - cloudMapOptions: { - name: 'myApp', - }, - memoryLimitMiB: 512, - }); - - // THEN - expect(stack).to(haveResource('AWS::ECS::Service', { - ServiceRegistries: [ - { - RegistryArn: { - 'Fn::GetAtt': [ - 'ServiceCloudmapServiceDE76B29D', - 'Arn', - ], - }, - }, - ], - })); - - expect(stack).to(haveResource('AWS::ServiceDiscovery::Service', { - DnsConfig: { - DnsRecords: [ - { - TTL: 60, - Type: 'A', - }, - ], - NamespaceId: { - 'Fn::GetAtt': [ - 'EcsClusterDefaultServiceDiscoveryNamespaceB0971B2F', - 'Id', - ], - }, - RoutingPolicy: 'MULTIVALUE', - }, - HealthCheckCustomConfig: { - FailureThreshold: 1, - }, - Name: 'myApp', - NamespaceId: { - 'Fn::GetAtt': [ - 'EcsClusterDefaultServiceDiscoveryNamespaceB0971B2F', - 'Id', - ], - }, - })); - - test.done(); - }, - - 'test Fargate loadbalanced construct'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('test'), - environment: { - TEST_ENVIRONMENT_VARIABLE1: 'test environment variable 1 value', - TEST_ENVIRONMENT_VARIABLE2: 'test environment variable 2 value', - }, - dockerLabels: { label1: 'labelValue1', label2: 'labelValue2' }, - }, - desiredCount: 2, - }); - - // THEN - stack contains a load balancer and a service - expect(stack).to(haveResource('AWS::ElasticLoadBalancingV2::LoadBalancer')); - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Environment: [ - { - Name: 'TEST_ENVIRONMENT_VARIABLE1', - Value: 'test environment variable 1 value', - }, - { - Name: 'TEST_ENVIRONMENT_VARIABLE2', - Value: 'test environment variable 2 value', - }, - ], - LogConfiguration: { - LogDriver: 'awslogs', - Options: { - 'awslogs-group': { Ref: 'ServiceTaskDefwebLogGroup2A898F61' }, - 'awslogs-stream-prefix': 'Service', - 'awslogs-region': { Ref: 'AWS::Region' }, - }, - }, - DockerLabels: { - label1: 'labelValue1', - label2: 'labelValue2', - }, - }, - ], - })); - - expect(stack).to(haveResource('AWS::ECS::Service', { - DesiredCount: 2, - LaunchType: 'FARGATE', - })); - - expect(stack).to(haveResource('AWS::ElasticLoadBalancingV2::Listener', { - Port: 80, - Protocol: 'HTTP', - })); - - test.done(); - }, - - 'test Fargate loadbalanced construct opting out of log driver creation'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('test'), - enableLogging: false, - environment: { - TEST_ENVIRONMENT_VARIABLE1: 'test environment variable 1 value', - TEST_ENVIRONMENT_VARIABLE2: 'test environment variable 2 value', - }, - }, - desiredCount: 2, - }); - - // THEN - stack contains a load balancer and a service - expect(stack).notTo(haveResource('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Environment: [ - { - Name: 'TEST_ENVIRONMENT_VARIABLE1', - Value: 'test environment variable 1 value', - }, - { - Name: 'TEST_ENVIRONMENT_VARIABLE2', - Value: 'test environment variable 2 value', - }, - ], - LogConfiguration: { - LogDriver: 'awslogs', - Options: { - 'awslogs-group': { Ref: 'ServiceTaskDefwebLogGroup2A898F61' }, - 'awslogs-stream-prefix': 'Service', - 'awslogs-region': { Ref: 'AWS::Region' }, - }, - }, - }, - ], - })); - - test.done(); - }, - - 'test Fargate loadbalanced construct with TLS'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - const zone = new PublicHostedZone(stack, 'HostedZone', { zoneName: 'example.com' }); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('test'), - }, - domainName: 'api.example.com', - domainZone: zone, - certificate: Certificate.fromCertificateArn(stack, 'Cert', 'helloworld'), - sslPolicy: SslPolicy.TLS12_EXT, - }); - - // THEN - stack contains a load balancer and a service - expect(stack).to(haveResource('AWS::ElasticLoadBalancingV2::LoadBalancer')); - - expect(stack).to(haveResource('AWS::ElasticLoadBalancingV2::Listener', { - Port: 443, - Protocol: 'HTTPS', - Certificates: [{ - CertificateArn: 'helloworld', - }], - SslPolicy: SslPolicy.TLS12_EXT, - })); - - expect(stack).to(haveResource('AWS::ElasticLoadBalancingV2::TargetGroup', { - Port: 80, - Protocol: 'HTTP', - TargetType: 'ip', - VpcId: { - Ref: 'VPCB9E5F0B4', - }, - })); - - expect(stack).to(haveResource('AWS::ECS::Service', { - DesiredCount: 1, - LaunchType: 'FARGATE', - })); - - expect(stack).to(haveResource('AWS::Route53::RecordSet', { - Name: 'api.example.com.', - HostedZoneId: { - Ref: 'HostedZoneDB99F866', - }, - Type: 'A', - AliasTarget: { - HostedZoneId: { 'Fn::GetAtt': ['ServiceLBE9A1ADBC', 'CanonicalHostedZoneID'] }, - DNSName: { 'Fn::Join': ['', ['dualstack.', { 'Fn::GetAtt': ['ServiceLBE9A1ADBC', 'DNSName'] }]] }, - }, - })); - - test.done(); - }, - - 'test Fargateloadbalanced construct with TLS and default certificate'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - const zone = new PublicHostedZone(stack, 'HostedZone', { zoneName: 'example.com' }); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('test'), - }, - domainName: 'api.example.com', - domainZone: zone, - protocol: ApplicationProtocol.HTTPS, - }); - - // THEN - stack contains a load balancer, a service, and a certificate - expect(stack).to(haveResource('AWS::CertificateManager::Certificate', { - DomainName: 'api.example.com', - DomainValidationOptions: [ - { - DomainName: 'api.example.com', - HostedZoneId: { - Ref: 'HostedZoneDB99F866', - }, - }, - ], - ValidationMethod: 'DNS', - })); - - expect(stack).to(haveResource('AWS::ElasticLoadBalancingV2::LoadBalancer')); - - expect(stack).to(haveResource('AWS::ElasticLoadBalancingV2::Listener', { - Port: 443, - Protocol: 'HTTPS', - Certificates: [{ - CertificateArn: { - Ref: 'ServiceCertificateA7C65FE6', - }, - }], - })); - - expect(stack).to(haveResource('AWS::ECS::Service', { - DesiredCount: 1, - LaunchType: 'FARGATE', - })); - - expect(stack).to(haveResource('AWS::Route53::RecordSet', { - Name: 'api.example.com.', - HostedZoneId: { - Ref: 'HostedZoneDB99F866', - }, - Type: 'A', - AliasTarget: { - HostedZoneId: { 'Fn::GetAtt': ['ServiceLBE9A1ADBC', 'CanonicalHostedZoneID'] }, - DNSName: { 'Fn::Join': ['', ['dualstack.', { 'Fn::GetAtt': ['ServiceLBE9A1ADBC', 'DNSName'] }]] }, - }, - })); - - test.done(); - }, - - 'errors when setting domainName but not domainZone'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // THEN - test.throws(() => { - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('test'), - }, - domainName: 'api.example.com', - }); - }); - - test.done(); - }, - - 'errors when setting both HTTP protocol and certificate'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // THEN - test.throws(() => { - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('test'), - }, - protocol: ApplicationProtocol.HTTP, - certificate: Certificate.fromCertificateArn(stack, 'Cert', 'helloworld'), - }); - }); - - test.done(); - }, - - 'errors when setting both HTTP protocol and redirectHTTP'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // THEN - test.throws(() => { - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('test'), - }, - protocol: ApplicationProtocol.HTTP, - redirectHTTP: true, - }); - }); - - test.done(); - }, - - 'does not throw errors when not setting HTTPS protocol but certificate for redirectHTTP'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - const zone = new PublicHostedZone(stack, 'HostedZone', { zoneName: 'example.com' }); - - // THEN - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('test'), - }, - domainName: 'api.example.com', - domainZone: zone, - redirectHTTP: true, - certificate: Certificate.fromCertificateArn(stack, 'Cert', 'helloworld'), - }); - - test.done(); - }, - - 'errors when setting HTTPS protocol but not domain name'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // THEN - test.throws(() => { - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('test'), - }, - protocol: ApplicationProtocol.HTTPS, - }); - }); - - test.done(); - }, - - 'test Fargate loadbalanced construct with optional log driver input'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('test'), - enableLogging: false, - environment: { - TEST_ENVIRONMENT_VARIABLE1: 'test environment variable 1 value', - TEST_ENVIRONMENT_VARIABLE2: 'test environment variable 2 value', - }, - logDriver: new ecs.AwsLogDriver({ - streamPrefix: 'TestStream', - }), - }, - desiredCount: 2, - }); - - // THEN - stack contains a load balancer and a service - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Environment: [ - { - Name: 'TEST_ENVIRONMENT_VARIABLE1', - Value: 'test environment variable 1 value', - }, - { - Name: 'TEST_ENVIRONMENT_VARIABLE2', - Value: 'test environment variable 2 value', - }, - ], - LogConfiguration: { - LogDriver: 'awslogs', - Options: { - 'awslogs-group': { Ref: 'ServiceTaskDefwebLogGroup2A898F61' }, - 'awslogs-stream-prefix': 'TestStream', - 'awslogs-region': { Ref: 'AWS::Region' }, - }, - }, - }, - ], - })); - - test.done(); - }, - - 'test Fargate loadbalanced construct with logging enabled'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('test'), - enableLogging: true, - environment: { - TEST_ENVIRONMENT_VARIABLE1: 'test environment variable 1 value', - TEST_ENVIRONMENT_VARIABLE2: 'test environment variable 2 value', - }, - }, - desiredCount: 2, - }); - - // THEN - stack contains a load balancer and a service - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Environment: [ - { - Name: 'TEST_ENVIRONMENT_VARIABLE1', - Value: 'test environment variable 1 value', - }, - { - Name: 'TEST_ENVIRONMENT_VARIABLE2', - Value: 'test environment variable 2 value', - }, - ], - LogConfiguration: { - LogDriver: 'awslogs', - Options: { - 'awslogs-group': { Ref: 'ServiceTaskDefwebLogGroup2A898F61' }, - 'awslogs-stream-prefix': 'Service', - 'awslogs-region': { Ref: 'AWS::Region' }, - }, - }, - }, - ], - })); - - test.done(); - }, - - 'test Fargate loadbalanced construct with both image and taskDefinition provided'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'Ec2TaskDef'); - taskDefinition.addContainer('web', { - image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), - memoryLimitMiB: 512, - }); - - // WHEN - test.throws(() => new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('test'), - enableLogging: true, - environment: { - TEST_ENVIRONMENT_VARIABLE1: 'test environment variable 1 value', - TEST_ENVIRONMENT_VARIABLE2: 'test environment variable 2 value', - }, - }, - desiredCount: 2, - taskDefinition, - })); - - test.done(); - }, - - 'test Fargate application loadbalanced construct with taskDefinition provided'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - const taskDefinition = new ecs.FargateTaskDefinition(stack, 'FargateTaskDef'); - const container = taskDefinition.addContainer('passedTaskDef', { - image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), - memoryLimitMiB: 512, - }); - container.addPortMappings({ - containerPort: 80, - }); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { - cluster, - taskDefinition, - desiredCount: 2, - memoryLimitMiB: 1024, - }); - - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Image: 'amazon/amazon-ecs-sample', - Memory: 512, - Name: 'passedTaskDef', - PortMappings: [ - { - ContainerPort: 80, - Protocol: 'tcp', - }, - ], - }, - ], - })); - - test.done(); - }, - - 'ALB - throws if desiredTaskCount is 0'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); - - // THEN - test.throws(() => - new ecsPatterns.ApplicationLoadBalancedEc2Service(stack, 'Service', { - cluster, - memoryLimitMiB: 1024, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('test'), - }, - desiredCount: 0, - }) - , /You must specify a desiredCount greater than 0/); - - test.done(); - }, - - 'NLB - throws if desiredTaskCount is 0'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); - - // THEN - test.throws(() => - new ecsPatterns.NetworkLoadBalancedEc2Service(stack, 'Service', { - cluster, - memoryLimitMiB: 1024, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('test'), - }, - desiredCount: 0, - }) - , /You must specify a desiredCount greater than 0/); - - test.done(); - }, - 'ALBFargate - having *HealthyPercent properties'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'ALB123Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), - }, - minHealthyPercent: 100, - maxHealthyPercent: 200, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::ECS::Service', { - DeploymentConfiguration: { - MinimumHealthyPercent: 100, - MaximumPercent: 200, - }, - })); - - test.done(); - }, - - 'NLBFargate - having *HealthyPercent properties'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'Service', { - cluster, - memoryLimitMiB: 1024, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), - }, - desiredCount: 1, - minHealthyPercent: 100, - maxHealthyPercent: 200, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::ECS::Service', { - DeploymentConfiguration: { - MinimumHealthyPercent: 100, - MaximumPercent: 200, - }, - })); - - test.done(); - }, - - 'ALB - having *HealthyPercent properties'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedEc2Service(stack, 'Service', { - cluster, - memoryLimitMiB: 1024, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), - }, - desiredCount: 1, - minHealthyPercent: 100, - maxHealthyPercent: 200, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::ECS::Service', { - DeploymentConfiguration: { - MinimumHealthyPercent: 100, - MaximumPercent: 200, - }, - })); - - test.done(); - }, - - 'ALB - includes provided protocol version properties'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); - const zone = new PublicHostedZone(stack, 'HostedZone', { zoneName: 'example.com' }); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedEc2Service(stack, 'Service', { - cluster, - memoryLimitMiB: 1024, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), - }, - desiredCount: 1, - domainName: 'api.example.com', - domainZone: zone, - protocol: ApplicationProtocol.HTTPS, - protocolVersion: ApplicationProtocolVersion.GRPC, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::ElasticLoadBalancingV2::TargetGroup', { - ProtocolVersion: 'GRPC', - })); - - test.done(); - }, - - 'NLB - having *HealthyPercent properties'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); - - // WHEN - new ecsPatterns.NetworkLoadBalancedEc2Service(stack, 'Service', { - cluster, - memoryLimitMiB: 1024, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), - }, - desiredCount: 1, - minHealthyPercent: 100, - maxHealthyPercent: 200, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::ECS::Service', { - DeploymentConfiguration: { - MinimumHealthyPercent: 100, - MaximumPercent: 200, - }, - })); - - test.done(); - }, - - 'ALB - having deployment controller'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedEc2Service(stack, 'Service', { - cluster, - memoryLimitMiB: 1024, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), - }, - deploymentController: { - type: ecs.DeploymentControllerType.CODE_DEPLOY, - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::ECS::Service', { - DeploymentController: { - Type: 'CODE_DEPLOY', - }, - })); - - test.done(); - }, - - 'NLB - having deployment controller'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); - - // WHEN - new ecsPatterns.NetworkLoadBalancedEc2Service(stack, 'Service', { - cluster, - memoryLimitMiB: 1024, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), - }, - deploymentController: { - type: ecs.DeploymentControllerType.CODE_DEPLOY, - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::ECS::Service', { - DeploymentController: { - Type: 'CODE_DEPLOY', - }, - })); - - test.done(); - }, - - 'ALB with circuit breaker'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedEc2Service(stack, 'Service', { - cluster, - memoryLimitMiB: 1024, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), - }, - circuitBreaker: { rollback: true }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::ECS::Service', { - DeploymentConfiguration: { - DeploymentCircuitBreaker: { - Enable: true, - Rollback: true, - }, - }, - DeploymentController: { - Type: 'ECS', - }, - })); - - test.done(); - }, - - 'NLB with circuit breaker'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); - - // WHEN - new ecsPatterns.NetworkLoadBalancedEc2Service(stack, 'Service', { - cluster, - memoryLimitMiB: 1024, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), - }, - circuitBreaker: { rollback: true }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::ECS::Service', { - DeploymentConfiguration: { - DeploymentCircuitBreaker: { - Enable: true, - Rollback: true, - }, - }, - DeploymentController: { - Type: 'ECS', - }, - })); - - test.done(); - }, - - 'NetworkLoadbalancedEC2Service accepts previously created load balancer'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'Vpc'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc, clusterName: 'MyCluster' }); - cluster.addCapacity('Capacity', { instanceType: new ec2.InstanceType('t2.micro') }); - const nlb = new NetworkLoadBalancer(stack, 'NLB', { vpc }); - const taskDef = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); - const container = taskDef.addContainer('Container', { - image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), - memoryLimitMiB: 1024, - }); - container.addPortMappings({ containerPort: 80 }); - - // WHEN - new ecsPatterns.NetworkLoadBalancedEc2Service(stack, 'Service', { - cluster, - loadBalancer: nlb, - taskDefinition: taskDef, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::ECS::Service', { - LaunchType: 'EC2', - })); - expect(stack).to(haveResourceLike('AWS::ElasticLoadBalancingV2::LoadBalancer', { - Type: 'network', - })); - test.done(); - }, - - 'NetworkLoadBalancedEC2Service accepts imported load balancer'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const nlbArn = 'arn:aws:elasticloadbalancing:us-west-2:123456789012:loadbalancer/app/my-load-balancer/50dc6c495c0c9188'; - const vpc = new ec2.Vpc(stack, 'Vpc'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc, clusterName: 'MyCluster' }); - cluster.addCapacity('Capacity', { instanceType: new ec2.InstanceType('t2.micro') }); - const nlb = NetworkLoadBalancer.fromNetworkLoadBalancerAttributes(stack, 'NLB', { - loadBalancerArn: nlbArn, - vpc, - }); - const taskDef = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); - const container = taskDef.addContainer('Container', { - image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), - memoryLimitMiB: 1024, - }); - container.addPortMappings({ - containerPort: 80, - }); - - // WHEN - new ecsPatterns.NetworkLoadBalancedEc2Service(stack, 'Service', { - cluster, - loadBalancer: nlb, - desiredCount: 1, - taskDefinition: taskDef, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::ECS::Service', { - LaunchType: 'EC2', - LoadBalancers: [{ ContainerName: 'Container', ContainerPort: 80 }], - })); - expect(stack).to(haveResourceLike('AWS::ElasticLoadBalancingV2::TargetGroup')); - expect(stack).to(haveResourceLike('AWS::ElasticLoadBalancingV2::Listener', { - LoadBalancerArn: nlb.loadBalancerArn, - Port: 80, - })); - test.done(); - }, - - 'ApplicationLoadBalancedEC2Service accepts previously created load balancer'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'Vpc'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc, clusterName: 'MyCluster' }); - cluster.addCapacity('Capacity', { instanceType: new ec2.InstanceType('t2.micro') }); - const sg = new ec2.SecurityGroup(stack, 'SG', { vpc }); - const alb = new ApplicationLoadBalancer(stack, 'NLB', { - vpc, - securityGroup: sg, - }); - const taskDef = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); - const container = taskDef.addContainer('Container', { - image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), - memoryLimitMiB: 1024, - }); - container.addPortMappings({ containerPort: 80 }); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedEc2Service(stack, 'Service', { - cluster, - loadBalancer: alb, - taskDefinition: taskDef, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::ECS::Service', { - LaunchType: 'EC2', - })); - expect(stack).to(haveResourceLike('AWS::ElasticLoadBalancingV2::LoadBalancer', { - Type: 'application', - })); - test.done(); - }, - - 'ApplicationLoadBalancedEC2Service accepts imported load balancer'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const albArn = 'arn:aws:elasticloadbalancing:us-west-2:123456789012:loadbalancer/app/my-load-balancer/50dc6c495c0c9188'; - const vpc = new ec2.Vpc(stack, 'Vpc'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc, clusterName: 'MyCluster' }); - cluster.addCapacity('Capacity', { instanceType: new ec2.InstanceType('t2.micro') }); - const sg = new ec2.SecurityGroup(stack, 'SG', { vpc }); - const alb = ApplicationLoadBalancer.fromApplicationLoadBalancerAttributes(stack, 'ALB', { - loadBalancerArn: albArn, - vpc, - securityGroupId: sg.securityGroupId, - loadBalancerDnsName: 'MyName', - }); - const taskDef = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); - const container = taskDef.addContainer('Container', { - image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), - memoryLimitMiB: 1024, - }); - container.addPortMappings({ - containerPort: 80, - }); - // WHEN - new ecsPatterns.ApplicationLoadBalancedEc2Service(stack, 'Service', { - cluster, - loadBalancer: alb, - taskDefinition: taskDef, - }); - // THEN - expect(stack).to(haveResourceLike('AWS::ECS::Service', { - LaunchType: 'EC2', - LoadBalancers: [{ ContainerName: 'Container', ContainerPort: 80 }], - })); - expect(stack).to(haveResourceLike('AWS::ElasticLoadBalancingV2::TargetGroup')); - expect(stack).to(haveResourceLike('AWS::ElasticLoadBalancingV2::Listener', { - LoadBalancerArn: alb.loadBalancerArn, - Port: 80, - })); - - test.done(); - }, - - 'test ECS loadbalanced construct default/open security group'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedEc2Service(stack, 'Service', { - cluster, - memoryReservationMiB: 1024, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('test'), - }, - }); - - // THEN - Stack contains no ingress security group rules - expect(stack).to(haveResourceLike('AWS::EC2::SecurityGroup', { - SecurityGroupIngress: [{ - CidrIp: '0.0.0.0/0', - FromPort: 80, - IpProtocol: 'tcp', - ToPort: 80, - }], - })); - - test.done(); - }, - - 'test ECS loadbalanced construct closed security group'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); - const zone = new PublicHostedZone(stack, 'HostedZone', { zoneName: 'example.com' }); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedEc2Service(stack, 'Service', { - cluster, - memoryReservationMiB: 1024, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('test'), - }, - domainName: 'api.example.com', - domainZone: zone, - certificate: Certificate.fromCertificateArn(stack, 'Cert', 'helloworld'), - openListener: false, - redirectHTTP: true, - }); - - // THEN - Stack contains no ingress security group rules - expect(stack).notTo(haveResourceLike('AWS::EC2::SecurityGroup', { - SecurityGroupIngress: arrayWith(objectLike({})), - })); - - test.done(); - }, -}; diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.queue-processing-ecs-service.ts b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.queue-processing-ecs-service.ts deleted file mode 100644 index 97bdb47c7b5b3..0000000000000 --- a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.queue-processing-ecs-service.ts +++ /dev/null @@ -1,399 +0,0 @@ -import { ABSENT, expect, haveResource, haveResourceLike } from '@aws-cdk/assert-internal'; -import * as autoscaling from '@aws-cdk/aws-autoscaling'; -import * as ec2 from '@aws-cdk/aws-ec2'; -import * as ecs from '@aws-cdk/aws-ecs'; -import * as sqs from '@aws-cdk/aws-sqs'; -import * as cdk from '@aws-cdk/core'; -import * as cxapi from '@aws-cdk/cx-api'; -import { Test } from 'nodeunit'; -import * as ecsPatterns from '../../lib'; - -export = { - 'test ECS queue worker service construct - with only required props'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); - - // WHEN - new ecsPatterns.QueueProcessingEc2Service(stack, 'Service', { - cluster, - memoryLimitMiB: 512, - image: ecs.ContainerImage.fromRegistry('test'), - }); - - // THEN - QueueWorker is of EC2 launch type, an SQS queue is created and all default properties are set. - expect(stack).to(haveResource('AWS::ECS::Service', { - DesiredCount: 1, - LaunchType: 'EC2', - })); - - expect(stack).to(haveResource('AWS::SQS::Queue', { - RedrivePolicy: { - deadLetterTargetArn: { - 'Fn::GetAtt': [ - 'ServiceEcsProcessingDeadLetterQueue4A89196E', - 'Arn', - ], - }, - maxReceiveCount: 3, - }, - })); - - expect(stack).to(haveResource('AWS::SQS::Queue', { - MessageRetentionPeriod: 1209600, - })); - - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Environment: [ - { - Name: 'QUEUE_NAME', - Value: { - 'Fn::GetAtt': [ - 'ServiceEcsProcessingQueueC266885C', - 'QueueName', - ], - }, - }, - ], - LogConfiguration: { - LogDriver: 'awslogs', - Options: { - 'awslogs-group': { - Ref: 'ServiceQueueProcessingTaskDefQueueProcessingContainerLogGroupD52338D1', - }, - 'awslogs-stream-prefix': 'Service', - 'awslogs-region': { - Ref: 'AWS::Region', - }, - }, - }, - Essential: true, - Image: 'test', - Memory: 512, - }, - ], - Family: 'ServiceQueueProcessingTaskDef83DB34F1', - })); - - test.done(); - }, - - 'test ECS queue worker service construct - with remove default desiredCount feature flag'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - stack.node.setContext(cxapi.ECS_REMOVE_DEFAULT_DESIRED_COUNT, true); - - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); - - // WHEN - new ecsPatterns.QueueProcessingEc2Service(stack, 'Service', { - cluster, - memoryLimitMiB: 512, - image: ecs.ContainerImage.fromRegistry('test'), - }); - - // THEN - QueueWorker is of EC2 launch type, and desiredCount is not defined on the Ec2Service. - expect(stack).to(haveResource('AWS::ECS::Service', { - DesiredCount: ABSENT, - LaunchType: 'EC2', - })); - - test.done(); - }, - - 'test ECS queue worker service construct - with optional props for queues'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); - - // WHEN - new ecsPatterns.QueueProcessingEc2Service(stack, 'Service', { - cluster, - memoryLimitMiB: 512, - image: ecs.ContainerImage.fromRegistry('test'), - maxReceiveCount: 42, - retentionPeriod: cdk.Duration.days(7), - visibilityTimeout: cdk.Duration.minutes(5), - }); - - // THEN - QueueWorker is of EC2 launch type, an SQS queue is created and all default properties are set. - expect(stack).to(haveResource('AWS::ECS::Service', { - DesiredCount: 1, - LaunchType: 'EC2', - })); - - expect(stack).to(haveResource('AWS::SQS::Queue', { - RedrivePolicy: { - deadLetterTargetArn: { - 'Fn::GetAtt': [ - 'ServiceEcsProcessingDeadLetterQueue4A89196E', - 'Arn', - ], - }, - maxReceiveCount: 42, - }, - VisibilityTimeout: 300, - })); - - expect(stack).to(haveResource('AWS::SQS::Queue', { - MessageRetentionPeriod: 604800, - })); - - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Environment: [ - { - Name: 'QUEUE_NAME', - Value: { - 'Fn::GetAtt': [ - 'ServiceEcsProcessingQueueC266885C', - 'QueueName', - ], - }, - }, - ], - LogConfiguration: { - LogDriver: 'awslogs', - Options: { - 'awslogs-group': { - Ref: 'ServiceQueueProcessingTaskDefQueueProcessingContainerLogGroupD52338D1', - }, - 'awslogs-stream-prefix': 'Service', - 'awslogs-region': { - Ref: 'AWS::Region', - }, - }, - }, - Essential: true, - Image: 'test', - Memory: 512, - }, - ], - Family: 'ServiceQueueProcessingTaskDef83DB34F1', - })); - - test.done(); - }, - - 'test ECS queue worker service construct - with optional props'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); - const queue = new sqs.Queue(stack, 'ecs-test-queue', { - queueName: 'ecs-test-sqs-queue', - }); - - // WHEN - new ecsPatterns.QueueProcessingEc2Service(stack, 'Service', { - cluster, - memoryLimitMiB: 1024, - image: ecs.ContainerImage.fromRegistry('test'), - command: ['-c', '4', 'amazon.com'], - enableLogging: false, - desiredTaskCount: 2, - environment: { - TEST_ENVIRONMENT_VARIABLE1: 'test environment variable 1 value', - TEST_ENVIRONMENT_VARIABLE2: 'test environment variable 2 value', - }, - queue, - maxScalingCapacity: 5, - minHealthyPercent: 60, - maxHealthyPercent: 150, - serviceName: 'ecs-test-service', - family: 'ecs-task-family', - circuitBreaker: { rollback: true }, - gpuCount: 256, - }); - - // THEN - QueueWorker is of EC2 launch type, an SQS queue is created and all optional properties are set. - expect(stack).to(haveResource('AWS::ECS::Service', { - DesiredCount: 2, - DeploymentConfiguration: { - MinimumHealthyPercent: 60, - MaximumPercent: 150, - DeploymentCircuitBreaker: { - Enable: true, - Rollback: true, - }, - }, - LaunchType: 'EC2', - ServiceName: 'ecs-test-service', - DeploymentController: { - Type: 'ECS', - }, - })); - - expect(stack).to(haveResource('AWS::SQS::Queue', { - QueueName: 'ecs-test-sqs-queue', - })); - - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Command: [ - '-c', - '4', - 'amazon.com', - ], - Environment: [ - { - Name: 'TEST_ENVIRONMENT_VARIABLE1', - Value: 'test environment variable 1 value', - }, - { - Name: 'TEST_ENVIRONMENT_VARIABLE2', - Value: 'test environment variable 2 value', - }, - { - Name: 'QUEUE_NAME', - Value: { - 'Fn::GetAtt': [ - 'ecstestqueueD1FDA34B', - 'QueueName', - ], - }, - }, - ], - Image: 'test', - Memory: 1024, - ResourceRequirements: [ - { - Type: 'GPU', - Value: '256', - }, - ], - }, - ], - Family: 'ecs-task-family', - })); - - test.done(); - }, - - 'can set desiredTaskCount to 0'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); - - // WHEN - new ecsPatterns.QueueProcessingEc2Service(stack, 'Service', { - cluster, - desiredTaskCount: 0, - maxScalingCapacity: 2, - memoryLimitMiB: 512, - image: ecs.ContainerImage.fromRegistry('test'), - }); - - // THEN - QueueWorker is of EC2 launch type, an SQS queue is created and all default properties are set. - expect(stack).to(haveResource('AWS::ECS::Service', { - DesiredCount: 0, - LaunchType: 'EC2', - })); - - test.done(); - }, - - 'throws if desiredTaskCount and maxScalingCapacity are 0'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); - - // THEN - test.throws(() => - new ecsPatterns.QueueProcessingEc2Service(stack, 'Service', { - cluster, - desiredTaskCount: 0, - memoryLimitMiB: 512, - image: ecs.ContainerImage.fromRegistry('test'), - }) - , /maxScalingCapacity must be set and greater than 0 if desiredCount is 0/); - - test.done(); - }, - - 'can set custom containerName'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); - - // WHEN - new ecsPatterns.QueueProcessingEc2Service(stack, 'Service', { - cluster, - memoryLimitMiB: 512, - image: ecs.ContainerImage.fromRegistry('test'), - containerName: 'my-container', - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Name: 'my-container', - }, - ], - })); - - test.done(); - }, - - 'can set capacity provider strategies'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - const autoScalingGroup = new autoscaling.AutoScalingGroup(stack, 'asg', { - vpc, - instanceType: new ec2.InstanceType('bogus'), - machineImage: ecs.EcsOptimizedImage.amazonLinux2(), - }); - const capacityProvider = new ecs.AsgCapacityProvider(stack, 'provider', { - autoScalingGroup, - }); - cluster.addAsgCapacityProvider(capacityProvider); - - // WHEN - new ecsPatterns.QueueProcessingEc2Service(stack, 'Service', { - cluster, - image: ecs.ContainerImage.fromRegistry('test'), - memoryLimitMiB: 512, - capacityProviderStrategies: [ - { - capacityProvider: capacityProvider.capacityProviderName, - }, - ], - }); - - // THEN - expect(stack).to( - haveResource('AWS::ECS::Service', { - LaunchType: ABSENT, - CapacityProviderStrategy: [ - { - CapacityProvider: { - Ref: 'providerD3FF4D3A', - }, - }, - ], - }), - ); - - test.done(); - }, -}; diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.scheduled-ecs-task.ts b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.scheduled-ecs-task.ts deleted file mode 100644 index 712c83ab83b93..0000000000000 --- a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.scheduled-ecs-task.ts +++ /dev/null @@ -1,341 +0,0 @@ -import { expect, haveResource } from '@aws-cdk/assert-internal'; -import * as ec2 from '@aws-cdk/aws-ec2'; -import * as ecs from '@aws-cdk/aws-ecs'; -import * as events from '@aws-cdk/aws-events'; -import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; -import { ScheduledEc2Task } from '../../lib'; - -export = { - 'Can create a scheduled Ec2 Task - with only required props'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 1 }); - const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { - instanceType: new ec2.InstanceType('t2.micro'), - }); - - new ScheduledEc2Task(stack, 'ScheduledEc2Task', { - cluster, - scheduledEc2TaskImageOptions: { - image: ecs.ContainerImage.fromRegistry('henk'), - memoryLimitMiB: 512, - }, - schedule: events.Schedule.expression('rate(1 minute)'), - }); - - // THEN - expect(stack).to(haveResource('AWS::Events::Rule', { - State: 'ENABLED', - Targets: [ - { - Arn: { 'Fn::GetAtt': ['EcsCluster97242B84', 'Arn'] }, - EcsParameters: { - TaskCount: 1, - TaskDefinitionArn: { Ref: 'ScheduledEc2TaskScheduledTaskDef56328BA4' }, - }, - Id: 'Target0', - Input: '{}', - RoleArn: { 'Fn::GetAtt': ['ScheduledEc2TaskScheduledTaskDefEventsRole64113C5F', 'Arn'] }, - }, - ], - })); - - expect(stack).to(haveResource('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Essential: true, - Image: 'henk', - LogConfiguration: { - LogDriver: 'awslogs', - Options: { - 'awslogs-group': { - Ref: 'ScheduledEc2TaskScheduledTaskDefScheduledContainerLogGroupA85E11E6', - }, - 'awslogs-stream-prefix': 'ScheduledEc2Task', - 'awslogs-region': { - Ref: 'AWS::Region', - }, - }, - }, - Memory: 512, - Name: 'ScheduledContainer', - }, - ], - })); - - test.done(); - }, - - 'Can create a scheduled Ec2 Task - with optional props'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 1 }); - const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); - - cluster.addCapacity('DefaultAutoScalingGroup', { - instanceType: new ec2.InstanceType('t2.micro'), - }); - - new ScheduledEc2Task(stack, 'ScheduledEc2Task', { - cluster, - enabled: false, - scheduledEc2TaskImageOptions: { - image: ecs.ContainerImage.fromRegistry('henk'), - memoryLimitMiB: 512, - cpu: 2, - environment: { TRIGGER: 'CloudWatch Events' }, - }, - desiredTaskCount: 2, - schedule: events.Schedule.expression('rate(1 minute)'), - ruleName: 'sample-scheduled-task-rule', - }); - - // THEN - expect(stack).to(haveResource('AWS::Events::Rule', { - Name: 'sample-scheduled-task-rule', - State: 'DISABLED', - Targets: [ - { - Arn: { 'Fn::GetAtt': ['EcsCluster97242B84', 'Arn'] }, - EcsParameters: { - TaskCount: 2, - TaskDefinitionArn: { Ref: 'ScheduledEc2TaskScheduledTaskDef56328BA4' }, - }, - Id: 'Target0', - Input: '{}', - RoleArn: { 'Fn::GetAtt': ['ScheduledEc2TaskScheduledTaskDefEventsRole64113C5F', 'Arn'] }, - }, - ], - })); - - expect(stack).to(haveResource('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Cpu: 2, - Environment: [ - { - Name: 'TRIGGER', - Value: 'CloudWatch Events', - }, - ], - Essential: true, - Image: 'henk', - LogConfiguration: { - LogDriver: 'awslogs', - Options: { - 'awslogs-group': { - Ref: 'ScheduledEc2TaskScheduledTaskDefScheduledContainerLogGroupA85E11E6', - }, - 'awslogs-stream-prefix': 'ScheduledEc2Task', - 'awslogs-region': { - Ref: 'AWS::Region', - }, - }, - }, - Memory: 512, - Name: 'ScheduledContainer', - }, - ], - })); - - test.done(); - }, - 'Scheduled ECS Task - with securityGroups defined'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 1 }); - const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); - const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'Ec2TaskDef', { - networkMode: ecs.NetworkMode.AWS_VPC, - }); - const sg = new ec2.SecurityGroup(stack, 'MySG', { vpc }); - - new ScheduledEc2Task(stack, 'ScheduledEc2Task', { - cluster, - scheduledEc2TaskDefinitionOptions: { - taskDefinition, - }, - schedule: events.Schedule.expression('rate(1 minute)'), - securityGroups: [sg], - }); - - // THEN - expect(stack).to(haveResource('AWS::Events::Rule', { - Targets: [ - { - Arn: { 'Fn::GetAtt': ['EcsCluster97242B84', 'Arn'] }, - EcsParameters: { - LaunchType: 'EC2', - NetworkConfiguration: { - AwsVpcConfiguration: { - AssignPublicIp: 'DISABLED', - SecurityGroups: [{ - 'Fn::GetAtt': [ - 'MySG94FE69A8', - 'GroupId', - ], - }], - Subnets: [ - { - Ref: 'VpcPrivateSubnet1Subnet536B997A', - }, - ], - }, - }, - TaskCount: 1, - TaskDefinitionArn: { Ref: 'Ec2TaskDef0226F28C' }, - }, - Id: 'Target0', - Input: '{}', - RoleArn: { 'Fn::GetAtt': ['Ec2TaskDefEventsRoleA0756175', 'Arn'] }, - }, - ], - })); - - test.done(); - }, - - 'Scheduled Ec2 Task - with MemoryReservation defined'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 1 }); - const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { - instanceType: new ec2.InstanceType('t2.micro'), - }); - - new ScheduledEc2Task(stack, 'ScheduledEc2Task', { - cluster, - scheduledEc2TaskImageOptions: { - image: ecs.ContainerImage.fromRegistry('henk'), - memoryReservationMiB: 512, - }, - schedule: events.Schedule.expression('rate(1 minute)'), - }); - - // THEN - expect(stack).to(haveResource('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Essential: true, - Image: 'henk', - LogConfiguration: { - LogDriver: 'awslogs', - Options: { - 'awslogs-group': { - Ref: 'ScheduledEc2TaskScheduledTaskDefScheduledContainerLogGroupA85E11E6', - }, - 'awslogs-stream-prefix': 'ScheduledEc2Task', - 'awslogs-region': { - Ref: 'AWS::Region', - }, - }, - }, - MemoryReservation: 512, - Name: 'ScheduledContainer', - }, - ], - })); - - test.done(); - }, - - 'Scheduled Ec2 Task - with Command defined'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 1 }); - const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { - instanceType: new ec2.InstanceType('t2.micro'), - }); - - new ScheduledEc2Task(stack, 'ScheduledEc2Task', { - cluster, - scheduledEc2TaskImageOptions: { - image: ecs.ContainerImage.fromRegistry('henk'), - memoryReservationMiB: 512, - command: ['-c', '4', 'amazon.com'], - }, - schedule: events.Schedule.expression('rate(1 minute)'), - }); - - // THEN - expect(stack).to(haveResource('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Command: [ - '-c', - '4', - 'amazon.com', - ], - Essential: true, - Image: 'henk', - LogConfiguration: { - LogDriver: 'awslogs', - Options: { - 'awslogs-group': { - Ref: 'ScheduledEc2TaskScheduledTaskDefScheduledContainerLogGroupA85E11E6', - }, - 'awslogs-stream-prefix': 'ScheduledEc2Task', - 'awslogs-region': { - Ref: 'AWS::Region', - }, - }, - }, - MemoryReservation: 512, - Name: 'ScheduledContainer', - }, - ], - })); - - test.done(); - }, - - 'throws if desiredTaskCount is 0'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 1 }); - const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { - instanceType: new ec2.InstanceType('t2.micro'), - }); - - // THEN - test.throws(() => - new ScheduledEc2Task(stack, 'ScheduledEc2Task', { - cluster, - scheduledEc2TaskImageOptions: { - image: ecs.ContainerImage.fromRegistry('henk'), - memoryLimitMiB: 512, - }, - schedule: events.Schedule.expression('rate(1 minute)'), - desiredTaskCount: 0, - }), - /You must specify a desiredTaskCount greater than 0/); - - test.done(); - }, - - 'Scheduled Ec2 Task - exposes ECS Task'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 1 }); - const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); - - const scheduledEc2Task = new ScheduledEc2Task(stack, 'ScheduledEc2Task', { - cluster, - scheduledEc2TaskImageOptions: { - image: ecs.ContainerImage.fromRegistry('henk'), - memoryLimitMiB: 512, - }, - schedule: events.Schedule.expression('rate(1 minute)'), - }); - - // THEN - test.notEqual(scheduledEc2Task.task, undefined); - - test.done(); - }, -}; diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service.expected.json b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service.expected.json index f43e4e5aa4e0b..48bab449fe610 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service.expected.json +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service.expected.json @@ -642,7 +642,7 @@ "Type": "AWS::ApplicationAutoScaling::ScalableTarget", "Properties": { "MaxCapacity": 2, - "MinCapacity": 1, + "MinCapacity": 0, "ResourceId": { "Fn::Join": [ "", diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service.ts b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service.ts index 540b8d2302e9a..a0c679f4afaa8 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service.ts @@ -15,6 +15,7 @@ new QueueProcessingFargateService(stack, 'QueueProcessingService', { vpc, memoryLimitMiB: 512, image: new ecs.AssetImage(path.join(__dirname, '..', 'sqs-reader')), + minScalingCapacity: 0, }); app.synth(); diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/load-balanced-fargate-service-v2.test.ts b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/load-balanced-fargate-service-v2.test.ts new file mode 100644 index 0000000000000..902d5412ee8bf --- /dev/null +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/load-balanced-fargate-service-v2.test.ts @@ -0,0 +1,664 @@ +import '@aws-cdk/assert-internal/jest'; +import { Vpc } from '@aws-cdk/aws-ec2'; +import * as ecs from '@aws-cdk/aws-ecs'; +import { CompositePrincipal, Role, ServicePrincipal } from '@aws-cdk/aws-iam'; +import { Duration, Stack } from '@aws-cdk/core'; +import { ApplicationMultipleTargetGroupsFargateService, NetworkMultipleTargetGroupsFargateService, ApplicationLoadBalancedFargateService } from '../../lib'; + +describe('When Application Load Balancer', () => { + test('test Fargate loadbalanced construct with default settings', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + new ApplicationMultipleTargetGroupsFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('test'), + }, + }); + + // THEN - stack contains a load balancer and a service + expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::LoadBalancer'); + + expect(stack).toHaveResource('AWS::ECS::Service', { + DesiredCount: 1, + LaunchType: 'FARGATE', + LoadBalancers: [ + { + ContainerName: 'web', + ContainerPort: 80, + TargetGroupArn: { + Ref: 'ServiceLBPublicListenerECSGroup0CC8688C', + }, + }, + ], + }); + + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Image: 'test', + LogConfiguration: { + LogDriver: 'awslogs', + Options: { + 'awslogs-group': { + Ref: 'ServiceTaskDefwebLogGroup2A898F61', + }, + 'awslogs-stream-prefix': 'Service', + 'awslogs-region': { + Ref: 'AWS::Region', + }, + }, + }, + Name: 'web', + PortMappings: [ + { + ContainerPort: 80, + Protocol: 'tcp', + }, + ], + }, + ], + Cpu: '256', + ExecutionRoleArn: { + 'Fn::GetAtt': [ + 'ServiceTaskDefExecutionRole919F7BE3', + 'Arn', + ], + }, + Family: 'ServiceTaskDef79D79521', + Memory: '512', + NetworkMode: 'awsvpc', + RequiresCompatibilities: [ + 'FARGATE', + ], + }); + }); + + test('test Fargate loadbalanced construct with all settings', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + new ApplicationMultipleTargetGroupsFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('test'), + containerName: 'hello', + containerPorts: [80, 90], + enableLogging: false, + environment: { + TEST_ENVIRONMENT_VARIABLE1: 'test environment variable 1 value', + TEST_ENVIRONMENT_VARIABLE2: 'test environment variable 2 value', + }, + logDriver: new ecs.AwsLogDriver({ + streamPrefix: 'TestStream', + }), + family: 'Ec2TaskDef', + executionRole: new Role(stack, 'ExecutionRole', { + path: '/', + assumedBy: new CompositePrincipal( + new ServicePrincipal('ecs.amazonaws.com'), + new ServicePrincipal('ecs-tasks.amazonaws.com'), + ), + }), + taskRole: new Role(stack, 'TaskRole', { + assumedBy: new ServicePrincipal('ecs-tasks.amazonaws.com'), + }), + dockerLabels: { label1: 'labelValue1', label2: 'labelValue2' }, + }, + cpu: 256, + assignPublicIp: true, + memoryLimitMiB: 512, + desiredCount: 3, + enableECSManagedTags: true, + healthCheckGracePeriod: Duration.millis(2000), + platformVersion: ecs.FargatePlatformVersion.VERSION1_4, + propagateTags: ecs.PropagatedTagSource.SERVICE, + serviceName: 'myService', + targetGroups: [ + { + containerPort: 80, + }, + { + containerPort: 90, + pathPattern: 'a/b/c', + priority: 10, + protocol: ecs.Protocol.TCP, + }, + ], + }); + + // THEN - stack contains a load balancer and a service + expect(stack).toHaveResource('AWS::ECS::Service', { + DesiredCount: 3, + EnableECSManagedTags: true, + HealthCheckGracePeriodSeconds: 2, + LaunchType: 'FARGATE', + LoadBalancers: [ + { + ContainerName: 'hello', + ContainerPort: 80, + TargetGroupArn: { + Ref: 'ServiceLBPublicListenerECSTargetGrouphello80Group233A4D54', + }, + }, + { + ContainerName: 'hello', + ContainerPort: 90, + TargetGroupArn: { + Ref: 'ServiceLBPublicListenerECSTargetGrouphello90GroupE58E4EAB', + }, + }, + ], + NetworkConfiguration: { + AwsvpcConfiguration: { + AssignPublicIp: 'ENABLED', + SecurityGroups: [ + { + 'Fn::GetAtt': [ + 'ServiceSecurityGroupEEA09B68', + 'GroupId', + ], + }, + ], + Subnets: [ + { + Ref: 'VPCPublicSubnet1SubnetB4246D30', + }, + { + Ref: 'VPCPublicSubnet2Subnet74179F39', + }, + ], + }, + }, + PlatformVersion: ecs.FargatePlatformVersion.VERSION1_4, + PropagateTags: 'SERVICE', + ServiceName: 'myService', + }); + + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Environment: [ + { + Name: 'TEST_ENVIRONMENT_VARIABLE1', + Value: 'test environment variable 1 value', + }, + { + Name: 'TEST_ENVIRONMENT_VARIABLE2', + Value: 'test environment variable 2 value', + }, + ], + Essential: true, + Image: 'test', + LogConfiguration: { + LogDriver: 'awslogs', + Options: { + 'awslogs-group': { + Ref: 'ServiceTaskDefhelloLogGroup44519781', + }, + 'awslogs-stream-prefix': 'TestStream', + 'awslogs-region': { + Ref: 'AWS::Region', + }, + }, + }, + Name: 'hello', + PortMappings: [ + { + ContainerPort: 80, + Protocol: 'tcp', + }, + { + ContainerPort: 90, + Protocol: 'tcp', + }, + ], + DockerLabels: { + label1: 'labelValue1', + label2: 'labelValue2', + }, + }, + ], + Cpu: '256', + ExecutionRoleArn: { + 'Fn::GetAtt': [ + 'ExecutionRole605A040B', + 'Arn', + ], + }, + Family: 'Ec2TaskDef', + Memory: '512', + NetworkMode: 'awsvpc', + RequiresCompatibilities: [ + 'FARGATE', + ], + TaskRoleArn: { + 'Fn::GetAtt': [ + 'TaskRole30FC0FBB', + 'Arn', + ], + }, + }); + }); + + test('errors if no essential container in pre-defined task definition', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + const taskDefinition = new ecs.FargateTaskDefinition(stack, 'FargateTaskDef'); + + // THEN + expect(() => { + new ApplicationMultipleTargetGroupsFargateService(stack, 'Service', { + cluster, + taskDefinition, + }); + }).toThrow(/At least one essential container must be specified/); + }); + + test('errors when setting both taskDefinition and taskImageOptions', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + const taskDefinition = new ecs.FargateTaskDefinition(stack, 'Ec2TaskDef'); + + // THEN + expect(() => { + new ApplicationMultipleTargetGroupsFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('test'), + }, + taskDefinition, + }); + }).toThrow(/You must specify only one of TaskDefinition or TaskImageOptions./); + }); + + test('errors when setting neither taskDefinition nor taskImageOptions', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // THEN + expect(() => { + new ApplicationMultipleTargetGroupsFargateService(stack, 'Service', { + cluster, + }); + }).toThrow(/You must specify one of: taskDefinition or image/); + }); + + test('test Fargate loadbalancer construct with application load balancer name set', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + new ApplicationLoadBalancedFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('test'), + }, + loadBalancerName: 'alb-test-load-balancer', + }); + + // THEN - stack contains a load balancer and a service + expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::LoadBalancer', { + Name: 'alb-test-load-balancer', + }); + + expect(stack).toHaveResource('AWS::ECS::Service', { + DesiredCount: 1, + LaunchType: 'FARGATE', + LoadBalancers: [ + { + ContainerName: 'web', + ContainerPort: 80, + TargetGroupArn: { + Ref: 'ServiceLBPublicListenerECSGroup0CC8688C', + }, + }, + ], + }); + + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Image: 'test', + LogConfiguration: { + LogDriver: 'awslogs', + Options: { + 'awslogs-group': { + Ref: 'ServiceTaskDefwebLogGroup2A898F61', + }, + 'awslogs-stream-prefix': 'Service', + 'awslogs-region': { + Ref: 'AWS::Region', + }, + }, + }, + Name: 'web', + PortMappings: [ + { + ContainerPort: 80, + Protocol: 'tcp', + }, + ], + }, + ], + Cpu: '256', + ExecutionRoleArn: { + 'Fn::GetAtt': [ + 'ServiceTaskDefExecutionRole919F7BE3', + 'Arn', + ], + }, + Family: 'ServiceTaskDef79D79521', + Memory: '512', + NetworkMode: 'awsvpc', + RequiresCompatibilities: [ + 'FARGATE', + ], + }); + }); +}); + +describe('When Network Load Balancer', () => { + test('test Fargate loadbalanced construct with default settings', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + new NetworkMultipleTargetGroupsFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('test'), + }, + }); + + // THEN - stack contains a load balancer and a service + expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::LoadBalancer'); + + expect(stack).toHaveResource('AWS::ECS::Service', { + DesiredCount: 1, + LaunchType: 'FARGATE', + LoadBalancers: [ + { + ContainerName: 'web', + ContainerPort: 80, + TargetGroupArn: { + Ref: 'ServiceLBPublicListenerECSGroup0CC8688C', + }, + }, + ], + }); + + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Image: 'test', + LogConfiguration: { + LogDriver: 'awslogs', + Options: { + 'awslogs-group': { + Ref: 'ServiceTaskDefwebLogGroup2A898F61', + }, + 'awslogs-stream-prefix': 'Service', + 'awslogs-region': { + Ref: 'AWS::Region', + }, + }, + }, + Name: 'web', + PortMappings: [ + { + ContainerPort: 80, + Protocol: 'tcp', + }, + ], + }, + ], + Cpu: '256', + ExecutionRoleArn: { + 'Fn::GetAtt': [ + 'ServiceTaskDefExecutionRole919F7BE3', + 'Arn', + ], + }, + Family: 'ServiceTaskDef79D79521', + Memory: '512', + NetworkMode: 'awsvpc', + RequiresCompatibilities: [ + 'FARGATE', + ], + }); + }); + + test('test Fargate loadbalanced construct with all settings', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + new NetworkMultipleTargetGroupsFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('test'), + containerName: 'hello', + containerPorts: [80, 90], + enableLogging: false, + environment: { + TEST_ENVIRONMENT_VARIABLE1: 'test environment variable 1 value', + TEST_ENVIRONMENT_VARIABLE2: 'test environment variable 2 value', + }, + logDriver: new ecs.AwsLogDriver({ + streamPrefix: 'TestStream', + }), + family: 'Ec2TaskDef', + executionRole: new Role(stack, 'ExecutionRole', { + path: '/', + assumedBy: new CompositePrincipal( + new ServicePrincipal('ecs.amazonaws.com'), + new ServicePrincipal('ecs-tasks.amazonaws.com'), + ), + }), + taskRole: new Role(stack, 'TaskRole', { + assumedBy: new ServicePrincipal('ecs-tasks.amazonaws.com'), + }), + dockerLabels: { label1: 'labelValue1', label2: 'labelValue2' }, + }, + cpu: 256, + assignPublicIp: true, + memoryLimitMiB: 512, + desiredCount: 3, + enableECSManagedTags: true, + healthCheckGracePeriod: Duration.millis(2000), + propagateTags: ecs.PropagatedTagSource.SERVICE, + serviceName: 'myService', + targetGroups: [ + { + containerPort: 80, + }, + { + containerPort: 90, + }, + ], + }); + + // THEN - stack contains a load balancer and a service + expect(stack).toHaveResource('AWS::ECS::Service', { + DesiredCount: 3, + EnableECSManagedTags: true, + HealthCheckGracePeriodSeconds: 2, + LaunchType: 'FARGATE', + LoadBalancers: [ + { + ContainerName: 'hello', + ContainerPort: 80, + TargetGroupArn: { + Ref: 'ServiceLBPublicListenerECSTargetGrouphello80Group233A4D54', + }, + }, + { + ContainerName: 'hello', + ContainerPort: 90, + TargetGroupArn: { + Ref: 'ServiceLBPublicListenerECSTargetGrouphello90GroupE58E4EAB', + }, + }, + ], + NetworkConfiguration: { + AwsvpcConfiguration: { + AssignPublicIp: 'ENABLED', + SecurityGroups: [ + { + 'Fn::GetAtt': [ + 'ServiceSecurityGroupEEA09B68', + 'GroupId', + ], + }, + ], + Subnets: [ + { + Ref: 'VPCPublicSubnet1SubnetB4246D30', + }, + { + Ref: 'VPCPublicSubnet2Subnet74179F39', + }, + ], + }, + }, + PropagateTags: 'SERVICE', + ServiceName: 'myService', + }); + + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Environment: [ + { + Name: 'TEST_ENVIRONMENT_VARIABLE1', + Value: 'test environment variable 1 value', + }, + { + Name: 'TEST_ENVIRONMENT_VARIABLE2', + Value: 'test environment variable 2 value', + }, + ], + Essential: true, + Image: 'test', + LogConfiguration: { + LogDriver: 'awslogs', + Options: { + 'awslogs-group': { + Ref: 'ServiceTaskDefhelloLogGroup44519781', + }, + 'awslogs-stream-prefix': 'TestStream', + 'awslogs-region': { + Ref: 'AWS::Region', + }, + }, + }, + Name: 'hello', + PortMappings: [ + { + ContainerPort: 80, + Protocol: 'tcp', + }, + { + ContainerPort: 90, + Protocol: 'tcp', + }, + ], + DockerLabels: { + label1: 'labelValue1', + label2: 'labelValue2', + }, + }, + ], + Cpu: '256', + ExecutionRoleArn: { + 'Fn::GetAtt': [ + 'ExecutionRole605A040B', + 'Arn', + ], + }, + Family: 'Ec2TaskDef', + Memory: '512', + NetworkMode: 'awsvpc', + RequiresCompatibilities: [ + 'FARGATE', + ], + TaskRoleArn: { + 'Fn::GetAtt': [ + 'TaskRole30FC0FBB', + 'Arn', + ], + }, + }); + }); + + test('errors if no essential container in pre-defined task definition', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + const taskDefinition = new ecs.FargateTaskDefinition(stack, 'FargateTaskDef'); + + // THEN + expect(() => { + new NetworkMultipleTargetGroupsFargateService(stack, 'Service', { + cluster, + taskDefinition, + }); + }).toThrow(/At least one essential container must be specified/); + }); + + test('errors when setting both taskDefinition and taskImageOptions', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + const taskDefinition = new ecs.FargateTaskDefinition(stack, 'Ec2TaskDef'); + + // THEN + expect(() => { + new NetworkMultipleTargetGroupsFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('test'), + }, + taskDefinition, + }); + }).toThrow(/You must specify only one of TaskDefinition or TaskImageOptions./); + }); + + test('errors when setting neither taskDefinition nor taskImageOptions', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // THEN + expect(() => { + new NetworkMultipleTargetGroupsFargateService(stack, 'Service', { + cluster, + }); + }).toThrow(/You must specify one of: taskDefinition or image/); + }); +}); diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/load-balanced-fargate-service.test.ts b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/load-balanced-fargate-service.test.ts new file mode 100644 index 0000000000000..765d86788277e --- /dev/null +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/load-balanced-fargate-service.test.ts @@ -0,0 +1,1028 @@ +import { SynthUtils } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; +import { DnsValidatedCertificate } from '@aws-cdk/aws-certificatemanager'; +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as ecs from '@aws-cdk/aws-ecs'; +import { ApplicationLoadBalancer, ApplicationProtocol, NetworkLoadBalancer } from '@aws-cdk/aws-elasticloadbalancingv2'; +import * as iam from '@aws-cdk/aws-iam'; +import * as route53 from '@aws-cdk/aws-route53'; +import * as cdk from '@aws-cdk/core'; +import * as ecsPatterns from '../../lib'; + +test('setting loadBalancerType to Network creates an NLB Public', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ElasticLoadBalancingV2::LoadBalancer', { + Type: 'network', + Scheme: 'internet-facing', + }); +}); + +test('setting loadBalancerType to Network and publicLoadBalancer to false creates an NLB Private', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), + }, + publicLoadBalancer: false, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ElasticLoadBalancingV2::LoadBalancer', { + Type: 'network', + Scheme: 'internal', + }); +}); + +test('setting vpc and cluster throws error', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + expect(() => new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'Service', { + cluster, + vpc, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), + }, + })).toThrow(); +}); + +test('setting executionRole updated taskDefinition with given execution role', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + const executionRole = new iam.Role(stack, 'ExecutionRole', { + path: '/', + assumedBy: new iam.CompositePrincipal( + new iam.ServicePrincipal('ecs.amazonaws.com'), + new iam.ServicePrincipal('ecs-tasks.amazonaws.com'), + ), + }); + + // WHEN + new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), + executionRole, + }, + }); + + // THEN + const serviceTaskDefinition = SynthUtils.synthesize(stack).template.Resources.ServiceTaskDef1922A00F; + expect(serviceTaskDefinition.Properties.ExecutionRoleArn).toEqual({ 'Fn::GetAtt': ['ExecutionRole605A040B', 'Arn'] }); +}); + +test('setting taskRole updated taskDefinition with given task role', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + const taskRole = new iam.Role(stack, 'taskRoleTest', { + path: '/', + assumedBy: new iam.CompositePrincipal( + new iam.ServicePrincipal('ecs.amazonaws.com'), + new iam.ServicePrincipal('ecs-tasks.amazonaws.com'), + ), + }); + + // WHEN + new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), + taskRole, + }, + }); + + // THEN + const serviceTaskDefinition = SynthUtils.synthesize(stack).template.Resources.ServiceTaskDef1922A00F; + expect(serviceTaskDefinition.Properties.TaskRoleArn).toEqual({ 'Fn::GetAtt': ['taskRoleTest9DA66B6E', 'Arn'] }); +}); + +test('setting containerName updates container name with given name', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), + containerName: 'bob', + }, + }); + + // THEN + const serviceTaskDefinition = SynthUtils.synthesize(stack).template.Resources.ServiceTaskDef1922A00F; + expect(serviceTaskDefinition.Properties.ContainerDefinitions[0].Name).toEqual('bob'); +}); + +test('not setting containerName updates container name with default', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), + }, + }); + + // THEN + const serviceTaskDefinition = SynthUtils.synthesize(stack).template.Resources.ServiceTaskDef1922A00F; + expect(serviceTaskDefinition.Properties.ContainerDefinitions[0].Name).toEqual('web'); +}); + +test('setting servicename updates service name with given name', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), + }, + serviceName: 'bob', + }); + // THEN + const serviceTaskDefinition = SynthUtils.synthesize(stack).template.Resources.Service9571FDD8; + expect(serviceTaskDefinition.Properties.ServiceName).toEqual('bob'); +}); + +test('not setting servicename updates service name with default', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), + }, + }); + + // THEN + const serviceTaskDefinition = SynthUtils.synthesize(stack).template.Resources.Service9571FDD8; + expect(serviceTaskDefinition.Properties.ServiceName).toBeUndefined(); +}); + +test('setting healthCheckGracePeriod works', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), + }, + healthCheckGracePeriod: cdk.Duration.seconds(600), + }); + // THEN + const serviceTaskDefinition = SynthUtils.synthesize(stack).template.Resources.Service9571FDD8; + expect(serviceTaskDefinition.Properties.HealthCheckGracePeriodSeconds).toEqual(600); +}); + +test('selecting correct vpcSubnets', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'Vpc', { + maxAzs: 2, + subnetConfiguration: [ + { + subnetType: ec2.SubnetType.PUBLIC, + cidrMask: 20, + name: 'Public', + }, + { + subnetType: ec2.SubnetType.ISOLATED, + cidrMask: 20, + name: 'ISOLATED', + }, + ], + }); + // WHEN + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { + vpc, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), + }, + taskSubnets: { + subnetType: ec2.SubnetType.ISOLATED, + }, + }); + // THEN + expect(stack).toHaveResourceLike('AWS::ECS::Service', { + NetworkConfiguration: { + AwsvpcConfiguration: { + Subnets: [ + { + Ref: 'VpcISOLATEDSubnet1Subnet80F07FA0', + }, + { + Ref: 'VpcISOLATEDSubnet2SubnetB0B548C3', + }, + ], + }, + }, + }); +}); + +test('target group uses HTTP/80 as default', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), + }, + }); + // THEN + expect(stack).toHaveResourceLike('AWS::ElasticLoadBalancingV2::TargetGroup', { + Port: 80, + Protocol: 'HTTP', + }); +}); + +test('target group uses HTTPS/443 when configured', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), + }, + targetProtocol: ApplicationProtocol.HTTPS, + }); + // THEN + expect(stack).toHaveResourceLike('AWS::ElasticLoadBalancingV2::TargetGroup', { + Port: 443, + Protocol: 'HTTPS', + }); +}); + +test('setting platform version', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), + }, + platformVersion: ecs.FargatePlatformVersion.VERSION1_4, + }); + // THEN + expect(stack).toHaveResource('AWS::ECS::Service', { + PlatformVersion: ecs.FargatePlatformVersion.VERSION1_4, + }); +}); + +test('test load balanced service with family defined', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), + enableLogging: false, + environment: { + TEST_ENVIRONMENT_VARIABLE1: 'test environment variable 1 value', + TEST_ENVIRONMENT_VARIABLE2: 'test environment variable 2 value', + }, + family: 'fargate-task-family', + }, + desiredCount: 2, + memoryLimitMiB: 512, + serviceName: 'fargate-test-service', + }); + + // THEN + expect(stack).toHaveResource('AWS::ECS::Service', { + DesiredCount: 2, + LaunchType: 'FARGATE', + ServiceName: 'fargate-test-service', + }); + + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Environment: [ + { + Name: 'TEST_ENVIRONMENT_VARIABLE1', + Value: 'test environment variable 1 value', + }, + { + Name: 'TEST_ENVIRONMENT_VARIABLE2', + Value: 'test environment variable 2 value', + }, + ], + Image: '/aws/aws-example-app', + }, + ], + Family: 'fargate-task-family', + }); +}); + +test('setting ALB deployment controller', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), + }, + deploymentController: { + type: ecs.DeploymentControllerType.CODE_DEPLOY, + }, + }); + + // THEN + expect(stack).toHaveResource('AWS::ECS::Service', { + DeploymentController: { + Type: 'CODE_DEPLOY', + }, + }); +}); + +test('setting NLB deployment controller', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'Service', { + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), + }, + deploymentController: { + type: ecs.DeploymentControllerType.CODE_DEPLOY, + }, + }); + + // THEN + expect(stack).toHaveResource('AWS::ECS::Service', { + DeploymentController: { + Type: 'CODE_DEPLOY', + }, + }); +}); + +test('setting ALB circuitBreaker works', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), + }, + circuitBreaker: { rollback: true }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ECS::Service', { + DeploymentConfiguration: { + DeploymentCircuitBreaker: { + Enable: true, + Rollback: true, + }, + }, + DeploymentController: { + Type: 'ECS', + }, + }); +}); + +test('setting NLB circuitBreaker works', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'Service', { + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), + }, + circuitBreaker: { rollback: true }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ECS::Service', { + DeploymentConfiguration: { + DeploymentCircuitBreaker: { + Enable: true, + Rollback: true, + }, + }, + DeploymentController: { + Type: 'ECS', + }, + }); +}); + +test('setting NLB special listener port to create the listener', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'FargateNlbService', { + cluster, + listenerPort: 2015, + taskImageOptions: { + containerPort: 2015, + image: ecs.ContainerImage.fromRegistry('abiosoft/caddy'), + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ElasticLoadBalancingV2::Listener', { + DefaultActions: [ + { + Type: 'forward', + }, + ], + Port: 2015, + Protocol: 'TCP', + }); +}); + +test('setting ALB special listener port to create the listener', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'FargateAlbService', { + cluster, + listenerPort: 2015, + taskImageOptions: { + containerPort: 2015, + image: ecs.ContainerImage.fromRegistry('abiosoft/caddy'), + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ElasticLoadBalancingV2::Listener', { + DefaultActions: [ + { + Type: 'forward', + }, + ], + Port: 2015, + Protocol: 'HTTP', + }); +}); + +test('setting ALB HTTPS protocol to create the listener on 443', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'FargateAlbService', { + cluster, + protocol: ApplicationProtocol.HTTPS, + domainName: 'domain.com', + domainZone: route53.HostedZone.fromHostedZoneAttributes(stack, 'HostedZone', { + hostedZoneId: 'fakeId', + zoneName: 'domain.com', + }), + taskImageOptions: { + containerPort: 2015, + image: ecs.ContainerImage.fromRegistry('abiosoft/caddy'), + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ElasticLoadBalancingV2::Listener', { + DefaultActions: [ + { + Type: 'forward', + }, + ], + Port: 443, + Protocol: 'HTTPS', + }); +}); + +test('setting ALB HTTPS correctly sets the recordset name', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'FargateAlbService', { + cluster, + protocol: ApplicationProtocol.HTTPS, + domainName: 'test.domain.com', + domainZone: route53.HostedZone.fromHostedZoneAttributes(stack, 'HostedZone', { + hostedZoneId: 'fakeId', + zoneName: 'domain.com.', + }), + taskImageOptions: { + containerPort: 2015, + image: ecs.ContainerImage.fromRegistry('abiosoft/caddy'), + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::Route53::RecordSet', { + Name: 'test.domain.com.', + }); +}); + +test('setting ALB cname option correctly sets the recordset type', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'FargateAlbService', { + cluster, + protocol: ApplicationProtocol.HTTPS, + domainName: 'test.domain.com', + domainZone: route53.HostedZone.fromHostedZoneAttributes(stack, 'HostedZone', { + hostedZoneId: 'fakeId', + zoneName: 'domain.com.', + }), + recordType: ecsPatterns.ApplicationLoadBalancedServiceRecordType.CNAME, + taskImageOptions: { + containerPort: 2015, + image: ecs.ContainerImage.fromRegistry('abiosoft/caddy'), + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::Route53::RecordSet', { + Name: 'test.domain.com.', + Type: 'CNAME', + }); +}); + +test('setting ALB record type to NONE correctly omits the recordset', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'FargateAlbService', { + cluster, + protocol: ApplicationProtocol.HTTPS, + domainName: 'test.domain.com', + domainZone: route53.HostedZone.fromHostedZoneAttributes(stack, 'HostedZone', { + hostedZoneId: 'fakeId', + zoneName: 'domain.com.', + }), + recordType: ecsPatterns.ApplicationLoadBalancedServiceRecordType.NONE, + taskImageOptions: { + containerPort: 2015, + image: ecs.ContainerImage.fromRegistry('abiosoft/caddy'), + }, + }); + + // THEN + expect(stack).not.toHaveResource('AWS::Route53::RecordSet'); +}); + + +test('setting NLB cname option correctly sets the recordset type', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'FargateNlbService', { + cluster, + domainName: 'test.domain.com', + domainZone: route53.HostedZone.fromHostedZoneAttributes(stack, 'HostedZone', { + hostedZoneId: 'fakeId', + zoneName: 'domain.com.', + }), + recordType: ecsPatterns.NetworkLoadBalancedServiceRecordType.CNAME, + taskImageOptions: { + containerPort: 2015, + image: ecs.ContainerImage.fromRegistry('abiosoft/caddy'), + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::Route53::RecordSet', { + Name: 'test.domain.com.', + Type: 'CNAME', + }); +}); + +test('setting NLB record type to NONE correctly omits the recordset', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'FargateNlbService', { + cluster, + domainName: 'test.domain.com', + domainZone: route53.HostedZone.fromHostedZoneAttributes(stack, 'HostedZone', { + hostedZoneId: 'fakeId', + zoneName: 'domain.com.', + }), + recordType: ecsPatterns.NetworkLoadBalancedServiceRecordType.NONE, + taskImageOptions: { + containerPort: 2015, + image: ecs.ContainerImage.fromRegistry('abiosoft/caddy'), + }, + }); + + // THEN + expect(stack).not.toHaveResource('AWS::Route53::RecordSet'); +}); + +test('setting ALB HTTP protocol to create the listener on 80', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'FargateAlbService', { + cluster, + protocol: ApplicationProtocol.HTTP, + taskImageOptions: { + containerPort: 2015, + image: ecs.ContainerImage.fromRegistry('abiosoft/caddy'), + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ElasticLoadBalancingV2::Listener', { + DefaultActions: [ + { + Type: 'forward', + }, + ], + Port: 80, + Protocol: 'HTTP', + }); +}); + +test('setting ALB without any protocol or listenerPort to create the listener on 80', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'FargateAlbService', { + cluster, + taskImageOptions: { + containerPort: 2015, + image: ecs.ContainerImage.fromRegistry('abiosoft/caddy'), + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ElasticLoadBalancingV2::Listener', { + DefaultActions: [ + { + Type: 'forward', + }, + ], + Port: 80, + Protocol: 'HTTP', + }); +}); + +test('passing in existing network load balancer to NLB Fargate Service', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const nlb = new NetworkLoadBalancer(stack, 'NLB', { vpc }); + + // WHEN + new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'Service', { + vpc, + loadBalancer: nlb, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ECS::Service', { + LaunchType: 'FARGATE', + }); + + expect(stack).toHaveResourceLike('AWS::ElasticLoadBalancingV2::LoadBalancer', { + Type: 'network', + }); +}); + +test('passing in imported network load balancer and resources to NLB Fargate service', () => { + // GIVEN + const app = new cdk.App(); + const stack1 = new cdk.Stack(app, 'MyStack'); + const vpc1 = new ec2.Vpc(stack1, 'VPC'); + const cluster1 = new ecs.Cluster(stack1, 'Cluster', { vpc: vpc1 }); + const nlbArn = 'arn:aws:elasticloadbalancing:us-west-2:123456789012:loadbalancer/app/my-load-balancer/50dc6c495c0c9188'; + const stack2 = new cdk.Stack(stack1, 'Stack2'); + const cluster2 = ecs.Cluster.fromClusterAttributes(stack2, 'ImportedCluster', { + vpc: vpc1, + securityGroups: cluster1.connections.securityGroups, + clusterName: 'cluster-name', + }); + + // WHEN + const nlb2 = NetworkLoadBalancer.fromNetworkLoadBalancerAttributes(stack2, 'ImportedNLB', { + loadBalancerArn: nlbArn, + vpc: vpc1, + }); + const taskDef = new ecs.FargateTaskDefinition(stack2, 'TaskDef', { + cpu: 1024, + memoryLimitMiB: 1024, + }); + const container = taskDef.addContainer('myContainer', { + image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + memoryLimitMiB: 1024, + }); + container.addPortMappings({ + containerPort: 80, + }); + + new ecsPatterns.NetworkLoadBalancedFargateService(stack2, 'FargateNLBService', { + cluster: cluster2, + loadBalancer: nlb2, + desiredCount: 1, + taskDefinition: taskDef, + }); + + // THEN + expect(stack2).toHaveResourceLike('AWS::ECS::Service', { + LaunchType: 'FARGATE', + LoadBalancers: [{ ContainerName: 'myContainer', ContainerPort: 80 }], + }); + + expect(stack2).toHaveResourceLike('AWS::ElasticLoadBalancingV2::TargetGroup'); + + expect(stack2).toHaveResourceLike('AWS::ElasticLoadBalancingV2::Listener', { + LoadBalancerArn: nlb2.loadBalancerArn, + Port: 80, + }); +}); + +test('passing in previously created application load balancer to ALB Fargate Service', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'Vpc'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc, clusterName: 'MyCluster' }); + const sg = new ec2.SecurityGroup(stack, 'SecurityGroup', { vpc }); + cluster.connections.addSecurityGroup(sg); + const alb = new ApplicationLoadBalancer(stack, 'ALB', { vpc, securityGroup: sg }); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { + cluster, + loadBalancer: alb, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ECS::Service', { + LaunchType: 'FARGATE', + }); + + expect(stack).toHaveResourceLike('AWS::ElasticLoadBalancingV2::LoadBalancer', { + Type: 'application', + }); +}); + +test('passing in imported application load balancer and resources to ALB Fargate Service', () => { + // GIVEN + const stack1 = new cdk.Stack(); + const albArn = 'arn:aws:elasticloadbalancing:us-west-2:123456789012:loadbalancer/app/my-load-balancer/50dc6c495c0c9188'; + const vpc = new ec2.Vpc(stack1, 'Vpc'); + const cluster = new ecs.Cluster(stack1, 'Cluster', { vpc, clusterName: 'MyClusterName' }); + const sg = new ec2.SecurityGroup(stack1, 'SecurityGroup', { vpc }); + cluster.connections.addSecurityGroup(sg); + const alb = ApplicationLoadBalancer.fromApplicationLoadBalancerAttributes(stack1, 'ALB', { + loadBalancerArn: albArn, + vpc, + securityGroupId: sg.securityGroupId, + loadBalancerDnsName: 'MyDnsName', + }); + + // WHEN + const taskDef = new ecs.FargateTaskDefinition(stack1, 'TaskDef', { + cpu: 1024, + memoryLimitMiB: 1024, + }); + const container = taskDef.addContainer('Container', { + image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + memoryLimitMiB: 1024, + }); + container.addPortMappings({ + containerPort: 80, + }); + + new ecsPatterns.ApplicationLoadBalancedFargateService(stack1, 'FargateALBService', { + cluster, + loadBalancer: alb, + desiredCount: 1, + taskDefinition: taskDef, + }); + + // THEN + expect(stack1).toHaveResourceLike('AWS::ECS::Service', { + LaunchType: 'FARGATE', + LoadBalancers: [{ ContainerName: 'Container', ContainerPort: 80 }], + }); + + expect(stack1).toHaveResourceLike('AWS::ElasticLoadBalancingV2::TargetGroup'); + + expect(stack1).toHaveResourceLike('AWS::ElasticLoadBalancingV2::Listener', { + LoadBalancerArn: alb.loadBalancerArn, + Port: 80, + }); +}); + +test('passing in previously created security groups to ALB Fargate Service', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'Vpc'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc, clusterName: 'MyCluster' }); + const securityGroup = new ec2.SecurityGroup(stack, 'SecurityGroup', { + allowAllOutbound: false, + description: 'Example', + securityGroupName: 'Rolly', + vpc, + }); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + }, + securityGroups: [securityGroup], + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ECS::Service', { + LaunchType: 'FARGATE', + }); + + expect(stack).toHaveResource('AWS::EC2::SecurityGroup', { + GroupDescription: 'Example', + GroupName: 'Rolly', + SecurityGroupEgress: [ + { + CidrIp: '255.255.255.255/32', + Description: 'Disallow all traffic', + FromPort: 252, + IpProtocol: 'icmp', + ToPort: 86, + }, + ], + VpcId: { + Ref: 'Vpc8378EB38', + }, + }); +}); + +test('domainName and domainZone not required for HTTPS listener with provided cert', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + const exampleDotComZone = new route53.PublicHostedZone(stack, 'ExampleDotCom', { + zoneName: 'example.com', + }); + const certificate = new DnsValidatedCertificate(stack, 'Certificate', { + domainName: 'test.example.com', + hostedZone: exampleDotComZone, + }); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'FargateAlbService', { + cluster, + protocol: ApplicationProtocol.HTTPS, + + taskImageOptions: { + containerPort: 2015, + image: ecs.ContainerImage.fromRegistry('abiosoft/caddy'), + }, + certificate: certificate, + }); + + // THEN + expect(stack).not.toHaveResourceLike('AWS::Route53::RecordSet', { + Name: 'test.domain.com.', + }); +}); + +test('test ALB load balanced service with docker labels defined', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), + dockerLabels: { label1: 'labelValue1', label2: 'labelValue2' }, + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Image: '/aws/aws-example-app', + DockerLabels: { + label1: 'labelValue1', + label2: 'labelValue2', + }, + }, + ], + }); +}); + +test('test Network load balanced service with docker labels defined', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), + dockerLabels: { label1: 'labelValue1', label2: 'labelValue2' }, + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Image: '/aws/aws-example-app', + DockerLabels: { + label1: 'labelValue1', + label2: 'labelValue2', + }, + }, + ], + }); +}); diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/queue-processing-fargate-service.test.ts b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/queue-processing-fargate-service.test.ts new file mode 100644 index 0000000000000..916bcb43cdf63 --- /dev/null +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/queue-processing-fargate-service.test.ts @@ -0,0 +1,555 @@ +import { ABSENT } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as ecs from '@aws-cdk/aws-ecs'; +import * as sqs from '@aws-cdk/aws-sqs'; +import * as cdk from '@aws-cdk/core'; +import * as cxapi from '@aws-cdk/cx-api'; +import * as ecsPatterns from '../../lib'; + +test('test fargate queue worker service construct - with only required props', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); + + // WHEN + new ecsPatterns.QueueProcessingFargateService(stack, 'Service', { + cluster, + memoryLimitMiB: 512, + image: ecs.ContainerImage.fromRegistry('test'), + }); + + // THEN - QueueWorker is of FARGATE launch type, an SQS queue is created and all default properties are set. + expect(stack).toHaveResource('AWS::ECS::Service', { + DesiredCount: 1, + LaunchType: 'FARGATE', + }); + + expect(stack).toHaveResource('AWS::SQS::Queue', { + RedrivePolicy: { + deadLetterTargetArn: { + 'Fn::GetAtt': [ + 'ServiceEcsProcessingDeadLetterQueue4A89196E', + 'Arn', + ], + }, + maxReceiveCount: 3, + }, + }); + + expect(stack).toHaveResource('AWS::SQS::Queue', { + MessageRetentionPeriod: 1209600, + }); + + expect(stack).toHaveResource('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [ + { + Action: [ + 'sqs:ReceiveMessage', + 'sqs:ChangeMessageVisibility', + 'sqs:GetQueueUrl', + 'sqs:DeleteMessage', + 'sqs:GetQueueAttributes', + ], + Effect: 'Allow', + Resource: { + 'Fn::GetAtt': [ + 'ServiceEcsProcessingQueueC266885C', + 'Arn', + ], + }, + }, + ], + Version: '2012-10-17', + }, + }); + + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Environment: [ + { + Name: 'QUEUE_NAME', + Value: { + 'Fn::GetAtt': [ + 'ServiceEcsProcessingQueueC266885C', + 'QueueName', + ], + }, + }, + ], + LogConfiguration: { + LogDriver: 'awslogs', + Options: { + 'awslogs-group': { + Ref: 'ServiceQueueProcessingTaskDefQueueProcessingContainerLogGroupD52338D1', + }, + 'awslogs-stream-prefix': 'Service', + 'awslogs-region': { + Ref: 'AWS::Region', + }, + }, + }, + Image: 'test', + }, + ], + Family: 'ServiceQueueProcessingTaskDef83DB34F1', + }); +}); + +test('test fargate queue worker service construct - with remove default desiredCount feature flag', () => { + // GIVEN + const stack = new cdk.Stack(); + stack.node.setContext(cxapi.ECS_REMOVE_DEFAULT_DESIRED_COUNT, true); + + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + new ecsPatterns.QueueProcessingFargateService(stack, 'Service', { + cluster, + memoryLimitMiB: 512, + image: ecs.ContainerImage.fromRegistry('test'), + }); + + // THEN - QueueWorker is of FARGATE launch type, and desiredCount is not defined on the FargateService. + expect(stack).toHaveResource('AWS::ECS::Service', { + DesiredCount: ABSENT, + LaunchType: 'FARGATE', + }); +}); + +test('test fargate queue worker service construct - with optional props for queues', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); + + // WHEN + new ecsPatterns.QueueProcessingFargateService(stack, 'Service', { + cluster, + memoryLimitMiB: 512, + image: ecs.ContainerImage.fromRegistry('test'), + maxReceiveCount: 42, + retentionPeriod: cdk.Duration.days(7), + visibilityTimeout: cdk.Duration.minutes(5), + }); + + // THEN - QueueWorker is of FARGATE launch type, an SQS queue is created and all default properties are set. + expect(stack).toHaveResource('AWS::ECS::Service', { + DesiredCount: 1, + LaunchType: 'FARGATE', + }); + + expect(stack).toHaveResource('AWS::SQS::Queue', { + RedrivePolicy: { + deadLetterTargetArn: { + 'Fn::GetAtt': [ + 'ServiceEcsProcessingDeadLetterQueue4A89196E', + 'Arn', + ], + }, + maxReceiveCount: 42, + }, + VisibilityTimeout: 300, + }); + + expect(stack).toHaveResource('AWS::SQS::Queue', { + MessageRetentionPeriod: 604800, + }); + + expect(stack).toHaveResource('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [ + { + Action: [ + 'sqs:ReceiveMessage', + 'sqs:ChangeMessageVisibility', + 'sqs:GetQueueUrl', + 'sqs:DeleteMessage', + 'sqs:GetQueueAttributes', + ], + Effect: 'Allow', + Resource: { + 'Fn::GetAtt': [ + 'ServiceEcsProcessingQueueC266885C', + 'Arn', + ], + }, + }, + ], + Version: '2012-10-17', + }, + }); + + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Environment: [ + { + Name: 'QUEUE_NAME', + Value: { + 'Fn::GetAtt': [ + 'ServiceEcsProcessingQueueC266885C', + 'QueueName', + ], + }, + }, + ], + LogConfiguration: { + LogDriver: 'awslogs', + Options: { + 'awslogs-group': { + Ref: 'ServiceQueueProcessingTaskDefQueueProcessingContainerLogGroupD52338D1', + }, + 'awslogs-stream-prefix': 'Service', + 'awslogs-region': { + Ref: 'AWS::Region', + }, + }, + }, + Image: 'test', + }, + ], + Family: 'ServiceQueueProcessingTaskDef83DB34F1', + }); +}); + +test('test Fargate queue worker service construct - without desiredCount specified', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); + const queue = new sqs.Queue(stack, 'fargate-test-queue', { + queueName: 'fargate-test-sqs-queue', + }); + + // WHEN + new ecsPatterns.QueueProcessingFargateService(stack, 'Service', { + cluster, + memoryLimitMiB: 512, + image: ecs.ContainerImage.fromRegistry('test'), + command: ['-c', '4', 'amazon.com'], + enableLogging: false, + environment: { + TEST_ENVIRONMENT_VARIABLE1: 'test environment variable 1 value', + TEST_ENVIRONMENT_VARIABLE2: 'test environment variable 2 value', + }, + queue, + maxScalingCapacity: 5, + minScalingCapacity: 2, + minHealthyPercent: 60, + maxHealthyPercent: 150, + serviceName: 'fargate-test-service', + family: 'fargate-task-family', + platformVersion: ecs.FargatePlatformVersion.VERSION1_4, + deploymentController: { + type: ecs.DeploymentControllerType.CODE_DEPLOY, + }, + }); + + // THEN - QueueWorker is of FARGATE launch type, an SQS queue is created and all optional properties are set. + expect(stack).toHaveResource('AWS::ECS::Service', { + DeploymentConfiguration: { + MinimumHealthyPercent: 60, + MaximumPercent: 150, + }, + LaunchType: 'FARGATE', + ServiceName: 'fargate-test-service', + PlatformVersion: ecs.FargatePlatformVersion.VERSION1_4, + DeploymentController: { + Type: 'CODE_DEPLOY', + }, + }); + + expect(stack).toHaveResource('AWS::ApplicationAutoScaling::ScalableTarget', { + MaxCapacity: 5, + MinCapacity: 2, + }); + + expect(stack).toHaveResource('AWS::SQS::Queue', { QueueName: 'fargate-test-sqs-queue' }); + + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Command: [ + '-c', + '4', + 'amazon.com', + ], + Environment: [ + { + Name: 'TEST_ENVIRONMENT_VARIABLE1', + Value: 'test environment variable 1 value', + }, + { + Name: 'TEST_ENVIRONMENT_VARIABLE2', + Value: 'test environment variable 2 value', + }, + { + Name: 'QUEUE_NAME', + Value: { + 'Fn::GetAtt': [ + 'fargatetestqueue28B43841', + 'QueueName', + ], + }, + }, + ], + Image: 'test', + }, + ], + Family: 'fargate-task-family', + }); +}); + +test('test Fargate queue worker service construct - with optional props', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); + const queue = new sqs.Queue(stack, 'fargate-test-queue', { + queueName: 'fargate-test-sqs-queue', + }); + + // WHEN + new ecsPatterns.QueueProcessingFargateService(stack, 'Service', { + cluster, + memoryLimitMiB: 512, + image: ecs.ContainerImage.fromRegistry('test'), + command: ['-c', '4', 'amazon.com'], + enableLogging: false, + desiredTaskCount: 2, + environment: { + TEST_ENVIRONMENT_VARIABLE1: 'test environment variable 1 value', + TEST_ENVIRONMENT_VARIABLE2: 'test environment variable 2 value', + }, + queue, + maxScalingCapacity: 5, + minHealthyPercent: 60, + maxHealthyPercent: 150, + serviceName: 'fargate-test-service', + family: 'fargate-task-family', + platformVersion: ecs.FargatePlatformVersion.VERSION1_4, + circuitBreaker: { rollback: true }, + }); + + // THEN - QueueWorker is of FARGATE launch type, an SQS queue is created and all optional properties are set. + expect(stack).toHaveResource('AWS::ECS::Service', { + DesiredCount: 2, + DeploymentConfiguration: { + MinimumHealthyPercent: 60, + MaximumPercent: 150, + DeploymentCircuitBreaker: { + Enable: true, + Rollback: true, + }, + }, + LaunchType: 'FARGATE', + ServiceName: 'fargate-test-service', + PlatformVersion: ecs.FargatePlatformVersion.VERSION1_4, + DeploymentController: { + Type: 'ECS', + }, + }); + + expect(stack).toHaveResource('AWS::SQS::Queue', { QueueName: 'fargate-test-sqs-queue' }); + + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Command: [ + '-c', + '4', + 'amazon.com', + ], + Environment: [ + { + Name: 'TEST_ENVIRONMENT_VARIABLE1', + Value: 'test environment variable 1 value', + }, + { + Name: 'TEST_ENVIRONMENT_VARIABLE2', + Value: 'test environment variable 2 value', + }, + { + Name: 'QUEUE_NAME', + Value: { + 'Fn::GetAtt': [ + 'fargatetestqueue28B43841', + 'QueueName', + ], + }, + }, + ], + Image: 'test', + }, + ], + Family: 'fargate-task-family', + }); +}); + +test('can set custom containerName', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); + + // WHEN + new ecsPatterns.QueueProcessingFargateService(stack, 'Service', { + cluster, + containerName: 'my-container', + image: ecs.ContainerImage.fromRegistry('test'), + }); + + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Name: 'my-container', + }, + ], + }); +}); + +test('can set custom networking options', () => { + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC', { + subnetConfiguration: [ + { + cidrMask: 24, + name: 'Public', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'Isolated', + subnetType: ec2.SubnetType.ISOLATED, + }, + ], + }); + const securityGroup = new ec2.SecurityGroup(stack, 'MyCustomSG', { + vpc, + }); + + // WHEN - SecurityGroups and taskSubnets selection is defined + new ecsPatterns.QueueProcessingFargateService(stack, 'Service', { + vpc, + memoryLimitMiB: 512, + image: ecs.ContainerImage.fromRegistry('test'), + securityGroups: [securityGroup], + taskSubnets: { subnetType: ec2.SubnetType.ISOLATED }, + }); + + // THEN - NetworkConfiguration is created with the specific security groups and selected subnets + expect(stack).toHaveResource('AWS::ECS::Service', { + LaunchType: 'FARGATE', + NetworkConfiguration: { + AwsvpcConfiguration: { + AssignPublicIp: 'DISABLED', + SecurityGroups: [ + { + 'Fn::GetAtt': [ + 'MyCustomSGDE27C661', + 'GroupId', + ], + }, + ], + Subnets: [ + { + Ref: 'VPCIsolatedSubnet1SubnetEBD00FC6', + }, + { + Ref: 'VPCIsolatedSubnet2Subnet4B1C8CAA', + }, + ], + }, + }, + }); +}); + +test('can set use public IP', () => { + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + // WHEN - Assign Public IP is set to True + new ecsPatterns.QueueProcessingFargateService(stack, 'Service', { + vpc, + memoryLimitMiB: 512, + image: ecs.ContainerImage.fromRegistry('test'), + assignPublicIp: true, + }); + + // THEN - The Subnets defaults to Public and AssignPublicIp settings change to ENABLED + expect(stack).toHaveResource('AWS::ECS::Service', { + LaunchType: 'FARGATE', + NetworkConfiguration: { + AwsvpcConfiguration: { + AssignPublicIp: 'ENABLED', + SecurityGroups: [ + { + 'Fn::GetAtt': [ + 'ServiceQueueProcessingFargateServiceSecurityGroup6E981512', + 'GroupId', + ], + }, + ], + Subnets: [ + { + Ref: 'VPCPublicSubnet1SubnetB4246D30', + }, + { + Ref: 'VPCPublicSubnet2Subnet74179F39', + }, + ], + }, + }, + }); +}); + +test('can set capacity provider strategies', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'MyVpc', {}); + const cluster = new ecs.Cluster(stack, 'EcsCluster', { + vpc, + }); + cluster.enableFargateCapacityProviders(); + + // WHEN + new ecsPatterns.QueueProcessingFargateService(stack, 'Service', { + cluster, + image: ecs.ContainerImage.fromRegistry('test'), + capacityProviderStrategies: [ + { + capacityProvider: 'FARGATE_SPOT', + weight: 2, + }, + { + capacityProvider: 'FARGATE', + weight: 1, + }, + ], + }); + + // THEN + expect(stack).toHaveResource('AWS::ECS::Service', { + LaunchType: ABSENT, + CapacityProviderStrategy: [ + { + CapacityProvider: 'FARGATE_SPOT', + Weight: 2, + }, + { + CapacityProvider: 'FARGATE', + Weight: 1, + }, + ], + }); +}); diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/scheduled-fargate-task.test.ts b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/scheduled-fargate-task.test.ts new file mode 100644 index 0000000000000..5d37bba01af2f --- /dev/null +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/scheduled-fargate-task.test.ts @@ -0,0 +1,412 @@ +import '@aws-cdk/assert-internal/jest'; +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as ecs from '@aws-cdk/aws-ecs'; +import * as events from '@aws-cdk/aws-events'; +import * as cdk from '@aws-cdk/core'; +import { ScheduledFargateTask } from '../../lib'; + +test('Can create a scheduled Fargate Task - with only required props', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 1 }); + const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); + + new ScheduledFargateTask(stack, 'ScheduledFargateTask', { + cluster, + scheduledFargateTaskImageOptions: { + image: ecs.ContainerImage.fromRegistry('henk'), + memoryLimitMiB: 512, + }, + schedule: events.Schedule.expression('rate(1 minute)'), + }); + + // THEN + expect(stack).toHaveResource('AWS::Events::Rule', { + State: 'ENABLED', + Targets: [ + { + Arn: { 'Fn::GetAtt': ['EcsCluster97242B84', 'Arn'] }, + EcsParameters: { + LaunchType: 'FARGATE', + NetworkConfiguration: { + AwsVpcConfiguration: { + AssignPublicIp: 'DISABLED', + SecurityGroups: [ + { + 'Fn::GetAtt': [ + 'ScheduledFargateTaskScheduledTaskDefSecurityGroupE075BC19', + 'GroupId', + ], + }, + ], + Subnets: [ + { + Ref: 'VpcPrivateSubnet1Subnet536B997A', + }, + ], + }, + }, + TaskCount: 1, + TaskDefinitionArn: { Ref: 'ScheduledFargateTaskScheduledTaskDef521FA675' }, + }, + Id: 'Target0', + Input: '{}', + RoleArn: { 'Fn::GetAtt': ['ScheduledFargateTaskScheduledTaskDefEventsRole6CE19522', 'Arn'] }, + }, + ], + }); + + expect(stack).toHaveResource('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Essential: true, + Image: 'henk', + LogConfiguration: { + LogDriver: 'awslogs', + Options: { + 'awslogs-group': { + Ref: 'ScheduledFargateTaskScheduledTaskDefScheduledContainerLogGroup4134B16C', + }, + 'awslogs-stream-prefix': 'ScheduledFargateTask', + 'awslogs-region': { + Ref: 'AWS::Region', + }, + }, + }, + Name: 'ScheduledContainer', + }, + ], + }); +}); + +test('Can create a scheduled Fargate Task - with optional props', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 1 }); + const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); + + new ScheduledFargateTask(stack, 'ScheduledFargateTask', { + cluster, + enabled: false, + scheduledFargateTaskImageOptions: { + image: ecs.ContainerImage.fromRegistry('henk'), + memoryLimitMiB: 512, + cpu: 2, + environment: { TRIGGER: 'CloudWatch Events' }, + }, + desiredTaskCount: 2, + schedule: events.Schedule.expression('rate(1 minute)'), + ruleName: 'sample-scheduled-task-rule', + }); + + // THEN + expect(stack).toHaveResource('AWS::Events::Rule', { + Name: 'sample-scheduled-task-rule', + State: 'DISABLED', + Targets: [ + { + Arn: { 'Fn::GetAtt': ['EcsCluster97242B84', 'Arn'] }, + EcsParameters: { + LaunchType: 'FARGATE', + NetworkConfiguration: { + AwsVpcConfiguration: { + AssignPublicIp: 'DISABLED', + SecurityGroups: [ + { + 'Fn::GetAtt': [ + 'ScheduledFargateTaskScheduledTaskDefSecurityGroupE075BC19', + 'GroupId', + ], + }, + ], + Subnets: [ + { + Ref: 'VpcPrivateSubnet1Subnet536B997A', + }, + ], + }, + }, + TaskCount: 2, + TaskDefinitionArn: { Ref: 'ScheduledFargateTaskScheduledTaskDef521FA675' }, + }, + Id: 'Target0', + Input: '{}', + RoleArn: { 'Fn::GetAtt': ['ScheduledFargateTaskScheduledTaskDefEventsRole6CE19522', 'Arn'] }, + }, + ], + }); + + expect(stack).toHaveResource('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Environment: [ + { + Name: 'TRIGGER', + Value: 'CloudWatch Events', + }, + ], + Essential: true, + Image: 'henk', + LogConfiguration: { + LogDriver: 'awslogs', + Options: { + 'awslogs-group': { + Ref: 'ScheduledFargateTaskScheduledTaskDefScheduledContainerLogGroup4134B16C', + }, + 'awslogs-stream-prefix': 'ScheduledFargateTask', + 'awslogs-region': { + Ref: 'AWS::Region', + }, + }, + }, + Name: 'ScheduledContainer', + }, + ], + }); +}); + +test('Scheduled Fargate Task - with MemoryReservation defined', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 1 }); + const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); + + new ScheduledFargateTask(stack, 'ScheduledFargateTask', { + cluster, + scheduledFargateTaskImageOptions: { + image: ecs.ContainerImage.fromRegistry('henk'), + }, + schedule: events.Schedule.expression('rate(1 minute)'), + }); + + // THEN + expect(stack).toHaveResource('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Essential: true, + Image: 'henk', + LogConfiguration: { + LogDriver: 'awslogs', + Options: { + 'awslogs-group': { + Ref: 'ScheduledFargateTaskScheduledTaskDefScheduledContainerLogGroup4134B16C', + }, + 'awslogs-stream-prefix': 'ScheduledFargateTask', + 'awslogs-region': { + Ref: 'AWS::Region', + }, + }, + }, + Name: 'ScheduledContainer', + }, + ], + }); +}); + +test('Scheduled Fargate Task - with Command defined', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 1 }); + const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); + + new ScheduledFargateTask(stack, 'ScheduledFargateTask', { + cluster, + scheduledFargateTaskImageOptions: { + image: ecs.ContainerImage.fromRegistry('henk'), + command: ['-c', '4', 'amazon.com'], + }, + schedule: events.Schedule.expression('rate(1 minute)'), + }); + + // THEN + expect(stack).toHaveResource('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Command: [ + '-c', + '4', + 'amazon.com', + ], + Essential: true, + Image: 'henk', + LogConfiguration: { + LogDriver: 'awslogs', + Options: { + 'awslogs-group': { + Ref: 'ScheduledFargateTaskScheduledTaskDefScheduledContainerLogGroup4134B16C', + }, + 'awslogs-stream-prefix': 'ScheduledFargateTask', + 'awslogs-region': { + Ref: 'AWS::Region', + }, + }, + }, + Name: 'ScheduledContainer', + }, + ], + }); +}); + +test('Scheduled Fargate Task - with subnetSelection defined', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'Vpc', { + maxAzs: 1, + subnetConfiguration: [ + { name: 'Public', cidrMask: 28, subnetType: ec2.SubnetType.PUBLIC }, + ], + }); + const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); + + new ScheduledFargateTask(stack, 'ScheduledFargateTask', { + cluster, + scheduledFargateTaskImageOptions: { + image: ecs.ContainerImage.fromRegistry('henk'), + }, + subnetSelection: { subnetType: ec2.SubnetType.PUBLIC }, + schedule: events.Schedule.expression('rate(1 minute)'), + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::Events::Rule', { + Targets: [ + { + EcsParameters: { + NetworkConfiguration: { + AwsVpcConfiguration: { + AssignPublicIp: 'ENABLED', + Subnets: [ + { + Ref: 'VpcPublicSubnet1Subnet5C2D37C4', + }, + ], + }, + }, + }, + }, + ], + }); +}); + +test('Scheduled Fargate Task - with platformVersion defined', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 1 }); + const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); + + new ScheduledFargateTask(stack, 'ScheduledFargateTask', { + cluster, + scheduledFargateTaskImageOptions: { + image: ecs.ContainerImage.fromRegistry('henk'), + memoryLimitMiB: 512, + }, + schedule: events.Schedule.expression('rate(1 minute)'), + platformVersion: ecs.FargatePlatformVersion.VERSION1_4, + }); + + // THEN + expect(stack).toHaveResource('AWS::Events::Rule', { + Targets: [ + { + Arn: { 'Fn::GetAtt': ['EcsCluster97242B84', 'Arn'] }, + EcsParameters: { + LaunchType: 'FARGATE', + NetworkConfiguration: { + AwsVpcConfiguration: { + AssignPublicIp: 'DISABLED', + SecurityGroups: [ + { + 'Fn::GetAtt': [ + 'ScheduledFargateTaskScheduledTaskDefSecurityGroupE075BC19', + 'GroupId', + ], + }, + ], + Subnets: [ + { + Ref: 'VpcPrivateSubnet1Subnet536B997A', + }, + ], + }, + }, + PlatformVersion: '1.4.0', + TaskCount: 1, + TaskDefinitionArn: { Ref: 'ScheduledFargateTaskScheduledTaskDef521FA675' }, + }, + Id: 'Target0', + Input: '{}', + RoleArn: { 'Fn::GetAtt': ['ScheduledFargateTaskScheduledTaskDefEventsRole6CE19522', 'Arn'] }, + }, + ], + }); +}); + +test('Scheduled Fargate Task - with securityGroups defined', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 1 }); + const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); + const sg = new ec2.SecurityGroup(stack, 'SG', { vpc }); + + new ScheduledFargateTask(stack, 'ScheduledFargateTask', { + cluster, + scheduledFargateTaskImageOptions: { + image: ecs.ContainerImage.fromRegistry('henk'), + memoryLimitMiB: 512, + }, + schedule: events.Schedule.expression('rate(1 minute)'), + securityGroups: [sg], + }); + + // THEN + expect(stack).toHaveResource('AWS::Events::Rule', { + Targets: [ + { + Arn: { 'Fn::GetAtt': ['EcsCluster97242B84', 'Arn'] }, + EcsParameters: { + LaunchType: 'FARGATE', + NetworkConfiguration: { + AwsVpcConfiguration: { + AssignPublicIp: 'DISABLED', + SecurityGroups: [{ + 'Fn::GetAtt': [ + 'SGADB53937', + 'GroupId', + ], + }], + Subnets: [ + { + Ref: 'VpcPrivateSubnet1Subnet536B997A', + }, + ], + }, + }, + TaskCount: 1, + TaskDefinitionArn: { Ref: 'ScheduledFargateTaskScheduledTaskDef521FA675' }, + }, + Id: 'Target0', + Input: '{}', + RoleArn: { 'Fn::GetAtt': ['ScheduledFargateTaskScheduledTaskDefEventsRole6CE19522', 'Arn'] }, + }, + ], + }); +}); + +test('Scheduled Fargate Task - exposes ECS Task', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 1 }); + const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); + + const scheduledFargateTask = new ScheduledFargateTask(stack, 'ScheduledFargateTask', { + cluster, + scheduledFargateTaskImageOptions: { + image: ecs.ContainerImage.fromRegistry('henk'), + memoryLimitMiB: 512, + }, + schedule: events.Schedule.expression('rate(1 minute)'), + }); + + // THEN + expect(scheduledFargateTask.task).toBeDefined(); +}); diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.load-balanced-fargate-service-v2.ts b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.load-balanced-fargate-service-v2.ts deleted file mode 100644 index cad68a5a270ae..0000000000000 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.load-balanced-fargate-service-v2.ts +++ /dev/null @@ -1,689 +0,0 @@ -import { expect, haveResource, haveResourceLike } from '@aws-cdk/assert-internal'; -import { Vpc } from '@aws-cdk/aws-ec2'; -import * as ecs from '@aws-cdk/aws-ecs'; -import { CompositePrincipal, Role, ServicePrincipal } from '@aws-cdk/aws-iam'; -import { Duration, Stack } from '@aws-cdk/core'; -import { Test } from 'nodeunit'; -import { ApplicationMultipleTargetGroupsFargateService, NetworkMultipleTargetGroupsFargateService, ApplicationLoadBalancedFargateService } from '../../lib'; - -export = { - 'When Application Load Balancer': { - 'test Fargate loadbalanced construct with default settings'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - new ApplicationMultipleTargetGroupsFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('test'), - }, - }); - - // THEN - stack contains a load balancer and a service - expect(stack).to(haveResource('AWS::ElasticLoadBalancingV2::LoadBalancer')); - - expect(stack).to(haveResource('AWS::ECS::Service', { - DesiredCount: 1, - LaunchType: 'FARGATE', - LoadBalancers: [ - { - ContainerName: 'web', - ContainerPort: 80, - TargetGroupArn: { - Ref: 'ServiceLBPublicListenerECSGroup0CC8688C', - }, - }, - ], - })); - - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Image: 'test', - LogConfiguration: { - LogDriver: 'awslogs', - Options: { - 'awslogs-group': { - Ref: 'ServiceTaskDefwebLogGroup2A898F61', - }, - 'awslogs-stream-prefix': 'Service', - 'awslogs-region': { - Ref: 'AWS::Region', - }, - }, - }, - Name: 'web', - PortMappings: [ - { - ContainerPort: 80, - Protocol: 'tcp', - }, - ], - }, - ], - Cpu: '256', - ExecutionRoleArn: { - 'Fn::GetAtt': [ - 'ServiceTaskDefExecutionRole919F7BE3', - 'Arn', - ], - }, - Family: 'ServiceTaskDef79D79521', - Memory: '512', - NetworkMode: 'awsvpc', - RequiresCompatibilities: [ - 'FARGATE', - ], - })); - - test.done(); - }, - - 'test Fargate loadbalanced construct with all settings'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - new ApplicationMultipleTargetGroupsFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('test'), - containerName: 'hello', - containerPorts: [80, 90], - enableLogging: false, - environment: { - TEST_ENVIRONMENT_VARIABLE1: 'test environment variable 1 value', - TEST_ENVIRONMENT_VARIABLE2: 'test environment variable 2 value', - }, - logDriver: new ecs.AwsLogDriver({ - streamPrefix: 'TestStream', - }), - family: 'Ec2TaskDef', - executionRole: new Role(stack, 'ExecutionRole', { - path: '/', - assumedBy: new CompositePrincipal( - new ServicePrincipal('ecs.amazonaws.com'), - new ServicePrincipal('ecs-tasks.amazonaws.com'), - ), - }), - taskRole: new Role(stack, 'TaskRole', { - assumedBy: new ServicePrincipal('ecs-tasks.amazonaws.com'), - }), - dockerLabels: { label1: 'labelValue1', label2: 'labelValue2' }, - }, - cpu: 256, - assignPublicIp: true, - memoryLimitMiB: 512, - desiredCount: 3, - enableECSManagedTags: true, - healthCheckGracePeriod: Duration.millis(2000), - platformVersion: ecs.FargatePlatformVersion.VERSION1_4, - propagateTags: ecs.PropagatedTagSource.SERVICE, - serviceName: 'myService', - targetGroups: [ - { - containerPort: 80, - }, - { - containerPort: 90, - pathPattern: 'a/b/c', - priority: 10, - protocol: ecs.Protocol.TCP, - }, - ], - }); - - // THEN - stack contains a load balancer and a service - expect(stack).to(haveResource('AWS::ECS::Service', { - DesiredCount: 3, - EnableECSManagedTags: true, - HealthCheckGracePeriodSeconds: 2, - LaunchType: 'FARGATE', - LoadBalancers: [ - { - ContainerName: 'hello', - ContainerPort: 80, - TargetGroupArn: { - Ref: 'ServiceLBPublicListenerECSTargetGrouphello80Group233A4D54', - }, - }, - { - ContainerName: 'hello', - ContainerPort: 90, - TargetGroupArn: { - Ref: 'ServiceLBPublicListenerECSTargetGrouphello90GroupE58E4EAB', - }, - }, - ], - NetworkConfiguration: { - AwsvpcConfiguration: { - AssignPublicIp: 'ENABLED', - SecurityGroups: [ - { - 'Fn::GetAtt': [ - 'ServiceSecurityGroupEEA09B68', - 'GroupId', - ], - }, - ], - Subnets: [ - { - Ref: 'VPCPublicSubnet1SubnetB4246D30', - }, - { - Ref: 'VPCPublicSubnet2Subnet74179F39', - }, - ], - }, - }, - PlatformVersion: ecs.FargatePlatformVersion.VERSION1_4, - PropagateTags: 'SERVICE', - ServiceName: 'myService', - })); - - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Environment: [ - { - Name: 'TEST_ENVIRONMENT_VARIABLE1', - Value: 'test environment variable 1 value', - }, - { - Name: 'TEST_ENVIRONMENT_VARIABLE2', - Value: 'test environment variable 2 value', - }, - ], - Essential: true, - Image: 'test', - LogConfiguration: { - LogDriver: 'awslogs', - Options: { - 'awslogs-group': { - Ref: 'ServiceTaskDefhelloLogGroup44519781', - }, - 'awslogs-stream-prefix': 'TestStream', - 'awslogs-region': { - Ref: 'AWS::Region', - }, - }, - }, - Name: 'hello', - PortMappings: [ - { - ContainerPort: 80, - Protocol: 'tcp', - }, - { - ContainerPort: 90, - Protocol: 'tcp', - }, - ], - DockerLabels: { - label1: 'labelValue1', - label2: 'labelValue2', - }, - }, - ], - Cpu: '256', - ExecutionRoleArn: { - 'Fn::GetAtt': [ - 'ExecutionRole605A040B', - 'Arn', - ], - }, - Family: 'Ec2TaskDef', - Memory: '512', - NetworkMode: 'awsvpc', - RequiresCompatibilities: [ - 'FARGATE', - ], - TaskRoleArn: { - 'Fn::GetAtt': [ - 'TaskRole30FC0FBB', - 'Arn', - ], - }, - })); - - test.done(); - }, - - 'errors if no essential container in pre-defined task definition'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - const taskDefinition = new ecs.FargateTaskDefinition(stack, 'FargateTaskDef'); - - // THEN - test.throws(() => { - new ApplicationMultipleTargetGroupsFargateService(stack, 'Service', { - cluster, - taskDefinition, - }); - }, /At least one essential container must be specified/); - - test.done(); - }, - - 'errors when setting both taskDefinition and taskImageOptions'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - const taskDefinition = new ecs.FargateTaskDefinition(stack, 'Ec2TaskDef'); - - // THEN - test.throws(() => { - new ApplicationMultipleTargetGroupsFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('test'), - }, - taskDefinition, - }); - }, /You must specify only one of TaskDefinition or TaskImageOptions./); - - test.done(); - }, - - 'errors when setting neither taskDefinition nor taskImageOptions'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // THEN - test.throws(() => { - new ApplicationMultipleTargetGroupsFargateService(stack, 'Service', { - cluster, - }); - }, /You must specify one of: taskDefinition or image/); - - test.done(); - }, - - 'test Fargate loadbalancer construct with application load balancer name set'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - new ApplicationLoadBalancedFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('test'), - }, - loadBalancerName: 'alb-test-load-balancer', - }); - - // THEN - stack contains a load balancer and a service - expect(stack).to(haveResource('AWS::ElasticLoadBalancingV2::LoadBalancer', { - Name: 'alb-test-load-balancer', - })); - - expect(stack).to(haveResource('AWS::ECS::Service', { - DesiredCount: 1, - LaunchType: 'FARGATE', - LoadBalancers: [ - { - ContainerName: 'web', - ContainerPort: 80, - TargetGroupArn: { - Ref: 'ServiceLBPublicListenerECSGroup0CC8688C', - }, - }, - ], - })); - - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Image: 'test', - LogConfiguration: { - LogDriver: 'awslogs', - Options: { - 'awslogs-group': { - Ref: 'ServiceTaskDefwebLogGroup2A898F61', - }, - 'awslogs-stream-prefix': 'Service', - 'awslogs-region': { - Ref: 'AWS::Region', - }, - }, - }, - Name: 'web', - PortMappings: [ - { - ContainerPort: 80, - Protocol: 'tcp', - }, - ], - }, - ], - Cpu: '256', - ExecutionRoleArn: { - 'Fn::GetAtt': [ - 'ServiceTaskDefExecutionRole919F7BE3', - 'Arn', - ], - }, - Family: 'ServiceTaskDef79D79521', - Memory: '512', - NetworkMode: 'awsvpc', - RequiresCompatibilities: [ - 'FARGATE', - ], - })); - - test.done(); - }, - }, - - 'When Network Load Balancer': { - 'test Fargate loadbalanced construct with default settings'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - new NetworkMultipleTargetGroupsFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('test'), - }, - }); - - // THEN - stack contains a load balancer and a service - expect(stack).to(haveResource('AWS::ElasticLoadBalancingV2::LoadBalancer')); - - expect(stack).to(haveResource('AWS::ECS::Service', { - DesiredCount: 1, - LaunchType: 'FARGATE', - LoadBalancers: [ - { - ContainerName: 'web', - ContainerPort: 80, - TargetGroupArn: { - Ref: 'ServiceLBPublicListenerECSGroup0CC8688C', - }, - }, - ], - })); - - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Image: 'test', - LogConfiguration: { - LogDriver: 'awslogs', - Options: { - 'awslogs-group': { - Ref: 'ServiceTaskDefwebLogGroup2A898F61', - }, - 'awslogs-stream-prefix': 'Service', - 'awslogs-region': { - Ref: 'AWS::Region', - }, - }, - }, - Name: 'web', - PortMappings: [ - { - ContainerPort: 80, - Protocol: 'tcp', - }, - ], - }, - ], - Cpu: '256', - ExecutionRoleArn: { - 'Fn::GetAtt': [ - 'ServiceTaskDefExecutionRole919F7BE3', - 'Arn', - ], - }, - Family: 'ServiceTaskDef79D79521', - Memory: '512', - NetworkMode: 'awsvpc', - RequiresCompatibilities: [ - 'FARGATE', - ], - })); - - test.done(); - }, - - 'test Fargate loadbalanced construct with all settings'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - new NetworkMultipleTargetGroupsFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('test'), - containerName: 'hello', - containerPorts: [80, 90], - enableLogging: false, - environment: { - TEST_ENVIRONMENT_VARIABLE1: 'test environment variable 1 value', - TEST_ENVIRONMENT_VARIABLE2: 'test environment variable 2 value', - }, - logDriver: new ecs.AwsLogDriver({ - streamPrefix: 'TestStream', - }), - family: 'Ec2TaskDef', - executionRole: new Role(stack, 'ExecutionRole', { - path: '/', - assumedBy: new CompositePrincipal( - new ServicePrincipal('ecs.amazonaws.com'), - new ServicePrincipal('ecs-tasks.amazonaws.com'), - ), - }), - taskRole: new Role(stack, 'TaskRole', { - assumedBy: new ServicePrincipal('ecs-tasks.amazonaws.com'), - }), - dockerLabels: { label1: 'labelValue1', label2: 'labelValue2' }, - }, - cpu: 256, - assignPublicIp: true, - memoryLimitMiB: 512, - desiredCount: 3, - enableECSManagedTags: true, - healthCheckGracePeriod: Duration.millis(2000), - propagateTags: ecs.PropagatedTagSource.SERVICE, - serviceName: 'myService', - targetGroups: [ - { - containerPort: 80, - }, - { - containerPort: 90, - }, - ], - }); - - // THEN - stack contains a load balancer and a service - expect(stack).to(haveResource('AWS::ECS::Service', { - DesiredCount: 3, - EnableECSManagedTags: true, - HealthCheckGracePeriodSeconds: 2, - LaunchType: 'FARGATE', - LoadBalancers: [ - { - ContainerName: 'hello', - ContainerPort: 80, - TargetGroupArn: { - Ref: 'ServiceLBPublicListenerECSTargetGrouphello80Group233A4D54', - }, - }, - { - ContainerName: 'hello', - ContainerPort: 90, - TargetGroupArn: { - Ref: 'ServiceLBPublicListenerECSTargetGrouphello90GroupE58E4EAB', - }, - }, - ], - NetworkConfiguration: { - AwsvpcConfiguration: { - AssignPublicIp: 'ENABLED', - SecurityGroups: [ - { - 'Fn::GetAtt': [ - 'ServiceSecurityGroupEEA09B68', - 'GroupId', - ], - }, - ], - Subnets: [ - { - Ref: 'VPCPublicSubnet1SubnetB4246D30', - }, - { - Ref: 'VPCPublicSubnet2Subnet74179F39', - }, - ], - }, - }, - PropagateTags: 'SERVICE', - ServiceName: 'myService', - })); - - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Environment: [ - { - Name: 'TEST_ENVIRONMENT_VARIABLE1', - Value: 'test environment variable 1 value', - }, - { - Name: 'TEST_ENVIRONMENT_VARIABLE2', - Value: 'test environment variable 2 value', - }, - ], - Essential: true, - Image: 'test', - LogConfiguration: { - LogDriver: 'awslogs', - Options: { - 'awslogs-group': { - Ref: 'ServiceTaskDefhelloLogGroup44519781', - }, - 'awslogs-stream-prefix': 'TestStream', - 'awslogs-region': { - Ref: 'AWS::Region', - }, - }, - }, - Name: 'hello', - PortMappings: [ - { - ContainerPort: 80, - Protocol: 'tcp', - }, - { - ContainerPort: 90, - Protocol: 'tcp', - }, - ], - DockerLabels: { - label1: 'labelValue1', - label2: 'labelValue2', - }, - }, - ], - Cpu: '256', - ExecutionRoleArn: { - 'Fn::GetAtt': [ - 'ExecutionRole605A040B', - 'Arn', - ], - }, - Family: 'Ec2TaskDef', - Memory: '512', - NetworkMode: 'awsvpc', - RequiresCompatibilities: [ - 'FARGATE', - ], - TaskRoleArn: { - 'Fn::GetAtt': [ - 'TaskRole30FC0FBB', - 'Arn', - ], - }, - })); - - test.done(); - }, - - 'errors if no essential container in pre-defined task definition'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - const taskDefinition = new ecs.FargateTaskDefinition(stack, 'FargateTaskDef'); - - // THEN - test.throws(() => { - new NetworkMultipleTargetGroupsFargateService(stack, 'Service', { - cluster, - taskDefinition, - }); - }, /At least one essential container must be specified/); - - test.done(); - }, - - 'errors when setting both taskDefinition and taskImageOptions'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - const taskDefinition = new ecs.FargateTaskDefinition(stack, 'Ec2TaskDef'); - - // THEN - test.throws(() => { - new NetworkMultipleTargetGroupsFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('test'), - }, - taskDefinition, - }); - }, /You must specify only one of TaskDefinition or TaskImageOptions./); - - test.done(); - }, - - 'errors when setting neither taskDefinition nor taskImageOptions'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // THEN - test.throws(() => { - new NetworkMultipleTargetGroupsFargateService(stack, 'Service', { - cluster, - }); - }, /You must specify one of: taskDefinition or image/); - - test.done(); - }, - }, -}; diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.load-balanced-fargate-service.ts b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.load-balanced-fargate-service.ts deleted file mode 100644 index b0f8d0d573d7f..0000000000000 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.load-balanced-fargate-service.ts +++ /dev/null @@ -1,1076 +0,0 @@ -import { expect, haveResource, haveResourceLike, SynthUtils } from '@aws-cdk/assert-internal'; -import { DnsValidatedCertificate } from '@aws-cdk/aws-certificatemanager'; -import * as ec2 from '@aws-cdk/aws-ec2'; -import * as ecs from '@aws-cdk/aws-ecs'; -import { ApplicationLoadBalancer, ApplicationProtocol, NetworkLoadBalancer } from '@aws-cdk/aws-elasticloadbalancingv2'; -import * as iam from '@aws-cdk/aws-iam'; -import * as route53 from '@aws-cdk/aws-route53'; -import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; -import * as ecsPatterns from '../../lib'; - -export = { - 'setting loadBalancerType to Network creates an NLB Public'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::ElasticLoadBalancingV2::LoadBalancer', { - Type: 'network', - Scheme: 'internet-facing', - })); - - test.done(); - }, - - 'setting loadBalancerType to Network and publicLoadBalancer to false creates an NLB Private'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), - }, - publicLoadBalancer: false, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::ElasticLoadBalancingV2::LoadBalancer', { - Type: 'network', - Scheme: 'internal', - })); - - test.done(); - }, - - 'setting vpc and cluster throws error'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - test.throws(() => new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'Service', { - cluster, - vpc, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), - }, - })); - - test.done(); - }, - - 'setting executionRole updated taskDefinition with given execution role'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - const executionRole = new iam.Role(stack, 'ExecutionRole', { - path: '/', - assumedBy: new iam.CompositePrincipal( - new iam.ServicePrincipal('ecs.amazonaws.com'), - new iam.ServicePrincipal('ecs-tasks.amazonaws.com'), - ), - }); - - // WHEN - new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), - executionRole, - }, - }); - - // THEN - const serviceTaskDefinition = SynthUtils.synthesize(stack).template.Resources.ServiceTaskDef1922A00F; - test.deepEqual(serviceTaskDefinition.Properties.ExecutionRoleArn, { 'Fn::GetAtt': ['ExecutionRole605A040B', 'Arn'] }); - test.done(); - }, - - 'setting taskRole updated taskDefinition with given task role'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - const taskRole = new iam.Role(stack, 'taskRoleTest', { - path: '/', - assumedBy: new iam.CompositePrincipal( - new iam.ServicePrincipal('ecs.amazonaws.com'), - new iam.ServicePrincipal('ecs-tasks.amazonaws.com'), - ), - }); - - // WHEN - new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), - taskRole, - }, - }); - - // THEN - const serviceTaskDefinition = SynthUtils.synthesize(stack).template.Resources.ServiceTaskDef1922A00F; - test.deepEqual(serviceTaskDefinition.Properties.TaskRoleArn, { 'Fn::GetAtt': ['taskRoleTest9DA66B6E', 'Arn'] }); - test.done(); - }, - - 'setting containerName updates container name with given name'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), - containerName: 'bob', - }, - }); - - // THEN - const serviceTaskDefinition = SynthUtils.synthesize(stack).template.Resources.ServiceTaskDef1922A00F; - test.deepEqual(serviceTaskDefinition.Properties.ContainerDefinitions[0].Name, 'bob'); - test.done(); - }, - - 'not setting containerName updates container name with default'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), - }, - }); - - // THEN - const serviceTaskDefinition = SynthUtils.synthesize(stack).template.Resources.ServiceTaskDef1922A00F; - test.deepEqual(serviceTaskDefinition.Properties.ContainerDefinitions[0].Name, 'web'); - test.done(); - }, - - 'setting servicename updates service name with given name'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), - }, - serviceName: 'bob', - }); - // THEN - const serviceTaskDefinition = SynthUtils.synthesize(stack).template.Resources.Service9571FDD8; - test.deepEqual(serviceTaskDefinition.Properties.ServiceName, 'bob'); - test.done(); - }, - - 'not setting servicename updates service name with default'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), - }, - }); - - // THEN - const serviceTaskDefinition = SynthUtils.synthesize(stack).template.Resources.Service9571FDD8; - test.equal(serviceTaskDefinition.Properties.ServiceName, undefined); - test.done(); - }, - - 'setting healthCheckGracePeriod works'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), - }, - healthCheckGracePeriod: cdk.Duration.seconds(600), - }); - // THEN - const serviceTaskDefinition = SynthUtils.synthesize(stack).template.Resources.Service9571FDD8; - test.deepEqual(serviceTaskDefinition.Properties.HealthCheckGracePeriodSeconds, 600); - test.done(); - }, - - 'selecting correct vpcSubnets'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'Vpc', { - maxAzs: 2, - subnetConfiguration: [ - { - subnetType: ec2.SubnetType.PUBLIC, - cidrMask: 20, - name: 'Public', - }, - { - subnetType: ec2.SubnetType.ISOLATED, - cidrMask: 20, - name: 'ISOLATED', - }, - ], - }); - // WHEN - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { - vpc, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), - }, - taskSubnets: { - subnetType: ec2.SubnetType.ISOLATED, - }, - }); - // THEN - expect(stack).to(haveResourceLike('AWS::ECS::Service', { - NetworkConfiguration: { - AwsvpcConfiguration: { - Subnets: [ - { - Ref: 'VpcISOLATEDSubnet1Subnet80F07FA0', - }, - { - Ref: 'VpcISOLATEDSubnet2SubnetB0B548C3', - }, - ], - }, - }, - })); - test.done(); - }, - - 'target group uses HTTP/80 as default'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), - }, - }); - // THEN - expect(stack).to(haveResourceLike('AWS::ElasticLoadBalancingV2::TargetGroup', { - Port: 80, - Protocol: 'HTTP', - })); - test.done(); - }, - - 'target group uses HTTPS/443 when configured'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), - }, - targetProtocol: ApplicationProtocol.HTTPS, - }); - // THEN - expect(stack).to(haveResourceLike('AWS::ElasticLoadBalancingV2::TargetGroup', { - Port: 443, - Protocol: 'HTTPS', - })); - test.done(); - }, - - 'setting platform version'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), - }, - platformVersion: ecs.FargatePlatformVersion.VERSION1_4, - }); - // THEN - expect(stack).to(haveResource('AWS::ECS::Service', { - PlatformVersion: ecs.FargatePlatformVersion.VERSION1_4, - })); - test.done(); - }, - - 'test load balanced service with family defined'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), - enableLogging: false, - environment: { - TEST_ENVIRONMENT_VARIABLE1: 'test environment variable 1 value', - TEST_ENVIRONMENT_VARIABLE2: 'test environment variable 2 value', - }, - family: 'fargate-task-family', - }, - desiredCount: 2, - memoryLimitMiB: 512, - serviceName: 'fargate-test-service', - }); - - // THEN - expect(stack).to(haveResource('AWS::ECS::Service', { - DesiredCount: 2, - LaunchType: 'FARGATE', - ServiceName: 'fargate-test-service', - })); - - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Environment: [ - { - Name: 'TEST_ENVIRONMENT_VARIABLE1', - Value: 'test environment variable 1 value', - }, - { - Name: 'TEST_ENVIRONMENT_VARIABLE2', - Value: 'test environment variable 2 value', - }, - ], - Image: '/aws/aws-example-app', - }, - ], - Family: 'fargate-task-family', - })); - - test.done(); - }, - - 'setting ALB deployment controller'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), - }, - deploymentController: { - type: ecs.DeploymentControllerType.CODE_DEPLOY, - }, - }); - // THEN - expect(stack).to(haveResource('AWS::ECS::Service', { - DeploymentController: { - Type: 'CODE_DEPLOY', - }, - })); - test.done(); - }, - - 'setting NLB deployment controller'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'Service', { - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), - }, - deploymentController: { - type: ecs.DeploymentControllerType.CODE_DEPLOY, - }, - }); - // THEN - expect(stack).to(haveResource('AWS::ECS::Service', { - DeploymentController: { - Type: 'CODE_DEPLOY', - }, - })); - test.done(); - }, - - 'setting ALB circuitBreaker works'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), - }, - circuitBreaker: { rollback: true }, - }); - // THEN - expect(stack).to(haveResourceLike('AWS::ECS::Service', { - DeploymentConfiguration: { - DeploymentCircuitBreaker: { - Enable: true, - Rollback: true, - }, - }, - DeploymentController: { - Type: 'ECS', - }, - })); - test.done(); - }, - - 'setting NLB circuitBreaker works'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'Service', { - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), - }, - circuitBreaker: { rollback: true }, - }); - // THEN - expect(stack).to(haveResourceLike('AWS::ECS::Service', { - DeploymentConfiguration: { - DeploymentCircuitBreaker: { - Enable: true, - Rollback: true, - }, - }, - DeploymentController: { - Type: 'ECS', - }, - })); - test.done(); - }, - - 'setting NLB special listener port to create the listener'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'FargateNlbService', { - cluster, - listenerPort: 2015, - taskImageOptions: { - containerPort: 2015, - image: ecs.ContainerImage.fromRegistry('abiosoft/caddy'), - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::ElasticLoadBalancingV2::Listener', { - DefaultActions: [ - { - Type: 'forward', - }, - ], - Port: 2015, - Protocol: 'TCP', - })); - - test.done(); - }, - - 'setting ALB special listener port to create the listener'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'FargateAlbService', { - cluster, - listenerPort: 2015, - taskImageOptions: { - containerPort: 2015, - image: ecs.ContainerImage.fromRegistry('abiosoft/caddy'), - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::ElasticLoadBalancingV2::Listener', { - DefaultActions: [ - { - Type: 'forward', - }, - ], - Port: 2015, - Protocol: 'HTTP', - })); - - test.done(); - }, - - 'setting ALB HTTPS protocol to create the listener on 443'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'FargateAlbService', { - cluster, - protocol: ApplicationProtocol.HTTPS, - domainName: 'domain.com', - domainZone: route53.HostedZone.fromHostedZoneAttributes(stack, 'HostedZone', { - hostedZoneId: 'fakeId', - zoneName: 'domain.com', - }), - taskImageOptions: { - containerPort: 2015, - image: ecs.ContainerImage.fromRegistry('abiosoft/caddy'), - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::ElasticLoadBalancingV2::Listener', { - DefaultActions: [ - { - Type: 'forward', - }, - ], - Port: 443, - Protocol: 'HTTPS', - })); - - test.done(); - }, - - 'setting ALB HTTPS correctly sets the recordset name'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'FargateAlbService', { - cluster, - protocol: ApplicationProtocol.HTTPS, - domainName: 'test.domain.com', - domainZone: route53.HostedZone.fromHostedZoneAttributes(stack, 'HostedZone', { - hostedZoneId: 'fakeId', - zoneName: 'domain.com.', - }), - taskImageOptions: { - containerPort: 2015, - image: ecs.ContainerImage.fromRegistry('abiosoft/caddy'), - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::Route53::RecordSet', { - Name: 'test.domain.com.', - })); - - test.done(); - }, - - 'setting ALB cname option correctly sets the recordset type'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'FargateAlbService', { - cluster, - protocol: ApplicationProtocol.HTTPS, - domainName: 'test.domain.com', - domainZone: route53.HostedZone.fromHostedZoneAttributes(stack, 'HostedZone', { - hostedZoneId: 'fakeId', - zoneName: 'domain.com.', - }), - recordType: ecsPatterns.ApplicationLoadBalancedServiceRecordType.CNAME, - taskImageOptions: { - containerPort: 2015, - image: ecs.ContainerImage.fromRegistry('abiosoft/caddy'), - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::Route53::RecordSet', { - Name: 'test.domain.com.', - Type: 'CNAME', - })); - - test.done(); - }, - - 'setting ALB record type to NONE correctly omits the recordset'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'FargateAlbService', { - cluster, - protocol: ApplicationProtocol.HTTPS, - domainName: 'test.domain.com', - domainZone: route53.HostedZone.fromHostedZoneAttributes(stack, 'HostedZone', { - hostedZoneId: 'fakeId', - zoneName: 'domain.com.', - }), - recordType: ecsPatterns.ApplicationLoadBalancedServiceRecordType.NONE, - taskImageOptions: { - containerPort: 2015, - image: ecs.ContainerImage.fromRegistry('abiosoft/caddy'), - }, - }); - - // THEN - expect(stack).notTo(haveResource('AWS::Route53::RecordSet')); - - test.done(); - }, - - - 'setting NLB cname option correctly sets the recordset type'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'FargateNlbService', { - cluster, - domainName: 'test.domain.com', - domainZone: route53.HostedZone.fromHostedZoneAttributes(stack, 'HostedZone', { - hostedZoneId: 'fakeId', - zoneName: 'domain.com.', - }), - recordType: ecsPatterns.NetworkLoadBalancedServiceRecordType.CNAME, - taskImageOptions: { - containerPort: 2015, - image: ecs.ContainerImage.fromRegistry('abiosoft/caddy'), - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::Route53::RecordSet', { - Name: 'test.domain.com.', - Type: 'CNAME', - })); - - test.done(); - }, - - 'setting NLB record type to NONE correctly omits the recordset'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'FargateNlbService', { - cluster, - domainName: 'test.domain.com', - domainZone: route53.HostedZone.fromHostedZoneAttributes(stack, 'HostedZone', { - hostedZoneId: 'fakeId', - zoneName: 'domain.com.', - }), - recordType: ecsPatterns.NetworkLoadBalancedServiceRecordType.NONE, - taskImageOptions: { - containerPort: 2015, - image: ecs.ContainerImage.fromRegistry('abiosoft/caddy'), - }, - }); - - // THEN - expect(stack).notTo(haveResource('AWS::Route53::RecordSet')); - - test.done(); - }, - - 'setting ALB HTTP protocol to create the listener on 80'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'FargateAlbService', { - cluster, - protocol: ApplicationProtocol.HTTP, - taskImageOptions: { - containerPort: 2015, - image: ecs.ContainerImage.fromRegistry('abiosoft/caddy'), - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::ElasticLoadBalancingV2::Listener', { - DefaultActions: [ - { - Type: 'forward', - }, - ], - Port: 80, - Protocol: 'HTTP', - })); - - test.done(); - }, - - 'setting ALB without any protocol or listenerPort to create the listener on 80'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'FargateAlbService', { - cluster, - taskImageOptions: { - containerPort: 2015, - image: ecs.ContainerImage.fromRegistry('abiosoft/caddy'), - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::ElasticLoadBalancingV2::Listener', { - DefaultActions: [ - { - Type: 'forward', - }, - ], - Port: 80, - Protocol: 'HTTP', - })); - - test.done(); - }, - - 'passing in existing network load balancer to NLB Fargate Service'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const nlb = new NetworkLoadBalancer(stack, 'NLB', { vpc }); - - // WHEN - new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'Service', { - vpc, - loadBalancer: nlb, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::ECS::Service', { - LaunchType: 'FARGATE', - })); - expect(stack).to(haveResourceLike('AWS::ElasticLoadBalancingV2::LoadBalancer', { - Type: 'network', - })); - test.done(); - }, - - 'passing in imported network load balancer and resources to NLB Fargate service'(test: Test) { - // GIVEN - const app = new cdk.App(); - const stack1 = new cdk.Stack(app, 'MyStack'); - const vpc1 = new ec2.Vpc(stack1, 'VPC'); - const cluster1 = new ecs.Cluster(stack1, 'Cluster', { vpc: vpc1 }); - const nlbArn = 'arn:aws:elasticloadbalancing:us-west-2:123456789012:loadbalancer/app/my-load-balancer/50dc6c495c0c9188'; - const stack2 = new cdk.Stack(stack1, 'Stack2'); - const cluster2 = ecs.Cluster.fromClusterAttributes(stack2, 'ImportedCluster', { - vpc: vpc1, - securityGroups: cluster1.connections.securityGroups, - clusterName: 'cluster-name', - }); - - // WHEN - const nlb2 = NetworkLoadBalancer.fromNetworkLoadBalancerAttributes(stack2, 'ImportedNLB', { - loadBalancerArn: nlbArn, - vpc: vpc1, - }); - const taskDef = new ecs.FargateTaskDefinition(stack2, 'TaskDef', { - cpu: 1024, - memoryLimitMiB: 1024, - }); - const container = taskDef.addContainer('myContainer', { - image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), - memoryLimitMiB: 1024, - }); - container.addPortMappings({ - containerPort: 80, - }); - - new ecsPatterns.NetworkLoadBalancedFargateService(stack2, 'FargateNLBService', { - cluster: cluster2, - loadBalancer: nlb2, - desiredCount: 1, - taskDefinition: taskDef, - }); - - // THEN - expect(stack2).to(haveResourceLike('AWS::ECS::Service', { - LaunchType: 'FARGATE', - LoadBalancers: [{ ContainerName: 'myContainer', ContainerPort: 80 }], - })); - expect(stack2).to(haveResourceLike('AWS::ElasticLoadBalancingV2::TargetGroup')); - expect(stack2).to(haveResourceLike('AWS::ElasticLoadBalancingV2::Listener', { - LoadBalancerArn: nlb2.loadBalancerArn, - Port: 80, - })); - - test.done(); - }, - - 'passing in previously created application load balancer to ALB Fargate Service'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'Vpc'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc, clusterName: 'MyCluster' }); - const sg = new ec2.SecurityGroup(stack, 'SecurityGroup', { vpc }); - cluster.connections.addSecurityGroup(sg); - const alb = new ApplicationLoadBalancer(stack, 'ALB', { vpc, securityGroup: sg }); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { - cluster, - loadBalancer: alb, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::ECS::Service', { - LaunchType: 'FARGATE', - })); - expect(stack).to(haveResourceLike('AWS::ElasticLoadBalancingV2::LoadBalancer', { - Type: 'application', - })); - test.done(); - }, - - 'passing in imported application load balancer and resources to ALB Fargate Service'(test: Test) { - // GIVEN - const stack1 = new cdk.Stack(); - const albArn = 'arn:aws:elasticloadbalancing:us-west-2:123456789012:loadbalancer/app/my-load-balancer/50dc6c495c0c9188'; - const vpc = new ec2.Vpc(stack1, 'Vpc'); - const cluster = new ecs.Cluster(stack1, 'Cluster', { vpc, clusterName: 'MyClusterName' }); - const sg = new ec2.SecurityGroup(stack1, 'SecurityGroup', { vpc }); - cluster.connections.addSecurityGroup(sg); - const alb = ApplicationLoadBalancer.fromApplicationLoadBalancerAttributes(stack1, 'ALB', { - loadBalancerArn: albArn, - vpc, - securityGroupId: sg.securityGroupId, - loadBalancerDnsName: 'MyDnsName', - }); - - // WHEN - const taskDef = new ecs.FargateTaskDefinition(stack1, 'TaskDef', { - cpu: 1024, - memoryLimitMiB: 1024, - }); - const container = taskDef.addContainer('Container', { - image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), - memoryLimitMiB: 1024, - }); - container.addPortMappings({ - containerPort: 80, - }); - - new ecsPatterns.ApplicationLoadBalancedFargateService(stack1, 'FargateALBService', { - cluster, - loadBalancer: alb, - desiredCount: 1, - taskDefinition: taskDef, - }); - - // THEN - expect(stack1).to(haveResourceLike('AWS::ECS::Service', { - LaunchType: 'FARGATE', - LoadBalancers: [{ ContainerName: 'Container', ContainerPort: 80 }], - })); - expect(stack1).to(haveResourceLike('AWS::ElasticLoadBalancingV2::TargetGroup')); - expect(stack1).to(haveResourceLike('AWS::ElasticLoadBalancingV2::Listener', { - LoadBalancerArn: alb.loadBalancerArn, - Port: 80, - })); - - test.done(); - }, - - 'passing in previously created security groups to ALB Fargate Service'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'Vpc'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc, clusterName: 'MyCluster' }); - const securityGroup = new ec2.SecurityGroup(stack, 'SecurityGroup', { - allowAllOutbound: false, - description: 'Example', - securityGroupName: 'Rolly', - vpc, - }); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), - }, - securityGroups: [securityGroup], - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::ECS::Service', { - LaunchType: 'FARGATE', - })); - expect(stack).to(haveResource('AWS::EC2::SecurityGroup', { - GroupDescription: 'Example', - GroupName: 'Rolly', - SecurityGroupEgress: [ - { - CidrIp: '255.255.255.255/32', - Description: 'Disallow all traffic', - FromPort: 252, - IpProtocol: 'icmp', - ToPort: 86, - }, - ], - VpcId: { - Ref: 'Vpc8378EB38', - }, - })); - test.done(); - }, - - 'domainName and domainZone not required for HTTPS listener with provided cert'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - const exampleDotComZone = new route53.PublicHostedZone(stack, 'ExampleDotCom', { - zoneName: 'example.com', - }); - const certificate = new DnsValidatedCertificate(stack, 'Certificate', { - domainName: 'test.example.com', - hostedZone: exampleDotComZone, - }); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'FargateAlbService', { - cluster, - protocol: ApplicationProtocol.HTTPS, - - taskImageOptions: { - containerPort: 2015, - image: ecs.ContainerImage.fromRegistry('abiosoft/caddy'), - }, - certificate: certificate, - }); - - // THEN - expect(stack).notTo(haveResourceLike('AWS::Route53::RecordSet', { - Name: 'test.domain.com.', - })); - - test.done(); - - }, - - 'test ALB load balanced service with docker labels defined'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), - dockerLabels: { label1: 'labelValue1', label2: 'labelValue2' }, - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Image: '/aws/aws-example-app', - DockerLabels: { - label1: 'labelValue1', - label2: 'labelValue2', - }, - }, - ], - })); - - test.done(); - }, - - 'test Network load balanced service with docker labels defined'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), - dockerLabels: { label1: 'labelValue1', label2: 'labelValue2' }, - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Image: '/aws/aws-example-app', - DockerLabels: { - label1: 'labelValue1', - label2: 'labelValue2', - }, - }, - ], - })); - - test.done(); - }, -}; diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.queue-processing-fargate-service.ts b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.queue-processing-fargate-service.ts deleted file mode 100644 index 6b5a05ccaaf7b..0000000000000 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.queue-processing-fargate-service.ts +++ /dev/null @@ -1,577 +0,0 @@ -import { ABSENT, expect, haveResource, haveResourceLike } from '@aws-cdk/assert-internal'; -import * as ec2 from '@aws-cdk/aws-ec2'; -import * as ecs from '@aws-cdk/aws-ecs'; -import * as sqs from '@aws-cdk/aws-sqs'; -import * as cdk from '@aws-cdk/core'; -import * as cxapi from '@aws-cdk/cx-api'; -import { Test } from 'nodeunit'; -import * as ecsPatterns from '../../lib'; - -export = { - 'test fargate queue worker service construct - with only required props'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); - - // WHEN - new ecsPatterns.QueueProcessingFargateService(stack, 'Service', { - cluster, - memoryLimitMiB: 512, - image: ecs.ContainerImage.fromRegistry('test'), - }); - - // THEN - QueueWorker is of FARGATE launch type, an SQS queue is created and all default properties are set. - expect(stack).to(haveResource('AWS::ECS::Service', { - DesiredCount: 1, - LaunchType: 'FARGATE', - })); - - expect(stack).to(haveResource('AWS::SQS::Queue', { - RedrivePolicy: { - deadLetterTargetArn: { - 'Fn::GetAtt': [ - 'ServiceEcsProcessingDeadLetterQueue4A89196E', - 'Arn', - ], - }, - maxReceiveCount: 3, - }, - })); - - expect(stack).to(haveResource('AWS::SQS::Queue', { - MessageRetentionPeriod: 1209600, - })); - - expect(stack).to(haveResource('AWS::IAM::Policy', { - PolicyDocument: { - Statement: [ - { - Action: [ - 'sqs:ReceiveMessage', - 'sqs:ChangeMessageVisibility', - 'sqs:GetQueueUrl', - 'sqs:DeleteMessage', - 'sqs:GetQueueAttributes', - ], - Effect: 'Allow', - Resource: { - 'Fn::GetAtt': [ - 'ServiceEcsProcessingQueueC266885C', - 'Arn', - ], - }, - }, - ], - Version: '2012-10-17', - }, - })); - - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Environment: [ - { - Name: 'QUEUE_NAME', - Value: { - 'Fn::GetAtt': [ - 'ServiceEcsProcessingQueueC266885C', - 'QueueName', - ], - }, - }, - ], - LogConfiguration: { - LogDriver: 'awslogs', - Options: { - 'awslogs-group': { - Ref: 'ServiceQueueProcessingTaskDefQueueProcessingContainerLogGroupD52338D1', - }, - 'awslogs-stream-prefix': 'Service', - 'awslogs-region': { - Ref: 'AWS::Region', - }, - }, - }, - Image: 'test', - }, - ], - Family: 'ServiceQueueProcessingTaskDef83DB34F1', - })); - - test.done(); - }, - - 'test fargate queue worker service construct - with remove default desiredCount feature flag'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - stack.node.setContext(cxapi.ECS_REMOVE_DEFAULT_DESIRED_COUNT, true); - - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - new ecsPatterns.QueueProcessingFargateService(stack, 'Service', { - cluster, - memoryLimitMiB: 512, - image: ecs.ContainerImage.fromRegistry('test'), - }); - - // THEN - QueueWorker is of FARGATE launch type, and desiredCount is not defined on the FargateService. - expect(stack).to(haveResource('AWS::ECS::Service', { - DesiredCount: ABSENT, - LaunchType: 'FARGATE', - })); - - test.done(); - }, - - 'test fargate queue worker service construct - with optional props for queues'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); - - // WHEN - new ecsPatterns.QueueProcessingFargateService(stack, 'Service', { - cluster, - memoryLimitMiB: 512, - image: ecs.ContainerImage.fromRegistry('test'), - maxReceiveCount: 42, - retentionPeriod: cdk.Duration.days(7), - visibilityTimeout: cdk.Duration.minutes(5), - }); - - // THEN - QueueWorker is of FARGATE launch type, an SQS queue is created and all default properties are set. - expect(stack).to(haveResource('AWS::ECS::Service', { - DesiredCount: 1, - LaunchType: 'FARGATE', - })); - - expect(stack).to(haveResource('AWS::SQS::Queue', { - RedrivePolicy: { - deadLetterTargetArn: { - 'Fn::GetAtt': [ - 'ServiceEcsProcessingDeadLetterQueue4A89196E', - 'Arn', - ], - }, - maxReceiveCount: 42, - }, - VisibilityTimeout: 300, - })); - - expect(stack).to(haveResource('AWS::SQS::Queue', { - MessageRetentionPeriod: 604800, - })); - - expect(stack).to(haveResource('AWS::IAM::Policy', { - PolicyDocument: { - Statement: [ - { - Action: [ - 'sqs:ReceiveMessage', - 'sqs:ChangeMessageVisibility', - 'sqs:GetQueueUrl', - 'sqs:DeleteMessage', - 'sqs:GetQueueAttributes', - ], - Effect: 'Allow', - Resource: { - 'Fn::GetAtt': [ - 'ServiceEcsProcessingQueueC266885C', - 'Arn', - ], - }, - }, - ], - Version: '2012-10-17', - }, - })); - - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Environment: [ - { - Name: 'QUEUE_NAME', - Value: { - 'Fn::GetAtt': [ - 'ServiceEcsProcessingQueueC266885C', - 'QueueName', - ], - }, - }, - ], - LogConfiguration: { - LogDriver: 'awslogs', - Options: { - 'awslogs-group': { - Ref: 'ServiceQueueProcessingTaskDefQueueProcessingContainerLogGroupD52338D1', - }, - 'awslogs-stream-prefix': 'Service', - 'awslogs-region': { - Ref: 'AWS::Region', - }, - }, - }, - Image: 'test', - }, - ], - Family: 'ServiceQueueProcessingTaskDef83DB34F1', - })); - - test.done(); - }, - - 'test Fargate queue worker service construct - without desiredCount specified'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); - const queue = new sqs.Queue(stack, 'fargate-test-queue', { - queueName: 'fargate-test-sqs-queue', - }); - - // WHEN - new ecsPatterns.QueueProcessingFargateService(stack, 'Service', { - cluster, - memoryLimitMiB: 512, - image: ecs.ContainerImage.fromRegistry('test'), - command: ['-c', '4', 'amazon.com'], - enableLogging: false, - environment: { - TEST_ENVIRONMENT_VARIABLE1: 'test environment variable 1 value', - TEST_ENVIRONMENT_VARIABLE2: 'test environment variable 2 value', - }, - queue, - maxScalingCapacity: 5, - minScalingCapacity: 2, - minHealthyPercent: 60, - maxHealthyPercent: 150, - serviceName: 'fargate-test-service', - family: 'fargate-task-family', - platformVersion: ecs.FargatePlatformVersion.VERSION1_4, - deploymentController: { - type: ecs.DeploymentControllerType.CODE_DEPLOY, - }, - }); - - // THEN - QueueWorker is of FARGATE launch type, an SQS queue is created and all optional properties are set. - expect(stack).to(haveResource('AWS::ECS::Service', { - DeploymentConfiguration: { - MinimumHealthyPercent: 60, - MaximumPercent: 150, - }, - LaunchType: 'FARGATE', - ServiceName: 'fargate-test-service', - PlatformVersion: ecs.FargatePlatformVersion.VERSION1_4, - DeploymentController: { - Type: 'CODE_DEPLOY', - }, - })); - - expect(stack).to(haveResource('AWS::ApplicationAutoScaling::ScalableTarget', { - MaxCapacity: 5, - MinCapacity: 2, - })); - - expect(stack).to(haveResource('AWS::SQS::Queue', { QueueName: 'fargate-test-sqs-queue' })); - - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Command: [ - '-c', - '4', - 'amazon.com', - ], - Environment: [ - { - Name: 'TEST_ENVIRONMENT_VARIABLE1', - Value: 'test environment variable 1 value', - }, - { - Name: 'TEST_ENVIRONMENT_VARIABLE2', - Value: 'test environment variable 2 value', - }, - { - Name: 'QUEUE_NAME', - Value: { - 'Fn::GetAtt': [ - 'fargatetestqueue28B43841', - 'QueueName', - ], - }, - }, - ], - Image: 'test', - }, - ], - Family: 'fargate-task-family', - })); - - test.done(); - }, - - 'test Fargate queue worker service construct - with optional props'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); - const queue = new sqs.Queue(stack, 'fargate-test-queue', { - queueName: 'fargate-test-sqs-queue', - }); - - // WHEN - new ecsPatterns.QueueProcessingFargateService(stack, 'Service', { - cluster, - memoryLimitMiB: 512, - image: ecs.ContainerImage.fromRegistry('test'), - command: ['-c', '4', 'amazon.com'], - enableLogging: false, - desiredTaskCount: 2, - environment: { - TEST_ENVIRONMENT_VARIABLE1: 'test environment variable 1 value', - TEST_ENVIRONMENT_VARIABLE2: 'test environment variable 2 value', - }, - queue, - maxScalingCapacity: 5, - minHealthyPercent: 60, - maxHealthyPercent: 150, - serviceName: 'fargate-test-service', - family: 'fargate-task-family', - platformVersion: ecs.FargatePlatformVersion.VERSION1_4, - circuitBreaker: { rollback: true }, - }); - - // THEN - QueueWorker is of FARGATE launch type, an SQS queue is created and all optional properties are set. - expect(stack).to(haveResource('AWS::ECS::Service', { - DesiredCount: 2, - DeploymentConfiguration: { - MinimumHealthyPercent: 60, - MaximumPercent: 150, - DeploymentCircuitBreaker: { - Enable: true, - Rollback: true, - }, - }, - LaunchType: 'FARGATE', - ServiceName: 'fargate-test-service', - PlatformVersion: ecs.FargatePlatformVersion.VERSION1_4, - DeploymentController: { - Type: 'ECS', - }, - })); - - expect(stack).to(haveResource('AWS::SQS::Queue', { QueueName: 'fargate-test-sqs-queue' })); - - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Command: [ - '-c', - '4', - 'amazon.com', - ], - Environment: [ - { - Name: 'TEST_ENVIRONMENT_VARIABLE1', - Value: 'test environment variable 1 value', - }, - { - Name: 'TEST_ENVIRONMENT_VARIABLE2', - Value: 'test environment variable 2 value', - }, - { - Name: 'QUEUE_NAME', - Value: { - 'Fn::GetAtt': [ - 'fargatetestqueue28B43841', - 'QueueName', - ], - }, - }, - ], - Image: 'test', - }, - ], - Family: 'fargate-task-family', - })); - - test.done(); - }, - - 'can set custom containerName'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); - - // WHEN - new ecsPatterns.QueueProcessingFargateService(stack, 'Service', { - cluster, - containerName: 'my-container', - image: ecs.ContainerImage.fromRegistry('test'), - }); - - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Name: 'my-container', - }, - ], - })); - - test.done(); - }, - - 'can set custom networking options'(test: Test) { - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC', { - subnetConfiguration: [ - { - cidrMask: 24, - name: 'Public', - subnetType: ec2.SubnetType.PUBLIC, - }, - { - cidrMask: 24, - name: 'Isolated', - subnetType: ec2.SubnetType.ISOLATED, - }, - ], - }); - const securityGroup = new ec2.SecurityGroup(stack, 'MyCustomSG', { - vpc, - }); - - // WHEN - SecurityGroups and taskSubnets selection is defined - new ecsPatterns.QueueProcessingFargateService(stack, 'Service', { - vpc, - memoryLimitMiB: 512, - image: ecs.ContainerImage.fromRegistry('test'), - securityGroups: [securityGroup], - taskSubnets: { subnetType: ec2.SubnetType.ISOLATED }, - }); - - // THEN - NetworkConfiguration is created with the specific security groups and selected subnets - expect(stack).to(haveResource('AWS::ECS::Service', { - LaunchType: 'FARGATE', - NetworkConfiguration: { - AwsvpcConfiguration: { - AssignPublicIp: 'DISABLED', - SecurityGroups: [ - { - 'Fn::GetAtt': [ - 'MyCustomSGDE27C661', - 'GroupId', - ], - }, - ], - Subnets: [ - { - Ref: 'VPCIsolatedSubnet1SubnetEBD00FC6', - }, - { - Ref: 'VPCIsolatedSubnet2Subnet4B1C8CAA', - }, - ], - }, - }, - })); - - test.done(); - }, - - 'can set use public IP'(test: Test) { - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - - // WHEN - Assign Public IP is set to True - new ecsPatterns.QueueProcessingFargateService(stack, 'Service', { - vpc, - memoryLimitMiB: 512, - image: ecs.ContainerImage.fromRegistry('test'), - assignPublicIp: true, - }); - - // THEN - The Subnets defaults to Public and AssignPublicIp settings change to ENABLED - expect(stack).to(haveResource('AWS::ECS::Service', { - LaunchType: 'FARGATE', - NetworkConfiguration: { - AwsvpcConfiguration: { - AssignPublicIp: 'ENABLED', - SecurityGroups: [ - { - 'Fn::GetAtt': [ - 'ServiceQueueProcessingFargateServiceSecurityGroup6E981512', - 'GroupId', - ], - }, - ], - Subnets: [ - { - Ref: 'VPCPublicSubnet1SubnetB4246D30', - }, - { - Ref: 'VPCPublicSubnet2Subnet74179F39', - }, - ], - }, - }, - })); - - test.done(); - }, - - 'can set capacity provider strategies'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'MyVpc', {}); - const cluster = new ecs.Cluster(stack, 'EcsCluster', { - vpc, - }); - cluster.enableFargateCapacityProviders(); - - // WHEN - new ecsPatterns.QueueProcessingFargateService(stack, 'Service', { - cluster, - image: ecs.ContainerImage.fromRegistry('test'), - capacityProviderStrategies: [ - { - capacityProvider: 'FARGATE_SPOT', - weight: 2, - }, - { - capacityProvider: 'FARGATE', - weight: 1, - }, - ], - }); - - // THEN - expect(stack).to( - haveResource('AWS::ECS::Service', { - LaunchType: ABSENT, - CapacityProviderStrategy: [ - { - CapacityProvider: 'FARGATE_SPOT', - Weight: 2, - }, - { - CapacityProvider: 'FARGATE', - Weight: 1, - }, - ], - }), - ); - - test.done(); - }, -}; diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.scheduled-fargate-task.ts b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.scheduled-fargate-task.ts deleted file mode 100644 index 497e885460f26..0000000000000 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.scheduled-fargate-task.ts +++ /dev/null @@ -1,430 +0,0 @@ -import { expect, haveResource, haveResourceLike } from '@aws-cdk/assert-internal'; -import * as ec2 from '@aws-cdk/aws-ec2'; -import * as ecs from '@aws-cdk/aws-ecs'; -import * as events from '@aws-cdk/aws-events'; -import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; -import { ScheduledFargateTask } from '../../lib'; - -export = { - 'Can create a scheduled Fargate Task - with only required props'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 1 }); - const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); - - new ScheduledFargateTask(stack, 'ScheduledFargateTask', { - cluster, - scheduledFargateTaskImageOptions: { - image: ecs.ContainerImage.fromRegistry('henk'), - memoryLimitMiB: 512, - }, - schedule: events.Schedule.expression('rate(1 minute)'), - }); - - // THEN - expect(stack).to(haveResource('AWS::Events::Rule', { - State: 'ENABLED', - Targets: [ - { - Arn: { 'Fn::GetAtt': ['EcsCluster97242B84', 'Arn'] }, - EcsParameters: { - LaunchType: 'FARGATE', - NetworkConfiguration: { - AwsVpcConfiguration: { - AssignPublicIp: 'DISABLED', - SecurityGroups: [ - { - 'Fn::GetAtt': [ - 'ScheduledFargateTaskScheduledTaskDefSecurityGroupE075BC19', - 'GroupId', - ], - }, - ], - Subnets: [ - { - Ref: 'VpcPrivateSubnet1Subnet536B997A', - }, - ], - }, - }, - TaskCount: 1, - TaskDefinitionArn: { Ref: 'ScheduledFargateTaskScheduledTaskDef521FA675' }, - }, - Id: 'Target0', - Input: '{}', - RoleArn: { 'Fn::GetAtt': ['ScheduledFargateTaskScheduledTaskDefEventsRole6CE19522', 'Arn'] }, - }, - ], - })); - - expect(stack).to(haveResource('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Essential: true, - Image: 'henk', - LogConfiguration: { - LogDriver: 'awslogs', - Options: { - 'awslogs-group': { - Ref: 'ScheduledFargateTaskScheduledTaskDefScheduledContainerLogGroup4134B16C', - }, - 'awslogs-stream-prefix': 'ScheduledFargateTask', - 'awslogs-region': { - Ref: 'AWS::Region', - }, - }, - }, - Name: 'ScheduledContainer', - }, - ], - })); - - test.done(); - }, - - 'Can create a scheduled Fargate Task - with optional props'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 1 }); - const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); - - new ScheduledFargateTask(stack, 'ScheduledFargateTask', { - cluster, - enabled: false, - scheduledFargateTaskImageOptions: { - image: ecs.ContainerImage.fromRegistry('henk'), - memoryLimitMiB: 512, - cpu: 2, - environment: { TRIGGER: 'CloudWatch Events' }, - }, - desiredTaskCount: 2, - schedule: events.Schedule.expression('rate(1 minute)'), - ruleName: 'sample-scheduled-task-rule', - }); - - // THEN - expect(stack).to(haveResource('AWS::Events::Rule', { - Name: 'sample-scheduled-task-rule', - State: 'DISABLED', - Targets: [ - { - Arn: { 'Fn::GetAtt': ['EcsCluster97242B84', 'Arn'] }, - EcsParameters: { - LaunchType: 'FARGATE', - NetworkConfiguration: { - AwsVpcConfiguration: { - AssignPublicIp: 'DISABLED', - SecurityGroups: [ - { - 'Fn::GetAtt': [ - 'ScheduledFargateTaskScheduledTaskDefSecurityGroupE075BC19', - 'GroupId', - ], - }, - ], - Subnets: [ - { - Ref: 'VpcPrivateSubnet1Subnet536B997A', - }, - ], - }, - }, - TaskCount: 2, - TaskDefinitionArn: { Ref: 'ScheduledFargateTaskScheduledTaskDef521FA675' }, - }, - Id: 'Target0', - Input: '{}', - RoleArn: { 'Fn::GetAtt': ['ScheduledFargateTaskScheduledTaskDefEventsRole6CE19522', 'Arn'] }, - }, - ], - })); - - expect(stack).to(haveResource('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Environment: [ - { - Name: 'TRIGGER', - Value: 'CloudWatch Events', - }, - ], - Essential: true, - Image: 'henk', - LogConfiguration: { - LogDriver: 'awslogs', - Options: { - 'awslogs-group': { - Ref: 'ScheduledFargateTaskScheduledTaskDefScheduledContainerLogGroup4134B16C', - }, - 'awslogs-stream-prefix': 'ScheduledFargateTask', - 'awslogs-region': { - Ref: 'AWS::Region', - }, - }, - }, - Name: 'ScheduledContainer', - }, - ], - })); - - test.done(); - }, - - 'Scheduled Fargate Task - with MemoryReservation defined'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 1 }); - const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); - - new ScheduledFargateTask(stack, 'ScheduledFargateTask', { - cluster, - scheduledFargateTaskImageOptions: { - image: ecs.ContainerImage.fromRegistry('henk'), - }, - schedule: events.Schedule.expression('rate(1 minute)'), - }); - - // THEN - expect(stack).to(haveResource('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Essential: true, - Image: 'henk', - LogConfiguration: { - LogDriver: 'awslogs', - Options: { - 'awslogs-group': { - Ref: 'ScheduledFargateTaskScheduledTaskDefScheduledContainerLogGroup4134B16C', - }, - 'awslogs-stream-prefix': 'ScheduledFargateTask', - 'awslogs-region': { - Ref: 'AWS::Region', - }, - }, - }, - Name: 'ScheduledContainer', - }, - ], - })); - - test.done(); - }, - - 'Scheduled Fargate Task - with Command defined'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 1 }); - const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); - - new ScheduledFargateTask(stack, 'ScheduledFargateTask', { - cluster, - scheduledFargateTaskImageOptions: { - image: ecs.ContainerImage.fromRegistry('henk'), - command: ['-c', '4', 'amazon.com'], - }, - schedule: events.Schedule.expression('rate(1 minute)'), - }); - - // THEN - expect(stack).to(haveResource('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Command: [ - '-c', - '4', - 'amazon.com', - ], - Essential: true, - Image: 'henk', - LogConfiguration: { - LogDriver: 'awslogs', - Options: { - 'awslogs-group': { - Ref: 'ScheduledFargateTaskScheduledTaskDefScheduledContainerLogGroup4134B16C', - }, - 'awslogs-stream-prefix': 'ScheduledFargateTask', - 'awslogs-region': { - Ref: 'AWS::Region', - }, - }, - }, - Name: 'ScheduledContainer', - }, - ], - })); - - test.done(); - }, - - 'Scheduled Fargate Task - with subnetSelection defined'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'Vpc', { - maxAzs: 1, - subnetConfiguration: [ - { name: 'Public', cidrMask: 28, subnetType: ec2.SubnetType.PUBLIC }, - ], - }); - const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); - - new ScheduledFargateTask(stack, 'ScheduledFargateTask', { - cluster, - scheduledFargateTaskImageOptions: { - image: ecs.ContainerImage.fromRegistry('henk'), - }, - subnetSelection: { subnetType: ec2.SubnetType.PUBLIC }, - schedule: events.Schedule.expression('rate(1 minute)'), - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::Events::Rule', { - Targets: [ - { - EcsParameters: { - NetworkConfiguration: { - AwsVpcConfiguration: { - AssignPublicIp: 'ENABLED', - Subnets: [ - { - Ref: 'VpcPublicSubnet1Subnet5C2D37C4', - }, - ], - }, - }, - }, - }, - ], - })); - - test.done(); - }, - - 'Scheduled Fargate Task - with platformVersion defined'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 1 }); - const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); - - new ScheduledFargateTask(stack, 'ScheduledFargateTask', { - cluster, - scheduledFargateTaskImageOptions: { - image: ecs.ContainerImage.fromRegistry('henk'), - memoryLimitMiB: 512, - }, - schedule: events.Schedule.expression('rate(1 minute)'), - platformVersion: ecs.FargatePlatformVersion.VERSION1_4, - }); - - // THEN - expect(stack).to(haveResource('AWS::Events::Rule', { - Targets: [ - { - Arn: { 'Fn::GetAtt': ['EcsCluster97242B84', 'Arn'] }, - EcsParameters: { - LaunchType: 'FARGATE', - NetworkConfiguration: { - AwsVpcConfiguration: { - AssignPublicIp: 'DISABLED', - SecurityGroups: [ - { - 'Fn::GetAtt': [ - 'ScheduledFargateTaskScheduledTaskDefSecurityGroupE075BC19', - 'GroupId', - ], - }, - ], - Subnets: [ - { - Ref: 'VpcPrivateSubnet1Subnet536B997A', - }, - ], - }, - }, - PlatformVersion: '1.4.0', - TaskCount: 1, - TaskDefinitionArn: { Ref: 'ScheduledFargateTaskScheduledTaskDef521FA675' }, - }, - Id: 'Target0', - Input: '{}', - RoleArn: { 'Fn::GetAtt': ['ScheduledFargateTaskScheduledTaskDefEventsRole6CE19522', 'Arn'] }, - }, - ], - })); - - test.done(); - }, - 'Scheduled Fargate Task - with securityGroups defined'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 1 }); - const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); - const sg = new ec2.SecurityGroup(stack, 'SG', { vpc }); - - new ScheduledFargateTask(stack, 'ScheduledFargateTask', { - cluster, - scheduledFargateTaskImageOptions: { - image: ecs.ContainerImage.fromRegistry('henk'), - memoryLimitMiB: 512, - }, - schedule: events.Schedule.expression('rate(1 minute)'), - securityGroups: [sg], - }); - - // THEN - expect(stack).to(haveResource('AWS::Events::Rule', { - Targets: [ - { - Arn: { 'Fn::GetAtt': ['EcsCluster97242B84', 'Arn'] }, - EcsParameters: { - LaunchType: 'FARGATE', - NetworkConfiguration: { - AwsVpcConfiguration: { - AssignPublicIp: 'DISABLED', - SecurityGroups: [{ - 'Fn::GetAtt': [ - 'SGADB53937', - 'GroupId', - ], - }], - Subnets: [ - { - Ref: 'VpcPrivateSubnet1Subnet536B997A', - }, - ], - }, - }, - TaskCount: 1, - TaskDefinitionArn: { Ref: 'ScheduledFargateTaskScheduledTaskDef521FA675' }, - }, - Id: 'Target0', - Input: '{}', - RoleArn: { 'Fn::GetAtt': ['ScheduledFargateTaskScheduledTaskDefEventsRole6CE19522', 'Arn'] }, - }, - ], - })); - - test.done(); - }, - - 'Scheduled Fargate Task - exposes ECS Task'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 1 }); - const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); - - const scheduledFargateTask = new ScheduledFargateTask(stack, 'ScheduledFargateTask', { - cluster, - scheduledFargateTaskImageOptions: { - image: ecs.ContainerImage.fromRegistry('henk'), - memoryLimitMiB: 512, - }, - schedule: events.Schedule.expression('rate(1 minute)'), - }); - - // THEN - test.notEqual(scheduledFargateTask.task, undefined); - - test.done(); - }, -}; diff --git a/packages/@aws-cdk/aws-ecs/.eslintrc.js b/packages/@aws-cdk/aws-ecs/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-ecs/.eslintrc.js +++ b/packages/@aws-cdk/aws-ecs/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-ecs/README.md b/packages/@aws-cdk/aws-ecs/README.md index 8ffbde1d9a0e8..6a27855e031f5 100644 --- a/packages/@aws-cdk/aws-ecs/README.md +++ b/packages/@aws-cdk/aws-ecs/README.md @@ -23,7 +23,7 @@ The following example creates an Amazon ECS cluster, adds capacity to it, and runs a service on it: ```ts -import * as ecs from '@aws-cdk/aws-ecs'; +declare const vpc: ec2.Vpc; // Create an ECS cluster const cluster = new ecs.Cluster(this, 'Cluster', { @@ -89,8 +89,10 @@ tasks on. You can run many tasks on a single cluster. The following code creates a cluster that can run AWS Fargate tasks: ```ts +declare const vpc: ec2.Vpc; + const cluster = new ecs.Cluster(this, 'Cluster', { - vpc: vpc + vpc, }); ``` @@ -105,8 +107,10 @@ with various instance types. The following example creates an Amazon ECS cluster and adds capacity to it: ```ts +declare const vpc: ec2.Vpc; + const cluster = new ecs.Cluster(this, 'Cluster', { - vpc: vpc + vpc, }); // Either add default capacity @@ -119,7 +123,7 @@ cluster.addCapacity('DefaultAutoScalingGroupCapacity', { const autoScalingGroup = new autoscaling.AutoScalingGroup(this, 'ASG', { vpc, instanceType: new ec2.InstanceType('t2.xlarge'), - machineImage: EcsOptimizedImage.amazonLinux(), + machineImage: ecs.EcsOptimizedImage.amazonLinux(), // Or use Amazon ECS-Optimized Amazon Linux 2 AMI // machineImage: EcsOptimizedImage.amazonLinux2(), desiredCapacity: 3, @@ -143,9 +147,11 @@ to periodically update to the latest AMI manually by using the [CDK CLI context management commands](https://docs.aws.amazon.com/cdk/latest/guide/context.html): ```ts +declare const vpc: ec2.Vpc; const autoScalingGroup = new autoscaling.AutoScalingGroup(this, 'ASG', { - // ... - machineImage: EcsOptimizedImage.amazonLinux({ cacheInContext: true }), + machineImage: ecs.EcsOptimizedImage.amazonLinux({ cachedInContext: true }), + vpc, + instanceType: new ec2.InstanceType('t2.micro'), }); ``` @@ -159,6 +165,8 @@ The following example will create a capacity with self-managed Amazon EC2 capaci The following example adds Bottlerocket capacity to the cluster: ```ts +declare const cluster: ecs.Cluster; + cluster.addCapacity('bottlerocket-asg', { minCapacity: 2, instanceType: new ec2.InstanceType('c5.large'), @@ -174,6 +182,8 @@ for use when launching your EC2 instances that are powered by Arm-based AWS Graviton Processors. ```ts +declare const cluster: ecs.Cluster; + cluster.addCapacity('graviton-cluster', { minCapacity: 2, instanceType: new ec2.InstanceType('c6g.large'), @@ -184,10 +194,12 @@ cluster.addCapacity('graviton-cluster', { Bottlerocket is also supported: ```ts +declare const cluster: ecs.Cluster; + cluster.addCapacity('graviton-cluster', { minCapacity: 2, instanceType: new ec2.InstanceType('c6g.large'), - machineImage: ecs.MachineImageType.BOTTLEROCKET, + machineImageType: ecs.MachineImageType.BOTTLEROCKET, }); ``` @@ -196,6 +208,8 @@ cluster.addCapacity('graviton-cluster', { To add spot instances into the cluster, you must specify the `spotPrice` in the `ecs.AddCapacityOptions` and optionally enable the `spotInstanceDraining` property. ```ts +declare const cluster: ecs.Cluster; + // Add an AutoScalingGroup with spot instances to the existing cluster cluster.addCapacity('AsgSpot', { maxCapacity: 2, @@ -217,7 +231,8 @@ then you may do so by providing a KMS key for the `topicEncryptionKey` property ```ts // Given -const key = kms.Key(...); +declare const cluster: ecs.Cluster; +declare const key: kms.Key; // Then, use that key to encrypt the lifecycle-event SNS Topic. cluster.addCapacity('ASGEncryptedSNS', { instanceType: new ec2.InstanceType("t2.xlarge"), @@ -244,7 +259,7 @@ For a `FargateTaskDefinition`, specify the task size (`memoryLimitMiB` and `cpu` ```ts const fargateTaskDefinition = new ecs.FargateTaskDefinition(this, 'TaskDef', { memoryLimitMiB: 512, - cpu: 256 + cpu: 256, }); ``` @@ -255,13 +270,17 @@ On Fargate Platform Version 1.4.0 or later, you may specify up to 200GiB of const fargateTaskDefinition = new ecs.FargateTaskDefinition(this, 'TaskDef', { memoryLimitMiB: 512, cpu: 256, - ephemeralStorageGiB: 100 + ephemeralStorageGiB: 100, }); ``` To add containers to a task definition, call `addContainer()`: ```ts +const fargateTaskDefinition = new ecs.FargateTaskDefinition(this, 'TaskDef', { + memoryLimitMiB: 512, + cpu: 256, +}); const container = fargateTaskDefinition.addContainer("WebContainer", { // Use an image from DockerHub image: ecs.ContainerImage.fromRegistry("amazon/amazon-ecs-sample"), @@ -273,13 +292,13 @@ For a `Ec2TaskDefinition`: ```ts const ec2TaskDefinition = new ecs.Ec2TaskDefinition(this, 'TaskDef', { - networkMode: NetworkMode.BRIDGE + networkMode: ecs.NetworkMode.BRIDGE, }); const container = ec2TaskDefinition.addContainer("WebContainer", { // Use an image from DockerHub image: ecs.ContainerImage.fromRegistry("amazon/amazon-ecs-sample"), - memoryLimitMiB: 1024 + memoryLimitMiB: 1024, // ... other options here ... }); ``` @@ -292,7 +311,7 @@ const externalTaskDefinition = new ecs.ExternalTaskDefinition(this, 'TaskDef'); const container = externalTaskDefinition.addContainer("WebContainer", { // Use an image from DockerHub image: ecs.ContainerImage.fromRegistry("amazon/amazon-ecs-sample"), - memoryLimitMiB: 1024 + memoryLimitMiB: 1024, // ... other options here ... }); ``` @@ -302,34 +321,42 @@ You can specify container properties when you add them to the task definition, o To add a port mapping when adding a container to the task definition, specify the `portMappings` option: ```ts +declare const taskDefinition: ecs.TaskDefinition; + taskDefinition.addContainer("WebContainer", { image: ecs.ContainerImage.fromRegistry("amazon/amazon-ecs-sample"), memoryLimitMiB: 1024, - portMappings: [{ containerPort: 3000 }] + portMappings: [{ containerPort: 3000 }], }); ``` To add port mappings directly to a container definition, call `addPortMappings()`: ```ts +declare const container: ecs.ContainerDefinition; + container.addPortMappings({ - containerPort: 3000 + containerPort: 3000, }); ``` To add data volumes to a task definition, call `addVolume()`: ```ts +const fargateTaskDefinition = new ecs.FargateTaskDefinition(this, 'TaskDef', { + memoryLimitMiB: 512, + cpu: 256, +}); const volume = { // Use an Elastic FileSystem name: "mydatavolume", - efsVolumeConfiguration: ecs.EfsVolumeConfiguration({ - fileSystemId: "EFS" + efsVolumeConfiguration: { + fileSystemId: "EFS", // ... other options here ... - }) + }, }; -const container = fargateTaskDefinition.addVolume("mydatavolume"); +const container = fargateTaskDefinition.addVolume(volume); ``` > Note: ECS Anywhere doesn't support volume attachments in the task definition. @@ -345,7 +372,7 @@ The following example uses both: const taskDefinition = new ecs.TaskDefinition(this, 'TaskDef', { memoryMiB: '512', cpu: '256', - networkMode: NetworkMode.AWS_VPC, + networkMode: ecs.NetworkMode.AWS_VPC, compatibility: ecs.Compatibility.EC2_AND_FARGATE, }); ``` @@ -372,6 +399,12 @@ obtained from either DockerHub or from ECR repositories, built directly from a l To pass environment variables to the container, you can use the `environment`, `environmentFiles`, and `secrets` props. ```ts +declare const secret: secretsmanager.Secret; +declare const dbSecret: secretsmanager.Secret; +declare const parameter: ssm.StringParameter; +declare const taskDefinition: ecs.TaskDefinition; +declare const s3Bucket: s3.Bucket; + taskDefinition.addContainer('container', { image: ecs.ContainerImage.fromRegistry("amazon/amazon-ecs-sample"), memoryLimitMiB: 1024, @@ -386,7 +419,7 @@ taskDefinition.addContainer('container', { SECRET: ecs.Secret.fromSecretsManager(secret), DB_PASSWORD: ecs.Secret.fromSecretsManager(dbSecret, 'password'), // Reference a specific JSON field, (requires platform version 1.4.0 or later for Fargate tasks) PARAMETER: ecs.Secret.fromSsmParameter(parameter), - } + }, }); ``` @@ -402,24 +435,26 @@ If a task fails, Amazon ECS automatically restarts the task. ```ts -const taskDefinition; +declare const cluster: ecs.Cluster; +declare const taskDefinition: ecs.TaskDefinition; const service = new ecs.FargateService(this, 'Service', { cluster, taskDefinition, - desiredCount: 5 + desiredCount: 5, }); ``` ECS Anywhere service definition looks like: ```ts -const taskDefinition; +declare const cluster: ecs.Cluster; +declare const taskDefinition: ecs.TaskDefinition; const service = new ecs.ExternalService(this, 'Service', { cluster, taskDefinition, - desiredCount: 5 + desiredCount: 5, }); ``` @@ -434,7 +469,9 @@ deployment circuit breaker and optionally enable `rollback` for automatic rollba for more details. ```ts -const service = new ecs.FargateService(stack, 'Service', { +declare const cluster: ecs.Cluster; +declare const taskDefinition: ecs.TaskDefinition; +const service = new ecs.FargateService(this, 'Service', { cluster, taskDefinition, circuitBreaker: { rollback: true }, @@ -448,22 +485,23 @@ const service = new ecs.FargateService(stack, 'Service', { `Services` are load balancing targets and can be added to a target group, which will be attached to an application/network load balancers: ```ts -import * as elbv2 from '@aws-cdk/aws-elasticloadbalancingv2'; - -const service = new ecs.FargateService(this, 'Service', { /* ... */ }); +declare const vpc: ec2.Vpc; +declare const cluster: ecs.Cluster; +declare const taskDefinition: ecs.TaskDefinition; +const service = new ecs.FargateService(this, 'Service', { cluster, taskDefinition }); const lb = new elbv2.ApplicationLoadBalancer(this, 'LB', { vpc, internetFacing: true }); const listener = lb.addListener('Listener', { port: 80 }); const targetGroup1 = listener.addTargets('ECS1', { port: 80, - targets: [service] + targets: [service], }); const targetGroup2 = listener.addTargets('ECS2', { port: 80, targets: [service.loadBalancerTarget({ containerName: 'MyContainer', containerPort: 8080 - })] + })], }); ``` @@ -474,9 +512,10 @@ Note that in the example above, the default `service` only allows you to registe Alternatively, you can also create all load balancer targets to be registered in this service, add them to target groups, and attach target groups to listeners accordingly. ```ts -import * as elbv2 from '@aws-cdk/aws-elasticloadbalancingv2'; - -const service = new ecs.FargateService(this, 'Service', { /* ... */ }); +declare const cluster: ecs.Cluster; +declare const taskDefinition: ecs.TaskDefinition; +declare const vpc: ec2.Vpc; +const service = new ecs.FargateService(this, 'Service', { cluster, taskDefinition }); const lb = new elbv2.ApplicationLoadBalancer(this, 'LB', { vpc, internetFacing: true }); const listener = lb.addListener('Listener', { port: 80 }); @@ -512,11 +551,12 @@ for the alternatives. `Services` can also be directly attached to a classic load balancer as targets: ```ts -import * as elb from '@aws-cdk/aws-elasticloadbalancing'; - -const service = new ecs.Ec2Service(this, 'Service', { /* ... */ }); +declare const cluster: ecs.Cluster; +declare const taskDefinition: ecs.TaskDefinition; +declare const vpc: ec2.Vpc; +const service = new ecs.Ec2Service(this, 'Service', { cluster, taskDefinition }); -const lb = new elb.LoadBalancer(stack, 'LB', { vpc }); +const lb = new elb.LoadBalancer(this, 'LB', { vpc }); lb.addListener({ externalPort: 80 }); lb.addTarget(service); ``` @@ -524,15 +564,16 @@ lb.addTarget(service); Similarly, if you want to have more control over load balancer targeting: ```ts -import * as elb from '@aws-cdk/aws-elasticloadbalancing'; +declare const cluster: ecs.Cluster; +declare const taskDefinition: ecs.TaskDefinition; +declare const vpc: ec2.Vpc; +const service = new ecs.Ec2Service(this, 'Service', { cluster, taskDefinition }); -const service = new ecs.Ec2Service(this, 'Service', { /* ... */ }); - -const lb = new elb.LoadBalancer(stack, 'LB', { vpc }); +const lb = new elb.LoadBalancer(this, 'LB', { vpc }); lb.addListener({ externalPort: 80 }); lb.addTarget(service.loadBalancerTarget({ containerName: 'MyContainer', - containerPort: 80 + containerPort: 80, })); ``` @@ -547,15 +588,17 @@ You can configure the task count of a service to match demand. Task auto-scaling configured by calling `autoScaleTaskCount()`: ```ts +declare const target: elbv2.ApplicationTargetGroup; +declare const service: ecs.BaseService; const scaling = service.autoScaleTaskCount({ maxCapacity: 10 }); scaling.scaleOnCpuUtilization('CpuScaling', { - targetUtilizationPercent: 50 + targetUtilizationPercent: 50, }); scaling.scaleOnRequestCount('RequestScaling', { requestsPerTarget: 10000, - targetGroup: target -}) + targetGroup: target, +}); ``` Task auto-scaling is powered by *Application Auto-Scaling*. @@ -567,19 +610,18 @@ To start an Amazon ECS task on an Amazon EC2-backed Cluster, instantiate an `@aws-cdk/aws-events-targets.EcsTask` instead of an `Ec2Service`: ```ts -import * as targets from '@aws-cdk/aws-events-targets'; - +declare const cluster: ecs.Cluster; // Create a Task Definition for the container to start const taskDefinition = new ecs.Ec2TaskDefinition(this, 'TaskDef'); taskDefinition.addContainer('TheContainer', { image: ecs.ContainerImage.fromAsset(path.resolve(__dirname, '..', 'eventhandler-image')), memoryLimitMiB: 256, - logging: new ecs.AwsLogDriver({ streamPrefix: 'EventDemo', mode: AwsLogDriverMode.NON_BLOCKING }) + logging: new ecs.AwsLogDriver({ streamPrefix: 'EventDemo', mode: ecs.AwsLogDriverMode.NON_BLOCKING }), }); // An Rule that describes the event trigger (in this case a scheduled run) const rule = new events.Rule(this, 'Rule', { - schedule: events.Schedule.expression('rate(1 min)') + schedule: events.Schedule.expression('rate(1 min)'), }); // Pass an environment variable to the container 'TheContainer' in the task @@ -592,8 +634,8 @@ rule.addTarget(new targets.EcsTask({ environment: [{ name: 'I_WAS_TRIGGERED', value: 'From CloudWatch Events' - }] - }] + }], + }], })); ``` @@ -609,6 +651,7 @@ Currently Supported Log Drivers: - splunk - syslog - awsfirelens +- Generic ### awslogs Log Driver @@ -618,7 +661,7 @@ const taskDefinition = new ecs.Ec2TaskDefinition(this, 'TaskDef'); taskDefinition.addContainer('TheContainer', { image: ecs.ContainerImage.fromRegistry('example-image'), memoryLimitMiB: 256, - logging: ecs.LogDrivers.awsLogs({ streamPrefix: 'EventDemo' }) + logging: ecs.LogDrivers.awsLogs({ streamPrefix: 'EventDemo' }), }); ``` @@ -630,7 +673,7 @@ const taskDefinition = new ecs.Ec2TaskDefinition(this, 'TaskDef'); taskDefinition.addContainer('TheContainer', { image: ecs.ContainerImage.fromRegistry('example-image'), memoryLimitMiB: 256, - logging: ecs.LogDrivers.fluentd() + logging: ecs.LogDrivers.fluentd(), }); ``` @@ -642,7 +685,7 @@ const taskDefinition = new ecs.Ec2TaskDefinition(this, 'TaskDef'); taskDefinition.addContainer('TheContainer', { image: ecs.ContainerImage.fromRegistry('example-image'), memoryLimitMiB: 256, - logging: ecs.LogDrivers.gelf({ address: 'my-gelf-address' }) + logging: ecs.LogDrivers.gelf({ address: 'my-gelf-address' }), }); ``` @@ -654,7 +697,7 @@ const taskDefinition = new ecs.Ec2TaskDefinition(this, 'TaskDef'); taskDefinition.addContainer('TheContainer', { image: ecs.ContainerImage.fromRegistry('example-image'), memoryLimitMiB: 256, - logging: ecs.LogDrivers.journald() + logging: ecs.LogDrivers.journald(), }); ``` @@ -666,7 +709,7 @@ const taskDefinition = new ecs.Ec2TaskDefinition(this, 'TaskDef'); taskDefinition.addContainer('TheContainer', { image: ecs.ContainerImage.fromRegistry('example-image'), memoryLimitMiB: 256, - logging: ecs.LogDrivers.jsonFile() + logging: ecs.LogDrivers.jsonFile(), }); ``` @@ -679,9 +722,9 @@ taskDefinition.addContainer('TheContainer', { image: ecs.ContainerImage.fromRegistry('example-image'), memoryLimitMiB: 256, logging: ecs.LogDrivers.splunk({ - secretToken: cdk.SecretValue.secretsManager('my-splunk-token'), - url: 'my-splunk-url' - }) + token: SecretValue.secretsManager('my-splunk-token'), + url: 'my-splunk-url', + }), }); ``` @@ -693,7 +736,7 @@ const taskDefinition = new ecs.Ec2TaskDefinition(this, 'TaskDef'); taskDefinition.addContainer('TheContainer', { image: ecs.ContainerImage.fromRegistry('example-image'), memoryLimitMiB: 256, - logging: ecs.LogDrivers.syslog() + logging: ecs.LogDrivers.syslog(), }); ``` @@ -710,14 +753,17 @@ taskDefinition.addContainer('TheContainer', { Name: 'firehose', region: 'us-west-2', delivery_stream: 'my-stream', - } - }) + }, + }), }); ``` To pass secrets to the log configuration, use the `secretOptions` property of the log configuration. The task execution role is automatically granted read permissions on the secrets/parameters. ```ts +declare const secret: secretsmanager.Secret; +declare const parameter: ssm.StringParameter; + const taskDefinition = new ecs.Ec2TaskDefinition(this, 'TaskDef'); taskDefinition.addContainer('TheContainer', { image: ecs.ContainerImage.fromRegistry('example-image'), @@ -730,7 +776,7 @@ taskDefinition.addContainer('TheContainer', { apikey: ecs.Secret.fromSecretsManager(secret), host: ecs.Secret.fromSsmParameter(parameter), }, - }) + }), }); ``` @@ -747,9 +793,9 @@ taskDefinition.addContainer('TheContainer', { logging: new ecs.GenericLogDriver({ logDriver: 'fluentd', options: { - tag: 'example-tag' - } - }) + tag: 'example-tag', + }, + }), }); ``` @@ -759,7 +805,10 @@ To register your ECS service with a CloudMap Service Registry, you may add the `cloudMapOptions` property to your service: ```ts -const service = new ecs.Ec2Service(stack, 'Service', { +declare const taskDefinition: ecs.TaskDefinition; +declare const cluster: ecs.Cluster; + +const service = new ecs.Ec2Service(this, 'Service', { cluster, taskDefinition, cloudMapOptions: { @@ -774,8 +823,14 @@ By default, `SRV` DNS record types will target the default container and default port. However, you may target a different container and port on the same ECS task: ```ts +declare const taskDefinition: ecs.TaskDefinition; +declare const cluster: ecs.Cluster; + // Add a container to the task definition -const specificContainer = taskDefinition.addContainer(...); +const specificContainer = taskDefinition.addContainer('Container', { + image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), + memoryLimitMiB: 2048, +}); // Add a port mapping specificContainer.addPortMappings({ @@ -783,7 +838,7 @@ specificContainer.addPortMappings({ protocol: ecs.Protocol.TCP, }); -new ecs.Ec2Service(stack, 'Service', { +new ecs.Ec2Service(this, 'Service', { cluster, taskDefinition, cloudMapOptions: { @@ -802,8 +857,8 @@ You may associate an ECS service with a specific CloudMap service. To do this, use the service's `associateCloudMapService` method: ```ts -const cloudMapService = new cloudmap.Service(...); -const ecsService = new ecs.FargateService(...); +declare const cloudMapService: cloudmap.Service; +declare const ecsService: ecs.FargateService; ecsService.associateCloudMapService({ service: cloudMapService, @@ -827,18 +882,20 @@ cluster. This will add both `FARGATE` and `FARGATE_SPOT` as available capacity providers on your cluster. ```ts -const cluster = new ecs.Cluster(stack, 'FargateCPCluster', { +declare const vpc: ec2.Vpc; + +const cluster = new ecs.Cluster(this, 'FargateCPCluster', { vpc, enableFargateCapacityProviders: true, }); -const taskDefinition = new ecs.FargateTaskDefinition(stack, 'TaskDef'); +const taskDefinition = new ecs.FargateTaskDefinition(this, 'TaskDef'); taskDefinition.addContainer('web', { image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), }); -new ecs.FargateService(stack, 'FargateService', { +new ecs.FargateService(this, 'FargateService', { cluster, taskDefinition, capacityProviderStrategies: [ @@ -849,7 +906,7 @@ new ecs.FargateService(stack, 'FargateService', { { capacityProvider: 'FARGATE', weight: 1, - } + }, ], }); ``` @@ -869,11 +926,13 @@ running on them. If you want to disable this behavior, set both `enableManagedScaling` to and `enableManagedTerminationProtection` to `false`. ```ts -const cluster = new ecs.Cluster(stack, 'Cluster', { +declare const vpc: ec2.Vpc; + +const cluster = new ecs.Cluster(this, 'Cluster', { vpc, }); -const autoScalingGroup = new autoscaling.AutoScalingGroup(stack, 'ASG', { +const autoScalingGroup = new autoscaling.AutoScalingGroup(this, 'ASG', { vpc, instanceType: new ec2.InstanceType('t2.micro'), machineImage: ecs.EcsOptimizedImage.amazonLinux2(), @@ -881,26 +940,26 @@ const autoScalingGroup = new autoscaling.AutoScalingGroup(stack, 'ASG', { maxCapacity: 100, }); -const capacityProvider = new ecs.AsgCapacityProvider(stack, 'AsgCapacityProvider', { +const capacityProvider = new ecs.AsgCapacityProvider(this, 'AsgCapacityProvider', { autoScalingGroup, }); cluster.addAsgCapacityProvider(capacityProvider); -const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); +const taskDefinition = new ecs.Ec2TaskDefinition(this, 'TaskDef'); taskDefinition.addContainer('web', { image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), memoryReservationMiB: 256, }); -new ecs.Ec2Service(stack, 'EC2Service', { +new ecs.Ec2Service(this, 'EC2Service', { cluster, taskDefinition, capacityProviderStrategies: [ { capacityProvider: capacityProvider.capacityProviderName, weight: 1, - } + }, ], }); ``` @@ -919,7 +978,7 @@ const inferenceAccelerators = [{ deviceType: 'eia2.medium', }]; -const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'Ec2TaskDef', { +const taskDefinition = new ecs.Ec2TaskDefinition(this, 'Ec2TaskDef', { inferenceAccelerators, }); ``` @@ -929,6 +988,7 @@ field and set it to a list of device names used for the inference accelerators. list should match a `DeviceName` for an `InferenceAccelerator` specified in the task definition. ```ts +declare const taskDefinition: ecs.TaskDefinition; const inferenceAcceleratorResources = ['device1']; taskDefinition.addContainer('cont', { @@ -948,7 +1008,10 @@ To enable the ECS Exec feature for your containers, set the boolean flag `enable your `Ec2Service` or `FargateService`. ```ts -const service = new ecs.Ec2Service(stack, 'Service', { +declare const cluster: ecs.Cluster; +declare const taskDefinition: ecs.TaskDefinition; + +const service = new ecs.Ec2Service(this, 'Service', { cluster, taskDefinition, enableExecuteCommand: true, @@ -967,19 +1030,20 @@ of the `executeCommandConfiguration`. To use this key for encrypting CloudWatch to these resources on creation. ```ts -const kmsKey = new kms.Key(stack, 'KmsKey'); +declare const vpc: ec2.Vpc; +const kmsKey = new kms.Key(this, 'KmsKey'); // Pass the KMS key in the `encryptionKey` field to associate the key to the log group -const logGroup = new logs.LogGroup(stack, 'LogGroup', { +const logGroup = new logs.LogGroup(this, 'LogGroup', { encryptionKey: kmsKey, }); // Pass the KMS key in the `encryptionKey` field to associate the key to the S3 bucket -const execBucket = new s3.Bucket(stack, 'EcsExecBucket', { +const execBucket = new s3.Bucket(this, 'EcsExecBucket', { encryptionKey: kmsKey, }); -const cluster = new ecs.Cluster(stack, 'Cluster', { +const cluster = new ecs.Cluster(this, 'Cluster', { vpc, executeCommandConfiguration: { kmsKey, diff --git a/packages/@aws-cdk/aws-ecs/jest.config.js b/packages/@aws-cdk/aws-ecs/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-ecs/jest.config.js +++ b/packages/@aws-cdk/aws-ecs/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-ecs/lib/base/base-service.ts b/packages/@aws-cdk/aws-ecs/lib/base/base-service.ts index ce5097e9ebccf..6bac2c663b82d 100644 --- a/packages/@aws-cdk/aws-ecs/lib/base/base-service.ts +++ b/packages/@aws-cdk/aws-ecs/lib/base/base-service.ts @@ -570,6 +570,8 @@ export abstract class BaseService extends Resource * * @example * + * declare const listener: elbv2.ApplicationListener; + * declare const service: ecs.BaseService; * listener.addTargets('ECS', { * port: 80, * targets: [service.loadBalancerTarget({ @@ -605,6 +607,8 @@ export abstract class BaseService extends Resource * * @example * + * declare const listener: elbv2.ApplicationListener; + * declare const service: ecs.BaseService; * service.registerLoadBalancerTargets( * { * containerName: 'web', diff --git a/packages/@aws-cdk/aws-ecs/lib/base/from-service-attributes.ts b/packages/@aws-cdk/aws-ecs/lib/base/from-service-attributes.ts index 80ec042626153..cfaff590b3eb1 100644 --- a/packages/@aws-cdk/aws-ecs/lib/base/from-service-attributes.ts +++ b/packages/@aws-cdk/aws-ecs/lib/base/from-service-attributes.ts @@ -54,5 +54,7 @@ export function fromServiceAtrributes(scope: Construct, id: string, attrs: Servi public readonly serviceName = name; public readonly cluster = attrs.cluster; } - return new Import(scope, id); + return new Import(scope, id, { + environmentFromArn: arn, + }); } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ecs/lib/cluster.ts b/packages/@aws-cdk/aws-ecs/lib/cluster.ts index 49d99bf68925d..aae5d320b20af 100644 --- a/packages/@aws-cdk/aws-ecs/lib/cluster.ts +++ b/packages/@aws-cdk/aws-ecs/lib/cluster.ts @@ -324,15 +324,15 @@ export class Cluster extends Resource implements ICluster { * * @param provider the capacity provider to add to this cluster. */ - public addAsgCapacityProvider(provider: AsgCapacityProvider, options: AddAutoScalingGroupCapacityOptions = {}) { + public addAsgCapacityProvider(provider: AsgCapacityProvider, options: AddAutoScalingGroupCapacityOptions= {}) { // Don't add the same capacity provider more than once. if (this._capacityProviderNames.includes(provider.capacityProviderName)) { return; } - this._hasEc2Capacity = true; this.configureAutoScalingGroup(provider.autoScalingGroup, { ...options, + machineImageType: provider.machineImageType, // Don't enable the instance-draining lifecycle hook if managed termination protection is enabled taskDrainTime: provider.enableManagedTerminationProtection ? Duration.seconds(0) : options.taskDrainTime, }); @@ -821,11 +821,9 @@ export interface AddCapacityOptions extends AddAutoScalingGroupCapacityOptions, * To use an image that does not update on every deployment, pass: * * ```ts - * { - * machineImage: EcsOptimizedImage.amazonLinux2(AmiHardwareType.STANDARD, { - * cachedInContext: true, - * }), - * } + * const machineImage = ecs.EcsOptimizedImage.amazonLinux2(ecs.AmiHardwareType.STANDARD, { + * cachedInContext: true, + * }); * ``` * * For more information, see [Amazon ECS-optimized @@ -1064,6 +1062,11 @@ export class AsgCapacityProvider extends CoreConstruct { */ readonly autoScalingGroup: autoscaling.AutoScalingGroup; + /** + * Auto Scaling Group machineImageType. + */ + readonly machineImageType: MachineImageType; + /** * Whether managed termination protection is enabled */ @@ -1074,6 +1077,8 @@ export class AsgCapacityProvider extends CoreConstruct { this.autoScalingGroup = props.autoScalingGroup as autoscaling.AutoScalingGroup; + this.machineImageType = props.machineImageType ?? MachineImageType.AMAZON_LINUX_2; + this.enableManagedTerminationProtection = props.enableManagedTerminationProtection === undefined ? true : props.enableManagedTerminationProtection; diff --git a/packages/@aws-cdk/aws-ecs/lib/index.ts b/packages/@aws-cdk/aws-ecs/lib/index.ts index bd076ccfd05f7..09d355dd18b38 100644 --- a/packages/@aws-cdk/aws-ecs/lib/index.ts +++ b/packages/@aws-cdk/aws-ecs/lib/index.ts @@ -36,6 +36,7 @@ export * from './log-drivers/json-file-log-driver'; export * from './log-drivers/splunk-log-driver'; export * from './log-drivers/syslog-log-driver'; export * from './log-drivers/log-driver'; +export * from './log-drivers/generic-log-driver'; export * from './log-drivers/log-drivers'; export * from './proxy-configuration/app-mesh-proxy-configuration'; diff --git a/packages/@aws-cdk/aws-ecs/lib/log-drivers/generic-log-driver.ts b/packages/@aws-cdk/aws-ecs/lib/log-drivers/generic-log-driver.ts index 9e356a8cd3c19..8181b7d689d44 100644 --- a/packages/@aws-cdk/aws-ecs/lib/log-drivers/generic-log-driver.ts +++ b/packages/@aws-cdk/aws-ecs/lib/log-drivers/generic-log-driver.ts @@ -1,5 +1,5 @@ import { ContainerDefinition, Secret } from '../container-definition'; -import { LogDriver, LogDriverConfig } from '../index'; +import { LogDriver, LogDriverConfig } from './log-driver'; import { removeEmpty, renderLogDriverSecretOptions } from './utils'; // v2 - keep this import as a separate section to reduce merge conflict when forward merging with the v2 branch. diff --git a/packages/@aws-cdk/aws-ecs/package.json b/packages/@aws-cdk/aws-ecs/package.json index f050efe94d045..d1839630a6eff 100644 --- a/packages/@aws-cdk/aws-ecs/package.json +++ b/packages/@aws-cdk/aws-ecs/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::ECS", - "jest": "true", "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,18 +72,17 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", + "@aws-cdk/assert-internal": "0.0.0", "@aws-cdk/aws-s3-deployment": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/cx-api": "0.0.0", - "@types/nodeunit": "^0.0.32", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24", "@types/proxyquire": "^1.3.28", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", "jest": "^26.6.3", - "pkglint": "0.0.0", - "proxyquire": "^2.1.3", - "@aws-cdk/assert-internal": "0.0.0" + "proxyquire": "^2.1.3" }, "dependencies": { "@aws-cdk/aws-applicationautoscaling": "0.0.0", @@ -132,6 +130,8 @@ "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-route53": "0.0.0", "@aws-cdk/aws-route53-targets": "0.0.0", + "@aws-cdk/aws-s3": "0.0.0", + "@aws-cdk/aws-s3-assets": "0.0.0", "@aws-cdk/aws-secretsmanager": "0.0.0", "@aws-cdk/aws-servicediscovery": "0.0.0", "@aws-cdk/aws-sns": "0.0.0", @@ -139,8 +139,6 @@ "@aws-cdk/aws-ssm": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/cx-api": "0.0.0", - "@aws-cdk/aws-s3": "0.0.0", - "@aws-cdk/aws-s3-assets": "0.0.0", "constructs": "^3.3.69" }, "engines": { diff --git a/packages/@aws-cdk/aws-ecs/rosetta/default.ts-fixture b/packages/@aws-cdk/aws-ecs/rosetta/default.ts-fixture new file mode 100644 index 0000000000000..2cc599faf6c3f --- /dev/null +++ b/packages/@aws-cdk/aws-ecs/rosetta/default.ts-fixture @@ -0,0 +1,24 @@ +// Fixture with packages imported, but nothing else +import { Construct, SecretValue, Stack } from '@aws-cdk/core'; +import autoscaling = require('@aws-cdk/aws-autoscaling'); +import cloudmap = require('@aws-cdk/aws-servicediscovery'); +import ecs = require('@aws-cdk/aws-ecs'); +import ec2 = require('@aws-cdk/aws-ec2'); +import elb = require('@aws-cdk/aws-elasticloadbalancing'); +import elbv2 = require('@aws-cdk/aws-elasticloadbalancingv2'); +import events = require('@aws-cdk/aws-events'); +import kms = require('@aws-cdk/aws-kms'); +import logs = require('@aws-cdk/aws-logs'); +import s3 = require('@aws-cdk/aws-s3'); +import secretsmanager = require('@aws-cdk/aws-secretsmanager'); +import ssm = require('@aws-cdk/aws-ssm'); +import targets = require('@aws-cdk/aws-events-targets'); +import path = require('path'); + +class Fixture extends Stack { + constructor(scope: Construct, id: string) { + super(scope, id); + + /// here + } +} diff --git a/packages/@aws-cdk/aws-ecs/test/cluster.test.ts b/packages/@aws-cdk/aws-ecs/test/cluster.test.ts index 52de16b353137..594a59d0380a0 100644 --- a/packages/@aws-cdk/aws-ecs/test/cluster.test.ts +++ b/packages/@aws-cdk/aws-ecs/test/cluster.test.ts @@ -2142,3 +2142,107 @@ describe('cluster', () => { }); }); + +test('can add ASG capacity via Capacity Provider by not specifying machineImageType', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'test'); + const vpc = new ec2.Vpc(stack, 'Vpc'); + const cluster = new ecs.Cluster(stack, 'EcsCluster'); + + const autoScalingGroupAl2 = new autoscaling.AutoScalingGroup(stack, 'asgal2', { + vpc, + instanceType: new ec2.InstanceType('bogus'), + machineImage: ecs.EcsOptimizedImage.amazonLinux2(), + }); + + const autoScalingGroupBottlerocket = new autoscaling.AutoScalingGroup(stack, 'asgBottlerocket', { + vpc, + instanceType: new ec2.InstanceType('bogus'), + machineImage: new ecs.BottleRocketImage(), + }); + + // WHEN + const capacityProviderAl2 = new ecs.AsgCapacityProvider(stack, 'provideral2', { + autoScalingGroup: autoScalingGroupAl2, + enableManagedTerminationProtection: false, + }); + + const capacityProviderBottlerocket = new ecs.AsgCapacityProvider(stack, 'providerBottlerocket', { + autoScalingGroup: autoScalingGroupBottlerocket, + enableManagedTerminationProtection: false, + machineImageType: ecs.MachineImageType.BOTTLEROCKET, + }); + + cluster.enableFargateCapacityProviders(); + + // Ensure not added twice + cluster.addAsgCapacityProvider(capacityProviderAl2); + cluster.addAsgCapacityProvider(capacityProviderAl2); + + // Add Bottlerocket ASG Capacity Provider + cluster.addAsgCapacityProvider(capacityProviderBottlerocket); + + + // THEN Bottlerocket LaunchConfiguration + expect(stack).toHaveResource('AWS::AutoScaling::LaunchConfiguration', { + ImageId: { + Ref: 'SsmParameterValueawsservicebottlerocketawsecs1x8664latestimageidC96584B6F00A464EAD1953AFF4B05118Parameter', + + }, + UserData: { + 'Fn::Base64': { + 'Fn::Join': [ + '', + [ + '\n[settings.ecs]\ncluster = \"', + { + Ref: 'EcsCluster97242B84', + }, + '\"', + ], + ], + }, + }, + }); + + // THEN AmazonLinux2 LaunchConfiguration + expect(stack).toHaveResource('AWS::AutoScaling::LaunchConfiguration', { + ImageId: { + Ref: 'SsmParameterValueawsserviceecsoptimizedamiamazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter', + }, + UserData: { + 'Fn::Base64': { + 'Fn::Join': [ + '', + [ + '#!/bin/bash\necho ECS_CLUSTER=', + { + Ref: 'EcsCluster97242B84', + + }, + ' >> /etc/ecs/ecs.config\nsudo iptables --insert FORWARD 1 --in-interface docker+ --destination 169.254.169.254/32 --jump DROP\nsudo service iptables save\necho ECS_AWSVPC_BLOCK_IMDS=true >> /etc/ecs/ecs.config', + ], + ], + }, + }, + }); + + expect(stack).toHaveResource('AWS::ECS::ClusterCapacityProviderAssociations', { + CapacityProviders: [ + 'FARGATE', + 'FARGATE_SPOT', + { + Ref: 'provideral2A427CBC0', + }, + { + Ref: 'providerBottlerocket90C039FA', + }, + ], + Cluster: { + Ref: 'EcsCluster97242B84', + }, + DefaultCapacityProviderStrategy: [], + }); + +}); \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ecs/test/container-definition.test.ts b/packages/@aws-cdk/aws-ecs/test/container-definition.test.ts index b5c60ae1c5c0c..a5153b82d331a 100644 --- a/packages/@aws-cdk/aws-ecs/test/container-definition.test.ts +++ b/packages/@aws-cdk/aws-ecs/test/container-definition.test.ts @@ -5,9 +5,9 @@ import * as ecr_assets from '@aws-cdk/aws-ecr-assets'; import * as s3 from '@aws-cdk/aws-s3'; import * as secretsmanager from '@aws-cdk/aws-secretsmanager'; import * as ssm from '@aws-cdk/aws-ssm'; +import { testFutureBehavior } from '@aws-cdk/cdk-build-tools/lib/feature-flag'; import * as cdk from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; -import { testFutureBehavior } from 'cdk-build-tools/lib/feature-flag'; import * as ecs from '../lib'; describe('container definition', () => { diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/ec2-service.test.ts b/packages/@aws-cdk/aws-ecs/test/ec2/ec2-service.test.ts index 48da04142ff3c..21d4292346974 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/ec2-service.test.ts +++ b/packages/@aws-cdk/aws-ecs/test/ec2/ec2-service.test.ts @@ -3292,6 +3292,8 @@ describe('ec2 service', () => { expect(service.serviceArn).toEqual('arn:aws:ecs:us-west-2:123456789012:service/my-http-service'); expect(service.serviceName).toEqual('my-http-service'); + expect(service.env.account).toEqual('123456789012'); + expect(service.env.region).toEqual('us-west-2'); }); diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/ec2-task-definition.test.ts b/packages/@aws-cdk/aws-ecs/test/ec2/ec2-task-definition.test.ts index 793dff5c3b97b..966473e5cc6cb 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/ec2-task-definition.test.ts +++ b/packages/@aws-cdk/aws-ecs/test/ec2/ec2-task-definition.test.ts @@ -5,9 +5,9 @@ import { Repository } from '@aws-cdk/aws-ecr'; import * as iam from '@aws-cdk/aws-iam'; import * as secretsmanager from '@aws-cdk/aws-secretsmanager'; import * as ssm from '@aws-cdk/aws-ssm'; +import { testFutureBehavior } from '@aws-cdk/cdk-build-tools/lib/feature-flag'; import * as cdk from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; -import { testFutureBehavior } from 'cdk-build-tools/lib/feature-flag'; import * as ecs from '../../lib'; describe('ec2 task definition', () => { diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.environment-file.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.environment-file.expected.json index b26608d3626bf..eee0801d80061 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.environment-file.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.environment-file.expected.json @@ -1267,7 +1267,7 @@ "Ref": "EnvFileDeploymentAwsCliLayerA8FC897D" } ], - "Runtime": "python3.6", + "Runtime": "python3.7", "Timeout": 900 }, "DependsOn": [ diff --git a/packages/@aws-cdk/aws-ecs/test/fargate/fargate-service.test.ts b/packages/@aws-cdk/aws-ecs/test/fargate/fargate-service.test.ts index ef4ceae4ccedc..71866a116443f 100644 --- a/packages/@aws-cdk/aws-ecs/test/fargate/fargate-service.test.ts +++ b/packages/@aws-cdk/aws-ecs/test/fargate/fargate-service.test.ts @@ -2124,6 +2124,8 @@ describe('fargate service', () => { expect(service.serviceArn).toEqual('arn:aws:ecs:us-west-2:123456789012:service/my-http-service'); expect(service.serviceName).toEqual('my-http-service'); + expect(service.env.account).toEqual('123456789012'); + expect(service.env.region).toEqual('us-west-2'); }); diff --git a/packages/@aws-cdk/aws-efs/.eslintrc.js b/packages/@aws-cdk/aws-efs/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-efs/.eslintrc.js +++ b/packages/@aws-cdk/aws-efs/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-efs/jest.config.js b/packages/@aws-cdk/aws-efs/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-efs/jest.config.js +++ b/packages/@aws-cdk/aws-efs/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-efs/package.json b/packages/@aws-cdk/aws-efs/package.json index d6dbf8bce203b..e97a3d99e8fd6 100644 --- a/packages/@aws-cdk/aws-efs/package.json +++ b/packages/@aws-cdk/aws-efs/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::EFS", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,12 +72,12 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/aws-ec2": "0.0.0", @@ -91,12 +90,12 @@ }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { - "@aws-cdk/core": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", - "@aws-cdk/cx-api": "0.0.0", "@aws-cdk/cloud-assembly-schema": "0.0.0", + "@aws-cdk/core": "0.0.0", + "@aws-cdk/cx-api": "0.0.0", "constructs": "^3.3.69" }, "engines": { diff --git a/packages/@aws-cdk/aws-efs/test/efs-file-system.test.ts b/packages/@aws-cdk/aws-efs/test/efs-file-system.test.ts index 60a0133e63ca2..b417ff5bf106c 100644 --- a/packages/@aws-cdk/aws-efs/test/efs-file-system.test.ts +++ b/packages/@aws-cdk/aws-efs/test/efs-file-system.test.ts @@ -4,7 +4,7 @@ import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; import { App, RemovalPolicy, Size, Stack, Tags } from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; -import { testFutureBehavior, testLegacyBehavior } from 'cdk-build-tools/lib/feature-flag'; +import { testFutureBehavior, testLegacyBehavior } from '@aws-cdk/cdk-build-tools/lib/feature-flag'; import { FileSystem, LifecyclePolicy, PerformanceMode, ThroughputMode } from '../lib'; let stack = new Stack(); @@ -42,7 +42,7 @@ testLegacyBehavior('when @aws-cdk/aws-efs:defaultEncryptionAtRest is missing, en }); Template.fromStack(customStack).hasResourceProperties('AWS::EFS::FileSystem', { - Encrypted: Match.absentProperty(), + Encrypted: Match.absent(), }); }); diff --git a/packages/@aws-cdk/aws-eks-legacy/.eslintrc.js b/packages/@aws-cdk/aws-eks-legacy/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-eks-legacy/.eslintrc.js +++ b/packages/@aws-cdk/aws-eks-legacy/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-eks-legacy/jest.config.js b/packages/@aws-cdk/aws-eks-legacy/jest.config.js index cd664e1d069e5..34818e1593f6b 100644 --- a/packages/@aws-cdk/aws-eks-legacy/jest.config.js +++ b/packages/@aws-cdk/aws-eks-legacy/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +const baseConfig = require('../../../tools/@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-eks-legacy/package.json b/packages/@aws-cdk/aws-eks-legacy/package.json index 1494c1d93020f..66251dac2e6ee 100644 --- a/packages/@aws-cdk/aws-eks-legacy/package.json +++ b/packages/@aws-cdk/aws-eks-legacy/package.json @@ -55,8 +55,7 @@ "build+test+extract": "yarn build+test && yarn rosetta:extract" }, "cdk-build": { - "cloudformation": "AWS::EKS", - "jest": true + "cloudformation": "AWS::EKS" }, "keywords": [ "aws", @@ -71,13 +70,13 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-autoscaling": "0.0.0", diff --git a/packages/@aws-cdk/aws-eks/.eslintrc.js b/packages/@aws-cdk/aws-eks/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-eks/.eslintrc.js +++ b/packages/@aws-cdk/aws-eks/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-eks/.npmignore b/packages/@aws-cdk/aws-eks/.npmignore index e8acf10a468a1..8f3952dca3211 100644 --- a/packages/@aws-cdk/aws-eks/.npmignore +++ b/packages/@aws-cdk/aws-eks/.npmignore @@ -25,4 +25,7 @@ tsconfig.json junit.xml test/ !*.lit.ts -jest.config.js \ No newline at end of file +jest.config.js + +# Don't include lambda node_modules. These are installed at build time. +lib/cluster-resource-handler/node_modules diff --git a/packages/@aws-cdk/aws-eks/README.md b/packages/@aws-cdk/aws-eks/README.md index 1437446e6640a..3b04f5d9e7f61 100644 --- a/packages/@aws-cdk/aws-eks/README.md +++ b/packages/@aws-cdk/aws-eks/README.md @@ -372,6 +372,18 @@ const asg = new ec2.AutoScalingGroup(...); cluster.connectAutoScalingGroupCapacity(asg); ``` +To connect a self-managed node group to an imported cluster, use the `cluster.connectAutoScalingGroupCapacity()` method: + +```ts +const importedCluster = eks.Cluster.fromClusterAttributes(stack, 'ImportedCluster', { + clusterName: cluster.clusterName, + clusterSecurityGroupId: cluster.clusterSecurityGroupId, +}); + +const asg = new ec2.AutoScalingGroup(...); +importedCluster.connectAutoScalingGroupCapacity(asg); +``` + In both cases, the [cluster security group](https://docs.aws.amazon.com/eks/latest/userguide/sec-group-reqs.html#cluster-sg) will be automatically attached to the auto-scaling group, allowing for traffic to flow freely between managed and self-managed nodes. diff --git a/packages/@aws-cdk/aws-eks/jest.config.js b/packages/@aws-cdk/aws-eks/jest.config.js index cd664e1d069e5..34818e1593f6b 100644 --- a/packages/@aws-cdk/aws-eks/jest.config.js +++ b/packages/@aws-cdk/aws-eks/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +const baseConfig = require('../../../tools/@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-eks/lib/cluster-resource-handler/cluster.ts b/packages/@aws-cdk/aws-eks/lib/cluster-resource-handler/cluster.ts index 4dc909113ac91..61a33ddb3ab05 100644 --- a/packages/@aws-cdk/aws-eks/lib/cluster-resource-handler/cluster.ts +++ b/packages/@aws-cdk/aws-eks/lib/cluster-resource-handler/cluster.ts @@ -1,5 +1,6 @@ /* eslint-disable no-console */ +// eslint-disable-next-line import/no-extraneous-dependencies import { IsCompleteResponse, OnEventResponse } from '@aws-cdk/custom-resources/lib/provider-framework/types'; // eslint-disable-next-line import/no-extraneous-dependencies import * as aws from 'aws-sdk'; @@ -23,7 +24,7 @@ export class ClusterResourceHandler extends ResourceHandler { super(eks, event); this.newProps = parseProps(this.event.ResourceProperties); - this.oldProps = event.RequestType === 'Update' ? parseProps(event.OldResourceProperties) : { }; + this.oldProps = event.RequestType === 'Update' ? parseProps(event.OldResourceProperties) : {}; } // ------ @@ -271,16 +272,16 @@ export class ClusterResourceHandler extends ResourceHandler { function parseProps(props: any): aws.EKS.CreateClusterRequest { - const parsed = props?.Config ?? { }; + const parsed = props?.Config ?? {}; // this is weird but these boolean properties are passed by CFN as a string, and we need them to be booleanic for the SDK. // Otherwise it fails with 'Unexpected Parameter: params.resourcesVpcConfig.endpointPrivateAccess is expected to be a boolean' - if (typeof(parsed.resourcesVpcConfig?.endpointPrivateAccess) === 'string') { + if (typeof (parsed.resourcesVpcConfig?.endpointPrivateAccess) === 'string') { parsed.resourcesVpcConfig.endpointPrivateAccess = parsed.resourcesVpcConfig.endpointPrivateAccess === 'true'; } - if (typeof(parsed.resourcesVpcConfig?.endpointPublicAccess) === 'string') { + if (typeof (parsed.resourcesVpcConfig?.endpointPublicAccess) === 'string') { parsed.resourcesVpcConfig.endpointPublicAccess = parsed.resourcesVpcConfig.endpointPublicAccess === 'true'; } @@ -303,13 +304,13 @@ function analyzeUpdate(oldProps: Partial, newProps console.log('old props: ', JSON.stringify(oldProps)); console.log('new props: ', JSON.stringify(newProps)); - const newVpcProps = newProps.resourcesVpcConfig || { }; - const oldVpcProps = oldProps.resourcesVpcConfig || { }; + const newVpcProps = newProps.resourcesVpcConfig || {}; + const oldVpcProps = oldProps.resourcesVpcConfig || {}; const oldPublicAccessCidrs = new Set(oldVpcProps.publicAccessCidrs ?? []); const newPublicAccessCidrs = new Set(newVpcProps.publicAccessCidrs ?? []); - const newEnc = newProps.encryptionConfig || { }; - const oldEnc = oldProps.encryptionConfig || { }; + const newEnc = newProps.encryptionConfig || {}; + const oldEnc = oldProps.encryptionConfig || {}; return { replaceName: newProps.name !== oldProps.name, @@ -329,4 +330,4 @@ function analyzeUpdate(oldProps: Partial, newProps function setsEqual(first: Set, second: Set) { return first.size === second.size || [...first].every((e: string) => second.has(e)); -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-eks/lib/cluster-resource-handler/common.ts b/packages/@aws-cdk/aws-eks/lib/cluster-resource-handler/common.ts index 7383689e4a95a..8f563de833bf6 100644 --- a/packages/@aws-cdk/aws-eks/lib/cluster-resource-handler/common.ts +++ b/packages/@aws-cdk/aws-eks/lib/cluster-resource-handler/common.ts @@ -1,3 +1,4 @@ +// eslint-disable-next-line import/no-extraneous-dependencies import { IsCompleteResponse, OnEventResponse } from '@aws-cdk/custom-resources/lib/provider-framework/types'; // eslint-disable-next-line import/no-extraneous-dependencies @@ -40,6 +41,12 @@ export abstract class ResourceHandler { } public onEvent() { + // eslint-disable-next-line @typescript-eslint/no-require-imports, import/no-extraneous-dependencies + const ProxyAgent: any = require('proxy-agent'); + aws.config.update({ + httpOptions: { agent: new ProxyAgent() }, + }); + switch (this.requestType) { case 'Create': return this.onCreate(); case 'Update': return this.onUpdate(); diff --git a/packages/@aws-cdk/aws-eks/lib/cluster-resource-handler/index.ts b/packages/@aws-cdk/aws-eks/lib/cluster-resource-handler/index.ts index d1be0c12e1e38..e7fc357846259 100644 --- a/packages/@aws-cdk/aws-eks/lib/cluster-resource-handler/index.ts +++ b/packages/@aws-cdk/aws-eks/lib/cluster-resource-handler/index.ts @@ -1,5 +1,5 @@ /* eslint-disable no-console */ - +// eslint-disable-next-line import/no-extraneous-dependencies import { IsCompleteResponse } from '@aws-cdk/custom-resources/lib/provider-framework/types'; // eslint-disable-next-line import/no-extraneous-dependencies import * as aws from 'aws-sdk'; @@ -57,4 +57,4 @@ function createResourceHandler(event: AWSLambda.CloudFormationCustomResourceEven default: throw new Error(`Unsupported resource type "${event.ResourceType}`); } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-eks/lib/cluster-resource-provider.ts b/packages/@aws-cdk/aws-eks/lib/cluster-resource-provider.ts index 12839a3ee6044..f425b0a1eaba6 100644 --- a/packages/@aws-cdk/aws-eks/lib/cluster-resource-provider.ts +++ b/packages/@aws-cdk/aws-eks/lib/cluster-resource-provider.ts @@ -4,6 +4,7 @@ import * as iam from '@aws-cdk/aws-iam'; import * as lambda from '@aws-cdk/aws-lambda'; import { Duration, NestedStack, Stack } from '@aws-cdk/core'; import * as cr from '@aws-cdk/custom-resources'; +import { NodeProxyAgentLayer } from '@aws-cdk/lambda-layer-node-proxy-agent'; import { Construct } from 'constructs'; // v2 - keep this import as a separate section to reduce merge conflict when forward merging with the v2 branch. @@ -33,6 +34,13 @@ export interface ClusterResourceProviderProps { * Environment to add to the handler. */ readonly environment?: { [key: string]: string }; + + /** + * An AWS Lambda layer that includes the NPM dependency `proxy-agent`. + * + * If not defined, a default layer will be used. + */ + readonly onEventLayer?: lambda.ILayerVersion; } /** @@ -69,6 +77,14 @@ export class ClusterResourceProvider extends NestedStack { vpcSubnets: props.subnets ? { subnets: props.subnets } : undefined, }); + // Allow user to customize the layer + if (!props.onEventLayer) { + // `NodeProxyAgentLayer` provides `proxy-agent` which is needed to configure `aws-sdk-js` with a user provided proxy. + onEvent.addLayers(new NodeProxyAgentLayer(this, 'NodeProxyAgentLayer')); + } else { + onEvent.addLayers(props.onEventLayer); + } + const isComplete = new lambda.Function(this, 'IsCompleteHandler', { code: lambda.Code.fromAsset(HANDLER_DIR), description: 'isComplete handler for EKS cluster resource provider', @@ -96,4 +112,4 @@ export class ClusterResourceProvider extends NestedStack { * The custom resource service token for this provider. */ public get serviceToken() { return this.provider.serviceToken; } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-eks/lib/cluster-resource.ts b/packages/@aws-cdk/aws-eks/lib/cluster-resource.ts index e134601aef73d..662f4e345a24c 100644 --- a/packages/@aws-cdk/aws-eks/lib/cluster-resource.ts +++ b/packages/@aws-cdk/aws-eks/lib/cluster-resource.ts @@ -1,6 +1,7 @@ import * as ec2 from '@aws-cdk/aws-ec2'; import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; +import * as lambda from '@aws-cdk/aws-lambda'; import { ArnComponents, CustomResource, Token, Stack, Lazy } from '@aws-cdk/core'; import { Construct } from 'constructs'; import { CLUSTER_RESOURCE_TYPE } from './cluster-resource-handler/consts'; @@ -24,6 +25,7 @@ export interface ClusterResourceProps { readonly environment?: { [key: string]: string }; readonly subnets?: ec2.ISubnet[]; readonly secretsEncryptionKey?: kms.IKey; + readonly onEventLayer?: lambda.ILayerVersion; } /** @@ -62,6 +64,7 @@ export class ClusterResource extends CoreConstruct { subnets: props.subnets, vpc: props.vpc, environment: props.environment, + onEventLayer: props.onEventLayer, }); const resource = new CustomResource(this, 'Resource', { diff --git a/packages/@aws-cdk/aws-eks/lib/cluster.ts b/packages/@aws-cdk/aws-eks/lib/cluster.ts index 009a79ecdb8ce..2db0438537f97 100644 --- a/packages/@aws-cdk/aws-eks/lib/cluster.ts +++ b/packages/@aws-cdk/aws-eks/lib/cluster.ts @@ -129,6 +129,13 @@ export interface ICluster extends IResource, ec2.IConnectable { */ readonly kubectlMemory?: Size; + /** + * An AWS Lambda layer that includes the NPM dependency `proxy-agent`. + * + * If not defined, a default layer will be used. + */ + readonly onEventLayer?: lambda.ILayerVersion; + /** * Indicates whether Kubernetes resources can be automatically pruned. When * this is enabled (default), prune labels will be allocated and injected to @@ -174,6 +181,27 @@ export interface ICluster extends IResource, ec2.IConnectable { */ addCdk8sChart(id: string, chart: Construct): KubernetesManifest; + /** + * Connect capacity in the form of an existing AutoScalingGroup to the EKS cluster. + * + * The AutoScalingGroup must be running an EKS-optimized AMI containing the + * /etc/eks/bootstrap.sh script. This method will configure Security Groups, + * add the right policies to the instance role, apply the right tags, and add + * the required user data to the instance's launch configuration. + * + * Spot instances will be labeled `lifecycle=Ec2Spot` and tainted with `PreferNoSchedule`. + * If kubectl is enabled, the + * [spot interrupt handler](https://github.com/awslabs/ec2-spot-labs/tree/master/ec2-spot-eks-solution/spot-termination-handler) + * daemon will be installed on all spot instances to handle + * [EC2 Spot Instance Termination Notices](https://aws.amazon.com/blogs/aws/new-ec2-spot-instance-termination-notices/). + * + * Prefer to use `addAutoScalingGroupCapacity` if possible. + * + * @see https://docs.aws.amazon.com/eks/latest/userguide/launch-workers.html + * @param autoScalingGroup [disable-awslint:ref-via-interface] + * @param options options for adding auto scaling groups, like customizing the bootstrap script + */ + connectAutoScalingGroupCapacity(autoScalingGroup: autoscaling.AutoScalingGroup, options: AutoScalingGroupOptions): void; } /** @@ -281,6 +309,18 @@ export interface ClusterAttributes { */ readonly kubectlMemory?: Size; + /** + * An AWS Lambda Layer which includes the NPM dependency `proxy-agent`. This layer + * is used by the onEvent handler to route AWS SDK requests through a proxy. + * + * The handler expects the layer to include the following node_modules: + * + * proxy-agent + * + * @default - a layer bundled with this module. + */ + readonly onEventLayer?: lambda.ILayerVersion; + /** * Indicates whether Kubernetes resources added through `addManifest()` can be * automatically pruned. When this is enabled (default), prune labels will be @@ -450,6 +490,30 @@ export interface ClusterOptions extends CommonClusterOptions { */ readonly kubectlMemory?: Size; + /** + * An AWS Lambda Layer which includes the NPM dependency `proxy-agent`. + * + * By default, the provider will use the layer included in the + * "aws-lambda-layer-node-proxy-agent" SAR application which is available in all + * commercial regions. + * + * To deploy the layer locally, visit + * https://github.com/aws-samples/aws-lambda-layer-node-proxy-agent/blob/master/cdk/README.md + * for instructions on how to prepare the .zip file and then define it in your + * app as follows: + * + * ```ts + * const layer = new lambda.LayerVersion(this, 'node-proxy-agent-layer', { + * code: lambda.Code.fromAsset(`${__dirname}/layer.zip`)), + * compatibleRuntimes: [lambda.Runtime.NODEJS_14_X] + * }) + * ``` + * + * @default - the layer provided by the `aws-lambda-layer-node-proxy-agent` SAR app. + * @see https://github.com/aws-samples/aws-lambda-layer-node-proxy-agent + */ + readonly onEventLayer?: lambda.ILayerVersion; + /** * Indicates whether Kubernetes resources added through `addManifest()` can be * automatically pruned. When this is enabled (default), prune labels will be @@ -678,6 +742,16 @@ abstract class ClusterBase extends Resource implements ICluster { public abstract readonly kubectlMemory?: Size; public abstract readonly prune: boolean; public abstract readonly openIdConnectProvider: iam.IOpenIdConnectProvider; + public abstract readonly awsAuth: AwsAuth; + + private _spotInterruptHandler?: HelmChart; + + /** + * Manages the aws-auth config map. + * + * @internal + */ + protected _awsAuth?: AwsAuth; /** * Defines a Kubernetes resource in this cluster. @@ -728,6 +802,124 @@ abstract class ClusterBase extends Resource implements ICluster { cluster: this, }); } + + /** + * Installs the AWS spot instance interrupt handler on the cluster if it's not + * already added. + */ + private addSpotInterruptHandler() { + if (!this._spotInterruptHandler) { + this._spotInterruptHandler = this.addHelmChart('spot-interrupt-handler', { + chart: 'aws-node-termination-handler', + version: '0.13.2', + repository: 'https://aws.github.io/eks-charts', + namespace: 'kube-system', + values: { + nodeSelector: { + lifecycle: LifecycleLabel.SPOT, + }, + }, + }); + } + + return this._spotInterruptHandler; + } + + /** + * Connect capacity in the form of an existing AutoScalingGroup to the EKS cluster. + * + * The AutoScalingGroup must be running an EKS-optimized AMI containing the + * /etc/eks/bootstrap.sh script. This method will configure Security Groups, + * add the right policies to the instance role, apply the right tags, and add + * the required user data to the instance's launch configuration. + * + * Spot instances will be labeled `lifecycle=Ec2Spot` and tainted with `PreferNoSchedule`. + * If kubectl is enabled, the + * [spot interrupt handler](https://github.com/awslabs/ec2-spot-labs/tree/master/ec2-spot-eks-solution/spot-termination-handler) + * daemon will be installed on all spot instances to handle + * [EC2 Spot Instance Termination Notices](https://aws.amazon.com/blogs/aws/new-ec2-spot-instance-termination-notices/). + * + * Prefer to use `addAutoScalingGroupCapacity` if possible. + * + * @see https://docs.aws.amazon.com/eks/latest/userguide/launch-workers.html + * @param autoScalingGroup [disable-awslint:ref-via-interface] + * @param options options for adding auto scaling groups, like customizing the bootstrap script + */ + public connectAutoScalingGroupCapacity(autoScalingGroup: autoscaling.AutoScalingGroup, options: AutoScalingGroupOptions) { + // self rules + autoScalingGroup.connections.allowInternally(ec2.Port.allTraffic()); + + // Cluster to:nodes rules + autoScalingGroup.connections.allowFrom(this, ec2.Port.tcp(443)); + autoScalingGroup.connections.allowFrom(this, ec2.Port.tcpRange(1025, 65535)); + + // Allow HTTPS from Nodes to Cluster + autoScalingGroup.connections.allowTo(this, ec2.Port.tcp(443)); + + // Allow all node outbound traffic + autoScalingGroup.connections.allowToAnyIpv4(ec2.Port.allTcp()); + autoScalingGroup.connections.allowToAnyIpv4(ec2.Port.allUdp()); + autoScalingGroup.connections.allowToAnyIpv4(ec2.Port.allIcmp()); + + // allow traffic to/from managed node groups (eks attaches this security group to the managed nodes) + autoScalingGroup.addSecurityGroup(this.clusterSecurityGroup); + + const bootstrapEnabled = options.bootstrapEnabled ?? true; + if (options.bootstrapOptions && !bootstrapEnabled) { + throw new Error('Cannot specify "bootstrapOptions" if "bootstrapEnabled" is false'); + } + + if (bootstrapEnabled) { + const userData = options.machineImageType === MachineImageType.BOTTLEROCKET ? + renderBottlerocketUserData(this) : + renderAmazonLinuxUserData(this, autoScalingGroup, options.bootstrapOptions); + autoScalingGroup.addUserData(...userData); + } + + autoScalingGroup.role.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('AmazonEKSWorkerNodePolicy')); + autoScalingGroup.role.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('AmazonEKS_CNI_Policy')); + autoScalingGroup.role.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('AmazonEC2ContainerRegistryReadOnly')); + + // EKS Required Tags + // https://docs.aws.amazon.com/eks/latest/userguide/worker.html + Tags.of(autoScalingGroup).add(`kubernetes.io/cluster/${this.clusterName}`, 'owned', { + applyToLaunchedInstances: true, + // exclude security groups to avoid multiple "owned" security groups. + // (the cluster security group already has this tag) + excludeResourceTypes: ['AWS::EC2::SecurityGroup'], + }); + + // do not attempt to map the role if `kubectl` is not enabled for this + // cluster or if `mapRole` is set to false. By default this should happen. + let mapRole = options.mapRole ?? true; + if (mapRole && !(this instanceof Cluster)) { + // do the mapping... + Annotations.of(autoScalingGroup).addWarning('Auto-mapping aws-auth role for imported cluster is not supported, please map role manually'); + mapRole = false; + } + if (mapRole) { + // see https://docs.aws.amazon.com/en_us/eks/latest/userguide/add-user-role.html + this.awsAuth.addRoleMapping(autoScalingGroup.role, { + username: 'system:node:{{EC2PrivateDNSName}}', + groups: [ + 'system:bootstrappers', + 'system:nodes', + ], + }); + } else { + // since we are not mapping the instance role to RBAC, synthesize an + // output so it can be pasted into `aws-auth-cm.yaml` + new CfnOutput(autoScalingGroup, 'InstanceRoleARN', { + value: autoScalingGroup.role.roleArn, + }); + } + + const addSpotInterruptHandler = options.spotInterruptHandler ?? true; + // if this is an ASG with spot instances, install the spot interrupt handler (only if kubectl is enabled). + if (autoScalingGroup.spotPrice && addSpotInterruptHandler) { + this.addSpotInterruptHandler(); + } + } } /** @@ -898,6 +1090,12 @@ export class Cluster extends ClusterBase { */ public readonly kubectlMemory?: Size; + /** + * The AWS Lambda layer that contains the NPM dependency `proxy-agent`. If + * undefined, a SAR app that contains this layer will be used. + */ + public readonly onEventLayer?: lambda.ILayerVersion; + /** * Determines if Kubernetes resources can be pruned automatically. */ @@ -910,13 +1108,6 @@ export class Cluster extends ClusterBase { */ private readonly _clusterResource: ClusterResource; - /** - * Manages the aws-auth config map. - */ - private _awsAuth?: AwsAuth; - - private _spotInterruptHandler?: HelmChart; - private _neuronDevicePlugin?: KubernetesManifest; private readonly endpointAccess: EndpointAccess; @@ -988,6 +1179,7 @@ export class Cluster extends ClusterBase { this.endpointAccess = props.endpointAccess ?? EndpointAccess.PUBLIC_AND_PRIVATE; this.kubectlEnvironment = props.kubectlEnvironment; this.kubectlLayer = props.kubectlLayer; + this.onEventLayer = props.onEventLayer; this.kubectlMemory = props.kubectlMemory; const privateSubents = this.selectPrivateSubnets().slice(0, 16); @@ -1037,6 +1229,7 @@ export class Cluster extends ClusterBase { secretsEncryptionKey: props.secretsEncryptionKey, vpc: this.vpc, subnets: placeClusterHandlerInVpc ? privateSubents : undefined, + onEventLayer: this.onEventLayer, }); if (this.endpointAccess._config.privateAccess && privateSubents.length !== 0) { @@ -1227,97 +1420,6 @@ export class Cluster extends ClusterBase { }); } - /** - * Connect capacity in the form of an existing AutoScalingGroup to the EKS cluster. - * - * The AutoScalingGroup must be running an EKS-optimized AMI containing the - * /etc/eks/bootstrap.sh script. This method will configure Security Groups, - * add the right policies to the instance role, apply the right tags, and add - * the required user data to the instance's launch configuration. - * - * Spot instances will be labeled `lifecycle=Ec2Spot` and tainted with `PreferNoSchedule`. - * If kubectl is enabled, the - * [spot interrupt handler](https://github.com/awslabs/ec2-spot-labs/tree/master/ec2-spot-eks-solution/spot-termination-handler) - * daemon will be installed on all spot instances to handle - * [EC2 Spot Instance Termination Notices](https://aws.amazon.com/blogs/aws/new-ec2-spot-instance-termination-notices/). - * - * Prefer to use `addAutoScalingGroupCapacity` if possible. - * - * @see https://docs.aws.amazon.com/eks/latest/userguide/launch-workers.html - * @param autoScalingGroup [disable-awslint:ref-via-interface] - * @param options options for adding auto scaling groups, like customizing the bootstrap script - */ - public connectAutoScalingGroupCapacity(autoScalingGroup: autoscaling.AutoScalingGroup, options: AutoScalingGroupOptions) { - // self rules - autoScalingGroup.connections.allowInternally(ec2.Port.allTraffic()); - - // Cluster to:nodes rules - autoScalingGroup.connections.allowFrom(this, ec2.Port.tcp(443)); - autoScalingGroup.connections.allowFrom(this, ec2.Port.tcpRange(1025, 65535)); - - // Allow HTTPS from Nodes to Cluster - autoScalingGroup.connections.allowTo(this, ec2.Port.tcp(443)); - - // Allow all node outbound traffic - autoScalingGroup.connections.allowToAnyIpv4(ec2.Port.allTcp()); - autoScalingGroup.connections.allowToAnyIpv4(ec2.Port.allUdp()); - autoScalingGroup.connections.allowToAnyIpv4(ec2.Port.allIcmp()); - - // allow traffic to/from managed node groups (eks attaches this security group to the managed nodes) - autoScalingGroup.addSecurityGroup(this.clusterSecurityGroup); - - const bootstrapEnabled = options.bootstrapEnabled ?? true; - if (options.bootstrapOptions && !bootstrapEnabled) { - throw new Error('Cannot specify "bootstrapOptions" if "bootstrapEnabled" is false'); - } - - if (bootstrapEnabled) { - const userData = options.machineImageType === MachineImageType.BOTTLEROCKET ? - renderBottlerocketUserData(this) : - renderAmazonLinuxUserData(this, autoScalingGroup, options.bootstrapOptions); - autoScalingGroup.addUserData(...userData); - } - - autoScalingGroup.role.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('AmazonEKSWorkerNodePolicy')); - autoScalingGroup.role.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('AmazonEKS_CNI_Policy')); - autoScalingGroup.role.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('AmazonEC2ContainerRegistryReadOnly')); - - // EKS Required Tags - // https://docs.aws.amazon.com/eks/latest/userguide/worker.html - Tags.of(autoScalingGroup).add(`kubernetes.io/cluster/${this.clusterName}`, 'owned', { - applyToLaunchedInstances: true, - // exclude security groups to avoid multiple "owned" security groups. - // (the cluster security group already has this tag) - excludeResourceTypes: ['AWS::EC2::SecurityGroup'], - }); - - // do not attempt to map the role if `kubectl` is not enabled for this - // cluster or if `mapRole` is set to false. By default this should happen. - const mapRole = options.mapRole ?? true; - if (mapRole) { - // see https://docs.aws.amazon.com/en_us/eks/latest/userguide/add-user-role.html - this.awsAuth.addRoleMapping(autoScalingGroup.role, { - username: 'system:node:{{EC2PrivateDNSName}}', - groups: [ - 'system:bootstrappers', - 'system:nodes', - ], - }); - } else { - // since we are not mapping the instance role to RBAC, synthesize an - // output so it can be pasted into `aws-auth-cm.yaml` - new CfnOutput(autoScalingGroup, 'InstanceRoleARN', { - value: autoScalingGroup.role.roleArn, - }); - } - - const addSpotInterruptHandler = options.spotInterruptHandler ?? true; - // if this is an ASG with spot instances, install the spot interrupt handler (only if kubectl is enabled). - if (autoScalingGroup.spotPrice && addSpotInterruptHandler) { - this.addSpotInterruptHandler(); - } - } - /** * Lazily creates the AwsAuth resource, which manages AWS authentication mapping. */ @@ -1458,28 +1560,6 @@ export class Cluster extends ClusterBase { return privateSubnets; } - /** - * Installs the AWS spot instance interrupt handler on the cluster if it's not - * already added. - */ - private addSpotInterruptHandler() { - if (!this._spotInterruptHandler) { - this._spotInterruptHandler = this.addHelmChart('spot-interrupt-handler', { - chart: 'aws-node-termination-handler', - version: '0.13.2', - repository: 'https://aws.github.io/eks-charts', - namespace: 'kube-system', - values: { - nodeSelector: { - lifecycle: LifecycleLabel.SPOT, - }, - }, - }); - } - - return this._spotInterruptHandler; - } - /** * Installs the Neuron device plugin on the cluster if it's not * already added. @@ -1735,6 +1815,7 @@ class ImportedCluster extends ClusterBase { public readonly kubectlSecurityGroup?: ec2.ISecurityGroup | undefined; public readonly kubectlPrivateSubnets?: ec2.ISubnet[] | undefined; public readonly kubectlLayer?: lambda.ILayerVersion; + public readonly onEventLayer?: lambda.ILayerVersion; public readonly kubectlMemory?: Size; public readonly prune: boolean; @@ -1752,6 +1833,7 @@ class ImportedCluster extends ClusterBase { this.kubectlEnvironment = props.kubectlEnvironment; this.kubectlPrivateSubnets = props.kubectlPrivateSubnetIds ? props.kubectlPrivateSubnetIds.map((subnetid, index) => ec2.Subnet.fromSubnetId(this, `KubectlSubnet${index}`, subnetid)) : undefined; this.kubectlLayer = props.kubectlLayer; + this.onEventLayer = props.onEventLayer; this.kubectlMemory = props.kubectlMemory; this.prune = props.prune ?? true; @@ -1815,6 +1897,10 @@ class ImportedCluster extends ClusterBase { } return this.props.openIdConnectProvider; } + + public get awsAuth(): AwsAuth { + throw new Error('"awsAuth" is not supported on imported clusters'); + } } /** diff --git a/packages/@aws-cdk/aws-eks/lib/fargate-profile.ts b/packages/@aws-cdk/aws-eks/lib/fargate-profile.ts index 4ce6f094909bd..8d5b0301ff24b 100644 --- a/packages/@aws-cdk/aws-eks/lib/fargate-profile.ts +++ b/packages/@aws-cdk/aws-eks/lib/fargate-profile.ts @@ -1,6 +1,6 @@ import * as ec2 from '@aws-cdk/aws-ec2'; import * as iam from '@aws-cdk/aws-iam'; -import { CustomResource, ITaggable, Lazy, TagManager, TagType } from '@aws-cdk/core'; +import { Annotations, CustomResource, ITaggable, Lazy, TagManager, TagType } from '@aws-cdk/core'; import { Construct } from 'constructs'; import { Cluster } from './cluster'; import { FARGATE_PROFILE_RESOURCE_TYPE } from './cluster-resource-handler/consts'; @@ -46,7 +46,7 @@ export interface FargateProfileOptions { * By default, all private subnets are selected. You can customize this using * `subnetSelection`. * - * @default - all private subnets used by theEKS cluster + * @default - all private subnets used by the EKS cluster */ readonly vpc?: ec2.IVpc; @@ -55,6 +55,8 @@ export interface FargateProfileOptions { * on Fargate are not assigned public IP addresses, so only private subnets * (with no direct route to an Internet Gateway) are allowed. * + * You must specify the VPC to customize the subnet selection + * * @default - all private subnets of the VPC are selected. */ readonly subnetSelection?: ec2.SubnetSelection; @@ -147,6 +149,7 @@ export class FargateProfile extends CoreConstruct implements ITaggable { const provider = ClusterResourceProvider.getOrCreate(this, { adminRole: props.cluster.adminRole, + onEventLayer: props.cluster.onEventLayer, }); this.podExecutionRole = props.podExecutionRole ?? new iam.Role(this, 'PodExecutionRole', { @@ -156,6 +159,10 @@ export class FargateProfile extends CoreConstruct implements ITaggable { this.podExecutionRole.grantPassRole(props.cluster.adminRole); + if (props.subnetSelection && !props.vpc) { + Annotations.of(this).addWarning('Vpc must be defined to use a custom subnet selection. All private subnets belonging to the EKS cluster will be used by default'); + } + let subnets: string[] | undefined; if (props.vpc) { const selection: ec2.SubnetSelection = props.subnetSelection ?? { subnetType: ec2.SubnetType.PRIVATE }; diff --git a/packages/@aws-cdk/aws-eks/lib/user-data.ts b/packages/@aws-cdk/aws-eks/lib/user-data.ts index 8add0f7cb5bbc..f14c254b1f24f 100644 --- a/packages/@aws-cdk/aws-eks/lib/user-data.ts +++ b/packages/@aws-cdk/aws-eks/lib/user-data.ts @@ -1,9 +1,9 @@ import * as autoscaling from '@aws-cdk/aws-autoscaling'; import { Stack } from '@aws-cdk/core'; -import { BootstrapOptions, ICluster, Cluster } from './cluster'; +import { BootstrapOptions, ICluster } from './cluster'; // eslint-disable-next-line max-len -export function renderAmazonLinuxUserData(cluster: Cluster, autoScalingGroup: autoscaling.AutoScalingGroup, options: BootstrapOptions = {}): string[] { +export function renderAmazonLinuxUserData(cluster: ICluster, autoScalingGroup: autoscaling.AutoScalingGroup, options: BootstrapOptions = {}): string[] { const stack = Stack.of(autoScalingGroup); @@ -13,8 +13,21 @@ export function renderAmazonLinuxUserData(cluster: Cluster, autoScalingGroup: au const extraArgs = new Array(); - extraArgs.push(`--apiserver-endpoint '${cluster.clusterEndpoint}'`); - extraArgs.push(`--b64-cluster-ca '${cluster.clusterCertificateAuthorityData}'`); + try { + const clusterEndpoint = cluster.clusterEndpoint; + const clusterCertificateAuthorityData = + cluster.clusterCertificateAuthorityData; + extraArgs.push(`--apiserver-endpoint '${clusterEndpoint}'`); + extraArgs.push(`--b64-cluster-ca '${clusterCertificateAuthorityData}'`); + } catch (e) { + /** + * Errors are ignored here. + * apiserver-endpoint and b64-cluster-ca arguments are added in #12659 to make nodes join the cluster faster. + * As these are not necessary arguments, we don't need to pass these arguments when they don't exist. + * + * @see https://github.com/aws/aws-cdk/pull/12659 + */ + } extraArgs.push(`--use-max-pods ${options.useMaxPods ?? true}`); diff --git a/packages/@aws-cdk/aws-eks/package.json b/packages/@aws-cdk/aws-eks/package.json index 6e2d193036981..7864034ff146b 100644 --- a/packages/@aws-cdk/aws-eks/package.json +++ b/packages/@aws-cdk/aws-eks/package.json @@ -57,8 +57,7 @@ "cloudformation": "AWS::EKS", "env": { "AWSLINT_BASE_CONSTRUCT": true - }, - "jest": true + } }, "keywords": [ "aws", @@ -73,20 +72,20 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/aws-lambda": "^8.10.79", - "@types/sinon": "^9.0.11", + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/aws-lambda": "^8.10.84", "@types/jest": "^26.0.24", + "@types/sinon": "^9.0.11", "@types/yaml": "1.9.6", "aws-sdk": "^2.848.0", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "sinon": "^9.2.4", - "cdk8s-plus": "^0.33.0", "cdk8s": "^0.33.0", - "@aws-cdk/assert-internal": "0.0.0" + "cdk8s-plus": "^0.33.0", + "jest": "^26.6.3", + "sinon": "^9.2.4" }, "dependencies": { "@aws-cdk/aws-autoscaling": "0.0.0", @@ -94,11 +93,13 @@ "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", + "@aws-cdk/aws-lambda-nodejs": "0.0.0", "@aws-cdk/aws-ssm": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/custom-resources": "0.0.0", "@aws-cdk/lambda-layer-awscli": "0.0.0", "@aws-cdk/lambda-layer-kubectl": "0.0.0", + "@aws-cdk/lambda-layer-node-proxy-agent": "0.0.0", "constructs": "^3.3.69", "yaml": "1.10.2" }, @@ -112,12 +113,14 @@ "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", + "@aws-cdk/aws-lambda-nodejs": "0.0.0", "@aws-cdk/aws-ssm": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/custom-resources": "0.0.0", - "constructs": "^3.3.69", "@aws-cdk/lambda-layer-awscli": "0.0.0", - "@aws-cdk/lambda-layer-kubectl": "0.0.0" + "@aws-cdk/lambda-layer-kubectl": "0.0.0", + "@aws-cdk/lambda-layer-node-proxy-agent": "0.0.0", + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-eks/test/cluster.test.ts b/packages/@aws-cdk/aws-eks/test/cluster.test.ts index f68a2738dbb40..14e2bfad0746b 100644 --- a/packages/@aws-cdk/aws-eks/test/cluster.test.ts +++ b/packages/@aws-cdk/aws-eks/test/cluster.test.ts @@ -36,8 +36,6 @@ describe('cluster', () => { const template = SynthUtils.toCloudFormation(nested); expect(template.Resources.OnEventHandler42BEBAE0.Properties.Environment).toEqual({ Variables: { foo: 'bar' } }); - - }); test('throws when trying to place cluster handlers in a vpc with no private subnets', () => { @@ -220,8 +218,38 @@ describe('cluster', () => { expect(template.Resources.ClusterselfmanagedInstanceSecurityGroup64468C3A.Properties.Tags).toEqual([ { Key: 'Name', Value: 'Stack/Cluster/self-managed' }, ]); + }); + test('connect autoscaling group with imported cluster', () => { + // GIVEN + const { stack, vpc } = testFixture(); + const cluster = new eks.Cluster(stack, 'Cluster', { + vpc, + defaultCapacity: 0, + version: CLUSTER_VERSION, + prune: false, + }); + + const importedCluster = eks.Cluster.fromClusterAttributes(stack, 'ImportedCluster', { + clusterName: cluster.clusterName, + clusterSecurityGroupId: cluster.clusterSecurityGroupId, + }); + + const selfManaged = new asg.AutoScalingGroup(stack, 'self-managed', { + instanceType: new ec2.InstanceType('t2.medium'), + vpc: vpc, + machineImage: new ec2.AmazonLinuxImage(), + }); + + // WHEN + importedCluster.connectAutoScalingGroupCapacity(selfManaged, {}); + + const template = SynthUtils.toCloudFormation(stack); + expect(template.Resources.selfmanagedLaunchConfigD41289EB.Properties.SecurityGroups).toEqual([ + { 'Fn::GetAtt': ['selfmanagedInstanceSecurityGroupEA6D80C9', 'GroupId'] }, + { 'Fn::GetAtt': ['Cluster9EE0221C', 'ClusterSecurityGroupId'] }, + ]); }); test('cluster security group is attached when connecting self-managed nodes', () => { @@ -651,7 +679,7 @@ describe('cluster', () => { const { stack } = testFixtureNoVpc(); // WHEN - new eks.Cluster(stack, 'cluster', { version: CLUSTER_VERSION, prune: false }) ; + new eks.Cluster(stack, 'cluster', { version: CLUSTER_VERSION, prune: false }); // THEN expect(stack).toHaveResource('AWS::EC2::VPC'); @@ -2469,7 +2497,7 @@ describe('cluster', () => { version: CLUSTER_VERSION, prune: false, endpointAccess: - eks.EndpointAccess.PRIVATE, + eks.EndpointAccess.PRIVATE, vpcSubnets: [{ subnets: [ec2.PrivateSubnet.fromSubnetAttributes(stack, 'Private1', { subnetId: 'subnet1', @@ -2568,14 +2596,14 @@ describe('cluster', () => { const subnetConfiguration: ec2.SubnetConfiguration[] = []; for (let i = 0; i < 20; i++) { - subnetConfiguration.push( { + subnetConfiguration.push({ subnetType: ec2.SubnetType.PRIVATE, name: `Private${i}`, }, ); } - subnetConfiguration.push( { + subnetConfiguration.push({ subnetType: ec2.SubnetType.PUBLIC, name: 'Public1', }); @@ -2619,14 +2647,14 @@ describe('cluster', () => { const subnetConfiguration: ec2.SubnetConfiguration[] = []; for (let i = 0; i < 20; i++) { - subnetConfiguration.push( { + subnetConfiguration.push({ subnetType: ec2.SubnetType.PRIVATE, name: `Private${i}`, }, ); } - subnetConfiguration.push( { + subnetConfiguration.push({ subnetType: ec2.SubnetType.PUBLIC, name: 'Public1', }); diff --git a/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-handlers-vpc.expected.json b/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-handlers-vpc.expected.json index cdb744ed6be0e..bc3c838b43ef3 100644 --- a/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-handlers-vpc.expected.json +++ b/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-handlers-vpc.expected.json @@ -1115,7 +1115,7 @@ }, "/", { - "Ref": "AssetParameters7b7589d8284d359f531f595891e11720582fb63d0f0051cb08b5bfbcd6d60f60S3BucketE63A0899" + "Ref": "AssetParameters30ee592ed790de2e3261605468c9775597d2246a8fe1db5e656f903f536f3742S3BucketA4A228F5" }, "/", { @@ -1125,7 +1125,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters7b7589d8284d359f531f595891e11720582fb63d0f0051cb08b5bfbcd6d60f60S3VersionKey91A6BB03" + "Ref": "AssetParameters30ee592ed790de2e3261605468c9775597d2246a8fe1db5e656f903f536f3742S3VersionKey6CE1DED5" } ] } @@ -1138,7 +1138,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters7b7589d8284d359f531f595891e11720582fb63d0f0051cb08b5bfbcd6d60f60S3VersionKey91A6BB03" + "Ref": "AssetParameters30ee592ed790de2e3261605468c9775597d2246a8fe1db5e656f903f536f3742S3VersionKey6CE1DED5" } ] } @@ -1157,11 +1157,11 @@ "referencetoawscdkekshandlersinvpctestEksAllHandlersInVpcStackDefaultVpcE40EA7ACRef": { "Ref": "EksAllHandlersInVpcStackDefaultVpcBE11D4AE" }, - "referencetoawscdkekshandlersinvpctestAssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3Bucket020723FERef": { - "Ref": "AssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3Bucket14D204F9" + "referencetoawscdkekshandlersinvpctestAssetParametersd78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4S3Bucket4A93429DRef": { + "Ref": "AssetParametersd78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4S3Bucket5B1EB03C" }, - "referencetoawscdkekshandlersinvpctestAssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3VersionKeyEC505E3ARef": { - "Ref": "AssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3VersionKeyDE8A2F1F" + "referencetoawscdkekshandlersinvpctestAssetParametersd78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4S3VersionKey7F5C23CBRef": { + "Ref": "AssetParametersd78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4S3VersionKey51E064E9" }, "referencetoawscdkekshandlersinvpctestEksAllHandlersInVpcStackDefaultVpcPrivateSubnet1Subnet9479BAA8Ref": { "Ref": "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet1SubnetE2B86978" @@ -1172,6 +1172,12 @@ "referencetoawscdkekshandlersinvpctestEksAllHandlersInVpcStackDefaultVpcPrivateSubnet3Subnet1B127970Ref": { "Ref": "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet3SubnetA75A8BA9" }, + "referencetoawscdkekshandlersinvpctestAssetParametersca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864ccS3BucketE24ADE21Ref": { + "Ref": "AssetParametersca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864ccS3Bucket40405135" + }, + "referencetoawscdkekshandlersinvpctestAssetParametersca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864ccS3VersionKeyEA8B9B47Ref": { + "Ref": "AssetParametersca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864ccS3VersionKey50B477EB" + }, "referencetoawscdkekshandlersinvpctestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3Bucket9D7E9998Ref": { "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" }, @@ -1196,7 +1202,7 @@ }, "/", { - "Ref": "AssetParametersa894c8b40c44a95ab449d327b83cd64ab07c12c1d95cbe2852f2e36a1780ef30S3Bucket3108034A" + "Ref": "AssetParameters21c400ec0eb62a3fa5c541809780b108a89b7772406cc58eb6d989827ce09345S3BucketC59A67EA" }, "/", { @@ -1206,7 +1212,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersa894c8b40c44a95ab449d327b83cd64ab07c12c1d95cbe2852f2e36a1780ef30S3VersionKey72F9CB08" + "Ref": "AssetParameters21c400ec0eb62a3fa5c541809780b108a89b7772406cc58eb6d989827ce09345S3VersionKey10DC54D0" } ] } @@ -1219,7 +1225,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersa894c8b40c44a95ab449d327b83cd64ab07c12c1d95cbe2852f2e36a1780ef30S3VersionKey72F9CB08" + "Ref": "AssetParameters21c400ec0eb62a3fa5c541809780b108a89b7772406cc58eb6d989827ce09345S3VersionKey10DC54D0" } ] } @@ -1241,11 +1247,11 @@ "Arn" ] }, - "referencetoawscdkekshandlersinvpctestAssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3BucketF3527C76Ref": { - "Ref": "AssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3Bucket008DBB35" + "referencetoawscdkekshandlersinvpctestAssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3Bucket4673F14ERef": { + "Ref": "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3BucketC6FAEEC9" }, - "referencetoawscdkekshandlersinvpctestAssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3VersionKeyE9C79D35Ref": { - "Ref": "AssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3VersionKey97C3E1A0" + "referencetoawscdkekshandlersinvpctestAssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3VersionKey61C348A6Ref": { + "Ref": "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3VersionKeyA7EE7421" }, "referencetoawscdkekshandlersinvpctestEksAllHandlersInVpcStackDefaultVpcPrivateSubnet1Subnet9479BAA8Ref": { "Ref": "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet1SubnetE2B86978" @@ -1268,11 +1274,11 @@ "referencetoawscdkekshandlersinvpctestAssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyF4C27F59Ref": { "Ref": "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyE415415F" }, - "referencetoawscdkekshandlersinvpctestAssetParameterscd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793S3Bucket74F7CECDRef": { - "Ref": "AssetParameterscd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793S3BucketD4F52C82" + "referencetoawscdkekshandlersinvpctestAssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3Bucket95C9D5A0Ref": { + "Ref": "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3BucketD3288998" }, - "referencetoawscdkekshandlersinvpctestAssetParameterscd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793S3VersionKeyE5A09AFARef": { - "Ref": "AssetParameterscd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793S3VersionKey9D243E8D" + "referencetoawscdkekshandlersinvpctestAssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3VersionKey2505ECB3Ref": { + "Ref": "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3VersionKeyB00C0565" }, "referencetoawscdkekshandlersinvpctestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3Bucket9D7E9998Ref": { "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" @@ -1329,17 +1335,29 @@ } }, "Parameters": { - "AssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3Bucket14D204F9": { + "AssetParametersd78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4S3Bucket5B1EB03C": { + "Type": "String", + "Description": "S3 bucket for asset \"d78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4\"" + }, + "AssetParametersd78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4S3VersionKey51E064E9": { + "Type": "String", + "Description": "S3 key for asset version \"d78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4\"" + }, + "AssetParametersd78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4ArtifactHash26192139": { + "Type": "String", + "Description": "Artifact hash for asset \"d78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4\"" + }, + "AssetParametersca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864ccS3Bucket40405135": { "Type": "String", - "Description": "S3 bucket for asset \"87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dba\"" + "Description": "S3 bucket for asset \"ca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864cc\"" }, - "AssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3VersionKeyDE8A2F1F": { + "AssetParametersca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864ccS3VersionKey50B477EB": { "Type": "String", - "Description": "S3 key for asset version \"87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dba\"" + "Description": "S3 key for asset version \"ca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864cc\"" }, - "AssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaArtifactHash54822A43": { + "AssetParametersca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864ccArtifactHashCC7E7A09": { "Type": "String", - "Description": "Artifact hash for asset \"87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dba\"" + "Description": "Artifact hash for asset \"ca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864cc\"" }, "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1": { "Type": "String", @@ -1353,17 +1371,17 @@ "Type": "String", "Description": "Artifact hash for asset \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" }, - "AssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3Bucket008DBB35": { + "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3BucketC6FAEEC9": { "Type": "String", - "Description": "S3 bucket for asset \"bafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757\"" + "Description": "S3 bucket for asset \"4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10\"" }, - "AssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3VersionKey97C3E1A0": { + "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3VersionKeyA7EE7421": { "Type": "String", - "Description": "S3 key for asset version \"bafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757\"" + "Description": "S3 key for asset version \"4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10\"" }, - "AssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757ArtifactHashF584A7D8": { + "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10ArtifactHash528547CD": { "Type": "String", - "Description": "Artifact hash for asset \"bafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757\"" + "Description": "Artifact hash for asset \"4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10\"" }, "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketAEADE8C7": { "Type": "String", @@ -1377,41 +1395,41 @@ "Type": "String", "Description": "Artifact hash for asset \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" }, - "AssetParameterscd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793S3BucketD4F52C82": { + "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3BucketD3288998": { "Type": "String", - "Description": "S3 bucket for asset \"cd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793\"" + "Description": "S3 bucket for asset \"ea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03e\"" }, - "AssetParameterscd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793S3VersionKey9D243E8D": { + "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3VersionKeyB00C0565": { "Type": "String", - "Description": "S3 key for asset version \"cd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793\"" + "Description": "S3 key for asset version \"ea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03e\"" }, - "AssetParameterscd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793ArtifactHash42EBA5B2": { + "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eArtifactHash4654D012": { "Type": "String", - "Description": "Artifact hash for asset \"cd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793\"" + "Description": "Artifact hash for asset \"ea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03e\"" }, - "AssetParameters7b7589d8284d359f531f595891e11720582fb63d0f0051cb08b5bfbcd6d60f60S3BucketE63A0899": { + "AssetParameters30ee592ed790de2e3261605468c9775597d2246a8fe1db5e656f903f536f3742S3BucketA4A228F5": { "Type": "String", - "Description": "S3 bucket for asset \"7b7589d8284d359f531f595891e11720582fb63d0f0051cb08b5bfbcd6d60f60\"" + "Description": "S3 bucket for asset \"30ee592ed790de2e3261605468c9775597d2246a8fe1db5e656f903f536f3742\"" }, - "AssetParameters7b7589d8284d359f531f595891e11720582fb63d0f0051cb08b5bfbcd6d60f60S3VersionKey91A6BB03": { + "AssetParameters30ee592ed790de2e3261605468c9775597d2246a8fe1db5e656f903f536f3742S3VersionKey6CE1DED5": { "Type": "String", - "Description": "S3 key for asset version \"7b7589d8284d359f531f595891e11720582fb63d0f0051cb08b5bfbcd6d60f60\"" + "Description": "S3 key for asset version \"30ee592ed790de2e3261605468c9775597d2246a8fe1db5e656f903f536f3742\"" }, - "AssetParameters7b7589d8284d359f531f595891e11720582fb63d0f0051cb08b5bfbcd6d60f60ArtifactHashEB6B332A": { + "AssetParameters30ee592ed790de2e3261605468c9775597d2246a8fe1db5e656f903f536f3742ArtifactHashBC7D3F16": { "Type": "String", - "Description": "Artifact hash for asset \"7b7589d8284d359f531f595891e11720582fb63d0f0051cb08b5bfbcd6d60f60\"" + "Description": "Artifact hash for asset \"30ee592ed790de2e3261605468c9775597d2246a8fe1db5e656f903f536f3742\"" }, - "AssetParametersa894c8b40c44a95ab449d327b83cd64ab07c12c1d95cbe2852f2e36a1780ef30S3Bucket3108034A": { + "AssetParameters21c400ec0eb62a3fa5c541809780b108a89b7772406cc58eb6d989827ce09345S3BucketC59A67EA": { "Type": "String", - "Description": "S3 bucket for asset \"a894c8b40c44a95ab449d327b83cd64ab07c12c1d95cbe2852f2e36a1780ef30\"" + "Description": "S3 bucket for asset \"21c400ec0eb62a3fa5c541809780b108a89b7772406cc58eb6d989827ce09345\"" }, - "AssetParametersa894c8b40c44a95ab449d327b83cd64ab07c12c1d95cbe2852f2e36a1780ef30S3VersionKey72F9CB08": { + "AssetParameters21c400ec0eb62a3fa5c541809780b108a89b7772406cc58eb6d989827ce09345S3VersionKey10DC54D0": { "Type": "String", - "Description": "S3 key for asset version \"a894c8b40c44a95ab449d327b83cd64ab07c12c1d95cbe2852f2e36a1780ef30\"" + "Description": "S3 key for asset version \"21c400ec0eb62a3fa5c541809780b108a89b7772406cc58eb6d989827ce09345\"" }, - "AssetParametersa894c8b40c44a95ab449d327b83cd64ab07c12c1d95cbe2852f2e36a1780ef30ArtifactHash95BE80EE": { + "AssetParameters21c400ec0eb62a3fa5c541809780b108a89b7772406cc58eb6d989827ce09345ArtifactHash9BBC26F6": { "Type": "String", - "Description": "Artifact hash for asset \"a894c8b40c44a95ab449d327b83cd64ab07c12c1d95cbe2852f2e36a1780ef30\"" + "Description": "Artifact hash for asset \"21c400ec0eb62a3fa5c541809780b108a89b7772406cc58eb6d989827ce09345\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-private-endpoint.expected.json b/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-private-endpoint.expected.json index 1f5d852a6ec76..b4da9f1c8825f 100644 --- a/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-private-endpoint.expected.json +++ b/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-private-endpoint.expected.json @@ -1048,7 +1048,7 @@ }, "/", { - "Ref": "AssetParametersf2b553bd53fbb997e6f23206daa298a3f8bfa7c9805c8c7c99155b4acc2d0cd6S3BucketFA2AD206" + "Ref": "AssetParametersa56d8928013d02a98785ea769489d44faab804343ca2ee759e7f29a34f05c890S3Bucket02F74E4B" }, "/", { @@ -1058,7 +1058,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersf2b553bd53fbb997e6f23206daa298a3f8bfa7c9805c8c7c99155b4acc2d0cd6S3VersionKeyD5C722C7" + "Ref": "AssetParametersa56d8928013d02a98785ea769489d44faab804343ca2ee759e7f29a34f05c890S3VersionKey0582948B" } ] } @@ -1071,7 +1071,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersf2b553bd53fbb997e6f23206daa298a3f8bfa7c9805c8c7c99155b4acc2d0cd6S3VersionKeyD5C722C7" + "Ref": "AssetParametersa56d8928013d02a98785ea769489d44faab804343ca2ee759e7f29a34f05c890S3VersionKey0582948B" } ] } @@ -1087,11 +1087,17 @@ "Arn" ] }, - "referencetoawscdkeksclusterprivateendpointtestAssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3Bucket0D497746Ref": { - "Ref": "AssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3Bucket14D204F9" + "referencetoawscdkeksclusterprivateendpointtestAssetParametersd78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4S3BucketE84B7538Ref": { + "Ref": "AssetParametersd78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4S3Bucket5B1EB03C" }, - "referencetoawscdkeksclusterprivateendpointtestAssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3VersionKeyC516A514Ref": { - "Ref": "AssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3VersionKeyDE8A2F1F" + "referencetoawscdkeksclusterprivateendpointtestAssetParametersd78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4S3VersionKey5FC346A2Ref": { + "Ref": "AssetParametersd78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4S3VersionKey51E064E9" + }, + "referencetoawscdkeksclusterprivateendpointtestAssetParametersca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864ccS3BucketF4479BE8Ref": { + "Ref": "AssetParametersca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864ccS3Bucket40405135" + }, + "referencetoawscdkeksclusterprivateendpointtestAssetParametersca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864ccS3VersionKeyBBC4B419Ref": { + "Ref": "AssetParametersca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864ccS3VersionKey50B477EB" }, "referencetoawscdkeksclusterprivateendpointtestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3Bucket7DDAFC04Ref": { "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" @@ -1117,7 +1123,7 @@ }, "/", { - "Ref": "AssetParametersdfe35aaa6ae98d71e5f9b7ada4fe74c141cb56fbf3fba2bef43a5e4f26ad0ea6S3Bucket1FD74644" + "Ref": "AssetParametersb9c099cddd88daf1512888f8ad4404f0f292ed3432f712d6a0eeddd74499b026S3BucketAF6BC29D" }, "/", { @@ -1127,7 +1133,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersdfe35aaa6ae98d71e5f9b7ada4fe74c141cb56fbf3fba2bef43a5e4f26ad0ea6S3VersionKey618B12D4" + "Ref": "AssetParametersb9c099cddd88daf1512888f8ad4404f0f292ed3432f712d6a0eeddd74499b026S3VersionKey979EE7C4" } ] } @@ -1140,7 +1146,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersdfe35aaa6ae98d71e5f9b7ada4fe74c141cb56fbf3fba2bef43a5e4f26ad0ea6S3VersionKey618B12D4" + "Ref": "AssetParametersb9c099cddd88daf1512888f8ad4404f0f292ed3432f712d6a0eeddd74499b026S3VersionKey979EE7C4" } ] } @@ -1162,11 +1168,11 @@ "Arn" ] }, - "referencetoawscdkeksclusterprivateendpointtestAssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3BucketD11B5EC1Ref": { - "Ref": "AssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3Bucket008DBB35" + "referencetoawscdkeksclusterprivateendpointtestAssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3Bucket5F23B36DRef": { + "Ref": "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3BucketC6FAEEC9" }, - "referencetoawscdkeksclusterprivateendpointtestAssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3VersionKey8375F1D2Ref": { - "Ref": "AssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3VersionKey97C3E1A0" + "referencetoawscdkeksclusterprivateendpointtestAssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3VersionKey658F22A4Ref": { + "Ref": "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3VersionKeyA7EE7421" }, "referencetoawscdkeksclusterprivateendpointtestVpcPrivateSubnet1Subnet94DAD769Ref": { "Ref": "VpcPrivateSubnet1Subnet536B997A" @@ -1189,11 +1195,11 @@ "referencetoawscdkeksclusterprivateendpointtestAssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKey69E4725CRef": { "Ref": "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyE415415F" }, - "referencetoawscdkeksclusterprivateendpointtestAssetParameterscd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793S3Bucket0DEFF6BBRef": { - "Ref": "AssetParameterscd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793S3BucketD4F52C82" + "referencetoawscdkeksclusterprivateendpointtestAssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3Bucket99203424Ref": { + "Ref": "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3BucketD3288998" }, - "referencetoawscdkeksclusterprivateendpointtestAssetParameterscd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793S3VersionKeyE878793ARef": { - "Ref": "AssetParameterscd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793S3VersionKey9D243E8D" + "referencetoawscdkeksclusterprivateendpointtestAssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3VersionKey74D35E51Ref": { + "Ref": "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3VersionKeyB00C0565" }, "referencetoawscdkeksclusterprivateendpointtestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3Bucket7DDAFC04Ref": { "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" @@ -1250,17 +1256,29 @@ } }, "Parameters": { - "AssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3Bucket14D204F9": { + "AssetParametersd78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4S3Bucket5B1EB03C": { + "Type": "String", + "Description": "S3 bucket for asset \"d78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4\"" + }, + "AssetParametersd78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4S3VersionKey51E064E9": { + "Type": "String", + "Description": "S3 key for asset version \"d78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4\"" + }, + "AssetParametersd78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4ArtifactHash26192139": { + "Type": "String", + "Description": "Artifact hash for asset \"d78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4\"" + }, + "AssetParametersca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864ccS3Bucket40405135": { "Type": "String", - "Description": "S3 bucket for asset \"87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dba\"" + "Description": "S3 bucket for asset \"ca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864cc\"" }, - "AssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3VersionKeyDE8A2F1F": { + "AssetParametersca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864ccS3VersionKey50B477EB": { "Type": "String", - "Description": "S3 key for asset version \"87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dba\"" + "Description": "S3 key for asset version \"ca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864cc\"" }, - "AssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaArtifactHash54822A43": { + "AssetParametersca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864ccArtifactHashCC7E7A09": { "Type": "String", - "Description": "Artifact hash for asset \"87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dba\"" + "Description": "Artifact hash for asset \"ca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864cc\"" }, "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1": { "Type": "String", @@ -1274,17 +1292,17 @@ "Type": "String", "Description": "Artifact hash for asset \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" }, - "AssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3Bucket008DBB35": { + "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3BucketC6FAEEC9": { "Type": "String", - "Description": "S3 bucket for asset \"bafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757\"" + "Description": "S3 bucket for asset \"4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10\"" }, - "AssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3VersionKey97C3E1A0": { + "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3VersionKeyA7EE7421": { "Type": "String", - "Description": "S3 key for asset version \"bafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757\"" + "Description": "S3 key for asset version \"4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10\"" }, - "AssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757ArtifactHashF584A7D8": { + "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10ArtifactHash528547CD": { "Type": "String", - "Description": "Artifact hash for asset \"bafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757\"" + "Description": "Artifact hash for asset \"4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10\"" }, "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketAEADE8C7": { "Type": "String", @@ -1298,41 +1316,41 @@ "Type": "String", "Description": "Artifact hash for asset \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" }, - "AssetParameterscd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793S3BucketD4F52C82": { + "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3BucketD3288998": { "Type": "String", - "Description": "S3 bucket for asset \"cd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793\"" + "Description": "S3 bucket for asset \"ea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03e\"" }, - "AssetParameterscd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793S3VersionKey9D243E8D": { + "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3VersionKeyB00C0565": { "Type": "String", - "Description": "S3 key for asset version \"cd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793\"" + "Description": "S3 key for asset version \"ea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03e\"" }, - "AssetParameterscd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793ArtifactHash42EBA5B2": { + "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eArtifactHash4654D012": { "Type": "String", - "Description": "Artifact hash for asset \"cd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793\"" + "Description": "Artifact hash for asset \"ea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03e\"" }, - "AssetParametersf2b553bd53fbb997e6f23206daa298a3f8bfa7c9805c8c7c99155b4acc2d0cd6S3BucketFA2AD206": { + "AssetParametersa56d8928013d02a98785ea769489d44faab804343ca2ee759e7f29a34f05c890S3Bucket02F74E4B": { "Type": "String", - "Description": "S3 bucket for asset \"f2b553bd53fbb997e6f23206daa298a3f8bfa7c9805c8c7c99155b4acc2d0cd6\"" + "Description": "S3 bucket for asset \"a56d8928013d02a98785ea769489d44faab804343ca2ee759e7f29a34f05c890\"" }, - "AssetParametersf2b553bd53fbb997e6f23206daa298a3f8bfa7c9805c8c7c99155b4acc2d0cd6S3VersionKeyD5C722C7": { + "AssetParametersa56d8928013d02a98785ea769489d44faab804343ca2ee759e7f29a34f05c890S3VersionKey0582948B": { "Type": "String", - "Description": "S3 key for asset version \"f2b553bd53fbb997e6f23206daa298a3f8bfa7c9805c8c7c99155b4acc2d0cd6\"" + "Description": "S3 key for asset version \"a56d8928013d02a98785ea769489d44faab804343ca2ee759e7f29a34f05c890\"" }, - "AssetParametersf2b553bd53fbb997e6f23206daa298a3f8bfa7c9805c8c7c99155b4acc2d0cd6ArtifactHashD053AD55": { + "AssetParametersa56d8928013d02a98785ea769489d44faab804343ca2ee759e7f29a34f05c890ArtifactHash67434B72": { "Type": "String", - "Description": "Artifact hash for asset \"f2b553bd53fbb997e6f23206daa298a3f8bfa7c9805c8c7c99155b4acc2d0cd6\"" + "Description": "Artifact hash for asset \"a56d8928013d02a98785ea769489d44faab804343ca2ee759e7f29a34f05c890\"" }, - "AssetParametersdfe35aaa6ae98d71e5f9b7ada4fe74c141cb56fbf3fba2bef43a5e4f26ad0ea6S3Bucket1FD74644": { + "AssetParametersb9c099cddd88daf1512888f8ad4404f0f292ed3432f712d6a0eeddd74499b026S3BucketAF6BC29D": { "Type": "String", - "Description": "S3 bucket for asset \"dfe35aaa6ae98d71e5f9b7ada4fe74c141cb56fbf3fba2bef43a5e4f26ad0ea6\"" + "Description": "S3 bucket for asset \"b9c099cddd88daf1512888f8ad4404f0f292ed3432f712d6a0eeddd74499b026\"" }, - "AssetParametersdfe35aaa6ae98d71e5f9b7ada4fe74c141cb56fbf3fba2bef43a5e4f26ad0ea6S3VersionKey618B12D4": { + "AssetParametersb9c099cddd88daf1512888f8ad4404f0f292ed3432f712d6a0eeddd74499b026S3VersionKey979EE7C4": { "Type": "String", - "Description": "S3 key for asset version \"dfe35aaa6ae98d71e5f9b7ada4fe74c141cb56fbf3fba2bef43a5e4f26ad0ea6\"" + "Description": "S3 key for asset version \"b9c099cddd88daf1512888f8ad4404f0f292ed3432f712d6a0eeddd74499b026\"" }, - "AssetParametersdfe35aaa6ae98d71e5f9b7ada4fe74c141cb56fbf3fba2bef43a5e4f26ad0ea6ArtifactHash378913E5": { + "AssetParametersb9c099cddd88daf1512888f8ad4404f0f292ed3432f712d6a0eeddd74499b026ArtifactHash8B6627D0": { "Type": "String", - "Description": "Artifact hash for asset \"dfe35aaa6ae98d71e5f9b7ada4fe74c141cb56fbf3fba2bef43a5e4f26ad0ea6\"" + "Description": "Artifact hash for asset \"b9c099cddd88daf1512888f8ad4404f0f292ed3432f712d6a0eeddd74499b026\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-eks/test/integ.eks-cluster.expected.json b/packages/@aws-cdk/aws-eks/test/integ.eks-cluster.expected.json index 1509f2e16bcf6..8ec7f02e4bd0c 100644 --- a/packages/@aws-cdk/aws-eks/test/integ.eks-cluster.expected.json +++ b/packages/@aws-cdk/aws-eks/test/integ.eks-cluster.expected.json @@ -3866,7 +3866,7 @@ }, "/", { - "Ref": "AssetParameters5598bd5ce38da10f7a9c6f8e54d4f50d7c0befd5309540ab64d64985236f2ef9S3BucketC3BFBE73" + "Ref": "AssetParameters814bd2987aca76da9dffdab2f4cd144ebec3a7f5c35d6cd55548442ec311be8cS3Bucket43FFBFD7" }, "/", { @@ -3876,7 +3876,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters5598bd5ce38da10f7a9c6f8e54d4f50d7c0befd5309540ab64d64985236f2ef9S3VersionKeyFA8225D5" + "Ref": "AssetParameters814bd2987aca76da9dffdab2f4cd144ebec3a7f5c35d6cd55548442ec311be8cS3VersionKeyC7429316" } ] } @@ -3889,7 +3889,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters5598bd5ce38da10f7a9c6f8e54d4f50d7c0befd5309540ab64d64985236f2ef9S3VersionKeyFA8225D5" + "Ref": "AssetParameters814bd2987aca76da9dffdab2f4cd144ebec3a7f5c35d6cd55548442ec311be8cS3VersionKeyC7429316" } ] } @@ -3905,11 +3905,17 @@ "Arn" ] }, - "referencetoawscdkeksclustertestAssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3Bucket1516DB0ARef": { - "Ref": "AssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3Bucket14D204F9" + "referencetoawscdkeksclustertestAssetParametersd78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4S3BucketB7F30483Ref": { + "Ref": "AssetParametersd78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4S3Bucket5B1EB03C" }, - "referencetoawscdkeksclustertestAssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3VersionKey2B8F3ED3Ref": { - "Ref": "AssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3VersionKeyDE8A2F1F" + "referencetoawscdkeksclustertestAssetParametersd78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4S3VersionKeyC41131F8Ref": { + "Ref": "AssetParametersd78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4S3VersionKey51E064E9" + }, + "referencetoawscdkeksclustertestAssetParametersca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864ccS3BucketEA485873Ref": { + "Ref": "AssetParametersca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864ccS3Bucket40405135" + }, + "referencetoawscdkeksclustertestAssetParametersca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864ccS3VersionKey2E164B3ERef": { + "Ref": "AssetParametersca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864ccS3VersionKey50B477EB" }, "referencetoawscdkeksclustertestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3Bucket0815E7B5Ref": { "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" @@ -3935,7 +3941,7 @@ }, "/", { - "Ref": "AssetParameterscbbfa09db37e6a37ee43fbb48d73d4d96f216270558c932674a48e856763ce79S3Bucket2C7FA0F3" + "Ref": "AssetParameters8a135d8a645edaff330758972da87b3dddc295ce07475e8d9ea8fad8c35dcb22S3Bucket0782C98E" }, "/", { @@ -3945,7 +3951,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameterscbbfa09db37e6a37ee43fbb48d73d4d96f216270558c932674a48e856763ce79S3VersionKey4D3075F9" + "Ref": "AssetParameters8a135d8a645edaff330758972da87b3dddc295ce07475e8d9ea8fad8c35dcb22S3VersionKey5E9D14CC" } ] } @@ -3958,7 +3964,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameterscbbfa09db37e6a37ee43fbb48d73d4d96f216270558c932674a48e856763ce79S3VersionKey4D3075F9" + "Ref": "AssetParameters8a135d8a645edaff330758972da87b3dddc295ce07475e8d9ea8fad8c35dcb22S3VersionKey5E9D14CC" } ] } @@ -3980,11 +3986,11 @@ "Arn" ] }, - "referencetoawscdkeksclustertestAssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3Bucket174F3576Ref": { - "Ref": "AssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3Bucket008DBB35" + "referencetoawscdkeksclustertestAssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3Bucket3929FA93Ref": { + "Ref": "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3BucketC6FAEEC9" }, - "referencetoawscdkeksclustertestAssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3VersionKeyE8595856Ref": { - "Ref": "AssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3VersionKey97C3E1A0" + "referencetoawscdkeksclustertestAssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3VersionKey14530D6BRef": { + "Ref": "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3VersionKeyA7EE7421" }, "referencetoawscdkeksclustertestVpcPrivateSubnet1Subnet32A4EC2ARef": { "Ref": "VpcPrivateSubnet1Subnet536B997A" @@ -4007,11 +4013,11 @@ "referencetoawscdkeksclustertestAssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKey1C7C1F5FRef": { "Ref": "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyE415415F" }, - "referencetoawscdkeksclustertestAssetParameterscd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793S3BucketBEBB0185Ref": { - "Ref": "AssetParameterscd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793S3BucketD4F52C82" + "referencetoawscdkeksclustertestAssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3Bucket6ADB5CE5Ref": { + "Ref": "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3BucketD3288998" }, - "referencetoawscdkeksclustertestAssetParameterscd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793S3VersionKey8BEC8371Ref": { - "Ref": "AssetParameterscd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793S3VersionKey9D243E8D" + "referencetoawscdkeksclustertestAssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3VersionKey314C5B11Ref": { + "Ref": "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3VersionKeyB00C0565" }, "referencetoawscdkeksclustertestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3Bucket0815E7B5Ref": { "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" @@ -4525,7 +4531,7 @@ } }, "Handler": "framework.onEvent", - "Runtime": "nodejs14.x", + "Runtime": "nodejs12.x", "Timeout": 900 }, "DependsOn": [ @@ -4658,17 +4664,29 @@ } }, "Parameters": { - "AssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3Bucket14D204F9": { + "AssetParametersd78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4S3Bucket5B1EB03C": { + "Type": "String", + "Description": "S3 bucket for asset \"d78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4\"" + }, + "AssetParametersd78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4S3VersionKey51E064E9": { + "Type": "String", + "Description": "S3 key for asset version \"d78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4\"" + }, + "AssetParametersd78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4ArtifactHash26192139": { + "Type": "String", + "Description": "Artifact hash for asset \"d78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4\"" + }, + "AssetParametersca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864ccS3Bucket40405135": { "Type": "String", - "Description": "S3 bucket for asset \"87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dba\"" + "Description": "S3 bucket for asset \"ca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864cc\"" }, - "AssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3VersionKeyDE8A2F1F": { + "AssetParametersca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864ccS3VersionKey50B477EB": { "Type": "String", - "Description": "S3 key for asset version \"87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dba\"" + "Description": "S3 key for asset version \"ca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864cc\"" }, - "AssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaArtifactHash54822A43": { + "AssetParametersca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864ccArtifactHashCC7E7A09": { "Type": "String", - "Description": "Artifact hash for asset \"87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dba\"" + "Description": "Artifact hash for asset \"ca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864cc\"" }, "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1": { "Type": "String", @@ -4682,17 +4700,17 @@ "Type": "String", "Description": "Artifact hash for asset \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" }, - "AssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3Bucket008DBB35": { + "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3BucketC6FAEEC9": { "Type": "String", - "Description": "S3 bucket for asset \"bafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757\"" + "Description": "S3 bucket for asset \"4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10\"" }, - "AssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3VersionKey97C3E1A0": { + "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3VersionKeyA7EE7421": { "Type": "String", - "Description": "S3 key for asset version \"bafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757\"" + "Description": "S3 key for asset version \"4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10\"" }, - "AssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757ArtifactHashF584A7D8": { + "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10ArtifactHash528547CD": { "Type": "String", - "Description": "Artifact hash for asset \"bafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757\"" + "Description": "Artifact hash for asset \"4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10\"" }, "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketAEADE8C7": { "Type": "String", @@ -4706,17 +4724,17 @@ "Type": "String", "Description": "Artifact hash for asset \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" }, - "AssetParameterscd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793S3BucketD4F52C82": { + "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3BucketD3288998": { "Type": "String", - "Description": "S3 bucket for asset \"cd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793\"" + "Description": "S3 bucket for asset \"ea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03e\"" }, - "AssetParameterscd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793S3VersionKey9D243E8D": { + "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3VersionKeyB00C0565": { "Type": "String", - "Description": "S3 key for asset version \"cd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793\"" + "Description": "S3 key for asset version \"ea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03e\"" }, - "AssetParameterscd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793ArtifactHash42EBA5B2": { + "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eArtifactHash4654D012": { "Type": "String", - "Description": "Artifact hash for asset \"cd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793\"" + "Description": "Artifact hash for asset \"ea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03e\"" }, "AssetParametersb7d38dc0eeb2c5d024919020e09d2590b68559eab4a5264c3b1aa7a429d1edd4S3BucketF7BC1777": { "Type": "String", @@ -4754,29 +4772,29 @@ "Type": "String", "Description": "Artifact hash for asset \"5f49893093e1ad14831626016699156d48da5f0890f19eb930bc3c46cf5f636d\"" }, - "AssetParameters5598bd5ce38da10f7a9c6f8e54d4f50d7c0befd5309540ab64d64985236f2ef9S3BucketC3BFBE73": { + "AssetParameters814bd2987aca76da9dffdab2f4cd144ebec3a7f5c35d6cd55548442ec311be8cS3Bucket43FFBFD7": { "Type": "String", - "Description": "S3 bucket for asset \"5598bd5ce38da10f7a9c6f8e54d4f50d7c0befd5309540ab64d64985236f2ef9\"" + "Description": "S3 bucket for asset \"814bd2987aca76da9dffdab2f4cd144ebec3a7f5c35d6cd55548442ec311be8c\"" }, - "AssetParameters5598bd5ce38da10f7a9c6f8e54d4f50d7c0befd5309540ab64d64985236f2ef9S3VersionKeyFA8225D5": { + "AssetParameters814bd2987aca76da9dffdab2f4cd144ebec3a7f5c35d6cd55548442ec311be8cS3VersionKeyC7429316": { "Type": "String", - "Description": "S3 key for asset version \"5598bd5ce38da10f7a9c6f8e54d4f50d7c0befd5309540ab64d64985236f2ef9\"" + "Description": "S3 key for asset version \"814bd2987aca76da9dffdab2f4cd144ebec3a7f5c35d6cd55548442ec311be8c\"" }, - "AssetParameters5598bd5ce38da10f7a9c6f8e54d4f50d7c0befd5309540ab64d64985236f2ef9ArtifactHash8F06BD93": { + "AssetParameters814bd2987aca76da9dffdab2f4cd144ebec3a7f5c35d6cd55548442ec311be8cArtifactHash52827559": { "Type": "String", - "Description": "Artifact hash for asset \"5598bd5ce38da10f7a9c6f8e54d4f50d7c0befd5309540ab64d64985236f2ef9\"" + "Description": "Artifact hash for asset \"814bd2987aca76da9dffdab2f4cd144ebec3a7f5c35d6cd55548442ec311be8c\"" }, - "AssetParameterscbbfa09db37e6a37ee43fbb48d73d4d96f216270558c932674a48e856763ce79S3Bucket2C7FA0F3": { + "AssetParameters8a135d8a645edaff330758972da87b3dddc295ce07475e8d9ea8fad8c35dcb22S3Bucket0782C98E": { "Type": "String", - "Description": "S3 bucket for asset \"cbbfa09db37e6a37ee43fbb48d73d4d96f216270558c932674a48e856763ce79\"" + "Description": "S3 bucket for asset \"8a135d8a645edaff330758972da87b3dddc295ce07475e8d9ea8fad8c35dcb22\"" }, - "AssetParameterscbbfa09db37e6a37ee43fbb48d73d4d96f216270558c932674a48e856763ce79S3VersionKey4D3075F9": { + "AssetParameters8a135d8a645edaff330758972da87b3dddc295ce07475e8d9ea8fad8c35dcb22S3VersionKey5E9D14CC": { "Type": "String", - "Description": "S3 key for asset version \"cbbfa09db37e6a37ee43fbb48d73d4d96f216270558c932674a48e856763ce79\"" + "Description": "S3 key for asset version \"8a135d8a645edaff330758972da87b3dddc295ce07475e8d9ea8fad8c35dcb22\"" }, - "AssetParameterscbbfa09db37e6a37ee43fbb48d73d4d96f216270558c932674a48e856763ce79ArtifactHashF865E7E6": { + "AssetParameters8a135d8a645edaff330758972da87b3dddc295ce07475e8d9ea8fad8c35dcb22ArtifactHash75F0D468": { "Type": "String", - "Description": "Artifact hash for asset \"cbbfa09db37e6a37ee43fbb48d73d4d96f216270558c932674a48e856763ce79\"" + "Description": "Artifact hash for asset \"8a135d8a645edaff330758972da87b3dddc295ce07475e8d9ea8fad8c35dcb22\"" }, "SsmParameterValueawsserviceeksoptimizedami121amazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter": { "Type": "AWS::SSM::Parameter::Value", diff --git a/packages/@aws-cdk/aws-eks/test/integ.fargate-cluster.expected.json b/packages/@aws-cdk/aws-eks/test/integ.fargate-cluster.expected.json index 895978548bc4c..72efc126137d7 100644 --- a/packages/@aws-cdk/aws-eks/test/integ.fargate-cluster.expected.json +++ b/packages/@aws-cdk/aws-eks/test/integ.fargate-cluster.expected.json @@ -1125,7 +1125,7 @@ }, "/", { - "Ref": "AssetParameters8f90971131eea6a356f7cfb4997f4b70bb577cf34d007550f5e28c342f6c47f7S3Bucket3C7D361B" + "Ref": "AssetParameters9528c3c9068ee4a23508464ed79290c4fa16c4d17230421015fdc585ec202566S3BucketBE3E205B" }, "/", { @@ -1135,7 +1135,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters8f90971131eea6a356f7cfb4997f4b70bb577cf34d007550f5e28c342f6c47f7S3VersionKey455B40AC" + "Ref": "AssetParameters9528c3c9068ee4a23508464ed79290c4fa16c4d17230421015fdc585ec202566S3VersionKeyAEF361AA" } ] } @@ -1148,7 +1148,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters8f90971131eea6a356f7cfb4997f4b70bb577cf34d007550f5e28c342f6c47f7S3VersionKey455B40AC" + "Ref": "AssetParameters9528c3c9068ee4a23508464ed79290c4fa16c4d17230421015fdc585ec202566S3VersionKeyAEF361AA" } ] } @@ -1164,11 +1164,17 @@ "Arn" ] }, - "referencetoawscdkeksfargateclustertestAssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3Bucket122A6EA8Ref": { - "Ref": "AssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3Bucket14D204F9" + "referencetoawscdkeksfargateclustertestAssetParametersd78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4S3Bucket5CC464F5Ref": { + "Ref": "AssetParametersd78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4S3Bucket5B1EB03C" }, - "referencetoawscdkeksfargateclustertestAssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3VersionKey56570425Ref": { - "Ref": "AssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3VersionKeyDE8A2F1F" + "referencetoawscdkeksfargateclustertestAssetParametersd78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4S3VersionKey610B35BCRef": { + "Ref": "AssetParametersd78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4S3VersionKey51E064E9" + }, + "referencetoawscdkeksfargateclustertestAssetParametersca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864ccS3Bucket3165858DRef": { + "Ref": "AssetParametersca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864ccS3Bucket40405135" + }, + "referencetoawscdkeksfargateclustertestAssetParametersca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864ccS3VersionKey1A1207D1Ref": { + "Ref": "AssetParametersca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864ccS3VersionKey50B477EB" }, "referencetoawscdkeksfargateclustertestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3Bucket8EEF0922Ref": { "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" @@ -1194,7 +1200,7 @@ }, "/", { - "Ref": "AssetParametersb8180d6aa1f3be56dff3c797e0e2b7efda1b899b5ce276930cbccf6ce61b6ff9S3BucketDEA37CED" + "Ref": "AssetParameters6b899044dd4c0806c8b311f44f756b062c8da54e6ff69ae3ed28d6dab912802dS3Bucket92B50C24" }, "/", { @@ -1204,7 +1210,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersb8180d6aa1f3be56dff3c797e0e2b7efda1b899b5ce276930cbccf6ce61b6ff9S3VersionKey2C845455" + "Ref": "AssetParameters6b899044dd4c0806c8b311f44f756b062c8da54e6ff69ae3ed28d6dab912802dS3VersionKeyB7108D30" } ] } @@ -1217,7 +1223,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersb8180d6aa1f3be56dff3c797e0e2b7efda1b899b5ce276930cbccf6ce61b6ff9S3VersionKey2C845455" + "Ref": "AssetParameters6b899044dd4c0806c8b311f44f756b062c8da54e6ff69ae3ed28d6dab912802dS3VersionKeyB7108D30" } ] } @@ -1239,11 +1245,11 @@ "Arn" ] }, - "referencetoawscdkeksfargateclustertestAssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3Bucket78A48DE4Ref": { - "Ref": "AssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3Bucket008DBB35" + "referencetoawscdkeksfargateclustertestAssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3BucketC4DF4301Ref": { + "Ref": "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3BucketC6FAEEC9" }, - "referencetoawscdkeksfargateclustertestAssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3VersionKey69DB854ARef": { - "Ref": "AssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3VersionKey97C3E1A0" + "referencetoawscdkeksfargateclustertestAssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3VersionKey013AD4DERef": { + "Ref": "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3VersionKeyA7EE7421" }, "referencetoawscdkeksfargateclustertestFargateClusterDefaultVpcPrivateSubnet1Subnet0278E6BCRef": { "Ref": "FargateClusterDefaultVpcPrivateSubnet1Subnet50EA43AA" @@ -1266,11 +1272,11 @@ "referencetoawscdkeksfargateclustertestAssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyB82BAEF8Ref": { "Ref": "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyE415415F" }, - "referencetoawscdkeksfargateclustertestAssetParameterscd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793S3BucketC0936E6ARef": { - "Ref": "AssetParameterscd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793S3BucketD4F52C82" + "referencetoawscdkeksfargateclustertestAssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3Bucket899EE5ABRef": { + "Ref": "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3BucketD3288998" }, - "referencetoawscdkeksfargateclustertestAssetParameterscd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793S3VersionKey3CFF45CERef": { - "Ref": "AssetParameterscd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793S3VersionKey9D243E8D" + "referencetoawscdkeksfargateclustertestAssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3VersionKey1296E713Ref": { + "Ref": "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3VersionKeyB00C0565" }, "referencetoawscdkeksfargateclustertestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3Bucket8EEF0922Ref": { "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" @@ -1327,17 +1333,29 @@ } }, "Parameters": { - "AssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3Bucket14D204F9": { + "AssetParametersd78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4S3Bucket5B1EB03C": { + "Type": "String", + "Description": "S3 bucket for asset \"d78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4\"" + }, + "AssetParametersd78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4S3VersionKey51E064E9": { + "Type": "String", + "Description": "S3 key for asset version \"d78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4\"" + }, + "AssetParametersd78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4ArtifactHash26192139": { + "Type": "String", + "Description": "Artifact hash for asset \"d78765b92df2a80d8f6054e616200f6099a238f29fe81a199c2c217ffe1a12b4\"" + }, + "AssetParametersca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864ccS3Bucket40405135": { "Type": "String", - "Description": "S3 bucket for asset \"87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dba\"" + "Description": "S3 bucket for asset \"ca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864cc\"" }, - "AssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3VersionKeyDE8A2F1F": { + "AssetParametersca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864ccS3VersionKey50B477EB": { "Type": "String", - "Description": "S3 key for asset version \"87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dba\"" + "Description": "S3 key for asset version \"ca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864cc\"" }, - "AssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaArtifactHash54822A43": { + "AssetParametersca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864ccArtifactHashCC7E7A09": { "Type": "String", - "Description": "Artifact hash for asset \"87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dba\"" + "Description": "Artifact hash for asset \"ca2c913ffc0cd2016ee8bae9a571d12d6eca2284408cb99dd0ebff5b061864cc\"" }, "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1": { "Type": "String", @@ -1351,17 +1369,17 @@ "Type": "String", "Description": "Artifact hash for asset \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" }, - "AssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3Bucket008DBB35": { + "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3BucketC6FAEEC9": { "Type": "String", - "Description": "S3 bucket for asset \"bafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757\"" + "Description": "S3 bucket for asset \"4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10\"" }, - "AssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3VersionKey97C3E1A0": { + "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3VersionKeyA7EE7421": { "Type": "String", - "Description": "S3 key for asset version \"bafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757\"" + "Description": "S3 key for asset version \"4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10\"" }, - "AssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757ArtifactHashF584A7D8": { + "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10ArtifactHash528547CD": { "Type": "String", - "Description": "Artifact hash for asset \"bafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757\"" + "Description": "Artifact hash for asset \"4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10\"" }, "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketAEADE8C7": { "Type": "String", @@ -1375,41 +1393,41 @@ "Type": "String", "Description": "Artifact hash for asset \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" }, - "AssetParameterscd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793S3BucketD4F52C82": { + "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3BucketD3288998": { "Type": "String", - "Description": "S3 bucket for asset \"cd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793\"" + "Description": "S3 bucket for asset \"ea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03e\"" }, - "AssetParameterscd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793S3VersionKey9D243E8D": { + "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3VersionKeyB00C0565": { "Type": "String", - "Description": "S3 key for asset version \"cd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793\"" + "Description": "S3 key for asset version \"ea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03e\"" }, - "AssetParameterscd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793ArtifactHash42EBA5B2": { + "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eArtifactHash4654D012": { "Type": "String", - "Description": "Artifact hash for asset \"cd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793\"" + "Description": "Artifact hash for asset \"ea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03e\"" }, - "AssetParameters8f90971131eea6a356f7cfb4997f4b70bb577cf34d007550f5e28c342f6c47f7S3Bucket3C7D361B": { + "AssetParameters9528c3c9068ee4a23508464ed79290c4fa16c4d17230421015fdc585ec202566S3BucketBE3E205B": { "Type": "String", - "Description": "S3 bucket for asset \"8f90971131eea6a356f7cfb4997f4b70bb577cf34d007550f5e28c342f6c47f7\"" + "Description": "S3 bucket for asset \"9528c3c9068ee4a23508464ed79290c4fa16c4d17230421015fdc585ec202566\"" }, - "AssetParameters8f90971131eea6a356f7cfb4997f4b70bb577cf34d007550f5e28c342f6c47f7S3VersionKey455B40AC": { + "AssetParameters9528c3c9068ee4a23508464ed79290c4fa16c4d17230421015fdc585ec202566S3VersionKeyAEF361AA": { "Type": "String", - "Description": "S3 key for asset version \"8f90971131eea6a356f7cfb4997f4b70bb577cf34d007550f5e28c342f6c47f7\"" + "Description": "S3 key for asset version \"9528c3c9068ee4a23508464ed79290c4fa16c4d17230421015fdc585ec202566\"" }, - "AssetParameters8f90971131eea6a356f7cfb4997f4b70bb577cf34d007550f5e28c342f6c47f7ArtifactHashA258B8DC": { + "AssetParameters9528c3c9068ee4a23508464ed79290c4fa16c4d17230421015fdc585ec202566ArtifactHashE4B867B7": { "Type": "String", - "Description": "Artifact hash for asset \"8f90971131eea6a356f7cfb4997f4b70bb577cf34d007550f5e28c342f6c47f7\"" + "Description": "Artifact hash for asset \"9528c3c9068ee4a23508464ed79290c4fa16c4d17230421015fdc585ec202566\"" }, - "AssetParametersb8180d6aa1f3be56dff3c797e0e2b7efda1b899b5ce276930cbccf6ce61b6ff9S3BucketDEA37CED": { + "AssetParameters6b899044dd4c0806c8b311f44f756b062c8da54e6ff69ae3ed28d6dab912802dS3Bucket92B50C24": { "Type": "String", - "Description": "S3 bucket for asset \"b8180d6aa1f3be56dff3c797e0e2b7efda1b899b5ce276930cbccf6ce61b6ff9\"" + "Description": "S3 bucket for asset \"6b899044dd4c0806c8b311f44f756b062c8da54e6ff69ae3ed28d6dab912802d\"" }, - "AssetParametersb8180d6aa1f3be56dff3c797e0e2b7efda1b899b5ce276930cbccf6ce61b6ff9S3VersionKey2C845455": { + "AssetParameters6b899044dd4c0806c8b311f44f756b062c8da54e6ff69ae3ed28d6dab912802dS3VersionKeyB7108D30": { "Type": "String", - "Description": "S3 key for asset version \"b8180d6aa1f3be56dff3c797e0e2b7efda1b899b5ce276930cbccf6ce61b6ff9\"" + "Description": "S3 key for asset version \"6b899044dd4c0806c8b311f44f756b062c8da54e6ff69ae3ed28d6dab912802d\"" }, - "AssetParametersb8180d6aa1f3be56dff3c797e0e2b7efda1b899b5ce276930cbccf6ce61b6ff9ArtifactHashAC123599": { + "AssetParameters6b899044dd4c0806c8b311f44f756b062c8da54e6ff69ae3ed28d6dab912802dArtifactHashE3B502E1": { "Type": "String", - "Description": "Artifact hash for asset \"b8180d6aa1f3be56dff3c797e0e2b7efda1b899b5ce276930cbccf6ce61b6ff9\"" + "Description": "Artifact hash for asset \"6b899044dd4c0806c8b311f44f756b062c8da54e6ff69ae3ed28d6dab912802d\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-eks/test/user-data.test.ts b/packages/@aws-cdk/aws-eks/test/user-data.test.ts index a7ed42a5f3759..2e808ed723bca 100644 --- a/packages/@aws-cdk/aws-eks/test/user-data.test.ts +++ b/packages/@aws-cdk/aws-eks/test/user-data.test.ts @@ -35,8 +35,66 @@ describe('user data', () => { }, '/opt/aws/bin/cfn-signal --exit-code $? --stack my-stack --resource ASG46ED3070 --region us-west-33', ]); + }); + + test('imported cluster without clusterEndpoint', () => { + // GIVEN + const { asg, stack, cluster } = newFixtures(); + + const importedCluster = Cluster.fromClusterAttributes(stack, 'ImportedCluster', { + clusterName: cluster.clusterName, + openIdConnectProvider: cluster.openIdConnectProvider, + clusterCertificateAuthorityData: cluster.clusterCertificateAuthorityData, + }); + + // WHEN + const userData = stack.resolve(renderAmazonLinuxUserData(importedCluster, asg)); + + // THEN + expect(userData).toEqual([ + 'set -o xtrace', + { + 'Fn::Join': [ + '', + [ + '/etc/eks/bootstrap.sh ', + { Ref: 'clusterC5B25D0D' }, + ' --kubelet-extra-args "--node-labels lifecycle=OnDemand" --use-max-pods true', + ], + ], + }, + '/opt/aws/bin/cfn-signal --exit-code $? --stack my-stack --resource ASG46ED3070 --region us-west-33', + ]); + }); + + test('imported cluster without clusterCertificateAuthorityData', () => { + // GIVEN + const { asg, stack, cluster } = newFixtures(); + const importedCluster = Cluster.fromClusterAttributes(stack, 'ImportedCluster', { + clusterName: cluster.clusterName, + openIdConnectProvider: cluster.openIdConnectProvider, + clusterEndpoint: cluster.clusterEndpoint, + }); + // WHEN + const userData = stack.resolve(renderAmazonLinuxUserData(importedCluster, asg)); + + // THEN + expect(userData).toEqual([ + 'set -o xtrace', + { + 'Fn::Join': [ + '', + [ + '/etc/eks/bootstrap.sh ', + { Ref: 'clusterC5B25D0D' }, + ' --kubelet-extra-args "--node-labels lifecycle=OnDemand" --use-max-pods true', + ], + ], + }, + '/opt/aws/bin/cfn-signal --exit-code $? --stack my-stack --resource ASG46ED3070 --region us-west-33', + ]); }); test('--use-max-pods=true', () => { diff --git a/packages/@aws-cdk/aws-elasticache/.eslintrc.js b/packages/@aws-cdk/aws-elasticache/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-elasticache/.eslintrc.js +++ b/packages/@aws-cdk/aws-elasticache/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-elasticache/jest.config.js b/packages/@aws-cdk/aws-elasticache/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-elasticache/jest.config.js +++ b/packages/@aws-cdk/aws-elasticache/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-elasticache/package.json b/packages/@aws-cdk/aws-elasticache/package.json index 8a8a5a70c6c16..8176496ecfad9 100644 --- a/packages/@aws-cdk/aws-elasticache/package.json +++ b/packages/@aws-cdk/aws-elasticache/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::ElastiCache", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,11 +72,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-elasticbeanstalk/.eslintrc.js b/packages/@aws-cdk/aws-elasticbeanstalk/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-elasticbeanstalk/.eslintrc.js +++ b/packages/@aws-cdk/aws-elasticbeanstalk/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-elasticbeanstalk/jest.config.js b/packages/@aws-cdk/aws-elasticbeanstalk/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-elasticbeanstalk/jest.config.js +++ b/packages/@aws-cdk/aws-elasticbeanstalk/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-elasticbeanstalk/package.json b/packages/@aws-cdk/aws-elasticbeanstalk/package.json index a9bde94b14589..a7523e7a9bf58 100644 --- a/packages/@aws-cdk/aws-elasticbeanstalk/package.json +++ b/packages/@aws-cdk/aws-elasticbeanstalk/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::ElasticBeanstalk", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,11 +72,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-elasticloadbalancing/.eslintrc.js b/packages/@aws-cdk/aws-elasticloadbalancing/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancing/.eslintrc.js +++ b/packages/@aws-cdk/aws-elasticloadbalancing/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-elasticloadbalancing/jest.config.js b/packages/@aws-cdk/aws-elasticloadbalancing/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancing/jest.config.js +++ b/packages/@aws-cdk/aws-elasticloadbalancing/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-elasticloadbalancing/package.json b/packages/@aws-cdk/aws-elasticloadbalancing/package.json index e20392648d2dd..9b73054622979 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancing/package.json +++ b/packages/@aws-cdk/aws-elasticloadbalancing/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::ElasticLoadBalancing", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,12 +72,12 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/aws-ec2": "0.0.0", diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/.eslintrc.js b/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/.eslintrc.js index 01db0e3e9f01c..1a3b4ca2b6aec 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/.eslintrc.js +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/.eslintrc.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/jest.config.js b/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/jest.config.js index 5c1ef76634a9f..751c263a6e75c 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/jest.config.js +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/jest.config.js @@ -1,4 +1,4 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = { ...baseConfig, coverageThreshold: { diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/package.json b/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/package.json index 053caf2ce49a5..a431ef48ddbd5 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/package.json +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/package.json @@ -65,27 +65,27 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { + "@aws-cdk/aws-cognito": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/aws-elasticloadbalancingv2": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", - "@aws-cdk/aws-cognito": "0.0.0", "@aws-cdk/core": "0.0.0", "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { + "@aws-cdk/aws-cognito": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/aws-elasticloadbalancingv2": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", - "@aws-cdk/aws-cognito": "0.0.0", "@aws-cdk/core": "0.0.0", "constructs": "^3.3.69" }, @@ -99,7 +99,6 @@ "announce": false }, "cdk-build": { - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/.eslintrc.js b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/.eslintrc.js +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/jest.config.js b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/jest.config.js +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/lib/alb-target.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/lib/alb-target.ts new file mode 100644 index 0000000000000..3cc67a0984a2e --- /dev/null +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/lib/alb-target.ts @@ -0,0 +1,45 @@ +import * as elbv2 from '@aws-cdk/aws-elasticloadbalancingv2'; + +/** + * A single Application Load Balancer as the target for load balancing. + */ +export class AlbArnTarget implements elbv2.INetworkLoadBalancerTarget { + /** + * Create a new alb target + * + * @param albArn The ARN of the application load balancer to load balance to + * @param port The port on which the target is listening + */ + constructor(private readonly albArn: string, private readonly port: number) { + } + + /** + * Register this alb target with a load balancer + * + * Don't call this, it is called automatically when you add the target to a + * load balancer. + */ + public attachToNetworkTargetGroup(targetGroup: elbv2.INetworkTargetGroup): elbv2.LoadBalancerTargetProps { + return this.attach(targetGroup); + } + + private attach(_targetGroup: elbv2.ITargetGroup): elbv2.LoadBalancerTargetProps { + return { + targetType: elbv2.TargetType.ALB, + targetJson: { id: this.albArn, port: this.port }, + }; + } +} + +/** + * A single Application Load Balancer as the target for load balancing. + */ +export class AlbTarget extends AlbArnTarget { + /** + * @param alb The application load balancer to load balance to + * @param port The port on which the target is listening + */ + constructor(alb: elbv2.ApplicationLoadBalancer, port: number) { + super(alb.loadBalancerArn, port); + } +} diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/lib/index.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/lib/index.ts index 145ac293c4a98..dce98a495a5d6 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/lib/index.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/lib/index.ts @@ -1,3 +1,4 @@ +export * from './alb-target'; export * from './ip-target'; export * from './instance-target'; export * from './lambda-target'; \ No newline at end of file diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/package.json b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/package.json index e25ccb5ccd96f..e9b09e29964ff 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/package.json +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/package.json @@ -65,12 +65,14 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "@aws-cdk/aws-ecs": "0.0.0", + "@aws-cdk/aws-ecs-patterns": "0.0.0" }, "dependencies": { "@aws-cdk/aws-ec2": "0.0.0", @@ -104,7 +106,6 @@ "announce": false }, "cdk-build": { - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/alb-target.test.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/alb-target.test.ts new file mode 100644 index 0000000000000..1ccea0b91d1b2 --- /dev/null +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/alb-target.test.ts @@ -0,0 +1,68 @@ +import { expect, haveResource } from '@aws-cdk/assert-internal'; +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as elbv2 from '@aws-cdk/aws-elasticloadbalancingv2'; +import { Stack } from '@aws-cdk/core'; +import * as targets from '../lib'; + +test('Can create target groups with alb target', () => { + // GIVEN + const stack = new Stack(); + const vpc = new ec2.Vpc(stack, 'Stack'); + const alb = new elbv2.ApplicationLoadBalancer(stack, 'ALB', { vpc }); + const nlb = new elbv2.NetworkLoadBalancer(stack, 'NLB', { vpc }); + const listener = nlb.addListener('Listener', { port: 80 }); + + // WHEN + listener.addTargets('Targets', { + targets: [new targets.AlbTarget(alb, 80)], + port: 80, + }); + + // THEN + expect(stack).to(haveResource('AWS::ElasticLoadBalancingV2::TargetGroup', { + Port: 80, + Protocol: 'TCP', + Targets: [ + { + Id: { + Ref: 'ALBAEE750D2', + }, + Port: 80, + }, + ], + TargetType: 'alb', + VpcId: { + Ref: 'Stack8A423254', + }, + })); +}); + +test('Can create target groups with alb arn target', () => { + // GIVEN + const stack = new Stack(); + const vpc = new ec2.Vpc(stack, 'Stack'); + const nlb = new elbv2.NetworkLoadBalancer(stack, 'NLB', { vpc }); + const listener = nlb.addListener('Listener', { port: 80 }); + + // WHEN + listener.addTargets('Targets', { + targets: [new targets.AlbArnTarget('MOCK_ARN', 80)], + port: 80, + }); + + // THEN + expect(stack).to(haveResource('AWS::ElasticLoadBalancingV2::TargetGroup', { + Port: 80, + Protocol: 'TCP', + Targets: [ + { + Id: 'MOCK_ARN', + Port: 80, + }, + ], + TargetType: 'alb', + VpcId: { + Ref: 'Stack8A423254', + }, + })); +}); \ No newline at end of file diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/integ.alb-target.expected.json b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/integ.alb-target.expected.json new file mode 100644 index 0000000000000..8832e3edf3726 --- /dev/null +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/integ.alb-target.expected.json @@ -0,0 +1,673 @@ +{ + "Resources": { + "Vpc8378EB38": { + "Type": "AWS::EC2::VPC", + "Properties": { + "CidrBlock": "10.0.0.0/16", + "EnableDnsHostnames": true, + "EnableDnsSupport": true, + "InstanceTenancy": "default", + "Tags": [ + { + "Key": "Name", + "Value": "TestStack/Vpc" + } + ] + } + }, + "VpcPublicSubnet1Subnet5C2D37C4": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.0.0/18", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "TestStack/Vpc/PublicSubnet1" + } + ] + } + }, + "VpcPublicSubnet1RouteTable6C95E38E": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "TestStack/Vpc/PublicSubnet1" + } + ] + } + }, + "VpcPublicSubnet1RouteTableAssociation97140677": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" + }, + "SubnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + } + } + }, + "VpcPublicSubnet1DefaultRoute3DA9E72A": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VpcIGWD7BA715C" + } + }, + "DependsOn": [ + "VpcVPCGWBF912B6E" + ] + }, + "VpcPublicSubnet1EIPD7E02669": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "TestStack/Vpc/PublicSubnet1" + } + ] + } + }, + "VpcPublicSubnet1NATGateway4D7517AA": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "SubnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, + "AllocationId": { + "Fn::GetAtt": [ + "VpcPublicSubnet1EIPD7E02669", + "AllocationId" + ] + }, + "Tags": [ + { + "Key": "Name", + "Value": "TestStack/Vpc/PublicSubnet1" + } + ] + } + }, + "VpcPublicSubnet2Subnet691E08A3": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.64.0/18", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "TestStack/Vpc/PublicSubnet2" + } + ] + } + }, + "VpcPublicSubnet2RouteTable94F7E489": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "TestStack/Vpc/PublicSubnet2" + } + ] + } + }, + "VpcPublicSubnet2RouteTableAssociationDD5762D8": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" + }, + "SubnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + } + } + }, + "VpcPublicSubnet2DefaultRoute97F91067": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VpcIGWD7BA715C" + } + }, + "DependsOn": [ + "VpcVPCGWBF912B6E" + ] + }, + "VpcPrivateSubnet1Subnet536B997A": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.128.0/18", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "Name", + "Value": "TestStack/Vpc/PrivateSubnet1" + } + ] + } + }, + "VpcPrivateSubnet1RouteTableB2C5B500": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "TestStack/Vpc/PrivateSubnet1" + } + ] + } + }, + "VpcPrivateSubnet1RouteTableAssociation70C59FA6": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" + }, + "SubnetId": { + "Ref": "VpcPrivateSubnet1Subnet536B997A" + } + } + }, + "VpcPrivateSubnet1DefaultRouteBE02A9ED": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VpcPublicSubnet1NATGateway4D7517AA" + } + } + }, + "VpcPrivateSubnet2Subnet3788AAA1": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.192.0/18", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "Name", + "Value": "TestStack/Vpc/PrivateSubnet2" + } + ] + } + }, + "VpcPrivateSubnet2RouteTableA678073B": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "TestStack/Vpc/PrivateSubnet2" + } + ] + } + }, + "VpcPrivateSubnet2RouteTableAssociationA89CAD56": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" + }, + "SubnetId": { + "Ref": "VpcPrivateSubnet2Subnet3788AAA1" + } + } + }, + "VpcPrivateSubnet2DefaultRoute060D2087": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VpcPublicSubnet1NATGateway4D7517AA" + } + } + }, + "VpcIGWD7BA715C": { + "Type": "AWS::EC2::InternetGateway", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "TestStack/Vpc" + } + ] + } + }, + "VpcVPCGWBF912B6E": { + "Type": "AWS::EC2::VPCGatewayAttachment", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "InternetGatewayId": { + "Ref": "VpcIGWD7BA715C" + } + } + }, + "TaskTaskRoleE98524A1": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "ecs-tasks.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "Task79114B6B": { + "Type": "AWS::ECS::TaskDefinition", + "Properties": { + "ContainerDefinitions": [ + { + "Essential": true, + "Image": "public.ecr.aws/nginx/nginx:latest", + "Name": "nginx", + "PortMappings": [ + { + "ContainerPort": 80, + "Protocol": "tcp" + } + ] + } + ], + "Cpu": "256", + "Family": "TestStackTask24CEEDF4", + "Memory": "512", + "NetworkMode": "awsvpc", + "RequiresCompatibilities": [ + "FARGATE" + ], + "TaskRoleArn": { + "Fn::GetAtt": [ + "TaskTaskRoleE98524A1", + "Arn" + ] + } + } + }, + "ServiceLBE9A1ADBC": { + "Type": "AWS::ElasticLoadBalancingV2::LoadBalancer", + "Properties": { + "LoadBalancerAttributes": [ + { + "Key": "deletion_protection.enabled", + "Value": "false" + } + ], + "Scheme": "internal", + "SecurityGroups": [ + { + "Fn::GetAtt": [ + "ServiceLBSecurityGroupF7435A5C", + "GroupId" + ] + } + ], + "Subnets": [ + { + "Ref": "VpcPrivateSubnet1Subnet536B997A" + }, + { + "Ref": "VpcPrivateSubnet2Subnet3788AAA1" + } + ], + "Type": "application" + } + }, + "ServiceLBSecurityGroupF7435A5C": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "Automatically created Security Group for ELB TestStackServiceLBD3BB32E9", + "SecurityGroupIngress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow from anyone on port 80", + "FromPort": 80, + "IpProtocol": "tcp", + "ToPort": 80 + } + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } + } + }, + "ServiceLBSecurityGrouptoTestStackServiceSecurityGroup59159BDD804A6BA8AC": { + "Type": "AWS::EC2::SecurityGroupEgress", + "Properties": { + "GroupId": { + "Fn::GetAtt": [ + "ServiceLBSecurityGroupF7435A5C", + "GroupId" + ] + }, + "IpProtocol": "tcp", + "Description": "Load balancer to target", + "DestinationSecurityGroupId": { + "Fn::GetAtt": [ + "ServiceSecurityGroupEEA09B68", + "GroupId" + ] + }, + "FromPort": 80, + "ToPort": 80 + } + }, + "ServiceLBPublicListener46709EAA": { + "Type": "AWS::ElasticLoadBalancingV2::Listener", + "Properties": { + "DefaultActions": [ + { + "TargetGroupArn": { + "Ref": "ServiceLBPublicListenerECSGroup0CC8688C" + }, + "Type": "forward" + } + ], + "LoadBalancerArn": { + "Ref": "ServiceLBE9A1ADBC" + }, + "Port": 80, + "Protocol": "HTTP" + } + }, + "ServiceLBPublicListenerECSGroup0CC8688C": { + "Type": "AWS::ElasticLoadBalancingV2::TargetGroup", + "Properties": { + "Port": 80, + "Protocol": "HTTP", + "TargetType": "ip", + "VpcId": { + "Ref": "Vpc8378EB38" + } + } + }, + "Service9571FDD8": { + "Type": "AWS::ECS::Service", + "Properties": { + "Cluster": { + "Ref": "EcsDefaultClusterMnL3mNNYNVpc18E0451A" + }, + "DeploymentConfiguration": { + "MaximumPercent": 200, + "MinimumHealthyPercent": 50 + }, + "EnableECSManagedTags": false, + "HealthCheckGracePeriodSeconds": 60, + "LaunchType": "FARGATE", + "LoadBalancers": [ + { + "ContainerName": "nginx", + "ContainerPort": 80, + "TargetGroupArn": { + "Ref": "ServiceLBPublicListenerECSGroup0CC8688C" + } + } + ], + "NetworkConfiguration": { + "AwsvpcConfiguration": { + "AssignPublicIp": "DISABLED", + "SecurityGroups": [ + { + "Fn::GetAtt": [ + "ServiceSecurityGroupEEA09B68", + "GroupId" + ] + } + ], + "Subnets": [ + { + "Ref": "VpcPrivateSubnet1Subnet536B997A" + }, + { + "Ref": "VpcPrivateSubnet2Subnet3788AAA1" + } + ] + } + }, + "TaskDefinition": { + "Ref": "Task79114B6B" + } + }, + "DependsOn": [ + "ServiceLBPublicListenerECSGroup0CC8688C", + "ServiceLBPublicListener46709EAA" + ] + }, + "ServiceSecurityGroupEEA09B68": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "TestStack/Service/Service/SecurityGroup", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } + } + }, + "ServiceSecurityGroupfromTestStackServiceLBSecurityGroup76260E3B8004FB511A": { + "Type": "AWS::EC2::SecurityGroupIngress", + "Properties": { + "IpProtocol": "tcp", + "Description": "Load balancer to target", + "FromPort": 80, + "GroupId": { + "Fn::GetAtt": [ + "ServiceSecurityGroupEEA09B68", + "GroupId" + ] + }, + "SourceSecurityGroupId": { + "Fn::GetAtt": [ + "ServiceLBSecurityGroupF7435A5C", + "GroupId" + ] + }, + "ToPort": 80 + } + }, + "EcsDefaultClusterMnL3mNNYNVpc18E0451A": { + "Type": "AWS::ECS::Cluster" + }, + "NlbBCDB97FE": { + "Type": "AWS::ElasticLoadBalancingV2::LoadBalancer", + "Properties": { + "LoadBalancerAttributes": [ + { + "Key": "deletion_protection.enabled", + "Value": "false" + }, + { + "Key": "load_balancing.cross_zone.enabled", + "Value": "true" + } + ], + "Scheme": "internet-facing", + "Subnets": [ + { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, + { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + } + ], + "Type": "network" + }, + "DependsOn": [ + "VpcPublicSubnet1DefaultRoute3DA9E72A", + "VpcPublicSubnet2DefaultRoute97F91067" + ] + }, + "NlblistenerBE297616": { + "Type": "AWS::ElasticLoadBalancingV2::Listener", + "Properties": { + "DefaultActions": [ + { + "TargetGroupArn": { + "Ref": "NlblistenerTargetsGroupDD2A3CB0" + }, + "Type": "forward" + } + ], + "LoadBalancerArn": { + "Ref": "NlbBCDB97FE" + }, + "Port": 80, + "Protocol": "TCP" + } + }, + "NlblistenerTargetsGroupDD2A3CB0": { + "Type": "AWS::ElasticLoadBalancingV2::TargetGroup", + "Properties": { + "HealthCheckProtocol": "HTTP", + "Port": 80, + "Protocol": "TCP", + "Targets": [ + { + "Id": { + "Ref": "ServiceLBE9A1ADBC" + }, + "Port": 80 + } + ], + "TargetType": "alb", + "VpcId": { + "Ref": "Vpc8378EB38" + } + } + } + }, + "Outputs": { + "ServiceLoadBalancerDNSEC5B149E": { + "Value": { + "Fn::GetAtt": [ + "ServiceLBE9A1ADBC", + "DNSName" + ] + } + }, + "ServiceServiceURL250C0FB6": { + "Value": { + "Fn::Join": [ + "", + [ + "http://", + { + "Fn::GetAtt": [ + "ServiceLBE9A1ADBC", + "DNSName" + ] + } + ] + ] + } + }, + "NlbEndpoint": { + "Value": { + "Fn::Join": [ + "", + [ + "http://", + { + "Fn::GetAtt": [ + "NlbBCDB97FE", + "DNSName" + ] + } + ] + ] + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/integ.alb-target.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/integ.alb-target.ts new file mode 100644 index 0000000000000..80a5e6880ffab --- /dev/null +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/integ.alb-target.ts @@ -0,0 +1,49 @@ +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as ecs from '@aws-cdk/aws-ecs'; +import * as patterns from '@aws-cdk/aws-ecs-patterns'; +import * as elbv2 from '@aws-cdk/aws-elasticloadbalancingv2'; +import { App, CfnOutput, Stack, StackProps } from '@aws-cdk/core'; +import { Construct } from 'constructs'; +import * as targets from '../lib'; + +class TestStack extends Stack { + constructor(scope: Construct, id: string, props?: StackProps) { + super(scope, id, props); + + const vpc = new ec2.Vpc(this, 'Vpc', { maxAzs: 2, natGateways: 1 }); + + const task = new ecs.FargateTaskDefinition(this, 'Task', { cpu: 256, memoryLimitMiB: 512 }); + task.addContainer('nginx', { + image: ecs.ContainerImage.fromRegistry('public.ecr.aws/nginx/nginx:latest'), + portMappings: [{ containerPort: 80 }], + }); + const svc = new patterns.ApplicationLoadBalancedFargateService(this, 'Service', { + vpc, + taskDefinition: task, + publicLoadBalancer: false, + }); + + const nlb = new elbv2.NetworkLoadBalancer(this, 'Nlb', { + vpc, + crossZoneEnabled: true, + internetFacing: true, + }); + const listener = nlb.addListener('listener', { + port: 80, + }); + + listener.addTargets('Targets', { + targets: [new targets.AlbTarget(svc.loadBalancer, 80)], + port: 80, + healthCheck: { + protocol: elbv2.Protocol.HTTP, + }, + }); + + new CfnOutput(this, 'NlbEndpoint', { value: `http://${nlb.loadBalancerDnsName}` }); + } +} + +const app = new App(); +new TestStack(app, 'TestStack'); +app.synth(); diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/.eslintrc.js b/packages/@aws-cdk/aws-elasticloadbalancingv2/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/.eslintrc.js +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/README.md b/packages/@aws-cdk/aws-elasticloadbalancingv2/README.md index 200322e52999e..f3d23b5e827cf 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/README.md +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/README.md @@ -323,6 +323,47 @@ listener.addTargets('Targets', { Only a single Lambda function can be added to a single listener rule. +## Using Application Load Balancer Targets + +To use a single application load balancer as a target for the network load balancer, use the integration class in the +`@aws-cdk/aws-elasticloadbalancingv2-targets` package: + +```ts +import * as elbv2 from '@aws-cdk/aws-elasticloadbalancingv2'; +import * as targets from '@aws-cdk/aws-elasticloadbalancingv2-targets'; +import * as ecs from '@aws-cdk/aws-ecs'; +import * as patterns from '@aws-cdk/aws-ecs-patterns'; + +const task = new ecs.FargateTaskDefinition(this, 'Task', { cpu: 256, memoryLimitMiB: 512 }); +task.addContainer('nginx', { + image: ecs.ContainerImage.fromRegistry('public.ecr.aws/nginx/nginx:latest'), + portMappings: [{ containerPort: 80 }], +}); + +const svc = new patterns.ApplicationLoadBalancedFargateService(this, 'Service', { + vpc, + taskDefinition: task, + publicLoadBalancer: false, +}); + +const nlb = new elbv2.NetworkLoadBalancer(this, 'Nlb', { + vpc, + crossZoneEnabled: true, + internetFacing: true, +}); + +const listener = nlb.addListener('listener', { port: 80 }); + +listener.addTargets('Targets', { + targets: [new targets.AlbTarget(svc.loadBalancer, 80)], + port: 80, +}); + +new CfnOutput(this, 'NlbEndpoint', { value: `http://${nlb.loadBalancerDnsName}`}) +``` + +Only the network load balancer is allowed to add the application load balancer as the target. + ## Configuring Health Checks Health checks are configured upon creation of a target group: diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/jest.config.js b/packages/@aws-cdk/aws-elasticloadbalancingv2/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/jest.config.js +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener.ts index a1ea49a3b18a6..1a2e6c55ee815 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener.ts @@ -42,7 +42,7 @@ export interface BaseApplicationListenerProps { readonly certificateArns?: string[]; /** - * Certificate list of ACM cert ARNs + * Certificate list of ACM cert ARNs. You must provide exactly one certificate if the listener protocol is HTTPS or TLS. * * @default - No certificates. */ diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-target-group.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-target-group.ts index 4c3085f2d5a66..d1329665ba7d6 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-target-group.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-target-group.ts @@ -376,11 +376,21 @@ export class ApplicationTargetGroup extends TargetGroupBase implements IApplicat ret.push('At least one of \'port\' or \'protocol\' is required for a non-Lambda TargetGroup'); } - if (this.healthCheck && this.healthCheck.protocol && !ALB_HEALTH_CHECK_PROTOCOLS.includes(this.healthCheck.protocol)) { - ret.push([ - `Health check protocol '${this.healthCheck.protocol}' is not supported. `, - `Must be one of [${ALB_HEALTH_CHECK_PROTOCOLS.join(', ')}]`, - ].join('')); + if (this.healthCheck && this.healthCheck.protocol) { + + if (ALB_HEALTH_CHECK_PROTOCOLS.includes(this.healthCheck.protocol)) { + if (this.healthCheck.interval && this.healthCheck.timeout && + this.healthCheck.interval.toMilliseconds() <= this.healthCheck.timeout.toMilliseconds()) { + ret.push(`Healthcheck interval ${this.healthCheck.interval.toHumanString()} must be greater than the timeout ${this.healthCheck.timeout.toHumanString()}`); + } + } + + if (!ALB_HEALTH_CHECK_PROTOCOLS.includes(this.healthCheck.protocol)) { + ret.push([ + `Health check protocol '${this.healthCheck.protocol}' is not supported. `, + `Must be one of [${ALB_HEALTH_CHECK_PROTOCOLS.join(', ')}]`, + ].join('')); + } } return ret; diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/nlb/network-listener.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/nlb/network-listener.ts index 2a5fbce2a28a1..4cfed265217f5 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/nlb/network-listener.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/nlb/network-listener.ts @@ -53,7 +53,7 @@ export interface BaseNetworkListenerProps { readonly protocol?: Protocol; /** - * Certificate list of ACM cert ARNs + * Certificate list of ACM cert ARNs. You must provide exactly one certificate if the listener protocol is HTTPS or TLS. * * @default - No certificates. */ diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-target-group.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-target-group.ts index 96acd45b34a4c..29a9cb707556e 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-target-group.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-target-group.ts @@ -269,7 +269,7 @@ export abstract class TargetGroupBase extends CoreConstruct implements ITargetGr healthyThresholdCount: cdk.Lazy.number({ produce: () => this.healthCheck?.healthyThresholdCount }), unhealthyThresholdCount: cdk.Lazy.number({ produce: () => this.healthCheck?.unhealthyThresholdCount }), matcher: cdk.Lazy.any({ - produce: () => this.healthCheck?.healthyHttpCodes !== undefined || this.healthCheck?.healthyGrpcCodes !== undefined ? { + produce: () => this.healthCheck?.healthyHttpCodes !== undefined || this.healthCheck?.healthyGrpcCodes !== undefined ? { grpcCode: this.healthCheck.healthyGrpcCodes, httpCode: this.healthCheck.healthyHttpCodes, } : undefined, @@ -297,11 +297,6 @@ export abstract class TargetGroupBase extends CoreConstruct implements ITargetGr * Set/replace the target group's health check */ public configureHealthCheck(healthCheck: HealthCheck) { - if (healthCheck.interval && healthCheck.timeout) { - if (healthCheck.interval.toMilliseconds() <= healthCheck.timeout.toMilliseconds()) { - throw new Error(`Healthcheck interval ${healthCheck.interval.toHumanString()} must be greater than the timeout ${healthCheck.timeout.toHumanString()}`); - } - } this.healthCheck = healthCheck; } diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/enums.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/enums.ts index a711211a44065..2dc293e1b8905 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/enums.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/enums.ts @@ -170,6 +170,11 @@ export enum TargetType { * Target is a single Lambda Function */ LAMBDA = 'lambda', + + /** + * Target is a single Application Load Balancer + */ + ALB = 'alb', } /** diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/package.json b/packages/@aws-cdk/aws-elasticloadbalancingv2/package.json index cf411cbd32c88..2a74598925bbb 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/package.json +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::ElasticLoadBalancingV2", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,12 +72,12 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/aws-certificatemanager": "0.0.0", @@ -104,8 +103,8 @@ "@aws-cdk/cloud-assembly-schema": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/cx-api": "0.0.0", - "constructs": "^3.3.69", - "@aws-cdk/region-info": "0.0.0" + "@aws-cdk/region-info": "0.0.0", + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/load-balancer.test.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/load-balancer.test.ts index 7cf10a01d7595..d935a915d55e7 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/load-balancer.test.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/load-balancer.test.ts @@ -5,7 +5,7 @@ import * as ec2 from '@aws-cdk/aws-ec2'; import * as s3 from '@aws-cdk/aws-s3'; import * as cdk from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; -import { testFutureBehavior } from 'cdk-build-tools/lib/feature-flag'; +import { testFutureBehavior } from '@aws-cdk/cdk-build-tools/lib/feature-flag'; import * as elbv2 from '../../lib'; const s3GrantWriteCtx = { [cxapi.S3_GRANT_WRITE_WITHOUT_ACL]: true }; diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/target-group.test.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/target-group.test.ts index f1a3db5eb9508..078be310dd3f8 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/target-group.test.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/target-group.test.ts @@ -282,44 +282,187 @@ describe('tests', () => { }); }); - test('Interval equal to timeout', () => { - // GIVEN - const app = new cdk.App(); - const stack = new cdk.Stack(app, 'Stack'); - const vpc = new ec2.Vpc(stack, 'VPC', {}); + test.each([elbv2.Protocol.UDP, elbv2.Protocol.TCP_UDP, elbv2.Protocol.TLS])( + 'Throws validation error, when `healthCheck` has `protocol` set to %s', + (protocol) => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack'); + const vpc = new ec2.Vpc(stack, 'VPC', {}); + + // WHEN + new elbv2.ApplicationTargetGroup(stack, 'TargetGroup', { + vpc, + healthCheck: { + protocol: protocol, + }, + }); - // WHEN - const tg = new elbv2.ApplicationTargetGroup(stack, 'TargetGroup', { - vpc, + // THEN + expect(() => { + app.synth(); + }).toThrow(`Health check protocol '${protocol}' is not supported. Must be one of [HTTP, HTTPS]`); }); - // THEN - expect(() => { + test.each([elbv2.Protocol.UDP, elbv2.Protocol.TCP_UDP, elbv2.Protocol.TLS])( + 'Throws validation error, when `configureHealthCheck()` has `protocol` set to %s', + (protocol) => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack'); + const vpc = new ec2.Vpc(stack, 'VPC', {}); + const tg = new elbv2.ApplicationTargetGroup(stack, 'TargetGroup', { + vpc, + }); + + // WHEN + tg.configureHealthCheck({ + protocol: protocol, + }); + + // THEN + expect(() => { + app.synth(); + }).toThrow(`Health check protocol '${protocol}' is not supported. Must be one of [HTTP, HTTPS]`); + }); + + test.each([elbv2.Protocol.HTTP, elbv2.Protocol.HTTPS])( + 'Does not throw validation error, when `healthCheck` has `protocol` set to %s', + (protocol) => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack'); + const vpc = new ec2.Vpc(stack, 'VPC', {}); + + // WHEN + new elbv2.ApplicationTargetGroup(stack, 'TargetGroup', { + vpc, + healthCheck: { + protocol: protocol, + }, + }); + + // THEN + expect(() => { + app.synth(); + }).not.toThrowError(); + }); + + test.each([elbv2.Protocol.HTTP, elbv2.Protocol.HTTPS])( + 'Does not throw validation error, when `configureHealthCheck()` has `protocol` set to %s', + (protocol) => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack'); + const vpc = new ec2.Vpc(stack, 'VPC', {}); + const tg = new elbv2.ApplicationTargetGroup(stack, 'TargetGroup', { + vpc, + }); + + // WHEN + tg.configureHealthCheck({ + protocol: protocol, + }); + + // THEN + expect(() => { + app.synth(); + }).not.toThrowError(); + }); + + test.each([elbv2.Protocol.HTTP, elbv2.Protocol.HTTPS])( + 'Throws validation error, when `healthCheck` has `protocol` set to %s and `interval` is equal to `timeout`', + (protocol) => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack'); + const vpc = new ec2.Vpc(stack, 'VPC', {}); + + // WHEN + new elbv2.ApplicationTargetGroup(stack, 'TargetGroup', { + vpc, + healthCheck: { + interval: cdk.Duration.seconds(60), + timeout: cdk.Duration.seconds(60), + protocol: protocol, + }, + }); + + // THEN + expect(() => { + app.synth(); + }).toThrow('Healthcheck interval 1 minute must be greater than the timeout 1 minute'); + }); + + test.each([elbv2.Protocol.HTTP, elbv2.Protocol.HTTPS])( + 'Throws validation error, when `healthCheck` has `protocol` set to %s and `interval` is smaller than `timeout`', + (protocol) => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack'); + const vpc = new ec2.Vpc(stack, 'VPC', {}); + + // WHEN + new elbv2.ApplicationTargetGroup(stack, 'TargetGroup', { + vpc, + healthCheck: { + interval: cdk.Duration.seconds(60), + timeout: cdk.Duration.seconds(120), + protocol: protocol, + }, + }); + + // THEN + expect(() => { + app.synth(); + }).toThrow('Healthcheck interval 1 minute must be greater than the timeout 2 minutes'); + }); + + test.each([elbv2.Protocol.HTTP, elbv2.Protocol.HTTPS])( + 'Throws validation error, when `configureHealthCheck()` has `protocol` set to %s and `interval` is equal to `timeout`', + (protocol) => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack'); + const vpc = new ec2.Vpc(stack, 'VPC', {}); + const tg = new elbv2.ApplicationTargetGroup(stack, 'TargetGroup', { + vpc, + }); + + // WHEN tg.configureHealthCheck({ interval: cdk.Duration.seconds(60), timeout: cdk.Duration.seconds(60), + protocol: protocol, }); - }).toThrow(/Healthcheck interval 1 minute must be greater than the timeout 1 minute/); - }); - - test('Interval smaller than timeout', () => { - // GIVEN - const app = new cdk.App(); - const stack = new cdk.Stack(app, 'Stack'); - const vpc = new ec2.Vpc(stack, 'VPC', {}); - // WHEN - const tg = new elbv2.ApplicationTargetGroup(stack, 'TargetGroup', { - vpc, + // THEN + expect(() => { + app.synth(); + }).toThrow('Healthcheck interval 1 minute must be greater than the timeout 1 minute'); }); - // THEN - expect(() => { + test.each([elbv2.Protocol.HTTP, elbv2.Protocol.HTTPS])( + 'Throws validation error, when `configureHealthCheck()` has `protocol` set to %s and `interval` is smaller than `timeout`', + (protocol) => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack'); + const vpc = new ec2.Vpc(stack, 'VPC', {}); + const tg = new elbv2.ApplicationTargetGroup(stack, 'TargetGroup', { + vpc, + }); + + // WHEN tg.configureHealthCheck({ interval: cdk.Duration.seconds(60), timeout: cdk.Duration.seconds(120), + protocol: protocol, }); - }).toThrow(/Healthcheck interval 1 minute must be greater than the timeout 2 minutes/); - }); + // THEN + expect(() => { + app.synth(); + }).toThrow('Healthcheck interval 1 minute must be greater than the timeout 2 minutes'); + }); }); diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/load-balancer.test.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/load-balancer.test.ts index 63cfc2462bddf..ccfb2924e211e 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/load-balancer.test.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/load-balancer.test.ts @@ -4,7 +4,7 @@ import * as ec2 from '@aws-cdk/aws-ec2'; import * as s3 from '@aws-cdk/aws-s3'; import * as cdk from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; -import { testFutureBehavior } from 'cdk-build-tools/lib/feature-flag'; +import { testFutureBehavior } from '@aws-cdk/cdk-build-tools/lib/feature-flag'; import * as elbv2 from '../../lib'; const s3GrantWriteCtx = { [cxapi.S3_GRANT_WRITE_WITHOUT_ACL]: true }; diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/target-group.test.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/target-group.test.ts index 90aa39b37141b..1b35e2a2f232b 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/target-group.test.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/target-group.test.ts @@ -126,19 +126,6 @@ describe('tests', () => { }); }); - test('Throws error for unacceptable protocol', () => { - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'Vpc'); - - expect(() => { - new elbv2.NetworkTargetGroup(stack, 'Group', { - vpc, - port: 80, - protocol: elbv2.Protocol.HTTPS, - }); - }).toThrow(); - }); - test('Throws error for invalid health check interval', () => { const app = new cdk.App(); const stack = new cdk.Stack(app, 'Stack'); @@ -157,42 +144,243 @@ describe('tests', () => { }).toThrow(/Health check interval '5' not supported. Must be one of the following values '10,30'./); }); - test('Throws error for invalid health check protocol', () => { - const app = new cdk.App(); - const stack = new cdk.Stack(app, 'Stack'); - const vpc = new ec2.Vpc(stack, 'Vpc'); + test.each([elbv2.Protocol.UDP, elbv2.Protocol.TCP_UDP, elbv2.Protocol.TLS])( + 'Throws validation error, when `healthCheck` has `protocol` set to %s', + (protocol) => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack'); + const vpc = new ec2.Vpc(stack, 'VPC', {}); - new elbv2.NetworkTargetGroup(stack, 'Group', { - vpc, - port: 80, - healthCheck: { - protocol: elbv2.Protocol.UDP, - }, + // WHEN + new elbv2.NetworkTargetGroup(stack, 'TargetGroup', { + vpc, + port: 80, + healthCheck: { + protocol: protocol, + }, + }); + + // THEN + expect(() => { + app.synth(); + }).toThrow(`Health check protocol '${protocol}' is not supported. Must be one of [HTTP, HTTPS, TCP]`); }); - expect(() => { - app.synth(); - }).toThrow(/Health check protocol 'UDP' is not supported. Must be one of \[HTTP, HTTPS, TCP\]/); - }); + test.each([elbv2.Protocol.UDP, elbv2.Protocol.TCP_UDP, elbv2.Protocol.TLS])( + 'Throws validation error, when `configureHealthCheck()` has `protocol` set to %s', + (protocol) => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack'); + const vpc = new ec2.Vpc(stack, 'VPC', {}); + const tg = new elbv2.NetworkTargetGroup(stack, 'TargetGroup', { + vpc, + port: 80, + }); - test('Throws error for health check path property when protocol does not support it', () => { - const app = new cdk.App(); - const stack = new cdk.Stack(app, 'Stack'); - const vpc = new ec2.Vpc(stack, 'Vpc'); + // WHEN + tg.configureHealthCheck({ + protocol: protocol, + }); - new elbv2.NetworkTargetGroup(stack, 'Group', { - vpc, - port: 80, - healthCheck: { + // THEN + expect(() => { + app.synth(); + }).toThrow(`Health check protocol '${protocol}' is not supported. Must be one of [HTTP, HTTPS, TCP]`); + }); + + test.each([elbv2.Protocol.HTTP, elbv2.Protocol.HTTPS, elbv2.Protocol.TCP])( + 'Does not throw validation error, when `healthCheck` has `protocol` set to %s', + (protocol) => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack'); + const vpc = new ec2.Vpc(stack, 'VPC', {}); + + // WHEN + new elbv2.NetworkTargetGroup(stack, 'TargetGroup', { + vpc, + port: 80, + healthCheck: { + protocol: protocol, + }, + }); + + // THEN + expect(() => { + app.synth(); + }).not.toThrowError(); + }); + + test.each([elbv2.Protocol.HTTP, elbv2.Protocol.HTTPS, elbv2.Protocol.TCP])( + 'Does not throw validation error, when `configureHealthCheck()` has `protocol` set to %s', + (protocol) => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack'); + const vpc = new ec2.Vpc(stack, 'VPC', {}); + const tg = new elbv2.NetworkTargetGroup(stack, 'TargetGroup', { + vpc, + port: 80, + }); + + // WHEN + tg.configureHealthCheck({ + protocol: protocol, + }); + + // THEN + expect(() => { + app.synth(); + }).not.toThrowError(); + }); + + test.each([elbv2.Protocol.TCP, elbv2.Protocol.HTTPS])( + 'Does not throw a validation error, when `healthCheck` has `protocol` set to %s and `interval` is equal to `timeout`', + (protocol) => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack'); + const vpc = new ec2.Vpc(stack, 'VPC', {}); + + // WHEN + new elbv2.NetworkTargetGroup(stack, 'TargetGroup', { + vpc, + port: 80, + healthCheck: { + interval: cdk.Duration.seconds(10), + timeout: cdk.Duration.seconds(10), + protocol: protocol, + }, + }); + + // THEN + expect(() => { + app.synth(); + }).not.toThrowError(); + }); + + test.each([elbv2.Protocol.TCP, elbv2.Protocol.HTTPS])( + 'Does not throw a validation error, when `configureHealthCheck()` has `protocol` set to %s and `interval` is equal to `timeout`', + (protocol) => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack'); + const vpc = new ec2.Vpc(stack, 'VPC', {}); + const tg = new elbv2.NetworkTargetGroup(stack, 'TargetGroup', { + vpc, + port: 80, + }); + + // WHEN + tg.configureHealthCheck({ + interval: cdk.Duration.seconds(10), + timeout: cdk.Duration.seconds(10), + protocol: protocol, + }); + + // THEN + expect(() => { + app.synth(); + }).not.toThrowError(); + }); + + test.each([elbv2.Protocol.UDP, elbv2.Protocol.TCP_UDP, elbv2.Protocol.TLS])( + 'Throws validation error,`healthCheck` has `protocol` set to %s and `path` is provided', + (protocol) => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack'); + const vpc = new ec2.Vpc(stack, 'VPC', {}); + + // WHEN + new elbv2.NetworkTargetGroup(stack, 'TargetGroup', { + vpc, + port: 80, + healthCheck: { + path: '/my-path', + protocol: protocol, + }, + }); + + // THEN + expect(() => { + app.synth(); + }).toThrow(`'${protocol}' health checks do not support the path property. Must be one of [HTTP, HTTPS]`); + }); + + test.each([elbv2.Protocol.UDP, elbv2.Protocol.TCP_UDP, elbv2.Protocol.TLS])( + 'Throws validation error, when `configureHealthCheck()` has `protocol` set to %s and `path` is provided', + (protocol) => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack'); + const vpc = new ec2.Vpc(stack, 'VPC', {}); + const tg = new elbv2.NetworkTargetGroup(stack, 'TargetGroup', { + vpc, + port: 80, + }); + + // WHEN + tg.configureHealthCheck({ path: '/my-path', - protocol: elbv2.Protocol.TCP, - }, + protocol: protocol, + }); + + // THEN + expect(() => { + app.synth(); + }).toThrow(`'${protocol}' health checks do not support the path property. Must be one of [HTTP, HTTPS]`); }); - expect(() => { - app.synth(); - }).toThrow(/'TCP' health checks do not support the path property. Must be one of \[HTTP, HTTPS\]/); - }); + test.each([elbv2.Protocol.HTTP, elbv2.Protocol.HTTPS])( + 'Does not throw validation error, when `healthCheck` has `protocol` set to %s and `path` is provided', + (protocol) => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack'); + const vpc = new ec2.Vpc(stack, 'VPC', {}); + + // WHEN + new elbv2.NetworkTargetGroup(stack, 'TargetGroup', { + vpc, + port: 80, + healthCheck: { + path: '/my-path', + protocol: protocol, + }, + }); + + // THEN + expect(() => { + app.synth(); + }).not.toThrowError(); + }); + + test.each([elbv2.Protocol.HTTP, elbv2.Protocol.HTTPS])( + 'Does not throw validation error, when `configureHealthCheck()` has `protocol` set to %s and `path` is provided', + (protocol) => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack'); + const vpc = new ec2.Vpc(stack, 'VPC', {}); + const tg = new elbv2.NetworkTargetGroup(stack, 'TargetGroup', { + vpc, + port: 80, + }); + + // WHEN + tg.configureHealthCheck({ + path: '/my-path', + protocol: protocol, + }); + + // THEN + expect(() => { + app.synth(); + }).not.toThrowError(); + }); test('Throws error for invalid health check healthy threshold', () => { const app = new cdk.App(); diff --git a/packages/@aws-cdk/aws-elasticsearch/.eslintrc.js b/packages/@aws-cdk/aws-elasticsearch/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-elasticsearch/.eslintrc.js +++ b/packages/@aws-cdk/aws-elasticsearch/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-elasticsearch/jest.config.js b/packages/@aws-cdk/aws-elasticsearch/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-elasticsearch/jest.config.js +++ b/packages/@aws-cdk/aws-elasticsearch/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-elasticsearch/package.json b/packages/@aws-cdk/aws-elasticsearch/package.json index 37c35b69393b2..bed6ead349ed2 100644 --- a/packages/@aws-cdk/aws-elasticsearch/package.json +++ b/packages/@aws-cdk/aws-elasticsearch/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::Elasticsearch", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,12 +72,12 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/aws-certificatemanager": "0.0.0", @@ -89,8 +88,8 @@ "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-route53": "0.0.0", "@aws-cdk/aws-secretsmanager": "0.0.0", - "@aws-cdk/custom-resources": "0.0.0", "@aws-cdk/core": "0.0.0", + "@aws-cdk/custom-resources": "0.0.0", "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", @@ -103,8 +102,8 @@ "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-route53": "0.0.0", "@aws-cdk/aws-secretsmanager": "0.0.0", - "@aws-cdk/custom-resources": "0.0.0", "@aws-cdk/core": "0.0.0", + "@aws-cdk/custom-resources": "0.0.0", "constructs": "^3.3.69" }, "engines": { diff --git a/packages/@aws-cdk/aws-emr/.eslintrc.js b/packages/@aws-cdk/aws-emr/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-emr/.eslintrc.js +++ b/packages/@aws-cdk/aws-emr/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-emr/jest.config.js b/packages/@aws-cdk/aws-emr/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-emr/jest.config.js +++ b/packages/@aws-cdk/aws-emr/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-emr/package.json b/packages/@aws-cdk/aws-emr/package.json index 337790cd07b03..a4983f2f01503 100644 --- a/packages/@aws-cdk/aws-emr/package.json +++ b/packages/@aws-cdk/aws-emr/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::EMR", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,11 +72,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-emrcontainers/.eslintrc.js b/packages/@aws-cdk/aws-emrcontainers/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-emrcontainers/.eslintrc.js +++ b/packages/@aws-cdk/aws-emrcontainers/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-emrcontainers/jest.config.js b/packages/@aws-cdk/aws-emrcontainers/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-emrcontainers/jest.config.js +++ b/packages/@aws-cdk/aws-emrcontainers/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-emrcontainers/package.json b/packages/@aws-cdk/aws-emrcontainers/package.json index 8ea1659c08e57..4efce3b89f65d 100644 --- a/packages/@aws-cdk/aws-emrcontainers/package.json +++ b/packages/@aws-cdk/aws-emrcontainers/package.json @@ -58,7 +58,6 @@ }, "cdk-build": { "cloudformation": "AWS::EMRContainers", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -77,11 +76,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-events-targets/.eslintrc.js b/packages/@aws-cdk/aws-events-targets/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-events-targets/.eslintrc.js +++ b/packages/@aws-cdk/aws-events-targets/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-events-targets/jest.config.js b/packages/@aws-cdk/aws-events-targets/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-events-targets/jest.config.js +++ b/packages/@aws-cdk/aws-events-targets/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-events-targets/package.json b/packages/@aws-cdk/aws-events-targets/package.json index 3658b64701804..c2e0d3762085f 100644 --- a/packages/@aws-cdk/aws-events-targets/package.json +++ b/packages/@aws-cdk/aws-events-targets/package.json @@ -53,7 +53,6 @@ "build+test+extract": "yarn build+test && yarn rosetta:extract" }, "cdk-build": { - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,17 +72,17 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/aws-batch": "0.0.0", "@aws-cdk/aws-codecommit": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", - "@aws-cdk/aws-batch": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24", "aws-sdk": "^2.848.0", - "aws-sdk-mock": "^5.2.1", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "aws-sdk-mock": "^5.4.0", + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-apigateway": "0.0.0", @@ -99,8 +98,8 @@ "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-sns": "0.0.0", - "@aws-cdk/aws-sqs": "0.0.0", "@aws-cdk/aws-sns-subscriptions": "0.0.0", + "@aws-cdk/aws-sqs": "0.0.0", "@aws-cdk/aws-stepfunctions": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/custom-resources": "0.0.0", @@ -121,8 +120,8 @@ "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-sns": "0.0.0", - "@aws-cdk/aws-sqs": "0.0.0", "@aws-cdk/aws-sns-subscriptions": "0.0.0", + "@aws-cdk/aws-sqs": "0.0.0", "@aws-cdk/aws-stepfunctions": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/custom-resources": "0.0.0", diff --git a/packages/@aws-cdk/aws-events/.eslintrc.js b/packages/@aws-cdk/aws-events/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-events/.eslintrc.js +++ b/packages/@aws-cdk/aws-events/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-events/jest.config.js b/packages/@aws-cdk/aws-events/jest.config.js index cd664e1d069e5..34818e1593f6b 100644 --- a/packages/@aws-cdk/aws-events/jest.config.js +++ b/packages/@aws-cdk/aws-events/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +const baseConfig = require('../../../tools/@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-events/lib/event-pattern.ts b/packages/@aws-cdk/aws-events/lib/event-pattern.ts index bdd586f7e0e78..523223d3903d2 100644 --- a/packages/@aws-cdk/aws-events/lib/event-pattern.ts +++ b/packages/@aws-cdk/aws-events/lib/event-pattern.ts @@ -2,10 +2,14 @@ * Events in Amazon CloudWatch Events are represented as JSON objects. For more * information about JSON objects, see RFC 7159. * + * **Important**: this class can only be used with a `Rule` class. In particular, + * do not use it with `CfnRule` class: your pattern will not be rendered + * correctly. In a `CfnRule` class, write the pattern as you normally would when + * directly writing CloudFormation. + * * Rules use event patterns to select events and route them to targets. A * pattern either matches an event or it doesn't. Event patterns are represented - * as JSON objects with a structure that is similar to that of events, for - * example: + * as JSON objects with a structure that is similar to that of events. * * It is important to remember the following about event pattern matching: * diff --git a/packages/@aws-cdk/aws-events/package.json b/packages/@aws-cdk/aws-events/package.json index cf480c87c1dfe..e2cefb728f130 100644 --- a/packages/@aws-cdk/aws-events/package.json +++ b/packages/@aws-cdk/aws-events/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::Events", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -75,13 +74,12 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "@types/nodeunit": "^0.0.32", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-iam": "0.0.0", diff --git a/packages/@aws-cdk/aws-events/test/rule.test.ts b/packages/@aws-cdk/aws-events/test/rule.test.ts index 5cc3b6c5f03e1..21782c089b40c 100644 --- a/packages/@aws-cdk/aws-events/test/rule.test.ts +++ b/packages/@aws-cdk/aws-events/test/rule.test.ts @@ -1055,7 +1055,7 @@ describe('rule', () => { }); class SomeTarget implements IRuleTarget { - // eslint-disable-next-line cdk/no-core-construct + // eslint-disable-next-line @aws-cdk/no-core-construct public constructor(private readonly id?: string, private readonly resource?: cdk.IConstruct) { } diff --git a/packages/@aws-cdk/aws-eventschemas/.eslintrc.js b/packages/@aws-cdk/aws-eventschemas/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-eventschemas/.eslintrc.js +++ b/packages/@aws-cdk/aws-eventschemas/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-eventschemas/jest.config.js b/packages/@aws-cdk/aws-eventschemas/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-eventschemas/jest.config.js +++ b/packages/@aws-cdk/aws-eventschemas/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-eventschemas/package.json b/packages/@aws-cdk/aws-eventschemas/package.json index 2d9ea8b2602d6..817e1564b28d1 100644 --- a/packages/@aws-cdk/aws-eventschemas/package.json +++ b/packages/@aws-cdk/aws-eventschemas/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::EventSchemas", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-finspace/.eslintrc.js b/packages/@aws-cdk/aws-finspace/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-finspace/.eslintrc.js +++ b/packages/@aws-cdk/aws-finspace/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-finspace/jest.config.js b/packages/@aws-cdk/aws-finspace/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-finspace/jest.config.js +++ b/packages/@aws-cdk/aws-finspace/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-finspace/package.json b/packages/@aws-cdk/aws-finspace/package.json index 1886725b8d68e..bb869ef40b45d 100644 --- a/packages/@aws-cdk/aws-finspace/package.json +++ b/packages/@aws-cdk/aws-finspace/package.json @@ -58,7 +58,6 @@ }, "cdk-build": { "cloudformation": "AWS::FinSpace", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -77,11 +76,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", "@aws-cdk/assertions": "0.0.0", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-fis/.eslintrc.js b/packages/@aws-cdk/aws-fis/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-fis/.eslintrc.js +++ b/packages/@aws-cdk/aws-fis/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-fis/jest.config.js b/packages/@aws-cdk/aws-fis/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-fis/jest.config.js +++ b/packages/@aws-cdk/aws-fis/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-fis/package.json b/packages/@aws-cdk/aws-fis/package.json index ba17edd8f186f..3a0c6ab86b87b 100644 --- a/packages/@aws-cdk/aws-fis/package.json +++ b/packages/@aws-cdk/aws-fis/package.json @@ -58,7 +58,6 @@ }, "cdk-build": { "cloudformation": "AWS::FIS", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -77,11 +76,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-fms/.eslintrc.js b/packages/@aws-cdk/aws-fms/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-fms/.eslintrc.js +++ b/packages/@aws-cdk/aws-fms/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-fms/jest.config.js b/packages/@aws-cdk/aws-fms/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-fms/jest.config.js +++ b/packages/@aws-cdk/aws-fms/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-fms/package.json b/packages/@aws-cdk/aws-fms/package.json index d9056b520b7f1..f00081ac0ea9a 100644 --- a/packages/@aws-cdk/aws-fms/package.json +++ b/packages/@aws-cdk/aws-fms/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::FMS", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-frauddetector/.eslintrc.js b/packages/@aws-cdk/aws-frauddetector/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-frauddetector/.eslintrc.js +++ b/packages/@aws-cdk/aws-frauddetector/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-frauddetector/jest.config.js b/packages/@aws-cdk/aws-frauddetector/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-frauddetector/jest.config.js +++ b/packages/@aws-cdk/aws-frauddetector/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-frauddetector/package.json b/packages/@aws-cdk/aws-frauddetector/package.json index 84cfc1ce40738..0b8c48451b6b5 100644 --- a/packages/@aws-cdk/aws-frauddetector/package.json +++ b/packages/@aws-cdk/aws-frauddetector/package.json @@ -58,7 +58,6 @@ }, "cdk-build": { "cloudformation": "AWS::FraudDetector", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -77,11 +76,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", "@aws-cdk/assertions": "0.0.0", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-fsx/.eslintrc.js b/packages/@aws-cdk/aws-fsx/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-fsx/.eslintrc.js +++ b/packages/@aws-cdk/aws-fsx/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-fsx/jest.config.js b/packages/@aws-cdk/aws-fsx/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-fsx/jest.config.js +++ b/packages/@aws-cdk/aws-fsx/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-fsx/package.json b/packages/@aws-cdk/aws-fsx/package.json index 1370bae1727de..6c5b236e7037a 100644 --- a/packages/@aws-cdk/aws-fsx/package.json +++ b/packages/@aws-cdk/aws-fsx/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::FSx", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,12 +74,12 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/aws-ec2": "0.0.0", diff --git a/packages/@aws-cdk/aws-gamelift/.eslintrc.js b/packages/@aws-cdk/aws-gamelift/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-gamelift/.eslintrc.js +++ b/packages/@aws-cdk/aws-gamelift/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-gamelift/jest.config.js b/packages/@aws-cdk/aws-gamelift/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-gamelift/jest.config.js +++ b/packages/@aws-cdk/aws-gamelift/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-gamelift/package.json b/packages/@aws-cdk/aws-gamelift/package.json index 299bf7e8ca563..9e3d586dbab6b 100644 --- a/packages/@aws-cdk/aws-gamelift/package.json +++ b/packages/@aws-cdk/aws-gamelift/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::GameLift", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,11 +72,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-globalaccelerator-endpoints/.eslintrc.js b/packages/@aws-cdk/aws-globalaccelerator-endpoints/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-globalaccelerator-endpoints/.eslintrc.js +++ b/packages/@aws-cdk/aws-globalaccelerator-endpoints/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-globalaccelerator-endpoints/jest.config.js b/packages/@aws-cdk/aws-globalaccelerator-endpoints/jest.config.js index 49e81658a0875..e5862b88aa35e 100644 --- a/packages/@aws-cdk/aws-globalaccelerator-endpoints/jest.config.js +++ b/packages/@aws-cdk/aws-globalaccelerator-endpoints/jest.config.js @@ -1,4 +1,4 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = { ...baseConfig, coverageThreshold: { diff --git a/packages/@aws-cdk/aws-globalaccelerator-endpoints/package.json b/packages/@aws-cdk/aws-globalaccelerator-endpoints/package.json index 532b01de2fbe9..3991e52d8a5c8 100644 --- a/packages/@aws-cdk/aws-globalaccelerator-endpoints/package.json +++ b/packages/@aws-cdk/aws-globalaccelerator-endpoints/package.json @@ -52,7 +52,6 @@ "build+test+extract": "yarn build+test && yarn rosetta:extract" }, "cdk-build": { - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -70,14 +69,14 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24", "aws-sdk": "^2.848.0", - "aws-sdk-mock": "^5.2.1", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0" + "aws-sdk-mock": "^5.4.0", + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-ec2": "0.0.0", diff --git a/packages/@aws-cdk/aws-globalaccelerator/.eslintrc.js b/packages/@aws-cdk/aws-globalaccelerator/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-globalaccelerator/.eslintrc.js +++ b/packages/@aws-cdk/aws-globalaccelerator/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-globalaccelerator/jest.config.js b/packages/@aws-cdk/aws-globalaccelerator/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-globalaccelerator/jest.config.js +++ b/packages/@aws-cdk/aws-globalaccelerator/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-globalaccelerator/package.json b/packages/@aws-cdk/aws-globalaccelerator/package.json index b4b0e90197370..40f27c8a9d3b8 100644 --- a/packages/@aws-cdk/aws-globalaccelerator/package.json +++ b/packages/@aws-cdk/aws-globalaccelerator/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::GlobalAccelerator", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,13 +74,13 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", + "@aws-cdk/assert-internal": "0.0.0", "@aws-cdk/aws-elasticloadbalancingv2": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/aws-ec2": "0.0.0", @@ -92,8 +91,8 @@ "peerDependencies": { "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.3.69", - "@aws-cdk/custom-resources": "0.0.0" + "@aws-cdk/custom-resources": "0.0.0", + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-glue/.eslintrc.js b/packages/@aws-cdk/aws-glue/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-glue/.eslintrc.js +++ b/packages/@aws-cdk/aws-glue/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-glue/jest.config.js b/packages/@aws-cdk/aws-glue/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-glue/jest.config.js +++ b/packages/@aws-cdk/aws-glue/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-glue/package.json b/packages/@aws-cdk/aws-glue/package.json index daaba9400606c..50a535d9810eb 100644 --- a/packages/@aws-cdk/aws-glue/package.json +++ b/packages/@aws-cdk/aws-glue/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::Glue", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -73,24 +72,23 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/cx-api": "0.0.0", - "@types/nodeunit": "^0.0.32", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0" + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24", + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/assets": "0.0.0", "@aws-cdk/aws-cloudwatch": "0.0.0", - "@aws-cdk/aws-events": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", + "@aws-cdk/aws-events": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", - "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", + "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/aws-s3-assets": "0.0.0", "@aws-cdk/core": "0.0.0", @@ -100,11 +98,11 @@ "peerDependencies": { "@aws-cdk/assets": "0.0.0", "@aws-cdk/aws-cloudwatch": "0.0.0", - "@aws-cdk/aws-events": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", + "@aws-cdk/aws-events": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", - "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", + "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/aws-s3-assets": "0.0.0", "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-glue/test/table.test.ts b/packages/@aws-cdk/aws-glue/test/table.test.ts index fbb1424f766c1..6afc880d41dbb 100644 --- a/packages/@aws-cdk/aws-glue/test/table.test.ts +++ b/packages/@aws-cdk/aws-glue/test/table.test.ts @@ -4,8 +4,9 @@ import * as kms from '@aws-cdk/aws-kms'; import * as s3 from '@aws-cdk/aws-s3'; import * as cdk from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; -import { testFutureBehavior } from 'cdk-build-tools/lib/feature-flag'; +import { testFutureBehavior } from '@aws-cdk/cdk-build-tools/lib/feature-flag'; import * as glue from '../lib'; +import { CfnTable } from '../lib/glue.generated'; const s3GrantWriteCtx = { [cxapi.S3_GRANT_WRITE_WITHOUT_ACL]: true }; @@ -245,7 +246,7 @@ test('table.node.defaultChild', () => { }); // THEN - expect(table.node.defaultChild instanceof glue.CfnTable).toEqual(true); + expect(table.node.defaultChild instanceof CfnTable).toEqual(true); }); test('encrypted table: SSE-S3', () => { diff --git a/packages/@aws-cdk/aws-greengrass/.eslintrc.js b/packages/@aws-cdk/aws-greengrass/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-greengrass/.eslintrc.js +++ b/packages/@aws-cdk/aws-greengrass/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-greengrass/jest.config.js b/packages/@aws-cdk/aws-greengrass/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-greengrass/jest.config.js +++ b/packages/@aws-cdk/aws-greengrass/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-greengrass/package.json b/packages/@aws-cdk/aws-greengrass/package.json index e5909de8cf591..e360765daf13a 100644 --- a/packages/@aws-cdk/aws-greengrass/package.json +++ b/packages/@aws-cdk/aws-greengrass/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::Greengrass", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-greengrassv2/.eslintrc.js b/packages/@aws-cdk/aws-greengrassv2/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-greengrassv2/.eslintrc.js +++ b/packages/@aws-cdk/aws-greengrassv2/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-greengrassv2/jest.config.js b/packages/@aws-cdk/aws-greengrassv2/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-greengrassv2/jest.config.js +++ b/packages/@aws-cdk/aws-greengrassv2/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-greengrassv2/package.json b/packages/@aws-cdk/aws-greengrassv2/package.json index 4c21e7594e26b..b36f81ae49a34 100644 --- a/packages/@aws-cdk/aws-greengrassv2/package.json +++ b/packages/@aws-cdk/aws-greengrassv2/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::GreengrassV2", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-groundstation/.eslintrc.js b/packages/@aws-cdk/aws-groundstation/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-groundstation/.eslintrc.js +++ b/packages/@aws-cdk/aws-groundstation/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-groundstation/jest.config.js b/packages/@aws-cdk/aws-groundstation/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-groundstation/jest.config.js +++ b/packages/@aws-cdk/aws-groundstation/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-groundstation/package.json b/packages/@aws-cdk/aws-groundstation/package.json index f24da08699f70..bc3c56193416e 100644 --- a/packages/@aws-cdk/aws-groundstation/package.json +++ b/packages/@aws-cdk/aws-groundstation/package.json @@ -58,7 +58,6 @@ }, "cdk-build": { "cloudformation": "AWS::GroundStation", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -77,11 +76,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", "@aws-cdk/assertions": "0.0.0", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-guardduty/.eslintrc.js b/packages/@aws-cdk/aws-guardduty/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-guardduty/.eslintrc.js +++ b/packages/@aws-cdk/aws-guardduty/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-guardduty/jest.config.js b/packages/@aws-cdk/aws-guardduty/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-guardduty/jest.config.js +++ b/packages/@aws-cdk/aws-guardduty/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-guardduty/package.json b/packages/@aws-cdk/aws-guardduty/package.json index 0fb30da82ef61..dee1ab10f4c53 100644 --- a/packages/@aws-cdk/aws-guardduty/package.json +++ b/packages/@aws-cdk/aws-guardduty/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::GuardDuty", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,11 +72,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/tools/cdk-integ-tools/.eslintrc.js b/packages/@aws-cdk/aws-healthlake/.eslintrc.js similarity index 56% rename from tools/cdk-integ-tools/.eslintrc.js rename to packages/@aws-cdk/aws-healthlake/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/tools/cdk-integ-tools/.eslintrc.js +++ b/packages/@aws-cdk/aws-healthlake/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-healthlake/.gitignore b/packages/@aws-cdk/aws-healthlake/.gitignore new file mode 100644 index 0000000000000..62ebc95d75ce6 --- /dev/null +++ b/packages/@aws-cdk/aws-healthlake/.gitignore @@ -0,0 +1,19 @@ +*.js +*.js.map +*.d.ts +tsconfig.json +node_modules +*.generated.ts +dist +.jsii + +.LAST_BUILD +.nyc_output +coverage +.nycrc +.LAST_PACKAGE +*.snk +nyc.config.js +!.eslintrc.js +!jest.config.js +junit.xml diff --git a/packages/@aws-cdk/aws-healthlake/.npmignore b/packages/@aws-cdk/aws-healthlake/.npmignore new file mode 100644 index 0000000000000..f931fede67c44 --- /dev/null +++ b/packages/@aws-cdk/aws-healthlake/.npmignore @@ -0,0 +1,29 @@ +# Don't include original .ts files when doing `npm pack` +*.ts +!*.d.ts +coverage +.nyc_output +*.tgz + +dist +.LAST_PACKAGE +.LAST_BUILD +!*.js + +# Include .jsii +!.jsii + +*.snk + +*.tsbuildinfo + +tsconfig.json + +.eslintrc.js +jest.config.js + +# exclude cdk artifacts +**/cdk.out +junit.xml +test/ +!*.lit.ts diff --git a/tools/cdk-integ-tools/LICENSE b/packages/@aws-cdk/aws-healthlake/LICENSE similarity index 100% rename from tools/cdk-integ-tools/LICENSE rename to packages/@aws-cdk/aws-healthlake/LICENSE diff --git a/tools/cdk-integ-tools/NOTICE b/packages/@aws-cdk/aws-healthlake/NOTICE similarity index 100% rename from tools/cdk-integ-tools/NOTICE rename to packages/@aws-cdk/aws-healthlake/NOTICE diff --git a/packages/@aws-cdk/aws-healthlake/README.md b/packages/@aws-cdk/aws-healthlake/README.md new file mode 100644 index 0000000000000..81c90c8d4d295 --- /dev/null +++ b/packages/@aws-cdk/aws-healthlake/README.md @@ -0,0 +1,20 @@ +# AWS::HealthLake Construct Library + + +--- + +![cfn-resources: Stable](https://img.shields.io/badge/cfn--resources-stable-success.svg?style=for-the-badge) + +> All classes with the `Cfn` prefix in this module ([CFN Resources]) are always stable and safe to use. +> +> [CFN Resources]: https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib + +--- + + + +This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. + +```ts +import healthlake = require('@aws-cdk/aws-healthlake'); +``` diff --git a/packages/@aws-cdk/aws-healthlake/jest.config.js b/packages/@aws-cdk/aws-healthlake/jest.config.js new file mode 100644 index 0000000000000..3a2fd93a1228a --- /dev/null +++ b/packages/@aws-cdk/aws-healthlake/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-healthlake/lib/index.ts b/packages/@aws-cdk/aws-healthlake/lib/index.ts new file mode 100644 index 0000000000000..e7cf024404869 --- /dev/null +++ b/packages/@aws-cdk/aws-healthlake/lib/index.ts @@ -0,0 +1,2 @@ +// AWS::HealthLake CloudFormation Resources: +export * from './healthlake.generated'; diff --git a/packages/@aws-cdk/aws-healthlake/package.json b/packages/@aws-cdk/aws-healthlake/package.json new file mode 100644 index 0000000000000..ea2c9d0aac3bf --- /dev/null +++ b/packages/@aws-cdk/aws-healthlake/package.json @@ -0,0 +1,102 @@ +{ + "name": "@aws-cdk/aws-healthlake", + "version": "0.0.0", + "description": "The CDK Construct Library for AWS::HealthLake", + "main": "lib/index.js", + "types": "lib/index.d.ts", + "jsii": { + "outdir": "dist", + "projectReferences": true, + "targets": { + "dotnet": { + "namespace": "Amazon.CDK.AWS.HealthLake", + "packageId": "Amazon.CDK.AWS.HealthLake", + "signAssembly": true, + "assemblyOriginatorKeyFile": "../../key.snk", + "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png" + }, + "java": { + "package": "software.amazon.awscdk.services.healthlake", + "maven": { + "groupId": "software.amazon.awscdk", + "artifactId": "healthlake" + } + }, + "python": { + "classifiers": [ + "Framework :: AWS CDK", + "Framework :: AWS CDK :: 1" + ], + "distName": "aws-cdk.aws-healthlake", + "module": "aws_cdk.aws_healthlake" + } + } + }, + "repository": { + "type": "git", + "url": "https://github.com/aws/aws-cdk.git", + "directory": "packages/@aws-cdk/aws-healthlake" + }, + "homepage": "https://github.com/aws/aws-cdk", + "scripts": { + "build": "cdk-build", + "watch": "cdk-watch", + "lint": "cdk-lint", + "test": "cdk-test", + "integ": "cdk-integ", + "pkglint": "pkglint -f", + "package": "cdk-package", + "awslint": "cdk-awslint", + "cfn2ts": "cfn2ts", + "build+test": "yarn build && yarn test", + "build+test+package": "yarn build+test && yarn package", + "compat": "cdk-compat", + "gen": "cfn2ts", + "rosetta:extract": "yarn --silent jsii-rosetta extract", + "build+extract": "yarn build && yarn rosetta:extract", + "build+test+extract": "yarn build+test && yarn rosetta:extract" + }, + "cdk-build": { + "cloudformation": "AWS::HealthLake", + "env": { + "AWSLINT_BASE_CONSTRUCT": "true" + } + }, + "keywords": [ + "aws", + "cdk", + "constructs", + "AWS::HealthLake", + "aws-healthlake" + ], + "author": { + "name": "Amazon Web Services", + "url": "https://aws.amazon.com", + "organization": true + }, + "license": "Apache-2.0", + "devDependencies": { + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" + }, + "dependencies": { + "@aws-cdk/core": "0.0.0" + }, + "peerDependencies": { + "@aws-cdk/core": "0.0.0" + }, + "engines": { + "node": ">= 10.13.0 <13 || >=13.7.0" + }, + "stability": "experimental", + "maturity": "cfn-only", + "awscdkio": { + "announce": false + }, + "publishConfig": { + "tag": "latest" + } +} diff --git a/packages/@aws-cdk/aws-healthlake/test/healthlake.test.ts b/packages/@aws-cdk/aws-healthlake/test/healthlake.test.ts new file mode 100644 index 0000000000000..465c7bdea0693 --- /dev/null +++ b/packages/@aws-cdk/aws-healthlake/test/healthlake.test.ts @@ -0,0 +1,6 @@ +import '@aws-cdk/assertions'; +import {} from '../lib'; + +test('No tests are specified for this package', () => { + expect(true).toBe(true); +}); diff --git a/packages/@aws-cdk/aws-iam/.eslintrc.js b/packages/@aws-cdk/aws-iam/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-iam/.eslintrc.js +++ b/packages/@aws-cdk/aws-iam/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-iam/jest.config.js b/packages/@aws-cdk/aws-iam/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-iam/jest.config.js +++ b/packages/@aws-cdk/aws-iam/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-iam/lib/policy-statement.ts b/packages/@aws-cdk/aws-iam/lib/policy-statement.ts index 14ca172de5506..08a8353e84b36 100644 --- a/packages/@aws-cdk/aws-iam/lib/policy-statement.ts +++ b/packages/@aws-cdk/aws-iam/lib/policy-statement.ts @@ -1,10 +1,10 @@ import * as cdk from '@aws-cdk/core'; import { Group } from './group'; import { - AccountPrincipal, AccountRootPrincipal, Anyone, ArnPrincipal, CanonicalUserPrincipal, + AccountPrincipal, AccountRootPrincipal, AnyPrincipal, ArnPrincipal, CanonicalUserPrincipal, FederatedPrincipal, IPrincipal, PrincipalBase, PrincipalPolicyFragment, ServicePrincipal, ServicePrincipalOpts, } from './principals'; -import { mergePrincipal } from './util'; +import { LITERAL_STRING_KEY, mergePrincipal } from './util'; const ensureArrayOrUndefined = (field: any) => { if (field === undefined) { @@ -239,7 +239,7 @@ export class PolicyStatement { * Adds all identities in all accounts ("*") to this policy statement */ public addAnyPrincipal() { - this.addPrincipals(new Anyone()); + this.addPrincipals(new AnyPrincipal()); } // @@ -370,6 +370,11 @@ export class PolicyStatement { function _normPrincipal(principal: { [key: string]: any[] }) { const keys = Object.keys(principal); if (keys.length === 0) { return undefined; } + + if (LITERAL_STRING_KEY in principal) { + return principal[LITERAL_STRING_KEY][0]; + } + const result: any = {}; for (const key of keys) { const normVal = _norm(principal[key]); @@ -600,9 +605,13 @@ class JsonPrincipal extends PrincipalBase { constructor(json: any = { }) { super(); - // special case: if principal is a string, turn it into an "AWS" principal + // special case: if principal is a string, turn it into a "LiteralString" principal, + // so we render the exact same string back out. if (typeof(json) === 'string') { - json = { AWS: json }; + json = { [LITERAL_STRING_KEY]: [json] }; + } + if (typeof(json) !== 'object') { + throw new Error(`JSON IAM principal should be an object, got ${JSON.stringify(json)}`); } this.policyFragment = { diff --git a/packages/@aws-cdk/aws-iam/lib/principals.ts b/packages/@aws-cdk/aws-iam/lib/principals.ts index 2c89f96749324..001792cbcc475 100644 --- a/packages/@aws-cdk/aws-iam/lib/principals.ts +++ b/packages/@aws-cdk/aws-iam/lib/principals.ts @@ -3,7 +3,7 @@ import { Default, RegionInfo } from '@aws-cdk/region-info'; import { IOpenIdConnectProvider } from './oidc-provider'; import { Condition, Conditions, PolicyStatement } from './policy-statement'; import { ISamlProvider } from './saml-provider'; -import { mergePrincipal } from './util'; +import { LITERAL_STRING_KEY, mergePrincipal } from './util'; /** * Any object that has an associated principal that a permission can be granted to @@ -252,6 +252,15 @@ export class PrincipalWithConditions implements IPrincipal { * * This consists of the JSON used in the "Principal" field, and optionally a * set of "Condition"s that need to be applied to the policy. + * + * Generally, a principal looks like: + * + * { '': ['ID', 'ID', ...] } + * + * And this is also the type of the field `principalJson`. However, there is a + * special type of principal that is just the string '*', which is treated + * differently by some services. To represent that principal, `principalJson` + * should contain `{ 'LiteralString': ['*'] }`. */ export class PrincipalPolicyFragment { /** @@ -545,7 +554,14 @@ export class AccountRootPrincipal extends AccountPrincipal { } /** - * A principal representing all identities in all accounts + * A principal representing all AWS identities in all accounts + * + * Some services behave differently when you specify `Principal: '*'` + * or `Principal: { AWS: "*" }` in their resource policy. + * + * `AnyPrincipal` renders to `Principal: { AWS: "*" }`. This is correct + * most of the time, but in cases where you need the other principal, + * use `StarPrincipal` instead. */ export class AnyPrincipal extends ArnPrincipal { constructor() { @@ -563,6 +579,26 @@ export class AnyPrincipal extends ArnPrincipal { */ export class Anyone extends AnyPrincipal { } +/** + * A principal that uses a literal '*' in the IAM JSON language + * + * Some services behave differently when you specify `Principal: "*"` + * or `Principal: { AWS: "*" }` in their resource policy. + * + * `StarPrincipal` renders to `Principal: *`. Most of the time, you + * should use `AnyPrincipal` instead. + */ +export class StarPrincipal extends PrincipalBase { + public readonly policyFragment: PrincipalPolicyFragment = { + principalJson: { [LITERAL_STRING_KEY]: ['*'] }, + conditions: {}, + }; + + public toString() { + return 'StarPrincipal()'; + } +} + /** * Represents a principal that has multiple types of principals. A composite principal cannot * have conditions. i.e. multiple ServicePrincipals that form a composite principal diff --git a/packages/@aws-cdk/aws-iam/lib/user.ts b/packages/@aws-cdk/aws-iam/lib/user.ts index 4874e84f791df..47be80bf7b0ee 100644 --- a/packages/@aws-cdk/aws-iam/lib/user.ts +++ b/packages/@aws-cdk/aws-iam/lib/user.ts @@ -156,6 +156,9 @@ export class User extends Resource implements IIdentity, IUser { /** * Import an existing user given a user ARN. * + * If the ARN comes from a Token, the User cannot have a path; if so, any attempt + * to reference its username will fail. + * * @param scope construct scope * @param id construct id * @param userArn the ARN of an existing user to import @@ -167,6 +170,9 @@ export class User extends Resource implements IIdentity, IUser { /** * Import an existing user given user attributes. * + * If the ARN comes from a Token, the User cannot have a path; if so, any attempt + * to reference its username will fail. + * * @param scope construct scope * @param id construct id * @param attrs the attributes of the user to import @@ -175,7 +181,10 @@ export class User extends Resource implements IIdentity, IUser { class Import extends Resource implements IUser { public readonly grantPrincipal: IPrincipal = this; public readonly principalAccount = Aws.ACCOUNT_ID; - public readonly userName: string = Arn.extractResourceName(attrs.userArn, 'user'); + // Resource name with path can have multiple elements separated by slash. + // Therefore, use element after last slash as userName. Happens to work for Tokens since + // they don't have a '/' in them. + public readonly userName: string = Arn.extractResourceName(attrs.userArn, 'user').split('/').pop()!; public readonly userArn: string = attrs.userArn; public readonly assumeRoleAction: string = 'sts:AssumeRole'; public readonly policyFragment: PrincipalPolicyFragment = new ArnPrincipal(attrs.userArn).policyFragment; diff --git a/packages/@aws-cdk/aws-iam/lib/util.ts b/packages/@aws-cdk/aws-iam/lib/util.ts index 19fcbffe09639..11ef02a44ff5c 100644 --- a/packages/@aws-cdk/aws-iam/lib/util.ts +++ b/packages/@aws-cdk/aws-iam/lib/util.ts @@ -4,6 +4,8 @@ import { IPolicy } from './policy'; const MAX_POLICY_NAME_LEN = 128; +export const LITERAL_STRING_KEY = 'LiteralString'; + export function undefinedIfEmpty(f: () => string[]): string[] { return Lazy.list({ produce: () => { @@ -67,10 +69,18 @@ export class AttachedPolicies { /** * Merge two dictionaries that represent IAM principals + * + * Does an in-place merge. */ export function mergePrincipal(target: { [key: string]: string[] }, source: { [key: string]: string[] }) { + // If one represents a literal string, the other one must be empty + if ((LITERAL_STRING_KEY in source && !isEmptyObject(target)) || + (LITERAL_STRING_KEY in target && !isEmptyObject(source))) { + throw new Error(`Cannot merge principals ${JSON.stringify(target)} and ${JSON.stringify(source)}; if one uses a literal principal string the other one must be empty`); + } + for (const key of Object.keys(source)) { - target[key] = target[key] || []; + target[key] = target[key] ?? []; let value = source[key]; if (!Array.isArray(value)) { @@ -123,4 +133,8 @@ export class UniqueStringSet implements IResolvable, IPostProcessor { public toString(): string { return Token.asString(this); } +} + +function isEmptyObject(x: { [key: string]: any }): boolean { + return Object.keys(x).length === 0; } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-iam/package.json b/packages/@aws-cdk/aws-iam/package.json index ef766c83c1a25..0e951bb0cdf2c 100644 --- a/packages/@aws-cdk/aws-iam/package.json +++ b/packages/@aws-cdk/aws-iam/package.json @@ -57,8 +57,7 @@ "cloudformation": "AWS::IAM", "env": { "AWSLINT_BASE_CONSTRUCT": "true" - }, - "jest": true + } }, "keywords": [ "aws", @@ -73,16 +72,16 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/aws-lambda": "^8.10.79", + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/aws-lambda": "^8.10.84", "@types/jest": "^26.0.24", "@types/sinon": "^9.0.11", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", "jest": "^26.6.3", - "pkglint": "0.0.0", - "sinon": "^9.2.4", - "@aws-cdk/assert-internal": "0.0.0" + "sinon": "^9.2.4" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-iam/test/integ.user.expected.json b/packages/@aws-cdk/aws-iam/test/integ.user.expected.json index a57b3db4c6f32..648d9de3e9107 100644 --- a/packages/@aws-cdk/aws-iam/test/integ.user.expected.json +++ b/packages/@aws-cdk/aws-iam/test/integ.user.expected.json @@ -15,9 +15,21 @@ "NameForUserImportedByArn": { "Value": "rossrhodes" }, + "NameForUserImportedByArnPath": { + "Value": "johndoe" + }, + "NameForUserImportedByArnPathMultiple": { + "Value": "johndoe" + }, "NameForUserImportedByAttributes": { "Value": "johndoe" }, + "NameForUserImportedByAttributesPath": { + "Value": "johndoe" + }, + "NameForUserImportedByAttributesPathMultiple": { + "Value": "johndoe" + }, "NameForUserImportedByName": { "Value": "janedoe" } diff --git a/packages/@aws-cdk/aws-iam/test/integ.user.ts b/packages/@aws-cdk/aws-iam/test/integ.user.ts index 7f8d00695742c..c2e196b6af5bc 100644 --- a/packages/@aws-cdk/aws-iam/test/integ.user.ts +++ b/packages/@aws-cdk/aws-iam/test/integ.user.ts @@ -12,13 +12,25 @@ new User(stack, 'MyUser', { }); const userImportedByArn = User.fromUserArn(stack, 'ImportedUserByArn', 'arn:aws:iam::123456789012:user/rossrhodes'); +const userImportedByArnWithPath = User.fromUserArn(stack, 'ImportedUserByArnPath', 'arn:aws:iam::123456789012:user/path/johndoe'); +const userImportedByArnPathMultiple = User.fromUserArn(stack, 'ImportedUserByArnPathMultiple', 'arn:aws:iam::123456789012:user/p/a/t/h/johndoe'); const userImportedByAttributes = User.fromUserAttributes(stack, 'ImportedUserByAttributes', { userArn: 'arn:aws:iam::123456789012:user/johndoe', }); +const userImportedByAttributesPath = User.fromUserAttributes(stack, 'ImportedUserByAttributesPath', { + userArn: 'arn:aws:iam::123456789012:user/path/johndoe', +}); +const userImportedByAttributesPathMultiple = User.fromUserAttributes(stack, 'ImportedUserByAttributesPathMultiple', { + userArn: 'arn:aws:iam::123456789012:user/p/a/t/h/johndoe', +}); const userImportedByName = User.fromUserName(stack, 'ImportedUserByName', 'janedoe'); new CfnOutput(stack, 'NameForUserImportedByArn', { value: userImportedByArn.userName }); +new CfnOutput(stack, 'NameForUserImportedByArnPath', { value: userImportedByArnWithPath.userName }); +new CfnOutput(stack, 'NameForUserImportedByArnPathMultiple', { value: userImportedByArnPathMultiple.userName }); new CfnOutput(stack, 'NameForUserImportedByAttributes', { value: userImportedByAttributes.userName }); +new CfnOutput(stack, 'NameForUserImportedByAttributesPath', { value: userImportedByAttributesPath.userName }); +new CfnOutput(stack, 'NameForUserImportedByAttributesPathMultiple', { value: userImportedByAttributesPathMultiple.userName }); new CfnOutput(stack, 'NameForUserImportedByName', { value: userImportedByName.userName }); app.synth(); diff --git a/packages/@aws-cdk/aws-iam/test/policy-document.test.ts b/packages/@aws-cdk/aws-iam/test/policy-document.test.ts index c548b1aeb63fd..bf93e31901c6c 100644 --- a/packages/@aws-cdk/aws-iam/test/policy-document.test.ts +++ b/packages/@aws-cdk/aws-iam/test/policy-document.test.ts @@ -764,6 +764,7 @@ describe('IAM policy document', () => { }); }).toThrow(/Statement must be an array/); }); + }); test('adding another condition with the same operator does not delete the original', () => { diff --git a/packages/@aws-cdk/aws-iam/test/policy-statement.test.ts b/packages/@aws-cdk/aws-iam/test/policy-statement.test.ts index 929343ac240c7..09b6e30b1e4c0 100644 --- a/packages/@aws-cdk/aws-iam/test/policy-statement.test.ts +++ b/packages/@aws-cdk/aws-iam/test/policy-statement.test.ts @@ -39,7 +39,32 @@ describe('IAM policy statement', () => { const doc2 = PolicyDocument.fromJson(doc1.toJSON()); expect(stack.resolve(doc2)).toEqual(stack.resolve(doc1)); + }); + + test('should not convert `Principal: *` to `Principal: { AWS: * }`', () => { + const stack = new Stack(); + const s = PolicyStatement.fromJson({ + Action: ['service:action1'], + Principal: '*', + Resource: '*', + }); + + const doc1 = new PolicyDocument(); + doc1.addStatements(s); + + const rendered = stack.resolve(doc1); + expect(rendered).toEqual({ + Statement: [ + { + Action: 'service:action1', + Effect: 'Allow', + Principal: '*', + Resource: '*', + }, + ], + Version: '2012-10-17', + }); }); test('parses a given notPrincipal', () => { diff --git a/packages/@aws-cdk/aws-iam/test/principals.test.ts b/packages/@aws-cdk/aws-iam/test/principals.test.ts index 1914f174adfd4..1bf7d47950875 100644 --- a/packages/@aws-cdk/aws-iam/test/principals.test.ts +++ b/packages/@aws-cdk/aws-iam/test/principals.test.ts @@ -167,6 +167,35 @@ test('SAML principal', () => { }); }); +test('StarPrincipal', () => { + // GIVEN + const stack = new Stack(); + + // WHEN + const pol = new iam.PolicyDocument({ + statements: [ + new iam.PolicyStatement({ + actions: ['service:action'], + resources: ['*'], + principals: [new iam.StarPrincipal()], + }), + ], + }); + + // THEN + expect(stack.resolve(pol)).toEqual({ + Statement: [ + { + Action: 'service:action', + Effect: 'Allow', + Principal: '*', + Resource: '*', + }, + ], + Version: '2012-10-17', + }); +}); + test('PrincipalWithConditions.addCondition should work', () => { // GIVEN const stack = new Stack(); diff --git a/packages/@aws-cdk/aws-iam/test/user.test.ts b/packages/@aws-cdk/aws-iam/test/user.test.ts index 5cc42ae015619..d7435b08cbf24 100644 --- a/packages/@aws-cdk/aws-iam/test/user.test.ts +++ b/packages/@aws-cdk/aws-iam/test/user.test.ts @@ -1,5 +1,5 @@ import '@aws-cdk/assert-internal/jest'; -import { App, SecretValue, Stack } from '@aws-cdk/core'; +import { App, SecretValue, Stack, Token } from '@aws-cdk/core'; import { Group, ManagedPolicy, Policy, PolicyStatement, User } from '../lib'; describe('IAM user', () => { @@ -106,6 +106,58 @@ describe('IAM user', () => { expect(stack.resolve(user.userName)).toStrictEqual(userName); }); + test('user imported by tokenized user ARN has a name', () => { + // GIVEN + const stack = new Stack(); + + // WHEN + const user = User.fromUserArn(stack, 'import', Token.asString({ Ref: 'ARN' })); + + // THEN + expect(stack.resolve(user.userName)).toStrictEqual({ + 'Fn::Select': [1, { 'Fn::Split': [':user/', { Ref: 'ARN' }] }], + }); + }); + + test('user imported by user ARN with path', () => { + // GIVEN + const stack = new Stack(); + const userName = 'MyUserName'; + + // WHEN + const user = User.fromUserArn(stack, 'import', `arn:aws:iam::account-id:user/path/${userName}`); + + // THEN + expect(stack.resolve(user.userName)).toStrictEqual(userName); + }); + + test('user imported by user ARN with path (multiple elements)', () => { + // GIVEN + const stack = new Stack(); + const userName = 'MyUserName'; + + // WHEN + const user = User.fromUserArn(stack, 'import', `arn:aws:iam::account-id:user/p/a/t/h/${userName}`); + + // THEN + expect(stack.resolve(user.userName)).toStrictEqual(userName); + }); + + test('user imported by tokenized user attributes has a name', () => { + // GIVEN + const stack = new Stack(); + + // WHEN + const user = User.fromUserAttributes(stack, 'import', { + userArn: Token.asString({ Ref: 'ARN' }), + }); + + // THEN + expect(stack.resolve(user.userName)).toStrictEqual({ + 'Fn::Select': [1, { 'Fn::Split': [':user/', { Ref: 'ARN' }] }], + }); + }); + test('user imported by user attributes has a name', () => { // GIVEN const stack = new Stack(); @@ -120,6 +172,34 @@ describe('IAM user', () => { expect(stack.resolve(user.userName)).toStrictEqual(userName); }); + test('user imported by user attributes with path has a name', () => { + // GIVEN + const stack = new Stack(); + const userName = 'MyUserName'; + + // WHEN + const user = User.fromUserAttributes(stack, 'import', { + userArn: `arn:aws:iam::account-id:user/path/${userName}`, + }); + + // THEN + expect(stack.resolve(user.userName)).toStrictEqual(userName); + }); + + test('user imported by user attributes with path (multiple elements) has a name', () => { + // GIVEN + const stack = new Stack(); + const userName = 'MyUserName'; + + // WHEN + const user = User.fromUserAttributes(stack, 'import', { + userArn: `arn:aws:iam::account-id:user/p/a/t/h/${userName}`, + }); + + // THEN + expect(stack.resolve(user.userName)).toStrictEqual(userName); + }); + test('add to policy of imported user', () => { // GIVEN const stack = new Stack(); diff --git a/packages/@aws-cdk/aws-imagebuilder/.eslintrc.js b/packages/@aws-cdk/aws-imagebuilder/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-imagebuilder/.eslintrc.js +++ b/packages/@aws-cdk/aws-imagebuilder/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-imagebuilder/jest.config.js b/packages/@aws-cdk/aws-imagebuilder/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-imagebuilder/jest.config.js +++ b/packages/@aws-cdk/aws-imagebuilder/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-imagebuilder/package.json b/packages/@aws-cdk/aws-imagebuilder/package.json index 64537f6b27401..e3a90f5b90246 100644 --- a/packages/@aws-cdk/aws-imagebuilder/package.json +++ b/packages/@aws-cdk/aws-imagebuilder/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::ImageBuilder", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-inspector/.eslintrc.js b/packages/@aws-cdk/aws-inspector/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-inspector/.eslintrc.js +++ b/packages/@aws-cdk/aws-inspector/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-inspector/jest.config.js b/packages/@aws-cdk/aws-inspector/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-inspector/jest.config.js +++ b/packages/@aws-cdk/aws-inspector/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-inspector/package.json b/packages/@aws-cdk/aws-inspector/package.json index dad54ff5b2e51..aa8e421f9b561 100644 --- a/packages/@aws-cdk/aws-inspector/package.json +++ b/packages/@aws-cdk/aws-inspector/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::Inspector", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,11 +72,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-iot/.eslintrc.js b/packages/@aws-cdk/aws-iot/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-iot/.eslintrc.js +++ b/packages/@aws-cdk/aws-iot/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-iot/jest.config.js b/packages/@aws-cdk/aws-iot/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-iot/jest.config.js +++ b/packages/@aws-cdk/aws-iot/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-iot/package.json b/packages/@aws-cdk/aws-iot/package.json index f816d5f680164..9960168c78ec1 100644 --- a/packages/@aws-cdk/aws-iot/package.json +++ b/packages/@aws-cdk/aws-iot/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::IoT", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,11 +72,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-iot1click/.eslintrc.js b/packages/@aws-cdk/aws-iot1click/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-iot1click/.eslintrc.js +++ b/packages/@aws-cdk/aws-iot1click/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-iot1click/jest.config.js b/packages/@aws-cdk/aws-iot1click/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-iot1click/jest.config.js +++ b/packages/@aws-cdk/aws-iot1click/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-iot1click/package.json b/packages/@aws-cdk/aws-iot1click/package.json index 17ad106a288f2..eda66e8a3a082 100644 --- a/packages/@aws-cdk/aws-iot1click/package.json +++ b/packages/@aws-cdk/aws-iot1click/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::IoT1Click", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -74,11 +73,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-iotanalytics/.eslintrc.js b/packages/@aws-cdk/aws-iotanalytics/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-iotanalytics/.eslintrc.js +++ b/packages/@aws-cdk/aws-iotanalytics/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-iotanalytics/jest.config.js b/packages/@aws-cdk/aws-iotanalytics/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-iotanalytics/jest.config.js +++ b/packages/@aws-cdk/aws-iotanalytics/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-iotanalytics/package.json b/packages/@aws-cdk/aws-iotanalytics/package.json index 66434d4db2d33..37630cf29c02f 100644 --- a/packages/@aws-cdk/aws-iotanalytics/package.json +++ b/packages/@aws-cdk/aws-iotanalytics/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::IoTAnalytics", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-iotcoredeviceadvisor/.eslintrc.js b/packages/@aws-cdk/aws-iotcoredeviceadvisor/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-iotcoredeviceadvisor/.eslintrc.js +++ b/packages/@aws-cdk/aws-iotcoredeviceadvisor/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-iotcoredeviceadvisor/jest.config.js b/packages/@aws-cdk/aws-iotcoredeviceadvisor/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-iotcoredeviceadvisor/jest.config.js +++ b/packages/@aws-cdk/aws-iotcoredeviceadvisor/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-iotcoredeviceadvisor/package.json b/packages/@aws-cdk/aws-iotcoredeviceadvisor/package.json index 80fc81f75a022..45422d829b797 100644 --- a/packages/@aws-cdk/aws-iotcoredeviceadvisor/package.json +++ b/packages/@aws-cdk/aws-iotcoredeviceadvisor/package.json @@ -58,7 +58,6 @@ }, "cdk-build": { "cloudformation": "AWS::IoTCoreDeviceAdvisor", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -77,11 +76,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", "@aws-cdk/assertions": "0.0.0", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-iotevents/.eslintrc.js b/packages/@aws-cdk/aws-iotevents/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-iotevents/.eslintrc.js +++ b/packages/@aws-cdk/aws-iotevents/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-iotevents/jest.config.js b/packages/@aws-cdk/aws-iotevents/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-iotevents/jest.config.js +++ b/packages/@aws-cdk/aws-iotevents/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-iotevents/package.json b/packages/@aws-cdk/aws-iotevents/package.json index 9125c6a9a05b1..859cb5169f16a 100644 --- a/packages/@aws-cdk/aws-iotevents/package.json +++ b/packages/@aws-cdk/aws-iotevents/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::IoTEvents", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-iotfleethub/.eslintrc.js b/packages/@aws-cdk/aws-iotfleethub/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-iotfleethub/.eslintrc.js +++ b/packages/@aws-cdk/aws-iotfleethub/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-iotfleethub/jest.config.js b/packages/@aws-cdk/aws-iotfleethub/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-iotfleethub/jest.config.js +++ b/packages/@aws-cdk/aws-iotfleethub/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-iotfleethub/package.json b/packages/@aws-cdk/aws-iotfleethub/package.json index 69891556a7f4b..f0c4a45a394a0 100644 --- a/packages/@aws-cdk/aws-iotfleethub/package.json +++ b/packages/@aws-cdk/aws-iotfleethub/package.json @@ -58,7 +58,6 @@ }, "cdk-build": { "cloudformation": "AWS::IoTFleetHub", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -77,11 +76,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", "@aws-cdk/assertions": "0.0.0", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-iotsitewise/.eslintrc.js b/packages/@aws-cdk/aws-iotsitewise/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-iotsitewise/.eslintrc.js +++ b/packages/@aws-cdk/aws-iotsitewise/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-iotsitewise/jest.config.js b/packages/@aws-cdk/aws-iotsitewise/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-iotsitewise/jest.config.js +++ b/packages/@aws-cdk/aws-iotsitewise/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-iotsitewise/package.json b/packages/@aws-cdk/aws-iotsitewise/package.json index 9c86ba4bcd889..ccf98918699ad 100644 --- a/packages/@aws-cdk/aws-iotsitewise/package.json +++ b/packages/@aws-cdk/aws-iotsitewise/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::IoTSiteWise", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-iotthingsgraph/.eslintrc.js b/packages/@aws-cdk/aws-iotthingsgraph/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-iotthingsgraph/.eslintrc.js +++ b/packages/@aws-cdk/aws-iotthingsgraph/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-iotthingsgraph/jest.config.js b/packages/@aws-cdk/aws-iotthingsgraph/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-iotthingsgraph/jest.config.js +++ b/packages/@aws-cdk/aws-iotthingsgraph/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-iotthingsgraph/package.json b/packages/@aws-cdk/aws-iotthingsgraph/package.json index a00fc435787fe..5e2833e52494b 100644 --- a/packages/@aws-cdk/aws-iotthingsgraph/package.json +++ b/packages/@aws-cdk/aws-iotthingsgraph/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::IoTThingsGraph", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-iotwireless/.eslintrc.js b/packages/@aws-cdk/aws-iotwireless/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-iotwireless/.eslintrc.js +++ b/packages/@aws-cdk/aws-iotwireless/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-iotwireless/jest.config.js b/packages/@aws-cdk/aws-iotwireless/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-iotwireless/jest.config.js +++ b/packages/@aws-cdk/aws-iotwireless/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-iotwireless/package.json b/packages/@aws-cdk/aws-iotwireless/package.json index ee46fc9ca58ec..16e1afdc9ae88 100644 --- a/packages/@aws-cdk/aws-iotwireless/package.json +++ b/packages/@aws-cdk/aws-iotwireless/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::IoTWireless", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-ivs/.eslintrc.js b/packages/@aws-cdk/aws-ivs/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-ivs/.eslintrc.js +++ b/packages/@aws-cdk/aws-ivs/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-ivs/jest.config.js b/packages/@aws-cdk/aws-ivs/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-ivs/jest.config.js +++ b/packages/@aws-cdk/aws-ivs/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-ivs/package.json b/packages/@aws-cdk/aws-ivs/package.json index b199d66182db2..922a5672829a6 100644 --- a/packages/@aws-cdk/aws-ivs/package.json +++ b/packages/@aws-cdk/aws-ivs/package.json @@ -65,7 +65,6 @@ }, "cdk-build": { "cloudformation": "AWS::IVS", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -86,11 +85,11 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assertions": "0.0.0", - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-ivs/test/ivs.test.ts b/packages/@aws-cdk/aws-ivs/test/ivs.test.ts index 82e3b41e79e64..4104994ed882c 100644 --- a/packages/@aws-cdk/aws-ivs/test/ivs.test.ts +++ b/packages/@aws-cdk/aws-ivs/test/ivs.test.ts @@ -1,4 +1,4 @@ -import { Template } from '@aws-cdk/assertions'; +import { Match, Template } from '@aws-cdk/assertions'; import { App, Stack } from '@aws-cdk/core'; import * as ivs from '../lib'; @@ -22,12 +22,8 @@ beforeEach( () => { test('channel default properties', () => { new ivs.Channel(stack, 'Channel'); - Template.fromStack(stack).templateMatches({ - Resources: { - Channel4048F119: { - Type: 'AWS::IVS::Channel', - }, - }, + Template.fromStack(stack).hasResource('AWS::IVS::Channel', { + Properties: Match.absent(), }); }); @@ -36,15 +32,8 @@ test('channel name', () => { name: 'CarrotsAreTasty', }); - Template.fromStack(stack).templateMatches({ - Resources: { - Channel4048F119: { - Type: 'AWS::IVS::Channel', - Properties: { - Name: 'CarrotsAreTasty', - }, - }, - }, + Template.fromStack(stack).hasResourceProperties('AWS::IVS::Channel', { + Name: 'CarrotsAreTasty', }); }); @@ -53,15 +42,8 @@ test('channel is authorized', () => { authorized: true, }); - Template.fromStack(stack).templateMatches({ - Resources: { - Channel4048F119: { - Type: 'AWS::IVS::Channel', - Properties: { - Authorized: 'true', - }, - }, - }, + Template.fromStack(stack).hasResourceProperties('AWS::IVS::Channel', { + Authorized: true, }); }); @@ -70,15 +52,8 @@ test('channel type', () => { type: ivs.ChannelType.BASIC, }); - Template.fromStack(stack).templateMatches({ - Resources: { - Channel4048F119: { - Type: 'AWS::IVS::Channel', - Properties: { - Type: 'BASIC', - }, - }, - }, + Template.fromStack(stack).hasResourceProperties('AWS::IVS::Channel', { + Type: 'BASIC', }); }); @@ -87,15 +62,8 @@ test('channel latency mode', () => { latencyMode: ivs.LatencyMode.NORMAL, }); - Template.fromStack(stack).templateMatches({ - Resources: { - Channel4048F119: { - Type: 'AWS::IVS::Channel', - Properties: { - LatencyMode: 'NORMAL', - }, - }, - }, + Template.fromStack(stack).hasResourceProperties('AWS::IVS::Channel', { + LatencyMode: 'NORMAL', }); }); @@ -116,15 +84,8 @@ test('playback key pair mandatory properties', () => { publicKeyMaterial: publicKey, }); - Template.fromStack(stack).templateMatches({ - Resources: { - PlaybackKeyPairBE17315B: { - Type: 'AWS::IVS::PlaybackKeyPair', - Properties: { - PublicKeyMaterial: publicKey, - }, - }, - }, + Template.fromStack(stack).hasResourceProperties('AWS::IVS::PlaybackKeyPair', { + PublicKeyMaterial: publicKey, }); }); @@ -134,16 +95,9 @@ test('playback key pair name', () => { name: 'CarrotsAreNutritious', }); - Template.fromStack(stack).templateMatches({ - Resources: { - PlaybackKeyPairBE17315B: { - Type: 'AWS::IVS::PlaybackKeyPair', - Properties: { - PublicKeyMaterial: publicKey, - Name: 'CarrotsAreNutritious', - }, - }, - }, + Template.fromStack(stack).hasResourceProperties('AWS::IVS::PlaybackKeyPair', { + PublicKeyMaterial: publicKey, + Name: 'CarrotsAreNutritious', }); }); @@ -159,15 +113,8 @@ test('stream key mandatory properties', () => { channel: ivs.Channel.fromChannelArn(stack, 'ChannelRef', 'arn:aws:ivs:us-west-2:123456789012:channel/abcdABCDefgh'), }); - Template.fromStack(stack).templateMatches({ - Resources: { - StreamKey9F296F4F: { - Type: 'AWS::IVS::StreamKey', - Properties: { - ChannelArn: 'arn:aws:ivs:us-west-2:123456789012:channel/abcdABCDefgh', - }, - }, - }, + Template.fromStack(stack).hasResourceProperties('AWS::IVS::StreamKey', { + ChannelArn: 'arn:aws:ivs:us-west-2:123456789012:channel/abcdABCDefgh', }); }); @@ -194,15 +141,8 @@ test('stream key from channel reference', () => { const channel = ivs.Channel.fromChannelArn(stack, 'Channel', 'arn:aws:ivs:us-west-2:123456789012:channel/abcdABCDefgh'); channel.addStreamKey('StreamKey'); - Template.fromStack(stack).templateMatches({ - Resources: { - ChannelStreamKey60BDC2BE: { - Type: 'AWS::IVS::StreamKey', - Properties: { - ChannelArn: 'arn:aws:ivs:us-west-2:123456789012:channel/abcdABCDefgh', - }, - }, - }, + Template.fromStack(stack).hasResourceProperties('AWS::IVS::StreamKey', { + ChannelArn: 'arn:aws:ivs:us-west-2:123456789012:channel/abcdABCDefgh', }); }); diff --git a/packages/@aws-cdk/aws-kendra/.eslintrc.js b/packages/@aws-cdk/aws-kendra/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-kendra/.eslintrc.js +++ b/packages/@aws-cdk/aws-kendra/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-kendra/jest.config.js b/packages/@aws-cdk/aws-kendra/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-kendra/jest.config.js +++ b/packages/@aws-cdk/aws-kendra/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-kendra/package.json b/packages/@aws-cdk/aws-kendra/package.json index 33ab4f2afa7f2..8b2a1b20396e1 100644 --- a/packages/@aws-cdk/aws-kendra/package.json +++ b/packages/@aws-cdk/aws-kendra/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::Kendra", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-kinesis/.eslintrc.js b/packages/@aws-cdk/aws-kinesis/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-kinesis/.eslintrc.js +++ b/packages/@aws-cdk/aws-kinesis/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-kinesis/jest.config.js b/packages/@aws-cdk/aws-kinesis/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-kinesis/jest.config.js +++ b/packages/@aws-cdk/aws-kinesis/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-kinesis/package.json b/packages/@aws-cdk/aws-kinesis/package.json index 51697ec9931df..b1464884fb740 100644 --- a/packages/@aws-cdk/aws-kinesis/package.json +++ b/packages/@aws-cdk/aws-kinesis/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::Kinesis", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,13 +72,13 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/cx-api": "0.0.0", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/aws-cloudwatch": "0.0.0", diff --git a/packages/@aws-cdk/aws-kinesis/test/stream.test.ts b/packages/@aws-cdk/aws-kinesis/test/stream.test.ts index 388ac8b0caac5..089261c6ebdae 100644 --- a/packages/@aws-cdk/aws-kinesis/test/stream.test.ts +++ b/packages/@aws-cdk/aws-kinesis/test/stream.test.ts @@ -4,7 +4,7 @@ import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; import { App, Duration, Stack, CfnParameter } from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; -import { testFutureBehavior, testLegacyBehavior } from 'cdk-build-tools/lib/feature-flag'; +import { testFutureBehavior, testLegacyBehavior } from '@aws-cdk/cdk-build-tools/lib/feature-flag'; import { Stream, StreamEncryption } from '../lib'; /* eslint-disable quote-props */ diff --git a/packages/@aws-cdk/aws-kinesisanalytics-flink/.eslintrc.js b/packages/@aws-cdk/aws-kinesisanalytics-flink/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-kinesisanalytics-flink/.eslintrc.js +++ b/packages/@aws-cdk/aws-kinesisanalytics-flink/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-kinesisanalytics-flink/README.md b/packages/@aws-cdk/aws-kinesisanalytics-flink/README.md index 7dc9b1a088b16..5322ff28027f7 100644 --- a/packages/@aws-cdk/aws-kinesisanalytics-flink/README.md +++ b/packages/@aws-cdk/aws-kinesisanalytics-flink/README.md @@ -62,7 +62,7 @@ const flinkApp = new flink.Application(this, 'Application', { runtime: file.Runtime.FLINK_1_11, checkpointingEnabled: true, // default is true checkpointInterval: cdk.Duration.seconds(30), // default is 1 minute - minPausesBetweenCheckpoints: cdk.Duration.seconds(10), // default is 5 seconds + minPauseBetweenCheckpoints: cdk.Duration.seconds(10), // default is 5 seconds logLevel: flink.LogLevel.ERROR, // default is INFO metricsLevel: flink.MetricsLevel.PARALLELISM, // default is APPLICATION autoScalingEnabled: false, // default is true diff --git a/packages/@aws-cdk/aws-kinesisanalytics-flink/jest.config.js b/packages/@aws-cdk/aws-kinesisanalytics-flink/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-kinesisanalytics-flink/jest.config.js +++ b/packages/@aws-cdk/aws-kinesisanalytics-flink/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-kinesisanalytics-flink/lib/application.ts b/packages/@aws-cdk/aws-kinesisanalytics-flink/lib/application.ts index af11281fb71b7..5091d39c7f959 100644 --- a/packages/@aws-cdk/aws-kinesisanalytics-flink/lib/application.ts +++ b/packages/@aws-cdk/aws-kinesisanalytics-flink/lib/application.ts @@ -1,5 +1,5 @@ import * as iam from '@aws-cdk/aws-iam'; -import * as ka from '@aws-cdk/aws-kinesisanalytics'; +import { CfnApplicationCloudWatchLoggingOptionV2, CfnApplicationV2 } from '@aws-cdk/aws-kinesisanalytics'; import * as logs from '@aws-cdk/aws-logs'; import * as core from '@aws-cdk/core'; import { Construct } from 'constructs'; @@ -261,7 +261,7 @@ export class Application extends ApplicationBase { const code = props.code.bind(this); code.bucket.grantRead(this); - const resource = new ka.CfnApplicationV2(this, 'Resource', { + const resource = new CfnApplicationV2(this, 'Resource', { applicationName: props.applicationName, runtimeEnvironment: props.runtime.value, serviceExecutionRole: this.role.roleArn, @@ -313,7 +313,7 @@ export class Application extends ApplicationBase { resources: [logStreamArn], })); - new ka.CfnApplicationCloudWatchLoggingOptionV2(this, 'LoggingOption', { + new CfnApplicationCloudWatchLoggingOptionV2(this, 'LoggingOption', { applicationName: resource.ref, cloudWatchLoggingOption: { logStreamArn, diff --git a/packages/@aws-cdk/aws-kinesisanalytics-flink/package.json b/packages/@aws-cdk/aws-kinesisanalytics-flink/package.json index d9ee895e0ed29..f54538e7a374f 100644 --- a/packages/@aws-cdk/aws-kinesisanalytics-flink/package.json +++ b/packages/@aws-cdk/aws-kinesisanalytics-flink/package.json @@ -67,33 +67,33 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/assets": "0.0.0", - "@aws-cdk/core": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-kinesisanalytics": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/aws-s3-assets": "0.0.0", + "@aws-cdk/core": "0.0.0", "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { "@aws-cdk/assets": "0.0.0", - "@aws-cdk/core": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-kinesisanalytics": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/aws-s3-assets": "0.0.0", + "@aws-cdk/core": "0.0.0", "constructs": "^3.3.69" }, "engines": { @@ -110,7 +110,6 @@ "announce": false }, "cdk-build": { - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } diff --git a/packages/@aws-cdk/aws-kinesisanalytics/.eslintrc.js b/packages/@aws-cdk/aws-kinesisanalytics/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-kinesisanalytics/.eslintrc.js +++ b/packages/@aws-cdk/aws-kinesisanalytics/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-kinesisanalytics/jest.config.js b/packages/@aws-cdk/aws-kinesisanalytics/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-kinesisanalytics/jest.config.js +++ b/packages/@aws-cdk/aws-kinesisanalytics/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-kinesisanalytics/package.json b/packages/@aws-cdk/aws-kinesisanalytics/package.json index db7c571c963c8..1e345f2fdb47b 100644 --- a/packages/@aws-cdk/aws-kinesisanalytics/package.json +++ b/packages/@aws-cdk/aws-kinesisanalytics/package.json @@ -58,7 +58,6 @@ "AWS::KinesisAnalytics", "AWS::KinesisAnalyticsV2" ], - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -76,11 +75,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-kinesisfirehose-destinations/.eslintrc.js b/packages/@aws-cdk/aws-kinesisfirehose-destinations/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-kinesisfirehose-destinations/.eslintrc.js +++ b/packages/@aws-cdk/aws-kinesisfirehose-destinations/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-kinesisfirehose-destinations/jest.config.js b/packages/@aws-cdk/aws-kinesisfirehose-destinations/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-kinesisfirehose-destinations/jest.config.js +++ b/packages/@aws-cdk/aws-kinesisfirehose-destinations/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-kinesisfirehose-destinations/lib/private/helpers.ts b/packages/@aws-cdk/aws-kinesisfirehose-destinations/lib/private/helpers.ts index d8ef3d4ac43a5..b841776a47d4c 100644 --- a/packages/@aws-cdk/aws-kinesisfirehose-destinations/lib/private/helpers.ts +++ b/packages/@aws-cdk/aws-kinesisfirehose-destinations/lib/private/helpers.ts @@ -1,5 +1,6 @@ import * as iam from '@aws-cdk/aws-iam'; import * as firehose from '@aws-cdk/aws-kinesisfirehose'; +import { CfnDeliveryStream } from '@aws-cdk/aws-kinesisfirehose'; import * as kms from '@aws-cdk/aws-kms'; import * as logs from '@aws-cdk/aws-logs'; import * as s3 from '@aws-cdk/aws-s3'; @@ -48,14 +49,14 @@ export interface DestinationLoggingConfig extends ConfigWithDependables { /** * Logging options that will be injected into the destination configuration. */ - readonly loggingOptions: firehose.CfnDeliveryStream.CloudWatchLoggingOptionsProperty; + readonly loggingOptions: CfnDeliveryStream.CloudWatchLoggingOptionsProperty; } export interface DestinationBackupConfig extends ConfigWithDependables { /** * S3 backup configuration that will be injected into the destination configuration. */ - readonly backupConfig: firehose.CfnDeliveryStream.S3DestinationConfigurationProperty; + readonly backupConfig: CfnDeliveryStream.S3DestinationConfigurationProperty; } export function createLoggingOptions(scope: Construct, props: DestinationLoggingProps): DestinationLoggingConfig | undefined { @@ -80,7 +81,7 @@ export function createLoggingOptions(scope: Construct, props: DestinationLogging export function createBufferingHints( interval?: cdk.Duration, size?: cdk.Size, -): firehose.CfnDeliveryStream.BufferingHintsProperty | undefined { +): CfnDeliveryStream.BufferingHintsProperty | undefined { if (!interval && !size) { return undefined; } @@ -99,7 +100,7 @@ export function createBufferingHints( export function createEncryptionConfig( role: iam.IRole, encryptionKey?: kms.IKey, -): firehose.CfnDeliveryStream.EncryptionConfigurationProperty | undefined { +): CfnDeliveryStream.EncryptionConfigurationProperty | undefined { encryptionKey?.grantEncryptDecrypt(role); return encryptionKey ? { kmsEncryptionConfig: { awskmsKeyArn: encryptionKey.keyArn } } @@ -110,7 +111,7 @@ export function createProcessingConfig( scope: Construct, role: iam.IRole, dataProcessor?: firehose.IDataProcessor, -): firehose.CfnDeliveryStream.ProcessingConfigurationProperty | undefined { +): CfnDeliveryStream.ProcessingConfigurationProperty | undefined { return dataProcessor ? { enabled: true, @@ -123,7 +124,7 @@ function renderDataProcessor( processor: firehose.IDataProcessor, scope: Construct, role: iam.IRole, -): firehose.CfnDeliveryStream.ProcessorProperty { +): CfnDeliveryStream.ProcessorProperty { const processorConfig = processor.bind(scope, { role }); const parameters = [{ parameterName: 'RoleArn', parameterValue: role.roleArn }]; parameters.push(processorConfig.processorIdentifier); diff --git a/packages/@aws-cdk/aws-kinesisfirehose-destinations/package.json b/packages/@aws-cdk/aws-kinesisfirehose-destinations/package.json index 6633645989caf..36c981f2c54cd 100644 --- a/packages/@aws-cdk/aws-kinesisfirehose-destinations/package.json +++ b/packages/@aws-cdk/aws-kinesisfirehose-destinations/package.json @@ -72,14 +72,14 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assertions": "0.0.0", - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", - "@aws-cdk/aws-lambda-nodejs": "0.0.0" + "@aws-cdk/aws-lambda-nodejs": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24", + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-iam": "0.0.0", @@ -112,7 +112,6 @@ "announce": false }, "cdk-build": { - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } diff --git a/packages/@aws-cdk/aws-kinesisfirehose-destinations/test/integ.s3-bucket.lit.expected.json b/packages/@aws-cdk/aws-kinesisfirehose-destinations/test/integ.s3-bucket.lit.expected.json index ba6e2aecacda8..5ae3347a50989 100644 --- a/packages/@aws-cdk/aws-kinesisfirehose-destinations/test/integ.s3-bucket.lit.expected.json +++ b/packages/@aws-cdk/aws-kinesisfirehose-destinations/test/integ.s3-bucket.lit.expected.json @@ -2,6 +2,14 @@ "Resources": { "Bucket83908E77": { "Type": "AWS::S3::Bucket", + "Properties": { + "Tags": [ + { + "Key": "aws-cdk:auto-delete-objects", + "Value": "true" + } + ] + }, "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete" }, @@ -102,7 +110,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParametersfe5df38824187483182e1459db47adfae2a515aa4caedd437fc4033a0c5b3de9S3BucketD715D8B0" + "Ref": "AssetParameters3993fb4cd942505a050d08b09d5444e14c265cf9cd0fb8b0c5f621446b6cead9S3Bucket4673BB1A" }, "S3Key": { "Fn::Join": [ @@ -115,7 +123,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersfe5df38824187483182e1459db47adfae2a515aa4caedd437fc4033a0c5b3de9S3VersionKey6E76822C" + "Ref": "AssetParameters3993fb4cd942505a050d08b09d5444e14c265cf9cd0fb8b0c5f621446b6cead9S3VersionKey46E40510" } ] } @@ -128,7 +136,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersfe5df38824187483182e1459db47adfae2a515aa4caedd437fc4033a0c5b3de9S3VersionKey6E76822C" + "Ref": "AssetParameters3993fb4cd942505a050d08b09d5444e14c265cf9cd0fb8b0c5f621446b6cead9S3VersionKey46E40510" } ] } @@ -167,6 +175,14 @@ }, "BackupBucket26B8E51C": { "Type": "AWS::S3::Bucket", + "Properties": { + "Tags": [ + { + "Key": "aws-cdk:auto-delete-objects", + "Value": "true" + } + ] + }, "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete" }, @@ -751,17 +767,17 @@ } }, "Parameters": { - "AssetParametersfe5df38824187483182e1459db47adfae2a515aa4caedd437fc4033a0c5b3de9S3BucketD715D8B0": { + "AssetParameters3993fb4cd942505a050d08b09d5444e14c265cf9cd0fb8b0c5f621446b6cead9S3Bucket4673BB1A": { "Type": "String", - "Description": "S3 bucket for asset \"fe5df38824187483182e1459db47adfae2a515aa4caedd437fc4033a0c5b3de9\"" + "Description": "S3 bucket for asset \"3993fb4cd942505a050d08b09d5444e14c265cf9cd0fb8b0c5f621446b6cead9\"" }, - "AssetParametersfe5df38824187483182e1459db47adfae2a515aa4caedd437fc4033a0c5b3de9S3VersionKey6E76822C": { + "AssetParameters3993fb4cd942505a050d08b09d5444e14c265cf9cd0fb8b0c5f621446b6cead9S3VersionKey46E40510": { "Type": "String", - "Description": "S3 key for asset version \"fe5df38824187483182e1459db47adfae2a515aa4caedd437fc4033a0c5b3de9\"" + "Description": "S3 key for asset version \"3993fb4cd942505a050d08b09d5444e14c265cf9cd0fb8b0c5f621446b6cead9\"" }, - "AssetParametersfe5df38824187483182e1459db47adfae2a515aa4caedd437fc4033a0c5b3de9ArtifactHash9AE3702B": { + "AssetParameters3993fb4cd942505a050d08b09d5444e14c265cf9cd0fb8b0c5f621446b6cead9ArtifactHashBD621721": { "Type": "String", - "Description": "Artifact hash for asset \"fe5df38824187483182e1459db47adfae2a515aa4caedd437fc4033a0c5b3de9\"" + "Description": "Artifact hash for asset \"3993fb4cd942505a050d08b09d5444e14c265cf9cd0fb8b0c5f621446b6cead9\"" }, "AssetParameters5ee078f2a1957fe672d6cfd84faf49e07b8460758b5cd2669b3df1212a14cd19S3BucketFEDDFB43": { "Type": "String", diff --git a/packages/@aws-cdk/aws-kinesisfirehose-destinations/test/s3-bucket.test.ts b/packages/@aws-cdk/aws-kinesisfirehose-destinations/test/s3-bucket.test.ts index 448d0b8efcf40..74d37d180f954 100644 --- a/packages/@aws-cdk/aws-kinesisfirehose-destinations/test/s3-bucket.test.ts +++ b/packages/@aws-cdk/aws-kinesisfirehose-destinations/test/s3-bucket.test.ts @@ -169,7 +169,7 @@ describe('S3 destination', () => { Template.fromStack(stack).resourceCountIs('AWS::Logs::LogGroup', 0); Template.fromStack(stack).hasResourceProperties('AWS::KinesisFirehose::DeliveryStream', { ExtendedS3DestinationConfiguration: { - CloudWatchLoggingOptions: Match.absentProperty(), + CloudWatchLoggingOptions: Match.absent(), }, }); }); @@ -548,7 +548,7 @@ describe('S3 destination', () => { Template.fromStack(stack).resourceCountIs('AWS::S3::Bucket', 1); Template.fromStack(stack).hasResourceProperties('AWS::KinesisFirehose::DeliveryStream', { ExtendedS3DestinationConfiguration: { - S3BackupConfiguration: Match.absentProperty(), + S3BackupConfiguration: Match.absent(), }, }); }); diff --git a/packages/@aws-cdk/aws-kinesisfirehose/.eslintrc.js b/packages/@aws-cdk/aws-kinesisfirehose/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-kinesisfirehose/.eslintrc.js +++ b/packages/@aws-cdk/aws-kinesisfirehose/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-kinesisfirehose/jest.config.js b/packages/@aws-cdk/aws-kinesisfirehose/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-kinesisfirehose/jest.config.js +++ b/packages/@aws-cdk/aws-kinesisfirehose/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-kinesisfirehose/package.json b/packages/@aws-cdk/aws-kinesisfirehose/package.json index fe73affa84c97..abaabc25fc1c7 100644 --- a/packages/@aws-cdk/aws-kinesisfirehose/package.json +++ b/packages/@aws-cdk/aws-kinesisfirehose/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::KinesisFirehose", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ "devDependencies": { "@aws-cdk/assertions": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/aws-cloudwatch": "0.0.0", diff --git a/packages/@aws-cdk/aws-kinesisfirehose/test/delivery-stream.test.ts b/packages/@aws-cdk/aws-kinesisfirehose/test/delivery-stream.test.ts index f716e56a8f326..ec206b739ed01 100644 --- a/packages/@aws-cdk/aws-kinesisfirehose/test/delivery-stream.test.ts +++ b/packages/@aws-cdk/aws-kinesisfirehose/test/delivery-stream.test.ts @@ -47,10 +47,10 @@ describe('delivery stream', () => { }); Template.fromStack(stack).hasResourceProperties('AWS::KinesisFirehose::DeliveryStream', { - DeliveryStreamEncryptionConfigurationInput: Match.absentProperty(), - DeliveryStreamName: Match.absentProperty(), + DeliveryStreamEncryptionConfigurationInput: Match.absent(), + DeliveryStreamName: Match.absent(), DeliveryStreamType: 'DirectPut', - KinesisStreamSourceConfiguration: Match.absentProperty(), + KinesisStreamSourceConfiguration: Match.absent(), ExtendedS3DestinationConfiguration: { BucketARN: bucketArn, RoleARN: roleArn, @@ -205,7 +205,7 @@ describe('delivery stream', () => { Template.fromStack(stack).hasResourceProperties('AWS::KinesisFirehose::DeliveryStream', { DeliveryStreamType: 'DirectPut', DeliveryStreamEncryptionConfigurationInput: { - KeyARN: Match.absentProperty(), + KeyARN: Match.absent(), KeyType: 'AWS_OWNED_CMK', }, }); @@ -222,7 +222,7 @@ describe('delivery stream', () => { Template.fromStack(stack).resourceCountIs('AWS::IAM::Policy', 0); Template.fromStack(stack).hasResourceProperties('AWS::KinesisFirehose::DeliveryStream', { DeliveryStreamType: 'DirectPut', - DeliveryStreamEncryptionConfigurationInput: Match.absentProperty(), + DeliveryStreamEncryptionConfigurationInput: Match.absent(), }); }); @@ -326,7 +326,7 @@ describe('delivery stream', () => { DependsOn: [dependableId], }); Template.fromStack(stack).hasResource('AWS::IAM::Role', { - DependsOn: Match.absentProperty(), + DependsOn: Match.absent(), }); }); diff --git a/packages/@aws-cdk/aws-kms/.eslintrc.js b/packages/@aws-cdk/aws-kms/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-kms/.eslintrc.js +++ b/packages/@aws-cdk/aws-kms/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-kms/jest.config.js b/packages/@aws-cdk/aws-kms/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-kms/jest.config.js +++ b/packages/@aws-cdk/aws-kms/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-kms/package.json b/packages/@aws-cdk/aws-kms/package.json index 9bb9e8b04c1f8..74fd0a5f586aa 100644 --- a/packages/@aws-cdk/aws-kms/package.json +++ b/packages/@aws-cdk/aws-kms/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::KMS", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -73,28 +72,28 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", "@aws-cdk/assert-internal": "0.0.0", - "@aws-cdk/cloud-assembly-schema": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/cloud-assembly-schema": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/aws-iam": "0.0.0", + "@aws-cdk/cloud-assembly-schema": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/cx-api": "0.0.0", - "constructs": "^3.3.69", - "@aws-cdk/cloud-assembly-schema": "0.0.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { "@aws-cdk/aws-iam": "0.0.0", + "@aws-cdk/cloud-assembly-schema": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/cx-api": "0.0.0", - "constructs": "^3.3.69", - "@aws-cdk/cloud-assembly-schema": "0.0.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-kms/test/alias.test.ts b/packages/@aws-cdk/aws-kms/test/alias.test.ts index 3ad224ef6e681..094d2a3e7dbed 100644 --- a/packages/@aws-cdk/aws-kms/test/alias.test.ts +++ b/packages/@aws-cdk/aws-kms/test/alias.test.ts @@ -124,7 +124,7 @@ test('can be used wherever a key is expected', () => { aliasName: 'alias/myAlias', }); - /* eslint-disable cdk/no-core-construct */ + /* eslint-disable @aws-cdk/no-core-construct */ class MyConstruct extends Construct { constructor(scope: Construct, id: string, key: IKey) { super(scope, id); @@ -138,7 +138,7 @@ test('can be used wherever a key is expected', () => { } } new MyConstruct(stack, 'MyConstruct', myAlias); - /* eslint-enable cdk/no-core-construct */ + /* eslint-enable @aws-cdk/no-core-construct */ expect(stack).toHaveOutput({ outputName: 'OutId', @@ -165,7 +165,7 @@ test('imported alias by name - can be used where a key is expected', () => { const myAlias = Alias.fromAliasName(stack, 'MyAlias', 'alias/myAlias'); - /* eslint-disable cdk/no-core-construct */ + /* eslint-disable @aws-cdk/no-core-construct */ class MyConstruct extends Construct { constructor(scope: Construct, id: string, key: IKey) { super(scope, id); @@ -179,7 +179,7 @@ test('imported alias by name - can be used where a key is expected', () => { } } new MyConstruct(stack, 'MyConstruct', myAlias); - /* eslint-enable cdk/no-core-construct */ + /* eslint-enable @aws-cdk/no-core-construct */ expect(stack).toHaveOutput({ outputName: 'OutId', diff --git a/packages/@aws-cdk/aws-kms/test/key.test.ts b/packages/@aws-cdk/aws-kms/test/key.test.ts index a7144cbb950d7..fae1564223d45 100644 --- a/packages/@aws-cdk/aws-kms/test/key.test.ts +++ b/packages/@aws-cdk/aws-kms/test/key.test.ts @@ -3,7 +3,7 @@ import '@aws-cdk/assert-internal/jest'; import * as iam from '@aws-cdk/aws-iam'; import * as cdk from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; -import { testFutureBehavior, testLegacyBehavior } from 'cdk-build-tools/lib/feature-flag'; +import { testFutureBehavior, testLegacyBehavior } from '@aws-cdk/cdk-build-tools/lib/feature-flag'; import * as kms from '../lib'; const ADMIN_ACTIONS: string[] = [ diff --git a/packages/@aws-cdk/aws-lakeformation/.eslintrc.js b/packages/@aws-cdk/aws-lakeformation/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-lakeformation/.eslintrc.js +++ b/packages/@aws-cdk/aws-lakeformation/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-lakeformation/jest.config.js b/packages/@aws-cdk/aws-lakeformation/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-lakeformation/jest.config.js +++ b/packages/@aws-cdk/aws-lakeformation/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-lakeformation/package.json b/packages/@aws-cdk/aws-lakeformation/package.json index 87af67a50de81..7609498bebed8 100644 --- a/packages/@aws-cdk/aws-lakeformation/package.json +++ b/packages/@aws-cdk/aws-lakeformation/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::LakeFormation", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-lambda-destinations/.eslintrc.js b/packages/@aws-cdk/aws-lambda-destinations/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-lambda-destinations/.eslintrc.js +++ b/packages/@aws-cdk/aws-lambda-destinations/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-lambda-destinations/jest.config.js b/packages/@aws-cdk/aws-lambda-destinations/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-lambda-destinations/jest.config.js +++ b/packages/@aws-cdk/aws-lambda-destinations/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-lambda-destinations/package.json b/packages/@aws-cdk/aws-lambda-destinations/package.json index 4156149551b5b..66dea74b84119 100644 --- a/packages/@aws-cdk/aws-lambda-destinations/package.json +++ b/packages/@aws-cdk/aws-lambda-destinations/package.json @@ -64,13 +64,13 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-events": "0.0.0", @@ -103,7 +103,6 @@ }, "maturity": "stable", "cdk-build": { - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } diff --git a/packages/@aws-cdk/aws-lambda-event-sources/.eslintrc.js b/packages/@aws-cdk/aws-lambda-event-sources/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/.eslintrc.js +++ b/packages/@aws-cdk/aws-lambda-event-sources/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-lambda-event-sources/jest.config.js b/packages/@aws-cdk/aws-lambda-event-sources/jest.config.js index cd664e1d069e5..34818e1593f6b 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/jest.config.js +++ b/packages/@aws-cdk/aws-lambda-event-sources/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +const baseConfig = require('../../../tools/@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-lambda-event-sources/lib/kafka.ts b/packages/@aws-cdk/aws-lambda-event-sources/lib/kafka.ts index 117aae2b19b80..54e98a47bb55d 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/lib/kafka.ts +++ b/packages/@aws-cdk/aws-lambda-event-sources/lib/kafka.ts @@ -49,6 +49,10 @@ export enum AuthenticationMethod { * SASL_SCRAM_256_AUTH authentication method for your Kafka cluster */ SASL_SCRAM_256_AUTH = 'SASL_SCRAM_256_AUTH', + /** + * BASIC_AUTH (SASL/PLAIN) authentication method for your Kafka cluster + */ + BASIC_AUTH = 'BASIC_AUTH', } /** @@ -193,6 +197,9 @@ export class SelfManagedKafkaEventSource extends StreamEventSource { private sourceAccessConfigurations() { let authType; switch (this.innerProps.authenticationMethod) { + case AuthenticationMethod.BASIC_AUTH: + authType = lambda.SourceAccessConfigurationType.BASIC_AUTH; + break; case AuthenticationMethod.SASL_SCRAM_256_AUTH: authType = lambda.SourceAccessConfigurationType.SASL_SCRAM_256_AUTH; break; diff --git a/packages/@aws-cdk/aws-lambda-event-sources/package.json b/packages/@aws-cdk/aws-lambda-event-sources/package.json index 0db8f4d09f9a6..1660dfe07b24a 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/package.json +++ b/packages/@aws-cdk/aws-lambda-event-sources/package.json @@ -64,12 +64,12 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-apigateway": "0.0.0", @@ -129,7 +129,6 @@ }, "maturity": "stable", "cdk-build": { - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } diff --git a/packages/@aws-cdk/aws-lambda-event-sources/test/kafka.test.ts b/packages/@aws-cdk/aws-lambda-event-sources/test/kafka.test.ts index 1c361ffe7a442..804069373c114 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/test/kafka.test.ts +++ b/packages/@aws-cdk/aws-lambda-event-sources/test/kafka.test.ts @@ -240,7 +240,7 @@ describe('KafkaEventSource', () => { topic: kafkaTopic, startingPosition: lambda.StartingPosition.TRIM_HORIZON, vpc: vpc, - vpcSubnets: { subnetType: SubnetType.PRIVATE }, + vpcSubnets: { subnetType: SubnetType.PRIVATE_WITH_NAT }, securityGroup: sg, })); @@ -300,7 +300,7 @@ describe('KafkaEventSource', () => { secret: secret, startingPosition: lambda.StartingPosition.TRIM_HORIZON, vpc: vpc, - vpcSubnets: { subnetType: SubnetType.PRIVATE }, + vpcSubnets: { subnetType: SubnetType.PRIVATE_WITH_NAT }, securityGroup: sg, })); @@ -411,7 +411,7 @@ describe('KafkaEventSource', () => { secret: secret, startingPosition: lambda.StartingPosition.TRIM_HORIZON, vpc: vpc, - vpcSubnets: { subnetType: SubnetType.PRIVATE }, + vpcSubnets: { subnetType: SubnetType.PRIVATE_WITH_NAT }, })); }).toThrow(/securityGroup must be set/); @@ -437,7 +437,7 @@ describe('KafkaEventSource', () => { secret: secret, startingPosition: lambda.StartingPosition.TRIM_HORIZON, vpc: vpc, - vpcSubnets: { subnetType: SubnetType.PRIVATE }, + vpcSubnets: { subnetType: SubnetType.PRIVATE_WITH_NAT }, securityGroup: sg, authenticationMethod: sources.AuthenticationMethod.SASL_SCRAM_256_AUTH, })); @@ -452,9 +452,41 @@ describe('KafkaEventSource', () => { }, ]), }); + }); + test('using BASIC_AUTH', () => { + // GIVEN + const stack = new cdk.Stack(); + const fn = new TestFunction(stack, 'Fn'); + const kafkaTopic = 'some-topic'; + const secret = new Secret(stack, 'Secret', { secretName: 'AmazonMSK_KafkaSecret' }); + const bootstrapServers = ['kafka-broker:9092']; + const sg = SecurityGroup.fromSecurityGroupId(stack, 'SecurityGroup', 'sg-0123456789'); + const vpc = new Vpc(stack, 'Vpc'); + + // WHEN + fn.addEventSource(new sources.SelfManagedKafkaEventSource( + { + bootstrapServers: bootstrapServers, + topic: kafkaTopic, + secret: secret, + startingPosition: lambda.StartingPosition.TRIM_HORIZON, + vpc: vpc, + vpcSubnets: { subnetType: SubnetType.PRIVATE_WITH_NAT }, + securityGroup: sg, + authenticationMethod: sources.AuthenticationMethod.BASIC_AUTH, + })); + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::EventSourceMapping', { + SourceAccessConfigurations: Match.arrayWith([ + { + Type: 'BASIC_AUTH', + URI: { + Ref: 'SecretA720EF05', + }, + }, + ]), + }); }); }); - }); diff --git a/packages/@aws-cdk/aws-lambda-go/.eslintrc.js b/packages/@aws-cdk/aws-lambda-go/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-lambda-go/.eslintrc.js +++ b/packages/@aws-cdk/aws-lambda-go/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-lambda-go/README.md b/packages/@aws-cdk/aws-lambda-go/README.md index 5fb2907b0bf7a..16fcffee919ea 100644 --- a/packages/@aws-cdk/aws-lambda-go/README.md +++ b/packages/@aws-cdk/aws-lambda-go/README.md @@ -106,7 +106,7 @@ All other properties of `lambda.Function` are supported, see also the [AWS Lambd By default the following environment variables are set for you: * `GOOS=linux` -* `GOARCH=amd64` +* `GOARCH`: based on the target architecture of the Lambda function * `GO111MODULE=on` Use the `environment` prop to define additional environment variables when go runs: @@ -124,7 +124,7 @@ new lambda.GoFunction(this, 'handler', { ## Local Bundling -If `Go` is installed locally and the version is >= `go1.11` then it will be used to bundle your code in your environment. Otherwise, bundling will happen in a [Lambda compatible Docker container](https://hub.docker.com/layers/lambci/lambda/build-go1.x/images/sha256-e14dab718ed0bb06b2243825c5993e494a6969de7c01754ad7e80dacfce9b0cf?context=explore). +If `Go` is installed locally and the version is >= `go1.11` then it will be used to bundle your code in your environment. Otherwise, bundling will happen in a [Lambda compatible Docker container](https://gallery.ecr.aws/sam/build-go1.x) with the Docker platform based on the target architecture of the Lambda function. For macOS the recommended approach is to install `Go` as Docker volume performance is really poor. diff --git a/packages/@aws-cdk/aws-lambda-go/jest.config.js b/packages/@aws-cdk/aws-lambda-go/jest.config.js index 33885f40aacf1..92ed1d466ea3f 100644 --- a/packages/@aws-cdk/aws-lambda-go/jest.config.js +++ b/packages/@aws-cdk/aws-lambda-go/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require("cdk-build-tools/config/jest.config"); +const baseConfig = require("@aws-cdk/cdk-build-tools/config/jest.config"); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-lambda-go/lib/bundling.ts b/packages/@aws-cdk/aws-lambda-go/lib/bundling.ts index fd320cce90aed..afc233479ef3b 100644 --- a/packages/@aws-cdk/aws-lambda-go/lib/bundling.ts +++ b/packages/@aws-cdk/aws-lambda-go/lib/bundling.ts @@ -1,6 +1,6 @@ import * as os from 'os'; import * as path from 'path'; -import { AssetCode, Code, Runtime } from '@aws-cdk/aws-lambda'; +import { Architecture, AssetCode, Code, Runtime } from '@aws-cdk/aws-lambda'; import * as cdk from '@aws-cdk/core'; import { BundlingOptions } from './types'; import { exec, findUp, getGoBuildVersion } from './util'; @@ -55,6 +55,11 @@ export interface BundlingProps extends BundlingOptions { * The runtime of the lambda function */ readonly runtime: Runtime; + + /** + * The system architecture of the lambda function + */ + readonly architecture: Architecture; } /** @@ -104,7 +109,7 @@ export class Bundling implements cdk.BundlingOptions { const environment = { CGO_ENABLED: cgoEnabled, GO111MODULE: 'on', - GOARCH: 'amd64', + GOARCH: props.architecture.dockerPlatform.split('/')[1], GOOS: 'linux', ...props.environment, }; @@ -117,6 +122,7 @@ export class Bundling implements cdk.BundlingOptions { ...props.buildArgs ?? {}, IMAGE: Runtime.GO_1_X.bundlingImage.image, // always use the GO_1_X build image }, + platform: props.architecture.dockerPlatform, }) : cdk.DockerImage.fromRegistry('dummy'); // Do not build if we don't need to diff --git a/packages/@aws-cdk/aws-lambda-go/lib/function.ts b/packages/@aws-cdk/aws-lambda-go/lib/function.ts index 3b915e859cef3..4c7220ee27dce 100644 --- a/packages/@aws-cdk/aws-lambda-go/lib/function.ts +++ b/packages/@aws-cdk/aws-lambda-go/lib/function.ts @@ -104,6 +104,7 @@ export class GoFunction extends lambda.Function { } const runtime = props.runtime ?? lambda.Runtime.PROVIDED_AL2; + const architecture = props.architecture ?? lambda.Architecture.X86_64; super(scope, id, { ...props, @@ -112,6 +113,7 @@ export class GoFunction extends lambda.Function { ...props.bundling ?? {}, entry, runtime, + architecture, moduleDir, }), handler: 'bootstrap', // setting name to bootstrap so that the 'provided' runtime can also be used diff --git a/packages/@aws-cdk/aws-lambda-go/package.json b/packages/@aws-cdk/aws-lambda-go/package.json index 5ab8238df938e..4fca8e06193ad 100644 --- a/packages/@aws-cdk/aws-lambda-go/package.json +++ b/packages/@aws-cdk/aws-lambda-go/package.json @@ -67,11 +67,11 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assertions": "0.0.0", - "@types/jest": "^26.0.24", "@aws-cdk/aws-ec2": "0.0.0", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/aws-lambda": "0.0.0", @@ -97,9 +97,6 @@ "docker" ] }, - "cdk-build": { - "jest": true - }, "publishConfig": { "tag": "latest" } diff --git a/packages/@aws-cdk/aws-lambda-go/test/bundling.test.ts b/packages/@aws-cdk/aws-lambda-go/test/bundling.test.ts index 474657dff61b9..73dfec99b45c1 100644 --- a/packages/@aws-cdk/aws-lambda-go/test/bundling.test.ts +++ b/packages/@aws-cdk/aws-lambda-go/test/bundling.test.ts @@ -1,26 +1,28 @@ import * as child_process from 'child_process'; import * as os from 'os'; import * as path from 'path'; -import { Code, Runtime } from '@aws-cdk/aws-lambda'; +import { Architecture, Code, Runtime } from '@aws-cdk/aws-lambda'; import { AssetHashType, DockerImage } from '@aws-cdk/core'; import { Bundling } from '../lib/bundling'; import * as util from '../lib/util'; -jest.spyOn(Code, 'fromAsset'); -const fromAssetMock = jest.spyOn(DockerImage, 'fromBuild'); let getGoBuildVersionMock = jest.spyOn(util, 'getGoBuildVersion'); beforeEach(() => { jest.clearAllMocks(); jest.resetAllMocks(); Bundling.clearRunsLocallyCache(); - getGoBuildVersionMock.mockReturnValue(true); - fromAssetMock.mockReturnValue({ + + jest.spyOn(Code, 'fromAsset'); + + jest.spyOn(DockerImage, 'fromBuild').mockReturnValue({ image: 'built-image', cp: () => 'built-image', run: () => {}, toJSON: () => 'build-image', }); + + getGoBuildVersionMock.mockReturnValue(true); }); const moduleDir = '/project/go.mod'; @@ -30,6 +32,7 @@ test('bundling', () => { Bundling.bundle({ entry, runtime: Runtime.GO_1_X, + architecture: Architecture.X86_64, moduleDir, forcedDockerBundling: true, environment: { @@ -55,12 +58,20 @@ test('bundling', () => { ], }), }); + + expect(DockerImage.fromBuild).toHaveBeenCalledWith(expect.stringMatching(/aws-lambda-go\/lib$/), expect.objectContaining({ + buildArgs: expect.objectContaining({ + IMAGE: expect.stringMatching(/build-go/), + }), + platform: 'linux/amd64', + })); }); test('bundling with file as entry', () => { Bundling.bundle({ entry: '/project/main.go', runtime: Runtime.GO_1_X, + architecture: Architecture.X86_64, moduleDir, }); @@ -81,6 +92,7 @@ test('bundling with file in subdirectory as entry', () => { Bundling.bundle({ entry: '/project/cmd/api/main.go', runtime: Runtime.GO_1_X, + architecture: Architecture.X86_64, moduleDir, }); @@ -101,6 +113,7 @@ test('bundling with file other than main.go in subdirectory as entry', () => { Bundling.bundle({ entry: '/project/cmd/api/api.go', runtime: Runtime.GO_1_X, + architecture: Architecture.X86_64, moduleDir, }); @@ -122,6 +135,7 @@ test('go with Windows paths', () => { Bundling.bundle({ entry: 'C:\\my-project\\cmd\\api', runtime: Runtime.GO_1_X, + architecture: Architecture.X86_64, moduleDir: 'C:\\my-project\\go.mod', forcedDockerBundling: true, }); @@ -141,13 +155,14 @@ test('with Docker build args', () => { Bundling.bundle({ entry, runtime: Runtime.GO_1_X, + architecture: Architecture.X86_64, moduleDir, forcedDockerBundling: true, buildArgs: { HELLO: 'WORLD', }, }); - expect(fromAssetMock).toHaveBeenCalledWith(expect.stringMatching(/lib$/), expect.objectContaining({ + expect(DockerImage.fromBuild).toHaveBeenCalledWith(expect.stringMatching(/aws-lambda-go\/lib$/), expect.objectContaining({ buildArgs: expect.objectContaining({ HELLO: 'WORLD', }), @@ -171,6 +186,7 @@ test('Local bundling', () => { KEY: 'value', }, runtime: Runtime.PROVIDED_AL2, + architecture: Architecture.X86_64, }); expect(bundler.local).toBeDefined(); @@ -188,7 +204,7 @@ test('Local bundling', () => { ); // Docker image is not built - expect(fromAssetMock).not.toHaveBeenCalled(); + expect(DockerImage.fromBuild).not.toHaveBeenCalled(); }); test('Incorrect go version', () => { @@ -198,6 +214,7 @@ test('Incorrect go version', () => { entry, moduleDir, runtime: Runtime.PROVIDED_AL2, + architecture: Architecture.X86_64, }); const tryBundle = bundler.local?.tryBundle('/outdir', { image: Runtime.GO_1_X.bundlingDockerImage }); @@ -211,6 +228,7 @@ test('Custom bundling docker image', () => { entry, moduleDir, runtime: Runtime.GO_1_X, + architecture: Architecture.X86_64, forcedDockerBundling: true, dockerImage: DockerImage.fromRegistry('my-custom-image'), }); @@ -227,6 +245,7 @@ test('Go build flags can be passed', () => { Bundling.bundle({ entry, runtime: Runtime.GO_1_X, + architecture: Architecture.X86_64, moduleDir, environment: { KEY: 'value', @@ -258,6 +277,7 @@ test('AssetHashType can be specified', () => { Bundling.bundle({ entry, runtime: Runtime.GO_1_X, + architecture: Architecture.X86_64, moduleDir, environment: { KEY: 'value', @@ -291,6 +311,7 @@ test('with command hooks', () => { entry, moduleDir, runtime: Runtime.PROVIDED_AL2, + architecture: Architecture.X86_64, commandHooks: { beforeBundling(inputDir: string, outputDir: string): string[] { return [ diff --git a/packages/@aws-cdk/aws-lambda-nodejs/.eslintrc.js b/packages/@aws-cdk/aws-lambda-nodejs/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/.eslintrc.js +++ b/packages/@aws-cdk/aws-lambda-nodejs/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-lambda-nodejs/README.md b/packages/@aws-cdk/aws-lambda-nodejs/README.md index 22347b28b1dd9..2c0572231a8ae 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/README.md +++ b/packages/@aws-cdk/aws-lambda-nodejs/README.md @@ -99,7 +99,8 @@ used by your function. Otherwise bundling will fail. ## Local bundling If `esbuild` is available it will be used to bundle your code in your environment. Otherwise, -bundling will happen in a [Lambda compatible Docker container](https://gallery.ecr.aws/sam/build-nodejs12.x). +bundling will happen in a [Lambda compatible Docker container](https://gallery.ecr.aws/sam/build-nodejs12.x) +with the Docker platform based on the target architecture of the Lambda function. For macOS the recommendend approach is to install `esbuild` as Docker volume performance is really poor. diff --git a/packages/@aws-cdk/aws-lambda-nodejs/jest.config.js b/packages/@aws-cdk/aws-lambda-nodejs/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/jest.config.js +++ b/packages/@aws-cdk/aws-lambda-nodejs/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-lambda-nodejs/lib/bundling.ts b/packages/@aws-cdk/aws-lambda-nodejs/lib/bundling.ts index 3c33ad74f2471..3db8b21c3f592 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/lib/bundling.ts +++ b/packages/@aws-cdk/aws-lambda-nodejs/lib/bundling.ts @@ -1,6 +1,6 @@ import * as os from 'os'; import * as path from 'path'; -import { AssetCode, Code, Runtime } from '@aws-cdk/aws-lambda'; +import { Architecture, AssetCode, Code, Runtime } from '@aws-cdk/aws-lambda'; import * as cdk from '@aws-cdk/core'; import { EsbuildInstallation } from './esbuild-installation'; import { PackageManager } from './package-manager'; @@ -28,6 +28,11 @@ export interface BundlingProps extends BundlingOptions { */ readonly runtime: Runtime; + /** + * The system architecture of the lambda function + */ + readonly architecture: Architecture; + /** * Path to project root */ @@ -99,6 +104,7 @@ export class Bundling implements cdk.BundlingOptions { IMAGE: props.runtime.bundlingImage.image, ESBUILD_VERSION: props.esbuildVersion ?? ESBUILD_MAJOR_VERSION, }, + platform: props.architecture.dockerPlatform, }) : cdk.DockerImage.fromRegistry('dummy'); // Do not build if we don't need to diff --git a/packages/@aws-cdk/aws-lambda-nodejs/lib/function.ts b/packages/@aws-cdk/aws-lambda-nodejs/lib/function.ts index 09c4964fd610d..0bb00a2c35e5c 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/lib/function.ts +++ b/packages/@aws-cdk/aws-lambda-nodejs/lib/function.ts @@ -1,6 +1,7 @@ import * as fs from 'fs'; import * as path from 'path'; import * as lambda from '@aws-cdk/aws-lambda'; +import { Architecture } from '@aws-cdk/aws-lambda'; import { Bundling } from './bundling'; import { PackageManager } from './package-manager'; import { BundlingOptions } from './types'; @@ -95,6 +96,7 @@ export class NodejsFunction extends lambda.Function { const entry = path.resolve(findEntry(id, props.entry)); const handler = props.handler ?? 'handler'; const runtime = props.runtime ?? lambda.Runtime.NODEJS_14_X; + const architecture = props.architecture ?? Architecture.X86_64; const depsLockFilePath = findLockFile(props.depsLockFilePath); const projectRoot = props.projectRoot ?? path.dirname(depsLockFilePath); @@ -105,6 +107,7 @@ export class NodejsFunction extends lambda.Function { ...props.bundling ?? {}, entry, runtime, + architecture, depsLockFilePath, projectRoot, }), diff --git a/packages/@aws-cdk/aws-lambda-nodejs/package.json b/packages/@aws-cdk/aws-lambda-nodejs/package.json index ce16b825a12fc..185aeed69b3ec 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/package.json +++ b/packages/@aws-cdk/aws-lambda-nodejs/package.json @@ -64,14 +64,14 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", + "@aws-cdk/assert-internal": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24", "delay": "5.0.0", - "esbuild": "^0.12.15", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "esbuild": "^0.13.5" }, "dependencies": { "@aws-cdk/aws-lambda": "0.0.0", @@ -93,9 +93,6 @@ "announce": false }, "nozem": false, - "cdk-build": { - "jest": true - }, "publishConfig": { "tag": "latest" } diff --git a/packages/@aws-cdk/aws-lambda-nodejs/test/bundling.test.ts b/packages/@aws-cdk/aws-lambda-nodejs/test/bundling.test.ts index a38a6fa08d5bc..df70c1437d356 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/test/bundling.test.ts +++ b/packages/@aws-cdk/aws-lambda-nodejs/test/bundling.test.ts @@ -1,7 +1,7 @@ import * as child_process from 'child_process'; import * as os from 'os'; import * as path from 'path'; -import { Code, Runtime } from '@aws-cdk/aws-lambda'; +import { Architecture, Code, Runtime } from '@aws-cdk/aws-lambda'; import { AssetHashType, DockerImage } from '@aws-cdk/core'; import { version as delayVersion } from 'delay/package.json'; import { Bundling } from '../lib/bundling'; @@ -9,10 +9,6 @@ import { EsbuildInstallation } from '../lib/esbuild-installation'; import { LogLevel, SourceMapMode } from '../lib/types'; import * as util from '../lib/util'; -jest.mock('@aws-cdk/aws-lambda'); - -// Mock DockerImage.fromAsset() to avoid building the image -let fromBuildMock: jest.SpyInstance; let detectEsbuildMock: jest.SpyInstance; beforeEach(() => { jest.clearAllMocks(); @@ -20,12 +16,14 @@ beforeEach(() => { jest.restoreAllMocks(); Bundling.clearEsbuildInstallationCache(); + jest.spyOn(Code, 'fromAsset'); + detectEsbuildMock = jest.spyOn(EsbuildInstallation, 'detect').mockReturnValue({ isLocal: true, version: '0.8.8', }); - fromBuildMock = jest.spyOn(DockerImage, 'fromBuild').mockReturnValue({ + jest.spyOn(DockerImage, 'fromBuild').mockReturnValue({ image: 'built-image', cp: () => 'dest-path', run: () => {}, @@ -44,6 +42,7 @@ test('esbuild bundling in Docker', () => { projectRoot, depsLockFilePath, runtime: Runtime.NODEJS_12_X, + architecture: Architecture.X86_64, environment: { KEY: 'value', }, @@ -67,6 +66,13 @@ test('esbuild bundling in Docker', () => { workingDirectory: '/', }), }); + + expect(DockerImage.fromBuild).toHaveBeenCalledWith(expect.stringMatching(/aws-lambda-nodejs\/lib$/), expect.objectContaining({ + buildArgs: expect.objectContaining({ + IMAGE: expect.stringMatching(/build-nodejs/), + }), + platform: 'linux/amd64', + })); }); test('esbuild bundling with handler named index.ts', () => { @@ -75,6 +81,7 @@ test('esbuild bundling with handler named index.ts', () => { projectRoot, depsLockFilePath, runtime: Runtime.NODEJS_12_X, + architecture: Architecture.X86_64, forceDockerBundling: true, }); @@ -96,6 +103,7 @@ test('esbuild bundling with tsx handler', () => { projectRoot, depsLockFilePath, runtime: Runtime.NODEJS_12_X, + architecture: Architecture.X86_64, forceDockerBundling: true, }); @@ -121,6 +129,7 @@ test('esbuild with Windows paths', () => { Bundling.bundle({ entry: 'C:\\my-project\\lib\\entry.ts', runtime: Runtime.NODEJS_12_X, + architecture: Architecture.X86_64, projectRoot: 'C:\\my-project', depsLockFilePath: 'C:\\my-project\\package-lock.json', forceDockerBundling: true, @@ -144,6 +153,7 @@ test('esbuild bundling with externals and dependencies', () => { projectRoot: path.dirname(packageLock), depsLockFilePath: packageLock, runtime: Runtime.NODEJS_12_X, + architecture: Architecture.X86_64, externalModules: ['abc'], nodeModules: ['delay'], forceDockerBundling: true, @@ -173,6 +183,7 @@ test('esbuild bundling with esbuild options', () => { projectRoot, depsLockFilePath, runtime: Runtime.NODEJS_12_X, + architecture: Architecture.X86_64, minify: true, sourceMap: true, target: 'es2020', @@ -224,6 +235,7 @@ test('esbuild bundling source map default', () => { projectRoot, depsLockFilePath, runtime: Runtime.NODEJS_14_X, + architecture: Architecture.X86_64, sourceMap: true, sourceMapMode: SourceMapMode.DEFAULT, }); @@ -249,6 +261,7 @@ test('esbuild bundling source map inline', () => { projectRoot, depsLockFilePath, runtime: Runtime.NODEJS_14_X, + architecture: Architecture.X86_64, sourceMap: true, sourceMapMode: SourceMapMode.INLINE, }); @@ -274,6 +287,7 @@ test('esbuild bundling source map enabled when only source map mode exists', () projectRoot, depsLockFilePath, runtime: Runtime.NODEJS_14_X, + architecture: Architecture.X86_64, sourceMapMode: SourceMapMode.INLINE, }); @@ -299,6 +313,7 @@ test('esbuild bundling throws when sourceMapMode used with false sourceMap', () projectRoot, depsLockFilePath, runtime: Runtime.NODEJS_14_X, + architecture: Architecture.X86_64, sourceMap: false, sourceMapMode: SourceMapMode.INLINE, }); @@ -312,6 +327,7 @@ test('Detects yarn.lock', () => { projectRoot: path.dirname(yarnLock), depsLockFilePath: yarnLock, runtime: Runtime.NODEJS_12_X, + architecture: Architecture.X86_64, nodeModules: ['delay'], forceDockerBundling: true, }); @@ -334,6 +350,7 @@ test('Detects pnpm-lock.yaml', () => { projectRoot, depsLockFilePath: pnpmLock, runtime: Runtime.NODEJS_12_X, + architecture: Architecture.X86_64, nodeModules: ['delay'], forceDockerBundling: true, }); @@ -355,13 +372,14 @@ test('with Docker build args', () => { projectRoot, depsLockFilePath, runtime: Runtime.NODEJS_12_X, + architecture: Architecture.X86_64, buildArgs: { HELLO: 'WORLD', }, forceDockerBundling: true, }); - expect(fromBuildMock).toHaveBeenCalledWith(expect.stringMatching(/lib$/), expect.objectContaining({ + expect(DockerImage.fromBuild).toHaveBeenCalledWith(expect.stringMatching(/lib$/), expect.objectContaining({ buildArgs: expect.objectContaining({ HELLO: 'WORLD', }), @@ -383,6 +401,7 @@ test('Local bundling', () => { projectRoot, depsLockFilePath, runtime: Runtime.NODEJS_12_X, + architecture: Architecture.X86_64, environment: { KEY: 'value', }, @@ -403,7 +422,7 @@ test('Local bundling', () => { ); // Docker image is not built - expect(fromBuildMock).not.toHaveBeenCalled(); + expect(DockerImage.fromBuild).not.toHaveBeenCalled(); spawnSyncMock.mockRestore(); }); @@ -420,6 +439,7 @@ test('Incorrect esbuild version', () => { projectRoot, depsLockFilePath, runtime: Runtime.NODEJS_12_X, + architecture: Architecture.X86_64, }); expect(() => bundler.local?.tryBundle('/outdir', { @@ -433,6 +453,7 @@ test('Custom bundling docker image', () => { projectRoot, depsLockFilePath, runtime: Runtime.NODEJS_12_X, + architecture: Architecture.X86_64, dockerImage: DockerImage.fromRegistry('my-custom-image'), forceDockerBundling: true, }); @@ -451,6 +472,7 @@ test('with command hooks', () => { projectRoot, depsLockFilePath, runtime: Runtime.NODEJS_12_X, + architecture: Architecture.X86_64, commandHooks: { beforeBundling(inputDir: string, outputDir: string): string[] { return [ @@ -486,6 +508,7 @@ test('esbuild bundling with projectRoot', () => { depsLockFilePath, tsconfig, runtime: Runtime.NODEJS_12_X, + architecture: Architecture.X86_64, }); // Correctly bundles with esbuild @@ -508,6 +531,7 @@ test('esbuild bundling with projectRoot and externals and dependencies', () => { projectRoot: repoRoot, depsLockFilePath: packageLock, runtime: Runtime.NODEJS_12_X, + architecture: Architecture.X86_64, externalModules: ['abc'], nodeModules: ['delay'], forceDockerBundling: true, diff --git a/packages/@aws-cdk/aws-lambda-python/.eslintrc.js b/packages/@aws-cdk/aws-lambda-python/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-lambda-python/.eslintrc.js +++ b/packages/@aws-cdk/aws-lambda-python/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-lambda-python/README.md b/packages/@aws-cdk/aws-lambda-python/README.md index ffd19568aa5dc..4106b6210b871 100644 --- a/packages/@aws-cdk/aws-lambda-python/README.md +++ b/packages/@aws-cdk/aws-lambda-python/README.md @@ -42,11 +42,11 @@ All other properties of `lambda.Function` are supported, see also the [AWS Lambd If `requirements.txt` or `Pipfile` exists at the entry path, the construct will handle installing all required modules in a [Lambda compatible Docker container](https://gallery.ecr.aws/sam/build-python3.7) -according to the `runtime`. +according to the `runtime` and with the Docker platform based on the target architecture of the Lambda function. -Python bundles are only recreated and published when a file in a source directory has changed. +Python bundles are only recreated and published when a file in a source directory has changed. Therefore (and as a general best-practice), it is highly recommended to commit a lockfile with a -list of all transitive dependencies and their exact versions. +list of all transitive dependencies and their exact versions. This will ensure that when any dependency version is updated, the bundle asset is recreated and uploaded. To that end, we recommend using [`pipenv`] or [`poetry`] which has lockfile support. diff --git a/packages/@aws-cdk/aws-lambda-python/jest.config.js b/packages/@aws-cdk/aws-lambda-python/jest.config.js index fc310b5014407..d052cbb29f05d 100644 --- a/packages/@aws-cdk/aws-lambda-python/jest.config.js +++ b/packages/@aws-cdk/aws-lambda-python/jest.config.js @@ -1,4 +1,4 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = { ...baseConfig, coverageThreshold: { diff --git a/packages/@aws-cdk/aws-lambda-python/lib/bundling.ts b/packages/@aws-cdk/aws-lambda-python/lib/bundling.ts index 0c2b4bf624786..722cd2d062fb6 100644 --- a/packages/@aws-cdk/aws-lambda-python/lib/bundling.ts +++ b/packages/@aws-cdk/aws-lambda-python/lib/bundling.ts @@ -27,6 +27,11 @@ export interface BundlingOptions { */ readonly runtime: lambda.Runtime; + /** + * The system architecture of the lambda function + */ + readonly architecture: lambda.Architecture; + /** * Output path suffix ('python' for a layer, '.' otherwise) */ @@ -77,7 +82,7 @@ export interface BundlingOptions { * Produce bundled Lambda asset code */ export function bundle(options: BundlingOptions): lambda.Code { - const { entry, runtime, outputPathSuffix } = options; + const { entry, runtime, architecture, outputPathSuffix } = options; const stagedir = cdk.FileSystem.mkdtemp('python-bundling-'); const hasDeps = stageDependencies(entry, stagedir); @@ -102,6 +107,7 @@ export function bundle(options: BundlingOptions): lambda.Code { buildArgs: { IMAGE: runtime.bundlingImage.image, }, + platform: architecture.dockerPlatform, file: dockerfile, }); diff --git a/packages/@aws-cdk/aws-lambda-python/lib/function.ts b/packages/@aws-cdk/aws-lambda-python/lib/function.ts index 733c115c0383d..84d21b7564909 100644 --- a/packages/@aws-cdk/aws-lambda-python/lib/function.ts +++ b/packages/@aws-cdk/aws-lambda-python/lib/function.ts @@ -102,12 +102,14 @@ export class PythonFunction extends lambda.Function { const handler = props.handler ?? 'handler'; const runtime = props.runtime ?? lambda.Runtime.PYTHON_3_7; + const architecture = props.architecture ?? lambda.Architecture.X86_64; super(scope, id, { ...props, runtime, code: bundle({ runtime, + architecture, entry, outputPathSuffix: '.', assetHashType: props.assetHashType, diff --git a/packages/@aws-cdk/aws-lambda-python/lib/layer.ts b/packages/@aws-cdk/aws-lambda-python/lib/layer.ts index 1a9684e224580..4f247acc10bae 100644 --- a/packages/@aws-cdk/aws-lambda-python/lib/layer.ts +++ b/packages/@aws-cdk/aws-lambda-python/lib/layer.ts @@ -21,6 +21,12 @@ export interface PythonLayerVersionProps extends lambda.LayerVersionOptions { * @default - All runtimes are supported. */ readonly compatibleRuntimes?: lambda.Runtime[]; + + /** + * The system architectures compatible with this layer. + * @default [Architecture.X86_64] + */ + readonly compatibleArchitectures?: lambda.Architecture[]; } /** @@ -30,6 +36,7 @@ export interface PythonLayerVersionProps extends lambda.LayerVersionOptions { export class PythonLayerVersion extends lambda.LayerVersion { constructor(scope: Construct, id: string, props: PythonLayerVersionProps) { const compatibleRuntimes = props.compatibleRuntimes ?? [lambda.Runtime.PYTHON_3_7]; + const compatibleArchitectures = props.compatibleArchitectures ?? [lambda.Architecture.X86_64]; // Ensure that all compatible runtimes are python for (const runtime of compatibleRuntimes) { @@ -40,8 +47,9 @@ export class PythonLayerVersion extends lambda.LayerVersion { // Entry and defaults const entry = path.resolve(props.entry); - // Pick the first compatibleRuntime to use for bundling or PYTHON_3_7 - const runtime = compatibleRuntimes[0] ?? lambda.Runtime.PYTHON_3_7; + // Pick the first compatibleRuntime and compatibleArchitectures to use for bundling + const runtime = compatibleRuntimes[0]; + const architecture = compatibleArchitectures[0]; super(scope, id, { ...props, @@ -49,6 +57,7 @@ export class PythonLayerVersion extends lambda.LayerVersion { code: bundle({ entry, runtime, + architecture, outputPathSuffix: 'python', }), }); diff --git a/packages/@aws-cdk/aws-lambda-python/package.json b/packages/@aws-cdk/aws-lambda-python/package.json index 72e5a12de703a..b58c0fd91d57c 100644 --- a/packages/@aws-cdk/aws-lambda-python/package.json +++ b/packages/@aws-cdk/aws-lambda-python/package.json @@ -65,22 +65,22 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assertions": "0.0.0", - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { + "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/core": "0.0.0", - "@aws-cdk/aws-ec2": "0.0.0", "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { + "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/core": "0.0.0", - "@aws-cdk/aws-ec2": "0.0.0", "constructs": "^3.3.69" }, "engines": { @@ -91,9 +91,6 @@ "awscdkio": { "announce": false }, - "cdk-build": { - "jest": true - }, "nozem": { "ostools": [ "docker" diff --git a/packages/@aws-cdk/aws-lambda-python/test/bundling.test.ts b/packages/@aws-cdk/aws-lambda-python/test/bundling.test.ts index 712852023a367..01449e0cadeaa 100644 --- a/packages/@aws-cdk/aws-lambda-python/test/bundling.test.ts +++ b/packages/@aws-cdk/aws-lambda-python/test/bundling.test.ts @@ -1,10 +1,11 @@ import * as fs from 'fs'; import * as path from 'path'; -import { Code, Runtime } from '@aws-cdk/aws-lambda'; -import { FileSystem } from '@aws-cdk/core'; +import { Architecture, Code, Runtime } from '@aws-cdk/aws-lambda'; +import { DockerImage, FileSystem } from '@aws-cdk/core'; import { stageDependencies, bundle } from '../lib/bundling'; jest.spyOn(Code, 'fromAsset'); +jest.spyOn(DockerImage, 'fromBuild'); jest.mock('child_process', () => ({ spawnSync: jest.fn(() => { @@ -28,6 +29,7 @@ test('Bundling a function without dependencies', () => { bundle({ entry: entry, runtime: Runtime.PYTHON_3_7, + architecture: Architecture.X86_64, outputPathSuffix: '.', }); @@ -40,6 +42,13 @@ test('Bundling a function without dependencies', () => { ], }), })); + + expect(DockerImage.fromBuild).toHaveBeenCalledWith(expect.stringMatching(/python-bundling/), expect.objectContaining({ + buildArgs: expect.objectContaining({ + IMAGE: expect.stringMatching(/build-python/), + }), + platform: 'linux/amd64', + })); }); test('Bundling a function with requirements.txt installed', () => { @@ -47,6 +56,7 @@ test('Bundling a function with requirements.txt installed', () => { bundle({ entry: entry, runtime: Runtime.PYTHON_3_7, + architecture: Architecture.X86_64, outputPathSuffix: '.', }); @@ -66,6 +76,7 @@ test('Bundling Python 2.7 with requirements.txt installed', () => { bundle({ entry: entry, runtime: Runtime.PYTHON_2_7, + architecture: Architecture.X86_64, outputPathSuffix: '.', }); @@ -86,6 +97,7 @@ test('Bundling a layer with dependencies', () => { bundle({ entry: entry, runtime: Runtime.PYTHON_2_7, + architecture: Architecture.X86_64, outputPathSuffix: 'python', }); @@ -105,6 +117,7 @@ test('Bundling a python code layer', () => { bundle({ entry: path.join(entry, '.'), runtime: Runtime.PYTHON_2_7, + architecture: Architecture.X86_64, outputPathSuffix: 'python', }); diff --git a/packages/@aws-cdk/aws-lambda-python/test/integ.function.expected.json b/packages/@aws-cdk/aws-lambda-python/test/integ.function.expected.json index e48b9c2e0ad92..ed3d577fb40a3 100644 --- a/packages/@aws-cdk/aws-lambda-python/test/integ.function.expected.json +++ b/packages/@aws-cdk/aws-lambda-python/test/integ.function.expected.json @@ -36,7 +36,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParametersfc7bfbf72c74b955f7bc25d2bb123c0eeec9557cda17481146d51672768907b2S3Bucket383ED51E" + "Ref": "AssetParameters3dc2f7b8375fbf383f44eb8f798d324f60d516946c9f829fca3c5f747f973374S3Bucket07AE44EE" }, "S3Key": { "Fn::Join": [ @@ -49,7 +49,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersfc7bfbf72c74b955f7bc25d2bb123c0eeec9557cda17481146d51672768907b2S3VersionKeyA520554C" + "Ref": "AssetParameters3dc2f7b8375fbf383f44eb8f798d324f60d516946c9f829fca3c5f747f973374S3VersionKey01F8F2A1" } ] } @@ -62,7 +62,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersfc7bfbf72c74b955f7bc25d2bb123c0eeec9557cda17481146d51672768907b2S3VersionKeyA520554C" + "Ref": "AssetParameters3dc2f7b8375fbf383f44eb8f798d324f60d516946c9f829fca3c5f747f973374S3VersionKey01F8F2A1" } ] } @@ -87,17 +87,17 @@ } }, "Parameters": { - "AssetParametersfc7bfbf72c74b955f7bc25d2bb123c0eeec9557cda17481146d51672768907b2S3Bucket383ED51E": { + "AssetParameters3dc2f7b8375fbf383f44eb8f798d324f60d516946c9f829fca3c5f747f973374S3Bucket07AE44EE": { "Type": "String", - "Description": "S3 bucket for asset \"fc7bfbf72c74b955f7bc25d2bb123c0eeec9557cda17481146d51672768907b2\"" + "Description": "S3 bucket for asset \"3dc2f7b8375fbf383f44eb8f798d324f60d516946c9f829fca3c5f747f973374\"" }, - "AssetParametersfc7bfbf72c74b955f7bc25d2bb123c0eeec9557cda17481146d51672768907b2S3VersionKeyA520554C": { + "AssetParameters3dc2f7b8375fbf383f44eb8f798d324f60d516946c9f829fca3c5f747f973374S3VersionKey01F8F2A1": { "Type": "String", - "Description": "S3 key for asset version \"fc7bfbf72c74b955f7bc25d2bb123c0eeec9557cda17481146d51672768907b2\"" + "Description": "S3 key for asset version \"3dc2f7b8375fbf383f44eb8f798d324f60d516946c9f829fca3c5f747f973374\"" }, - "AssetParametersfc7bfbf72c74b955f7bc25d2bb123c0eeec9557cda17481146d51672768907b2ArtifactHashB863A6ED": { + "AssetParameters3dc2f7b8375fbf383f44eb8f798d324f60d516946c9f829fca3c5f747f973374ArtifactHashDECBC32A": { "Type": "String", - "Description": "Artifact hash for asset \"fc7bfbf72c74b955f7bc25d2bb123c0eeec9557cda17481146d51672768907b2\"" + "Description": "Artifact hash for asset \"3dc2f7b8375fbf383f44eb8f798d324f60d516946c9f829fca3c5f747f973374\"" } }, "Outputs": { diff --git a/packages/@aws-cdk/aws-lambda/.eslintrc.js b/packages/@aws-cdk/aws-lambda/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-lambda/.eslintrc.js +++ b/packages/@aws-cdk/aws-lambda/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-lambda/README.md b/packages/@aws-cdk/aws-lambda/README.md index c6098ff19fe11..dc97826d51135 100644 --- a/packages/@aws-cdk/aws-lambda/README.md +++ b/packages/@aws-cdk/aws-lambda/README.md @@ -326,6 +326,31 @@ new LayerVersion(this, 'MyLayer', { }); ``` +## Architecture + +Lambda functions, by default, run on compute systems that have the 64 bit x86 architecture. + +The AWS Lambda service also runs compute on the ARM architecture, which can reduce cost +for some workloads. + +A lambda function can be configured to be run on one of these platforms: + +```ts +new Function(this, 'MyFunction', { + ... + architecture: Architecture.ARM_64, +}); +``` + +Similarly, lambda layer versions can also be tagged with architectures it is compatible with. + +```ts +new LayerVersion(this, 'MyLayer', { + ... + compatibleArchitectures: [Architecture.X86_64, Architecture.ARM_64], +}); +``` + ## Lambda Insights Lambda functions can be configured to use CloudWatch [Lambda Insights](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Lambda-Insights.html) @@ -649,7 +674,7 @@ Language-specific higher level constructs are provided in separate modules: ## Code Signing -Code signing for AWS Lambda helps to ensure that only trusted code runs in your Lambda functions. +Code signing for AWS Lambda helps to ensure that only trusted code runs in your Lambda functions. When enabled, AWS Lambda checks every code deployment and verifies that the code package is signed by a trusted source. For more information, see [Configuring code signing for AWS Lambda](https://docs.aws.amazon.com/lambda/latest/dg/configuration-codesigning.html). The following code configures a function with code signing. diff --git a/packages/@aws-cdk/aws-lambda/jest.config.js b/packages/@aws-cdk/aws-lambda/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-lambda/jest.config.js +++ b/packages/@aws-cdk/aws-lambda/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-lambda/lib/architecture.ts b/packages/@aws-cdk/aws-lambda/lib/architecture.ts new file mode 100644 index 0000000000000..ae86624ca006b --- /dev/null +++ b/packages/@aws-cdk/aws-lambda/lib/architecture.ts @@ -0,0 +1,39 @@ +/** + * Architectures supported by AWS Lambda + */ +export class Architecture { + /** + * 64 bit architecture with x86 instruction set. + */ + public static readonly X86_64 = new Architecture('x86_64', 'linux/amd64'); + + /** + * 64 bit architecture with the ARM instruction set. + */ + public static readonly ARM_64 = new Architecture('arm64', 'linux/arm64'); + + /** + * Used to specify a custom architecture name. + * Use this if the architecture name is not yet supported by the CDK. + * @param name the architecture name as recognized by AWS Lambda. + * @param [dockerPlatform=linux/amd64] the platform to use for this architecture when building with Docker + */ + public static custom(name: string, dockerPlatform?: string) { + return new Architecture(name, dockerPlatform ?? 'linux/amd64'); + } + + /** + * The name of the architecture as recognized by the AWS Lambda service APIs. + */ + public readonly name: string; + + /** + * The platform to use for this architecture when building with Docker. + */ + public readonly dockerPlatform: string; + + private constructor(archName: string, dockerPlatform: string) { + this.name = archName; + this.dockerPlatform = dockerPlatform; + } +} diff --git a/packages/@aws-cdk/aws-lambda/lib/function-hash.ts b/packages/@aws-cdk/aws-lambda/lib/function-hash.ts index c651aee68cd4d..0b7eff434ba65 100644 --- a/packages/@aws-cdk/aws-lambda/lib/function-hash.ts +++ b/packages/@aws-cdk/aws-lambda/lib/function-hash.ts @@ -49,11 +49,13 @@ export function trimFromStart(s: string, maxLength: number) { * must not be generated. * * Adding a new property to this list - If the property is part of the UpdateFunctionConfiguration - * API, then it must be classified as true, otherwise false. - * See https://docs.aws.amazon.com/lambda/latest/dg/API_UpdateFunctionConfiguration.html + * API or UpdateFunctionCode API, then it must be classified as true, otherwise false. + * See https://docs.aws.amazon.com/lambda/latest/dg/API_UpdateFunctionConfiguration.html and + * https://docs.aws.amazon.com/lambda/latest/dg/API_UpdateFunctionConfiguration.html */ -const VERSION_LOCKED: { [key: string]: boolean } = { +export const VERSION_LOCKED: { [key: string]: boolean } = { // locked to the version + Architectures: true, Code: true, DeadLetterConfig: true, Description: true, diff --git a/packages/@aws-cdk/aws-lambda/lib/function.ts b/packages/@aws-cdk/aws-lambda/lib/function.ts index 9cd67a478f003..fffd20decd8d9 100644 --- a/packages/@aws-cdk/aws-lambda/lib/function.ts +++ b/packages/@aws-cdk/aws-lambda/lib/function.ts @@ -7,6 +7,7 @@ import * as logs from '@aws-cdk/aws-logs'; import * as sqs from '@aws-cdk/aws-sqs'; import { Annotations, CfnResource, Duration, Fn, Lazy, Names, Stack } from '@aws-cdk/core'; import { Construct } from 'constructs'; +import { Architecture } from './architecture'; import { Code, CodeConfig } from './code'; import { ICodeSigningConfig } from './code-signing-config'; import { EventInvokeConfigOptions } from './event-invoke-config'; @@ -219,6 +220,10 @@ export interface FunctionOptions extends EventInvokeConfigOptions { * Specify the version of CloudWatch Lambda insights to use for monitoring * @see https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Lambda-Insights.html * + * When used with `DockerImageFunction` or `DockerImageCode`, the Docker image should have + * the Lambda insights agent installed. + * @see https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Lambda-Insights-Getting-Started-docker.html + * * @default - No Lambda Insights */ readonly insightsVersion?: LambdaInsightsVersion; @@ -310,6 +315,19 @@ export interface FunctionOptions extends EventInvokeConfigOptions { * @default - Not Sign the Code */ readonly codeSigningConfig?: ICodeSigningConfig; + + /** + * DEPRECATED + * @default [Architecture.X86_64] + * @deprecated use `architecture` + */ + readonly architectures?: Architecture[]; + + /** + * The system architectures compatible with this lambda function. + * @default Architecture.X86_64 + */ + readonly architecture?: Architecture; } export interface FunctionProps extends FunctionOptions { @@ -648,6 +666,14 @@ export class Function extends FunctionBase { }]; } + if (props.architecture && props.architectures !== undefined) { + throw new Error('Either architecture or architectures must be specified but not both.'); + } + if (props.architectures && props.architectures.length > 1) { + throw new Error('Only one architecture must be specified.'); + } + const architecture = props.architecture ?? (props.architectures && props.architectures[0]); + const resource: CfnFunction = new CfnFunction(this, 'Resource', { functionName: this.physicalName, description: props.description, @@ -680,6 +706,7 @@ export class Function extends FunctionBase { kmsKeyArn: props.environmentEncryption?.keyArn, fileSystemConfigs, codeSigningConfigArn: props.codeSigningConfig?.codeSigningConfigArn, + architectures: architecture ? [architecture.name] : undefined, }); resource.node.addDependency(this.role); @@ -759,9 +786,7 @@ export class Function extends FunctionBase { } // Configure Lambda insights - if (props.insightsVersion !== undefined) { - this.configureLambdaInsights(props.insightsVersion); - } + this.configureLambdaInsights(props); } /** @@ -792,6 +817,11 @@ export class Function extends FunctionBase { const runtimes = layer.compatibleRuntimes.map(runtime => runtime.name).join(', '); throw new Error(`This lambda function uses a runtime that is incompatible with this layer (${this.runtime.name} is not in [${runtimes}])`); } + + // Currently no validations for compatible architectures since Lambda service + // allows layers configured with one architecture to be used with a Lambda function + // from another architecture. + this.layers.push(layer); } } @@ -884,8 +914,15 @@ Environment variables can be marked for removal when used in Lambda@Edge by sett * * https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Lambda-Insights-extension-versions.html */ - private configureLambdaInsights(insightsVersion: LambdaInsightsVersion): void { - this.addLayers(LayerVersion.fromLayerVersionArn(this, 'LambdaInsightsLayer', insightsVersion.layerVersionArn)); + private configureLambdaInsights(props: FunctionProps): void { + if (props.insightsVersion === undefined) { + return; + } + if (props.runtime !== Runtime.FROM_IMAGE) { + // Layers cannot be added to Lambda container images. The image should have the insights agent installed. + // See https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Lambda-Insights-Getting-Started-docker.html + this.addLayers(LayerVersion.fromLayerVersionArn(this, 'LambdaInsightsLayer', props.insightsVersion.layerVersionArn)); + } this.role?.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('CloudWatchLambdaInsightsExecutionRolePolicy')); } diff --git a/packages/@aws-cdk/aws-lambda/lib/index.ts b/packages/@aws-cdk/aws-lambda/lib/index.ts index 41c77bb8d038d..875e05e995631 100644 --- a/packages/@aws-cdk/aws-lambda/lib/index.ts +++ b/packages/@aws-cdk/aws-lambda/lib/index.ts @@ -19,6 +19,7 @@ export * from './scalable-attribute-api'; export * from './code-signing-config'; export * from './lambda-insights'; export * from './log-retention'; +export * from './architecture'; // AWS::Lambda CloudFormation Resources: export * from './lambda.generated'; diff --git a/packages/@aws-cdk/aws-lambda/lib/layers.ts b/packages/@aws-cdk/aws-lambda/lib/layers.ts index babf91079b8b6..7176badb0ee42 100644 --- a/packages/@aws-cdk/aws-lambda/lib/layers.ts +++ b/packages/@aws-cdk/aws-lambda/lib/layers.ts @@ -1,5 +1,6 @@ import { IResource, RemovalPolicy, Resource } from '@aws-cdk/core'; import { Construct } from 'constructs'; +import { Architecture } from './architecture'; import { Code } from './code'; import { CfnLayerVersion, CfnLayerVersionPermission } from './lambda.generated'; import { Runtime } from './runtime'; @@ -46,6 +47,12 @@ export interface LayerVersionProps extends LayerVersionOptions { */ readonly compatibleRuntimes?: Runtime[]; + /** + * The system architectures compatible with this layer. + * @default [Architecture.X86_64] + */ + readonly compatibleArchitectures?: Architecture[]; + /** * The content of this Layer. * @@ -196,6 +203,7 @@ export class LayerVersion extends LayerVersionBase { const resource: CfnLayerVersion = new CfnLayerVersion(this, 'Resource', { compatibleRuntimes: props.compatibleRuntimes && props.compatibleRuntimes.map(r => r.name), + compatibleArchitectures: props.compatibleArchitectures?.map(a => a.name), content: { s3Bucket: code.s3Location.bucketName, s3Key: code.s3Location.objectKey, diff --git a/packages/@aws-cdk/aws-lambda/package.json b/packages/@aws-cdk/aws-lambda/package.json index 7c2ece3a6bd33..f139f180e7420 100644 --- a/packages/@aws-cdk/aws-lambda/package.json +++ b/packages/@aws-cdk/aws-lambda/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::Lambda", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -77,16 +76,17 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/cfnspec": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/aws-lambda": "^8.10.84", "@types/jest": "^26.0.24", - "@types/aws-lambda": "^8.10.79", - "@types/lodash": "^4.14.171", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", + "@types/lodash": "^4.14.175", "jest": "^26.6.3", - "lodash": "^4.17.21", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "lodash": "^4.17.21" }, "dependencies": { "@aws-cdk/aws-applicationautoscaling": "0.0.0", diff --git a/packages/@aws-cdk/aws-lambda/test/code.test.ts b/packages/@aws-cdk/aws-lambda/test/code.test.ts index 49e87cf220ebe..194ebda9aff37 100644 --- a/packages/@aws-cdk/aws-lambda/test/code.test.ts +++ b/packages/@aws-cdk/aws-lambda/test/code.test.ts @@ -4,7 +4,7 @@ import { ABSENT, ResourcePart } from '@aws-cdk/assert-internal'; import * as ecr from '@aws-cdk/aws-ecr'; import * as cdk from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; -import { testFutureBehavior } from 'cdk-build-tools/lib/feature-flag'; +import { testFutureBehavior } from '@aws-cdk/cdk-build-tools/lib/feature-flag'; import * as lambda from '../lib'; /* eslint-disable dot-notation */ diff --git a/packages/@aws-cdk/aws-lambda/test/function-hash.test.ts b/packages/@aws-cdk/aws-lambda/test/function-hash.test.ts index b1b4ab5200ea4..dbadd01b0975b 100644 --- a/packages/@aws-cdk/aws-lambda/test/function-hash.test.ts +++ b/packages/@aws-cdk/aws-lambda/test/function-hash.test.ts @@ -1,9 +1,10 @@ import '@aws-cdk/assert-internal/jest'; import * as path from 'path'; +import { resourceSpecification } from '@aws-cdk/cfnspec'; import { App, CfnOutput, CfnResource, Stack } from '@aws-cdk/core'; import { LAMBDA_RECOGNIZE_VERSION_PROPS } from '@aws-cdk/cx-api'; import * as lambda from '../lib'; -import { calculateFunctionHash, trimFromStart } from '../lib/function-hash'; +import { calculateFunctionHash, trimFromStart, VERSION_LOCKED } from '../lib/function-hash'; describe('function hash', () => { describe('trimFromStart', () => { @@ -274,5 +275,13 @@ describe('function hash', () => { (fn1.node.defaultChild as CfnResource).addPropertyOverride('UnclassifiedProp', 'Value'); expect(calculateFunctionHash(fn1)).toEqual(original); }); + + test('all CFN properties are classified', () => { + const spec = resourceSpecification('AWS::Lambda::Function'); + expect(spec.Properties).toBeDefined(); + const expected = Object.keys(spec.Properties!).sort(); + const actual = Object.keys(VERSION_LOCKED).sort(); + expect(actual).toEqual(expected); + }); }); }); diff --git a/packages/@aws-cdk/aws-lambda/test/function.test.ts b/packages/@aws-cdk/aws-lambda/test/function.test.ts index b4f79aff6cc9e..66d18e663e7f9 100644 --- a/packages/@aws-cdk/aws-lambda/test/function.test.ts +++ b/packages/@aws-cdk/aws-lambda/test/function.test.ts @@ -2174,6 +2174,59 @@ describe('function', () => { })).toThrow(/Layers are not supported for container image functions/); }); + test('specified architectures is recognized', () => { + const stack = new cdk.Stack(); + new lambda.Function(stack, 'MyFunction', { + code: lambda.Code.fromInline('foo'), + runtime: lambda.Runtime.NODEJS_12_X, + handler: 'index.handler', + + architectures: [lambda.Architecture.ARM_64], + }); + + expect(stack).toHaveResource('AWS::Lambda::Function', { + Architectures: ['arm64'], + }); + }); + + test('specified architecture is recognized', () => { + const stack = new cdk.Stack(); + new lambda.Function(stack, 'MyFunction', { + code: lambda.Code.fromInline('foo'), + runtime: lambda.Runtime.NODEJS_12_X, + handler: 'index.handler', + + architecture: lambda.Architecture.ARM_64, + }); + + expect(stack).toHaveResource('AWS::Lambda::Function', { + Architectures: ['arm64'], + }); + }); + + test('both architectures and architecture are not recognized', () => { + const stack = new cdk.Stack(); + expect(() => new lambda.Function(stack, 'MyFunction', { + code: lambda.Code.fromInline('foo'), + runtime: lambda.Runtime.NODEJS_12_X, + handler: 'index.handler', + + architecture: lambda.Architecture.ARM_64, + architectures: [lambda.Architecture.X86_64], + })).toThrow(/architecture or architectures must be specified/); + }); + + test('Only one architecture allowed', () => { + const stack = new cdk.Stack(); + expect(() => new lambda.Function(stack, 'MyFunction', { + code: lambda.Code.fromInline('foo'), + runtime: lambda.Runtime.NODEJS_12_X, + handler: 'index.handler', + + architectures: [lambda.Architecture.X86_64, lambda.Architecture.ARM_64], + })).toThrow(/one architecture must be specified/); + }); + }); function newTestLambda(scope: constructs.Construct) { diff --git a/packages/@aws-cdk/aws-lambda/test/lambda-insights.test.ts b/packages/@aws-cdk/aws-lambda/test/lambda-insights.test.ts index 990c0c7fb7405..762df158da6f4 100644 --- a/packages/@aws-cdk/aws-lambda/test/lambda-insights.test.ts +++ b/packages/@aws-cdk/aws-lambda/test/lambda-insights.test.ts @@ -1,5 +1,6 @@ import '@aws-cdk/assert-internal/jest'; import { MatchStyle } from '@aws-cdk/assert-internal'; +import * as ecr from '@aws-cdk/aws-ecr'; import * as cdk from '@aws-cdk/core'; import * as lambda from '../lib'; @@ -313,4 +314,43 @@ describe('lambda-insights', () => { // On synthesis it should not throw an error expect(() => app.synth()).not.toThrow(); }); + + test('insights layer is skipped for container images and the role is updated', () => { + const stack = new cdk.Stack(); + new lambda.DockerImageFunction(stack, 'MyFunction', { + code: lambda.DockerImageCode.fromEcr(ecr.Repository.fromRepositoryArn(stack, 'MyRepo', + 'arn:aws:ecr:us-east-1:0123456789:repository/MyRepo')), + insightsVersion: lambda.LambdaInsightsVersion.VERSION_1_0_98_0, + }); + + expect(stack).toCountResources('AWS::Lambda::LayerVersion', 0); + + expect(stack).toHaveResourceLike('AWS::IAM::Role', { + 'AssumeRolePolicyDocument': { + 'Statement': [ + { + 'Action': 'sts:AssumeRole', + 'Principal': { + 'Service': 'lambda.amazonaws.com', + }, + }, + ], + }, + 'ManagedPolicyArns': [ + { }, + { + 'Fn::Join': [ + '', + [ + 'arn:', + { + 'Ref': 'AWS::Partition', + }, + ':iam::aws:policy/CloudWatchLambdaInsightsExecutionRolePolicy', + ], + ], + }, + ], + }); + }); }); diff --git a/packages/@aws-cdk/aws-lambda/test/layers.test.ts b/packages/@aws-cdk/aws-lambda/test/layers.test.ts index 3d8cc9d70de6f..1c416236c0980 100644 --- a/packages/@aws-cdk/aws-lambda/test/layers.test.ts +++ b/packages/@aws-cdk/aws-lambda/test/layers.test.ts @@ -103,4 +103,18 @@ describe('layers', () => { DeletionPolicy: 'Retain', }, ResourcePart.CompleteDefinition); }); + + test('specified compatible architectures is recognized', () => { + const stack = new cdk.Stack(); + const bucket = new s3.Bucket(stack, 'Bucket'); + const code = new lambda.S3Code(bucket, 'ObjectKey'); + new lambda.LayerVersion(stack, 'MyLayer', { + code, + compatibleArchitectures: [lambda.Architecture.ARM_64], + }); + + expect(stack).toHaveResource('AWS::Lambda::LayerVersion', { + CompatibleArchitectures: ['arm64'], + }); + }); }); diff --git a/packages/@aws-cdk/aws-licensemanager/.eslintrc.js b/packages/@aws-cdk/aws-licensemanager/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-licensemanager/.eslintrc.js +++ b/packages/@aws-cdk/aws-licensemanager/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-licensemanager/jest.config.js b/packages/@aws-cdk/aws-licensemanager/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-licensemanager/jest.config.js +++ b/packages/@aws-cdk/aws-licensemanager/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-licensemanager/package.json b/packages/@aws-cdk/aws-licensemanager/package.json index 0219ff3d93dc0..0e2ca75813a54 100644 --- a/packages/@aws-cdk/aws-licensemanager/package.json +++ b/packages/@aws-cdk/aws-licensemanager/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::LicenseManager", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/tools/cdk-release/.eslintrc.js b/packages/@aws-cdk/aws-lightsail/.eslintrc.js similarity index 56% rename from tools/cdk-release/.eslintrc.js rename to packages/@aws-cdk/aws-lightsail/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/tools/cdk-release/.eslintrc.js +++ b/packages/@aws-cdk/aws-lightsail/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-lightsail/.gitignore b/packages/@aws-cdk/aws-lightsail/.gitignore new file mode 100644 index 0000000000000..62ebc95d75ce6 --- /dev/null +++ b/packages/@aws-cdk/aws-lightsail/.gitignore @@ -0,0 +1,19 @@ +*.js +*.js.map +*.d.ts +tsconfig.json +node_modules +*.generated.ts +dist +.jsii + +.LAST_BUILD +.nyc_output +coverage +.nycrc +.LAST_PACKAGE +*.snk +nyc.config.js +!.eslintrc.js +!jest.config.js +junit.xml diff --git a/packages/@aws-cdk/aws-lightsail/.npmignore b/packages/@aws-cdk/aws-lightsail/.npmignore new file mode 100644 index 0000000000000..f931fede67c44 --- /dev/null +++ b/packages/@aws-cdk/aws-lightsail/.npmignore @@ -0,0 +1,29 @@ +# Don't include original .ts files when doing `npm pack` +*.ts +!*.d.ts +coverage +.nyc_output +*.tgz + +dist +.LAST_PACKAGE +.LAST_BUILD +!*.js + +# Include .jsii +!.jsii + +*.snk + +*.tsbuildinfo + +tsconfig.json + +.eslintrc.js +jest.config.js + +# exclude cdk artifacts +**/cdk.out +junit.xml +test/ +!*.lit.ts diff --git a/tools/cdk-release/LICENSE b/packages/@aws-cdk/aws-lightsail/LICENSE similarity index 100% rename from tools/cdk-release/LICENSE rename to packages/@aws-cdk/aws-lightsail/LICENSE diff --git a/tools/cdk-release/NOTICE b/packages/@aws-cdk/aws-lightsail/NOTICE similarity index 100% rename from tools/cdk-release/NOTICE rename to packages/@aws-cdk/aws-lightsail/NOTICE diff --git a/packages/@aws-cdk/aws-lightsail/README.md b/packages/@aws-cdk/aws-lightsail/README.md new file mode 100644 index 0000000000000..09d952a84e6c7 --- /dev/null +++ b/packages/@aws-cdk/aws-lightsail/README.md @@ -0,0 +1,20 @@ +# AWS::Lightsail Construct Library + + +--- + +![cfn-resources: Stable](https://img.shields.io/badge/cfn--resources-stable-success.svg?style=for-the-badge) + +> All classes with the `Cfn` prefix in this module ([CFN Resources]) are always stable and safe to use. +> +> [CFN Resources]: https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib + +--- + + + +This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. + +```ts +import lightsail = require('@aws-cdk/aws-lightsail'); +``` diff --git a/packages/@aws-cdk/aws-lightsail/jest.config.js b/packages/@aws-cdk/aws-lightsail/jest.config.js new file mode 100644 index 0000000000000..3a2fd93a1228a --- /dev/null +++ b/packages/@aws-cdk/aws-lightsail/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-lightsail/lib/index.ts b/packages/@aws-cdk/aws-lightsail/lib/index.ts new file mode 100644 index 0000000000000..f7da3b26e282a --- /dev/null +++ b/packages/@aws-cdk/aws-lightsail/lib/index.ts @@ -0,0 +1,2 @@ +// AWS::Lightsail CloudFormation Resources: +export * from './lightsail.generated'; diff --git a/packages/@aws-cdk/aws-lightsail/package.json b/packages/@aws-cdk/aws-lightsail/package.json new file mode 100644 index 0000000000000..4af08f90eb479 --- /dev/null +++ b/packages/@aws-cdk/aws-lightsail/package.json @@ -0,0 +1,103 @@ +{ + "name": "@aws-cdk/aws-lightsail", + "version": "0.0.0", + "description": "The CDK Construct Library for AWS::Lightsail", + "main": "lib/index.js", + "types": "lib/index.d.ts", + "jsii": { + "outdir": "dist", + "projectReferences": true, + "targets": { + "dotnet": { + "namespace": "Amazon.CDK.AWS.Lightsail", + "packageId": "Amazon.CDK.AWS.Lightsail", + "signAssembly": true, + "assemblyOriginatorKeyFile": "../../key.snk", + "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png" + }, + "java": { + "package": "software.amazon.awscdk.services.lightsail", + "maven": { + "groupId": "software.amazon.awscdk", + "artifactId": "lightsail" + } + }, + "python": { + "classifiers": [ + "Framework :: AWS CDK", + "Framework :: AWS CDK :: 1" + ], + "distName": "aws-cdk.aws-lightsail", + "module": "aws_cdk.aws_lightsail" + } + } + }, + "repository": { + "type": "git", + "url": "https://github.com/aws/aws-cdk.git", + "directory": "packages/@aws-cdk/aws-lightsail" + }, + "homepage": "https://github.com/aws/aws-cdk", + "scripts": { + "build": "cdk-build", + "watch": "cdk-watch", + "lint": "cdk-lint", + "test": "cdk-test", + "integ": "cdk-integ", + "pkglint": "pkglint -f", + "package": "cdk-package", + "awslint": "cdk-awslint", + "cfn2ts": "cfn2ts", + "build+test": "yarn build && yarn test", + "build+test+package": "yarn build+test && yarn package", + "compat": "cdk-compat", + "gen": "cfn2ts", + "rosetta:extract": "yarn --silent jsii-rosetta extract", + "build+extract": "yarn build && yarn rosetta:extract", + "build+test+extract": "yarn build+test && yarn rosetta:extract" + }, + "cdk-build": { + "cloudformation": "AWS::Lightsail", + "jest": true, + "env": { + "AWSLINT_BASE_CONSTRUCT": "true" + } + }, + "keywords": [ + "aws", + "cdk", + "constructs", + "AWS::Lightsail", + "aws-lightsail" + ], + "author": { + "name": "Amazon Web Services", + "url": "https://aws.amazon.com", + "organization": true + }, + "license": "Apache-2.0", + "devDependencies": { + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" + }, + "dependencies": { + "@aws-cdk/core": "0.0.0" + }, + "peerDependencies": { + "@aws-cdk/core": "0.0.0" + }, + "engines": { + "node": ">= 10.13.0 <13 || >=13.7.0" + }, + "stability": "experimental", + "maturity": "cfn-only", + "awscdkio": { + "announce": false + }, + "publishConfig": { + "tag": "latest" + } +} diff --git a/packages/@aws-cdk/aws-lightsail/test/lightsail.test.ts b/packages/@aws-cdk/aws-lightsail/test/lightsail.test.ts new file mode 100644 index 0000000000000..465c7bdea0693 --- /dev/null +++ b/packages/@aws-cdk/aws-lightsail/test/lightsail.test.ts @@ -0,0 +1,6 @@ +import '@aws-cdk/assertions'; +import {} from '../lib'; + +test('No tests are specified for this package', () => { + expect(true).toBe(true); +}); diff --git a/packages/@aws-cdk/aws-location/.eslintrc.js b/packages/@aws-cdk/aws-location/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-location/.eslintrc.js +++ b/packages/@aws-cdk/aws-location/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-location/jest.config.js b/packages/@aws-cdk/aws-location/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-location/jest.config.js +++ b/packages/@aws-cdk/aws-location/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-location/package.json b/packages/@aws-cdk/aws-location/package.json index 5a9473d0d22dd..745400558765a 100644 --- a/packages/@aws-cdk/aws-location/package.json +++ b/packages/@aws-cdk/aws-location/package.json @@ -58,7 +58,6 @@ }, "cdk-build": { "cloudformation": "AWS::Location", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -77,11 +76,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", "@aws-cdk/assertions": "0.0.0", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-logs-destinations/.eslintrc.js b/packages/@aws-cdk/aws-logs-destinations/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-logs-destinations/.eslintrc.js +++ b/packages/@aws-cdk/aws-logs-destinations/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-logs-destinations/jest.config.js b/packages/@aws-cdk/aws-logs-destinations/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-logs-destinations/jest.config.js +++ b/packages/@aws-cdk/aws-logs-destinations/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-logs-destinations/package.json b/packages/@aws-cdk/aws-logs-destinations/package.json index 5d13936533fcc..13f8f5c567006 100644 --- a/packages/@aws-cdk/aws-logs-destinations/package.json +++ b/packages/@aws-cdk/aws-logs-destinations/package.json @@ -64,13 +64,13 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-iam": "0.0.0", @@ -98,7 +98,6 @@ }, "maturity": "stable", "cdk-build": { - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } diff --git a/packages/@aws-cdk/aws-logs/.eslintrc.js b/packages/@aws-cdk/aws-logs/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-logs/.eslintrc.js +++ b/packages/@aws-cdk/aws-logs/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-logs/jest.config.js b/packages/@aws-cdk/aws-logs/jest.config.js index d737012e12863..6adf60b166cac 100644 --- a/packages/@aws-cdk/aws-logs/jest.config.js +++ b/packages/@aws-cdk/aws-logs/jest.config.js @@ -1,4 +1,4 @@ -const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +const baseConfig = require('../../../tools/@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = { ...baseConfig, coverageThreshold: { diff --git a/packages/@aws-cdk/aws-logs/package.json b/packages/@aws-cdk/aws-logs/package.json index eb68f23c4e252..a21e787888c1c 100644 --- a/packages/@aws-cdk/aws-logs/package.json +++ b/packages/@aws-cdk/aws-logs/package.json @@ -57,8 +57,7 @@ "cloudformation": "AWS::Logs", "env": { "AWSLINT_BASE_CONSTRUCT": true - }, - "jest": true + } }, "keywords": [ "aws", @@ -73,19 +72,19 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/aws-lambda": "^8.10.84", "@types/jest": "^26.0.24", - "@types/aws-lambda": "^8.10.79", "@types/sinon": "^9.0.11", "aws-sdk": "^2.848.0", - "aws-sdk-mock": "^5.2.1", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "nock": "^13.1.1", + "aws-sdk-mock": "^5.4.0", "jest": "^26.6.3", - "pkglint": "0.0.0", - "sinon": "^9.2.4", - "@aws-cdk/assert-internal": "0.0.0" + "nock": "^13.1.3", + "sinon": "^9.2.4" }, "dependencies": { "@aws-cdk/aws-cloudwatch": "0.0.0", diff --git a/packages/@aws-cdk/aws-lookoutequipment/.eslintrc.js b/packages/@aws-cdk/aws-lookoutequipment/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-lookoutequipment/.eslintrc.js +++ b/packages/@aws-cdk/aws-lookoutequipment/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-lookoutequipment/jest.config.js b/packages/@aws-cdk/aws-lookoutequipment/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-lookoutequipment/jest.config.js +++ b/packages/@aws-cdk/aws-lookoutequipment/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-lookoutequipment/package.json b/packages/@aws-cdk/aws-lookoutequipment/package.json index 3d3d93d1a9bb4..583212fe12b16 100644 --- a/packages/@aws-cdk/aws-lookoutequipment/package.json +++ b/packages/@aws-cdk/aws-lookoutequipment/package.json @@ -58,7 +58,6 @@ }, "cdk-build": { "cloudformation": "AWS::LookoutEquipment", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -77,11 +76,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", "@aws-cdk/assertions": "0.0.0", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-lookoutmetrics/.eslintrc.js b/packages/@aws-cdk/aws-lookoutmetrics/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-lookoutmetrics/.eslintrc.js +++ b/packages/@aws-cdk/aws-lookoutmetrics/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-lookoutmetrics/jest.config.js b/packages/@aws-cdk/aws-lookoutmetrics/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-lookoutmetrics/jest.config.js +++ b/packages/@aws-cdk/aws-lookoutmetrics/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-lookoutmetrics/package.json b/packages/@aws-cdk/aws-lookoutmetrics/package.json index f79a8e599ed12..b1da867ff825e 100644 --- a/packages/@aws-cdk/aws-lookoutmetrics/package.json +++ b/packages/@aws-cdk/aws-lookoutmetrics/package.json @@ -58,7 +58,6 @@ }, "cdk-build": { "cloudformation": "AWS::LookoutMetrics", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -77,11 +76,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", "@aws-cdk/assertions": "0.0.0", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-lookoutvision/.eslintrc.js b/packages/@aws-cdk/aws-lookoutvision/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-lookoutvision/.eslintrc.js +++ b/packages/@aws-cdk/aws-lookoutvision/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-lookoutvision/jest.config.js b/packages/@aws-cdk/aws-lookoutvision/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-lookoutvision/jest.config.js +++ b/packages/@aws-cdk/aws-lookoutvision/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-lookoutvision/package.json b/packages/@aws-cdk/aws-lookoutvision/package.json index 33ede00a2af8c..41f2c0c5d20c0 100644 --- a/packages/@aws-cdk/aws-lookoutvision/package.json +++ b/packages/@aws-cdk/aws-lookoutvision/package.json @@ -58,7 +58,6 @@ }, "cdk-build": { "cloudformation": "AWS::LookoutVision", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -77,11 +76,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-macie/.eslintrc.js b/packages/@aws-cdk/aws-macie/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-macie/.eslintrc.js +++ b/packages/@aws-cdk/aws-macie/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-macie/jest.config.js b/packages/@aws-cdk/aws-macie/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-macie/jest.config.js +++ b/packages/@aws-cdk/aws-macie/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-macie/package.json b/packages/@aws-cdk/aws-macie/package.json index cd1d450bd73b6..bf3b4f9104a59 100644 --- a/packages/@aws-cdk/aws-macie/package.json +++ b/packages/@aws-cdk/aws-macie/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::Macie", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-managedblockchain/.eslintrc.js b/packages/@aws-cdk/aws-managedblockchain/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-managedblockchain/.eslintrc.js +++ b/packages/@aws-cdk/aws-managedblockchain/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-managedblockchain/jest.config.js b/packages/@aws-cdk/aws-managedblockchain/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-managedblockchain/jest.config.js +++ b/packages/@aws-cdk/aws-managedblockchain/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-managedblockchain/package.json b/packages/@aws-cdk/aws-managedblockchain/package.json index 09d5ad7a954ea..3994b29d5fa75 100644 --- a/packages/@aws-cdk/aws-managedblockchain/package.json +++ b/packages/@aws-cdk/aws-managedblockchain/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::ManagedBlockchain", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-mediaconnect/.eslintrc.js b/packages/@aws-cdk/aws-mediaconnect/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-mediaconnect/.eslintrc.js +++ b/packages/@aws-cdk/aws-mediaconnect/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-mediaconnect/jest.config.js b/packages/@aws-cdk/aws-mediaconnect/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-mediaconnect/jest.config.js +++ b/packages/@aws-cdk/aws-mediaconnect/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-mediaconnect/package.json b/packages/@aws-cdk/aws-mediaconnect/package.json index d0f29ba806f03..c329c2d368efc 100644 --- a/packages/@aws-cdk/aws-mediaconnect/package.json +++ b/packages/@aws-cdk/aws-mediaconnect/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::MediaConnect", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-mediaconvert/.eslintrc.js b/packages/@aws-cdk/aws-mediaconvert/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-mediaconvert/.eslintrc.js +++ b/packages/@aws-cdk/aws-mediaconvert/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-mediaconvert/jest.config.js b/packages/@aws-cdk/aws-mediaconvert/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-mediaconvert/jest.config.js +++ b/packages/@aws-cdk/aws-mediaconvert/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-mediaconvert/package.json b/packages/@aws-cdk/aws-mediaconvert/package.json index 725541270f71b..172cd0658252e 100644 --- a/packages/@aws-cdk/aws-mediaconvert/package.json +++ b/packages/@aws-cdk/aws-mediaconvert/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::MediaConvert", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-medialive/.eslintrc.js b/packages/@aws-cdk/aws-medialive/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-medialive/.eslintrc.js +++ b/packages/@aws-cdk/aws-medialive/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-medialive/jest.config.js b/packages/@aws-cdk/aws-medialive/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-medialive/jest.config.js +++ b/packages/@aws-cdk/aws-medialive/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-medialive/package.json b/packages/@aws-cdk/aws-medialive/package.json index dd9f764f06d1b..cdf5f7caac8fe 100644 --- a/packages/@aws-cdk/aws-medialive/package.json +++ b/packages/@aws-cdk/aws-medialive/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::MediaLive", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-mediapackage/.eslintrc.js b/packages/@aws-cdk/aws-mediapackage/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-mediapackage/.eslintrc.js +++ b/packages/@aws-cdk/aws-mediapackage/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-mediapackage/jest.config.js b/packages/@aws-cdk/aws-mediapackage/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-mediapackage/jest.config.js +++ b/packages/@aws-cdk/aws-mediapackage/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-mediapackage/package.json b/packages/@aws-cdk/aws-mediapackage/package.json index 9910b1dc2f864..817eafaaea6da 100644 --- a/packages/@aws-cdk/aws-mediapackage/package.json +++ b/packages/@aws-cdk/aws-mediapackage/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::MediaPackage", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-mediastore/.eslintrc.js b/packages/@aws-cdk/aws-mediastore/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-mediastore/.eslintrc.js +++ b/packages/@aws-cdk/aws-mediastore/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-mediastore/jest.config.js b/packages/@aws-cdk/aws-mediastore/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-mediastore/jest.config.js +++ b/packages/@aws-cdk/aws-mediastore/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-mediastore/package.json b/packages/@aws-cdk/aws-mediastore/package.json index 5a5ec1ff16709..34e48b7593020 100644 --- a/packages/@aws-cdk/aws-mediastore/package.json +++ b/packages/@aws-cdk/aws-mediastore/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::MediaStore", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/tools/pkgtools/.eslintrc.js b/packages/@aws-cdk/aws-memorydb/.eslintrc.js similarity index 56% rename from tools/pkgtools/.eslintrc.js rename to packages/@aws-cdk/aws-memorydb/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/tools/pkgtools/.eslintrc.js +++ b/packages/@aws-cdk/aws-memorydb/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-memorydb/.gitignore b/packages/@aws-cdk/aws-memorydb/.gitignore new file mode 100644 index 0000000000000..62ebc95d75ce6 --- /dev/null +++ b/packages/@aws-cdk/aws-memorydb/.gitignore @@ -0,0 +1,19 @@ +*.js +*.js.map +*.d.ts +tsconfig.json +node_modules +*.generated.ts +dist +.jsii + +.LAST_BUILD +.nyc_output +coverage +.nycrc +.LAST_PACKAGE +*.snk +nyc.config.js +!.eslintrc.js +!jest.config.js +junit.xml diff --git a/packages/@aws-cdk/aws-memorydb/.npmignore b/packages/@aws-cdk/aws-memorydb/.npmignore new file mode 100644 index 0000000000000..f931fede67c44 --- /dev/null +++ b/packages/@aws-cdk/aws-memorydb/.npmignore @@ -0,0 +1,29 @@ +# Don't include original .ts files when doing `npm pack` +*.ts +!*.d.ts +coverage +.nyc_output +*.tgz + +dist +.LAST_PACKAGE +.LAST_BUILD +!*.js + +# Include .jsii +!.jsii + +*.snk + +*.tsbuildinfo + +tsconfig.json + +.eslintrc.js +jest.config.js + +# exclude cdk artifacts +**/cdk.out +junit.xml +test/ +!*.lit.ts diff --git a/tools/cfn2ts/LICENSE b/packages/@aws-cdk/aws-memorydb/LICENSE similarity index 100% rename from tools/cfn2ts/LICENSE rename to packages/@aws-cdk/aws-memorydb/LICENSE diff --git a/tools/cfn2ts/NOTICE b/packages/@aws-cdk/aws-memorydb/NOTICE similarity index 100% rename from tools/cfn2ts/NOTICE rename to packages/@aws-cdk/aws-memorydb/NOTICE diff --git a/packages/@aws-cdk/aws-memorydb/README.md b/packages/@aws-cdk/aws-memorydb/README.md new file mode 100644 index 0000000000000..e2b1d4faa518a --- /dev/null +++ b/packages/@aws-cdk/aws-memorydb/README.md @@ -0,0 +1,20 @@ +# AWS::MemoryDB Construct Library + + +--- + +![cfn-resources: Stable](https://img.shields.io/badge/cfn--resources-stable-success.svg?style=for-the-badge) + +> All classes with the `Cfn` prefix in this module ([CFN Resources]) are always stable and safe to use. +> +> [CFN Resources]: https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib + +--- + + + +This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. + +```ts +import memorydb = require('@aws-cdk/aws-memorydb'); +``` diff --git a/packages/@aws-cdk/aws-memorydb/jest.config.js b/packages/@aws-cdk/aws-memorydb/jest.config.js new file mode 100644 index 0000000000000..3a2fd93a1228a --- /dev/null +++ b/packages/@aws-cdk/aws-memorydb/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-memorydb/lib/index.ts b/packages/@aws-cdk/aws-memorydb/lib/index.ts new file mode 100644 index 0000000000000..99e822affff5c --- /dev/null +++ b/packages/@aws-cdk/aws-memorydb/lib/index.ts @@ -0,0 +1,2 @@ +// AWS::MemoryDB CloudFormation Resources: +export * from './memorydb.generated'; diff --git a/packages/@aws-cdk/aws-memorydb/package.json b/packages/@aws-cdk/aws-memorydb/package.json new file mode 100644 index 0000000000000..4ecfac53a2db6 --- /dev/null +++ b/packages/@aws-cdk/aws-memorydb/package.json @@ -0,0 +1,103 @@ +{ + "name": "@aws-cdk/aws-memorydb", + "version": "0.0.0", + "description": "The CDK Construct Library for AWS::MemoryDB", + "main": "lib/index.js", + "types": "lib/index.d.ts", + "jsii": { + "outdir": "dist", + "projectReferences": true, + "targets": { + "dotnet": { + "namespace": "Amazon.CDK.AWS.MemoryDB", + "packageId": "Amazon.CDK.AWS.MemoryDB", + "signAssembly": true, + "assemblyOriginatorKeyFile": "../../key.snk", + "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png" + }, + "java": { + "package": "software.amazon.awscdk.services.memorydb", + "maven": { + "groupId": "software.amazon.awscdk", + "artifactId": "memorydb" + } + }, + "python": { + "classifiers": [ + "Framework :: AWS CDK", + "Framework :: AWS CDK :: 1" + ], + "distName": "aws-cdk.aws-memorydb", + "module": "aws_cdk.aws_memorydb" + } + } + }, + "repository": { + "type": "git", + "url": "https://github.com/aws/aws-cdk.git", + "directory": "packages/@aws-cdk/aws-memorydb" + }, + "homepage": "https://github.com/aws/aws-cdk", + "scripts": { + "build": "cdk-build", + "watch": "cdk-watch", + "lint": "cdk-lint", + "test": "cdk-test", + "integ": "cdk-integ", + "pkglint": "pkglint -f", + "package": "cdk-package", + "awslint": "cdk-awslint", + "cfn2ts": "cfn2ts", + "build+test": "yarn build && yarn test", + "build+test+package": "yarn build+test && yarn package", + "compat": "cdk-compat", + "gen": "cfn2ts", + "rosetta:extract": "yarn --silent jsii-rosetta extract", + "build+extract": "yarn build && yarn rosetta:extract", + "build+test+extract": "yarn build+test && yarn rosetta:extract" + }, + "cdk-build": { + "cloudformation": "AWS::MemoryDB", + "jest": true, + "env": { + "AWSLINT_BASE_CONSTRUCT": "true" + } + }, + "keywords": [ + "aws", + "cdk", + "constructs", + "AWS::MemoryDB", + "aws-memorydb" + ], + "author": { + "name": "Amazon Web Services", + "url": "https://aws.amazon.com", + "organization": true + }, + "license": "Apache-2.0", + "devDependencies": { + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" + }, + "dependencies": { + "@aws-cdk/core": "0.0.0" + }, + "peerDependencies": { + "@aws-cdk/core": "0.0.0" + }, + "engines": { + "node": ">= 10.13.0 <13 || >=13.7.0" + }, + "stability": "experimental", + "maturity": "cfn-only", + "awscdkio": { + "announce": false + }, + "publishConfig": { + "tag": "latest" + } +} diff --git a/packages/@aws-cdk/aws-memorydb/test/memorydb.test.ts b/packages/@aws-cdk/aws-memorydb/test/memorydb.test.ts new file mode 100644 index 0000000000000..465c7bdea0693 --- /dev/null +++ b/packages/@aws-cdk/aws-memorydb/test/memorydb.test.ts @@ -0,0 +1,6 @@ +import '@aws-cdk/assertions'; +import {} from '../lib'; + +test('No tests are specified for this package', () => { + expect(true).toBe(true); +}); diff --git a/packages/@aws-cdk/aws-msk/.eslintrc.js b/packages/@aws-cdk/aws-msk/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-msk/.eslintrc.js +++ b/packages/@aws-cdk/aws-msk/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-msk/README.md b/packages/@aws-cdk/aws-msk/README.md index ce86c6a477c45..664ec4f66c973 100644 --- a/packages/@aws-cdk/aws-msk/README.md +++ b/packages/@aws-cdk/aws-msk/README.md @@ -29,7 +29,7 @@ The following example creates an MSK Cluster. import * as msk from '@aws-cdk/aws-msk'; const cluster = new Cluster(this, 'Cluster', { - kafkaVersion: msk.KafkaVersion.V2_6_1, + kafkaVersion: msk.KafkaVersion.V2_8_1, vpc, }); ``` diff --git a/packages/@aws-cdk/aws-msk/jest.config.js b/packages/@aws-cdk/aws-msk/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-msk/jest.config.js +++ b/packages/@aws-cdk/aws-msk/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-msk/lib/cluster-version.ts b/packages/@aws-cdk/aws-msk/lib/cluster-version.ts index 0d3b511aae59e..b04c154b76054 100644 --- a/packages/@aws-cdk/aws-msk/lib/cluster-version.ts +++ b/packages/@aws-cdk/aws-msk/lib/cluster-version.ts @@ -47,6 +47,11 @@ export class KafkaVersion { */ public static readonly V2_8_0 = KafkaVersion.of('2.8.0'); + /** + * Kafka version 2.8.1 + */ + public static readonly V2_8_1 = KafkaVersion.of('2.8.1'); + /** * Custom cluster version * @param version custom version number diff --git a/packages/@aws-cdk/aws-msk/lib/cluster.ts b/packages/@aws-cdk/aws-msk/lib/cluster.ts index 6123f6896138c..8dfdae4561004 100644 --- a/packages/@aws-cdk/aws-msk/lib/cluster.ts +++ b/packages/@aws-cdk/aws-msk/lib/cluster.ts @@ -9,7 +9,8 @@ import * as core from '@aws-cdk/core'; import * as cr from '@aws-cdk/custom-resources'; import * as constructs from 'constructs'; import { addressOf } from 'constructs/lib/private/uniqueid'; -import { CfnCluster, KafkaVersion } from './'; +import { KafkaVersion } from './'; +import { CfnCluster } from './msk.generated'; /** * Represents a MSK Cluster @@ -539,7 +540,7 @@ export class Cluster extends ClusterBase { new iam.PolicyStatement({ sid: 'Allow access through AWS Secrets Manager for all principals in the account that are authorized to use AWS Secrets Manager', - principals: [new iam.Anyone()], + principals: [new iam.AnyPrincipal()], actions: [ 'kms:Encrypt', 'kms:Decrypt', diff --git a/packages/@aws-cdk/aws-msk/package.json b/packages/@aws-cdk/aws-msk/package.json index dd1523cffaf01..7c5d79482230f 100644 --- a/packages/@aws-cdk/aws-msk/package.json +++ b/packages/@aws-cdk/aws-msk/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::MSK", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -76,34 +75,34 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "cdk-integ-tools": "0.0.0", - "pkglint": "0.0.0", "jest": "^26.6.3" }, "dependencies": { - "@aws-cdk/core": "0.0.0", "@aws-cdk/aws-acmpca": "0.0.0", + "@aws-cdk/aws-ec2": "0.0.0", + "@aws-cdk/aws-iam": "0.0.0", + "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", - "@aws-cdk/aws-kms": "0.0.0", - "@aws-cdk/aws-iam": "0.0.0", - "@aws-cdk/aws-ec2": "0.0.0", - "@aws-cdk/custom-resources": "0.0.0", "@aws-cdk/aws-secretsmanager": "0.0.0", + "@aws-cdk/core": "0.0.0", + "@aws-cdk/custom-resources": "0.0.0", "constructs": "^3.3.69" }, "peerDependencies": { - "@aws-cdk/core": "0.0.0", "@aws-cdk/aws-acmpca": "0.0.0", + "@aws-cdk/aws-ec2": "0.0.0", + "@aws-cdk/aws-iam": "0.0.0", + "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", - "@aws-cdk/aws-kms": "0.0.0", - "@aws-cdk/aws-iam": "0.0.0", - "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/aws-secretsmanager": "0.0.0", + "@aws-cdk/core": "0.0.0", "@aws-cdk/custom-resources": "0.0.0", "constructs": "^3.3.69" }, diff --git a/packages/@aws-cdk/aws-msk/test/integ.cluster.expected.json b/packages/@aws-cdk/aws-msk/test/integ.cluster.expected.json index 9a0d0db6e2325..2b523706bd3e2 100644 --- a/packages/@aws-cdk/aws-msk/test/integ.cluster.expected.json +++ b/packages/@aws-cdk/aws-msk/test/integ.cluster.expected.json @@ -95,15 +95,15 @@ "VPCPublicSubnet1NATGatewayE0556630": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + }, "AllocationId": { "Fn::GetAtt": [ "VPCPublicSubnet1EIP6AD938E8", "AllocationId" ] }, - "SubnetId": { - "Ref": "VPCPublicSubnet1SubnetB4246D30" - }, "Tags": [ { "Key": "Name", @@ -192,15 +192,15 @@ "VPCPublicSubnet2NATGateway3C070193": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VPCPublicSubnet2Subnet74179F39" + }, "AllocationId": { "Fn::GetAtt": [ "VPCPublicSubnet2EIP4947BC00", "AllocationId" ] }, - "SubnetId": { - "Ref": "VPCPublicSubnet2Subnet74179F39" - }, "Tags": [ { "Key": "Name", @@ -399,7 +399,7 @@ } }, "ClusterName": "integ-test", - "KafkaVersion": "2.6.1", + "KafkaVersion": "2.8.1", "NumberOfBrokerNodes": 2, "EncryptionInfo": { "EncryptionInTransit": { @@ -524,7 +524,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters5c61041c12314e1ad8e67a0107fa3733382a206a78cdc1576fffa7e93caca5b4S3BucketB17E5ABD" + "Ref": "AssetParameters1c4eb88f5a8270f387281dcff6e3493840634113c4d57044f4aff74e3ef94c2dS3Bucket4C71F166" }, "S3Key": { "Fn::Join": [ @@ -537,7 +537,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters5c61041c12314e1ad8e67a0107fa3733382a206a78cdc1576fffa7e93caca5b4S3VersionKey77778F6A" + "Ref": "AssetParameters1c4eb88f5a8270f387281dcff6e3493840634113c4d57044f4aff74e3ef94c2dS3VersionKey0124EFC4" } ] } @@ -550,7 +550,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters5c61041c12314e1ad8e67a0107fa3733382a206a78cdc1576fffa7e93caca5b4S3VersionKey77778F6A" + "Ref": "AssetParameters1c4eb88f5a8270f387281dcff6e3493840634113c4d57044f4aff74e3ef94c2dS3VersionKey0124EFC4" } ] } @@ -576,17 +576,17 @@ } }, "Parameters": { - "AssetParameters5c61041c12314e1ad8e67a0107fa3733382a206a78cdc1576fffa7e93caca5b4S3BucketB17E5ABD": { + "AssetParameters1c4eb88f5a8270f387281dcff6e3493840634113c4d57044f4aff74e3ef94c2dS3Bucket4C71F166": { "Type": "String", - "Description": "S3 bucket for asset \"5c61041c12314e1ad8e67a0107fa3733382a206a78cdc1576fffa7e93caca5b4\"" + "Description": "S3 bucket for asset \"1c4eb88f5a8270f387281dcff6e3493840634113c4d57044f4aff74e3ef94c2d\"" }, - "AssetParameters5c61041c12314e1ad8e67a0107fa3733382a206a78cdc1576fffa7e93caca5b4S3VersionKey77778F6A": { + "AssetParameters1c4eb88f5a8270f387281dcff6e3493840634113c4d57044f4aff74e3ef94c2dS3VersionKey0124EFC4": { "Type": "String", - "Description": "S3 key for asset version \"5c61041c12314e1ad8e67a0107fa3733382a206a78cdc1576fffa7e93caca5b4\"" + "Description": "S3 key for asset version \"1c4eb88f5a8270f387281dcff6e3493840634113c4d57044f4aff74e3ef94c2d\"" }, - "AssetParameters5c61041c12314e1ad8e67a0107fa3733382a206a78cdc1576fffa7e93caca5b4ArtifactHash580E429C": { + "AssetParameters1c4eb88f5a8270f387281dcff6e3493840634113c4d57044f4aff74e3ef94c2dArtifactHash6350D824": { "Type": "String", - "Description": "Artifact hash for asset \"5c61041c12314e1ad8e67a0107fa3733382a206a78cdc1576fffa7e93caca5b4\"" + "Description": "Artifact hash for asset \"1c4eb88f5a8270f387281dcff6e3493840634113c4d57044f4aff74e3ef94c2d\"" } }, "Outputs": { diff --git a/packages/@aws-cdk/aws-msk/test/integ.cluster.ts b/packages/@aws-cdk/aws-msk/test/integ.cluster.ts index c05fa496d7210..06ad0893d20d7 100644 --- a/packages/@aws-cdk/aws-msk/test/integ.cluster.ts +++ b/packages/@aws-cdk/aws-msk/test/integ.cluster.ts @@ -10,7 +10,7 @@ const vpc = new ec2.Vpc(stack, 'VPC', { maxAzs: 2 }); const cluster = new msk.Cluster(stack, 'Cluster', { clusterName: 'integ-test', - kafkaVersion: msk.KafkaVersion.V2_6_1, + kafkaVersion: msk.KafkaVersion.V2_8_1, vpc, removalPolicy: cdk.RemovalPolicy.DESTROY, }); diff --git a/packages/@aws-cdk/aws-mwaa/.eslintrc.js b/packages/@aws-cdk/aws-mwaa/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-mwaa/.eslintrc.js +++ b/packages/@aws-cdk/aws-mwaa/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-mwaa/jest.config.js b/packages/@aws-cdk/aws-mwaa/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-mwaa/jest.config.js +++ b/packages/@aws-cdk/aws-mwaa/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-mwaa/package.json b/packages/@aws-cdk/aws-mwaa/package.json index 0a784d8121200..e7c300df1afa8 100644 --- a/packages/@aws-cdk/aws-mwaa/package.json +++ b/packages/@aws-cdk/aws-mwaa/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::MWAA", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-neptune/.eslintrc.js b/packages/@aws-cdk/aws-neptune/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-neptune/.eslintrc.js +++ b/packages/@aws-cdk/aws-neptune/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-neptune/jest.config.js b/packages/@aws-cdk/aws-neptune/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-neptune/jest.config.js +++ b/packages/@aws-cdk/aws-neptune/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-neptune/package.json b/packages/@aws-cdk/aws-neptune/package.json index b3a429fb6642a..fd8bf57f76a8e 100644 --- a/packages/@aws-cdk/aws-neptune/package.json +++ b/packages/@aws-cdk/aws-neptune/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::Neptune", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assertions": "0.0.0", - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/aws-ec2": "0.0.0", diff --git a/packages/@aws-cdk/aws-neptune/test/cluster.test.ts b/packages/@aws-cdk/aws-neptune/test/cluster.test.ts index 74f4770a8a74c..f53af7911dc6c 100644 --- a/packages/@aws-cdk/aws-neptune/test/cluster.test.ts +++ b/packages/@aws-cdk/aws-neptune/test/cluster.test.ts @@ -446,7 +446,7 @@ describe('DatabaseCluster', () => { // THEN Template.fromStack(stack).hasResourceProperties('AWS::Neptune::DBCluster', { - IamAuthEnabled: Match.absentProperty(), + IamAuthEnabled: Match.absent(), }); }); diff --git a/packages/@aws-cdk/aws-networkfirewall/.eslintrc.js b/packages/@aws-cdk/aws-networkfirewall/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-networkfirewall/.eslintrc.js +++ b/packages/@aws-cdk/aws-networkfirewall/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-networkfirewall/jest.config.js b/packages/@aws-cdk/aws-networkfirewall/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-networkfirewall/jest.config.js +++ b/packages/@aws-cdk/aws-networkfirewall/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-networkfirewall/package.json b/packages/@aws-cdk/aws-networkfirewall/package.json index 3b6617b2582c5..a0205fb192de7 100644 --- a/packages/@aws-cdk/aws-networkfirewall/package.json +++ b/packages/@aws-cdk/aws-networkfirewall/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::NetworkFirewall", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-networkmanager/.eslintrc.js b/packages/@aws-cdk/aws-networkmanager/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-networkmanager/.eslintrc.js +++ b/packages/@aws-cdk/aws-networkmanager/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-networkmanager/jest.config.js b/packages/@aws-cdk/aws-networkmanager/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-networkmanager/jest.config.js +++ b/packages/@aws-cdk/aws-networkmanager/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-networkmanager/package.json b/packages/@aws-cdk/aws-networkmanager/package.json index dd671b4ffd623..6891e55cb1b6e 100644 --- a/packages/@aws-cdk/aws-networkmanager/package.json +++ b/packages/@aws-cdk/aws-networkmanager/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::NetworkManager", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-nimblestudio/.eslintrc.js b/packages/@aws-cdk/aws-nimblestudio/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-nimblestudio/.eslintrc.js +++ b/packages/@aws-cdk/aws-nimblestudio/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-nimblestudio/jest.config.js b/packages/@aws-cdk/aws-nimblestudio/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-nimblestudio/jest.config.js +++ b/packages/@aws-cdk/aws-nimblestudio/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-nimblestudio/package.json b/packages/@aws-cdk/aws-nimblestudio/package.json index 8270304b555fa..c0291fea71a29 100644 --- a/packages/@aws-cdk/aws-nimblestudio/package.json +++ b/packages/@aws-cdk/aws-nimblestudio/package.json @@ -58,7 +58,6 @@ }, "cdk-build": { "cloudformation": "AWS::NimbleStudio", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -77,11 +76,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", "@aws-cdk/assertions": "0.0.0", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-opensearchservice/.eslintrc.js b/packages/@aws-cdk/aws-opensearchservice/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-opensearchservice/.eslintrc.js +++ b/packages/@aws-cdk/aws-opensearchservice/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-opensearchservice/README.md b/packages/@aws-cdk/aws-opensearchservice/README.md index dddddf5b24f09..d0ddd81e7c0d4 100644 --- a/packages/@aws-cdk/aws-opensearchservice/README.md +++ b/packages/@aws-cdk/aws-opensearchservice/README.md @@ -24,14 +24,14 @@ Higher level constructs for Domain | ![Stable](https://img.shields.io/badge/stab Amazon OpenSearch Service is the successor to Amazon Elasticsearch Service. -See [Migrating to OpenSearch](https://docs.aws.amazon.com/cdk/api/latest/docs/aws-elasticsearch-readme.html#migrating-to-opensearch) for migration instructions from `@aws-cdk/aws-elasticsearch` to this module, `@aws-cdk/aws-opensearch`. +See [Migrating to OpenSearch](https://docs.aws.amazon.com/cdk/api/latest/docs/aws-elasticsearch-readme.html#migrating-to-opensearch) for migration instructions from `@aws-cdk/aws-elasticsearch` to this module, `@aws-cdk/aws-opensearchservice`. ## Quick start Create a development cluster by simply specifying the version: ```ts -import * as opensearch from '@aws-cdk/aws-opensearch'; +import * as opensearch from '@aws-cdk/aws-opensearchservice'; const devDomain = new opensearch.Domain(this, 'Domain', { version: opensearch.EngineVersion.OPENSEARCH_1_0, @@ -41,7 +41,7 @@ const devDomain = new opensearch.Domain(this, 'Domain', { To perform version upgrades without replacing the entire domain, specify the `enableVersionUpgrade` property. ```ts -import * as opensearch from '@aws-cdk/aws-opensearch'; +import * as opensearch from '@aws-cdk/aws-opensearchservice'; const devDomain = new opensearch.Domain(this, 'Domain', { version: opensearch.EngineVersion.OPENSEARCH_1_0, diff --git a/packages/@aws-cdk/aws-opensearchservice/jest.config.js b/packages/@aws-cdk/aws-opensearchservice/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-opensearchservice/jest.config.js +++ b/packages/@aws-cdk/aws-opensearchservice/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-opensearchservice/package.json b/packages/@aws-cdk/aws-opensearchservice/package.json index e00852181986c..523f58fe1caea 100644 --- a/packages/@aws-cdk/aws-opensearchservice/package.json +++ b/packages/@aws-cdk/aws-opensearchservice/package.json @@ -58,7 +58,6 @@ }, "cdk-build": { "cloudformation": "AWS::OpenSearchService", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -78,12 +77,12 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", "@aws-cdk/assert-internal": "0.0.0", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/aws-certificatemanager": "0.0.0", @@ -94,8 +93,8 @@ "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-route53": "0.0.0", "@aws-cdk/aws-secretsmanager": "0.0.0", - "@aws-cdk/custom-resources": "0.0.0", "@aws-cdk/core": "0.0.0", + "@aws-cdk/custom-resources": "0.0.0", "constructs": "^3.3.69" }, "peerDependencies": { @@ -107,8 +106,8 @@ "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-route53": "0.0.0", "@aws-cdk/aws-secretsmanager": "0.0.0", - "@aws-cdk/custom-resources": "0.0.0", "@aws-cdk/core": "0.0.0", + "@aws-cdk/custom-resources": "0.0.0", "constructs": "^3.3.69" }, "engines": { diff --git a/packages/@aws-cdk/aws-opsworks/.eslintrc.js b/packages/@aws-cdk/aws-opsworks/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-opsworks/.eslintrc.js +++ b/packages/@aws-cdk/aws-opsworks/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-opsworks/jest.config.js b/packages/@aws-cdk/aws-opsworks/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-opsworks/jest.config.js +++ b/packages/@aws-cdk/aws-opsworks/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-opsworks/package.json b/packages/@aws-cdk/aws-opsworks/package.json index 5d6f8b77a7d04..0933f51bad400 100644 --- a/packages/@aws-cdk/aws-opsworks/package.json +++ b/packages/@aws-cdk/aws-opsworks/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::OpsWorks", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,11 +72,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-opsworkscm/.eslintrc.js b/packages/@aws-cdk/aws-opsworkscm/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-opsworkscm/.eslintrc.js +++ b/packages/@aws-cdk/aws-opsworkscm/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-opsworkscm/jest.config.js b/packages/@aws-cdk/aws-opsworkscm/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-opsworkscm/jest.config.js +++ b/packages/@aws-cdk/aws-opsworkscm/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-opsworkscm/package.json b/packages/@aws-cdk/aws-opsworkscm/package.json index 03870f42fa5a0..95389c6c13394 100644 --- a/packages/@aws-cdk/aws-opsworkscm/package.json +++ b/packages/@aws-cdk/aws-opsworkscm/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::OpsWorksCM", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-pinpoint/.eslintrc.js b/packages/@aws-cdk/aws-pinpoint/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-pinpoint/.eslintrc.js +++ b/packages/@aws-cdk/aws-pinpoint/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-pinpoint/jest.config.js b/packages/@aws-cdk/aws-pinpoint/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-pinpoint/jest.config.js +++ b/packages/@aws-cdk/aws-pinpoint/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-pinpoint/package.json b/packages/@aws-cdk/aws-pinpoint/package.json index 8475739eaa6f7..e095a349312ac 100644 --- a/packages/@aws-cdk/aws-pinpoint/package.json +++ b/packages/@aws-cdk/aws-pinpoint/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::Pinpoint", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-pinpointemail/.eslintrc.js b/packages/@aws-cdk/aws-pinpointemail/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-pinpointemail/.eslintrc.js +++ b/packages/@aws-cdk/aws-pinpointemail/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-pinpointemail/jest.config.js b/packages/@aws-cdk/aws-pinpointemail/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-pinpointemail/jest.config.js +++ b/packages/@aws-cdk/aws-pinpointemail/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-pinpointemail/package.json b/packages/@aws-cdk/aws-pinpointemail/package.json index d57fe0f9ac922..f95e74754de4c 100644 --- a/packages/@aws-cdk/aws-pinpointemail/package.json +++ b/packages/@aws-cdk/aws-pinpointemail/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::PinpointEmail", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-qldb/.eslintrc.js b/packages/@aws-cdk/aws-qldb/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-qldb/.eslintrc.js +++ b/packages/@aws-cdk/aws-qldb/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-qldb/jest.config.js b/packages/@aws-cdk/aws-qldb/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-qldb/jest.config.js +++ b/packages/@aws-cdk/aws-qldb/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-qldb/package.json b/packages/@aws-cdk/aws-qldb/package.json index 3922e74b5a384..519381dd6de63 100644 --- a/packages/@aws-cdk/aws-qldb/package.json +++ b/packages/@aws-cdk/aws-qldb/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::QLDB", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-quicksight/.eslintrc.js b/packages/@aws-cdk/aws-quicksight/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-quicksight/.eslintrc.js +++ b/packages/@aws-cdk/aws-quicksight/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-quicksight/jest.config.js b/packages/@aws-cdk/aws-quicksight/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-quicksight/jest.config.js +++ b/packages/@aws-cdk/aws-quicksight/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-quicksight/package.json b/packages/@aws-cdk/aws-quicksight/package.json index 00f42d396c801..a611643089d80 100644 --- a/packages/@aws-cdk/aws-quicksight/package.json +++ b/packages/@aws-cdk/aws-quicksight/package.json @@ -58,7 +58,6 @@ }, "cdk-build": { "cloudformation": "AWS::QuickSight", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -77,11 +76,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-ram/.eslintrc.js b/packages/@aws-cdk/aws-ram/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-ram/.eslintrc.js +++ b/packages/@aws-cdk/aws-ram/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-ram/jest.config.js b/packages/@aws-cdk/aws-ram/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-ram/jest.config.js +++ b/packages/@aws-cdk/aws-ram/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-ram/package.json b/packages/@aws-cdk/aws-ram/package.json index 6f817b0f45b4b..cab6b01c59df3 100644 --- a/packages/@aws-cdk/aws-ram/package.json +++ b/packages/@aws-cdk/aws-ram/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::RAM", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-rds/.eslintrc.js b/packages/@aws-cdk/aws-rds/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-rds/.eslintrc.js +++ b/packages/@aws-cdk/aws-rds/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-rds/README.md b/packages/@aws-cdk/aws-rds/README.md index 054a660f3529e..cad785735dfb6 100644 --- a/packages/@aws-cdk/aws-rds/README.md +++ b/packages/@aws-cdk/aws-rds/README.md @@ -200,6 +200,23 @@ new rds.DatabaseInstance(this, 'InstanceWithSecretLogin', { }); ``` +Secrets generated by `fromGeneratedSecret()` can be customized: + +```ts +const myKey = kms.Key(this, 'MyKey'); + +new rds.DatabaseInstance(this, 'InstanceWithCustomizedSecret', { + engine, + vpc, + credentials: rds.Credentials.fromGeneratedSecret('postgres', { + secretName: 'my-cool-name', + encryptionKey: myKey, + excludeCharacters: ['!&*^#@()'], + replicaRegions: [{ region: 'eu-west-1' }, { region: 'eu-west-2' }], + }), +}); +``` + ## Connecting To control who can access the cluster or instance, use the `.connections` attribute. RDS databases have diff --git a/packages/@aws-cdk/aws-rds/jest.config.js b/packages/@aws-cdk/aws-rds/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-rds/jest.config.js +++ b/packages/@aws-cdk/aws-rds/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-rds/lib/cluster-engine.ts b/packages/@aws-cdk/aws-rds/lib/cluster-engine.ts index 6bbb94261cec8..606fddd75edbf 100644 --- a/packages/@aws-cdk/aws-rds/lib/cluster-engine.ts +++ b/packages/@aws-cdk/aws-rds/lib/cluster-engine.ts @@ -334,6 +334,8 @@ export class AuroraMysqlEngineVersion { public static readonly VER_2_09_1 = AuroraMysqlEngineVersion.builtIn_5_7('2.09.1'); /** Version "5.7.mysql_aurora.2.09.2". */ public static readonly VER_2_09_2 = AuroraMysqlEngineVersion.builtIn_5_7('2.09.2'); + /** Version "5.7.mysql_aurora.2.10.0". */ + public static readonly VER_2_10_0 = AuroraMysqlEngineVersion.builtIn_5_7('2.10.0'); /** * Create a new AuroraMysqlEngineVersion with an arbitrary version. diff --git a/packages/@aws-cdk/aws-rds/lib/database-secret.ts b/packages/@aws-cdk/aws-rds/lib/database-secret.ts index 0a0537b23a63e..25b691c92f86b 100644 --- a/packages/@aws-cdk/aws-rds/lib/database-secret.ts +++ b/packages/@aws-cdk/aws-rds/lib/database-secret.ts @@ -53,6 +53,13 @@ export interface DatabaseSecretProps { * @default false */ readonly replaceOnPasswordCriteriaChanges?: boolean; + + /** + * A list of regions where to replicate this secret. + * + * @default - Secret is not replicated + */ + readonly replicaRegions?: secretsmanager.ReplicaRegion[]; } /** @@ -77,6 +84,7 @@ export class DatabaseSecret extends secretsmanager.Secret { generateStringKey: 'password', excludeCharacters, }, + replicaRegions: props.replicaRegions, }); if (props.replaceOnPasswordCriteriaChanges) { diff --git a/packages/@aws-cdk/aws-rds/lib/instance-engine.ts b/packages/@aws-cdk/aws-rds/lib/instance-engine.ts index 3ed27351c2196..dfea03877a0d2 100644 --- a/packages/@aws-cdk/aws-rds/lib/instance-engine.ts +++ b/packages/@aws-cdk/aws-rds/lib/instance-engine.ts @@ -769,9 +769,14 @@ export class PostgresEngineVersion { public static readonly VER_9_6_21 = PostgresEngineVersion.of('9.6.21', '9.6'); /** * Version "9.6.22". - * @deprecated PostgreSQL 9.6 will reach end of life in November 2022 + * @deprecated PostgreSQL 9.6 will reach end of life in November 2021 */ public static readonly VER_9_6_22 = PostgresEngineVersion.of('9.6.22', '9.6'); + /** + * Version "9.6.23". + * @deprecated PostgreSQL 9.6 will reach end of life in November 2021 + */ + public static readonly VER_9_6_23 = PostgresEngineVersion.of('9.6.23', '9.6'); /** Version "10" (only a major version, without a specific minor version). */ public static readonly VER_10 = PostgresEngineVersion.of('10', '10'); @@ -805,6 +810,8 @@ export class PostgresEngineVersion { public static readonly VER_10_16 = PostgresEngineVersion.of('10.16', '10', { s3Import: true, s3Export: true }); /** Version "10.17". */ public static readonly VER_10_17 = PostgresEngineVersion.of('10.17', '10', { s3Import: true, s3Export: true }); + /** Version "10.18". */ + public static readonly VER_10_18 = PostgresEngineVersion.of('10.18', '10', { s3Import: true, s3Export: true }); /** Version "11" (only a major version, without a specific minor version). */ public static readonly VER_11 = PostgresEngineVersion.of('11', '11', { s3Import: true }); @@ -830,6 +837,8 @@ export class PostgresEngineVersion { public static readonly VER_11_11 = PostgresEngineVersion.of('11.11', '11', { s3Import: true, s3Export: true }); /** Version "11.12". */ public static readonly VER_11_12 = PostgresEngineVersion.of('11.12', '11', { s3Import: true, s3Export: true }); + /** Version "11.13". */ + public static readonly VER_11_13 = PostgresEngineVersion.of('11.13', '11', { s3Import: true, s3Export: true }); /** Version "12" (only a major version, without a specific minor version). */ public static readonly VER_12 = PostgresEngineVersion.of('12', '12', { s3Import: true }); @@ -845,6 +854,8 @@ export class PostgresEngineVersion { public static readonly VER_12_6 = PostgresEngineVersion.of('12.6', '12', { s3Import: true, s3Export: true }); /** Version "12.7". */ public static readonly VER_12_7 = PostgresEngineVersion.of('12.7', '12', { s3Import: true, s3Export: true }); + /** Version "12.8". */ + public static readonly VER_12_8 = PostgresEngineVersion.of('12.8', '12', { s3Import: true, s3Export: true }); /** Version "13" (only a major version, without a specific minor version). */ public static readonly VER_13 = PostgresEngineVersion.of('13', '13', { s3Import: true, s3Export: true }); @@ -854,6 +865,8 @@ export class PostgresEngineVersion { public static readonly VER_13_2 = PostgresEngineVersion.of('13.2', '13', { s3Import: true, s3Export: true }); /** Version "13.3". */ public static readonly VER_13_3 = PostgresEngineVersion.of('13.3', '13', { s3Import: true, s3Export: true }); + /** Version "13.4". */ + public static readonly VER_13_4 = PostgresEngineVersion.of('13.4', '13', { s3Import: true, s3Export: true }); /** * Create a new PostgresEngineVersion with an arbitrary version. diff --git a/packages/@aws-cdk/aws-rds/lib/instance.ts b/packages/@aws-cdk/aws-rds/lib/instance.ts index 6ea2418ee1a97..8d285b7375006 100644 --- a/packages/@aws-cdk/aws-rds/lib/instance.ts +++ b/packages/@aws-cdk/aws-rds/lib/instance.ts @@ -1065,6 +1065,7 @@ export class DatabaseInstanceFromSnapshot extends DatabaseInstanceSource impleme encryptionKey: credentials.encryptionKey, excludeCharacters: credentials.excludeCharacters, replaceOnPasswordCriteriaChanges: credentials.replaceOnPasswordCriteriaChanges, + replicaRegions: credentials.replicaRegions, }); } diff --git a/packages/@aws-cdk/aws-rds/lib/private/util.ts b/packages/@aws-cdk/aws-rds/lib/private/util.ts index df9ace2dbd3bc..c142a903bad7a 100644 --- a/packages/@aws-cdk/aws-rds/lib/private/util.ts +++ b/packages/@aws-cdk/aws-rds/lib/private/util.ts @@ -100,6 +100,7 @@ export function renderCredentials(scope: Construct, engine: IEngine, credentials // if username must be referenced as a string we can safely replace the // secret when customization options are changed without risking a replacement replaceOnPasswordCriteriaChanges: credentials?.usernameAsString, + replicaRegions: renderedCredentials.replicaRegions, }), // pass username if it must be referenced as a string credentials?.usernameAsString ? renderedCredentials.username : undefined, diff --git a/packages/@aws-cdk/aws-rds/lib/props.ts b/packages/@aws-cdk/aws-rds/lib/props.ts index c57e8ccee8fd6..e9ed3c126cd65 100644 --- a/packages/@aws-cdk/aws-rds/lib/props.ts +++ b/packages/@aws-cdk/aws-rds/lib/props.ts @@ -147,6 +147,13 @@ export interface CredentialsBaseOptions { * @default - the DatabaseSecret default exclude character set (" %+~`#$&*()|[]{}:;<>?!'/@\"\\") */ readonly excludeCharacters?: string; + + /** + * A list of regions where to replicate this secret. + * + * @default - Secret is not replicated + */ + readonly replicaRegions?: secretsmanager.ReplicaRegion[]; } /** @@ -285,6 +292,13 @@ export abstract class Credentials { * @default - the DatabaseSecret default exclude character set (" %+~`#$&*()|[]{}:;<>?!'/@\"\\") */ public abstract readonly excludeCharacters?: string; + + /** + * A list of regions where to replicate the generated secret. + * + * @default - Secret is not replicated + */ + public abstract readonly replicaRegions?: secretsmanager.ReplicaRegion[]; } /** @@ -304,6 +318,13 @@ export interface SnapshotCredentialsFromGeneratedPasswordOptions { * @default - the DatabaseSecret default exclude character set (" %+~`#$&*()|[]{}:;<>?!'/@\"\\") */ readonly excludeCharacters?: string; + + /** + * A list of regions where to replicate this secret. + * + * @default - Secret is not replicated + */ + readonly replicaRegions?: secretsmanager.ReplicaRegion[]; } /** @@ -420,6 +441,13 @@ export abstract class SnapshotCredentials { * @default - the DatabaseSecret default exclude character set (" %+~`#$&*()|[]{}:;<>?!'/@\"\\") */ public abstract readonly excludeCharacters?: string; + + /** + * A list of regions where to replicate the generated secret. + * + * @default - Secret is not replicated + */ + public abstract readonly replicaRegions?: secretsmanager.ReplicaRegion[]; } /** diff --git a/packages/@aws-cdk/aws-rds/package.json b/packages/@aws-cdk/aws-rds/package.json index d3fcb9f70771c..e2add95207135 100644 --- a/packages/@aws-cdk/aws-rds/package.json +++ b/packages/@aws-cdk/aws-rds/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::RDS", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,16 +72,16 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", + "@aws-cdk/assert-internal": "0.0.0", "@aws-cdk/aws-events-targets": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/cx-api": "0.0.0", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "jest": "^26.6.3", - "@aws-cdk/assert-internal": "0.0.0" + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24", + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-cloudwatch": "0.0.0", @@ -105,9 +104,9 @@ "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/aws-logs": "0.0.0", + "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/aws-secretsmanager": "0.0.0", "@aws-cdk/core": "0.0.0", - "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/cx-api": "0.0.0", "constructs": "^3.3.69" }, diff --git a/packages/@aws-cdk/aws-rds/test/cluster.test.ts b/packages/@aws-cdk/aws-rds/test/cluster.test.ts index 4e9de20a9fa5d..97d5548611fcd 100644 --- a/packages/@aws-cdk/aws-rds/test/cluster.test.ts +++ b/packages/@aws-cdk/aws-rds/test/cluster.test.ts @@ -7,7 +7,7 @@ import * as logs from '@aws-cdk/aws-logs'; import * as s3 from '@aws-cdk/aws-s3'; import * as cdk from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; -import { testFutureBehavior } from 'cdk-build-tools/lib/feature-flag'; +import { testFutureBehavior } from '@aws-cdk/cdk-build-tools/lib/feature-flag'; import { AuroraEngineVersion, AuroraMysqlEngineVersion, AuroraPostgresEngineVersion, CfnDBCluster, Credentials, DatabaseCluster, DatabaseClusterEngine, DatabaseClusterFromSnapshot, ParameterGroup, PerformanceInsightRetention, SubnetGroup, DatabaseSecret, @@ -1784,8 +1784,32 @@ describe('cluster', () => { ], }, }); + }); + test('fromGeneratedSecret with replica regions', () => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + // WHEN + new DatabaseCluster(stack, 'Database', { + engine: DatabaseClusterEngine.aurora({ version: AuroraEngineVersion.VER_1_22_2 }), + credentials: Credentials.fromGeneratedSecret('admin', { + replicaRegions: [{ region: 'eu-west-1' }], + }), + instanceProps: { + vpc, + }, + }); + + // THEN + expect(stack).toHaveResource('AWS::SecretsManager::Secret', { + ReplicaRegions: [ + { + Region: 'eu-west-1', + }, + ], + }); }); test('can set custom name to database secret by fromSecret', () => { diff --git a/packages/@aws-cdk/aws-rds/test/instance.test.ts b/packages/@aws-cdk/aws-rds/test/instance.test.ts index f0591eb2469d1..7364599e4ed25 100644 --- a/packages/@aws-cdk/aws-rds/test/instance.test.ts +++ b/packages/@aws-cdk/aws-rds/test/instance.test.ts @@ -9,7 +9,7 @@ import * as logs from '@aws-cdk/aws-logs'; import * as s3 from '@aws-cdk/aws-s3'; import * as cdk from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; -import { testFutureBehavior } from 'cdk-build-tools/lib/feature-flag'; +import { testFutureBehavior } from '@aws-cdk/cdk-build-tools/lib/feature-flag'; import * as rds from '../lib'; let stack: cdk.Stack; @@ -348,8 +348,25 @@ describe('instance', () => { 'Fn::Join': ['', ['{{resolve:secretsmanager:', { Ref: 'InstanceSecretB6DFA6BE8ee0a797cad8a68dbeb85f8698cdb5bb' }, ':SecretString:password::}}']], }, }); + }); + test('fromGeneratedSecret with replica regions', () => { + new rds.DatabaseInstanceFromSnapshot(stack, 'Instance', { + snapshotIdentifier: 'my-snapshot', + engine: rds.DatabaseInstanceEngine.mysql({ version: rds.MysqlEngineVersion.VER_8_0_19 }), + vpc, + credentials: rds.SnapshotCredentials.fromGeneratedSecret('admin', { + replicaRegions: [{ region: 'eu-west-1' }], + }), + }); + expect(stack).toHaveResource('AWS::SecretsManager::Secret', { + ReplicaRegions: [ + { + Region: 'eu-west-1', + }, + ], + }); }); test('throws if generating a new password without a username', () => { @@ -1227,8 +1244,26 @@ describe('instance', () => { ], }, }); + }); + test('fromGeneratedSecret with replica regions', () => { + // WHEN + new rds.DatabaseInstance(stack, 'Database', { + engine: rds.DatabaseInstanceEngine.postgres({ version: rds.PostgresEngineVersion.VER_12_3 }), + vpc, + credentials: rds.Credentials.fromGeneratedSecret('postgres', { + replicaRegions: [{ region: 'eu-west-1' }], + }), + }); + // THEN + expect(stack).toHaveResource('AWS::SecretsManager::Secret', { + ReplicaRegions: [ + { + Region: 'eu-west-1', + }, + ], + }); }); test('fromPassword', () => { diff --git a/packages/@aws-cdk/aws-redshift/.eslintrc.js b/packages/@aws-cdk/aws-redshift/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-redshift/.eslintrc.js +++ b/packages/@aws-cdk/aws-redshift/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-redshift/jest.config.js b/packages/@aws-cdk/aws-redshift/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-redshift/jest.config.js +++ b/packages/@aws-cdk/aws-redshift/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-redshift/lib/private/database-query.ts b/packages/@aws-cdk/aws-redshift/lib/private/database-query.ts index 2f724334b637a..7acb424a66594 100644 --- a/packages/@aws-cdk/aws-redshift/lib/private/database-query.ts +++ b/packages/@aws-cdk/aws-redshift/lib/private/database-query.ts @@ -36,7 +36,7 @@ export class DatabaseQuery extends CoreConstruct implements iam.IG const adminUser = this.getAdminUser(props); const handler = new lambda.SingletonFunction(this, 'Handler', { code: lambda.Code.fromAsset(path.join(__dirname, 'database-query-provider')), - runtime: lambda.Runtime.NODEJS_14_X, + runtime: lambda.Runtime.NODEJS_12_X, handler: 'index.handler', timeout: cdk.Duration.minutes(1), uuid: '3de5bea7-27da-4796-8662-5efb56431b5f', diff --git a/packages/@aws-cdk/aws-redshift/package.json b/packages/@aws-cdk/aws-redshift/package.json index fe7a1c23393a2..d6ed1ff2f96ca 100644 --- a/packages/@aws-cdk/aws-redshift/package.json +++ b/packages/@aws-cdk/aws-redshift/package.json @@ -62,7 +62,6 @@ }, "cdk-build": { "cloudformation": "AWS::Redshift", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -81,13 +80,13 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", "aws-sdk": "^2.848.0", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-ec2": "0.0.0", diff --git a/packages/@aws-cdk/aws-redshift/test/cluster.test.ts b/packages/@aws-cdk/aws-redshift/test/cluster.test.ts index 28f2fbfd4655b..a1091815a30c1 100644 --- a/packages/@aws-cdk/aws-redshift/test/cluster.test.ts +++ b/packages/@aws-cdk/aws-redshift/test/cluster.test.ts @@ -3,7 +3,8 @@ import * as ec2 from '@aws-cdk/aws-ec2'; import * as kms from '@aws-cdk/aws-kms'; import * as s3 from '@aws-cdk/aws-s3'; import * as cdk from '@aws-cdk/core'; -import { CfnCluster, Cluster, ClusterParameterGroup, ClusterSubnetGroup, ClusterType } from '../lib'; +import { Cluster, ClusterParameterGroup, ClusterSubnetGroup, ClusterType } from '../lib'; +import { CfnCluster } from '../lib/redshift.generated'; let stack: cdk.Stack; let vpc: ec2.IVpc; @@ -145,7 +146,7 @@ describe('node count', () => { // THEN Template.fromStack(stack).hasResourceProperties('AWS::Redshift::Cluster', { ClusterType: 'single-node', - NumberOfNodes: Match.absentProperty(), + NumberOfNodes: Match.absent(), }); }); @@ -163,7 +164,7 @@ describe('node count', () => { // THEN Template.fromStack(stack).hasResourceProperties('AWS::Redshift::Cluster', { ClusterType: 'single-node', - NumberOfNodes: Match.absentProperty(), + NumberOfNodes: Match.absent(), }); }); diff --git a/packages/@aws-cdk/aws-redshift/test/integ.database.expected.json b/packages/@aws-cdk/aws-redshift/test/integ.database.expected.json index b346d3e7abfb3..16d60bb08c0d0 100644 --- a/packages/@aws-cdk/aws-redshift/test/integ.database.expected.json +++ b/packages/@aws-cdk/aws-redshift/test/integ.database.expected.json @@ -841,7 +841,7 @@ } }, "Handler": "framework.onEvent", - "Runtime": "nodejs14.x", + "Runtime": "nodejs12.x", "Timeout": 900 }, "DependsOn": [ @@ -996,7 +996,7 @@ } }, "Handler": "framework.onEvent", - "Runtime": "nodejs14.x", + "Runtime": "nodejs12.x", "Timeout": 900 }, "DependsOn": [ @@ -1129,7 +1129,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters483841e46ab98aa099d0371a7800e2ace3ddbbb12cb8efb3162ca172ebdafd49S3Bucket148631C8" + "Ref": "AssetParameters7eb6a250bd5ce32c07f08f536377d71e59ad43e16e25b9aa6e50f6fc20fdfc4fS3Bucket3B967306" }, "S3Key": { "Fn::Join": [ @@ -1142,7 +1142,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters483841e46ab98aa099d0371a7800e2ace3ddbbb12cb8efb3162ca172ebdafd49S3VersionKey1A4E04E7" + "Ref": "AssetParameters7eb6a250bd5ce32c07f08f536377d71e59ad43e16e25b9aa6e50f6fc20fdfc4fS3VersionKeyC171429B" } ] } @@ -1155,7 +1155,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters483841e46ab98aa099d0371a7800e2ace3ddbbb12cb8efb3162ca172ebdafd49S3VersionKey1A4E04E7" + "Ref": "AssetParameters7eb6a250bd5ce32c07f08f536377d71e59ad43e16e25b9aa6e50f6fc20fdfc4fS3VersionKeyC171429B" } ] } @@ -1172,7 +1172,7 @@ ] }, "Handler": "index.handler", - "Runtime": "nodejs14.x", + "Runtime": "nodejs12.x", "Timeout": 60 }, "DependsOn": [ @@ -1302,7 +1302,7 @@ } }, "Handler": "framework.onEvent", - "Runtime": "nodejs14.x", + "Runtime": "nodejs12.x", "Timeout": 900 }, "DependsOn": [ @@ -1349,17 +1349,17 @@ } }, "Parameters": { - "AssetParameters483841e46ab98aa099d0371a7800e2ace3ddbbb12cb8efb3162ca172ebdafd49S3Bucket148631C8": { + "AssetParameters7eb6a250bd5ce32c07f08f536377d71e59ad43e16e25b9aa6e50f6fc20fdfc4fS3Bucket3B967306": { "Type": "String", - "Description": "S3 bucket for asset \"483841e46ab98aa099d0371a7800e2ace3ddbbb12cb8efb3162ca172ebdafd49\"" + "Description": "S3 bucket for asset \"7eb6a250bd5ce32c07f08f536377d71e59ad43e16e25b9aa6e50f6fc20fdfc4f\"" }, - "AssetParameters483841e46ab98aa099d0371a7800e2ace3ddbbb12cb8efb3162ca172ebdafd49S3VersionKey1A4E04E7": { + "AssetParameters7eb6a250bd5ce32c07f08f536377d71e59ad43e16e25b9aa6e50f6fc20fdfc4fS3VersionKeyC171429B": { "Type": "String", - "Description": "S3 key for asset version \"483841e46ab98aa099d0371a7800e2ace3ddbbb12cb8efb3162ca172ebdafd49\"" + "Description": "S3 key for asset version \"7eb6a250bd5ce32c07f08f536377d71e59ad43e16e25b9aa6e50f6fc20fdfc4f\"" }, - "AssetParameters483841e46ab98aa099d0371a7800e2ace3ddbbb12cb8efb3162ca172ebdafd49ArtifactHashEB952795": { + "AssetParameters7eb6a250bd5ce32c07f08f536377d71e59ad43e16e25b9aa6e50f6fc20fdfc4fArtifactHash0EE8CD3D": { "Type": "String", - "Description": "Artifact hash for asset \"483841e46ab98aa099d0371a7800e2ace3ddbbb12cb8efb3162ca172ebdafd49\"" + "Description": "Artifact hash for asset \"7eb6a250bd5ce32c07f08f536377d71e59ad43e16e25b9aa6e50f6fc20fdfc4f\"" }, "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1": { "Type": "String", diff --git a/packages/@aws-cdk/aws-resourcegroups/.eslintrc.js b/packages/@aws-cdk/aws-resourcegroups/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-resourcegroups/.eslintrc.js +++ b/packages/@aws-cdk/aws-resourcegroups/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-resourcegroups/jest.config.js b/packages/@aws-cdk/aws-resourcegroups/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-resourcegroups/jest.config.js +++ b/packages/@aws-cdk/aws-resourcegroups/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-resourcegroups/package.json b/packages/@aws-cdk/aws-resourcegroups/package.json index 88e73e2bd2426..2f9b4f2ee4163 100644 --- a/packages/@aws-cdk/aws-resourcegroups/package.json +++ b/packages/@aws-cdk/aws-resourcegroups/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::ResourceGroups", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-robomaker/.eslintrc.js b/packages/@aws-cdk/aws-robomaker/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-robomaker/.eslintrc.js +++ b/packages/@aws-cdk/aws-robomaker/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-robomaker/jest.config.js b/packages/@aws-cdk/aws-robomaker/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-robomaker/jest.config.js +++ b/packages/@aws-cdk/aws-robomaker/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-robomaker/package.json b/packages/@aws-cdk/aws-robomaker/package.json index 124451f52e67b..000b195520ffd 100644 --- a/packages/@aws-cdk/aws-robomaker/package.json +++ b/packages/@aws-cdk/aws-robomaker/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::RoboMaker", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-route53-patterns/.eslintrc.js b/packages/@aws-cdk/aws-route53-patterns/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-route53-patterns/.eslintrc.js +++ b/packages/@aws-cdk/aws-route53-patterns/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-route53-patterns/jest.config.js b/packages/@aws-cdk/aws-route53-patterns/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-route53-patterns/jest.config.js +++ b/packages/@aws-cdk/aws-route53-patterns/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-route53-patterns/package.json b/packages/@aws-cdk/aws-route53-patterns/package.json index 4692f1c25903d..02e94d1139a5d 100644 --- a/packages/@aws-cdk/aws-route53-patterns/package.json +++ b/packages/@aws-cdk/aws-route53-patterns/package.json @@ -65,13 +65,13 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-certificatemanager": "0.0.0", @@ -105,7 +105,6 @@ "announce": false }, "cdk-build": { - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } diff --git a/packages/@aws-cdk/aws-route53-targets/.eslintrc.js b/packages/@aws-cdk/aws-route53-targets/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-route53-targets/.eslintrc.js +++ b/packages/@aws-cdk/aws-route53-targets/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-route53-targets/jest.config.js b/packages/@aws-cdk/aws-route53-targets/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-route53-targets/jest.config.js +++ b/packages/@aws-cdk/aws-route53-targets/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-route53-targets/lib/api-gateway-domain-name.ts b/packages/@aws-cdk/aws-route53-targets/lib/api-gateway-domain-name.ts index c87e26568d6b8..0cc215d5c5eed 100644 --- a/packages/@aws-cdk/aws-route53-targets/lib/api-gateway-domain-name.ts +++ b/packages/@aws-cdk/aws-route53-targets/lib/api-gateway-domain-name.ts @@ -26,7 +26,7 @@ export class ApiGatewayDomain implements route53.IAliasRecordTarget { * `ApiGatewayDomain` class. */ export class ApiGateway extends ApiGatewayDomain { - constructor(api: apig.RestApi) { + constructor(api: apig.RestApiBase) { if (!api.domainName) { throw new Error('API does not define a default domain name'); } diff --git a/packages/@aws-cdk/aws-route53-targets/package.json b/packages/@aws-cdk/aws-route53-targets/package.json index 0d42c4d83462f..8da79638f150b 100644 --- a/packages/@aws-cdk/aws-route53-targets/package.json +++ b/packages/@aws-cdk/aws-route53-targets/package.json @@ -64,16 +64,16 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/aws-apigatewayv2": "0.0.0", "@aws-cdk/aws-certificatemanager": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", - "@aws-cdk/aws-apigatewayv2": "0.0.0", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24", + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-apigateway": "0.0.0", @@ -82,8 +82,8 @@ "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/aws-elasticloadbalancing": "0.0.0", "@aws-cdk/aws-elasticloadbalancingv2": "0.0.0", - "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-globalaccelerator": "0.0.0", + "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-route53": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/core": "0.0.0", @@ -98,8 +98,8 @@ "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/aws-elasticloadbalancing": "0.0.0", "@aws-cdk/aws-elasticloadbalancingv2": "0.0.0", - "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-globalaccelerator": "0.0.0", + "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-route53": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/core": "0.0.0", @@ -115,7 +115,6 @@ }, "maturity": "stable", "cdk-build": { - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } diff --git a/packages/@aws-cdk/aws-route53-targets/test/apigateway-target.test.ts b/packages/@aws-cdk/aws-route53-targets/test/apigateway-target.test.ts index e62c87b59c385..5658a1f56323a 100644 --- a/packages/@aws-cdk/aws-route53-targets/test/apigateway-target.test.ts +++ b/packages/@aws-cdk/aws-route53-targets/test/apigateway-target.test.ts @@ -106,3 +106,51 @@ test('fails if an ApiGateway is used with an API that does not define a domain n }); }).toThrow(/API does not define a default domain name/); }); + +test('targets.ApiGateway accepts a SpecRestApi', () => { + // GIVEN + const stack = new Stack(); + const cert = new acm.Certificate(stack, 'cert', { domainName: 'example.com' }); + const api = new apigw.SpecRestApi(stack, 'api', { + domainName: { + domainName: 'example.com', + certificate: cert, + }, + apiDefinition: apigw.ApiDefinition.fromInline({ + key1: 'val1', + }), + }); + const zone = new route53.HostedZone(stack, 'zone', { + zoneName: 'example.com', + }); + api.root.addMethod('GET'); + + // WHEN + new route53.ARecord(stack, 'A', { + zone, + target: route53.RecordTarget.fromAlias(new targets.ApiGateway(api)), + }); + + // THEN + expectStack(stack).to(haveResource('AWS::Route53::RecordSet', { + Name: 'example.com.', + Type: 'A', + AliasTarget: { + DNSName: { + 'Fn::GetAtt': [ + 'apiCustomDomain64773C4F', + 'RegionalDomainName', + ], + }, + HostedZoneId: { + 'Fn::GetAtt': [ + 'apiCustomDomain64773C4F', + 'RegionalHostedZoneId', + ], + }, + }, + HostedZoneId: { + Ref: 'zoneEB40FF1E', + }, + })); +}); \ No newline at end of file diff --git a/packages/@aws-cdk/aws-route53/.eslintrc.js b/packages/@aws-cdk/aws-route53/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-route53/.eslintrc.js +++ b/packages/@aws-cdk/aws-route53/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-route53/jest.config.js b/packages/@aws-cdk/aws-route53/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-route53/jest.config.js +++ b/packages/@aws-cdk/aws-route53/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-route53/package.json b/packages/@aws-cdk/aws-route53/package.json index 24e72e9300c93..2fc93edef1b21 100644 --- a/packages/@aws-cdk/aws-route53/package.json +++ b/packages/@aws-cdk/aws-route53/package.json @@ -57,8 +57,7 @@ "cloudformation": "AWS::Route53", "env": { "AWSLINT_BASE_CONSTRUCT": true - }, - "jest": true + } }, "keywords": [ "aws", @@ -73,23 +72,22 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/aws-lambda": "^8.10.79", + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/aws-lambda": "^8.10.84", "@types/jest": "^26.0.24", - "@types/nodeunit": "^0.0.32", "aws-sdk": "^2.848.0", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-logs": "0.0.0", - "@aws-cdk/core": "0.0.0", "@aws-cdk/cloud-assembly-schema": "0.0.0", + "@aws-cdk/core": "0.0.0", "@aws-cdk/custom-resources": "0.0.0", "constructs": "^3.3.69" }, @@ -98,8 +96,8 @@ "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-logs": "0.0.0", - "@aws-cdk/core": "0.0.0", "@aws-cdk/cloud-assembly-schema": "0.0.0", + "@aws-cdk/core": "0.0.0", "@aws-cdk/custom-resources": "0.0.0", "constructs": "^3.3.69" }, diff --git a/packages/@aws-cdk/aws-route53recoverycontrol/.eslintrc.js b/packages/@aws-cdk/aws-route53recoverycontrol/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-route53recoverycontrol/.eslintrc.js +++ b/packages/@aws-cdk/aws-route53recoverycontrol/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-route53recoverycontrol/jest.config.js b/packages/@aws-cdk/aws-route53recoverycontrol/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-route53recoverycontrol/jest.config.js +++ b/packages/@aws-cdk/aws-route53recoverycontrol/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-route53recoverycontrol/package.json b/packages/@aws-cdk/aws-route53recoverycontrol/package.json index 8ceaa50512b21..71c0d5c3e12b9 100644 --- a/packages/@aws-cdk/aws-route53recoverycontrol/package.json +++ b/packages/@aws-cdk/aws-route53recoverycontrol/package.json @@ -58,7 +58,6 @@ }, "cdk-build": { "cloudformation": "AWS::Route53RecoveryControl", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -77,11 +76,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", "@aws-cdk/assertions": "0.0.0", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-route53recoveryreadiness/.eslintrc.js b/packages/@aws-cdk/aws-route53recoveryreadiness/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-route53recoveryreadiness/.eslintrc.js +++ b/packages/@aws-cdk/aws-route53recoveryreadiness/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-route53recoveryreadiness/jest.config.js b/packages/@aws-cdk/aws-route53recoveryreadiness/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-route53recoveryreadiness/jest.config.js +++ b/packages/@aws-cdk/aws-route53recoveryreadiness/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-route53recoveryreadiness/package.json b/packages/@aws-cdk/aws-route53recoveryreadiness/package.json index afa6c384f2f7b..386a35690f2dc 100644 --- a/packages/@aws-cdk/aws-route53recoveryreadiness/package.json +++ b/packages/@aws-cdk/aws-route53recoveryreadiness/package.json @@ -58,7 +58,6 @@ }, "cdk-build": { "cloudformation": "AWS::Route53RecoveryReadiness", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -77,11 +76,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", "@aws-cdk/assertions": "0.0.0", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-route53resolver/.eslintrc.js b/packages/@aws-cdk/aws-route53resolver/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-route53resolver/.eslintrc.js +++ b/packages/@aws-cdk/aws-route53resolver/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-route53resolver/jest.config.js b/packages/@aws-cdk/aws-route53resolver/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-route53resolver/jest.config.js +++ b/packages/@aws-cdk/aws-route53resolver/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-route53resolver/lib/firewall-domain-list.ts b/packages/@aws-cdk/aws-route53resolver/lib/firewall-domain-list.ts index a6303b2c78114..80f211ab07f66 100644 --- a/packages/@aws-cdk/aws-route53resolver/lib/firewall-domain-list.ts +++ b/packages/@aws-cdk/aws-route53resolver/lib/firewall-domain-list.ts @@ -45,8 +45,8 @@ export abstract class FirewallDomains { */ public static fromList(list: string[]): FirewallDomains { for (const domain of list) { - if (!/^[\w-.]+$/.test(domain)) { - throw new Error(`Invalid domain: ${domain}. Valid characters: A-Z, a-z, 0-9, _, -, .`); + if (!/^([\w-.]{1,255}|\*[\w-.]{1,254})$/.test(domain)) { + throw new Error(`Invalid domain: ${domain}. Domain can optionally start with *. Max length of 255. Valid characters: A-Z, a-z, 0-9, _, -, .`); } } diff --git a/packages/@aws-cdk/aws-route53resolver/package.json b/packages/@aws-cdk/aws-route53resolver/package.json index 5e24de4caaffb..74d7bd95b363b 100644 --- a/packages/@aws-cdk/aws-route53resolver/package.json +++ b/packages/@aws-cdk/aws-route53resolver/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::Route53Resolver", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -74,12 +73,12 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/aws-ec2": "0.0.0", @@ -106,7 +105,7 @@ "props-physical-name:@aws-cdk/aws-route53resolver.FirewallRuleGroupProps", "props-physical-name:@aws-cdk/aws-route53resolver.FirewallRuleGroupAssociationProps" ] - }, + }, "awscdkio": { "announce": false }, diff --git a/packages/@aws-cdk/aws-route53resolver/test/firewall-domain-list.test.ts b/packages/@aws-cdk/aws-route53resolver/test/firewall-domain-list.test.ts index 3806a59c670ba..5eaef3352d702 100644 --- a/packages/@aws-cdk/aws-route53resolver/test/firewall-domain-list.test.ts +++ b/packages/@aws-cdk/aws-route53resolver/test/firewall-domain-list.test.ts @@ -12,7 +12,11 @@ beforeEach(() => { test('domain list from strings', () => { // WHEN new FirewallDomainList(stack, 'List', { - domains: FirewallDomains.fromList(['first-domain.com', 'second-domain.net']), + domains: FirewallDomains.fromList([ + 'first-domain.com', + 'second-domain.net', + '*.wildcard.com', + ]), }); // THEN @@ -20,6 +24,7 @@ test('domain list from strings', () => { Domains: [ 'first-domain.com', 'second-domain.net', + '*.wildcard.com', ], }); }); diff --git a/packages/@aws-cdk/aws-s3-assets/.eslintrc.js b/packages/@aws-cdk/aws-s3-assets/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-s3-assets/.eslintrc.js +++ b/packages/@aws-cdk/aws-s3-assets/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-s3-assets/jest.config.js b/packages/@aws-cdk/aws-s3-assets/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-s3-assets/jest.config.js +++ b/packages/@aws-cdk/aws-s3-assets/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-s3-assets/package.json b/packages/@aws-cdk/aws-s3-assets/package.json index 987039fd3ab4b..8ab66aee891bb 100644 --- a/packages/@aws-cdk/aws-s3-assets/package.json +++ b/packages/@aws-cdk/aws-s3-assets/package.json @@ -52,7 +52,6 @@ "build+test+extract": "yarn build+test && yarn rosetta:extract" }, "cdk-build": { - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -71,18 +70,18 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cloud-assembly-schema": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/assets": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", - "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", + "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/cx-api": "0.0.0", "constructs": "^3.3.69" @@ -91,8 +90,8 @@ "peerDependencies": { "@aws-cdk/assets": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", - "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", + "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/cx-api": "0.0.0", "constructs": "^3.3.69" diff --git a/packages/@aws-cdk/aws-s3-deployment/.eslintrc.js b/packages/@aws-cdk/aws-s3-deployment/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-s3-deployment/.eslintrc.js +++ b/packages/@aws-cdk/aws-s3-deployment/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-s3-deployment/jest.config.js b/packages/@aws-cdk/aws-s3-deployment/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-s3-deployment/jest.config.js +++ b/packages/@aws-cdk/aws-s3-deployment/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-s3-deployment/lib/bucket-deployment.ts b/packages/@aws-cdk/aws-s3-deployment/lib/bucket-deployment.ts index 439af53a90dd9..8e25826647a64 100644 --- a/packages/@aws-cdk/aws-s3-deployment/lib/bucket-deployment.ts +++ b/packages/@aws-cdk/aws-s3-deployment/lib/bucket-deployment.ts @@ -278,7 +278,7 @@ export class BucketDeployment extends CoreConstruct { uuid: this.renderSingletonUuid(props.memoryLimit, props.vpc), code: lambda.Code.fromAsset(path.join(__dirname, 'lambda')), layers: [new AwsCliLayer(this, 'AwsCliLayer')], - runtime: lambda.Runtime.PYTHON_3_6, + runtime: lambda.Runtime.PYTHON_3_7, environment: props.useEfs ? { MOUNT_PATH: mountPath, } : undefined, diff --git a/packages/@aws-cdk/aws-s3-deployment/package.json b/packages/@aws-cdk/aws-s3-deployment/package.json index 3d1f7e7659f5e..102b6e90ffc00 100644 --- a/packages/@aws-cdk/aws-s3-deployment/package.json +++ b/packages/@aws-cdk/aws-s3-deployment/package.json @@ -52,7 +52,6 @@ "build+test+extract": "yarn build+test && yarn rosetta:extract" }, "cdk-build": { - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -79,13 +78,13 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cx-api": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-cloudfront": "0.0.0", @@ -95,22 +94,22 @@ "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/aws-s3-assets": "0.0.0", - "@aws-cdk/lambda-layer-awscli": "0.0.0", "@aws-cdk/core": "0.0.0", + "@aws-cdk/lambda-layer-awscli": "0.0.0", "case": "1.6.3", "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { "@aws-cdk/aws-cloudfront": "0.0.0", - "@aws-cdk/aws-efs": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", + "@aws-cdk/aws-efs": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/aws-s3-assets": "0.0.0", - "@aws-cdk/lambda-layer-awscli": "0.0.0", "@aws-cdk/core": "0.0.0", + "@aws-cdk/lambda-layer-awscli": "0.0.0", "constructs": "^3.3.69" }, "bundledDependencies": [ diff --git a/packages/@aws-cdk/aws-s3-deployment/test/bucket-deployment.test.ts b/packages/@aws-cdk/aws-s3-deployment/test/bucket-deployment.test.ts index b7a0e258b6393..7f799b2f9ff65 100644 --- a/packages/@aws-cdk/aws-s3-deployment/test/bucket-deployment.test.ts +++ b/packages/@aws-cdk/aws-s3-deployment/test/bucket-deployment.test.ts @@ -6,7 +6,7 @@ import * as iam from '@aws-cdk/aws-iam'; import * as s3 from '@aws-cdk/aws-s3'; import * as cdk from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; -import { testFutureBehavior } from 'cdk-build-tools/lib/feature-flag'; +import { testFutureBehavior } from '@aws-cdk/cdk-build-tools/lib/feature-flag'; import * as s3deploy from '../lib'; /* eslint-disable max-len */ diff --git a/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-cloudfront.expected.json b/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-cloudfront.expected.json index bd5c7309210e3..ee73484606056 100644 --- a/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-cloudfront.expected.json +++ b/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-cloudfront.expected.json @@ -343,7 +343,7 @@ "Ref": "DeployWithInvalidationAwsCliLayerDEDD5787" } ], - "Runtime": "python3.6", + "Runtime": "python3.7", "Timeout": 900 }, "DependsOn": [ diff --git a/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment.expected.json b/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment.expected.json index 8b247a49a4428..28a59330cb59b 100644 --- a/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment.expected.json +++ b/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment.expected.json @@ -352,7 +352,7 @@ "Ref": "DeployMeAwsCliLayer5F9219E9" } ], - "Runtime": "python3.6", + "Runtime": "python3.7", "Timeout": 900 }, "DependsOn": [ @@ -1495,7 +1495,7 @@ "Ref": "DeployMeWithEfsStorageAwsCliLayer1619A3EE" } ], - "Runtime": "python3.6", + "Runtime": "python3.7", "Timeout": 900, "VpcConfig": { "SecurityGroupIds": [ diff --git a/packages/@aws-cdk/aws-s3-notifications/.eslintrc.js b/packages/@aws-cdk/aws-s3-notifications/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-s3-notifications/.eslintrc.js +++ b/packages/@aws-cdk/aws-s3-notifications/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-s3-notifications/jest.config.js b/packages/@aws-cdk/aws-s3-notifications/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-s3-notifications/jest.config.js +++ b/packages/@aws-cdk/aws-s3-notifications/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-s3-notifications/package.json b/packages/@aws-cdk/aws-s3-notifications/package.json index 62602ff1b6ce4..2ffab562221db 100644 --- a/packages/@aws-cdk/aws-s3-notifications/package.json +++ b/packages/@aws-cdk/aws-s3-notifications/package.json @@ -64,12 +64,12 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-iam": "0.0.0", @@ -99,7 +99,6 @@ }, "maturity": "stable", "cdk-build": { - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } diff --git a/packages/@aws-cdk/aws-s3/.eslintrc.js b/packages/@aws-cdk/aws-s3/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-s3/.eslintrc.js +++ b/packages/@aws-cdk/aws-s3/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-s3/README.md b/packages/@aws-cdk/aws-s3/README.md index 3470a526ded88..b666ee14b44d5 100644 --- a/packages/@aws-cdk/aws-s3/README.md +++ b/packages/@aws-cdk/aws-s3/README.md @@ -14,7 +14,7 @@ Define an unencrypted S3 bucket. ```ts -new Bucket(this, 'MyFirstBucket'); +const bucket = new s3.Bucket(this, 'MyFirstBucket'); ``` `Bucket` constructs expose the following deploy-time attributes: @@ -43,8 +43,8 @@ new Bucket(this, 'MyFirstBucket'); Define a KMS-encrypted bucket: ```ts -const bucket = new Bucket(this, 'MyEncryptedBucket', { - encryption: BucketEncryption.KMS +const bucket = new s3.Bucket(this, 'MyEncryptedBucket', { + encryption: s3.BucketEncryption.KMS, }); // you can access the encryption key: @@ -56,9 +56,9 @@ You can also supply your own key: ```ts const myKmsKey = new kms.Key(this, 'MyKey'); -const bucket = new Bucket(this, 'MyEncryptedBucket', { - encryption: BucketEncryption.KMS, - encryptionKey: myKmsKey +const bucket = new s3.Bucket(this, 'MyEncryptedBucket', { + encryption: s3.BucketEncryption.KMS, + encryptionKey: myKmsKey, }); assert(bucket.encryptionKey === myKmsKey); @@ -67,19 +67,17 @@ assert(bucket.encryptionKey === myKmsKey); Enable KMS-SSE encryption via [S3 Bucket Keys](https://docs.aws.amazon.com/AmazonS3/latest/dev/bucket-key.html): ```ts -const bucket = new Bucket(this, 'MyEncryptedBucket', { - encryption: BucketEncryption.KMS, - bucketKeyEnabled: true +const bucket = new s3.Bucket(this, 'MyEncryptedBucket', { + encryption: s3.BucketEncryption.KMS, + bucketKeyEnabled: true, }); - -assert(bucket.bucketKeyEnabled === true); ``` Use `BucketEncryption.ManagedKms` to use the S3 master KMS key: ```ts -const bucket = new Bucket(this, 'Buck', { - encryption: BucketEncryption.KMS_MANAGED +const bucket = new s3.Bucket(this, 'Buck', { + encryption: s3.BucketEncryption.KMS_MANAGED, }); assert(bucket.encryptionKey == null); @@ -91,7 +89,7 @@ A bucket policy will be automatically created for the bucket upon the first call `addToResourcePolicy(statement)`: ```ts -const bucket = new Bucket(this, 'MyBucket'); +const bucket = new s3.Bucket(this, 'MyBucket'); const result = bucket.addToResourcePolicy(new iam.PolicyStatement({ actions: ['s3:GetObject'], resources: [bucket.arnForObjects('file.txt')], @@ -99,24 +97,32 @@ const result = bucket.addToResourcePolicy(new iam.PolicyStatement({ })); ``` -If you try to add a policy statement to an existing bucket, this method will +If you try to add a policy statement to an existing bucket, this method will not do anything: ```ts -const bucket = Bucket.fromBucketName(this, 'existingBucket', 'bucket-name'); +const bucket = s3.Bucket.fromBucketName(this, 'existingBucket', 'bucket-name'); -// Nothing will change here +// No policy statement will be added to the resource const result = bucket.addToResourcePolicy(new iam.PolicyStatement({ - ... + actions: ['s3:GetObject'], + resources: [bucket.arnForObjects('file.txt')], + principals: [new iam.AccountRootPrincipal()], })); ``` -That's because it's not possible to tell whether the bucket -already has a policy attached, let alone to re-use that policy to add more +That's because it's not possible to tell whether the bucket +already has a policy attached, let alone to re-use that policy to add more statements to it. We recommend that you always check the result of the call: ```ts -const result = bucket.addToResourcePolicy(...) +const bucket = new s3.Bucket(this, 'MyBucket'); +const result = bucket.addToResourcePolicy(new iam.PolicyStatement({ + actions: ['s3:GetObject'], + resources: [bucket.arnForObjects('file.txt')], + principals: [new iam.AccountRootPrincipal()], +})); + if (!result.statementAdded) { // Uh-oh! Someone probably made a mistake here. } @@ -126,7 +132,8 @@ The bucket policy can be directly accessed after creation to add statements or adjust the removal policy. ```ts -bucket.policy?.applyRemovalPolicy(RemovalPolicy.RETAIN); +const bucket = new s3.Bucket(this, 'MyBucket'); +bucket.policy?.applyRemovalPolicy(cdk.RemovalPolicy.RETAIN); ``` Most of the time, you won't have to manipulate the bucket policy directly. @@ -134,10 +141,10 @@ Instead, buckets have "grant" methods called to give prepackaged sets of permiss to other resources. For example: ```ts -const lambda = new lambda.Function(this, 'Lambda', { /* ... */ }); +declare const myLambda: lambda.Function; -const bucket = new Bucket(this, 'MyBucket'); -bucket.grantReadWrite(lambda); +const bucket = new s3.Bucket(this, 'MyBucket'); +bucket.grantReadWrite(myLambda); ``` Will give the Lambda's execution role permissions to read and write @@ -150,8 +157,8 @@ from the bucket. To require all requests use Secure Socket Layer (SSL): ```ts -const bucket = new Bucket(this, 'Bucket', { - enforceSSL: true +const bucket = new s3.Bucket(this, 'Bucket', { + enforceSSL: true, }); ``` @@ -168,12 +175,13 @@ factory method. This method accepts `BucketAttributes` which describes the prope existing bucket: ```ts -const bucket = Bucket.fromBucketAttributes(this, 'ImportedBucket', { - bucketArn: 'arn:aws:s3:::my-bucket' +declare const myLambda: lambda.Function; +const bucket = s3.Bucket.fromBucketAttributes(this, 'ImportedBucket', { + bucketArn: 'arn:aws:s3:::my-bucket', }); // now you can just call methods on the bucket -bucket.addEventNotification(EventType.OBJECT_CREATED, ...); +bucket.addEventNotification(s3.EventType.OBJECT_CREATED, new s3n.LambdaDestination(myLambda), {prefix: 'home/myusername/*'}); ``` Alternatively, short-hand factories are available as `Bucket.fromBucketName` and @@ -181,15 +189,15 @@ Alternatively, short-hand factories are available as `Bucket.fromBucketName` and name or ARN respectively: ```ts -const byName = Bucket.fromBucketName(this, 'BucketByName', 'my-bucket'); -const byArn = Bucket.fromBucketArn(this, 'BucketByArn', 'arn:aws:s3:::my-bucket'); +const byName = s3.Bucket.fromBucketName(this, 'BucketByName', 'my-bucket'); +const byArn = s3.Bucket.fromBucketArn(this, 'BucketByArn', 'arn:aws:s3:::my-bucket'); ``` The bucket's region defaults to the current stack's region, but can also be explicitly set in cases where one of the bucket's regional properties needs to contain the correct values. ```ts -const myCrossRegionBucket = Bucket.fromBucketAttributes(this, 'CrossRegionImport', { +const myCrossRegionBucket = s3.Bucket.fromBucketAttributes(this, 'CrossRegionImport', { bucketArn: 'arn:aws:s3:::my-bucket', region: 'us-east-1', }); @@ -209,8 +217,7 @@ these common use cases. The following example will subscribe an SNS topic to be notified of all `s3:ObjectCreated:*` events: ```ts -import * as s3n from '@aws-cdk/aws-s3-notifications'; - +const bucket = new s3.Bucket(this, 'MyBucket'); const topic = new sns.Topic(this, 'MyTopic'); bucket.addEventNotification(s3.EventType.OBJECT_CREATED, new s3n.SnsDestination(topic)); ``` @@ -225,6 +232,8 @@ following example will notify `myQueue` when objects prefixed with `foo/` and have the `.jpg` suffix are removed from the bucket. ```ts +declare const myQueue: sqs.Queue; +const bucket = new s3.Bucket(this, 'MyBucket'); bucket.addEventNotification(s3.EventType.OBJECT_REMOVED, new s3n.SqsDestination(myQueue), { prefix: 'foo/', suffix: '.jpg' }); @@ -233,8 +242,9 @@ bucket.addEventNotification(s3.EventType.OBJECT_REMOVED, Adding notifications on existing buckets: ```ts -const bucket = Bucket.fromBucketAttributes(this, 'ImportedBucket', { - bucketArn: 'arn:aws:s3:::my-bucket' +declare const topic: sns.Topic; +const bucket = s3.Bucket.fromBucketAttributes(this, 'ImportedBucket', { + bucketArn: 'arn:aws:s3:::my-bucket', }); bucket.addEventNotification(s3.EventType.OBJECT_CREATED, new s3n.SnsDestination(topic)); ``` @@ -249,24 +259,24 @@ Use `blockPublicAccess` to specify [block public access settings] on the bucket. Enable all block public access settings: ```ts -const bucket = new Bucket(this, 'MyBlockedBucket', { - blockPublicAccess: BlockPublicAccess.BLOCK_ALL +const bucket = new s3.Bucket(this, 'MyBlockedBucket', { + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, }); ``` Block and ignore public ACLs: ```ts -const bucket = new Bucket(this, 'MyBlockedBucket', { - blockPublicAccess: BlockPublicAccess.BLOCK_ACLS +const bucket = new s3.Bucket(this, 'MyBlockedBucket', { + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ACLS, }); ``` Alternatively, specify the settings manually: ```ts -const bucket = new Bucket(this, 'MyBlockedBucket', { - blockPublicAccess: new BlockPublicAccess({ blockPublicPolicy: true }) +const bucket = new s3.Bucket(this, 'MyBlockedBucket', { + blockPublicAccess: new s3.BlockPublicAccess({ blockPublicPolicy: true }), }); ``` @@ -279,9 +289,9 @@ When `blockPublicPolicy` is set to `true`, `grantPublicRead()` throws an error. Use `serverAccessLogsBucket` to describe where server access logs are to be stored. ```ts -const accessLogsBucket = new Bucket(this, 'AccessLogsBucket'); +const accessLogsBucket = new s3.Bucket(this, 'AccessLogsBucket'); -const bucket = new Bucket(this, 'MyBucket', { +const bucket = new s3.Bucket(this, 'MyBucket', { serverAccessLogsBucket: accessLogsBucket, }); ``` @@ -289,9 +299,11 @@ const bucket = new Bucket(this, 'MyBucket', { It's also possible to specify a prefix for Amazon S3 to assign to all log object keys. ```ts -const bucket = new Bucket(this, 'MyBucket', { +const accessLogsBucket = new s3.Bucket(this, 'AccessLogsBucket'); + +const bucket = new s3.Bucket(this, 'MyBucket', { serverAccessLogsBucket: accessLogsBucket, - serverAccessLogsPrefix: 'logs' + serverAccessLogsPrefix: 'logs', }); ``` @@ -322,8 +334,8 @@ const dataBucket = new s3.Bucket(this, 'DataBucket', { bucket: inventoryBucket, prefix: 'with-all-versions', }, - } - ] + }, + ], }); ``` @@ -356,8 +368,8 @@ You can use the two following properties to specify the bucket [redirection poli You can statically redirect a to a given Bucket URL or any other host name with `websiteRedirect`: ```ts -const bucket = new Bucket(this, 'MyRedirectedBucket', { - websiteRedirect: { hostName: 'www.example.com' } +const bucket = new s3.Bucket(this, 'MyRedirectedBucket', { + websiteRedirect: { hostName: 'www.example.com' }, }); ``` @@ -366,17 +378,17 @@ const bucket = new Bucket(this, 'MyRedirectedBucket', { Alternatively, you can also define multiple `websiteRoutingRules`, to define complex, conditional redirections: ```ts -const bucket = new Bucket(this, 'MyRedirectedBucket', { +const bucket = new s3.Bucket(this, 'MyRedirectedBucket', { websiteRoutingRules: [{ hostName: 'www.example.com', httpRedirectCode: '302', - protocol: RedirectProtocol.HTTPS, - replaceKey: ReplaceKey.prefixWith('test/'), + protocol: s3.RedirectProtocol.HTTPS, + replaceKey: s3.ReplaceKey.prefixWith('test/'), condition: { httpErrorCodeReturnedEquals: '200', keyPrefixEquals: 'prefix', - } - }] + }, + }], }); ``` @@ -397,18 +409,19 @@ We recommend to use Virtual Hosted-Style URL for newly made bucket. You can generate both of them. ```ts +const bucket = new s3.Bucket(this, 'MyBucket'); bucket.urlForObject('objectname'); // Path-Style URL bucket.virtualHostedUrlForObject('objectname'); // Virtual Hosted-Style URL bucket.virtualHostedUrlForObject('objectname', { regional: false }); // Virtual Hosted-Style URL but non-regional ``` -### Object Ownership +## Object Ownership You can use the two following properties to specify the bucket [object Ownership]. [object Ownership]: https://docs.aws.amazon.com/AmazonS3/latest/dev/about-object-ownership.html -#### Object writer +### Object writer The Uploading account will own the object. @@ -418,7 +431,7 @@ new s3.Bucket(this, 'MyBucket', { }); ``` -#### Bucket owner preferred +### Bucket owner preferred The bucket owner will own the object if the object is uploaded with the bucket-owner-full-control canned ACL. Without this setting and canned ACL, the object is uploaded and remains owned by the uploading account. @@ -428,7 +441,7 @@ new s3.Bucket(this, 'MyBucket', { }); ``` -### Bucket deletion +## Bucket deletion When a bucket is removed from a stack (or the stack is deleted), the S3 bucket will be removed according to its removal policy (which by default will @@ -440,8 +453,13 @@ To override this and force all objects to get deleted during bucket deletion, enable the`autoDeleteObjects` option. ```ts -const bucket = new Bucket(this, 'MyTempFileBucket', { - removalPolicy: RemovalPolicy.DESTROY, +const bucket = new s3.Bucket(this, 'MyTempFileBucket', { + removalPolicy: cdk.RemovalPolicy.DESTROY, autoDeleteObjects: true, }); ``` + +**Warning** if you have deployed a bucket with `autoDeleteObjects: true`, +switching this to `false` in a CDK version *before* `1.126.0` will lead to +all objects in the bucket being deleted. Be sure to update your bucket resources +by deploying with CDK version `1.126.0` or later **before** switching this value to `false`. diff --git a/packages/@aws-cdk/aws-s3/jest.config.js b/packages/@aws-cdk/aws-s3/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-s3/jest.config.js +++ b/packages/@aws-cdk/aws-s3/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-s3/lib/auto-delete-objects-handler/index.ts b/packages/@aws-cdk/aws-s3/lib/auto-delete-objects-handler/index.ts index f431aacf3fca2..2459d44ab1d18 100644 --- a/packages/@aws-cdk/aws-s3/lib/auto-delete-objects-handler/index.ts +++ b/packages/@aws-cdk/aws-s3/lib/auto-delete-objects-handler/index.ts @@ -1,6 +1,8 @@ // eslint-disable-next-line import/no-extraneous-dependencies import { S3 } from 'aws-sdk'; +const AUTO_DELETE_OBJECTS_TAG = 'aws-cdk:auto-delete-objects'; + const s3 = new S3(); export async function handler(event: AWSLambda.CloudFormationCustomResourceEvent) { @@ -52,5 +54,29 @@ async function onDelete(bucketName?: string) { if (!bucketName) { throw new Error('No BucketName was provided.'); } - await emptyBucket(bucketName); + if (!await isBucketTaggedForDeletion(bucketName)) { + process.stdout.write(`Bucket does not have '${AUTO_DELETE_OBJECTS_TAG}' tag, skipping cleaning.\n`); + return; + } + try { + await emptyBucket(bucketName); + } catch (e) { + if (e.code !== 'NoSuchBucket') { + throw e; + } + // Bucket doesn't exist. Ignoring + } } + +/** + * The bucket will only be tagged for deletion if it's being deleted in the same + * deployment as this Custom Resource. + * + * If the Custom Resource is every deleted before the bucket, it must be because + * `autoDeleteObjects` has been switched to false, in which case the tag would have + * been removed before we get to this Delete event. + */ +async function isBucketTaggedForDeletion(bucketName: string) { + const response = await s3.getBucketTagging({ Bucket: bucketName }).promise(); + return response.TagSet.some(tag => tag.Key === AUTO_DELETE_OBJECTS_TAG && tag.Value === 'true'); +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-s3/lib/bucket.ts b/packages/@aws-cdk/aws-s3/lib/bucket.ts index 970710c9a3dc4..67037f874bc3e 100644 --- a/packages/@aws-cdk/aws-s3/lib/bucket.ts +++ b/packages/@aws-cdk/aws-s3/lib/bucket.ts @@ -5,7 +5,7 @@ import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; import { Fn, IResource, Lazy, RemovalPolicy, Resource, ResourceProps, Stack, Token, - CustomResource, CustomResourceProvider, CustomResourceProviderRuntime, FeatureFlags, + CustomResource, CustomResourceProvider, CustomResourceProviderRuntime, FeatureFlags, Tags, } from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; import { Construct } from 'constructs'; @@ -18,6 +18,7 @@ import { CfnBucket } from './s3.generated'; import { parseBucketArn, parseBucketName } from './util'; const AUTO_DELETE_OBJECTS_RESOURCE_TYPE = 'Custom::S3AutoDeleteObjects'; +const AUTO_DELETE_OBJECTS_TAG = 'aws-cdk:auto-delete-objects'; export interface IBucket extends IResource { /** @@ -308,7 +309,9 @@ export interface IBucket extends IResource { * * @example * - * bucket.addEventNotification(EventType.OnObjectCreated, myLambda, 'home/myusername/*') + * declare const myLambda: lambda.Function; + * const bucket = new s3.Bucket(this, 'MyBucket'); + * bucket.addEventNotification(s3.EventType.OBJECT_CREATED, new s3n.LambdaDestination(myLambda), {prefix: 'home/myusername/*'}) * * @see * https://docs.aws.amazon.com/AmazonS3/latest/dev/NotificationHowTo.html @@ -318,7 +321,7 @@ export interface IBucket extends IResource { /** * Subscribes a destination to receive notifications when an object is * created in the bucket. This is identical to calling - * `onEvent(EventType.ObjectCreated)`. + * `onEvent(s3.EventType.OBJECT_CREATED)`. * * @param dest The notification destination (see onEvent) * @param filters Filters (see onEvent) @@ -328,7 +331,7 @@ export interface IBucket extends IResource { /** * Subscribes a destination to receive notifications when an object is * removed from the bucket. This is identical to calling - * `onEvent(EventType.ObjectRemoved)`. + * `onEvent(EventType.OBJECT_REMOVED)`. * * @param dest The notification destination (see onEvent) * @param filters Filters (see onEvent) @@ -460,7 +463,7 @@ export abstract class BucketBase extends Resource implements IBucket { * Indicates if a bucket resource policy should automatically created upon * the first call to `addToResourcePolicy`. */ - protected abstract autoCreatePolicy = false; + protected abstract autoCreatePolicy: boolean; /** * Whether to disallow public access @@ -784,7 +787,9 @@ export abstract class BucketBase extends Resource implements IBucket { * * @example * - * bucket.addEventNotification(EventType.OnObjectCreated, myLambda, 'home/myusername/*') + * declare const myLambda: lambda.Function; + * const bucket = new s3.Bucket(this, 'MyBucket'); + * bucket.addEventNotification(s3.EventType.OBJECT_CREATED, new s3n.LambdaDestination(myLambda), {prefix: 'home/myusername/*'}); * * @see * https://docs.aws.amazon.com/AmazonS3/latest/dev/NotificationHowTo.html @@ -796,7 +801,7 @@ export abstract class BucketBase extends Resource implements IBucket { /** * Subscribes a destination to receive notifications when an object is * created in the bucket. This is identical to calling - * `onEvent(EventType.ObjectCreated)`. + * `onEvent(EventType.OBJECT_CREATED)`. * * @param dest The notification destination (see onEvent) * @param filters Filters (see onEvent) @@ -808,7 +813,7 @@ export abstract class BucketBase extends Resource implements IBucket { /** * Subscribes a destination to receive notifications when an object is * removed from the bucket. This is identical to calling - * `onEvent(EventType.ObjectRemoved)`. + * `onEvent(EventType.OBJECT_REMOVED)`. * * @param dest The notification destination (see onEvent) * @param filters Filters (see onEvent) @@ -936,7 +941,7 @@ export interface BucketMetrics { * Specifies a list of tag filters to use as a metrics configuration filter. * The metrics configuration includes only objects that meet the filter's criteria. */ - readonly tagFilters?: {[tag: string]: any}; + readonly tagFilters?: { [tag: string]: any }; } /** @@ -1228,6 +1233,11 @@ export interface BucketProps { * * Requires the `removalPolicy` to be set to `RemovalPolicy.DESTROY`. * + * **Warning** if you have deployed a bucket with `autoDeleteObjects: true`, + * switching this to `false` in a CDK version *before* `1.126.0` will lead to + * all objects in the bucket being deleted. Be sure to update your bucket resources + * by deploying with CDK version `1.126.0` or later **before** switching this value to `false`. + * * @default false */ readonly autoDeleteObjects?: boolean; @@ -1443,6 +1453,7 @@ export class Bucket extends BucketBase { private readonly metrics: BucketMetrics[] = []; private readonly cors: CorsRule[] = []; private readonly inventories: Inventory[] = []; + private readonly _resource: CfnBucket; constructor(scope: Construct, id: string, props: BucketProps = {}) { super(scope, id, { @@ -1470,6 +1481,7 @@ export class Bucket extends BucketBase { inventoryConfigurations: Lazy.any({ produce: () => this.parseInventoryConfiguration() }), ownershipControls: this.parseOwnershipControls(props), }); + this._resource = resource; resource.applyRemovalPolicy(props.removalPolicy); @@ -1789,7 +1801,7 @@ export class Bucket extends BucketBase { } } - private parseTagFilters(tagFilters?: {[tag: string]: any}) { + private parseTagFilters(tagFilters?: { [tag: string]: any }) { if (!tagFilters || tagFilters.length === 0) { return undefined; } @@ -1943,6 +1955,13 @@ export class Bucket extends BucketBase { if (this.policy) { customResource.node.addDependency(this.policy); } + + // We also tag the bucket to record the fact that we want it autodeleted. + // The custom resource will check this tag before actually doing the delete. + // Because tagging and untagging will ALWAYS happen before the CR is deleted, + // we can set `autoDeleteObjects: false` without the removal of the CR emptying + // the bucket as a side effect. + Tags.of(this._resource).add(AUTO_DELETE_OBJECTS_TAG, 'true'); } } diff --git a/packages/@aws-cdk/aws-s3/package.json b/packages/@aws-cdk/aws-s3/package.json index 865be5d5232b8..3117d2919f6a6 100644 --- a/packages/@aws-cdk/aws-s3/package.json +++ b/packages/@aws-cdk/aws-s3/package.json @@ -57,8 +57,7 @@ "cloudformation": "AWS::S3", "env": { "AWSLINT_BASE_CONSTRUCT": "true" - }, - "jest": true + } }, "keywords": [ "aws", @@ -73,14 +72,14 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/aws-lambda": "^8.10.79", + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/aws-lambda": "^8.10.84", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-events": "0.0.0", diff --git a/packages/@aws-cdk/aws-s3/rosetta/default.ts-fixture b/packages/@aws-cdk/aws-s3/rosetta/default.ts-fixture new file mode 100644 index 0000000000000..de01c16af1e9a --- /dev/null +++ b/packages/@aws-cdk/aws-s3/rosetta/default.ts-fixture @@ -0,0 +1,18 @@ +// Fixture with packages imported, but nothing else +import cdk = require('@aws-cdk/core'); +import s3 = require('@aws-cdk/aws-s3'); +import kms = require('@aws-cdk/aws-kms'); +import iam = require('@aws-cdk/aws-iam'); +import lambda = require('@aws-cdk/aws-lambda'); +import s3n = require('@aws-cdk/aws-s3-notifications'); +import sns = require('@aws-cdk/aws-sns'); +import sqs = require('@aws-cdk/aws-sqs'); +import assert = require('assert'); + +class Fixture extends cdk.Stack { + constructor(scope: cdk.Construct, id: string) { + super(scope, id); + + /// here + } +} diff --git a/packages/@aws-cdk/aws-s3/test/auto-delete-objects-handler.test.ts b/packages/@aws-cdk/aws-s3/test/auto-delete-objects-handler.test.ts index b09b9e5e4f5b3..b4b7f523faef2 100644 --- a/packages/@aws-cdk/aws-s3/test/auto-delete-objects-handler.test.ts +++ b/packages/@aws-cdk/aws-s3/test/auto-delete-objects-handler.test.ts @@ -1,6 +1,7 @@ const mockS3Client = { - listObjectVersions: jest.fn().mockReturnThis(), - deleteObjects: jest.fn().mockReturnThis(), + listObjectVersions: jest.fn(), + deleteObjects: jest.fn(), + getBucketTagging: jest.fn(), promise: jest.fn(), }; @@ -13,6 +14,7 @@ jest.mock('aws-sdk', () => { beforeEach(() => { mockS3Client.listObjectVersions.mockReturnThis(); mockS3Client.deleteObjects.mockReturnThis(); + givenTaggedForDeletion(); }); afterEach(() => { @@ -119,7 +121,7 @@ test('does nothing on update event when the new resource properties are absent', test('deletes all objects when the name changes on update event', async () => { // GIVEN - mockS3Client.promise.mockResolvedValue({ // listObjectVersions() call + mockAwsPromise(mockS3Client.listObjectVersions, { Versions: [ { Key: 'Key1', VersionId: 'VersionId1' }, { Key: 'Key2', VersionId: 'VersionId2' }, @@ -158,7 +160,7 @@ test('deletes all objects when the name changes on update event', async () => { test('deletes no objects on delete event when bucket has no objects', async () => { // GIVEN - mockS3Client.promise.mockResolvedValue({ Versions: [] }); // listObjectVersions() call + mockAwsPromise(mockS3Client.listObjectVersions, { Versions: [] }); // WHEN const event: Partial = { @@ -178,7 +180,7 @@ test('deletes no objects on delete event when bucket has no objects', async () = test('deletes all objects on delete event', async () => { // GIVEN - mockS3Client.promise.mockResolvedValue({ // listObjectVersions() call + mockAwsPromise(mockS3Client.listObjectVersions, { Versions: [ { Key: 'Key1', VersionId: 'VersionId1' }, { Key: 'Key2', VersionId: 'VersionId2' }, @@ -210,23 +212,46 @@ test('deletes all objects on delete event', async () => { }); }); +test('does not empty bucket if it is not tagged', async () => { + // GIVEN + givenNotTaggedForDeletion(); + mockAwsPromise(mockS3Client.listObjectVersions, { + Versions: [ + { Key: 'Key1', VersionId: 'VersionId1' }, + { Key: 'Key2', VersionId: 'VersionId2' }, + ], + }); + + // WHEN + const event: Partial = { + RequestType: 'Delete', + ResourceProperties: { + ServiceToken: 'Foo', + BucketName: 'MyBucket', + }, + }; + await invokeHandler(event); + + // THEN + expect(mockS3Client.listObjectVersions).not.toHaveBeenCalled(); +}); + test('delete event where bucket has many objects does recurse appropriately', async () => { // GIVEN - mockS3Client.promise // listObjectVersions() call - .mockResolvedValueOnce({ - Versions: [ - { Key: 'Key1', VersionId: 'VersionId1' }, - { Key: 'Key2', VersionId: 'VersionId2' }, - ], - IsTruncated: true, - }) - .mockResolvedValueOnce(undefined) // deleteObjects() call - .mockResolvedValueOnce({ // listObjectVersions() call - Versions: [ - { Key: 'Key3', VersionId: 'VersionId3' }, - { Key: 'Key4', VersionId: 'VersionId4' }, - ], - }); + mockAwsPromise(mockS3Client.listObjectVersions, { + Versions: [ + { Key: 'Key1', VersionId: 'VersionId1' }, + { Key: 'Key2', VersionId: 'VersionId2' }, + ], + IsTruncated: true, + }, 'once'); + mockAwsPromise(mockS3Client.listObjectVersions, { + Versions: [ + { Key: 'Key3', VersionId: 'VersionId3' }, + { Key: 'Key4', VersionId: 'VersionId4' }, + ], + }, 'once'); + mockAwsPromise(mockS3Client.deleteObjects, {}); // WHEN const event: Partial = { @@ -262,8 +287,49 @@ test('delete event where bucket has many objects does recurse appropriately', as }); }); +test('does nothing when the bucket does not exist', async () => { + // GIVEN + mockS3Client.promise.mockRejectedValue({ code: 'NoSuchBucket' }); + + // WHEN + const event: Partial = { + RequestType: 'Delete', + ResourceProperties: { + ServiceToken: 'Foo', + BucketName: 'MyBucket', + }, + }; + await invokeHandler(event); + + expect(mockS3Client.deleteObjects).not.toHaveBeenCalled(); +}); + // helper function to get around TypeScript expecting a complete event object, // even though our tests only need some of the fields async function invokeHandler(event: Partial) { return handler(event as AWSLambda.CloudFormationCustomResourceEvent); } + +function mockAwsPromise(fn: jest.Mock, value: A, when: 'once' | 'always' = 'always') { + (when === 'always' ? fn.mockReturnValue : fn.mockReturnValueOnce).call(fn, { + promise: () => value, + }); +} + +function givenTaggedForDeletion() { + mockAwsPromise(mockS3Client.getBucketTagging, { + TagSet: [ + { + Key: 'aws-cdk:auto-delete-objects', + Value: 'true', + }, + ], + + }); +} + +function givenNotTaggedForDeletion() { + mockAwsPromise(mockS3Client.getBucketTagging, { + TagSet: [], + }); +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-s3/test/bucket.test.ts b/packages/@aws-cdk/aws-s3/test/bucket.test.ts index d9be67427ab9c..3ef166722c1b6 100644 --- a/packages/@aws-cdk/aws-s3/test/bucket.test.ts +++ b/packages/@aws-cdk/aws-s3/test/bucket.test.ts @@ -5,7 +5,7 @@ import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; import * as cdk from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; -import { testFutureBehavior, testLegacyBehavior } from 'cdk-build-tools/lib/feature-flag'; +import { testFutureBehavior, testLegacyBehavior } from '@aws-cdk/cdk-build-tools/lib/feature-flag'; import * as s3 from '../lib'; // to make it easy to copy & paste from output: diff --git a/packages/@aws-cdk/aws-s3/test/integ.bucket-auto-delete-objects.expected.json b/packages/@aws-cdk/aws-s3/test/integ.bucket-auto-delete-objects.expected.json index 6623d9d3e7a8c..7a935337c08b2 100644 --- a/packages/@aws-cdk/aws-s3/test/integ.bucket-auto-delete-objects.expected.json +++ b/packages/@aws-cdk/aws-s3/test/integ.bucket-auto-delete-objects.expected.json @@ -2,6 +2,14 @@ "Resources": { "Bucket83908E77": { "Type": "AWS::S3::Bucket", + "Properties": { + "Tags": [ + { + "Key": "aws-cdk:auto-delete-objects", + "Value": "true" + } + ] + }, "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete" }, @@ -102,7 +110,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParametersfe5df38824187483182e1459db47adfae2a515aa4caedd437fc4033a0c5b3de9S3BucketD715D8B0" + "Ref": "AssetParameters3993fb4cd942505a050d08b09d5444e14c265cf9cd0fb8b0c5f621446b6cead9S3Bucket4673BB1A" }, "S3Key": { "Fn::Join": [ @@ -115,7 +123,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersfe5df38824187483182e1459db47adfae2a515aa4caedd437fc4033a0c5b3de9S3VersionKey6E76822C" + "Ref": "AssetParameters3993fb4cd942505a050d08b09d5444e14c265cf9cd0fb8b0c5f621446b6cead9S3VersionKey46E40510" } ] } @@ -128,7 +136,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersfe5df38824187483182e1459db47adfae2a515aa4caedd437fc4033a0c5b3de9S3VersionKey6E76822C" + "Ref": "AssetParameters3993fb4cd942505a050d08b09d5444e14c265cf9cd0fb8b0c5f621446b6cead9S3VersionKey46E40510" } ] } @@ -220,7 +228,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParametersf7ee44e9b6217d201200d9abd42c6493b0b11e86be8a7f36163c3ea049c54653S3BucketDB5FAF47" + "Ref": "AssetParameters618bbe9863c0edd5c4ca2e24b5063762f020fafec018cd06f57e2bd9f2f48abfS3BucketE1985B35" }, "S3Key": { "Fn::Join": [ @@ -233,7 +241,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersf7ee44e9b6217d201200d9abd42c6493b0b11e86be8a7f36163c3ea049c54653S3VersionKey9809F0E6" + "Ref": "AssetParameters618bbe9863c0edd5c4ca2e24b5063762f020fafec018cd06f57e2bd9f2f48abfS3VersionKey610C6DE2" } ] } @@ -246,7 +254,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersf7ee44e9b6217d201200d9abd42c6493b0b11e86be8a7f36163c3ea049c54653S3VersionKey9809F0E6" + "Ref": "AssetParameters618bbe9863c0edd5c4ca2e24b5063762f020fafec018cd06f57e2bd9f2f48abfS3VersionKey610C6DE2" } ] } @@ -289,29 +297,29 @@ } }, "Parameters": { - "AssetParametersfe5df38824187483182e1459db47adfae2a515aa4caedd437fc4033a0c5b3de9S3BucketD715D8B0": { + "AssetParameters3993fb4cd942505a050d08b09d5444e14c265cf9cd0fb8b0c5f621446b6cead9S3Bucket4673BB1A": { "Type": "String", - "Description": "S3 bucket for asset \"fe5df38824187483182e1459db47adfae2a515aa4caedd437fc4033a0c5b3de9\"" + "Description": "S3 bucket for asset \"3993fb4cd942505a050d08b09d5444e14c265cf9cd0fb8b0c5f621446b6cead9\"" }, - "AssetParametersfe5df38824187483182e1459db47adfae2a515aa4caedd437fc4033a0c5b3de9S3VersionKey6E76822C": { + "AssetParameters3993fb4cd942505a050d08b09d5444e14c265cf9cd0fb8b0c5f621446b6cead9S3VersionKey46E40510": { "Type": "String", - "Description": "S3 key for asset version \"fe5df38824187483182e1459db47adfae2a515aa4caedd437fc4033a0c5b3de9\"" + "Description": "S3 key for asset version \"3993fb4cd942505a050d08b09d5444e14c265cf9cd0fb8b0c5f621446b6cead9\"" }, - "AssetParametersfe5df38824187483182e1459db47adfae2a515aa4caedd437fc4033a0c5b3de9ArtifactHash9AE3702B": { + "AssetParameters3993fb4cd942505a050d08b09d5444e14c265cf9cd0fb8b0c5f621446b6cead9ArtifactHashBD621721": { "Type": "String", - "Description": "Artifact hash for asset \"fe5df38824187483182e1459db47adfae2a515aa4caedd437fc4033a0c5b3de9\"" + "Description": "Artifact hash for asset \"3993fb4cd942505a050d08b09d5444e14c265cf9cd0fb8b0c5f621446b6cead9\"" }, - "AssetParametersf7ee44e9b6217d201200d9abd42c6493b0b11e86be8a7f36163c3ea049c54653S3BucketDB5FAF47": { + "AssetParameters618bbe9863c0edd5c4ca2e24b5063762f020fafec018cd06f57e2bd9f2f48abfS3BucketE1985B35": { "Type": "String", - "Description": "S3 bucket for asset \"f7ee44e9b6217d201200d9abd42c6493b0b11e86be8a7f36163c3ea049c54653\"" + "Description": "S3 bucket for asset \"618bbe9863c0edd5c4ca2e24b5063762f020fafec018cd06f57e2bd9f2f48abf\"" }, - "AssetParametersf7ee44e9b6217d201200d9abd42c6493b0b11e86be8a7f36163c3ea049c54653S3VersionKey9809F0E6": { + "AssetParameters618bbe9863c0edd5c4ca2e24b5063762f020fafec018cd06f57e2bd9f2f48abfS3VersionKey610C6DE2": { "Type": "String", - "Description": "S3 key for asset version \"f7ee44e9b6217d201200d9abd42c6493b0b11e86be8a7f36163c3ea049c54653\"" + "Description": "S3 key for asset version \"618bbe9863c0edd5c4ca2e24b5063762f020fafec018cd06f57e2bd9f2f48abf\"" }, - "AssetParametersf7ee44e9b6217d201200d9abd42c6493b0b11e86be8a7f36163c3ea049c54653ArtifactHash7CDE16B1": { + "AssetParameters618bbe9863c0edd5c4ca2e24b5063762f020fafec018cd06f57e2bd9f2f48abfArtifactHash467DFC33": { "Type": "String", - "Description": "Artifact hash for asset \"f7ee44e9b6217d201200d9abd42c6493b0b11e86be8a7f36163c3ea049c54653\"" + "Description": "Artifact hash for asset \"618bbe9863c0edd5c4ca2e24b5063762f020fafec018cd06f57e2bd9f2f48abf\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-s3/test/integ.bucket-auto-delete-objects.ts b/packages/@aws-cdk/aws-s3/test/integ.bucket-auto-delete-objects.ts index 8052dd340d888..e89e12c83eeb9 100644 --- a/packages/@aws-cdk/aws-s3/test/integ.bucket-auto-delete-objects.ts +++ b/packages/@aws-cdk/aws-s3/test/integ.bucket-auto-delete-objects.ts @@ -1,3 +1,4 @@ +/// !cdk-integ pragma:ignore-assets import * as path from 'path'; import { App, CustomResource, CustomResourceProvider, CustomResourceProviderRuntime, RemovalPolicy, Stack, StackProps } from '@aws-cdk/core'; import { Construct } from 'constructs'; diff --git a/packages/@aws-cdk/aws-s3/test/put-objects-handler/index.ts b/packages/@aws-cdk/aws-s3/test/put-objects-handler/index.ts index d4137760eb591..4a392db00cb66 100644 --- a/packages/@aws-cdk/aws-s3/test/put-objects-handler/index.ts +++ b/packages/@aws-cdk/aws-s3/test/put-objects-handler/index.ts @@ -6,6 +6,9 @@ const s3 = new S3(); export async function handler(event: AWSLambda.CloudFormationCustomResourceEvent): Promise { switch (event.RequestType) { case 'Create': + if (event.ResourceProperties.Fail) { + throw new Error('Failing on request!'); + } const bucketName = event.ResourceProperties.BucketName; if (!bucketName) { throw new Error('Missing BucketName'); diff --git a/packages/@aws-cdk/aws-s3objectlambda/.eslintrc.js b/packages/@aws-cdk/aws-s3objectlambda/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-s3objectlambda/.eslintrc.js +++ b/packages/@aws-cdk/aws-s3objectlambda/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-s3objectlambda/jest.config.js b/packages/@aws-cdk/aws-s3objectlambda/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-s3objectlambda/jest.config.js +++ b/packages/@aws-cdk/aws-s3objectlambda/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-s3objectlambda/package.json b/packages/@aws-cdk/aws-s3objectlambda/package.json index f8e0d0986fe8a..8890f752cefe4 100644 --- a/packages/@aws-cdk/aws-s3objectlambda/package.json +++ b/packages/@aws-cdk/aws-s3objectlambda/package.json @@ -58,7 +58,6 @@ }, "cdk-build": { "cloudformation": "AWS::S3ObjectLambda", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -77,11 +76,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-s3outposts/.eslintrc.js b/packages/@aws-cdk/aws-s3outposts/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-s3outposts/.eslintrc.js +++ b/packages/@aws-cdk/aws-s3outposts/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-s3outposts/jest.config.js b/packages/@aws-cdk/aws-s3outposts/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-s3outposts/jest.config.js +++ b/packages/@aws-cdk/aws-s3outposts/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-s3outposts/package.json b/packages/@aws-cdk/aws-s3outposts/package.json index da5317e14e7b3..930f149e5fb6e 100644 --- a/packages/@aws-cdk/aws-s3outposts/package.json +++ b/packages/@aws-cdk/aws-s3outposts/package.json @@ -58,7 +58,6 @@ }, "cdk-build": { "cloudformation": "AWS::S3Outposts", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -77,11 +76,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-sagemaker/.eslintrc.js b/packages/@aws-cdk/aws-sagemaker/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-sagemaker/.eslintrc.js +++ b/packages/@aws-cdk/aws-sagemaker/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-sagemaker/jest.config.js b/packages/@aws-cdk/aws-sagemaker/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-sagemaker/jest.config.js +++ b/packages/@aws-cdk/aws-sagemaker/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-sagemaker/package.json b/packages/@aws-cdk/aws-sagemaker/package.json index 136d5ad52ea25..538e00d0afb5a 100644 --- a/packages/@aws-cdk/aws-sagemaker/package.json +++ b/packages/@aws-cdk/aws-sagemaker/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::SageMaker", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -74,11 +73,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-sam/.eslintrc.js b/packages/@aws-cdk/aws-sam/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-sam/.eslintrc.js +++ b/packages/@aws-cdk/aws-sam/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-sam/jest.config.js b/packages/@aws-cdk/aws-sam/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-sam/jest.config.js +++ b/packages/@aws-cdk/aws-sam/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-sam/package.json b/packages/@aws-cdk/aws-sam/package.json index 9083b5b5d83bf..9bd8d5caa4a13 100644 --- a/packages/@aws-cdk/aws-sam/package.json +++ b/packages/@aws-cdk/aws-sam/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::Serverless", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -74,13 +73,13 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", "jest": "^26.6.3", - "pkglint": "0.0.0", - "ts-jest": "^26.5.6", - "@aws-cdk/assertions": "0.0.0" + "ts-jest": "^26.5.6" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-sdb/.eslintrc.js b/packages/@aws-cdk/aws-sdb/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-sdb/.eslintrc.js +++ b/packages/@aws-cdk/aws-sdb/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-sdb/jest.config.js b/packages/@aws-cdk/aws-sdb/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-sdb/jest.config.js +++ b/packages/@aws-cdk/aws-sdb/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-sdb/package.json b/packages/@aws-cdk/aws-sdb/package.json index 9863fe0333e24..cce3519d22c62 100644 --- a/packages/@aws-cdk/aws-sdb/package.json +++ b/packages/@aws-cdk/aws-sdb/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::SDB", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,11 +72,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-secretsmanager/.eslintrc.js b/packages/@aws-cdk/aws-secretsmanager/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-secretsmanager/.eslintrc.js +++ b/packages/@aws-cdk/aws-secretsmanager/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-secretsmanager/jest.config.js b/packages/@aws-cdk/aws-secretsmanager/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-secretsmanager/jest.config.js +++ b/packages/@aws-cdk/aws-secretsmanager/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-secretsmanager/package.json b/packages/@aws-cdk/aws-secretsmanager/package.json index 8e465f8d54c77..9cc6876067018 100644 --- a/packages/@aws-cdk/aws-secretsmanager/package.json +++ b/packages/@aws-cdk/aws-secretsmanager/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::SecretsManager", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -74,12 +73,12 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/aws-ec2": "0.0.0", diff --git a/packages/@aws-cdk/aws-secretsmanager/test/secret.test.ts b/packages/@aws-cdk/aws-secretsmanager/test/secret.test.ts index d3da8d52a6c74..7f154c77b5f7f 100644 --- a/packages/@aws-cdk/aws-secretsmanager/test/secret.test.ts +++ b/packages/@aws-cdk/aws-secretsmanager/test/secret.test.ts @@ -4,7 +4,7 @@ import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; import * as lambda from '@aws-cdk/aws-lambda'; import * as cdk from '@aws-cdk/core'; -import { testFutureBehavior, testLegacyBehavior } from 'cdk-build-tools/lib/feature-flag'; +import { testFutureBehavior, testLegacyBehavior } from '@aws-cdk/cdk-build-tools/lib/feature-flag'; import * as secretsmanager from '../lib'; let app: cdk.App; diff --git a/packages/@aws-cdk/aws-securityhub/.eslintrc.js b/packages/@aws-cdk/aws-securityhub/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-securityhub/.eslintrc.js +++ b/packages/@aws-cdk/aws-securityhub/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-securityhub/jest.config.js b/packages/@aws-cdk/aws-securityhub/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-securityhub/jest.config.js +++ b/packages/@aws-cdk/aws-securityhub/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-securityhub/package.json b/packages/@aws-cdk/aws-securityhub/package.json index e71153d4822ad..b4102e4918385 100644 --- a/packages/@aws-cdk/aws-securityhub/package.json +++ b/packages/@aws-cdk/aws-securityhub/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::SecurityHub", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-servicecatalog/.eslintrc.js b/packages/@aws-cdk/aws-servicecatalog/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-servicecatalog/.eslintrc.js +++ b/packages/@aws-cdk/aws-servicecatalog/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-servicecatalog/jest.config.js b/packages/@aws-cdk/aws-servicecatalog/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-servicecatalog/jest.config.js +++ b/packages/@aws-cdk/aws-servicecatalog/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-servicecatalog/lib/cloudformation-template.ts b/packages/@aws-cdk/aws-servicecatalog/lib/cloudformation-template.ts index 670ff1bd4de1f..be0cb9adf2022 100644 --- a/packages/@aws-cdk/aws-servicecatalog/lib/cloudformation-template.ts +++ b/packages/@aws-cdk/aws-servicecatalog/lib/cloudformation-template.ts @@ -1,4 +1,5 @@ import * as s3_assets from '@aws-cdk/aws-s3-assets'; +import { hashValues } from './private/util'; // keep this import separate from other imports to reduce chance for merge conflicts with v2-main // eslint-disable-next-line no-duplicate-imports, import/order @@ -76,7 +77,7 @@ class CloudFormationAssetTemplate extends CloudFormationTemplate { public bind(scope: Construct): CloudFormationTemplateConfig { // If the same AssetCode is used multiple times, retain only the first instantiation. if (!this.asset) { - this.asset = new s3_assets.Asset(scope, 'Template', { + this.asset = new s3_assets.Asset(scope, `Template${hashValues(this.path)}`, { path: this.path, ...this.options, }); diff --git a/packages/@aws-cdk/aws-servicecatalog/package.json b/packages/@aws-cdk/aws-servicecatalog/package.json index bc482eedff82e..de3bfcfb667a5 100644 --- a/packages/@aws-cdk/aws-servicecatalog/package.json +++ b/packages/@aws-cdk/aws-servicecatalog/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::ServiceCatalog", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -74,11 +73,11 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assertions": "0.0.0", - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/aws-iam": "0.0.0", diff --git a/packages/@aws-cdk/aws-servicecatalog/test/integ.product.expected.json b/packages/@aws-cdk/aws-servicecatalog/test/integ.product.expected.json index 91767f1182eb6..786fdcad0f8fc 100644 --- a/packages/@aws-cdk/aws-servicecatalog/test/integ.product.expected.json +++ b/packages/@aws-cdk/aws-servicecatalog/test/integ.product.expected.json @@ -62,6 +62,57 @@ ] } } + }, + { + "DisableTemplateValidation": false, + "Info": { + "LoadTemplateFromURL": { + "Fn::Join": [ + "", + [ + "https://s3.", + { + "Ref": "AWS::Region" + }, + ".", + { + "Ref": "AWS::URLSuffix" + }, + "/", + { + "Ref": "AssetParameters6412a5f4524c6b41d26fbeee226c68c2dad735393940a51008d77e6f8b1038f5S3Bucket85C3FF42" + }, + "/", + { + "Fn::Select": [ + 0, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParameters6412a5f4524c6b41d26fbeee226c68c2dad735393940a51008d77e6f8b1038f5S3VersionKey34A02667" + } + ] + } + ] + }, + { + "Fn::Select": [ + 1, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParameters6412a5f4524c6b41d26fbeee226c68c2dad735393940a51008d77e6f8b1038f5S3VersionKey34A02667" + } + ] + } + ] + } + ] + ] + } + } } ] } @@ -79,6 +130,18 @@ "AssetParametersb59f768286e16b69628bb23b9c1a1f07300a24101b8979d8e2a94ff1ab03d09eArtifactHashB9EF04B2": { "Type": "String", "Description": "Artifact hash for asset \"b59f768286e16b69628bb23b9c1a1f07300a24101b8979d8e2a94ff1ab03d09e\"" + }, + "AssetParameters6412a5f4524c6b41d26fbeee226c68c2dad735393940a51008d77e6f8b1038f5S3Bucket85C3FF42": { + "Type": "String", + "Description": "S3 bucket for asset \"6412a5f4524c6b41d26fbeee226c68c2dad735393940a51008d77e6f8b1038f5\"" + }, + "AssetParameters6412a5f4524c6b41d26fbeee226c68c2dad735393940a51008d77e6f8b1038f5S3VersionKey34A02667": { + "Type": "String", + "Description": "S3 key for asset version \"6412a5f4524c6b41d26fbeee226c68c2dad735393940a51008d77e6f8b1038f5\"" + }, + "AssetParameters6412a5f4524c6b41d26fbeee226c68c2dad735393940a51008d77e6f8b1038f5ArtifactHashDC26AFAC": { + "Type": "String", + "Description": "Artifact hash for asset \"6412a5f4524c6b41d26fbeee226c68c2dad735393940a51008d77e6f8b1038f5\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-servicecatalog/test/integ.product.ts b/packages/@aws-cdk/aws-servicecatalog/test/integ.product.ts index 578f85e5e1d68..5c4192cc9b25c 100644 --- a/packages/@aws-cdk/aws-servicecatalog/test/integ.product.ts +++ b/packages/@aws-cdk/aws-servicecatalog/test/integ.product.ts @@ -15,7 +15,10 @@ new servicecatalog.CloudFormationProduct(stack, 'TestProduct', { 'https://awsdocs.s3.amazonaws.com/servicecatalog/development-environment.template'), }, { - cloudFormationTemplate: servicecatalog.CloudFormationTemplate.fromAsset(path.join(__dirname, 'development-environment.template.json')), + cloudFormationTemplate: servicecatalog.CloudFormationTemplate.fromAsset(path.join(__dirname, 'product1.template.json')), + }, + { + cloudFormationTemplate: servicecatalog.CloudFormationTemplate.fromAsset(path.join(__dirname, 'product2.template.json')), }, ], }); diff --git a/packages/@aws-cdk/aws-servicecatalog/test/product.test.ts b/packages/@aws-cdk/aws-servicecatalog/test/product.test.ts index 57f4e50bda0c0..f3e485b30e951 100644 --- a/packages/@aws-cdk/aws-servicecatalog/test/product.test.ts +++ b/packages/@aws-cdk/aws-servicecatalog/test/product.test.ts @@ -70,7 +70,7 @@ describe('Product', () => { owner: 'testOwner', productVersions: [ { - cloudFormationTemplate: servicecatalog.CloudFormationTemplate.fromAsset(path.join(__dirname, 'development-environment.template.json')), + cloudFormationTemplate: servicecatalog.CloudFormationTemplate.fromAsset(path.join(__dirname, 'product1.template.json')), }, ], }); @@ -80,6 +80,27 @@ describe('Product', () => { expect(synthesized.assets.length).toEqual(1); }), + test('multiple product versions from Assets', () => { + new servicecatalog.CloudFormationProduct(stack, 'MyProduct', { + productName: 'testProduct', + owner: 'testOwner', + productVersions: [ + { + productVersionName: 'v1', + cloudFormationTemplate: servicecatalog.CloudFormationTemplate.fromAsset(path.join(__dirname, 'product1.template.json')), + }, + { + productVersionName: 'v2', + cloudFormationTemplate: servicecatalog.CloudFormationTemplate.fromAsset(path.join(__dirname, 'product2.template.json')), + }, + ], + }); + + const assembly = app.synth(); + const synthesized = assembly.stacks[0]; + expect(synthesized.assets.length).toEqual(2); + }), + test('product test from multiple sources', () => { new servicecatalog.CloudFormationProduct(stack, 'MyProduct', { productName: 'testProduct', @@ -95,7 +116,7 @@ describe('Product', () => { }, { productVersionName: 'v3', - cloudFormationTemplate: servicecatalog.CloudFormationTemplate.fromAsset(path.join(__dirname, 'development-environment.template.json')), + cloudFormationTemplate: servicecatalog.CloudFormationTemplate.fromAsset(path.join(__dirname, 'product1.template.json')), }, ], }); diff --git a/packages/@aws-cdk/aws-servicecatalog/test/development-environment.template.json b/packages/@aws-cdk/aws-servicecatalog/test/product1.template.json similarity index 100% rename from packages/@aws-cdk/aws-servicecatalog/test/development-environment.template.json rename to packages/@aws-cdk/aws-servicecatalog/test/product1.template.json diff --git a/packages/@aws-cdk/aws-servicecatalog/test/product2.template.json b/packages/@aws-cdk/aws-servicecatalog/test/product2.template.json new file mode 100644 index 0000000000000..9785ab36f253f --- /dev/null +++ b/packages/@aws-cdk/aws-servicecatalog/test/product2.template.json @@ -0,0 +1,98 @@ +{ + "AWSTemplateFormatVersion" : "2010-09-09", + + "Description" : "AWS Service Catalog sample template. Creates an Amazon EC2 instance running the Amazon Linux AMI. The AMI is chosen based on the region in which the stack is run. This example creates an EC2 security group for the instance to give you SSH access. **WARNING** This template creates an Amazon EC2 instance. You will be billed for the AWS resources used if you create a stack from this template.", + + "Parameters" : { + "KeyName": { + "Description" : "Name of an existing EC2 key pair for SSH access to the EC2 instance.", + "Type": "AWS::EC2::KeyPair::KeyName" + }, + + "InstanceType" : { + "Description" : "EC2 instance type.", + "Type" : "String", + "Default" : "t2.micro", + "AllowedValues" : [ "t2.micro", "t2.small", "t2.medium"] + }, + + "SSHLocation" : { + "Description" : "The IP address range that can SSH to the EC2 instance.", + "Type": "String", + "MinLength": "9", + "MaxLength": "18", + "Default": "0.0.0.0/0", + "AllowedPattern": "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})/(\\d{1,2})", + "ConstraintDescription": "Must be a valid IP CIDR range of the form x.x.x.x/x." + } + }, + + "Metadata" : { + "AWS::CloudFormation::Interface" : { + "ParameterGroups" : [{ + "Label" : {"default": "Instance configuration"}, + "Parameters" : ["InstanceType"] + },{ + "Label" : {"default": "Security configuration"}, + "Parameters" : ["KeyName", "SSHLocation"] + }], + "ParameterLabels" : { + "InstanceType": {"default": "Server size:"}, + "KeyName": {"default": "Key pair:"}, + "SSHLocation": {"default": "CIDR range:"} + } + } + }, + + "Mappings" : { + "AWSRegionArch2AMI" : { + "us-east-1" : { "HVM64" : "ami-08842d60" }, + "us-west-2" : { "HVM64" : "ami-8786c6b7" }, + "us-west-1" : { "HVM64" : "ami-cfa8a18a" }, + "eu-west-1" : { "HVM64" : "ami-748e2903" }, + "ap-southeast-1" : { "HVM64" : "ami-d6e1c584" }, + "ap-northeast-1" : { "HVM64" : "ami-35072834" }, + "ap-southeast-2" : { "HVM64" : "ami-fd4724c7" }, + "sa-east-1" : { "HVM64" : "ami-956cc688" }, + "cn-north-1" : { "HVM64" : "ami-ac57c595" }, + "eu-central-1" : { "HVM64" : "ami-b43503a9" } + } + + }, + + "Resources" : { + "EC2Instance" : { + "Type" : "AWS::EC2::Instance", + "Properties" : { + "InstanceType" : { "Ref" : "InstanceType" }, + "SecurityGroups" : [ { "Ref" : "InstanceSecurityGroup" } ], + "KeyName" : { "Ref" : "KeyName" }, + "ImageId" : { "Fn::FindInMap" : [ "AWSRegionArch2AMI", { "Ref" : "AWS::Region" }, "HVM64" ] } + } + }, + + "InstanceSecurityGroup" : { + "Type" : "AWS::EC2::SecurityGroup", + "Properties" : { + "GroupDescription" : "Enable SSH access via port 22", + "SecurityGroupIngress" : [ { + "IpProtocol" : "tcp", + "FromPort" : "22", + "ToPort" : "22", + "CidrIp" : { "Ref" : "SSHLocation"} + } ] + } + } + }, + + "Outputs" : { + "PublicDNSName" : { + "Description" : "Public DNS name of the new EC2 instance", + "Value" : { "Fn::GetAtt" : [ "EC2Instance", "PublicDnsName" ] } + }, + "PublicIPAddress" : { + "Description" : "Public IP address of the new EC2 instance", + "Value" : { "Fn::GetAtt" : [ "EC2Instance", "PublicIp" ] } + } + } +} diff --git a/packages/@aws-cdk/aws-servicecatalogappregistry/.eslintrc.js b/packages/@aws-cdk/aws-servicecatalogappregistry/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-servicecatalogappregistry/.eslintrc.js +++ b/packages/@aws-cdk/aws-servicecatalogappregistry/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-servicecatalogappregistry/jest.config.js b/packages/@aws-cdk/aws-servicecatalogappregistry/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-servicecatalogappregistry/jest.config.js +++ b/packages/@aws-cdk/aws-servicecatalogappregistry/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-servicecatalogappregistry/package.json b/packages/@aws-cdk/aws-servicecatalogappregistry/package.json index 921cb1fd4de60..440022bde6091 100644 --- a/packages/@aws-cdk/aws-servicecatalogappregistry/package.json +++ b/packages/@aws-cdk/aws-servicecatalogappregistry/package.json @@ -58,7 +58,6 @@ }, "cdk-build": { "cloudformation": "AWS::ServiceCatalogAppRegistry", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -78,11 +77,11 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assertions": "0.0.0", - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-servicediscovery/.eslintrc.js b/packages/@aws-cdk/aws-servicediscovery/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-servicediscovery/.eslintrc.js +++ b/packages/@aws-cdk/aws-servicediscovery/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-servicediscovery/jest.config.js b/packages/@aws-cdk/aws-servicediscovery/jest.config.js index cd664e1d069e5..34818e1593f6b 100644 --- a/packages/@aws-cdk/aws-servicediscovery/jest.config.js +++ b/packages/@aws-cdk/aws-servicediscovery/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +const baseConfig = require('../../../tools/@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-servicediscovery/package.json b/packages/@aws-cdk/aws-servicediscovery/package.json index f23d76efe7566..4169aaadae0ca 100644 --- a/packages/@aws-cdk/aws-servicediscovery/package.json +++ b/packages/@aws-cdk/aws-servicediscovery/package.json @@ -57,8 +57,7 @@ "cloudformation": "AWS::ServiceDiscovery", "env": { "AWSLINT_BASE_CONSTRUCT": true - }, - "jest": true + } }, "nyc": { "statements": 75 @@ -76,13 +75,13 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-ec2": "0.0.0", diff --git a/packages/@aws-cdk/aws-ses-actions/.eslintrc.js b/packages/@aws-cdk/aws-ses-actions/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-ses-actions/.eslintrc.js +++ b/packages/@aws-cdk/aws-ses-actions/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-ses-actions/jest.config.js b/packages/@aws-cdk/aws-ses-actions/jest.config.js index fc310b5014407..d052cbb29f05d 100644 --- a/packages/@aws-cdk/aws-ses-actions/jest.config.js +++ b/packages/@aws-cdk/aws-ses-actions/jest.config.js @@ -1,4 +1,4 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = { ...baseConfig, coverageThreshold: { diff --git a/packages/@aws-cdk/aws-ses-actions/package.json b/packages/@aws-cdk/aws-ses-actions/package.json index 37ead111df047..5f5be5276102c 100644 --- a/packages/@aws-cdk/aws-ses-actions/package.json +++ b/packages/@aws-cdk/aws-ses-actions/package.json @@ -65,13 +65,13 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-iam": "0.0.0", @@ -115,7 +115,6 @@ "announce": false }, "cdk-build": { - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } diff --git a/packages/@aws-cdk/aws-ses-actions/test/integ.actions.expected.json b/packages/@aws-cdk/aws-ses-actions/test/integ.actions.expected.json index 4379649e02d69..fbb346b959470 100644 --- a/packages/@aws-cdk/aws-ses-actions/test/integ.actions.expected.json +++ b/packages/@aws-cdk/aws-ses-actions/test/integ.actions.expected.json @@ -385,7 +385,7 @@ ] }, "Handler": "index.handler", - "Runtime": "nodejs14.x" + "Runtime": "nodejs12.x" }, "DependsOn": [ "SingletonLambda224e77f9a32e4b4dac32983477abba16ServiceRole3037F5B4" diff --git a/packages/@aws-cdk/aws-ses/.eslintrc.js b/packages/@aws-cdk/aws-ses/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-ses/.eslintrc.js +++ b/packages/@aws-cdk/aws-ses/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-ses/jest.config.js b/packages/@aws-cdk/aws-ses/jest.config.js index cd664e1d069e5..34818e1593f6b 100644 --- a/packages/@aws-cdk/aws-ses/jest.config.js +++ b/packages/@aws-cdk/aws-ses/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +const baseConfig = require('../../../tools/@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-ses/lib/receipt-rule.ts b/packages/@aws-cdk/aws-ses/lib/receipt-rule.ts index 7f6f1fe914a6b..7d6a4bad92bb0 100644 --- a/packages/@aws-cdk/aws-ses/lib/receipt-rule.ts +++ b/packages/@aws-cdk/aws-ses/lib/receipt-rule.ts @@ -176,7 +176,7 @@ export class DropSpamReceiptRule extends CoreConstruct { super(scope, id); const fn = new lambda.SingletonFunction(this, 'Function', { - runtime: lambda.Runtime.NODEJS_14_X, + runtime: lambda.Runtime.NODEJS_12_X, handler: 'index.handler', code: lambda.Code.fromAsset(path.join(__dirname, 'drop-spam-handler')), uuid: '224e77f9-a32e-4b4d-ac32-983477abba16', diff --git a/packages/@aws-cdk/aws-ses/package.json b/packages/@aws-cdk/aws-ses/package.json index 4c2c765ef6982..a2a797e38b8cb 100644 --- a/packages/@aws-cdk/aws-ses/package.json +++ b/packages/@aws-cdk/aws-ses/package.json @@ -57,8 +57,7 @@ "cloudformation": "AWS::SES", "env": { "AWSLINT_BASE_CONSTRUCT": true - }, - "jest": true + } }, "keywords": [ "aws", @@ -73,14 +72,14 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/aws-lambda": "^8.10.79", + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/aws-lambda": "^8.10.84", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-iam": "0.0.0", diff --git a/packages/@aws-cdk/aws-ses/test/integ.receipt.expected.json b/packages/@aws-cdk/aws-ses/test/integ.receipt.expected.json index 0a9442a97f6a0..f0a9a624f4f3f 100644 --- a/packages/@aws-cdk/aws-ses/test/integ.receipt.expected.json +++ b/packages/@aws-cdk/aws-ses/test/integ.receipt.expected.json @@ -141,7 +141,7 @@ ] }, "Handler": "index.handler", - "Runtime": "nodejs14.x" + "Runtime": "nodejs12.x" }, "DependsOn": [ "SingletonLambda224e77f9a32e4b4dac32983477abba16ServiceRole3037F5B4" diff --git a/packages/@aws-cdk/aws-signer/.eslintrc.js b/packages/@aws-cdk/aws-signer/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-signer/.eslintrc.js +++ b/packages/@aws-cdk/aws-signer/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-signer/jest.config.js b/packages/@aws-cdk/aws-signer/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-signer/jest.config.js +++ b/packages/@aws-cdk/aws-signer/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-signer/package.json b/packages/@aws-cdk/aws-signer/package.json index e0318b1bcf011..84489e43c845b 100644 --- a/packages/@aws-cdk/aws-signer/package.json +++ b/packages/@aws-cdk/aws-signer/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::Signer", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-sns-subscriptions/.eslintrc.js b/packages/@aws-cdk/aws-sns-subscriptions/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-sns-subscriptions/.eslintrc.js +++ b/packages/@aws-cdk/aws-sns-subscriptions/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-sns-subscriptions/jest.config.js b/packages/@aws-cdk/aws-sns-subscriptions/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-sns-subscriptions/jest.config.js +++ b/packages/@aws-cdk/aws-sns-subscriptions/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-sns-subscriptions/package.json b/packages/@aws-cdk/aws-sns-subscriptions/package.json index 9d0b4db805c67..9bc3880a4ba23 100644 --- a/packages/@aws-cdk/aws-sns-subscriptions/package.json +++ b/packages/@aws-cdk/aws-sns-subscriptions/package.json @@ -64,13 +64,13 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-iam": "0.0.0", @@ -100,7 +100,6 @@ }, "maturity": "stable", "cdk-build": { - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } diff --git a/packages/@aws-cdk/aws-sns/.eslintrc.js b/packages/@aws-cdk/aws-sns/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-sns/.eslintrc.js +++ b/packages/@aws-cdk/aws-sns/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-sns/jest.config.js b/packages/@aws-cdk/aws-sns/jest.config.js index 1f611abd50de4..dcc7c22a3aae9 100644 --- a/packages/@aws-cdk/aws-sns/jest.config.js +++ b/packages/@aws-cdk/aws-sns/jest.config.js @@ -1,4 +1,4 @@ -const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +const baseConfig = require('../../../tools/@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = { ...baseConfig, coverageThreshold: { diff --git a/packages/@aws-cdk/aws-sns/lib/subscription-filter.ts b/packages/@aws-cdk/aws-sns/lib/subscription-filter.ts index c6fc1be95d247..69be08bb1db26 100644 --- a/packages/@aws-cdk/aws-sns/lib/subscription-filter.ts +++ b/packages/@aws-cdk/aws-sns/lib/subscription-filter.ts @@ -162,19 +162,19 @@ export class SubscriptionFilter { conditions.push(...allowlist.map(v => ({ numeric: ['=', v] }))); } - if (numericConditions.greaterThan) { + if (numericConditions.greaterThan !== undefined) { conditions.push({ numeric: ['>', numericConditions.greaterThan] }); } - if (numericConditions.greaterThanOrEqualTo) { + if (numericConditions.greaterThanOrEqualTo !== undefined) { conditions.push({ numeric: ['>=', numericConditions.greaterThanOrEqualTo] }); } - if (numericConditions.lessThan) { + if (numericConditions.lessThan !== undefined) { conditions.push({ numeric: ['<', numericConditions.lessThan] }); } - if (numericConditions.lessThanOrEqualTo) { + if (numericConditions.lessThanOrEqualTo !== undefined) { conditions.push({ numeric: ['<=', numericConditions.lessThanOrEqualTo] }); } diff --git a/packages/@aws-cdk/aws-sns/package.json b/packages/@aws-cdk/aws-sns/package.json index 26d7441d5ee6d..8e27308a61703 100644 --- a/packages/@aws-cdk/aws-sns/package.json +++ b/packages/@aws-cdk/aws-sns/package.json @@ -58,7 +58,6 @@ }, "cdk-build": { "cloudformation": "AWS::SNS", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -78,12 +77,12 @@ "devDependencies": { "@aws-cdk/assertions": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-cloudwatch": "0.0.0", diff --git a/packages/@aws-cdk/aws-sns/test/subscription.test.ts b/packages/@aws-cdk/aws-sns/test/subscription.test.ts index a495769648d4b..dd0f9588d2296 100644 --- a/packages/@aws-cdk/aws-sns/test/subscription.test.ts +++ b/packages/@aws-cdk/aws-sns/test/subscription.test.ts @@ -153,6 +153,40 @@ describe('Subscription', () => { }); + test('with numeric filter and 0 values', () => { + // GIVEN + const stack = new cdk.Stack(); + const topic = new sns.Topic(stack, 'Topic'); + + // WHEN + new sns.Subscription(stack, 'Subscription', { + endpoint: 'endpoint', + filterPolicy: { + price: sns.SubscriptionFilter.numericFilter({ + greaterThan: 0, + greaterThanOrEqualTo: 0, + lessThan: 0, + lessThanOrEqualTo: 0, + }), + }, + protocol: sns.SubscriptionProtocol.LAMBDA, + topic, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::SNS::Subscription', { + FilterPolicy: { + price: [ + { numeric: ['>', 0] }, + { numeric: ['>=', 0] }, + { numeric: ['<', 0] }, + { numeric: ['<=', 0] }, + ], + }, + }); + + }); + test('with existsFilter', () => { // GIVEN const stack = new cdk.Stack(); diff --git a/packages/@aws-cdk/aws-sqs/.eslintrc.js b/packages/@aws-cdk/aws-sqs/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-sqs/.eslintrc.js +++ b/packages/@aws-cdk/aws-sqs/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-sqs/.gitignore b/packages/@aws-cdk/aws-sqs/.gitignore index d0a956699806b..be330198b9888 100644 --- a/packages/@aws-cdk/aws-sqs/.gitignore +++ b/packages/@aws-cdk/aws-sqs/.gitignore @@ -16,4 +16,5 @@ nyc.config.js *.snk !.eslintrc.js -junit.xml \ No newline at end of file +junit.xml +!jest.config.js \ No newline at end of file diff --git a/packages/@aws-cdk/aws-sqs/.npmignore b/packages/@aws-cdk/aws-sqs/.npmignore index 9a032ae80868c..e8acf10a468a1 100644 --- a/packages/@aws-cdk/aws-sqs/.npmignore +++ b/packages/@aws-cdk/aws-sqs/.npmignore @@ -24,4 +24,5 @@ tsconfig.json **/cdk.out junit.xml test/ -!*.lit.ts \ No newline at end of file +!*.lit.ts +jest.config.js \ No newline at end of file diff --git a/packages/@aws-cdk/aws-sqs/jest.config.js b/packages/@aws-cdk/aws-sqs/jest.config.js new file mode 100644 index 0000000000000..34818e1593f6b --- /dev/null +++ b/packages/@aws-cdk/aws-sqs/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/@aws-cdk/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-sqs/lib/policy.ts b/packages/@aws-cdk/aws-sqs/lib/policy.ts index c5d323bf60c63..f4116205e69c2 100644 --- a/packages/@aws-cdk/aws-sqs/lib/policy.ts +++ b/packages/@aws-cdk/aws-sqs/lib/policy.ts @@ -23,12 +23,20 @@ export class QueuePolicy extends Resource { */ public readonly document = new PolicyDocument(); + /** + * Not currently supported by AWS CloudFormation. + * @attribute + */ + public readonly queuePolicyId: string; + constructor(scope: Construct, id: string, props: QueuePolicyProps) { super(scope, id); - new CfnQueuePolicy(this, 'Resource', { + const resource = new CfnQueuePolicy(this, 'Resource', { policyDocument: this.document, queues: props.queues.map(q => q.queueUrl), }); + + this.queuePolicyId = resource.attrId; } } diff --git a/packages/@aws-cdk/aws-sqs/package.json b/packages/@aws-cdk/aws-sqs/package.json index 7daec64f522f5..d3ab48584fd61 100644 --- a/packages/@aws-cdk/aws-sqs/package.json +++ b/packages/@aws-cdk/aws-sqs/package.json @@ -72,15 +72,15 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", - "@types/nodeunit": "^0.0.32", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24", "aws-sdk": "^2.848.0", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "nodeunit": "^0.11.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-cloudwatch": "0.0.0", diff --git a/packages/@aws-cdk/aws-sqs/test/sqs.test.ts b/packages/@aws-cdk/aws-sqs/test/sqs.test.ts new file mode 100644 index 0000000000000..3f86e6d68b6da --- /dev/null +++ b/packages/@aws-cdk/aws-sqs/test/sqs.test.ts @@ -0,0 +1,601 @@ +import { ResourcePart } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; +import * as iam from '@aws-cdk/aws-iam'; +import * as kms from '@aws-cdk/aws-kms'; +import { CfnParameter, Duration, Stack, App, Token } from '@aws-cdk/core'; +import * as sqs from '../lib'; + +/* eslint-disable quote-props */ + +test('default properties', () => { + const stack = new Stack(); + const q = new sqs.Queue(stack, 'Queue'); + + expect(q.fifo).toEqual(false); + + expect(stack).toMatchTemplate({ + 'Resources': { + 'Queue4A7E3555': { + 'Type': 'AWS::SQS::Queue', + 'UpdateReplacePolicy': 'Delete', + 'DeletionPolicy': 'Delete', + }, + }, + }); + + expect(stack).toHaveResource('AWS::SQS::Queue', { + DeletionPolicy: 'Delete', + }, ResourcePart.CompleteDefinition); +}); + +test('with a dead letter queue', () => { + const stack = new Stack(); + const dlq = new sqs.Queue(stack, 'DLQ'); + new sqs.Queue(stack, 'Queue', { deadLetterQueue: { queue: dlq, maxReceiveCount: 3 } }); + + expect(stack).toMatchTemplate({ + 'Resources': { + 'DLQ581697C4': { + 'Type': 'AWS::SQS::Queue', + 'UpdateReplacePolicy': 'Delete', + 'DeletionPolicy': 'Delete', + }, + 'Queue4A7E3555': { + 'Type': 'AWS::SQS::Queue', + 'Properties': { + 'RedrivePolicy': { + 'deadLetterTargetArn': { + 'Fn::GetAtt': [ + 'DLQ581697C4', + 'Arn', + ], + }, + 'maxReceiveCount': 3, + }, + }, + 'UpdateReplacePolicy': 'Delete', + 'DeletionPolicy': 'Delete', + }, + }, + }); +}); + +test('message retention period must be between 1 minute to 14 days', () => { + // GIVEN + const stack = new Stack(); + + // THEN + expect(() => new sqs.Queue(stack, 'MyQueue', { + retentionPeriod: Duration.seconds(30), + })).toThrow(/message retention period must be 60 seconds or more/); + + expect(() => new sqs.Queue(stack, 'AnotherQueue', { + retentionPeriod: Duration.days(15), + })).toThrow(/message retention period must be 1209600 seconds or less/); +}); + +test('message retention period can be provided as a parameter', () => { + // GIVEN + const stack = new Stack(); + const parameter = new CfnParameter(stack, 'my-retention-period', { + type: 'Number', + default: 30, + }); + + // WHEN + new sqs.Queue(stack, 'MyQueue', { + retentionPeriod: Duration.seconds(parameter.valueAsNumber), + }); + + // THEN + expect(stack).toMatchTemplate({ + 'Parameters': { + 'myretentionperiod': { + 'Type': 'Number', + 'Default': 30, + }, + }, + 'Resources': { + 'MyQueueE6CA6235': { + 'Type': 'AWS::SQS::Queue', + 'Properties': { + 'MessageRetentionPeriod': { + 'Ref': 'myretentionperiod', + }, + }, + 'UpdateReplacePolicy': 'Delete', + 'DeletionPolicy': 'Delete', + }, + }, + }); +}); + +test('addToPolicy will automatically create a policy for this queue', () => { + const stack = new Stack(); + const queue = new sqs.Queue(stack, 'MyQueue'); + queue.addToResourcePolicy(new iam.PolicyStatement({ + resources: ['*'], + actions: ['sqs:*'], + principals: [new iam.ArnPrincipal('arn')], + })); + + expect(stack).toMatchTemplate({ + 'Resources': { + 'MyQueueE6CA6235': { + 'Type': 'AWS::SQS::Queue', + 'UpdateReplacePolicy': 'Delete', + 'DeletionPolicy': 'Delete', + }, + 'MyQueuePolicy6BBEDDAC': { + 'Type': 'AWS::SQS::QueuePolicy', + 'Properties': { + 'PolicyDocument': { + 'Statement': [ + { + 'Action': 'sqs:*', + 'Effect': 'Allow', + 'Principal': { + 'AWS': 'arn', + }, + 'Resource': '*', + }, + ], + 'Version': '2012-10-17', + }, + 'Queues': [ + { + 'Ref': 'MyQueueE6CA6235', + }, + ], + }, + }, + }, + }); +}); + +describe('export and import', () => { + test('importing works correctly', () => { + // GIVEN + const stack = new Stack(); + + // WHEN + const imports = sqs.Queue.fromQueueArn(stack, 'Imported', 'arn:aws:sqs:us-east-1:123456789012:queue1'); + + // THEN + + // "import" returns an IQueue bound to `Fn::ImportValue`s. + expect(stack.resolve(imports.queueArn)).toEqual('arn:aws:sqs:us-east-1:123456789012:queue1'); + expect(stack.resolve(imports.queueUrl)).toEqual({ + 'Fn::Join': + ['', ['https://sqs.us-east-1.', { Ref: 'AWS::URLSuffix' }, '/123456789012/queue1']], + }); + expect(stack.resolve(imports.queueName)).toEqual('queue1'); + }); + + test('importing fifo and standard queues are detected correctly', () => { + const stack = new Stack(); + const stdQueue = sqs.Queue.fromQueueArn(stack, 'StdQueue', 'arn:aws:sqs:us-east-1:123456789012:queue1'); + const fifoQueue = sqs.Queue.fromQueueArn(stack, 'FifoQueue', 'arn:aws:sqs:us-east-1:123456789012:queue2.fifo'); + expect(stdQueue.fifo).toEqual(false); + expect(fifoQueue.fifo).toEqual(true); + }); + + test('import queueArn from token, fifo and standard queues can be defined', () => { + // GIVEN + const stack = new Stack(); + + // WHEN + const stdQueue1 = sqs.Queue.fromQueueAttributes(stack, 'StdQueue1', { + queueArn: Token.asString({ Ref: 'ARN' }), + }); + const stdQueue2 = sqs.Queue.fromQueueAttributes(stack, 'StdQueue2', { + queueArn: Token.asString({ Ref: 'ARN' }), + fifo: false, + }); + const fifoQueue = sqs.Queue.fromQueueAttributes(stack, 'FifoQueue', { + queueArn: Token.asString({ Ref: 'ARN' }), + fifo: true, + }); + + // THEN + expect(stdQueue1.fifo).toEqual(false); + expect(stdQueue2.fifo).toEqual(false); + expect(fifoQueue.fifo).toEqual(true); + }); + + test('import queueArn from token, check attributes', () => { + // GIVEN + const stack = new Stack(); + + // WHEN + const stdQueue1 = sqs.Queue.fromQueueArn(stack, 'StdQueue', Token.asString({ Ref: 'ARN' })); + + // THEN + expect(stack.resolve(stdQueue1.queueArn)).toEqual({ + Ref: 'ARN', + }); + expect(stack.resolve(stdQueue1.queueName)).toEqual({ + 'Fn::Select': [5, { 'Fn::Split': [':', { Ref: 'ARN' }] }], + }); + expect(stack.resolve(stdQueue1.queueUrl)).toEqual({ + 'Fn::Join': + ['', + ['https://sqs.', + { 'Fn::Select': [3, { 'Fn::Split': [':', { Ref: 'ARN' }] }] }, + '.', + { Ref: 'AWS::URLSuffix' }, + '/', + { 'Fn::Select': [4, { 'Fn::Split': [':', { Ref: 'ARN' }] }] }, + '/', + { 'Fn::Select': [5, { 'Fn::Split': [':', { Ref: 'ARN' }] }] }]], + }); + expect(stdQueue1.fifo).toEqual(false); + }); + + test('fails if fifo flag is set for non fifo queue name', () => { + // GIVEN + const app = new App(); + const stack = new Stack(app, 'my-stack'); + + // THEN + expect(() => sqs.Queue.fromQueueAttributes(stack, 'ImportedStdQueue', { + queueArn: 'arn:aws:sqs:us-west-2:123456789012:queue1', + fifo: true, + })).toThrow(/FIFO queue names must end in '.fifo'/); + }); + + test('fails if fifo flag is false for fifo queue name', () => { + // GIVEN + const app = new App(); + const stack = new Stack(app, 'my-stack'); + + // THEN + expect(() => sqs.Queue.fromQueueAttributes(stack, 'ImportedFifoQueue', { + queueArn: 'arn:aws:sqs:us-west-2:123456789012:queue1.fifo', + fifo: false, + })).toThrow(/Non-FIFO queue name may not end in '.fifo'/); + }); + + test('importing works correctly for cross region queue', () => { + // GIVEN + const stack = new Stack(undefined, 'Stack', { env: { region: 'us-east-1' } }); + + // WHEN + const imports = sqs.Queue.fromQueueArn(stack, 'Imported', 'arn:aws:sqs:us-west-2:123456789012:queue1'); + + // THEN + + // "import" returns an IQueue bound to `Fn::ImportValue`s. + expect(stack.resolve(imports.queueArn)).toEqual('arn:aws:sqs:us-west-2:123456789012:queue1'); + expect(stack.resolve(imports.queueUrl)).toEqual({ + 'Fn::Join': + ['', ['https://sqs.us-west-2.', { Ref: 'AWS::URLSuffix' }, '/123456789012/queue1']], + }); + expect(stack.resolve(imports.queueName)).toEqual('queue1'); + }); +}); + +describe('grants', () => { + test('grantConsumeMessages', () => { + testGrant((q, p) => q.grantConsumeMessages(p), + 'sqs:ReceiveMessage', + 'sqs:ChangeMessageVisibility', + 'sqs:GetQueueUrl', + 'sqs:DeleteMessage', + 'sqs:GetQueueAttributes', + ); + }); + + test('grantSendMessages', () => { + testGrant((q, p) => q.grantSendMessages(p), + 'sqs:SendMessage', + 'sqs:GetQueueAttributes', + 'sqs:GetQueueUrl', + ); + }); + + test('grantPurge', () => { + testGrant((q, p) => q.grantPurge(p), + 'sqs:PurgeQueue', + 'sqs:GetQueueAttributes', + 'sqs:GetQueueUrl', + ); + }); + + test('grant() is general purpose', () => { + testGrant((q, p) => q.grant(p, 'service:hello', 'service:world'), + 'service:hello', + 'service:world', + ); + }); + + test('grants also work on imported queues', () => { + const stack = new Stack(); + const queue = sqs.Queue.fromQueueAttributes(stack, 'Import', { + queueArn: 'arn:aws:sqs:us-east-1:123456789012:queue1', + queueUrl: 'https://queue-url', + }); + + const user = new iam.User(stack, 'User'); + + queue.grantPurge(user); + + expect(stack).toHaveResource('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': [ + { + 'Action': [ + 'sqs:PurgeQueue', + 'sqs:GetQueueAttributes', + 'sqs:GetQueueUrl', + ], + 'Effect': 'Allow', + 'Resource': 'arn:aws:sqs:us-east-1:123456789012:queue1', + }, + ], + 'Version': '2012-10-17', + }, + }); + }); +}); + +describe('queue encryption', () => { + test('encryptionMasterKey can be set to a custom KMS key', () => { + const stack = new Stack(); + + const key = new kms.Key(stack, 'CustomKey'); + const queue = new sqs.Queue(stack, 'Queue', { encryptionMasterKey: key }); + + expect(queue.encryptionMasterKey).toEqual(key); + expect(stack).toHaveResource('AWS::SQS::Queue', { + 'KmsMasterKeyId': { 'Fn::GetAtt': ['CustomKey1E6D0D07', 'Arn'] }, + }); + }); + + test('a kms key will be allocated if encryption = kms but a master key is not specified', () => { + const stack = new Stack(); + + new sqs.Queue(stack, 'Queue', { encryption: sqs.QueueEncryption.KMS }); + + expect(stack).toHaveResource('AWS::KMS::Key'); + expect(stack).toHaveResource('AWS::SQS::Queue', { + 'KmsMasterKeyId': { + 'Fn::GetAtt': [ + 'QueueKey39FCBAE6', + 'Arn', + ], + }, + }); + }); + + test('it is possible to use a managed kms key', () => { + const stack = new Stack(); + + new sqs.Queue(stack, 'Queue', { encryption: sqs.QueueEncryption.KMS_MANAGED }); + expect(stack).toMatchTemplate({ + 'Resources': { + 'Queue4A7E3555': { + 'Type': 'AWS::SQS::Queue', + 'Properties': { + 'KmsMasterKeyId': 'alias/aws/sqs', + }, + 'UpdateReplacePolicy': 'Delete', + 'DeletionPolicy': 'Delete', + }, + }, + }); + }); + + test('grant also affects key on encrypted queue', () => { + // GIVEN + const stack = new Stack(); + const queue = new sqs.Queue(stack, 'Queue', { + encryption: sqs.QueueEncryption.KMS, + }); + const role = new iam.Role(stack, 'Role', { + assumedBy: new iam.ServicePrincipal('someone'), + }); + + // WHEN + queue.grantSendMessages(role); + + // THEN + expect(stack).toHaveResource('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': [ + { + 'Action': [ + 'sqs:SendMessage', + 'sqs:GetQueueAttributes', + 'sqs:GetQueueUrl', + ], + 'Effect': 'Allow', + 'Resource': { 'Fn::GetAtt': ['Queue4A7E3555', 'Arn'] }, + }, + { + 'Action': [ + 'kms:Decrypt', + 'kms:Encrypt', + 'kms:ReEncrypt*', + 'kms:GenerateDataKey*', + ], + 'Effect': 'Allow', + 'Resource': { 'Fn::GetAtt': ['QueueKey39FCBAE6', 'Arn'] }, + }, + ], + 'Version': '2012-10-17', + }, + }); + }); +}); + +test('test ".fifo" suffixed queues register as fifo', () => { + const stack = new Stack(); + const queue = new sqs.Queue(stack, 'Queue', { + queueName: 'MyQueue.fifo', + }); + + expect(queue.fifo).toEqual(true); + + expect(stack).toMatchTemplate({ + 'Resources': { + 'Queue4A7E3555': { + 'Type': 'AWS::SQS::Queue', + 'Properties': { + 'QueueName': 'MyQueue.fifo', + 'FifoQueue': true, + }, + 'UpdateReplacePolicy': 'Delete', + 'DeletionPolicy': 'Delete', + }, + }, + }); +}); + +test('test a fifo queue is observed when the "fifo" property is specified', () => { + const stack = new Stack(); + const queue = new sqs.Queue(stack, 'Queue', { + fifo: true, + }); + + expect(queue.fifo).toEqual(true); + + expect(stack).toMatchTemplate({ + 'Resources': { + 'Queue4A7E3555': { + 'Type': 'AWS::SQS::Queue', + 'Properties': { + 'FifoQueue': true, + }, + 'UpdateReplacePolicy': 'Delete', + 'DeletionPolicy': 'Delete', + }, + }, + }); +}); + +test('test a fifo queue is observed when high throughput properties are specified', () => { + const stack = new Stack(); + const queue = new sqs.Queue(stack, 'Queue', { + fifo: true, + fifoThroughputLimit: sqs.FifoThroughputLimit.PER_MESSAGE_GROUP_ID, + deduplicationScope: sqs.DeduplicationScope.MESSAGE_GROUP, + }); + + expect(queue.fifo).toEqual(true); + expect(stack).toMatchTemplate({ + 'Resources': { + 'Queue4A7E3555': { + 'Type': 'AWS::SQS::Queue', + 'Properties': { + 'DeduplicationScope': 'messageGroup', + 'FifoQueue': true, + 'FifoThroughputLimit': 'perMessageGroupId', + }, + 'UpdateReplacePolicy': 'Delete', + 'DeletionPolicy': 'Delete', + }, + }, + }); +}); + +test('test a queue throws when fifoThroughputLimit specified on non fifo queue', () => { + const stack = new Stack(); + expect(() => { + new sqs.Queue(stack, 'Queue', { + fifo: false, + fifoThroughputLimit: sqs.FifoThroughputLimit.PER_MESSAGE_GROUP_ID, + }); + }).toThrow(); +}); + +test('test a queue throws when deduplicationScope specified on non fifo queue', () => { + const stack = new Stack(); + expect(() => { + new sqs.Queue(stack, 'Queue', { + fifo: false, + deduplicationScope: sqs.DeduplicationScope.MESSAGE_GROUP, + }); + }).toThrow(); +}); + +test('test metrics', () => { + // GIVEN + const stack = new Stack(); + const queue = new sqs.Queue(stack, 'Queue'); + + // THEN + expect(stack.resolve(queue.metricNumberOfMessagesSent())).toEqual({ + dimensions: { QueueName: { 'Fn::GetAtt': ['Queue4A7E3555', 'QueueName'] } }, + namespace: 'AWS/SQS', + metricName: 'NumberOfMessagesSent', + period: Duration.minutes(5), + statistic: 'Sum', + }); + + expect(stack.resolve(queue.metricSentMessageSize())).toEqual({ + dimensions: { QueueName: { 'Fn::GetAtt': ['Queue4A7E3555', 'QueueName'] } }, + namespace: 'AWS/SQS', + metricName: 'SentMessageSize', + period: Duration.minutes(5), + statistic: 'Average', + }); +}); + +test('fails if queue policy has no actions', () => { + // GIVEN + const app = new App(); + const stack = new Stack(app, 'my-stack'); + const queue = new sqs.Queue(stack, 'Queue'); + + // WHEN + queue.addToResourcePolicy(new iam.PolicyStatement({ + resources: ['*'], + principals: [new iam.ArnPrincipal('arn')], + })); + + // THEN + expect(() => app.synth()).toThrow(/A PolicyStatement must specify at least one \'action\' or \'notAction\'/); +}); + +test('fails if queue policy has no IAM principals', () => { + // GIVEN + const app = new App(); + const stack = new Stack(app, 'my-stack'); + const queue = new sqs.Queue(stack, 'Queue'); + + // WHEN + queue.addToResourcePolicy(new iam.PolicyStatement({ + resources: ['*'], + actions: ['sqs:*'], + })); + + // THEN + expect(() => app.synth()).toThrow(/A PolicyStatement used in a resource-based policy must specify at least one IAM principal/); +}); + +function testGrant(action: (q: sqs.Queue, principal: iam.IPrincipal) => void, ...expectedActions: string[]) { + const stack = new Stack(); + const queue = new sqs.Queue(stack, 'MyQueue'); + const principal = new iam.User(stack, 'User'); + + action(queue, principal); + + expect(stack).toHaveResource('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': [ + { + 'Action': expectedActions, + 'Effect': 'Allow', + 'Resource': { + 'Fn::GetAtt': [ + 'MyQueueE6CA6235', + 'Arn', + ], + }, + }, + ], + 'Version': '2012-10-17', + }, + }); +} diff --git a/packages/@aws-cdk/aws-sqs/test/test.sqs.ts b/packages/@aws-cdk/aws-sqs/test/test.sqs.ts deleted file mode 100644 index ae334e5fcd4d3..0000000000000 --- a/packages/@aws-cdk/aws-sqs/test/test.sqs.ts +++ /dev/null @@ -1,644 +0,0 @@ -import { expect, haveResource, ResourcePart } from '@aws-cdk/assert-internal'; -import * as iam from '@aws-cdk/aws-iam'; -import * as kms from '@aws-cdk/aws-kms'; -import { CfnParameter, Duration, Stack, App, Token } from '@aws-cdk/core'; -import { Test } from 'nodeunit'; -import * as sqs from '../lib'; - -/* eslint-disable quote-props */ - -export = { - 'default properties'(test: Test) { - const stack = new Stack(); - const q = new sqs.Queue(stack, 'Queue'); - - test.deepEqual(q.fifo, false); - - expect(stack).toMatch({ - 'Resources': { - 'Queue4A7E3555': { - 'Type': 'AWS::SQS::Queue', - 'UpdateReplacePolicy': 'Delete', - 'DeletionPolicy': 'Delete', - }, - }, - }); - - expect(stack).to(haveResource('AWS::SQS::Queue', { - DeletionPolicy: 'Delete', - }, ResourcePart.CompleteDefinition)); - - test.done(); - }, - 'with a dead letter queue'(test: Test) { - const stack = new Stack(); - const dlq = new sqs.Queue(stack, 'DLQ'); - new sqs.Queue(stack, 'Queue', { deadLetterQueue: { queue: dlq, maxReceiveCount: 3 } }); - - expect(stack).toMatch({ - 'Resources': { - 'DLQ581697C4': { - 'Type': 'AWS::SQS::Queue', - 'UpdateReplacePolicy': 'Delete', - 'DeletionPolicy': 'Delete', - }, - 'Queue4A7E3555': { - 'Type': 'AWS::SQS::Queue', - 'Properties': { - 'RedrivePolicy': { - 'deadLetterTargetArn': { - 'Fn::GetAtt': [ - 'DLQ581697C4', - 'Arn', - ], - }, - 'maxReceiveCount': 3, - }, - }, - 'UpdateReplacePolicy': 'Delete', - 'DeletionPolicy': 'Delete', - }, - }, - }); - - test.done(); - }, - - 'message retention period must be between 1 minute to 14 days'(test: Test) { - // GIVEN - const stack = new Stack(); - - // THEN - test.throws(() => new sqs.Queue(stack, 'MyQueue', { - retentionPeriod: Duration.seconds(30), - }), /message retention period must be 60 seconds or more/); - - test.throws(() => new sqs.Queue(stack, 'AnotherQueue', { - retentionPeriod: Duration.days(15), - }), /message retention period must be 1209600 seconds or less/); - - test.done(); - }, - - 'message retention period can be provided as a parameter'(test: Test) { - // GIVEN - const stack = new Stack(); - const parameter = new CfnParameter(stack, 'my-retention-period', { - type: 'Number', - default: 30, - }); - - // WHEN - new sqs.Queue(stack, 'MyQueue', { - retentionPeriod: Duration.seconds(parameter.valueAsNumber), - }); - - // THEN - expect(stack).toMatch({ - 'Parameters': { - 'myretentionperiod': { - 'Type': 'Number', - 'Default': 30, - }, - }, - 'Resources': { - 'MyQueueE6CA6235': { - 'Type': 'AWS::SQS::Queue', - 'Properties': { - 'MessageRetentionPeriod': { - 'Ref': 'myretentionperiod', - }, - }, - 'UpdateReplacePolicy': 'Delete', - 'DeletionPolicy': 'Delete', - }, - }, - }); - - test.done(); - }, - - 'addToPolicy will automatically create a policy for this queue'(test: Test) { - const stack = new Stack(); - const queue = new sqs.Queue(stack, 'MyQueue'); - queue.addToResourcePolicy(new iam.PolicyStatement({ - resources: ['*'], - actions: ['sqs:*'], - principals: [new iam.ArnPrincipal('arn')], - })); - - expect(stack).toMatch({ - 'Resources': { - 'MyQueueE6CA6235': { - 'Type': 'AWS::SQS::Queue', - 'UpdateReplacePolicy': 'Delete', - 'DeletionPolicy': 'Delete', - }, - 'MyQueuePolicy6BBEDDAC': { - 'Type': 'AWS::SQS::QueuePolicy', - 'Properties': { - 'PolicyDocument': { - 'Statement': [ - { - 'Action': 'sqs:*', - 'Effect': 'Allow', - 'Principal': { - 'AWS': 'arn', - }, - 'Resource': '*', - }, - ], - 'Version': '2012-10-17', - }, - 'Queues': [ - { - 'Ref': 'MyQueueE6CA6235', - }, - ], - }, - }, - }, - }); - test.done(); - }, - - 'export and import': { - 'importing works correctly'(test: Test) { - // GIVEN - const stack = new Stack(); - - // WHEN - const imports = sqs.Queue.fromQueueArn(stack, 'Imported', 'arn:aws:sqs:us-east-1:123456789012:queue1'); - - // THEN - - // "import" returns an IQueue bound to `Fn::ImportValue`s. - test.deepEqual(stack.resolve(imports.queueArn), 'arn:aws:sqs:us-east-1:123456789012:queue1'); - test.deepEqual(stack.resolve(imports.queueUrl), { - 'Fn::Join': - ['', ['https://sqs.us-east-1.', { Ref: 'AWS::URLSuffix' }, '/123456789012/queue1']], - }); - test.deepEqual(stack.resolve(imports.queueName), 'queue1'); - test.done(); - }, - - 'importing fifo and standard queues are detected correctly'(test: Test) { - const stack = new Stack(); - const stdQueue = sqs.Queue.fromQueueArn(stack, 'StdQueue', 'arn:aws:sqs:us-east-1:123456789012:queue1'); - const fifoQueue = sqs.Queue.fromQueueArn(stack, 'FifoQueue', 'arn:aws:sqs:us-east-1:123456789012:queue2.fifo'); - test.deepEqual(stdQueue.fifo, false); - test.deepEqual(fifoQueue.fifo, true); - test.done(); - }, - - 'import queueArn from token, fifo and standard queues can be defined'(test: Test) { - // GIVEN - const stack = new Stack(); - - // WHEN - const stdQueue1 = sqs.Queue.fromQueueAttributes(stack, 'StdQueue1', { - queueArn: Token.asString({ Ref: 'ARN' }), - }); - const stdQueue2 = sqs.Queue.fromQueueAttributes(stack, 'StdQueue2', { - queueArn: Token.asString({ Ref: 'ARN' }), - fifo: false, - }); - const fifoQueue = sqs.Queue.fromQueueAttributes(stack, 'FifoQueue', { - queueArn: Token.asString({ Ref: 'ARN' }), - fifo: true, - }); - - // THEN - test.deepEqual(stdQueue1.fifo, false); - test.deepEqual(stdQueue2.fifo, false); - test.deepEqual(fifoQueue.fifo, true); - test.done(); - }, - - 'import queueArn from token, check attributes'(test: Test) { - // GIVEN - const stack = new Stack(); - - // WHEN - const stdQueue1 = sqs.Queue.fromQueueArn(stack, 'StdQueue', Token.asString({ Ref: 'ARN' })); - - // THEN - test.deepEqual(stack.resolve(stdQueue1.queueArn), { - Ref: 'ARN', - }); - test.deepEqual(stack.resolve(stdQueue1.queueName), { - 'Fn::Select': [5, { 'Fn::Split': [':', { Ref: 'ARN' }] }], - }); - test.deepEqual(stack.resolve(stdQueue1.queueUrl), { - 'Fn::Join': - ['', - ['https://sqs.', - { 'Fn::Select': [3, { 'Fn::Split': [':', { Ref: 'ARN' }] }] }, - '.', - { Ref: 'AWS::URLSuffix' }, - '/', - { 'Fn::Select': [4, { 'Fn::Split': [':', { Ref: 'ARN' }] }] }, - '/', - { 'Fn::Select': [5, { 'Fn::Split': [':', { Ref: 'ARN' }] }] }]], - }); - test.deepEqual(stdQueue1.fifo, false); - test.done(); - }, - - 'fails if fifo flag is set for non fifo queue name'(test: Test) { - // GIVEN - const app = new App(); - const stack = new Stack(app, 'my-stack'); - - // THEN - test.throws(() => sqs.Queue.fromQueueAttributes(stack, 'ImportedStdQueue', { - queueArn: 'arn:aws:sqs:us-west-2:123456789012:queue1', - fifo: true, - }), /FIFO queue names must end in '.fifo'/); - test.done(); - }, - - - 'fails if fifo flag is false for fifo queue name'(test: Test) { - // GIVEN - const app = new App(); - const stack = new Stack(app, 'my-stack'); - - // THEN - test.throws(() => sqs.Queue.fromQueueAttributes(stack, 'ImportedFifoQueue', { - queueArn: 'arn:aws:sqs:us-west-2:123456789012:queue1.fifo', - fifo: false, - }), /Non-FIFO queue name may not end in '.fifo'/); - test.done(); - }, - - 'importing works correctly for cross region queue'(test: Test) { - // GIVEN - const stack = new Stack(undefined, 'Stack', { env: { region: 'us-east-1' } }); - - // WHEN - const imports = sqs.Queue.fromQueueArn(stack, 'Imported', 'arn:aws:sqs:us-west-2:123456789012:queue1'); - - // THEN - - // "import" returns an IQueue bound to `Fn::ImportValue`s. - test.deepEqual(stack.resolve(imports.queueArn), 'arn:aws:sqs:us-west-2:123456789012:queue1'); - test.deepEqual(stack.resolve(imports.queueUrl), { - 'Fn::Join': - ['', ['https://sqs.us-west-2.', { Ref: 'AWS::URLSuffix' }, '/123456789012/queue1']], - }); - test.deepEqual(stack.resolve(imports.queueName), 'queue1'); - test.done(); - }, - }, - - 'grants': { - 'grantConsumeMessages'(test: Test) { - testGrant((q, p) => q.grantConsumeMessages(p), - 'sqs:ReceiveMessage', - 'sqs:ChangeMessageVisibility', - 'sqs:GetQueueUrl', - 'sqs:DeleteMessage', - 'sqs:GetQueueAttributes', - ); - test.done(); - }, - - 'grantSendMessages'(test: Test) { - testGrant((q, p) => q.grantSendMessages(p), - 'sqs:SendMessage', - 'sqs:GetQueueAttributes', - 'sqs:GetQueueUrl', - ); - test.done(); - }, - - 'grantPurge'(test: Test) { - testGrant((q, p) => q.grantPurge(p), - 'sqs:PurgeQueue', - 'sqs:GetQueueAttributes', - 'sqs:GetQueueUrl', - ); - test.done(); - }, - - 'grant() is general purpose'(test: Test) { - testGrant((q, p) => q.grant(p, 'service:hello', 'service:world'), - 'service:hello', - 'service:world', - ); - test.done(); - }, - - 'grants also work on imported queues'(test: Test) { - const stack = new Stack(); - const queue = sqs.Queue.fromQueueAttributes(stack, 'Import', { - queueArn: 'arn:aws:sqs:us-east-1:123456789012:queue1', - queueUrl: 'https://queue-url', - }); - - const user = new iam.User(stack, 'User'); - - queue.grantPurge(user); - - expect(stack).to(haveResource('AWS::IAM::Policy', { - 'PolicyDocument': { - 'Statement': [ - { - 'Action': [ - 'sqs:PurgeQueue', - 'sqs:GetQueueAttributes', - 'sqs:GetQueueUrl', - ], - 'Effect': 'Allow', - 'Resource': 'arn:aws:sqs:us-east-1:123456789012:queue1', - }, - ], - 'Version': '2012-10-17', - }, - })); - - test.done(); - }, - }, - - 'queue encryption': { - 'encryptionMasterKey can be set to a custom KMS key'(test: Test) { - const stack = new Stack(); - - const key = new kms.Key(stack, 'CustomKey'); - const queue = new sqs.Queue(stack, 'Queue', { encryptionMasterKey: key }); - - test.same(queue.encryptionMasterKey, key); - expect(stack).to(haveResource('AWS::SQS::Queue', { - 'KmsMasterKeyId': { 'Fn::GetAtt': ['CustomKey1E6D0D07', 'Arn'] }, - })); - - test.done(); - }, - - 'a kms key will be allocated if encryption = kms but a master key is not specified'(test: Test) { - const stack = new Stack(); - - new sqs.Queue(stack, 'Queue', { encryption: sqs.QueueEncryption.KMS }); - - expect(stack).to(haveResource('AWS::KMS::Key')); - expect(stack).to(haveResource('AWS::SQS::Queue', { - 'KmsMasterKeyId': { - 'Fn::GetAtt': [ - 'QueueKey39FCBAE6', - 'Arn', - ], - }, - })); - - test.done(); - }, - - 'it is possible to use a managed kms key'(test: Test) { - const stack = new Stack(); - - new sqs.Queue(stack, 'Queue', { encryption: sqs.QueueEncryption.KMS_MANAGED }); - expect(stack).toMatch({ - 'Resources': { - 'Queue4A7E3555': { - 'Type': 'AWS::SQS::Queue', - 'Properties': { - 'KmsMasterKeyId': 'alias/aws/sqs', - }, - 'UpdateReplacePolicy': 'Delete', - 'DeletionPolicy': 'Delete', - }, - }, - }); - test.done(); - }, - - 'grant also affects key on encrypted queue'(test: Test) { - // GIVEN - const stack = new Stack(); - const queue = new sqs.Queue(stack, 'Queue', { - encryption: sqs.QueueEncryption.KMS, - }); - const role = new iam.Role(stack, 'Role', { - assumedBy: new iam.ServicePrincipal('someone'), - }); - - // WHEN - queue.grantSendMessages(role); - - // THEN - expect(stack).to(haveResource('AWS::IAM::Policy', { - 'PolicyDocument': { - 'Statement': [ - { - 'Action': [ - 'sqs:SendMessage', - 'sqs:GetQueueAttributes', - 'sqs:GetQueueUrl', - ], - 'Effect': 'Allow', - 'Resource': { 'Fn::GetAtt': ['Queue4A7E3555', 'Arn'] }, - }, - { - 'Action': [ - 'kms:Decrypt', - 'kms:Encrypt', - 'kms:ReEncrypt*', - 'kms:GenerateDataKey*', - ], - 'Effect': 'Allow', - 'Resource': { 'Fn::GetAtt': ['QueueKey39FCBAE6', 'Arn'] }, - }, - ], - 'Version': '2012-10-17', - }, - })); - - test.done(); - }, - }, - - 'test ".fifo" suffixed queues register as fifo'(test: Test) { - const stack = new Stack(); - const queue = new sqs.Queue(stack, 'Queue', { - queueName: 'MyQueue.fifo', - }); - - test.deepEqual(queue.fifo, true); - - expect(stack).toMatch({ - 'Resources': { - 'Queue4A7E3555': { - 'Type': 'AWS::SQS::Queue', - 'Properties': { - 'QueueName': 'MyQueue.fifo', - 'FifoQueue': true, - }, - 'UpdateReplacePolicy': 'Delete', - 'DeletionPolicy': 'Delete', - }, - }, - }); - - test.done(); - }, - - 'test a fifo queue is observed when the "fifo" property is specified'(test: Test) { - const stack = new Stack(); - const queue = new sqs.Queue(stack, 'Queue', { - fifo: true, - }); - - test.deepEqual(queue.fifo, true); - - expect(stack).toMatch({ - 'Resources': { - 'Queue4A7E3555': { - 'Type': 'AWS::SQS::Queue', - 'Properties': { - 'FifoQueue': true, - }, - 'UpdateReplacePolicy': 'Delete', - 'DeletionPolicy': 'Delete', - }, - }, - }); - - test.done(); - }, - - 'test a fifo queue is observed when high throughput properties are specified'(test: Test) { - const stack = new Stack(); - const queue = new sqs.Queue(stack, 'Queue', { - fifo: true, - fifoThroughputLimit: sqs.FifoThroughputLimit.PER_MESSAGE_GROUP_ID, - deduplicationScope: sqs.DeduplicationScope.MESSAGE_GROUP, - }); - - test.deepEqual(queue.fifo, true); - expect(stack).toMatch({ - 'Resources': { - 'Queue4A7E3555': { - 'Type': 'AWS::SQS::Queue', - 'Properties': { - 'DeduplicationScope': 'messageGroup', - 'FifoQueue': true, - 'FifoThroughputLimit': 'perMessageGroupId', - }, - 'UpdateReplacePolicy': 'Delete', - 'DeletionPolicy': 'Delete', - }, - }, - }); - - test.done(); - }, - - 'test a queue throws when fifoThroughputLimit specified on non fifo queue'(test: Test) { - const stack = new Stack(); - test.throws(() => { - new sqs.Queue(stack, 'Queue', { - fifo: false, - fifoThroughputLimit: sqs.FifoThroughputLimit.PER_MESSAGE_GROUP_ID, - }); - }); - test.done(); - }, - - 'test a queue throws when deduplicationScope specified on non fifo queue'(test: Test) { - const stack = new Stack(); - test.throws(() => { - new sqs.Queue(stack, 'Queue', { - fifo: false, - deduplicationScope: sqs.DeduplicationScope.MESSAGE_GROUP, - }); - }); - test.done(); - }, - - 'test metrics'(test: Test) { - // GIVEN - const stack = new Stack(); - const queue = new sqs.Queue(stack, 'Queue'); - - // THEN - test.deepEqual(stack.resolve(queue.metricNumberOfMessagesSent()), { - dimensions: { QueueName: { 'Fn::GetAtt': ['Queue4A7E3555', 'QueueName'] } }, - namespace: 'AWS/SQS', - metricName: 'NumberOfMessagesSent', - period: Duration.minutes(5), - statistic: 'Sum', - }); - - test.deepEqual(stack.resolve(queue.metricSentMessageSize()), { - dimensions: { QueueName: { 'Fn::GetAtt': ['Queue4A7E3555', 'QueueName'] } }, - namespace: 'AWS/SQS', - metricName: 'SentMessageSize', - period: Duration.minutes(5), - statistic: 'Average', - }); - - test.done(); - }, - - 'fails if queue policy has no actions'(test: Test) { - // GIVEN - const app = new App(); - const stack = new Stack(app, 'my-stack'); - const queue = new sqs.Queue(stack, 'Queue'); - - // WHEN - queue.addToResourcePolicy(new iam.PolicyStatement({ - resources: ['*'], - principals: [new iam.ArnPrincipal('arn')], - })); - - // THEN - test.throws(() => app.synth(), /A PolicyStatement must specify at least one \'action\' or \'notAction\'/); - test.done(); - }, - - 'fails if queue policy has no IAM principals'(test: Test) { - // GIVEN - const app = new App(); - const stack = new Stack(app, 'my-stack'); - const queue = new sqs.Queue(stack, 'Queue'); - - // WHEN - queue.addToResourcePolicy(new iam.PolicyStatement({ - resources: ['*'], - actions: ['sqs:*'], - })); - - // THEN - test.throws(() => app.synth(), /A PolicyStatement used in a resource-based policy must specify at least one IAM principal/); - test.done(); - }, -}; - -function testGrant(action: (q: sqs.Queue, principal: iam.IPrincipal) => void, ...expectedActions: string[]) { - const stack = new Stack(); - const queue = new sqs.Queue(stack, 'MyQueue'); - const principal = new iam.User(stack, 'User'); - - action(queue, principal); - - expect(stack).to(haveResource('AWS::IAM::Policy', { - 'PolicyDocument': { - 'Statement': [ - { - 'Action': expectedActions, - 'Effect': 'Allow', - 'Resource': { - 'Fn::GetAtt': [ - 'MyQueueE6CA6235', - 'Arn', - ], - }, - }, - ], - 'Version': '2012-10-17', - }, - })); -} diff --git a/packages/@aws-cdk/aws-ssm/.eslintrc.js b/packages/@aws-cdk/aws-ssm/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-ssm/.eslintrc.js +++ b/packages/@aws-cdk/aws-ssm/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-ssm/jest.config.js b/packages/@aws-cdk/aws-ssm/jest.config.js index f5d5c4c8ad18f..34818e1593f6b 100644 --- a/packages/@aws-cdk/aws-ssm/jest.config.js +++ b/packages/@aws-cdk/aws-ssm/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); -module.exports = baseConfig; \ No newline at end of file +const baseConfig = require('../../../tools/@aws-cdk/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-ssm/lib/parameter.ts b/packages/@aws-cdk/aws-ssm/lib/parameter.ts index a33759d7cf014..29c0eb8a33f03 100644 --- a/packages/@aws-cdk/aws-ssm/lib/parameter.ts +++ b/packages/@aws-cdk/aws-ssm/lib/parameter.ts @@ -137,6 +137,13 @@ export interface StringParameterProps extends ParameterOptions { * @default ParameterType.STRING */ readonly type?: ParameterType; + + /** + * The data type of the parameter, such as `text` or `aws:ec2:image`. + * + * @default - undefined + */ + readonly dataType?: ParameterDataType; } /** @@ -217,6 +224,20 @@ export enum ParameterType { AWS_EC2_IMAGE_ID = 'AWS::EC2::Image::Id', } +/** + * SSM parameter data type + */ +export enum ParameterDataType { + /** + * Text + */ + TEXT = 'text', + /** + * Aws Ec2 Image + */ + AWS_EC2_IMAGE = 'aws:ec2:image', +} + /** * SSM parameter tier */ @@ -430,20 +451,23 @@ export class StringParameter extends ParameterBase implements IStringParameter { _assertValidValue(props.stringValue, props.allowedPattern); } - if (this.physicalName.length > 2048) { - throw new Error('Name cannot be longer than 2048 characters.'); - } + validateParameterName(this.physicalName); if (props.description && props.description?.length > 1024) { throw new Error('Description cannot be longer than 1024 characters.'); } + if (props.type && props.type === ParameterType.AWS_EC2_IMAGE_ID) { + throw new Error('The type must either be ParameterType.STRING or ParameterType.STRING_LIST. Did you mean to set dataType: ParameterDataType.AWS_EC2_IMAGE instead?'); + } + const resource = new ssm.CfnParameter(this, 'Resource', { allowedPattern: props.allowedPattern, description: props.description, name: this.physicalName, tier: props.tier, type: props.type || ParameterType.STRING, + dataType: props.dataType, value: props.stringValue, }); @@ -497,9 +521,7 @@ export class StringListParameter extends ParameterBase implements IStringListPar props.stringListValue.forEach(str => _assertValidValue(str, props.allowedPattern!)); } - if (this.physicalName.length > 2048) { - throw new Error('Name cannot be longer than 2048 characters.'); - } + validateParameterName(this.physicalName); if (props.description && props.description?.length > 1024) { throw new Error('Description cannot be longer than 1024 characters.'); @@ -546,3 +568,13 @@ function _assertValidValue(value: string, allowedPattern: string): void { function makeIdentityForImportedValue(parameterName: string) { return `SsmParameterValue:${parameterName}:C96584B6-F00A-464E-AD19-53AFF4B05118`; } + +function validateParameterName(parameterName: string) { + if (Token.isUnresolved(parameterName)) { return; } + if (parameterName.length > 2048) { + throw new Error('name cannot be longer than 2048 characters.'); + } + if (!parameterName.match(/^[\/\w.-]+$/)) { + throw new Error(`name must only contain letters, numbers, and the following 4 symbols .-_/; got ${parameterName}`); + } +} diff --git a/packages/@aws-cdk/aws-ssm/package.json b/packages/@aws-cdk/aws-ssm/package.json index 47f9ff90a4852..c30ae7e97c8f1 100644 --- a/packages/@aws-cdk/aws-ssm/package.json +++ b/packages/@aws-cdk/aws-ssm/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::SSM", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,27 +72,27 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", - "@aws-cdk/core": "0.0.0", "@aws-cdk/cloud-assembly-schema": "0.0.0", + "@aws-cdk/core": "0.0.0", "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", - "@aws-cdk/core": "0.0.0", "@aws-cdk/cloud-assembly-schema": "0.0.0", + "@aws-cdk/core": "0.0.0", "constructs": "^3.3.69" }, "engines": { diff --git a/packages/@aws-cdk/aws-ssm/test/parameter.test.ts b/packages/@aws-cdk/aws-ssm/test/parameter.test.ts index 2e40e4626cbd3..45fbc70f9d926 100644 --- a/packages/@aws-cdk/aws-ssm/test/parameter.test.ts +++ b/packages/@aws-cdk/aws-ssm/test/parameter.test.ts @@ -28,6 +28,34 @@ test('creating a String SSM Parameter', () => { }); }); +test('type cannot be specified as AWS_EC2_IMAGE_ID', () => { + // GIVEN + const stack = new cdk.Stack(); + + // THEN + expect(() => new ssm.StringParameter(stack, 'myParam', { + stringValue: 'myValue', + type: ssm.ParameterType.AWS_EC2_IMAGE_ID, + })).toThrow('The type must either be ParameterType.STRING or ParameterType.STRING_LIST. Did you mean to set dataType: ParameterDataType.AWS_EC2_IMAGE instead?'); +}); + +test('dataType can be specified', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new ssm.StringParameter(stack, 'myParam', { + stringValue: 'myValue', + dataType: ssm.ParameterDataType.AWS_EC2_IMAGE, + }); + + // THEN + expect(stack).toHaveResource('AWS::SSM::Parameter', { + Value: 'myValue', + DataType: 'aws:ec2:image', + }); +}); + test('expect String SSM Parameter to have tier properly set', () => { // GIVEN const stack = new cdk.Stack(); @@ -141,7 +169,21 @@ test('String SSM Parameter throws on long names', () => { Nam eget dui. Etiam rhoncus. Maecenas tempus, tellus eget condimentum rhoncus, sem quam semper libero, sit amet adipiscing \ sem neque sed ipsum.', }); - }).toThrow(/Name cannot be longer than 2048 characters./); + }).toThrow(/name cannot be longer than 2048 characters./); +}); + +test.each([ + '/parameter/with spaces', + 'charactersOtherThan^allowed', + 'trying;this', +])('String SSM Parameter throws on invalid name %s', (parameterName) => { + // GIVEN + const stack = new cdk.Stack(); + + // THEN + expect(() => { + new ssm.StringParameter(stack, 'Parameter', { stringValue: 'Foo', parameterName }); + }).toThrow(/name must only contain letters, numbers, and the following 4 symbols.*/); }); test('StringList SSM Parameter throws on long descriptions', () => { @@ -194,7 +236,21 @@ test('StringList SSM Parameter throws on long names', () => { Nam eget dui. Etiam rhoncus. Maecenas tempus, tellus eget condimentum rhoncus, sem quam semper libero, sit amet adipiscing \ sem neque sed ipsum.', }); - }).toThrow(/Name cannot be longer than 2048 characters./); + }).toThrow(/name cannot be longer than 2048 characters./); +}); + +test.each([ + '/parameter/with spaces', + 'charactersOtherThan^allowed', + 'trying;this', +])('StringList SSM Parameter throws on invalid name %s', (parameterName) => { + // GIVEN + const stack = new cdk.Stack(); + + // THEN + expect(() => { + new ssm.StringListParameter(stack, 'Parameter', { stringListValue: ['Foo'], parameterName }); + }).toThrow(/name must only contain letters, numbers, and the following 4 symbols.*/); }); test('StringList SSM Parameter values cannot contain commas', () => { diff --git a/packages/@aws-cdk/aws-ssmcontacts/.eslintrc.js b/packages/@aws-cdk/aws-ssmcontacts/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-ssmcontacts/.eslintrc.js +++ b/packages/@aws-cdk/aws-ssmcontacts/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-ssmcontacts/jest.config.js b/packages/@aws-cdk/aws-ssmcontacts/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-ssmcontacts/jest.config.js +++ b/packages/@aws-cdk/aws-ssmcontacts/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-ssmcontacts/package.json b/packages/@aws-cdk/aws-ssmcontacts/package.json index 350d243514340..cc6f3d5c34464 100644 --- a/packages/@aws-cdk/aws-ssmcontacts/package.json +++ b/packages/@aws-cdk/aws-ssmcontacts/package.json @@ -58,7 +58,6 @@ }, "cdk-build": { "cloudformation": "AWS::SSMContacts", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -77,11 +76,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", "@aws-cdk/assertions": "0.0.0", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-ssmincidents/.eslintrc.js b/packages/@aws-cdk/aws-ssmincidents/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-ssmincidents/.eslintrc.js +++ b/packages/@aws-cdk/aws-ssmincidents/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-ssmincidents/jest.config.js b/packages/@aws-cdk/aws-ssmincidents/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-ssmincidents/jest.config.js +++ b/packages/@aws-cdk/aws-ssmincidents/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-ssmincidents/package.json b/packages/@aws-cdk/aws-ssmincidents/package.json index 668f68e02fd64..bbc9103e668fa 100644 --- a/packages/@aws-cdk/aws-ssmincidents/package.json +++ b/packages/@aws-cdk/aws-ssmincidents/package.json @@ -58,7 +58,6 @@ }, "cdk-build": { "cloudformation": "AWS::SSMIncidents", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -77,11 +76,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", "@aws-cdk/assertions": "0.0.0", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-sso/.eslintrc.js b/packages/@aws-cdk/aws-sso/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-sso/.eslintrc.js +++ b/packages/@aws-cdk/aws-sso/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-sso/jest.config.js b/packages/@aws-cdk/aws-sso/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-sso/jest.config.js +++ b/packages/@aws-cdk/aws-sso/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-sso/package.json b/packages/@aws-cdk/aws-sso/package.json index b6361b2336306..12b8dfc9536d2 100644 --- a/packages/@aws-cdk/aws-sso/package.json +++ b/packages/@aws-cdk/aws-sso/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::SSO", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/.eslintrc.js b/packages/@aws-cdk/aws-stepfunctions-tasks/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/.eslintrc.js +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/README.md b/packages/@aws-cdk/aws-stepfunctions-tasks/README.md index 063d058aab8c9..d33d3c7ff801e 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/README.md +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/README.md @@ -33,6 +33,7 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aw - [API Gateway](#api-gateway) - [Call REST API Endpoint](#call-rest-api-endpoint) - [Call HTTP API Endpoint](#call-http-api-endpoint) + - [AWS SDK](#aws-sdk) - [Athena](#athena) - [StartQueryExecution](#startqueryexecution) - [GetQueryExecution](#getqueryexecution) @@ -205,7 +206,7 @@ const submitJob = new tasks.LambdaInvoke(this, 'Invoke Handler', { }); ``` -You can also use [intrinsic functions](https://docs.aws.amazon.com/step-functions/latest/dg/amazon-states-language-intrinsic-functions.html) with `JsonPath.stringAt()`. +You can also use [intrinsic functions](https://docs.aws.amazon.com/step-functions/latest/dg/amazon-states-language-intrinsic-functions.html) with `JsonPath.stringAt()`. Here is an example of starting an Athena query that is dynamically created using the task input: ```ts @@ -314,6 +315,43 @@ const invokeTask = new tasks.CallApiGatewayHttpApiEndpoint(stack, 'Call HTTP API }); ``` +### AWS SDK + +Step Functions supports calling [AWS service's API actions](https://docs.aws.amazon.com/step-functions/latest/dg/supported-services-awssdk.html) +through the service integration pattern. + +You can use Step Functions' AWS SDK integrations to call any of the over two hundred AWS services +directly from your state machine, giving you access to over nine thousand API actions. + +```ts +const getObject = new tasks.CallAwsService(this, 'GetObject', { + service: 's3', + action: 'getObject', + parameters: { + Bucket: myBucket.bucketName, + Key: sfn.JsonPath.stringAt('$.key') + }, + iamResources: [myBucket.arnForObjects('*')], +}); +``` + +Use camelCase for actions and PascalCase for parameter names. + +The task automatically adds an IAM statement to the state machine role's policy based on the +service and action called. The resources for this statement must be specified in `iamResources`. + +Use the `iamAction` prop to manually specify the IAM action name in the case where the IAM +action name does not match with the API service/action name: + +```ts +const listBuckets = new tasks.CallAwsService(this, 'ListBuckets', { + service: 's3', + action: 'ListBuckets', + iamResources: ['*'], + iamAction: 's3:ListAllMyBuckets' +}); +``` + ## Athena Step Functions supports [Athena](https://docs.aws.amazon.com/step-functions/latest/dg/connect-athena.html) through the service integration pattern. @@ -531,20 +569,20 @@ taskDefinition.addContainer('TheContainer', { }); const runTask = new tasks.EcsRunTask(this, 'Run', { - integrationPattern: sfn.IntegrationPattern.RUN_JOB, - cluster, - taskDefinition, - launchTarget: new tasks.EcsEc2LaunchTarget({ - placementStrategies: [ - ecs.PlacementStrategy.spreadAcrossInstances(), - ecs.PlacementStrategy.packedByCpu(), - ecs.PlacementStrategy.randomly(), - ], - placementConstraints: [ - ecs.PlacementConstraint.memberOf('blieptuut') - ], - }), - }); + integrationPattern: sfn.IntegrationPattern.RUN_JOB, + cluster, + taskDefinition, + launchTarget: new tasks.EcsEc2LaunchTarget({ + placementStrategies: [ + ecs.PlacementStrategy.spreadAcrossInstances(), + ecs.PlacementStrategy.packedByCpu(), + ecs.PlacementStrategy.randomly(), + ], + placementConstraints: [ + ecs.PlacementConstraint.memberOf('blieptuut') + ], + }), +}); ``` #### Fargate @@ -644,6 +682,18 @@ new tasks.EmrCreateCluster(this, 'Create Cluster', { }); ``` +If you want to run multiple steps in [parallel](https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-concurrent-steps.html), +you can specify the `stepConcurrencyLevel` property. The concurrency range is between 1 +and 256 inclusive, where the default concurrency of 1 means no step concurrency is allowed. +`stepConcurrencyLevel` requires the EMR release label to be 5.28.0 or above. + +```ts +new tasks.EmrCreateCluster(this, 'Create Cluster', { + // ... + stepConcurrencyLevel: 10, +}); +``` + ### Termination Protection Locks a cluster (job flow) so the EC2 instances in the cluster cannot be @@ -676,10 +726,10 @@ Corresponds to the [`addJobFlowSteps`](https://docs.aws.amazon.com/emr/latest/AP ```ts new tasks.EmrAddStep(this, 'Task', { - clusterId: 'ClusterId', - name: 'StepName', - jar: 'Jar', - actionOnFailure: tasks.ActionOnFailure.CONTINUE, + clusterId: 'ClusterId', + name: 'StepName', + jar: 'Jar', + actionOnFailure: tasks.ActionOnFailure.CONTINUE, }); ``` @@ -747,9 +797,9 @@ import * as sfn from '@aws-cdk/aws-stepfunctions'; import * as tasks from '@aws-cdk/aws-stepfunctions-tasks'; const myEksCluster = new eks.Cluster(this, 'my sample cluster', { - version: eks.KubernetesVersion.V1_18, - clusterName: 'myEksCluster', - }); + version: eks.KubernetesVersion.V1_18, + clusterName: 'myEksCluster', +}); new tasks.EksCall(stack, 'Call a EKS Endpoint', { cluster: myEksCluster, @@ -1005,9 +1055,9 @@ new tasks.SageMakerCreateEndpointConfig(this, 'SagemakerEndpointConfig', { productionVariants: [{ initialInstanceCount: 2, instanceType: ec2.InstanceType.of(ec2.InstanceClass.M5, ec2.InstanceSize.XLARGE), - modelName: 'MyModel', - variantName: 'awesome-variant', - }], + modelName: 'MyModel', + variantName: 'awesome-variant', + }], }); ``` @@ -1019,9 +1069,9 @@ You can call the [`CreateModel`](https://docs.aws.amazon.com/sagemaker/latest/AP new tasks.SageMakerCreateModel(this, 'Sagemaker', { modelName: 'MyModel', primaryContainer: new tasks.ContainerDefinition({ - image: tasks.DockerImage.fromJsonExpression(sfn.JsonPath.stringAt('$.Model.imageName')), - mode: tasks.Mode.SINGLE_MODEL, - modelS3Location: tasks.S3Location.fromJsonExpression('$.TrainingJob.ModelArtifacts.S3ModelArtifacts'), + image: tasks.DockerImage.fromJsonExpression(sfn.JsonPath.stringAt('$.Model.imageName')), + mode: tasks.Mode.SINGLE_MODEL, + modelS3Location: tasks.S3Location.fromJsonExpression('$.TrainingJob.ModelArtifacts.S3ModelArtifacts'), }), }); ``` @@ -1032,9 +1082,9 @@ You can call the [`UpdateEndpoint`](https://docs.aws.amazon.com/sagemaker/latest ```ts new tasks.SageMakerUpdateEndpoint(this, 'SagemakerEndpoint', { - endpointName: sfn.JsonPath.stringAt('$.Endpoint.Name'), - endpointConfigName: sfn.JsonPath.stringAt('$.Endpoint.EndpointConfig'), - }); + endpointName: sfn.JsonPath.stringAt('$.Endpoint.Name'), + endpointConfigName: sfn.JsonPath.stringAt('$.Endpoint.EndpointConfig'), +}); ``` ## SNS @@ -1066,7 +1116,7 @@ const task1 = new tasks.SnsPublish(this, 'Publish1', { handles: { value: ['@kslater', '@jjf', null, '@mfanning'], }, - + }, }); // Combine a field from the execution data with @@ -1076,7 +1126,7 @@ const task2 = new tasks.SnsPublish(this, 'Publish2', { message: sfn.TaskInput.fromObject({ field1: 'somedata', field2: sfn.JsonPath.stringAt('$.field2'), - }) + }), }); ``` @@ -1091,7 +1141,7 @@ AWS Step Functions supports it's own [`StartExecution`](https://docs.aws.amazon. ```ts // Define a state machine with one Pass state const child = new sfn.StateMachine(this, 'ChildStateMachine', { - definition: sfn.Chain.start(new sfn.Pass(this, 'PassState')), + definition: sfn.Chain.start(new sfn.Pass(this, 'PassState')), }); // Include the state machine in a Task state with callback pattern @@ -1100,14 +1150,14 @@ const task = new tasks.StepFunctionsStartExecution(this, 'ChildTask', { integrationPattern: sfn.IntegrationPattern.WAIT_FOR_TASK_TOKEN, input: sfn.TaskInput.fromObject({ token: sfn.JsonPath.taskToken, - foo: 'bar' + foo: 'bar', }), - name: 'MyExecutionName' + name: 'MyExecutionName', }); // Define a second state machine with the Task state above new sfn.StateMachine(this, 'ParentStateMachine', { - definition: task + definition: task, }); ``` diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/jest.config.js b/packages/@aws-cdk/aws-stepfunctions-tasks/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/jest.config.js +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/aws-sdk/call-aws-service.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/aws-sdk/call-aws-service.ts new file mode 100644 index 0000000000000..f3987cc0677ae --- /dev/null +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/aws-sdk/call-aws-service.ts @@ -0,0 +1,96 @@ +import * as iam from '@aws-cdk/aws-iam'; +import * as sfn from '@aws-cdk/aws-stepfunctions'; +import { Token } from '@aws-cdk/core'; +import { Construct } from 'constructs'; +import { integrationResourceArn } from '../private/task-utils'; + +/** + * Properties for calling an AWS service's API action from your + * state machine. + * + * @see https://docs.aws.amazon.com/step-functions/latest/dg/supported-services-awssdk.html + */ +export interface CallAwsServiceProps extends sfn.TaskStateBaseProps { + /** + * The AWS service to call. + * + * @see https://docs.aws.amazon.com/step-functions/latest/dg/supported-services-awssdk.html + */ + readonly service: string; + + /** + * The API action to call. + * + * Use camelCase. + */ + readonly action: string; + + /** + * Parameters for the API action call. + * + * Use PascalCase for the parameter names. + * + * @default - no parameters + */ + readonly parameters?: { [key: string]: any }; + + /** + * The resources for the IAM statement that will be added to the state + * machine role's policy to allow the state machine to make the API call. + * + * By default the action for this IAM statement will be `service:action`. + */ + readonly iamResources: string[]; + + /** + * The action for the IAM statement that will be added to the state + * machine role's policy to allow the state machine to make the API call. + * + * Use in the case where the IAM action name does not match with the + * API service/action name, e.g. `s3:ListBuckets` requires `s3:ListAllMyBuckets`. + * + * @default - service:action + */ + readonly iamAction?: string; +} + +/** + * A StepFunctions task to call an AWS service API + */ +export class CallAwsService extends sfn.TaskStateBase { + protected readonly taskMetrics?: sfn.TaskMetricsConfig; + protected readonly taskPolicies?: iam.PolicyStatement[]; + + constructor(scope: Construct, id: string, private readonly props: CallAwsServiceProps) { + super(scope, id, props); + + this.taskPolicies = [ + new iam.PolicyStatement({ + resources: props.iamResources, + // The prefix and the action name are case insensitive + // https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_action.html + actions: [props.iamAction ?? `${props.service}:${props.action}`], + }), + ]; + } + + /** + * @internal + */ + protected _renderTask(): any { + let service = this.props.service; + + if (!Token.isUnresolved(service)) { + service = service.toLowerCase(); + } + + return { + Resource: integrationResourceArn( + 'aws-sdk', + `${service}:${this.props.action}`, + this.props.integrationPattern, + ), + Parameters: sfn.FieldUtils.renderObject(this.props.parameters) ?? {}, // Parameters is required for aws-sdk + }; + } +} diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/emr/emr-create-cluster.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/emr/emr-create-cluster.ts index bfb3d94e28b5c..4cac7c7180bde 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/emr/emr-create-cluster.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/emr/emr-create-cluster.ts @@ -130,6 +130,16 @@ export interface EmrCreateClusterProps extends sfn.TaskStateBaseProps { */ readonly securityConfiguration?: string; + /** + * Specifies the step concurrency level to allow multiple steps to run in parallel + * + * Requires EMR release label 5.28.0 or above. + * Must be in range [1, 256]. + * + * @default 1 - no step concurrency allowed + */ + readonly stepConcurrencyLevel?: number; + /** * A list of tags to associate with a cluster and propagate to Amazon EC2 instances. * @@ -191,6 +201,22 @@ export class EmrCreateCluster extends sfn.TaskStateBase { } this.taskPolicies = this.createPolicyStatements(this._serviceRole, this._clusterRole, this._autoScalingRole); + + if (this.props.releaseLabel !== undefined) { + this.validateReleaseLabel(this.props.releaseLabel); + } + + if (this.props.stepConcurrencyLevel !== undefined) { + if (this.props.stepConcurrencyLevel < 1 || this.props.stepConcurrencyLevel > 256) { + throw new Error(`Step concurrency level must be in range [1, 256], but got ${this.props.stepConcurrencyLevel}.`); + } + if (this.props.releaseLabel && this.props.stepConcurrencyLevel !== 1) { + const [major, minor] = this.props.releaseLabel.substr(4).split('.'); + if (Number(major) < 5 || (Number(major) === 5 && Number(minor) < 28)) { + throw new Error(`Step concurrency is only supported in EMR release version 5.28.0 and above but got ${this.props.releaseLabel}.`); + } + } + } } /** @@ -252,6 +278,7 @@ export class EmrCreateCluster extends sfn.TaskStateBase { ReleaseLabel: cdk.stringToCloudFormation(this.props.releaseLabel), ScaleDownBehavior: cdk.stringToCloudFormation(this.props.scaleDownBehavior?.valueOf()), SecurityConfiguration: cdk.stringToCloudFormation(this.props.securityConfiguration), + StepConcurrencyLevel: cdk.numberToCloudFormation(this.props.stepConcurrencyLevel), ...(this.props.tags ? this.renderTags(this.props.tags) : undefined), VisibleToAllUsers: cdk.booleanToCloudFormation(this.visibleToAllUsers), }), @@ -356,6 +383,25 @@ export class EmrCreateCluster extends sfn.TaskStateBase { return role; } + + /** + * Validates the release label string is in proper format. + * Release labels are in the form `emr-x.x.x`. For example, `emr-5.33.0`. + * + * @see https://docs.aws.amazon.com/emr/latest/ReleaseGuide/emr-release-components.html + */ + private validateReleaseLabel(releaseLabel: string): string { + const prefix = releaseLabel.substr(0, 4); + const versions = releaseLabel.substr(4).split('.'); + if (prefix !== 'emr-' || versions.length !== 3 || versions.some((e) => isNotANumber(e))) { + throw new Error(`The release label must be in the format 'emr-x.x.x' but got ${releaseLabel}`); + } + return releaseLabel; + + function isNotANumber(value: string): boolean { + return value === '' || isNaN(Number(value)); + } + } } export namespace EmrCreateCluster { diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/eval-nodejs-handler/index.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/eval-nodejs-handler/index.ts index 52db50f92605e..c40aeb340bfbb 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/eval-nodejs-handler/index.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/eval-nodejs-handler/index.ts @@ -15,5 +15,5 @@ export async function handler(event: Event): Promise { ); console.log(`Expression: ${expression}`); - return await eval(expression); + return eval(expression); } diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/index.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/index.ts index e7337f39b6831..0c089eee35bae 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/index.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/index.ts @@ -47,3 +47,4 @@ export * from './databrew/start-job-run'; export * from './eks/call'; export * from './apigateway'; export * from './eventbridge/put-events'; +export * from './aws-sdk/call-aws-service'; diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/private/task-utils.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/private/task-utils.ts index a612833075eaf..a0b28323c7e85 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/private/task-utils.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/private/task-utils.ts @@ -26,7 +26,7 @@ const resourceArnSuffix: Record = { [IntegrationPattern.WAIT_FOR_TASK_TOKEN]: '.waitForTaskToken', }; -export function integrationResourceArn(service: string, api: string, integrationPattern: IntegrationPattern): string { +export function integrationResourceArn(service: string, api: string, integrationPattern?: IntegrationPattern): string { if (!service || !api) { throw new Error("Both 'service' and 'api' must be provided to build the resource ARN."); } diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/package.json b/packages/@aws-cdk/aws-stepfunctions-tasks/package.json index dc297c9d37bfc..1853a14deb2cb 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/package.json +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/package.json @@ -71,19 +71,19 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "@aws-cdk/aws-s3-assets": "0.0.0", - "@aws-cdk/aws-sns-subscriptions": "0.0.0", - "@aws-cdk/aws-glue": "0.0.0", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0", "@aws-cdk/aws-apigatewayv2": "0.0.0", "@aws-cdk/aws-apigatewayv2-integrations": "0.0.0", "@aws-cdk/aws-batch": "0.0.0", "@aws-cdk/aws-databrew": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "@aws-cdk/aws-glue": "0.0.0", + "@aws-cdk/aws-s3-assets": "0.0.0", + "@aws-cdk/aws-sns-subscriptions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24", + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-apigateway": "0.0.0", @@ -137,7 +137,6 @@ "announce": false }, "cdk-build": { - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/aws-sdk/call-aws-service.test.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/test/aws-sdk/call-aws-service.test.ts new file mode 100644 index 0000000000000..89720879f7d9b --- /dev/null +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/aws-sdk/call-aws-service.test.ts @@ -0,0 +1,148 @@ +import '@aws-cdk/assert-internal/jest'; +import * as sfn from '@aws-cdk/aws-stepfunctions'; +import * as cdk from '@aws-cdk/core'; +import * as tasks from '../../lib'; + +let stack: cdk.Stack; + +beforeEach(() => { + // GIVEN + stack = new cdk.Stack(); +}); + +test('CallAwsService task', () => { + // WHEN + const task = new tasks.CallAwsService(stack, 'GetObject', { + service: 's3', + action: 'getObject', + parameters: { + Bucket: 'my-bucket', + Key: sfn.JsonPath.stringAt('$.key'), + }, + iamResources: ['*'], + }); + + new sfn.StateMachine(stack, 'StateMachine', { + definition: task, + }); + + // THEN + expect(stack.resolve(task.toStateJson())).toEqual({ + Type: 'Task', + Resource: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':states:::aws-sdk:s3:getObject', + ], + ], + }, + End: true, + Parameters: { + 'Bucket': 'my-bucket', + 'Key.$': '$.key', + }, + }); + + expect(stack).toHaveResource('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [ + { + Action: 's3:getObject', + Effect: 'Allow', + Resource: '*', + }, + ], + Version: '2012-10-17', + }, + }); +}); + +test('with custom IAM action', () => { + // WHEN + const task = new tasks.CallAwsService(stack, 'ListBuckets', { + service: 's3', + action: 'listBuckets', + iamResources: ['*'], + iamAction: 's3:ListAllMyBuckets', + }); + + new sfn.StateMachine(stack, 'StateMachine', { + definition: task, + }); + + // THEN + expect(stack.resolve(task.toStateJson())).toEqual({ + Type: 'Task', + Resource: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':states:::aws-sdk:s3:listBuckets', + ], + ], + }, + End: true, + Parameters: {}, + }); + + expect(stack).toHaveResource('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [ + { + Action: 's3:ListAllMyBuckets', + Effect: 'Allow', + Resource: '*', + }, + ], + Version: '2012-10-17', + }, + }); +}); + +test('with unresolved tokens', () => { + // WHEN + const task = new tasks.CallAwsService(stack, 'ListBuckets', { + service: new cdk.CfnParameter(stack, 'Service').valueAsString, + action: new cdk.CfnParameter(stack, 'Action').valueAsString, + iamResources: ['*'], + }); + + new sfn.StateMachine(stack, 'StateMachine', { + definition: task, + }); + + // THEN + expect(stack.resolve(task.toStateJson())).toEqual({ + Type: 'Task', + Resource: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':states:::aws-sdk:', + { + Ref: 'Service', + }, + ':', + { + Ref: 'Action', + }, + ], + ], + }, + End: true, + Parameters: {}, + }); +}); diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/aws-sdk/integ.call-aws-service.expected.json b/packages/@aws-cdk/aws-stepfunctions-tasks/test/aws-sdk/integ.call-aws-service.expected.json new file mode 100644 index 0000000000000..38f975ca5ec03 --- /dev/null +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/aws-sdk/integ.call-aws-service.expected.json @@ -0,0 +1,161 @@ +{ + "Resources": { + "Bucket83908E77": { + "Type": "AWS::S3::Bucket", + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "StateMachineRoleB840431D": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": { + "Fn::Join": [ + "", + [ + "states.", + { + "Ref": "AWS::Region" + }, + ".amazonaws.com" + ] + ] + } + } + } + ], + "Version": "2012-10-17" + } + } + }, + "StateMachineRoleDefaultPolicyDF1E6607": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "s3:putObject", + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "Bucket83908E77", + "Arn" + ] + }, + "/*" + ] + ] + } + }, + { + "Action": "s3:getObject", + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "Bucket83908E77", + "Arn" + ] + }, + "/*" + ] + ] + } + }, + { + "Action": "s3:deleteObject", + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "Bucket83908E77", + "Arn" + ] + }, + "/*" + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "StateMachineRoleDefaultPolicyDF1E6607", + "Roles": [ + { + "Ref": "StateMachineRoleB840431D" + } + ] + } + }, + "StateMachine2E01A3A5": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineRoleB840431D", + "Arn" + ] + }, + "DefinitionString": { + "Fn::Join": [ + "", + [ + "{\"StartAt\":\"PutObject\",\"States\":{\"PutObject\":{\"Next\":\"GetObject\",\"Type\":\"Task\",\"Resource\":\"arn:", + { + "Ref": "AWS::Partition" + }, + ":states:::aws-sdk:s3:putObject\",\"Parameters\":{\"Body.$\":\"$.body\",\"Bucket\":\"", + { + "Ref": "Bucket83908E77" + }, + "\",\"Key\":\"test.txt\"}},\"GetObject\":{\"Next\":\"DeleteObject\",\"Type\":\"Task\",\"Resource\":\"arn:", + { + "Ref": "AWS::Partition" + }, + ":states:::aws-sdk:s3:getObject\",\"Parameters\":{\"Bucket\":\"", + { + "Ref": "Bucket83908E77" + }, + "\",\"Key\":\"test.txt\"}},\"DeleteObject\":{\"End\":true,\"Type\":\"Task\",\"ResultPath\":null,\"Resource\":\"arn:", + { + "Ref": "AWS::Partition" + }, + ":states:::aws-sdk:s3:deleteObject\",\"Parameters\":{\"Bucket\":\"", + { + "Ref": "Bucket83908E77" + }, + "\",\"Key\":\"test.txt\"}}}}" + ] + ] + } + }, + "DependsOn": [ + "StateMachineRoleDefaultPolicyDF1E6607", + "StateMachineRoleB840431D" + ] + } + }, + "Outputs": { + "StateMachineArn": { + "Value": { + "Ref": "StateMachine2E01A3A5" + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/aws-sdk/integ.call-aws-service.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/test/aws-sdk/integ.call-aws-service.ts new file mode 100644 index 0000000000000..3c9302e389763 --- /dev/null +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/aws-sdk/integ.call-aws-service.ts @@ -0,0 +1,65 @@ +import * as s3 from '@aws-cdk/aws-s3'; +import * as sfn from '@aws-cdk/aws-stepfunctions'; +import { JsonPath } from '@aws-cdk/aws-stepfunctions'; +import * as cdk from '@aws-cdk/core'; +import * as tasks from '../../lib'; + +/** + * + * Stack verification steps: + * * aws stepfunctions start-execution --state-machine-arn --input {"body": "hello world!"} : should return execution arn + * * + * * aws stepfunctions describe-execution --execution-arn --query 'status': should return status as SUCCEEDED + * * aws stepfunctions describe-execution --execution-arn --query 'output': should return "hello world!" + */ +class TestStack extends cdk.Stack { + constructor(scope: cdk.App, id: string, props: cdk.StackProps = {}) { + super(scope, id, props); + + const bucket = new s3.Bucket(this, 'Bucket'); + + const commonParameters = { + Bucket: bucket.bucketName, + Key: 'test.txt', + }; + + const iamResources = [bucket.arnForObjects('*')]; + + const putObject = new tasks.CallAwsService(this, 'PutObject', { + service: 's3', + action: 'putObject', + parameters: { + Body: sfn.JsonPath.stringAt('$.body'), + ...commonParameters, + }, + iamResources, + }); + + const getObject = new tasks.CallAwsService(this, 'GetObject', { + service: 's3', + action: 'getObject', + parameters: commonParameters, + iamResources, + }); + + const deleteObject = new tasks.CallAwsService(this, 'DeleteObject', { + service: 's3', + action: 'deleteObject', + parameters: commonParameters, + iamResources, + resultPath: JsonPath.DISCARD, + }); + + const stateMachine = new sfn.StateMachine(this, 'StateMachine', { + definition: putObject.next(getObject).next(deleteObject), + }); + + new cdk.CfnOutput(this, 'StateMachineArn', { + value: stateMachine.stateMachineArn, + }); + } +} + +const app = new cdk.App(); +new TestStack(app, 'aws-stepfunctions-aws-sdk-integ'); +app.synth(); diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/eks/integ.call.expected.json b/packages/@aws-cdk/aws-stepfunctions-tasks/test/eks/integ.call.expected.json index 64b6481aab74f..8e3bc703cbde7 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/eks/integ.call.expected.json +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/eks/integ.call.expected.json @@ -84,9 +84,7 @@ "Ref": "EksClusterDefaultVpcIGWCA6A3220" } }, - "DependsOn": [ - "EksClusterDefaultVpcVPCGW0E4A5673" - ] + "DependsOn": ["EksClusterDefaultVpcVPCGW0E4A5673"] }, "EksClusterDefaultVpcPublicSubnet1EIPF53713C9": { "Type": "AWS::EC2::EIP", @@ -107,15 +105,15 @@ "EksClusterDefaultVpcPublicSubnet1NATGateway548C2CDF": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "EksClusterDefaultVpcPublicSubnet1SubnetCB1D1047" + }, "AllocationId": { "Fn::GetAtt": [ "EksClusterDefaultVpcPublicSubnet1EIPF53713C9", "AllocationId" ] }, - "SubnetId": { - "Ref": "EksClusterDefaultVpcPublicSubnet1SubnetCB1D1047" - }, "Tags": [ { "Key": "kubernetes.io/role/elb", @@ -197,9 +195,7 @@ "Ref": "EksClusterDefaultVpcIGWCA6A3220" } }, - "DependsOn": [ - "EksClusterDefaultVpcVPCGW0E4A5673" - ] + "DependsOn": ["EksClusterDefaultVpcVPCGW0E4A5673"] }, "EksClusterDefaultVpcPublicSubnet2EIP16D41D80": { "Type": "AWS::EC2::EIP", @@ -220,15 +216,15 @@ "EksClusterDefaultVpcPublicSubnet2NATGateway869DDCBF": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "EksClusterDefaultVpcPublicSubnet2SubnetA8FE675D" + }, "AllocationId": { "Fn::GetAtt": [ "EksClusterDefaultVpcPublicSubnet2EIP16D41D80", "AllocationId" ] }, - "SubnetId": { - "Ref": "EksClusterDefaultVpcPublicSubnet2SubnetA8FE675D" - }, "Tags": [ { "Key": "kubernetes.io/role/elb", @@ -310,9 +306,7 @@ "Ref": "EksClusterDefaultVpcIGWCA6A3220" } }, - "DependsOn": [ - "EksClusterDefaultVpcVPCGW0E4A5673" - ] + "DependsOn": ["EksClusterDefaultVpcVPCGW0E4A5673"] }, "EksClusterDefaultVpcPublicSubnet3EIPF8D34EDE": { "Type": "AWS::EC2::EIP", @@ -333,15 +327,15 @@ "EksClusterDefaultVpcPublicSubnet3NATGatewayC35C74D3": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "EksClusterDefaultVpcPublicSubnet3SubnetA04EFFC1" + }, "AllocationId": { "Fn::GetAtt": [ "EksClusterDefaultVpcPublicSubnet3EIPF8D34EDE", "AllocationId" ] }, - "SubnetId": { - "Ref": "EksClusterDefaultVpcPublicSubnet3SubnetA04EFFC1" - }, "Tags": [ { "Key": "kubernetes.io/role/elb", @@ -709,10 +703,7 @@ "Action": "iam:PassRole", "Effect": "Allow", "Resource": { - "Fn::GetAtt": [ - "EksClusterRoleC84B376F", - "Arn" - ] + "Fn::GetAtt": ["EksClusterRoleC84B376F", "Arn"] } }, { @@ -799,10 +790,7 @@ } }, { - "Action": [ - "iam:GetRole", - "iam:listAttachedRolePolicies" - ], + "Action": ["iam:GetRole", "iam:listAttachedRolePolicies"], "Effect": "Allow", "Resource": "*" }, @@ -883,10 +871,7 @@ "name": "eksCluster", "version": "1.18", "roleArn": { - "Fn::GetAtt": [ - "EksClusterRoleC84B376F", - "Arn" - ] + "Fn::GetAtt": ["EksClusterRoleC84B376F", "Arn"] }, "resourcesVpcConfig": { "subnetIds": [ @@ -922,10 +907,7 @@ } }, "AssumeRoleArn": { - "Fn::GetAtt": [ - "EksClusterCreationRole75AABE42", - "Arn" - ] + "Fn::GetAtt": ["EksClusterCreationRole75AABE42", "Arn"] }, "AttributesRevision": 2 }, @@ -1028,17 +1010,11 @@ [ "[{\"apiVersion\":\"v1\",\"kind\":\"ConfigMap\",\"metadata\":{\"name\":\"aws-auth\",\"namespace\":\"kube-system\",\"labels\":{\"aws.cdk.eks/prune-c8f58087a1a3e6c10f65d847befda9c1aa2145a8fc\":\"\"}},\"data\":{\"mapRoles\":\"[{\\\"rolearn\\\":\\\"", { - "Fn::GetAtt": [ - "EksClusterMastersRole3F49FAC3", - "Arn" - ] + "Fn::GetAtt": ["EksClusterMastersRole3F49FAC3", "Arn"] }, "\\\",\\\"username\\\":\\\"", { - "Fn::GetAtt": [ - "EksClusterMastersRole3F49FAC3", - "Arn" - ] + "Fn::GetAtt": ["EksClusterMastersRole3F49FAC3", "Arn"] }, "\\\",\\\"groups\\\":[\\\"system:masters\\\"]},{\\\"rolearn\\\":\\\"", { @@ -1049,17 +1025,11 @@ }, "\\\",\\\"username\\\":\\\"system:node:{{EC2PrivateDNSName}}\\\",\\\"groups\\\":[\\\"system:bootstrappers\\\",\\\"system:nodes\\\"]},{\\\"rolearn\\\":\\\"", { - "Fn::GetAtt": [ - "Role1ABCC5F0", - "Arn" - ] + "Fn::GetAtt": ["Role1ABCC5F0", "Arn"] }, "\\\",\\\"username\\\":\\\"", { - "Fn::GetAtt": [ - "Role1ABCC5F0", - "Arn" - ] + "Fn::GetAtt": ["Role1ABCC5F0", "Arn"] }, "\\\",\\\"groups\\\":[\\\"system:masters\\\"]}]\",\"mapUsers\":\"[]\",\"mapAccounts\":\"[]\"}}]" ] @@ -1069,17 +1039,12 @@ "Ref": "EksClusterFAB68BDB" }, "RoleArn": { - "Fn::GetAtt": [ - "EksClusterCreationRole75AABE42", - "Arn" - ] + "Fn::GetAtt": ["EksClusterCreationRole75AABE42", "Arn"] }, "PruneLabel": "aws.cdk.eks/prune-c8f58087a1a3e6c10f65d847befda9c1aa2145a8fc", "Overwrite": true }, - "DependsOn": [ - "EksClusterKubectlReadyBarrier502B0E83" - ], + "DependsOn": ["EksClusterKubectlReadyBarrier502B0E83"], "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete" }, @@ -1173,9 +1138,7 @@ ], "AmiType": "AL2_x86_64", "ForceUpdateEnabled": true, - "InstanceTypes": [ - "m5.large" - ], + "InstanceTypes": ["m5.large"], "ScalingConfig": { "DesiredSize": 2, "MaxSize": 2, @@ -1200,7 +1163,7 @@ }, "/", { - "Ref": "AssetParametersf14dbf982bfb4e61285bf9e6e91f20eb00e8a36c79c981ceec2437b42a02e216S3BucketE0529475" + "Ref": "AssetParameters0b198930f902d53efb864e939b03a42215307ad763b6c49e200b860e0bf87ba8S3Bucket0CDB4070" }, "/", { @@ -1210,7 +1173,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersf14dbf982bfb4e61285bf9e6e91f20eb00e8a36c79c981ceec2437b42a02e216S3VersionKey736B6614" + "Ref": "AssetParameters0b198930f902d53efb864e939b03a42215307ad763b6c49e200b860e0bf87ba8S3VersionKey9304E721" } ] } @@ -1223,7 +1186,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersf14dbf982bfb4e61285bf9e6e91f20eb00e8a36c79c981ceec2437b42a02e216S3VersionKey736B6614" + "Ref": "AssetParameters0b198930f902d53efb864e939b03a42215307ad763b6c49e200b860e0bf87ba8S3VersionKey9304E721" } ] } @@ -1234,16 +1197,19 @@ }, "Parameters": { "referencetoawsstepfunctionstasksekscallintegEksClusterCreationRole00B486C4Arn": { - "Fn::GetAtt": [ - "EksClusterCreationRole75AABE42", - "Arn" - ] + "Fn::GetAtt": ["EksClusterCreationRole75AABE42", "Arn"] + }, + "referencetoawsstepfunctionstasksekscallintegAssetParameters2fbc509041827d9042c1a07f5a1b3629c583224b5543800048ed8be264460e7eS3Bucket7F9374E5Ref": { + "Ref": "AssetParameters2fbc509041827d9042c1a07f5a1b3629c583224b5543800048ed8be264460e7eS3Bucket575E2F4C" }, - "referencetoawsstepfunctionstasksekscallintegAssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3Bucket61AA45E5Ref": { - "Ref": "AssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3Bucket14D204F9" + "referencetoawsstepfunctionstasksekscallintegAssetParameters2fbc509041827d9042c1a07f5a1b3629c583224b5543800048ed8be264460e7eS3VersionKey43EAF22DRef": { + "Ref": "AssetParameters2fbc509041827d9042c1a07f5a1b3629c583224b5543800048ed8be264460e7eS3VersionKeyFB3EB544" }, - "referencetoawsstepfunctionstasksekscallintegAssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3VersionKey48ACDBCFRef": { - "Ref": "AssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3VersionKeyDE8A2F1F" + "referencetoawsstepfunctionstasksekscallintegAssetParametersd1380bb36e9a4e378cf1d8fe7779efa967f218e380fd40aad493f588a9872dd6S3Bucket32160528Ref": { + "Ref": "AssetParametersd1380bb36e9a4e378cf1d8fe7779efa967f218e380fd40aad493f588a9872dd6S3Bucket04F6B25B" + }, + "referencetoawsstepfunctionstasksekscallintegAssetParametersd1380bb36e9a4e378cf1d8fe7779efa967f218e380fd40aad493f588a9872dd6S3VersionKeyCEEE7AF3Ref": { + "Ref": "AssetParametersd1380bb36e9a4e378cf1d8fe7779efa967f218e380fd40aad493f588a9872dd6S3VersionKey6A7508AF" }, "referencetoawsstepfunctionstasksekscallintegAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketCF9FB24DRef": { "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" @@ -1273,7 +1239,7 @@ }, "/", { - "Ref": "AssetParameters9d41118c36f364bd9f7de59dda09afbef182ac0f726496523af8ffd24aafc604S3BucketCAFDB26C" + "Ref": "AssetParameters71b4be22b7489e3746d72802bb115cc0c5c2c2a8efac49a7e81e6257bec20ae5S3BucketEC7134BF" }, "/", { @@ -1283,7 +1249,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters9d41118c36f364bd9f7de59dda09afbef182ac0f726496523af8ffd24aafc604S3VersionKey3CF353E9" + "Ref": "AssetParameters71b4be22b7489e3746d72802bb115cc0c5c2c2a8efac49a7e81e6257bec20ae5S3VersionKey3EC7EA95" } ] } @@ -1296,7 +1262,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters9d41118c36f364bd9f7de59dda09afbef182ac0f726496523af8ffd24aafc604S3VersionKey3CF353E9" + "Ref": "AssetParameters71b4be22b7489e3746d72802bb115cc0c5c2c2a8efac49a7e81e6257bec20ae5S3VersionKey3EC7EA95" } ] } @@ -1307,22 +1273,16 @@ }, "Parameters": { "referencetoawsstepfunctionstasksekscallintegEksClusterCA674174Arn": { - "Fn::GetAtt": [ - "EksClusterFAB68BDB", - "Arn" - ] + "Fn::GetAtt": ["EksClusterFAB68BDB", "Arn"] }, "referencetoawsstepfunctionstasksekscallintegEksClusterCreationRole00B486C4Arn": { - "Fn::GetAtt": [ - "EksClusterCreationRole75AABE42", - "Arn" - ] + "Fn::GetAtt": ["EksClusterCreationRole75AABE42", "Arn"] }, - "referencetoawsstepfunctionstasksekscallintegAssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3BucketB45933E2Ref": { - "Ref": "AssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3Bucket008DBB35" + "referencetoawsstepfunctionstasksekscallintegAssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3BucketF4AF10B8Ref": { + "Ref": "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3BucketC6FAEEC9" }, - "referencetoawsstepfunctionstasksekscallintegAssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3VersionKey897E2F88Ref": { - "Ref": "AssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3VersionKey97C3E1A0" + "referencetoawsstepfunctionstasksekscallintegAssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3VersionKey04C67745Ref": { + "Ref": "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3VersionKeyA7EE7421" }, "referencetoawsstepfunctionstasksekscallintegEksClusterDefaultVpcPrivateSubnet1Subnet3A6964EARef": { "Ref": "EksClusterDefaultVpcPrivateSubnet1Subnet4D665A2F" @@ -1334,10 +1294,7 @@ "Ref": "EksClusterDefaultVpcPrivateSubnet3Subnet6C4BFC07" }, "referencetoawsstepfunctionstasksekscallintegEksClusterCA674174ClusterSecurityGroupId": { - "Fn::GetAtt": [ - "EksClusterFAB68BDB", - "ClusterSecurityGroupId" - ] + "Fn::GetAtt": ["EksClusterFAB68BDB", "ClusterSecurityGroupId"] }, "referencetoawsstepfunctionstasksekscallintegAssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3Bucket3F56B6C0Ref": { "Ref": "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketAEADE8C7" @@ -1345,11 +1302,11 @@ "referencetoawsstepfunctionstasksekscallintegAssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKey14F73D88Ref": { "Ref": "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyE415415F" }, - "referencetoawsstepfunctionstasksekscallintegAssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0S3Bucket82DB0998Ref": { - "Ref": "AssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0S3Bucket6ABE1927" + "referencetoawsstepfunctionstasksekscallintegAssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3Bucket91831D54Ref": { + "Ref": "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3BucketD3288998" }, - "referencetoawsstepfunctionstasksekscallintegAssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0S3VersionKey5CB2DA63Ref": { - "Ref": "AssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0S3VersionKeyF55A2EA9" + "referencetoawsstepfunctionstasksekscallintegAssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3VersionKeyAFE7B9F9Ref": { + "Ref": "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3VersionKeyB00C0565" }, "referencetoawsstepfunctionstasksekscallintegAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketCF9FB24DRef": { "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" @@ -1395,10 +1352,7 @@ "Type": "AWS::StepFunctions::StateMachine", "Properties": { "RoleArn": { - "Fn::GetAtt": [ - "Role1ABCC5F0", - "Arn" - ] + "Fn::GetAtt": ["Role1ABCC5F0", "Arn"] }, "DefinitionString": { "Fn::Join": [ @@ -1414,26 +1368,18 @@ }, "\",\"CertificateAuthority\":\"", { - "Fn::GetAtt": [ - "EksClusterFAB68BDB", - "CertificateAuthorityData" - ] + "Fn::GetAtt": ["EksClusterFAB68BDB", "CertificateAuthorityData"] }, "\",\"Endpoint\":\"", { - "Fn::GetAtt": [ - "EksClusterFAB68BDB", - "Endpoint" - ] + "Fn::GetAtt": ["EksClusterFAB68BDB", "Endpoint"] }, "\",\"Method\":\"GET\",\"Path\":\"/api/v1/namespaces/default/pods\"}}},\"TimeoutSeconds\":30}" ] ] } }, - "DependsOn": [ - "Role1ABCC5F0" - ] + "DependsOn": ["Role1ABCC5F0"] } }, "Outputs": { @@ -1452,10 +1398,7 @@ }, " --role-arn ", { - "Fn::GetAtt": [ - "EksClusterMastersRole3F49FAC3", - "Arn" - ] + "Fn::GetAtt": ["EksClusterMastersRole3F49FAC3", "Arn"] } ] ] @@ -1476,10 +1419,7 @@ }, " --role-arn ", { - "Fn::GetAtt": [ - "EksClusterMastersRole3F49FAC3", - "Arn" - ] + "Fn::GetAtt": ["EksClusterMastersRole3F49FAC3", "Arn"] } ] ] @@ -1492,17 +1432,29 @@ } }, "Parameters": { - "AssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3Bucket14D204F9": { + "AssetParameters2fbc509041827d9042c1a07f5a1b3629c583224b5543800048ed8be264460e7eS3Bucket575E2F4C": { + "Type": "String", + "Description": "S3 bucket for asset \"2fbc509041827d9042c1a07f5a1b3629c583224b5543800048ed8be264460e7e\"" + }, + "AssetParameters2fbc509041827d9042c1a07f5a1b3629c583224b5543800048ed8be264460e7eS3VersionKeyFB3EB544": { + "Type": "String", + "Description": "S3 key for asset version \"2fbc509041827d9042c1a07f5a1b3629c583224b5543800048ed8be264460e7e\"" + }, + "AssetParameters2fbc509041827d9042c1a07f5a1b3629c583224b5543800048ed8be264460e7eArtifactHashDB8E8B5A": { + "Type": "String", + "Description": "Artifact hash for asset \"2fbc509041827d9042c1a07f5a1b3629c583224b5543800048ed8be264460e7e\"" + }, + "AssetParametersd1380bb36e9a4e378cf1d8fe7779efa967f218e380fd40aad493f588a9872dd6S3Bucket04F6B25B": { "Type": "String", - "Description": "S3 bucket for asset \"87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dba\"" + "Description": "S3 bucket for asset \"d1380bb36e9a4e378cf1d8fe7779efa967f218e380fd40aad493f588a9872dd6\"" }, - "AssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3VersionKeyDE8A2F1F": { + "AssetParametersd1380bb36e9a4e378cf1d8fe7779efa967f218e380fd40aad493f588a9872dd6S3VersionKey6A7508AF": { "Type": "String", - "Description": "S3 key for asset version \"87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dba\"" + "Description": "S3 key for asset version \"d1380bb36e9a4e378cf1d8fe7779efa967f218e380fd40aad493f588a9872dd6\"" }, - "AssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaArtifactHash54822A43": { + "AssetParametersd1380bb36e9a4e378cf1d8fe7779efa967f218e380fd40aad493f588a9872dd6ArtifactHashF7473C14": { "Type": "String", - "Description": "Artifact hash for asset \"87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dba\"" + "Description": "Artifact hash for asset \"d1380bb36e9a4e378cf1d8fe7779efa967f218e380fd40aad493f588a9872dd6\"" }, "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1": { "Type": "String", @@ -1516,17 +1468,17 @@ "Type": "String", "Description": "Artifact hash for asset \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" }, - "AssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3Bucket008DBB35": { + "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3BucketC6FAEEC9": { "Type": "String", - "Description": "S3 bucket for asset \"bafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757\"" + "Description": "S3 bucket for asset \"4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10\"" }, - "AssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3VersionKey97C3E1A0": { + "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3VersionKeyA7EE7421": { "Type": "String", - "Description": "S3 key for asset version \"bafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757\"" + "Description": "S3 key for asset version \"4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10\"" }, - "AssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757ArtifactHashF584A7D8": { + "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10ArtifactHash528547CD": { "Type": "String", - "Description": "Artifact hash for asset \"bafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757\"" + "Description": "Artifact hash for asset \"4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10\"" }, "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketAEADE8C7": { "Type": "String", @@ -1540,41 +1492,41 @@ "Type": "String", "Description": "Artifact hash for asset \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" }, - "AssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0S3Bucket6ABE1927": { + "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3BucketD3288998": { "Type": "String", - "Description": "S3 bucket for asset \"844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0\"" + "Description": "S3 bucket for asset \"ea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03e\"" }, - "AssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0S3VersionKeyF55A2EA9": { + "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3VersionKeyB00C0565": { "Type": "String", - "Description": "S3 key for asset version \"844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0\"" + "Description": "S3 key for asset version \"ea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03e\"" }, - "AssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0ArtifactHash1D7A2D6E": { + "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eArtifactHash4654D012": { "Type": "String", - "Description": "Artifact hash for asset \"844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0\"" + "Description": "Artifact hash for asset \"ea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03e\"" }, - "AssetParametersf14dbf982bfb4e61285bf9e6e91f20eb00e8a36c79c981ceec2437b42a02e216S3BucketE0529475": { + "AssetParameters0b198930f902d53efb864e939b03a42215307ad763b6c49e200b860e0bf87ba8S3Bucket0CDB4070": { "Type": "String", - "Description": "S3 bucket for asset \"f14dbf982bfb4e61285bf9e6e91f20eb00e8a36c79c981ceec2437b42a02e216\"" + "Description": "S3 bucket for asset \"0b198930f902d53efb864e939b03a42215307ad763b6c49e200b860e0bf87ba8\"" }, - "AssetParametersf14dbf982bfb4e61285bf9e6e91f20eb00e8a36c79c981ceec2437b42a02e216S3VersionKey736B6614": { + "AssetParameters0b198930f902d53efb864e939b03a42215307ad763b6c49e200b860e0bf87ba8S3VersionKey9304E721": { "Type": "String", - "Description": "S3 key for asset version \"f14dbf982bfb4e61285bf9e6e91f20eb00e8a36c79c981ceec2437b42a02e216\"" + "Description": "S3 key for asset version \"0b198930f902d53efb864e939b03a42215307ad763b6c49e200b860e0bf87ba8\"" }, - "AssetParametersf14dbf982bfb4e61285bf9e6e91f20eb00e8a36c79c981ceec2437b42a02e216ArtifactHash85D00783": { + "AssetParameters0b198930f902d53efb864e939b03a42215307ad763b6c49e200b860e0bf87ba8ArtifactHash27112E89": { "Type": "String", - "Description": "Artifact hash for asset \"f14dbf982bfb4e61285bf9e6e91f20eb00e8a36c79c981ceec2437b42a02e216\"" + "Description": "Artifact hash for asset \"0b198930f902d53efb864e939b03a42215307ad763b6c49e200b860e0bf87ba8\"" }, - "AssetParameters9d41118c36f364bd9f7de59dda09afbef182ac0f726496523af8ffd24aafc604S3BucketCAFDB26C": { + "AssetParameters71b4be22b7489e3746d72802bb115cc0c5c2c2a8efac49a7e81e6257bec20ae5S3BucketEC7134BF": { "Type": "String", - "Description": "S3 bucket for asset \"9d41118c36f364bd9f7de59dda09afbef182ac0f726496523af8ffd24aafc604\"" + "Description": "S3 bucket for asset \"71b4be22b7489e3746d72802bb115cc0c5c2c2a8efac49a7e81e6257bec20ae5\"" }, - "AssetParameters9d41118c36f364bd9f7de59dda09afbef182ac0f726496523af8ffd24aafc604S3VersionKey3CF353E9": { + "AssetParameters71b4be22b7489e3746d72802bb115cc0c5c2c2a8efac49a7e81e6257bec20ae5S3VersionKey3EC7EA95": { "Type": "String", - "Description": "S3 key for asset version \"9d41118c36f364bd9f7de59dda09afbef182ac0f726496523af8ffd24aafc604\"" + "Description": "S3 key for asset version \"71b4be22b7489e3746d72802bb115cc0c5c2c2a8efac49a7e81e6257bec20ae5\"" }, - "AssetParameters9d41118c36f364bd9f7de59dda09afbef182ac0f726496523af8ffd24aafc604ArtifactHashEC502675": { + "AssetParameters71b4be22b7489e3746d72802bb115cc0c5c2c2a8efac49a7e81e6257bec20ae5ArtifactHashCD2D1888": { "Type": "String", - "Description": "Artifact hash for asset \"9d41118c36f364bd9f7de59dda09afbef182ac0f726496523af8ffd24aafc604\"" + "Description": "Artifact hash for asset \"71b4be22b7489e3746d72802bb115cc0c5c2c2a8efac49a7e81e6257bec20ae5\"" } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/emr/emr-create-cluster.test.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/test/emr/emr-create-cluster.test.ts index 273a580a6a38e..3effd99e5eed0 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/emr/emr-create-cluster.test.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/emr/emr-create-cluster.test.ts @@ -172,6 +172,112 @@ test('Create Cluster with clusterConfiguration Name from payload', () => { }); }); +describe('Cluster with StepConcurrencyLevel', () => { + test('can be specified', async () => { + // WHEN + const task = new EmrCreateCluster(stack, 'Task', { + instances: {}, + clusterRole, + name: 'Cluster', + serviceRole, + autoScalingRole, + stepConcurrencyLevel: 2, + integrationPattern: sfn.IntegrationPattern.REQUEST_RESPONSE, + }); + + // THEN + expect(stack.resolve(task.toStateJson())).toMatchObject({ + Parameters: { + Name: 'Cluster', + StepConcurrencyLevel: 2, + }, + }); + }); + + test('throws if < 1 or > 256', async () => { + expect(() => new EmrCreateCluster(stack, 'Task1', { + instances: {}, + clusterRole, + name: 'Cluster', + serviceRole, + autoScalingRole, + stepConcurrencyLevel: 0, + integrationPattern: sfn.IntegrationPattern.REQUEST_RESPONSE, + })).toThrow('Step concurrency level must be in range [1, 256], but got 0.'); + + expect(() => new EmrCreateCluster(stack, 'Task2', { + instances: {}, + clusterRole, + name: 'Cluster', + serviceRole, + autoScalingRole, + stepConcurrencyLevel: 257, + integrationPattern: sfn.IntegrationPattern.REQUEST_RESPONSE, + })).toThrow('Step concurrency level must be in range [1, 256], but got 257.'); + }); + + test('throws if EMR release label below 5.28 and StepConcurrencyLevel !== 1', async () => { + expect(() => new EmrCreateCluster(stack, 'Task2', { + instances: {}, + clusterRole, + name: 'Cluster', + serviceRole, + autoScalingRole, + releaseLabel: 'emr-5.14.0', + stepConcurrencyLevel: 2, + integrationPattern: sfn.IntegrationPattern.REQUEST_RESPONSE, + })).toThrow('Step concurrency is only supported in EMR release version 5.28.0 and above but got emr-5.14.0.'); + }); + + test('does not throw if EMR release label below 5.28 and StepConcurrencyLevel === 1', async () => { + new EmrCreateCluster(stack, 'Task1', { + instances: {}, + clusterRole, + name: 'Cluster', + serviceRole, + autoScalingRole, + releaseLabel: 'emr-5.14.0', + stepConcurrencyLevel: 1, + integrationPattern: sfn.IntegrationPattern.REQUEST_RESPONSE, + }); + }); +}); + +test('Cluster with invalid release label will throw', async () => { + expect(() => new EmrCreateCluster(stack, 'Task1', { + instances: {}, + clusterRole, + name: 'Cluster', + serviceRole, + autoScalingRole, + releaseLabel: 'emra-5.14.0', + stepConcurrencyLevel: 1, + integrationPattern: sfn.IntegrationPattern.REQUEST_RESPONSE, + })).toThrow('The release label must be in the format \'emr-x.x.x\' but got emra-5.14.0'); + + expect(() => new EmrCreateCluster(stack, 'Task2', { + instances: {}, + clusterRole, + name: 'Cluster', + serviceRole, + autoScalingRole, + releaseLabel: 'emr-5.14.a', + stepConcurrencyLevel: 1, + integrationPattern: sfn.IntegrationPattern.REQUEST_RESPONSE, + })).toThrow('The release label must be in the format \'emr-x.x.x\' but got emr-5.14.a'); + + expect(() => new EmrCreateCluster(stack, 'Task3', { + instances: {}, + clusterRole, + name: 'Cluster', + serviceRole, + autoScalingRole, + releaseLabel: 'emr-5.14.0.0', + stepConcurrencyLevel: 1, + integrationPattern: sfn.IntegrationPattern.REQUEST_RESPONSE, + })).toThrow('The release label must be in the format \'emr-x.x.x\' but got emr-5.14.0.0'); +}); + test('Create Cluster with Tags', () => { // WHEN const task = new EmrCreateCluster(stack, 'Task', { diff --git a/packages/@aws-cdk/aws-stepfunctions/.eslintrc.js b/packages/@aws-cdk/aws-stepfunctions/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-stepfunctions/.eslintrc.js +++ b/packages/@aws-cdk/aws-stepfunctions/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-stepfunctions/README.md b/packages/@aws-cdk/aws-stepfunctions/README.md index 6171bac75805a..52aa717e6d1a2 100644 --- a/packages/@aws-cdk/aws-stepfunctions/README.md +++ b/packages/@aws-cdk/aws-stepfunctions/README.md @@ -22,6 +22,7 @@ example](https://docs.aws.amazon.com/step-functions/latest/dg/job-status-poller- ## Example ```ts +import * as cdk from '@aws-cdk/core'; import * as sfn from '@aws-cdk/aws-stepfunctions'; import * as tasks from '@aws-cdk/aws-stepfunctions-tasks'; import * as lambda from '@aws-cdk/aws-lambda'; @@ -36,7 +37,7 @@ const submitJob = new tasks.LambdaInvoke(this, 'Submit Job', { }); const waitX = new sfn.Wait(this, 'Wait X Seconds', { - time: sfn.WaitTime.secondsPath('$.waitSeconds'), + time: sfn.WaitTime.secondsPath('$.waitSeconds'), }); const getStatus = new tasks.LambdaInvoke(this, 'Get Job Status', { @@ -48,8 +49,8 @@ const getStatus = new tasks.LambdaInvoke(this, 'Get Job Status', { }); const jobFailed = new sfn.Fail(this, 'Job Failed', { - cause: 'AWS Batch Job Failed', - error: 'DescribeJob returned FAILED', + cause: 'AWS Batch Job Failed', + error: 'DescribeJob returned FAILED', }); const finalStatus = new tasks.LambdaInvoke(this, 'Get Final Job Status', { @@ -60,17 +61,17 @@ const finalStatus = new tasks.LambdaInvoke(this, 'Get Final Job Status', { }); const definition = submitJob - .next(waitX) - .next(getStatus) - .next(new sfn.Choice(this, 'Job Complete?') - // Look at the "status" field - .when(sfn.Condition.stringEquals('$.status', 'FAILED'), jobFailed) - .when(sfn.Condition.stringEquals('$.status', 'SUCCEEDED'), finalStatus) - .otherwise(waitX)); + .next(waitX) + .next(getStatus) + .next(new sfn.Choice(this, 'Job Complete?') + // Look at the "status" field + .when(sfn.Condition.stringEquals('$.status', 'FAILED'), jobFailed) + .when(sfn.Condition.stringEquals('$.status', 'SUCCEEDED'), finalStatus) + .otherwise(waitX)); new sfn.StateMachine(this, 'StateMachine', { - definition, - timeout: Duration.minutes(5) + definition, + timeout: cdk.Duration.minutes(5), }); ``` @@ -87,7 +88,7 @@ all states reachable from the start state: const startState = new sfn.Pass(this, 'StartState'); new sfn.StateMachine(this, 'StateMachine', { - definition: startState + definition: startState, }); ``` @@ -157,7 +158,7 @@ and also injects a field called `otherData`. const pass = new sfn.Pass(this, 'Filter input and inject data', { parameters: { // input to the pass state input: sfn.JsonPath.stringAt('$.input.greeting'), - otherData: 'some-extra-stuff' + otherData: 'some-extra-stuff', }, }); ``` @@ -178,7 +179,7 @@ state. // Wait until it's the time mentioned in the the state object's "triggerTime" // field. const wait = new sfn.Wait(this, 'Wait For Trigger Time', { - time: sfn.WaitTime.timestampPath('$.triggerTime'), + time: sfn.WaitTime.timestampPath('$.triggerTime'), }); // Set the next state @@ -309,8 +310,8 @@ Failures can be caught by encompassing `Parallel` states. ```ts const success = new sfn.Fail(this, 'Fail', { - error: 'WorkflowFailure', - cause: "Something went wrong" + error: 'WorkflowFailure', + cause: "Something went wrong", }); ``` @@ -324,8 +325,8 @@ execute the same steps for multiple entries of an array in the state input. ```ts const map = new sfn.Map(this, 'Map State', { - maxConcurrency: 1, - itemsPath: sfn.JsonPath.stringAt('$.inputForMap') + maxConcurrency: 1, + itemsPath: sfn.JsonPath.stringAt('$.inputForMap'), }); map.iterator(new sfn.Pass(this, 'Pass State')); ``` @@ -353,8 +354,8 @@ the State Machine uses. The following example uses the `DynamoDB` service integration to insert data into a DynamoDB table. ```ts -import * as ddb from '@aws-cdk/aws-dynamodb'; import * as cdk from '@aws-cdk/core'; +import * as ddb from '@aws-cdk/aws-dynamodb'; import * as sfn from '@aws-cdk/aws-stepfunctions'; // create a table @@ -389,7 +390,7 @@ const custom = new sfn.CustomState(this, 'my custom task', { }); const chain = sfn.Chain.start(custom) - .next(finalStatus); + .next(finalStatus); const sm = new sfn.StateMachine(this, 'StateMachine', { definition: chain, @@ -410,18 +411,18 @@ targets of `Choice.on` or `Parallel.branch`: ```ts const definition = step1 - .next(step2) - .next(choice - .when(condition1, step3.next(step4).next(step5)) - .otherwise(step6) - .afterwards()) - .next(parallel - .branch(step7.next(step8)) - .branch(step9.next(step10))) - .next(finish); + .next(step2) + .next(choice + .when(condition1, step3.next(step4).next(step5)) + .otherwise(step6) + .afterwards()) + .next(parallel + .branch(step7.next(step8)) + .branch(step9.next(step10))) + .next(finish); new sfn.StateMachine(this, 'StateMachine', { - definition, + definition, }); ``` @@ -430,10 +431,10 @@ step, you can use `Chain.start`: ```ts const definition = sfn.Chain - .start(step1) - .next(step2) - .next(step3) - // ... + .start(step1) + .next(step2) + .next(step3) + // ... ``` ## State Machine Fragments @@ -457,30 +458,30 @@ machine as a subclass of this, it will be convenient to use: ```ts interface MyJobProps { - jobFlavor: string; + jobFlavor: string; } class MyJob extends sfn.StateMachineFragment { - public readonly startState: sfn.State; - public readonly endStates: sfn.INextable[]; + public readonly startState: sfn.State; + public readonly endStates: sfn.INextable[]; - constructor(parent: cdk.Construct, id: string, props: MyJobProps) { - super(parent, id); + constructor(parent: cdk.Construct, id: string, props: MyJobProps) { + super(parent, id); - const first = new sfn.Task(this, 'First', { ... }); - // ... - const last = new sfn.Task(this, 'Last', { ... }); + const first = new sfn.Task(this, 'First', { ... }); + // ... + const last = new sfn.Task(this, 'Last', { ... }); - this.startState = first; - this.endStates = [last]; - } + this.startState = first; + this.endStates = [last]; + } } // Do 3 different variants of MyJob in parallel new sfn.Parallel(this, 'All jobs') - .branch(new MyJob(this, 'Quick', { jobFlavor: 'quick' }).prefixStates()) - .branch(new MyJob(this, 'Medium', { jobFlavor: 'medium' }).prefixStates()) - .branch(new MyJob(this, 'Slow', { jobFlavor: 'slow' }).prefixStates()); + .branch(new MyJob(this, 'Quick', { jobFlavor: 'quick' }).prefixStates()) + .branch(new MyJob(this, 'Medium', { jobFlavor: 'medium' }).prefixStates()) + .branch(new MyJob(this, 'Slow', { jobFlavor: 'slow' }).prefixStates()); ``` A few utility functions are available to parse state machine fragments. @@ -529,9 +530,9 @@ to create an alarm on a particular task failing: ```ts new cloudwatch.Alarm(this, 'TaskAlarm', { - metric: task.metricFailed(), - threshold: 1, - evaluationPeriods: 1, + metric: task.metricFailed(), + threshold: 1, + evaluationPeriods: 1, }); ``` @@ -539,9 +540,9 @@ There are also metrics on the complete state machine: ```ts new cloudwatch.Alarm(this, 'StateMachineAlarm', { - metric: stateMachine.metricFailed(), - threshold: 1, - evaluationPeriods: 1, + metric: stateMachine.metricFailed(), + threshold: 1, + evaluationPeriods: 1, }); ``` @@ -549,9 +550,9 @@ And there are metrics on the capacity of all state machines in your account: ```ts new cloudwatch.Alarm(this, 'ThrottledAlarm', { - metric: StateTransitionMetrics.metricThrottledEvents(), - threshold: 10, - evaluationPeriods: 2, + metric: StateTransitionMetrics.metricThrottledEvents(), + threshold: 10, + evaluationPeriods: 2, }); ``` @@ -580,11 +581,11 @@ destination LogGroup: const logGroup = new logs.LogGroup(stack, 'MyLogGroup'); new sfn.StateMachine(stack, 'MyStateMachine', { - definition: sfn.Chain.start(new sfn.Pass(stack, 'Pass')), - logs: { - destination: logGroup, - level: sfn.LogLevel.ALL, - } + definition: sfn.Chain.start(new sfn.Pass(stack, 'Pass')), + logs: { + destination: logGroup, + level: sfn.LogLevel.ALL, + }, }); ``` @@ -594,8 +595,8 @@ Enable X-Ray tracing for StateMachine: ```ts new sfn.StateMachine(stack, 'MyStateMachine', { - definition: sfn.Chain.start(new sfn.Pass(stack, 'Pass')), - tracingEnabled: true + definition: sfn.Chain.start(new sfn.Pass(stack, 'Pass')), + tracingEnabled: true, }); ``` @@ -732,5 +733,6 @@ const stack = new Stack(app, 'MyStack'); sfn.StateMachine.fromStateMachineArn( stack, 'ImportedStateMachine', - 'arn:aws:states:us-east-1:123456789012:stateMachine:StateMachine2E01A3A5-N5TJppzoevKQ'); + 'arn:aws:states:us-east-1:123456789012:stateMachine:StateMachine2E01A3A5-N5TJppzoevKQ', +); ``` diff --git a/packages/@aws-cdk/aws-stepfunctions/jest.config.js b/packages/@aws-cdk/aws-stepfunctions/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-stepfunctions/jest.config.js +++ b/packages/@aws-cdk/aws-stepfunctions/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-stepfunctions/package.json b/packages/@aws-cdk/aws-stepfunctions/package.json index a5141b16bf045..dbbb99ff04844 100644 --- a/packages/@aws-cdk/aws-stepfunctions/package.json +++ b/packages/@aws-cdk/aws-stepfunctions/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::StepFunctions", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,12 +72,12 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/aws-cloudwatch": "0.0.0", diff --git a/packages/@aws-cdk/aws-synthetics/.eslintrc.js b/packages/@aws-cdk/aws-synthetics/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-synthetics/.eslintrc.js +++ b/packages/@aws-cdk/aws-synthetics/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-synthetics/README.md b/packages/@aws-cdk/aws-synthetics/README.md index bd4fcaede272c..ba0482d3aa263 100644 --- a/packages/@aws-cdk/aws-synthetics/README.md +++ b/packages/@aws-cdk/aws-synthetics/README.md @@ -44,7 +44,7 @@ const canary = new synthetics.Canary(this, 'MyCanary', { }), runtime: synthetics.Runtime.SYNTHETICS_NODEJS_PUPPETEER_3_1, environmentVariables: { - stage: 'prod', + stage: 'prod', }, }); ``` @@ -56,24 +56,24 @@ const synthetics = require('Synthetics'); const log = require('SyntheticsLogger'); const pageLoadBlueprint = async function () { - // Configure the stage of the API using environment variables - const url = `https://api.example.com/${process.env.stage}/user/books/topbook/`; - - const page = await synthetics.getPage(); - const response = await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 30000 }); - // Wait for page to render. Increase or decrease wait time based on endpoint being monitored. - await page.waitFor(15000); - // This will take a screenshot that will be included in test output artifacts. - await synthetics.takeScreenshot('loaded', 'loaded'); - const pageTitle = await page.title(); - log.info('Page title: ' + pageTitle); - if (response.status() !== 200) { - throw 'Failed to load page!'; - } + // Configure the stage of the API using environment variables + const url = `https://api.example.com/${process.env.stage}/user/books/topbook/`; + + const page = await synthetics.getPage(); + const response = await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 30000 }); + // Wait for page to render. Increase or decrease wait time based on endpoint being monitored. + await page.waitFor(15000); + // This will take a screenshot that will be included in test output artifacts. + await synthetics.takeScreenshot('loaded', 'loaded'); + const pageTitle = await page.title(); + log.info('Page title: ' + pageTitle); + if (response.status() !== 200) { + throw 'Failed to load page!'; + } }; exports.handler = async () => { - return await pageLoadBlueprint(); + return await pageLoadBlueprint(); }; ``` @@ -87,6 +87,27 @@ The Canary code will be executed in a lambda function created by Synthetics on y To learn more about Synthetics capabilities, check out the [docs](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Synthetics_Canaries.html). + +### Canary Schedule + +You can specify the schedule on which a canary runs by providing a +[`Schedule`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-synthetics.Schedule.html) +object to the `schedule` property. + +Configure a run rate of up to 60 minutes with `Schedule.rate`: + +```ts +Schedule.rate(Duration.minutes(5)), // Runs every 5 minutes. +``` + +You can also specify a [cron expression](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Synthetics_Canaries_cron.html) via `Schedule.expression`: + +```ts +Schedule.expression('cron(0 0,8,16 * * ? *)'), // Run at 12am, 8am, 4pm UTC every day +``` + +If you want the canary to run just once upon deployment, you can use `Schedule.once()`. + ### Configuring the Canary Script To configure the script the canary executes, use the `test` property. The `test` property accepts a `Test` instance that can be initialized by the `Test` class static methods. Currently, the only implemented method is `Test.custom()`, which allows you to bring your own code. In the future, other methods will be added. `Test.custom()` accepts `code` and `handler` properties -- both are required by Synthetics to create a lambda function on your behalf. diff --git a/packages/@aws-cdk/aws-synthetics/jest.config.js b/packages/@aws-cdk/aws-synthetics/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-synthetics/jest.config.js +++ b/packages/@aws-cdk/aws-synthetics/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-synthetics/package.json b/packages/@aws-cdk/aws-synthetics/package.json index 7febc7e87b686..6504764f4f218 100644 --- a/packages/@aws-cdk/aws-synthetics/package.json +++ b/packages/@aws-cdk/aws-synthetics/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::Synthetics", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,27 +74,27 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { + "@aws-cdk/aws-cloudwatch": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/aws-s3-assets": "0.0.0", "@aws-cdk/core": "0.0.0", - "@aws-cdk/aws-cloudwatch": "0.0.0", "constructs": "^3.3.69" }, "peerDependencies": { - "@aws-cdk/core": "0.0.0", + "@aws-cdk/aws-cloudwatch": "0.0.0", + "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/aws-s3-assets": "0.0.0", - "@aws-cdk/aws-iam": "0.0.0", - "@aws-cdk/aws-cloudwatch": "0.0.0", + "@aws-cdk/core": "0.0.0", "constructs": "^3.3.69" }, "engines": { diff --git a/packages/@aws-cdk/aws-synthetics/test/canary.test.ts b/packages/@aws-cdk/aws-synthetics/test/canary.test.ts index c4583ef5494cf..27491d01b2850 100644 --- a/packages/@aws-cdk/aws-synthetics/test/canary.test.ts +++ b/packages/@aws-cdk/aws-synthetics/test/canary.test.ts @@ -229,7 +229,7 @@ test('environment variables are skipped if not provided', () => { // THEN Template.fromStack(stack).hasResourceProperties('AWS::Synthetics::Canary', { - RunConfig: Match.absentProperty(), + RunConfig: Match.absent(), }); }); diff --git a/packages/@aws-cdk/aws-timestream/.eslintrc.js b/packages/@aws-cdk/aws-timestream/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-timestream/.eslintrc.js +++ b/packages/@aws-cdk/aws-timestream/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-timestream/jest.config.js b/packages/@aws-cdk/aws-timestream/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-timestream/jest.config.js +++ b/packages/@aws-cdk/aws-timestream/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-timestream/package.json b/packages/@aws-cdk/aws-timestream/package.json index 82e1fb198680b..8e812faac660d 100644 --- a/packages/@aws-cdk/aws-timestream/package.json +++ b/packages/@aws-cdk/aws-timestream/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::Timestream", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-transfer/.eslintrc.js b/packages/@aws-cdk/aws-transfer/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-transfer/.eslintrc.js +++ b/packages/@aws-cdk/aws-transfer/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-transfer/jest.config.js b/packages/@aws-cdk/aws-transfer/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-transfer/jest.config.js +++ b/packages/@aws-cdk/aws-transfer/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-transfer/package.json b/packages/@aws-cdk/aws-transfer/package.json index 4d8e05fab19f5..3dcd461a79ab6 100644 --- a/packages/@aws-cdk/aws-transfer/package.json +++ b/packages/@aws-cdk/aws-transfer/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::Transfer", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-waf/.eslintrc.js b/packages/@aws-cdk/aws-waf/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-waf/.eslintrc.js +++ b/packages/@aws-cdk/aws-waf/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-waf/jest.config.js b/packages/@aws-cdk/aws-waf/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-waf/jest.config.js +++ b/packages/@aws-cdk/aws-waf/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-waf/package.json b/packages/@aws-cdk/aws-waf/package.json index 8c4f85f3402b7..33482a6fa8f12 100644 --- a/packages/@aws-cdk/aws-waf/package.json +++ b/packages/@aws-cdk/aws-waf/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::WAF", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,11 +72,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-wafregional/.eslintrc.js b/packages/@aws-cdk/aws-wafregional/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-wafregional/.eslintrc.js +++ b/packages/@aws-cdk/aws-wafregional/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-wafregional/jest.config.js b/packages/@aws-cdk/aws-wafregional/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-wafregional/jest.config.js +++ b/packages/@aws-cdk/aws-wafregional/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-wafregional/package.json b/packages/@aws-cdk/aws-wafregional/package.json index e82afe0e25e4a..4710718baec70 100644 --- a/packages/@aws-cdk/aws-wafregional/package.json +++ b/packages/@aws-cdk/aws-wafregional/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::WAFRegional", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,11 +72,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-wafv2/.eslintrc.js b/packages/@aws-cdk/aws-wafv2/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-wafv2/.eslintrc.js +++ b/packages/@aws-cdk/aws-wafv2/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-wafv2/jest.config.js b/packages/@aws-cdk/aws-wafv2/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-wafv2/jest.config.js +++ b/packages/@aws-cdk/aws-wafv2/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-wafv2/package.json b/packages/@aws-cdk/aws-wafv2/package.json index c46028b894625..6ac9c2eb572fa 100644 --- a/packages/@aws-cdk/aws-wafv2/package.json +++ b/packages/@aws-cdk/aws-wafv2/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::WAFv2", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-workspaces/.eslintrc.js b/packages/@aws-cdk/aws-workspaces/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-workspaces/.eslintrc.js +++ b/packages/@aws-cdk/aws-workspaces/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-workspaces/jest.config.js b/packages/@aws-cdk/aws-workspaces/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-workspaces/jest.config.js +++ b/packages/@aws-cdk/aws-workspaces/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-workspaces/package.json b/packages/@aws-cdk/aws-workspaces/package.json index 84f7406237f45..8a7f2477621a5 100644 --- a/packages/@aws-cdk/aws-workspaces/package.json +++ b/packages/@aws-cdk/aws-workspaces/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::WorkSpaces", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,11 +72,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-xray/.eslintrc.js b/packages/@aws-cdk/aws-xray/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-xray/.eslintrc.js +++ b/packages/@aws-cdk/aws-xray/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-xray/jest.config.js b/packages/@aws-cdk/aws-xray/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-xray/jest.config.js +++ b/packages/@aws-cdk/aws-xray/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-xray/package.json b/packages/@aws-cdk/aws-xray/package.json index e5ec9ff9da5fa..f1219a428f2fb 100644 --- a/packages/@aws-cdk/aws-xray/package.json +++ b/packages/@aws-cdk/aws-xray/package.json @@ -58,7 +58,6 @@ }, "cdk-build": { "cloudformation": "AWS::XRay", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -77,11 +76,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", "@aws-cdk/assertions": "0.0.0", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/cdk-assets-schema/.eslintrc.js b/packages/@aws-cdk/cdk-assets-schema/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/cdk-assets-schema/.eslintrc.js +++ b/packages/@aws-cdk/cdk-assets-schema/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/cdk-assets-schema/jest.config.js b/packages/@aws-cdk/cdk-assets-schema/jest.config.js index 5c1ef76634a9f..751c263a6e75c 100644 --- a/packages/@aws-cdk/cdk-assets-schema/jest.config.js +++ b/packages/@aws-cdk/cdk-assets-schema/jest.config.js @@ -1,4 +1,4 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = { ...baseConfig, coverageThreshold: { diff --git a/packages/@aws-cdk/cdk-assets-schema/package.json b/packages/@aws-cdk/cdk-assets-schema/package.json index f4e5ef6cb1b5f..a2a06573cbefc 100644 --- a/packages/@aws-cdk/cdk-assets-schema/package.json +++ b/packages/@aws-cdk/cdk-assets-schema/package.json @@ -52,10 +52,10 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0" + "jest": "^26.6.3" }, "repository": { "url": "https://github.com/aws/aws-cdk.git", @@ -76,9 +76,6 @@ }, "deprecated": "merged into @aws-cdk/cloud-assembly-schema", "maturity": "deprecated", - "cdk-build": { - "jest": true - }, "publishConfig": { "tag": "latest" } diff --git a/packages/@aws-cdk/cfnspec/.eslintrc.js b/packages/@aws-cdk/cfnspec/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/cfnspec/.eslintrc.js +++ b/packages/@aws-cdk/cfnspec/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/cfnspec/.gitignore b/packages/@aws-cdk/cfnspec/.gitignore index c7d816ca89794..01db1803f53af 100644 --- a/packages/@aws-cdk/cfnspec/.gitignore +++ b/packages/@aws-cdk/cfnspec/.gitignore @@ -12,3 +12,5 @@ dist .LAST_PACKAGE *.snk !.eslintrc.js + +!jest.config.js \ No newline at end of file diff --git a/packages/@aws-cdk/cfnspec/.npmignore b/packages/@aws-cdk/cfnspec/.npmignore index 3c75fd13efb4a..34100f8a5b6ee 100644 --- a/packages/@aws-cdk/cfnspec/.npmignore +++ b/packages/@aws-cdk/cfnspec/.npmignore @@ -7,3 +7,6 @@ dist .LAST_BUILD *.snk .eslintrc.js + +test/ +jest.config.js \ No newline at end of file diff --git a/packages/@aws-cdk/cfnspec/CHANGELOG.md b/packages/@aws-cdk/cfnspec/CHANGELOG.md index 36ec7ae147be5..19c814c818182 100644 --- a/packages/@aws-cdk/cfnspec/CHANGELOG.md +++ b/packages/@aws-cdk/cfnspec/CHANGELOG.md @@ -1,3 +1,325 @@ +# CloudFormation Resource Specification v43.0.0 + +## New Resource Types + + +## Attribute Changes + + +## Property Changes + +* AWS::EKS::Cluster Logging (__deleted__) +* AWS::EKS::Cluster Tags (__deleted__) +* AWS::EKS::Cluster ResourcesVpcConfig.UpdateType (__changed__) + * Old: Mutable + * New: Immutable + +## Property Type Changes + +* AWS::EKS::Cluster.ClusterLogging (__removed__) +* AWS::EKS::Cluster.Logging (__removed__) +* AWS::EKS::Cluster.LoggingTypeConfig (__removed__) +* AWS::EKS::Cluster.Provider (__added__) +* AWS::EKS::Cluster.EncryptionConfig Provider.PrimitiveType (__deleted__) +* AWS::EKS::Cluster.EncryptionConfig Provider.Type (__added__) +* AWS::EKS::Cluster.EncryptionConfig Provider.UpdateType (__changed__) + * Old: Immutable + * New: Mutable +* AWS::EKS::Cluster.EncryptionConfig Resources.UpdateType (__changed__) + * Old: Immutable + * New: Mutable +* AWS::EKS::Cluster.KubernetesNetworkConfig ServiceIpv4Cidr.UpdateType (__changed__) + * Old: Immutable + * New: Mutable +* AWS::EKS::Cluster.ResourcesVpcConfig EndpointPrivateAccess (__deleted__) +* AWS::EKS::Cluster.ResourcesVpcConfig EndpointPublicAccess (__deleted__) +* AWS::EKS::Cluster.ResourcesVpcConfig PublicAccessCidrs (__deleted__) +* AWS::EKS::Cluster.ResourcesVpcConfig SecurityGroupIds.UpdateType (__changed__) + * Old: Immutable + * New: Mutable +* AWS::EKS::Cluster.ResourcesVpcConfig SubnetIds.UpdateType (__changed__) + * Old: Immutable + * New: Mutable + + +# CloudFormation Resource Specification v43.0.0 + +## New Resource Types + +* AWS::Backup::Framework +* AWS::Backup::ReportPlan +* AWS::Lightsail::Disk +* AWS::Lightsail::Instance + +## Attribute Changes + + +## Property Changes + +* AWS::EKS::Cluster Logging (__deleted__) +* AWS::EKS::Cluster Tags (__deleted__) +* AWS::EKS::Cluster ResourcesVpcConfig.UpdateType (__changed__) + * Old: Mutable + * New: Immutable +* AWS::SSM::MaintenanceWindowTask CutoffBehavior (__added__) + +## Property Type Changes + +* AWS::EKS::Cluster.ClusterLogging (__removed__) +* AWS::EKS::Cluster.Logging (__removed__) +* AWS::EKS::Cluster.LoggingTypeConfig (__removed__) +* AWS::EKS::Cluster.Provider (__added__) +* AWS::Backup::BackupVault.LockConfigurationType changeableForDays (__deleted__) +* AWS::Backup::BackupVault.LockConfigurationType maxRetentionDays (__deleted__) +* AWS::Backup::BackupVault.LockConfigurationType minRetentionDays (__deleted__) +* AWS::Backup::BackupVault.LockConfigurationType ChangeableForDays (__added__) +* AWS::Backup::BackupVault.LockConfigurationType MaxRetentionDays (__added__) +* AWS::Backup::BackupVault.LockConfigurationType MinRetentionDays (__added__) +* AWS::EC2::LaunchTemplate.MetadataOptions HttpProtocolIpv6 (__added__) +* AWS::EKS::Cluster.EncryptionConfig Provider.PrimitiveType (__deleted__) +* AWS::EKS::Cluster.EncryptionConfig Provider.Type (__added__) +* AWS::EKS::Cluster.EncryptionConfig Provider.UpdateType (__changed__) + * Old: Immutable + * New: Mutable +* AWS::EKS::Cluster.EncryptionConfig Resources.UpdateType (__changed__) + * Old: Immutable + * New: Mutable +* AWS::EKS::Cluster.KubernetesNetworkConfig ServiceIpv4Cidr.UpdateType (__changed__) + * Old: Immutable + * New: Mutable +* AWS::EKS::Cluster.ResourcesVpcConfig EndpointPrivateAccess (__deleted__) +* AWS::EKS::Cluster.ResourcesVpcConfig EndpointPublicAccess (__deleted__) +* AWS::EKS::Cluster.ResourcesVpcConfig PublicAccessCidrs (__deleted__) +* AWS::EKS::Cluster.ResourcesVpcConfig SecurityGroupIds.UpdateType (__changed__) + * Old: Immutable + * New: Mutable +* AWS::EKS::Cluster.ResourcesVpcConfig SubnetIds.UpdateType (__changed__) + * Old: Immutable + * New: Mutable + +# Serverless Application Model (SAM) Resource Specification v2016-10-31 + +## New Resource Types + + +## Attribute Changes + + +## Property Changes + + +## Property Type Changes + +* AWS::Serverless::Function.EventInvokeDestinationConfig (__added__) +* AWS::Serverless::Function.DestinationConfig OnSuccess (__deleted__) +* AWS::Serverless::Function.EventInvokeConfig DestinationConfig.Type (__changed__) + * Old: DestinationConfig + * New: EventInvokeDestinationConfig + +# CloudFormation Resource Specification v43.0.0 + +## New Resource Types + +* AWS::APS::RuleGroupsNamespace + +## Attribute Changes + +* AWS::MediaConnect::Flow Source.SourceIngestPort (__added__) +* AWS::MediaConnect::FlowSource SourceIngestPort (__added__) +* AWS::OpenSearchService::Domain DomainArn (__added__) +* AWS::SQS::QueuePolicy Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sqs-policy.html + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sqs-queuepolicy.html +* AWS::SQS::QueuePolicy Id (__added__) + +## Property Changes + +* AWS::APS::Workspace AlertManagerDefinition (__added__) +* AWS::EKS::Cluster Logging (__added__) +* AWS::EKS::Cluster Tags (__added__) +* AWS::EKS::Cluster ResourcesVpcConfig.UpdateType (__changed__) + * Old: Immutable + * New: Mutable +* AWS::KinesisFirehose::DeliveryStream AmazonopensearchserviceDestinationConfiguration (__added__) +* AWS::Lambda::Function Architectures (__added__) +* AWS::Lambda::LayerVersion CompatibleArchitectures (__added__) +* AWS::MediaConnect::FlowOutput MinLatency (__added__) +* AWS::SQS::QueuePolicy PolicyDocument.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sqs-policy.html#cfn-sqs-queuepolicy-policydoc + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sqs-queuepolicy.html#cfn-sqs-queuepolicy-policydocument +* AWS::SQS::QueuePolicy Queues.Documentation (__changed__) + * Old: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sqs-policy.html#cfn-sqs-queuepolicy-queues + * New: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sqs-queuepolicy.html#cfn-sqs-queuepolicy-queues + +## Property Type Changes + +* AWS::EKS::Cluster.Provider (__removed__) +* AWS::EC2::LaunchTemplate.AcceleratorCount (__added__) +* AWS::EC2::LaunchTemplate.AcceleratorTotalMemoryMiB (__added__) +* AWS::EC2::LaunchTemplate.BaselineEbsBandwidthMbps (__added__) +* AWS::EC2::LaunchTemplate.MemoryGiBPerVCpu (__added__) +* AWS::EC2::LaunchTemplate.MemoryMiB (__added__) +* AWS::EC2::LaunchTemplate.NetworkInterfaceCount (__added__) +* AWS::EC2::LaunchTemplate.TotalLocalStorageGB (__added__) +* AWS::EC2::LaunchTemplate.VCpuCount (__added__) +* AWS::ECR::ReplicationConfiguration.RepositoryFilter (__added__) +* AWS::EKS::Cluster.ClusterLogging (__added__) +* AWS::EKS::Cluster.Logging (__added__) +* AWS::EKS::Cluster.LoggingTypeConfig (__added__) +* AWS::Kendra::DataSource.ProxyConfiguration (__added__) +* AWS::Kendra::DataSource.WebCrawlerAuthenticationConfiguration (__added__) +* AWS::Kendra::DataSource.WebCrawlerBasicAuthentication (__added__) +* AWS::Kendra::DataSource.WebCrawlerConfiguration (__added__) +* AWS::Kendra::DataSource.WebCrawlerSeedUrlConfiguration (__added__) +* AWS::Kendra::DataSource.WebCrawlerSiteMapsConfiguration (__added__) +* AWS::Kendra::DataSource.WebCrawlerUrls (__added__) +* AWS::Kendra::DataSource.WorkDocsConfiguration (__added__) +* AWS::KinesisFirehose::DeliveryStream.AmazonopensearchserviceBufferingHints (__added__) +* AWS::KinesisFirehose::DeliveryStream.AmazonopensearchserviceDestinationConfiguration (__added__) +* AWS::KinesisFirehose::DeliveryStream.AmazonopensearchserviceRetryOptions (__added__) +* AWS::ECR::ReplicationConfiguration.ReplicationRule RepositoryFilters (__added__) +* AWS::EKS::Cluster.EncryptionConfig Provider.Type (__deleted__) +* AWS::EKS::Cluster.EncryptionConfig Provider.PrimitiveType (__added__) +* AWS::EKS::Cluster.EncryptionConfig Provider.UpdateType (__changed__) + * Old: Mutable + * New: Immutable +* AWS::EKS::Cluster.EncryptionConfig Resources.UpdateType (__changed__) + * Old: Mutable + * New: Immutable +* AWS::EKS::Cluster.KubernetesNetworkConfig ServiceIpv4Cidr.UpdateType (__changed__) + * Old: Mutable + * New: Immutable +* AWS::EKS::Cluster.ResourcesVpcConfig EndpointPrivateAccess (__added__) +* AWS::EKS::Cluster.ResourcesVpcConfig EndpointPublicAccess (__added__) +* AWS::EKS::Cluster.ResourcesVpcConfig PublicAccessCidrs (__added__) +* AWS::EKS::Cluster.ResourcesVpcConfig SecurityGroupIds.UpdateType (__changed__) + * Old: Mutable + * New: Immutable +* AWS::EKS::Cluster.ResourcesVpcConfig SubnetIds.UpdateType (__changed__) + * Old: Mutable + * New: Immutable +* AWS::Kendra::DataSource.DataSourceConfiguration WebCrawlerConfiguration (__added__) +* AWS::Kendra::DataSource.DataSourceConfiguration WorkDocsConfiguration (__added__) +* AWS::Kendra::DataSource.ServiceNowConfiguration AuthenticationType (__added__) +* AWS::Kendra::DataSource.ServiceNowKnowledgeArticleConfiguration FilterQuery (__added__) +* AWS::Kendra::DataSource.SharePointConfiguration SslCertificateS3Path (__added__) +* AWS::MediaConnect::Flow.Encryption Algorithm.Required (__changed__) + * Old: true + * New: false +* AWS::MediaConnect::Flow.Source MinLatency (__added__) +* AWS::MediaConnect::Flow.Source SourceIngestPort (__added__) +* AWS::MediaConnect::FlowOutput.Encryption Algorithm.Required (__changed__) + * Old: true + * New: false + + +# CloudFormation Resource Specification v42.0.0 + +## New Resource Types + +* AWS::MemoryDB::ACL +* AWS::MemoryDB::Cluster +* AWS::MemoryDB::ParameterGroup +* AWS::MemoryDB::SubnetGroup +* AWS::MemoryDB::User + +## Attribute Changes + +* AWS::ApiGateway::GatewayResponse Id (__added__) +* AWS::Config::AggregationAuthorization AggregationAuthorizationArn (__added__) + +## Property Changes + +* AWS::ApiGateway::GatewayResponse ResponseParameters.DuplicatesAllowed (__deleted__) +* AWS::ApiGateway::GatewayResponse ResponseTemplates.DuplicatesAllowed (__deleted__) +* AWS::AppSync::DataSource OpenSearchServiceConfig (__added__) +* AWS::Backup::BackupVault LockConfiguration (__added__) +* AWS::Config::AggregationAuthorization Tags.DuplicatesAllowed (__added__) +* AWS::MSK::Cluster ClientAuthentication.UpdateType (__changed__) + * Old: Immutable + * New: Mutable +* AWS::MSK::Cluster EncryptionInfo.UpdateType (__changed__) + * Old: Immutable + * New: Mutable + +## Property Type Changes + +* AWS::AppSync::DataSource.OpenSearchServiceConfig (__added__) +* AWS::Backup::BackupVault.LockConfigurationType (__added__) +* AWS::IoT::TopicRule.OpenSearchAction (__added__) +* AWS::MSK::Cluster.Unauthenticated (__added__) +* AWS::ImageBuilder::ImageRecipe.AdditionalInstanceConfiguration UserDataOverride.Required (__changed__) + * Old: true + * New: false +* AWS::ImageBuilder::ImageRecipe.SystemsManagerAgent UninstallAfterBuild.Required (__changed__) + * Old: true + * New: false +* AWS::IoT::TopicRule.Action OpenSearch (__added__) +* AWS::MSK::Cluster.ClientAuthentication Unauthenticated (__added__) +* AWS::MSK::Cluster.ClientAuthentication Sasl.UpdateType (__changed__) + * Old: Immutable + * New: Mutable +* AWS::MSK::Cluster.ClientAuthentication Tls.UpdateType (__changed__) + * Old: Immutable + * New: Mutable +* AWS::MSK::Cluster.EncryptionInTransit ClientBroker.UpdateType (__changed__) + * Old: Immutable + * New: Mutable +* AWS::MSK::Cluster.EncryptionInfo EncryptionInTransit.UpdateType (__changed__) + * Old: Immutable + * New: Mutable +* AWS::MSK::Cluster.Iam Enabled.UpdateType (__changed__) + * Old: Immutable + * New: Mutable +* AWS::MSK::Cluster.Sasl Iam.UpdateType (__changed__) + * Old: Immutable + * New: Mutable +* AWS::MSK::Cluster.Sasl Scram.UpdateType (__changed__) + * Old: Immutable + * New: Mutable +* AWS::MSK::Cluster.Scram Enabled.UpdateType (__changed__) + * Old: Immutable + * New: Mutable +* AWS::MSK::Cluster.Tls Enabled (__added__) +* AWS::MSK::Cluster.Tls CertificateAuthorityArnList.UpdateType (__changed__) + * Old: Immutable + * New: Mutable + + +# CloudFormation Resource Specification v41.2.0 + +## New Resource Types + +* AWS::ACMPCA::Permission +* AWS::APS::Workspace +* AWS::HealthLake::FHIRDatastore +* AWS::OpenSearchService::Domain + +## Attribute Changes + +* AWS::EFS::MountTarget Id (__added__) + +## Property Changes + +* AWS::EMR::Studio IdpAuthUrl (__added__) +* AWS::EMR::Studio IdpRelayStateParameterName (__added__) +* AWS::EMR::Studio UserRole.Required (__changed__) + * Old: true + * New: false +* AWS::RoboMaker::SimulationApplication Environment (__added__) +* AWS::RoboMaker::SimulationApplication RenderingEngine.Required (__changed__) + * Old: true + * New: false +* AWS::RoboMaker::SimulationApplication Sources.Required (__changed__) + * Old: true + * New: false +* AWS::SQS::Queue RedriveAllowPolicy (__added__) + +## Property Type Changes + +* AWS::S3::Bucket.MetricsConfiguration AccessPointArn (__added__) + + # CloudFormation Resource Specification v41.1.0 ## New Resource Types diff --git a/packages/@aws-cdk/cfnspec/build-tools/create-missing-libraries.ts b/packages/@aws-cdk/cfnspec/build-tools/create-missing-libraries.ts index db1edab50e8a4..0f28a38a86f87 100644 --- a/packages/@aws-cdk/cfnspec/build-tools/create-missing-libraries.ts +++ b/packages/@aws-cdk/cfnspec/build-tools/create-missing-libraries.ts @@ -24,13 +24,9 @@ async function main() { // iterate over all cloudformation namespaces for (const namespace of cfnspec.namespaces()) { - const [moduleFamily, moduleBaseName] = (namespace === 'AWS::Serverless' ? 'AWS::SAM' : namespace).split('::'); - - const moduleName = `${moduleFamily}-${moduleBaseName.replace(/V\d+$/, '')}`.toLocaleLowerCase(); - const packagePath = path.join(root, moduleName); - - const lowcaseModuleName = moduleBaseName.toLocaleLowerCase(); - const packageName = `@aws-cdk/${moduleName}`; + const module = cfnspec.createModuleDefinitionFromCfnNamespace(namespace); + const lowcaseModuleName = module.moduleName.toLocaleLowerCase(); + const packagePath = path.join(root, module.moduleName); // we already have a module for this namesapce, move on. if (await fs.pathExists(packagePath)) { @@ -42,12 +38,12 @@ async function main() { if (scopes.indexOf(namespace) !== -1) { // V2-style module is already modeled in the root package, nothing to be done! continue; - } else if (await fs.pathExists(path.join(root, `${moduleFamily}-${moduleBaseName}`.toLocaleLowerCase()))) { + } else if (await fs.pathExists(path.join(root, `${module.moduleFamily}-${module.moduleBaseName}`.toLocaleLowerCase()))) { // V2-style package already has it's own package (legacy behavior), nothing to be done! continue; } else { // V2-style package needs to be added to it's "V1" package... Get down to business! - console.error(`Adding ${namespace} to ${packageName}`); + console.error(`Adding ${namespace} to ${module.packageName}`); scopes.push(namespace); packageJson['cdk-build'].cloudformation = scopes; await fs.writeJson(packageJsonPath, packageJson, { encoding: 'utf-8', spaces: 2 }); @@ -62,22 +58,6 @@ async function main() { } } - // dotnet names - const dotnetPackage = `Amazon.CDK.${moduleFamily}.${moduleBaseName}`; - - // java names - const javaGroupId = 'software.amazon.awscdk'; - const javaPackage = moduleFamily === 'AWS' - ? `services.${lowcaseModuleName}` - : `${moduleFamily.toLocaleLowerCase()}.${lowcaseModuleName}`; - const javaArtifactId = moduleFamily === 'AWS' - ? lowcaseModuleName - : `${moduleFamily.toLocaleLowerCase()}-${lowcaseModuleName}`; - - // python names - const pythonDistName = `aws-cdk.${moduleName}`; - const pythonModuleName = pythonDistName.replace(/-/g, '_'); - async function write(relativePath: string, contents: string[] | string | object) { const fullPath = path.join(packagePath, relativePath); const dir = path.dirname(fullPath); @@ -97,10 +77,10 @@ async function main() { await fs.writeFile(fullPath, data + '\n'); } - console.log(`generating module for ${packageName}...`); + console.log(`generating module for ${module.packageName}...`); await write('package.json', { - name: packageName, + name: module.packageName, version, description: `The CDK Construct Library for ${namespace}`, main: 'lib/index.js', @@ -110,17 +90,17 @@ async function main() { projectReferences: true, targets: { dotnet: { - namespace: dotnetPackage, - packageId: dotnetPackage, + namespace: module.dotnetPackage, + packageId: module.dotnetPackage, signAssembly: true, assemblyOriginatorKeyFile: '../../key.snk', iconUrl: 'https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png', }, java: { - package: `${javaGroupId}.${javaPackage}`, + package: `${module.javaGroupId}.${module.javaPackage}`, maven: { - groupId: javaGroupId, - artifactId: javaArtifactId, + groupId: module.javaGroupId, + artifactId: module.javaArtifactId, }, }, python: { @@ -128,15 +108,15 @@ async function main() { 'Framework :: AWS CDK', 'Framework :: AWS CDK :: 1', ], - distName: pythonDistName, - module: pythonModuleName, + distName: module.pythonDistName, + module: module.pythonModuleName, }, }, }, repository: { type: 'git', url: 'https://github.com/aws/aws-cdk.git', - directory: `packages/${packageName}`, + directory: `packages/${module.packageName}`, }, homepage: 'https://github.com/aws/aws-cdk', scripts: { @@ -169,7 +149,7 @@ async function main() { 'cdk', 'constructs', namespace, - moduleName, + module.moduleName, ], author: { name: 'Amazon Web Services', @@ -178,11 +158,11 @@ async function main() { }, license: 'Apache-2.0', devDependencies: { - '@types/jest': '^26.0.22', '@aws-cdk/assertions': version, - 'cdk-build-tools': version, - 'cfn2ts': version, - 'pkglint': version, + '@aws-cdk/cdk-build-tools': version, + '@aws-cdk/cfn2ts': version, + '@aws-cdk/pkglint': version, + '@types/jest': '^26.0.22', }, dependencies: { '@aws-cdk/core': version, @@ -271,37 +251,16 @@ async function main() { '});', ]); - await write('README.md', [ - `# ${namespace} Construct Library`, - '', - '', - '---', - '', - '![cfn-resources: Stable](https://img.shields.io/badge/cfn--resources-stable-success.svg?style=for-the-badge)', - '', - '> All classes with the `Cfn` prefix in this module ([CFN Resources]) are always stable and safe to use.', - '>', - '> [CFN Resources]: https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib', - '', - '---', - '', - '', - '', - 'This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project.', - '', - '```ts', - `import ${lowcaseModuleName} = require('${packageName}');`, - '```', - ]); + await cfnspec.createLibraryReadme(namespace, path.join(packagePath, 'README.md')); await write('.eslintrc.js', [ - "const baseConfig = require('cdk-build-tools/config/eslintrc');", + "const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc');", "baseConfig.parserOptions.project = __dirname + '/tsconfig.json';", 'module.exports = baseConfig;', ]); await write('jest.config.js', [ - "const baseConfig = require('cdk-build-tools/config/jest.config');", + "const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config');", 'module.exports = baseConfig;', ]); @@ -310,10 +269,10 @@ async function main() { await fs.copy(path.join(templateDir, file), path.join(packagePath, file)); } - await addDependencyToMegaPackage(path.join('@aws-cdk', 'cloudformation-include'), packageName, version, ['dependencies', 'peerDependencies']); - await addDependencyToMegaPackage('aws-cdk-lib', packageName, version, ['devDependencies']); - await addDependencyToMegaPackage('monocdk', packageName, version, ['devDependencies']); - await addDependencyToMegaPackage('decdk', packageName, version, ['dependencies']); + await addDependencyToMegaPackage(path.join('@aws-cdk', 'cloudformation-include'), module.packageName, version, ['dependencies', 'peerDependencies']); + await addDependencyToMegaPackage('aws-cdk-lib', module.packageName, version, ['devDependencies']); + await addDependencyToMegaPackage('monocdk', module.packageName, version, ['devDependencies']); + await addDependencyToMegaPackage('decdk', module.packageName, version, ['dependencies']); } } diff --git a/packages/@aws-cdk/cfnspec/cfn.version b/packages/@aws-cdk/cfnspec/cfn.version index 9472133111e1b..f3986a67888db 100644 --- a/packages/@aws-cdk/cfnspec/cfn.version +++ b/packages/@aws-cdk/cfnspec/cfn.version @@ -1 +1 @@ -41.1.0 +43.0.0 diff --git a/packages/@aws-cdk/cfnspec/jest.config.js b/packages/@aws-cdk/cfnspec/jest.config.js new file mode 100644 index 0000000000000..35bb1719cf56f --- /dev/null +++ b/packages/@aws-cdk/cfnspec/jest.config.js @@ -0,0 +1,10 @@ +const baseConfig = require('../../../tools/@aws-cdk/cdk-build-tools/config/jest.config'); +module.exports = { + ...baseConfig, + coverageThreshold: { + global: { + statements: 70, + branches: 50, + } + } +}; diff --git a/packages/@aws-cdk/cfnspec/lib/index.ts b/packages/@aws-cdk/cfnspec/lib/index.ts index 6ab020d9580cc..17ef1bde49c36 100644 --- a/packages/@aws-cdk/cfnspec/lib/index.ts +++ b/packages/@aws-cdk/cfnspec/lib/index.ts @@ -3,6 +3,7 @@ import { CfnLintFileSchema } from './_private_schema/cfn-lint'; import * as schema from './schema'; export { schema }; export * from './canned-metrics'; +export * from './library-creation'; /** * The complete AWS CloudFormation Resource specification, having any CDK patches and enhancements included in it. diff --git a/packages/@aws-cdk/cfnspec/lib/library-creation.ts b/packages/@aws-cdk/cfnspec/lib/library-creation.ts new file mode 100644 index 0000000000000..85292a89d2749 --- /dev/null +++ b/packages/@aws-cdk/cfnspec/lib/library-creation.ts @@ -0,0 +1,83 @@ +import * as fs from 'fs-extra'; + +export interface ModuleDefinition { + readonly namespace: string; + readonly moduleName: string; + readonly moduleFamily: string; + readonly moduleBaseName: string; + readonly packageName: string; + + readonly dotnetPackage: string; + readonly javaGroupId: string; + readonly javaPackage: string; + readonly javaArtifactId: string; + + readonly pythonDistName: string; + readonly pythonModuleName: string; +} + +export function createModuleDefinitionFromCfnNamespace(namespace: string): ModuleDefinition { + const [moduleFamily, moduleBaseName] = (namespace === 'AWS::Serverless' ? 'AWS::SAM' : namespace).split('::'); + const moduleName = `${moduleFamily}-${moduleBaseName.replace(/V\d+$/, '')}`.toLocaleLowerCase(); + + const lowcaseModuleName = moduleBaseName.toLocaleLowerCase(); + const packageName = `@aws-cdk/${moduleName}`; + + // dotnet names + const dotnetPackage = `Amazon.CDK.${moduleFamily}.${moduleBaseName}`; + + // java names + const javaGroupId = 'software.amazon.awscdk'; + const javaPackage = moduleFamily === 'AWS' + ? `services.${lowcaseModuleName}` + : `${moduleFamily.toLocaleLowerCase()}.${lowcaseModuleName}`; + const javaArtifactId = moduleFamily === 'AWS' + ? lowcaseModuleName + : `${moduleFamily.toLocaleLowerCase()}-${lowcaseModuleName}`; + + // python names + const pythonDistName = `aws-cdk.${moduleName}`; + const pythonModuleName = pythonDistName.replace(/-/g, '_'); + + return { + namespace, + moduleName, + moduleFamily, + moduleBaseName, + packageName, + dotnetPackage, + javaGroupId, + javaPackage, + javaArtifactId, + pythonDistName, + pythonModuleName, + }; +} + +export async function createLibraryReadme(namespace: string, readmePath: string) { + const module = createModuleDefinitionFromCfnNamespace(namespace); + + await fs.writeFile(readmePath, [ + `# ${namespace} Construct Library`, + '', + '', + '---', + '', + '![cfn-resources: Stable](https://img.shields.io/badge/cfn--resources-stable-success.svg?style=for-the-badge)', + '', + '> All classes with the `Cfn` prefix in this module ([CFN Resources]) are always stable and safe to use.', + '>', + '> [CFN Resources]: https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib', + '', + '---', + '', + '', + '', + 'This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project.', + '', + '```ts', + `import ${module.moduleName.toLocaleLowerCase()} = require('${module.packageName}');`, + '```', + '', + ].join('\n'), 'utf8'); +} diff --git a/packages/@aws-cdk/cfnspec/package.json b/packages/@aws-cdk/cfnspec/package.json index f9c34feb21e7a..28df618bf6231 100644 --- a/packages/@aws-cdk/cfnspec/package.json +++ b/packages/@aws-cdk/cfnspec/package.json @@ -20,24 +20,27 @@ "statements": 50, "lines": 50 }, + "cdk-build": { + "jest": true + }, "pkglint": { "ignore": true }, "main": "lib/index.js", "types": "lib/index.d.ts", "devDependencies": { + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/fs-extra": "^8.1.2", + "@types/jest": "^26.0.24", "@types/md5": "^2.3.1", - "@types/nodeunit": "^0.0.32", - "cdk-build-tools": "0.0.0", "fast-json-patch": "^2.2.1", - "fs-extra": "^9.1.0", + "jest": "^26.6.3", "json-diff": "^0.5.4", - "nodeunit": "^0.11.3", - "pkglint": "0.0.0", "sort-json": "^2.0.0" }, "dependencies": { + "fs-extra": "^9.1.0", "md5": "^2.3.0" }, "repository": { diff --git a/packages/@aws-cdk/cfnspec/spec-source/000_CloudFormationResourceSpecification.json b/packages/@aws-cdk/cfnspec/spec-source/000_CloudFormationResourceSpecification.json index 489c73cf6aaea..b5b29349fe4e4 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/000_CloudFormationResourceSpecification.json +++ b/packages/@aws-cdk/cfnspec/spec-source/000_CloudFormationResourceSpecification.json @@ -7077,6 +7077,23 @@ } } }, + "AWS::AppSync::DataSource.OpenSearchServiceConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appsync-datasource-opensearchserviceconfig.html", + "Properties": { + "AwsRegion": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appsync-datasource-opensearchserviceconfig.html#cfn-appsync-datasource-opensearchserviceconfig-awsregion", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Endpoint": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appsync-datasource-opensearchserviceconfig.html#cfn-appsync-datasource-opensearchserviceconfig-endpoint", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, "AWS::AppSync::DataSource.RdsHttpEndpointConfig": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appsync-datasource-rdshttpendpointconfig.html", "Properties": { @@ -9354,6 +9371,29 @@ } } }, + "AWS::Backup::BackupVault.LockConfigurationType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-backup-backupvault-lockconfigurationtype.html", + "Properties": { + "ChangeableForDays": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-backup-backupvault-lockconfigurationtype.html#cfn-backup-backupvault-lockconfigurationtype-changeablefordays", + "PrimitiveType": "Double", + "Required": false, + "UpdateType": "Mutable" + }, + "MaxRetentionDays": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-backup-backupvault-lockconfigurationtype.html#cfn-backup-backupvault-lockconfigurationtype-maxretentiondays", + "PrimitiveType": "Double", + "Required": false, + "UpdateType": "Mutable" + }, + "MinRetentionDays": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-backup-backupvault-lockconfigurationtype.html#cfn-backup-backupvault-lockconfigurationtype-minretentiondays", + "PrimitiveType": "Double", + "Required": true, + "UpdateType": "Mutable" + } + } + }, "AWS::Backup::BackupVault.NotificationObjectType": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-backup-backupvault-notificationobjecttype.html", "Properties": { @@ -9373,6 +9413,48 @@ } } }, + "AWS::Backup::Framework.ControlInputParameter": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-backup-framework-controlinputparameter.html", + "Properties": { + "ParameterName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-backup-framework-controlinputparameter.html#cfn-backup-framework-controlinputparameter-parametername", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "ParameterValue": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-backup-framework-controlinputparameter.html#cfn-backup-framework-controlinputparameter-parametervalue", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::Backup::Framework.FrameworkControl": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-backup-framework-frameworkcontrol.html", + "Properties": { + "ControlInputParameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-backup-framework-frameworkcontrol.html#cfn-backup-framework-frameworkcontrol-controlinputparameters", + "DuplicatesAllowed": false, + "ItemType": "ControlInputParameter", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "ControlName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-backup-framework-frameworkcontrol.html#cfn-backup-framework-frameworkcontrol-controlname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "ControlScope": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-backup-framework-frameworkcontrol.html#cfn-backup-framework-frameworkcontrol-controlscope", + "PrimitiveType": "Json", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::Batch::ComputeEnvironment.ComputeResources": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-batch-computeenvironment-computeresources.html", "Properties": { @@ -19723,6 +19805,57 @@ } } }, + "AWS::EC2::LaunchTemplate.AcceleratorCount": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-launchtemplate-acceleratorcount.html", + "Properties": { + "Max": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-launchtemplate-acceleratorcount.html#cfn-ec2-launchtemplate-acceleratorcount-max", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "Min": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-launchtemplate-acceleratorcount.html#cfn-ec2-launchtemplate-acceleratorcount-min", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::EC2::LaunchTemplate.AcceleratorTotalMemoryMiB": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-launchtemplate-acceleratortotalmemorymib.html", + "Properties": { + "Max": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-launchtemplate-acceleratortotalmemorymib.html#cfn-ec2-launchtemplate-acceleratortotalmemorymib-max", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "Min": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-launchtemplate-acceleratortotalmemorymib.html#cfn-ec2-launchtemplate-acceleratortotalmemorymib-min", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::EC2::LaunchTemplate.BaselineEbsBandwidthMbps": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-launchtemplate-baselineebsbandwidthmbps.html", + "Properties": { + "Max": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-launchtemplate-baselineebsbandwidthmbps.html#cfn-ec2-launchtemplate-baselineebsbandwidthmbps-max", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "Min": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-launchtemplate-baselineebsbandwidthmbps.html#cfn-ec2-launchtemplate-baselineebsbandwidthmbps-min", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::EC2::LaunchTemplate.BlockDeviceMapping": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-launchtemplate-blockdevicemapping.html", "Properties": { @@ -20166,6 +20299,40 @@ } } }, + "AWS::EC2::LaunchTemplate.MemoryGiBPerVCpu": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-launchtemplate-memorygibpervcpu.html", + "Properties": { + "Max": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-launchtemplate-memorygibpervcpu.html#cfn-ec2-launchtemplate-memorygibpervcpu-max", + "PrimitiveType": "Double", + "Required": false, + "UpdateType": "Mutable" + }, + "Min": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-launchtemplate-memorygibpervcpu.html#cfn-ec2-launchtemplate-memorygibpervcpu-min", + "PrimitiveType": "Double", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::EC2::LaunchTemplate.MemoryMiB": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-launchtemplate-memorymib.html", + "Properties": { + "Max": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-launchtemplate-memorymib.html#cfn-ec2-launchtemplate-memorymib-max", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "Min": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-launchtemplate-memorymib.html#cfn-ec2-launchtemplate-memorymib-min", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::EC2::LaunchTemplate.MetadataOptions": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-launchtemplate-launchtemplatedata-metadataoptions.html", "Properties": { @@ -20175,6 +20342,12 @@ "Required": false, "UpdateType": "Mutable" }, + "HttpProtocolIpv6": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-launchtemplate-launchtemplatedata-metadataoptions.html#cfn-ec2-launchtemplate-launchtemplatedata-metadataoptions-httpprotocolipv6", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, "HttpPutResponseHopLimit": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-launchtemplate-launchtemplatedata-metadataoptions.html#cfn-ec2-launchtemplate-launchtemplatedata-metadataoptions-httpputresponsehoplimit", "PrimitiveType": "Integer", @@ -20298,6 +20471,23 @@ } } }, + "AWS::EC2::LaunchTemplate.NetworkInterfaceCount": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-launchtemplate-networkinterfacecount.html", + "Properties": { + "Max": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-launchtemplate-networkinterfacecount.html#cfn-ec2-launchtemplate-networkinterfacecount-max", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "Min": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-launchtemplate-networkinterfacecount.html#cfn-ec2-launchtemplate-networkinterfacecount-min", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::EC2::LaunchTemplate.Placement": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-launchtemplate-launchtemplatedata-placement.html", "Properties": { @@ -20421,6 +20611,40 @@ } } }, + "AWS::EC2::LaunchTemplate.TotalLocalStorageGB": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-launchtemplate-totallocalstoragegb.html", + "Properties": { + "Max": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-launchtemplate-totallocalstoragegb.html#cfn-ec2-launchtemplate-totallocalstoragegb-max", + "PrimitiveType": "Double", + "Required": false, + "UpdateType": "Mutable" + }, + "Min": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-launchtemplate-totallocalstoragegb.html#cfn-ec2-launchtemplate-totallocalstoragegb-min", + "PrimitiveType": "Double", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::EC2::LaunchTemplate.VCpuCount": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-launchtemplate-vcpucount.html", + "Properties": { + "Max": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-launchtemplate-vcpucount.html#cfn-ec2-launchtemplate-vcpucount-max", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "Min": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-launchtemplate-vcpucount.html#cfn-ec2-launchtemplate-vcpucount-min", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::EC2::NetworkAclEntry.Icmp": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-networkaclentry-icmp.html", "Properties": { @@ -22001,6 +22225,30 @@ "Required": true, "Type": "List", "UpdateType": "Mutable" + }, + "RepositoryFilters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecr-replicationconfiguration-replicationrule.html#cfn-ecr-replicationconfiguration-replicationrule-repositoryfilters", + "ItemType": "RepositoryFilter", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::ECR::ReplicationConfiguration.RepositoryFilter": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecr-replicationconfiguration-repositoryfilter.html", + "Properties": { + "Filter": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecr-replicationconfiguration-repositoryfilter.html#cfn-ecr-replicationconfiguration-repositoryfilter-filter", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "FilterType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecr-replicationconfiguration-repositoryfilter.html#cfn-ecr-replicationconfiguration-repositoryfilter-filtertype", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" } } }, @@ -32275,6 +32523,45 @@ } } }, + "AWS::HealthLake::FHIRDatastore.KmsEncryptionConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-healthlake-fhirdatastore-kmsencryptionconfig.html", + "Properties": { + "CmkType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-healthlake-fhirdatastore-kmsencryptionconfig.html#cfn-healthlake-fhirdatastore-kmsencryptionconfig-cmktype", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "KmsKeyId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-healthlake-fhirdatastore-kmsencryptionconfig.html#cfn-healthlake-fhirdatastore-kmsencryptionconfig-kmskeyid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + } + } + }, + "AWS::HealthLake::FHIRDatastore.PreloadDataConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-healthlake-fhirdatastore-preloaddataconfig.html", + "Properties": { + "PreloadDataType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-healthlake-fhirdatastore-preloaddataconfig.html#cfn-healthlake-fhirdatastore-preloaddataconfig-preloaddatatype", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + } + } + }, + "AWS::HealthLake::FHIRDatastore.SseConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-healthlake-fhirdatastore-sseconfiguration.html", + "Properties": { + "KmsEncryptionConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-healthlake-fhirdatastore-sseconfiguration.html#cfn-healthlake-fhirdatastore-sseconfiguration-kmsencryptionconfig", + "Required": true, + "Type": "KmsEncryptionConfig", + "UpdateType": "Immutable" + } + } + }, "AWS::IAM::Group.Policy": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iam-policy.html", "Properties": { @@ -32610,7 +32897,7 @@ "UserDataOverride": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-imagebuilder-imagerecipe-additionalinstanceconfiguration.html#cfn-imagebuilder-imagerecipe-additionalinstanceconfiguration-userdataoverride", "PrimitiveType": "String", - "Required": true, + "Required": false, "UpdateType": "Mutable" } } @@ -32733,7 +33020,7 @@ "UninstallAfterBuild": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-imagebuilder-imagerecipe-systemsmanageragent.html#cfn-imagebuilder-imagerecipe-systemsmanageragent-uninstallafterbuild", "PrimitiveType": "Boolean", - "Required": true, + "Required": false, "UpdateType": "Mutable" } } @@ -33434,6 +33721,12 @@ "Type": "LambdaAction", "UpdateType": "Mutable" }, + "OpenSearch": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-action.html#cfn-iot-topicrule-action-opensearch", + "Required": false, + "Type": "OpenSearchAction", + "UpdateType": "Mutable" + }, "Republish": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-action.html#cfn-iot-topicrule-action-republish", "Required": false, @@ -33968,6 +34261,41 @@ } } }, + "AWS::IoT::TopicRule.OpenSearchAction": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-opensearchaction.html", + "Properties": { + "Endpoint": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-opensearchaction.html#cfn-iot-topicrule-opensearchaction-endpoint", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Id": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-opensearchaction.html#cfn-iot-topicrule-opensearchaction-id", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Index": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-opensearchaction.html#cfn-iot-topicrule-opensearchaction-index", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "RoleArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-opensearchaction.html#cfn-iot-topicrule-opensearchaction-rolearn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Type": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-opensearchaction.html#cfn-iot-topicrule-opensearchaction-type", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, "AWS::IoT::TopicRule.PutAssetPropertyValueEntry": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-putassetpropertyvalueentry.html", "Properties": { @@ -37260,6 +37588,18 @@ "Required": false, "Type": "SharePointConfiguration", "UpdateType": "Mutable" + }, + "WebCrawlerConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-datasourceconfiguration.html#cfn-kendra-datasource-datasourceconfiguration-webcrawlerconfiguration", + "Required": false, + "Type": "WebCrawlerConfiguration", + "UpdateType": "Mutable" + }, + "WorkDocsConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-datasourceconfiguration.html#cfn-kendra-datasource-datasourceconfiguration-workdocsconfiguration", + "Required": false, + "Type": "WorkDocsConfiguration", + "UpdateType": "Mutable" } } }, @@ -37478,6 +37818,29 @@ } } }, + "AWS::Kendra::DataSource.ProxyConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-proxyconfiguration.html", + "Properties": { + "Credentials": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-proxyconfiguration.html#cfn-kendra-datasource-proxyconfiguration-credentials", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Host": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-proxyconfiguration.html#cfn-kendra-datasource-proxyconfiguration-host", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Port": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-proxyconfiguration.html#cfn-kendra-datasource-proxyconfiguration-port", + "PrimitiveType": "Integer", + "Required": true, + "UpdateType": "Mutable" + } + } + }, "AWS::Kendra::DataSource.S3DataSourceConfiguration": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-s3datasourceconfiguration.html", "Properties": { @@ -37762,6 +38125,12 @@ "AWS::Kendra::DataSource.ServiceNowConfiguration": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-servicenowconfiguration.html", "Properties": { + "AuthenticationType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-servicenowconfiguration.html#cfn-kendra-datasource-servicenowconfiguration-authenticationtype", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, "HostUrl": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-servicenowconfiguration.html#cfn-kendra-datasource-servicenowconfiguration-hosturl", "PrimitiveType": "String", @@ -37829,6 +38198,12 @@ "Type": "List", "UpdateType": "Mutable" }, + "FilterQuery": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-servicenowknowledgearticleconfiguration.html#cfn-kendra-datasource-servicenowknowledgearticleconfiguration-filterquery", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, "IncludeAttachmentFilePatterns": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-servicenowknowledgearticleconfiguration.html#cfn-kendra-datasource-servicenowknowledgearticleconfiguration-includeattachmentfilepatterns", "PrimitiveItemType": "String", @@ -37936,6 +38311,12 @@ "Required": true, "UpdateType": "Mutable" }, + "SslCertificateS3Path": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-sharepointconfiguration.html#cfn-kendra-datasource-sharepointconfiguration-sslcertificates3path", + "Required": false, + "Type": "S3Path", + "UpdateType": "Mutable" + }, "Urls": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-sharepointconfiguration.html#cfn-kendra-datasource-sharepointconfiguration-urls", "PrimitiveItemType": "String", @@ -37968,6 +38349,193 @@ } } }, + "AWS::Kendra::DataSource.WebCrawlerAuthenticationConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-webcrawlerauthenticationconfiguration.html", + "Properties": { + "BasicAuthentication": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-webcrawlerauthenticationconfiguration.html#cfn-kendra-datasource-webcrawlerauthenticationconfiguration-basicauthentication", + "ItemType": "WebCrawlerBasicAuthentication", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::Kendra::DataSource.WebCrawlerBasicAuthentication": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-webcrawlerbasicauthentication.html", + "Properties": { + "Credentials": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-webcrawlerbasicauthentication.html#cfn-kendra-datasource-webcrawlerbasicauthentication-credentials", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Host": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-webcrawlerbasicauthentication.html#cfn-kendra-datasource-webcrawlerbasicauthentication-host", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Port": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-webcrawlerbasicauthentication.html#cfn-kendra-datasource-webcrawlerbasicauthentication-port", + "PrimitiveType": "Integer", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::Kendra::DataSource.WebCrawlerConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-webcrawlerconfiguration.html", + "Properties": { + "AuthenticationConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-webcrawlerconfiguration.html#cfn-kendra-datasource-webcrawlerconfiguration-authenticationconfiguration", + "Required": false, + "Type": "WebCrawlerAuthenticationConfiguration", + "UpdateType": "Mutable" + }, + "CrawlDepth": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-webcrawlerconfiguration.html#cfn-kendra-datasource-webcrawlerconfiguration-crawldepth", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "MaxContentSizePerPageInMegaBytes": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-webcrawlerconfiguration.html#cfn-kendra-datasource-webcrawlerconfiguration-maxcontentsizeperpageinmegabytes", + "PrimitiveType": "Double", + "Required": false, + "UpdateType": "Mutable" + }, + "MaxLinksPerPage": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-webcrawlerconfiguration.html#cfn-kendra-datasource-webcrawlerconfiguration-maxlinksperpage", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "MaxUrlsPerMinuteCrawlRate": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-webcrawlerconfiguration.html#cfn-kendra-datasource-webcrawlerconfiguration-maxurlsperminutecrawlrate", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "ProxyConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-webcrawlerconfiguration.html#cfn-kendra-datasource-webcrawlerconfiguration-proxyconfiguration", + "Required": false, + "Type": "ProxyConfiguration", + "UpdateType": "Mutable" + }, + "UrlExclusionPatterns": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-webcrawlerconfiguration.html#cfn-kendra-datasource-webcrawlerconfiguration-urlexclusionpatterns", + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "UrlInclusionPatterns": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-webcrawlerconfiguration.html#cfn-kendra-datasource-webcrawlerconfiguration-urlinclusionpatterns", + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "Urls": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-webcrawlerconfiguration.html#cfn-kendra-datasource-webcrawlerconfiguration-urls", + "Required": true, + "Type": "WebCrawlerUrls", + "UpdateType": "Mutable" + } + } + }, + "AWS::Kendra::DataSource.WebCrawlerSeedUrlConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-webcrawlerseedurlconfiguration.html", + "Properties": { + "SeedUrls": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-webcrawlerseedurlconfiguration.html#cfn-kendra-datasource-webcrawlerseedurlconfiguration-seedurls", + "PrimitiveItemType": "String", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + }, + "WebCrawlerMode": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-webcrawlerseedurlconfiguration.html#cfn-kendra-datasource-webcrawlerseedurlconfiguration-webcrawlermode", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::Kendra::DataSource.WebCrawlerSiteMapsConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-webcrawlersitemapsconfiguration.html", + "Properties": { + "SiteMaps": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-webcrawlersitemapsconfiguration.html#cfn-kendra-datasource-webcrawlersitemapsconfiguration-sitemaps", + "PrimitiveItemType": "String", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::Kendra::DataSource.WebCrawlerUrls": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-webcrawlerurls.html", + "Properties": { + "SeedUrlConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-webcrawlerurls.html#cfn-kendra-datasource-webcrawlerurls-seedurlconfiguration", + "Required": false, + "Type": "WebCrawlerSeedUrlConfiguration", + "UpdateType": "Mutable" + }, + "SiteMapsConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-webcrawlerurls.html#cfn-kendra-datasource-webcrawlerurls-sitemapsconfiguration", + "Required": false, + "Type": "WebCrawlerSiteMapsConfiguration", + "UpdateType": "Mutable" + } + } + }, + "AWS::Kendra::DataSource.WorkDocsConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-workdocsconfiguration.html", + "Properties": { + "CrawlComments": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-workdocsconfiguration.html#cfn-kendra-datasource-workdocsconfiguration-crawlcomments", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "ExclusionPatterns": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-workdocsconfiguration.html#cfn-kendra-datasource-workdocsconfiguration-exclusionpatterns", + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "FieldMappings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-workdocsconfiguration.html#cfn-kendra-datasource-workdocsconfiguration-fieldmappings", + "ItemType": "DataSourceToIndexFieldMapping", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "InclusionPatterns": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-workdocsconfiguration.html#cfn-kendra-datasource-workdocsconfiguration-inclusionpatterns", + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "OrganizationId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-workdocsconfiguration.html#cfn-kendra-datasource-workdocsconfiguration-organizationid", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "UseChangeLog": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-datasource-workdocsconfiguration.html#cfn-kendra-datasource-workdocsconfiguration-usechangelog", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::Kendra::Faq.S3Path": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kendra-faq-s3path.html", "Properties": { @@ -39544,6 +40112,117 @@ } } }, + "AWS::KinesisFirehose::DeliveryStream.AmazonopensearchserviceBufferingHints": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kinesisfirehose-deliverystream-amazonopensearchservicebufferinghints.html", + "Properties": { + "IntervalInSeconds": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kinesisfirehose-deliverystream-amazonopensearchservicebufferinghints.html#cfn-kinesisfirehose-deliverystream-amazonopensearchservicebufferinghints-intervalinseconds", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "SizeInMBs": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kinesisfirehose-deliverystream-amazonopensearchservicebufferinghints.html#cfn-kinesisfirehose-deliverystream-amazonopensearchservicebufferinghints-sizeinmbs", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::KinesisFirehose::DeliveryStream.AmazonopensearchserviceDestinationConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kinesisfirehose-deliverystream-amazonopensearchservicedestinationconfiguration.html", + "Properties": { + "BufferingHints": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kinesisfirehose-deliverystream-amazonopensearchservicedestinationconfiguration.html#cfn-kinesisfirehose-deliverystream-amazonopensearchservicedestinationconfiguration-bufferinghints", + "Required": false, + "Type": "AmazonopensearchserviceBufferingHints", + "UpdateType": "Mutable" + }, + "CloudWatchLoggingOptions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kinesisfirehose-deliverystream-amazonopensearchservicedestinationconfiguration.html#cfn-kinesisfirehose-deliverystream-amazonopensearchservicedestinationconfiguration-cloudwatchloggingoptions", + "Required": false, + "Type": "CloudWatchLoggingOptions", + "UpdateType": "Mutable" + }, + "ClusterEndpoint": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kinesisfirehose-deliverystream-amazonopensearchservicedestinationconfiguration.html#cfn-kinesisfirehose-deliverystream-amazonopensearchservicedestinationconfiguration-clusterendpoint", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "DomainARN": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kinesisfirehose-deliverystream-amazonopensearchservicedestinationconfiguration.html#cfn-kinesisfirehose-deliverystream-amazonopensearchservicedestinationconfiguration-domainarn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "IndexName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kinesisfirehose-deliverystream-amazonopensearchservicedestinationconfiguration.html#cfn-kinesisfirehose-deliverystream-amazonopensearchservicedestinationconfiguration-indexname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "IndexRotationPeriod": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kinesisfirehose-deliverystream-amazonopensearchservicedestinationconfiguration.html#cfn-kinesisfirehose-deliverystream-amazonopensearchservicedestinationconfiguration-indexrotationperiod", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "ProcessingConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kinesisfirehose-deliverystream-amazonopensearchservicedestinationconfiguration.html#cfn-kinesisfirehose-deliverystream-amazonopensearchservicedestinationconfiguration-processingconfiguration", + "Required": false, + "Type": "ProcessingConfiguration", + "UpdateType": "Mutable" + }, + "RetryOptions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kinesisfirehose-deliverystream-amazonopensearchservicedestinationconfiguration.html#cfn-kinesisfirehose-deliverystream-amazonopensearchservicedestinationconfiguration-retryoptions", + "Required": false, + "Type": "AmazonopensearchserviceRetryOptions", + "UpdateType": "Mutable" + }, + "RoleARN": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kinesisfirehose-deliverystream-amazonopensearchservicedestinationconfiguration.html#cfn-kinesisfirehose-deliverystream-amazonopensearchservicedestinationconfiguration-rolearn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "S3BackupMode": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kinesisfirehose-deliverystream-amazonopensearchservicedestinationconfiguration.html#cfn-kinesisfirehose-deliverystream-amazonopensearchservicedestinationconfiguration-s3backupmode", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "S3Configuration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kinesisfirehose-deliverystream-amazonopensearchservicedestinationconfiguration.html#cfn-kinesisfirehose-deliverystream-amazonopensearchservicedestinationconfiguration-s3configuration", + "Required": true, + "Type": "S3DestinationConfiguration", + "UpdateType": "Mutable" + }, + "TypeName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kinesisfirehose-deliverystream-amazonopensearchservicedestinationconfiguration.html#cfn-kinesisfirehose-deliverystream-amazonopensearchservicedestinationconfiguration-typename", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "VpcConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kinesisfirehose-deliverystream-amazonopensearchservicedestinationconfiguration.html#cfn-kinesisfirehose-deliverystream-amazonopensearchservicedestinationconfiguration-vpcconfiguration", + "Required": false, + "Type": "VpcConfiguration", + "UpdateType": "Immutable" + } + } + }, + "AWS::KinesisFirehose::DeliveryStream.AmazonopensearchserviceRetryOptions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kinesisfirehose-deliverystream-amazonopensearchserviceretryoptions.html", + "Properties": { + "DurationInSeconds": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kinesisfirehose-deliverystream-amazonopensearchserviceretryoptions.html#cfn-kinesisfirehose-deliverystream-amazonopensearchserviceretryoptions-durationinseconds", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::KinesisFirehose::DeliveryStream.BufferingHints": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kinesisfirehose-deliverystream-bufferinghints.html", "Properties": { @@ -41217,6 +41896,277 @@ } } }, + "AWS::Lightsail::Disk.AddOn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lightsail-disk-addon.html", + "Properties": { + "AddOnType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lightsail-disk-addon.html#cfn-lightsail-disk-addon-addontype", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "AutoSnapshotAddOnRequest": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lightsail-disk-addon.html#cfn-lightsail-disk-addon-autosnapshotaddonrequest", + "Required": false, + "Type": "AutoSnapshotAddOn", + "UpdateType": "Mutable" + }, + "Status": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lightsail-disk-addon.html#cfn-lightsail-disk-addon-status", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::Lightsail::Disk.AutoSnapshotAddOn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lightsail-disk-autosnapshotaddon.html", + "Properties": { + "SnapshotTimeOfDay": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lightsail-disk-autosnapshotaddon.html#cfn-lightsail-disk-autosnapshotaddon-snapshottimeofday", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::Lightsail::Instance.AddOn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lightsail-instance-addon.html", + "Properties": { + "AddOnType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lightsail-instance-addon.html#cfn-lightsail-instance-addon-addontype", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "AutoSnapshotAddOnRequest": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lightsail-instance-addon.html#cfn-lightsail-instance-addon-autosnapshotaddonrequest", + "Required": false, + "Type": "AutoSnapshotAddOn", + "UpdateType": "Mutable" + }, + "Status": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lightsail-instance-addon.html#cfn-lightsail-instance-addon-status", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::Lightsail::Instance.AutoSnapshotAddOn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lightsail-instance-autosnapshotaddon.html", + "Properties": { + "SnapshotTimeOfDay": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lightsail-instance-autosnapshotaddon.html#cfn-lightsail-instance-autosnapshotaddon-snapshottimeofday", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::Lightsail::Instance.Disk": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lightsail-instance-disk.html", + "Properties": { + "AttachedTo": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lightsail-instance-disk.html#cfn-lightsail-instance-disk-attachedto", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "AttachmentState": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lightsail-instance-disk.html#cfn-lightsail-instance-disk-attachmentstate", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "DiskName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lightsail-instance-disk.html#cfn-lightsail-instance-disk-diskname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "IOPS": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lightsail-instance-disk.html#cfn-lightsail-instance-disk-iops", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "IsSystemDisk": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lightsail-instance-disk.html#cfn-lightsail-instance-disk-issystemdisk", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "Path": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lightsail-instance-disk.html#cfn-lightsail-instance-disk-path", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "SizeInGb": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lightsail-instance-disk.html#cfn-lightsail-instance-disk-sizeingb", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::Lightsail::Instance.Hardware": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lightsail-instance-hardware.html", + "Properties": { + "CpuCount": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lightsail-instance-hardware.html#cfn-lightsail-instance-hardware-cpucount", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "Disks": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lightsail-instance-hardware.html#cfn-lightsail-instance-hardware-disks", + "DuplicatesAllowed": false, + "ItemType": "Disk", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "RamSizeInGb": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lightsail-instance-hardware.html#cfn-lightsail-instance-hardware-ramsizeingb", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::Lightsail::Instance.Location": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lightsail-instance-location.html", + "Properties": { + "AvailabilityZone": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lightsail-instance-location.html#cfn-lightsail-instance-location-availabilityzone", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "RegionName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lightsail-instance-location.html#cfn-lightsail-instance-location-regionname", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::Lightsail::Instance.MonthlyTransfer": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lightsail-instance-monthlytransfer.html", + "Properties": { + "GbPerMonthAllocated": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lightsail-instance-monthlytransfer.html#cfn-lightsail-instance-monthlytransfer-gbpermonthallocated", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::Lightsail::Instance.Networking": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lightsail-instance-networking.html", + "Properties": { + "MonthlyTransfer": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lightsail-instance-networking.html#cfn-lightsail-instance-networking-monthlytransfer", + "Required": false, + "UpdateType": "Mutable" + }, + "Ports": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lightsail-instance-networking.html#cfn-lightsail-instance-networking-ports", + "DuplicatesAllowed": false, + "ItemType": "Port", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::Lightsail::Instance.Port": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lightsail-instance-port.html", + "Properties": { + "AccessDirection": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lightsail-instance-port.html#cfn-lightsail-instance-port-accessdirection", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "AccessFrom": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lightsail-instance-port.html#cfn-lightsail-instance-port-accessfrom", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "AccessType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lightsail-instance-port.html#cfn-lightsail-instance-port-accesstype", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "CidrListAliases": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lightsail-instance-port.html#cfn-lightsail-instance-port-cidrlistaliases", + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "Cidrs": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lightsail-instance-port.html#cfn-lightsail-instance-port-cidrs", + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "CommonName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lightsail-instance-port.html#cfn-lightsail-instance-port-commonname", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "FromPort": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lightsail-instance-port.html#cfn-lightsail-instance-port-fromport", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "Ipv6Cidrs": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lightsail-instance-port.html#cfn-lightsail-instance-port-ipv6cidrs", + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "Protocol": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lightsail-instance-port.html#cfn-lightsail-instance-port-protocol", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "ToPort": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lightsail-instance-port.html#cfn-lightsail-instance-port-toport", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::Lightsail::Instance.State": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lightsail-instance-state.html", + "Properties": { + "Code": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lightsail-instance-state.html#cfn-lightsail-instance-state-code", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lightsail-instance-state.html#cfn-lightsail-instance-state-name", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::Location::Map.MapConfiguration": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-location-map-mapconfiguration.html", "Properties": { @@ -41793,13 +42743,19 @@ "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-msk-cluster-clientauthentication.html#cfn-msk-cluster-clientauthentication-sasl", "Required": false, "Type": "Sasl", - "UpdateType": "Immutable" + "UpdateType": "Mutable" }, "Tls": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-msk-cluster-clientauthentication.html#cfn-msk-cluster-clientauthentication-tls", "Required": false, "Type": "Tls", - "UpdateType": "Immutable" + "UpdateType": "Mutable" + }, + "Unauthenticated": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-msk-cluster-clientauthentication.html#cfn-msk-cluster-clientauthentication-unauthenticated", + "Required": false, + "Type": "Unauthenticated", + "UpdateType": "Mutable" } } }, @@ -41866,7 +42822,7 @@ "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-msk-cluster-encryptionintransit.html#cfn-msk-cluster-encryptionintransit-clientbroker", "PrimitiveType": "String", "Required": false, - "UpdateType": "Immutable" + "UpdateType": "Mutable" }, "InCluster": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-msk-cluster-encryptionintransit.html#cfn-msk-cluster-encryptionintransit-incluster", @@ -41889,7 +42845,7 @@ "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-msk-cluster-encryptioninfo.html#cfn-msk-cluster-encryptioninfo-encryptionintransit", "Required": false, "Type": "EncryptionInTransit", - "UpdateType": "Immutable" + "UpdateType": "Mutable" } } }, @@ -41917,7 +42873,7 @@ "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-msk-cluster-iam.html#cfn-msk-cluster-iam-enabled", "PrimitiveType": "Boolean", "Required": true, - "UpdateType": "Immutable" + "UpdateType": "Mutable" } } }, @@ -42012,13 +42968,13 @@ "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-msk-cluster-sasl.html#cfn-msk-cluster-sasl-iam", "Required": false, "Type": "Iam", - "UpdateType": "Immutable" + "UpdateType": "Mutable" }, "Scram": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-msk-cluster-sasl.html#cfn-msk-cluster-sasl-scram", "Required": false, "Type": "Scram", - "UpdateType": "Immutable" + "UpdateType": "Mutable" } } }, @@ -42029,7 +42985,7 @@ "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-msk-cluster-scram.html#cfn-msk-cluster-scram-enabled", "PrimitiveType": "Boolean", "Required": true, - "UpdateType": "Immutable" + "UpdateType": "Mutable" } } }, @@ -42052,7 +43008,24 @@ "PrimitiveItemType": "String", "Required": false, "Type": "List", - "UpdateType": "Immutable" + "UpdateType": "Mutable" + }, + "Enabled": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-msk-cluster-tls.html#cfn-msk-cluster-tls-enabled", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::MSK::Cluster.Unauthenticated": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-msk-cluster-unauthenticated.html", + "Properties": { + "Enabled": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-msk-cluster-unauthenticated.html#cfn-msk-cluster-unauthenticated-enabled", + "PrimitiveType": "Boolean", + "Required": true, + "UpdateType": "Mutable" } } }, @@ -42338,7 +43311,7 @@ "Algorithm": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-mediaconnect-flow-encryption.html#cfn-mediaconnect-flow-encryption-algorithm", "PrimitiveType": "String", - "Required": true, + "Required": false, "UpdateType": "Mutable" }, "ConstantInitializationVector": { @@ -42453,6 +43426,12 @@ "Required": false, "UpdateType": "Mutable" }, + "MinLatency": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-mediaconnect-flow-source.html#cfn-mediaconnect-flow-source-minlatency", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, "Name": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-mediaconnect-flow-source.html#cfn-mediaconnect-flow-source-name", "PrimitiveType": "String", @@ -42471,6 +43450,12 @@ "Required": false, "UpdateType": "Mutable" }, + "SourceIngestPort": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-mediaconnect-flow-source.html#cfn-mediaconnect-flow-source-sourceingestport", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, "StreamId": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-mediaconnect-flow-source.html#cfn-mediaconnect-flow-source-streamid", "PrimitiveType": "String", @@ -42556,7 +43541,7 @@ "Algorithm": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-mediaconnect-flowoutput-encryption.html#cfn-mediaconnect-flowoutput-encryption-algorithm", "PrimitiveType": "String", - "Required": true, + "Required": false, "UpdateType": "Mutable" }, "KeyType": { @@ -48214,6 +49199,23 @@ } } }, + "AWS::MemoryDB::Cluster.Endpoint": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-memorydb-cluster-endpoint.html", + "Properties": { + "Address": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-memorydb-cluster-endpoint.html#cfn-memorydb-cluster-endpoint-address", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Port": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-memorydb-cluster-endpoint.html#cfn-memorydb-cluster-endpoint-port", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::Neptune::DBCluster.DBClusterRole": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-neptune-dbcluster-dbclusterrole.html", "Properties": { @@ -49109,6 +50111,298 @@ } } }, + "AWS::OpenSearchService::Domain.AdvancedSecurityOptionsInput": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-opensearchservice-domain-advancedsecurityoptionsinput.html", + "Properties": { + "Enabled": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-opensearchservice-domain-advancedsecurityoptionsinput.html#cfn-opensearchservice-domain-advancedsecurityoptionsinput-enabled", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Immutable" + }, + "InternalUserDatabaseEnabled": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-opensearchservice-domain-advancedsecurityoptionsinput.html#cfn-opensearchservice-domain-advancedsecurityoptionsinput-internaluserdatabaseenabled", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Immutable" + }, + "MasterUserOptions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-opensearchservice-domain-advancedsecurityoptionsinput.html#cfn-opensearchservice-domain-advancedsecurityoptionsinput-masteruseroptions", + "Required": false, + "Type": "MasterUserOptions", + "UpdateType": "Immutable" + } + } + }, + "AWS::OpenSearchService::Domain.ClusterConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-opensearchservice-domain-clusterconfig.html", + "Properties": { + "DedicatedMasterCount": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-opensearchservice-domain-clusterconfig.html#cfn-opensearchservice-domain-clusterconfig-dedicatedmastercount", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "DedicatedMasterEnabled": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-opensearchservice-domain-clusterconfig.html#cfn-opensearchservice-domain-clusterconfig-dedicatedmasterenabled", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "DedicatedMasterType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-opensearchservice-domain-clusterconfig.html#cfn-opensearchservice-domain-clusterconfig-dedicatedmastertype", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "InstanceCount": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-opensearchservice-domain-clusterconfig.html#cfn-opensearchservice-domain-clusterconfig-instancecount", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "InstanceType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-opensearchservice-domain-clusterconfig.html#cfn-opensearchservice-domain-clusterconfig-instancetype", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "WarmCount": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-opensearchservice-domain-clusterconfig.html#cfn-opensearchservice-domain-clusterconfig-warmcount", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "WarmEnabled": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-opensearchservice-domain-clusterconfig.html#cfn-opensearchservice-domain-clusterconfig-warmenabled", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "WarmType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-opensearchservice-domain-clusterconfig.html#cfn-opensearchservice-domain-clusterconfig-warmtype", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "ZoneAwarenessConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-opensearchservice-domain-clusterconfig.html#cfn-opensearchservice-domain-clusterconfig-zoneawarenessconfig", + "Required": false, + "Type": "ZoneAwarenessConfig", + "UpdateType": "Mutable" + }, + "ZoneAwarenessEnabled": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-opensearchservice-domain-clusterconfig.html#cfn-opensearchservice-domain-clusterconfig-zoneawarenessenabled", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::OpenSearchService::Domain.CognitoOptions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-opensearchservice-domain-cognitooptions.html", + "Properties": { + "Enabled": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-opensearchservice-domain-cognitooptions.html#cfn-opensearchservice-domain-cognitooptions-enabled", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "IdentityPoolId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-opensearchservice-domain-cognitooptions.html#cfn-opensearchservice-domain-cognitooptions-identitypoolid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "RoleArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-opensearchservice-domain-cognitooptions.html#cfn-opensearchservice-domain-cognitooptions-rolearn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "UserPoolId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-opensearchservice-domain-cognitooptions.html#cfn-opensearchservice-domain-cognitooptions-userpoolid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::OpenSearchService::Domain.DomainEndpointOptions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-opensearchservice-domain-domainendpointoptions.html", + "Properties": { + "CustomEndpoint": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-opensearchservice-domain-domainendpointoptions.html#cfn-opensearchservice-domain-domainendpointoptions-customendpoint", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "CustomEndpointCertificateArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-opensearchservice-domain-domainendpointoptions.html#cfn-opensearchservice-domain-domainendpointoptions-customendpointcertificatearn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "CustomEndpointEnabled": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-opensearchservice-domain-domainendpointoptions.html#cfn-opensearchservice-domain-domainendpointoptions-customendpointenabled", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "EnforceHTTPS": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-opensearchservice-domain-domainendpointoptions.html#cfn-opensearchservice-domain-domainendpointoptions-enforcehttps", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "TLSSecurityPolicy": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-opensearchservice-domain-domainendpointoptions.html#cfn-opensearchservice-domain-domainendpointoptions-tlssecuritypolicy", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::OpenSearchService::Domain.EBSOptions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-opensearchservice-domain-ebsoptions.html", + "Properties": { + "EBSEnabled": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-opensearchservice-domain-ebsoptions.html#cfn-opensearchservice-domain-ebsoptions-ebsenabled", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "Iops": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-opensearchservice-domain-ebsoptions.html#cfn-opensearchservice-domain-ebsoptions-iops", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "VolumeSize": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-opensearchservice-domain-ebsoptions.html#cfn-opensearchservice-domain-ebsoptions-volumesize", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "VolumeType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-opensearchservice-domain-ebsoptions.html#cfn-opensearchservice-domain-ebsoptions-volumetype", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::OpenSearchService::Domain.EncryptionAtRestOptions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-opensearchservice-domain-encryptionatrestoptions.html", + "Properties": { + "Enabled": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-opensearchservice-domain-encryptionatrestoptions.html#cfn-opensearchservice-domain-encryptionatrestoptions-enabled", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "KmsKeyId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-opensearchservice-domain-encryptionatrestoptions.html#cfn-opensearchservice-domain-encryptionatrestoptions-kmskeyid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::OpenSearchService::Domain.LogPublishingOption": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-opensearchservice-domain-logpublishingoption.html", + "Properties": { + "CloudWatchLogsLogGroupArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-opensearchservice-domain-logpublishingoption.html#cfn-opensearchservice-domain-logpublishingoption-cloudwatchlogsloggrouparn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Enabled": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-opensearchservice-domain-logpublishingoption.html#cfn-opensearchservice-domain-logpublishingoption-enabled", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::OpenSearchService::Domain.MasterUserOptions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-opensearchservice-domain-masteruseroptions.html", + "Properties": { + "MasterUserARN": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-opensearchservice-domain-masteruseroptions.html#cfn-opensearchservice-domain-masteruseroptions-masteruserarn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "MasterUserName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-opensearchservice-domain-masteruseroptions.html#cfn-opensearchservice-domain-masteruseroptions-masterusername", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "MasterUserPassword": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-opensearchservice-domain-masteruseroptions.html#cfn-opensearchservice-domain-masteruseroptions-masteruserpassword", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + } + } + }, + "AWS::OpenSearchService::Domain.NodeToNodeEncryptionOptions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-opensearchservice-domain-nodetonodeencryptionoptions.html", + "Properties": { + "Enabled": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-opensearchservice-domain-nodetonodeencryptionoptions.html#cfn-opensearchservice-domain-nodetonodeencryptionoptions-enabled", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::OpenSearchService::Domain.SnapshotOptions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-opensearchservice-domain-snapshotoptions.html", + "Properties": { + "AutomatedSnapshotStartHour": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-opensearchservice-domain-snapshotoptions.html#cfn-opensearchservice-domain-snapshotoptions-automatedsnapshotstarthour", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::OpenSearchService::Domain.VPCOptions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-opensearchservice-domain-vpcoptions.html", + "Properties": { + "SecurityGroupIds": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-opensearchservice-domain-vpcoptions.html#cfn-opensearchservice-domain-vpcoptions-securitygroupids", + "DuplicatesAllowed": false, + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "SubnetIds": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-opensearchservice-domain-vpcoptions.html#cfn-opensearchservice-domain-vpcoptions-subnetids", + "DuplicatesAllowed": false, + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::OpenSearchService::Domain.ZoneAwarenessConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-opensearchservice-domain-zoneawarenessconfig.html", + "Properties": { + "AvailabilityZoneCount": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-opensearchservice-domain-zoneawarenessconfig.html#cfn-opensearchservice-domain-zoneawarenessconfig-availabilityzonecount", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::OpsWorks::App.DataSource": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-opsworks-app-datasource.html", "Properties": { @@ -54254,6 +55548,12 @@ "AWS::S3::Bucket.MetricsConfiguration": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-s3-bucket-metricsconfiguration.html", "Properties": { + "AccessPointArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-s3-bucket-metricsconfiguration.html#cfn-s3-bucket-metricsconfiguration-accesspointarn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, "Id": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-s3-bucket-metricsconfiguration.html#cfn-s3-bucket-metricsconfiguration-id", "PrimitiveType": "String", @@ -62203,7 +63503,7 @@ } } }, - "ResourceSpecificationVersion": "41.1.0", + "ResourceSpecificationVersion": "43.0.0", "ResourceTypes": { "AWS::ACMPCA::Certificate": { "Attributes": { @@ -62356,6 +63656,108 @@ } } }, + "AWS::ACMPCA::Permission": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-acmpca-permission.html", + "Properties": { + "Actions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-acmpca-permission.html#cfn-acmpca-permission-actions", + "PrimitiveItemType": "String", + "Required": true, + "Type": "List", + "UpdateType": "Immutable" + }, + "CertificateAuthorityArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-acmpca-permission.html#cfn-acmpca-permission-certificateauthorityarn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "Principal": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-acmpca-permission.html#cfn-acmpca-permission-principal", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "SourceAccount": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-acmpca-permission.html#cfn-acmpca-permission-sourceaccount", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + } + } + }, + "AWS::APS::RuleGroupsNamespace": { + "Attributes": { + "Arn": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-aps-rulegroupsnamespace.html", + "Properties": { + "Data": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-aps-rulegroupsnamespace.html#cfn-aps-rulegroupsnamespace-data", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-aps-rulegroupsnamespace.html#cfn-aps-rulegroupsnamespace-name", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-aps-rulegroupsnamespace.html#cfn-aps-rulegroupsnamespace-tags", + "DuplicatesAllowed": false, + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "Workspace": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-aps-rulegroupsnamespace.html#cfn-aps-rulegroupsnamespace-workspace", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::APS::Workspace": { + "Attributes": { + "Arn": { + "PrimitiveType": "String" + }, + "PrometheusEndpoint": { + "PrimitiveType": "String" + }, + "WorkspaceId": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-aps-workspace.html", + "Properties": { + "AlertManagerDefinition": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-aps-workspace.html#cfn-aps-workspace-alertmanagerdefinition", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Alias": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-aps-workspace.html#cfn-aps-workspace-alias", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-aps-workspace.html#cfn-aps-workspace-tags", + "DuplicatesAllowed": false, + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, "AWS::AccessAnalyzer::Analyzer": { "Attributes": { "Arn": { @@ -63240,11 +64642,15 @@ } }, "AWS::ApiGateway::GatewayResponse": { + "Attributes": { + "Id": { + "PrimitiveType": "String" + } + }, "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-gatewayresponse.html", "Properties": { "ResponseParameters": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-gatewayresponse.html#cfn-apigateway-gatewayresponse-responseparameters", - "DuplicatesAllowed": false, "PrimitiveItemType": "String", "Required": false, "Type": "Map", @@ -63252,7 +64658,6 @@ }, "ResponseTemplates": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-gatewayresponse.html#cfn-apigateway-gatewayresponse-responsetemplates", - "DuplicatesAllowed": false, "PrimitiveItemType": "String", "Required": false, "Type": "Map", @@ -65876,6 +67281,12 @@ "Required": true, "UpdateType": "Immutable" }, + "OpenSearchServiceConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-appsync-datasource.html#cfn-appsync-datasource-opensearchserviceconfig", + "Required": false, + "Type": "OpenSearchServiceConfig", + "UpdateType": "Mutable" + }, "RelationalDatabaseConfig": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-appsync-datasource.html#cfn-appsync-datasource-relationaldatabaseconfig", "Required": false, @@ -67221,6 +68632,12 @@ "Required": false, "UpdateType": "Immutable" }, + "LockConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-backup-backupvault.html#cfn-backup-backupvault-lockconfiguration", + "Required": false, + "Type": "LockConfigurationType", + "UpdateType": "Mutable" + }, "Notifications": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-backup-backupvault.html#cfn-backup-backupvault-notifications", "Required": false, @@ -67229,6 +68646,93 @@ } } }, + "AWS::Backup::Framework": { + "Attributes": { + "CreationTime": { + "PrimitiveType": "Double" + }, + "DeploymentStatus": { + "PrimitiveType": "String" + }, + "FrameworkArn": { + "PrimitiveType": "String" + }, + "FrameworkStatus": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-backup-framework.html", + "Properties": { + "FrameworkControls": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-backup-framework.html#cfn-backup-framework-frameworkcontrols", + "DuplicatesAllowed": false, + "ItemType": "FrameworkControl", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + }, + "FrameworkDescription": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-backup-framework.html#cfn-backup-framework-frameworkdescription", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "FrameworkName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-backup-framework.html#cfn-backup-framework-frameworkname", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "FrameworkTags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-backup-framework.html#cfn-backup-framework-frameworktags", + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::Backup::ReportPlan": { + "Attributes": { + "ReportPlanArn": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-backup-reportplan.html", + "Properties": { + "ReportDeliveryChannel": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-backup-reportplan.html#cfn-backup-reportplan-reportdeliverychannel", + "PrimitiveType": "Json", + "Required": true, + "UpdateType": "Mutable" + }, + "ReportPlanDescription": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-backup-reportplan.html#cfn-backup-reportplan-reportplandescription", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "ReportPlanName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-backup-reportplan.html#cfn-backup-reportplan-reportplanname", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "ReportPlanTags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-backup-reportplan.html#cfn-backup-reportplan-reportplantags", + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "ReportSetting": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-backup-reportplan.html#cfn-backup-reportplan-reportsetting", + "PrimitiveType": "Json", + "Required": true, + "UpdateType": "Mutable" + } + } + }, "AWS::Batch::ComputeEnvironment": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-batch-computeenvironment.html", "Properties": { @@ -70799,6 +72303,11 @@ } }, "AWS::Config::AggregationAuthorization": { + "Attributes": { + "AggregationAuthorizationArn": { + "PrimitiveType": "String" + } + }, "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-config-aggregationauthorization.html", "Properties": { "AuthorizedAccountId": { @@ -70815,6 +72324,7 @@ }, "Tags": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-config-aggregationauthorization.html#cfn-config-aggregationauthorization-tags", + "DuplicatesAllowed": false, "ItemType": "Tag", "Required": false, "Type": "List", @@ -77408,6 +78918,9 @@ }, "AWS::EFS::MountTarget": { "Attributes": { + "Id": { + "PrimitiveType": "String" + }, "IpAddress": { "PrimitiveType": "String" } @@ -78081,6 +79594,18 @@ "Required": true, "UpdateType": "Immutable" }, + "IdpAuthUrl": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-emr-studio.html#cfn-emr-studio-idpauthurl", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "IdpRelayStateParameterName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-emr-studio.html#cfn-emr-studio-idprelaystateparametername", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, "Name": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-emr-studio.html#cfn-emr-studio-name", "PrimitiveType": "String", @@ -78111,7 +79636,7 @@ "UserRole": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-emr-studio.html#cfn-emr-studio-userrole", "PrimitiveType": "String", - "Required": true, + "Required": false, "UpdateType": "Immutable" }, "VpcId": { @@ -82888,6 +84413,56 @@ } } }, + "AWS::HealthLake::FHIRDatastore": { + "Attributes": { + "DatastoreArn": { + "PrimitiveType": "String" + }, + "DatastoreEndpoint": { + "PrimitiveType": "String" + }, + "DatastoreId": { + "PrimitiveType": "String" + }, + "DatastoreStatus": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-healthlake-fhirdatastore.html", + "Properties": { + "DatastoreName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-healthlake-fhirdatastore.html#cfn-healthlake-fhirdatastore-datastorename", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "DatastoreTypeVersion": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-healthlake-fhirdatastore.html#cfn-healthlake-fhirdatastore-datastoretypeversion", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "PreloadDataConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-healthlake-fhirdatastore.html#cfn-healthlake-fhirdatastore-preloaddataconfig", + "Required": false, + "Type": "PreloadDataConfig", + "UpdateType": "Immutable" + }, + "SseConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-healthlake-fhirdatastore.html#cfn-healthlake-fhirdatastore-sseconfiguration", + "Required": false, + "Type": "SseConfiguration", + "UpdateType": "Immutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-healthlake-fhirdatastore.html#cfn-healthlake-fhirdatastore-tags", + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, "AWS::IAM::AccessKey": { "Attributes": { "SecretAccessKey": { @@ -86576,6 +88151,12 @@ }, "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-kinesisfirehose-deliverystream.html", "Properties": { + "AmazonopensearchserviceDestinationConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-kinesisfirehose-deliverystream.html#cfn-kinesisfirehose-deliverystream-amazonopensearchservicedestinationconfiguration", + "Required": false, + "Type": "AmazonopensearchserviceDestinationConfiguration", + "UpdateType": "Mutable" + }, "DeliveryStreamEncryptionConfigurationInput": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-kinesisfirehose-deliverystream.html#cfn-kinesisfirehose-deliverystream-deliverystreamencryptionconfigurationinput", "Required": false, @@ -86958,6 +88539,14 @@ }, "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html", "Properties": { + "Architectures": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html#cfn-lambda-function-architectures", + "DuplicatesAllowed": false, + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, "Code": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html#cfn-lambda-function-code", "Required": true, @@ -87088,6 +88677,13 @@ "AWS::Lambda::LayerVersion": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-layerversion.html", "Properties": { + "CompatibleArchitectures": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-layerversion.html#cfn-lambda-layerversion-compatiblearchitectures", + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Immutable" + }, "CompatibleRuntimes": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-layerversion.html#cfn-lambda-layerversion-compatibleruntimes", "PrimitiveItemType": "String", @@ -87361,6 +88957,194 @@ } } }, + "AWS::Lightsail::Disk": { + "Attributes": { + "AttachedTo": { + "PrimitiveType": "String" + }, + "AttachmentState": { + "PrimitiveType": "String" + }, + "DiskArn": { + "PrimitiveType": "String" + }, + "Iops": { + "PrimitiveType": "Integer" + }, + "IsAttached": { + "PrimitiveType": "Boolean" + }, + "Path": { + "PrimitiveType": "String" + }, + "ResourceType": { + "PrimitiveType": "String" + }, + "State": { + "PrimitiveType": "String" + }, + "SupportCode": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lightsail-disk.html", + "Properties": { + "AddOns": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lightsail-disk.html#cfn-lightsail-disk-addons", + "ItemType": "AddOn", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "AvailabilityZone": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lightsail-disk.html#cfn-lightsail-disk-availabilityzone", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "DiskName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lightsail-disk.html#cfn-lightsail-disk-diskname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "SizeInGb": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lightsail-disk.html#cfn-lightsail-disk-sizeingb", + "PrimitiveType": "Integer", + "Required": true, + "UpdateType": "Immutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lightsail-disk.html#cfn-lightsail-disk-tags", + "DuplicatesAllowed": false, + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::Lightsail::Instance": { + "Attributes": { + "Hardware.CpuCount": { + "PrimitiveType": "Integer" + }, + "Hardware.RamSizeInGb": { + "PrimitiveType": "Integer" + }, + "InstanceArn": { + "PrimitiveType": "String" + }, + "IsStaticIp": { + "PrimitiveType": "Boolean" + }, + "KeyPairName": { + "PrimitiveType": "String" + }, + "Location.AvailabilityZone": { + "PrimitiveType": "String" + }, + "Location.RegionName": { + "PrimitiveType": "String" + }, + "Networking.MonthlyTransfer.GbPerMonthAllocated": { + "PrimitiveType": "String" + }, + "PrivateIpAddress": { + "PrimitiveType": "String" + }, + "PublicIpAddress": { + "PrimitiveType": "String" + }, + "ResourceType": { + "PrimitiveType": "String" + }, + "SshKeyName": { + "PrimitiveType": "String" + }, + "State.Code": { + "PrimitiveType": "Integer" + }, + "State.Name": { + "PrimitiveType": "String" + }, + "SupportCode": { + "PrimitiveType": "String" + }, + "UserData": { + "PrimitiveType": "String" + }, + "UserName": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lightsail-instance.html", + "Properties": { + "AddOns": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lightsail-instance.html#cfn-lightsail-instance-addons", + "ItemType": "AddOn", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "AvailabilityZone": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lightsail-instance.html#cfn-lightsail-instance-availabilityzone", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "BlueprintId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lightsail-instance.html#cfn-lightsail-instance-blueprintid", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "BundleId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lightsail-instance.html#cfn-lightsail-instance-bundleid", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "Hardware": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lightsail-instance.html#cfn-lightsail-instance-hardware", + "Required": false, + "Type": "Hardware", + "UpdateType": "Mutable" + }, + "InstanceName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lightsail-instance.html#cfn-lightsail-instance-instancename", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "Location": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lightsail-instance.html#cfn-lightsail-instance-location", + "Required": false, + "Type": "Location", + "UpdateType": "Mutable" + }, + "Networking": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lightsail-instance.html#cfn-lightsail-instance-networking", + "Required": false, + "Type": "Networking", + "UpdateType": "Mutable" + }, + "State": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lightsail-instance.html#cfn-lightsail-instance-state", + "Required": false, + "Type": "State", + "UpdateType": "Mutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lightsail-instance.html#cfn-lightsail-instance-tags", + "DuplicatesAllowed": false, + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, "AWS::Location::GeofenceCollection": { "Attributes": { "Arn": { @@ -87969,7 +89753,7 @@ "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-msk-cluster.html#cfn-msk-cluster-clientauthentication", "Required": false, "Type": "ClientAuthentication", - "UpdateType": "Immutable" + "UpdateType": "Mutable" }, "ClusterName": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-msk-cluster.html#cfn-msk-cluster-clustername", @@ -87987,7 +89771,7 @@ "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-msk-cluster.html#cfn-msk-cluster-encryptioninfo", "Required": false, "Type": "EncryptionInfo", - "UpdateType": "Immutable" + "UpdateType": "Mutable" }, "EnhancedMonitoring": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-msk-cluster.html#cfn-msk-cluster-enhancedmonitoring", @@ -88385,6 +90169,9 @@ }, "Source.SourceArn": { "PrimitiveType": "String" + }, + "Source.SourceIngestPort": { + "PrimitiveType": "String" } }, "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-mediaconnect-flow.html", @@ -88513,6 +90300,12 @@ "Required": false, "UpdateType": "Mutable" }, + "MinLatency": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-mediaconnect-flowoutput.html#cfn-mediaconnect-flowoutput-minlatency", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, "Name": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-mediaconnect-flowoutput.html#cfn-mediaconnect-flowoutput-name", "PrimitiveType": "String", @@ -88564,6 +90357,9 @@ }, "SourceArn": { "PrimitiveType": "String" + }, + "SourceIngestPort": { + "PrimitiveType": "String" } }, "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-mediaconnect-flowsource.html", @@ -89376,6 +91172,332 @@ } } }, + "AWS::MemoryDB::ACL": { + "Attributes": { + "Arn": { + "PrimitiveType": "String" + }, + "Status": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-acl.html", + "Properties": { + "ACLName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-acl.html#cfn-memorydb-acl-aclname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-acl.html#cfn-memorydb-acl-tags", + "DuplicatesAllowed": false, + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "UserNames": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-acl.html#cfn-memorydb-acl-usernames", + "DuplicatesAllowed": false, + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::MemoryDB::Cluster": { + "Attributes": { + "ARN": { + "PrimitiveType": "String" + }, + "ClusterEndpoint.Address": { + "PrimitiveType": "String" + }, + "ClusterEndpoint.Port": { + "PrimitiveType": "Integer" + }, + "ParameterGroupStatus": { + "PrimitiveType": "String" + }, + "Status": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-cluster.html", + "Properties": { + "ACLName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-cluster.html#cfn-memorydb-cluster-aclname", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "AutoMinorVersionUpgrade": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-cluster.html#cfn-memorydb-cluster-autominorversionupgrade", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "ClusterEndpoint": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-cluster.html#cfn-memorydb-cluster-clusterendpoint", + "Required": false, + "Type": "Endpoint", + "UpdateType": "Mutable" + }, + "ClusterName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-cluster.html#cfn-memorydb-cluster-clustername", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "Description": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-cluster.html#cfn-memorydb-cluster-description", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "EngineVersion": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-cluster.html#cfn-memorydb-cluster-engineversion", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "FinalSnapshotName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-cluster.html#cfn-memorydb-cluster-finalsnapshotname", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "KmsKeyId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-cluster.html#cfn-memorydb-cluster-kmskeyid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "MaintenanceWindow": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-cluster.html#cfn-memorydb-cluster-maintenancewindow", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "NodeType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-cluster.html#cfn-memorydb-cluster-nodetype", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "NumReplicasPerShard": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-cluster.html#cfn-memorydb-cluster-numreplicaspershard", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "NumShards": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-cluster.html#cfn-memorydb-cluster-numshards", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "ParameterGroupName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-cluster.html#cfn-memorydb-cluster-parametergroupname", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Port": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-cluster.html#cfn-memorydb-cluster-port", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Immutable" + }, + "SecurityGroupIds": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-cluster.html#cfn-memorydb-cluster-securitygroupids", + "DuplicatesAllowed": true, + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "SnapshotArns": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-cluster.html#cfn-memorydb-cluster-snapshotarns", + "DuplicatesAllowed": true, + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Immutable" + }, + "SnapshotName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-cluster.html#cfn-memorydb-cluster-snapshotname", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "SnapshotRetentionLimit": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-cluster.html#cfn-memorydb-cluster-snapshotretentionlimit", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "SnapshotWindow": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-cluster.html#cfn-memorydb-cluster-snapshotwindow", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "SnsTopicArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-cluster.html#cfn-memorydb-cluster-snstopicarn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "SnsTopicStatus": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-cluster.html#cfn-memorydb-cluster-snstopicstatus", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "SubnetGroupName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-cluster.html#cfn-memorydb-cluster-subnetgroupname", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "TLSEnabled": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-cluster.html#cfn-memorydb-cluster-tlsenabled", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Immutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-cluster.html#cfn-memorydb-cluster-tags", + "DuplicatesAllowed": false, + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::MemoryDB::ParameterGroup": { + "Attributes": { + "ARN": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-parametergroup.html", + "Properties": { + "Description": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-parametergroup.html#cfn-memorydb-parametergroup-description", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "Family": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-parametergroup.html#cfn-memorydb-parametergroup-family", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "ParameterGroupName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-parametergroup.html#cfn-memorydb-parametergroup-parametergroupname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "Parameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-parametergroup.html#cfn-memorydb-parametergroup-parameters", + "PrimitiveType": "Json", + "Required": false, + "UpdateType": "Mutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-parametergroup.html#cfn-memorydb-parametergroup-tags", + "DuplicatesAllowed": false, + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::MemoryDB::SubnetGroup": { + "Attributes": { + "ARN": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-subnetgroup.html", + "Properties": { + "Description": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-subnetgroup.html#cfn-memorydb-subnetgroup-description", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "SubnetGroupName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-subnetgroup.html#cfn-memorydb-subnetgroup-subnetgroupname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "SubnetIds": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-subnetgroup.html#cfn-memorydb-subnetgroup-subnetids", + "DuplicatesAllowed": false, + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-subnetgroup.html#cfn-memorydb-subnetgroup-tags", + "DuplicatesAllowed": false, + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::MemoryDB::User": { + "Attributes": { + "Arn": { + "PrimitiveType": "String" + }, + "Status": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-user.html", + "Properties": { + "AccessString": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-user.html#cfn-memorydb-user-accessstring", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "AuthenticationMode": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-user.html#cfn-memorydb-user-authenticationmode", + "PrimitiveType": "Json", + "Required": true, + "UpdateType": "Mutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-user.html#cfn-memorydb-user-tags", + "DuplicatesAllowed": false, + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "UserName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-user.html#cfn-memorydb-user-username", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + } + } + }, "AWS::Neptune::DBCluster": { "Attributes": { "ClusterResourceId": { @@ -90403,6 +92525,119 @@ } } }, + "AWS::OpenSearchService::Domain": { + "Attributes": { + "Arn": { + "PrimitiveType": "String" + }, + "DomainArn": { + "PrimitiveType": "String" + }, + "DomainEndpoint": { + "PrimitiveType": "String" + }, + "Id": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-opensearchservice-domain.html", + "Properties": { + "AccessPolicies": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-opensearchservice-domain.html#cfn-opensearchservice-domain-accesspolicies", + "PrimitiveType": "Json", + "Required": false, + "UpdateType": "Mutable" + }, + "AdvancedOptions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-opensearchservice-domain.html#cfn-opensearchservice-domain-advancedoptions", + "PrimitiveItemType": "String", + "Required": false, + "Type": "Map", + "UpdateType": "Mutable" + }, + "AdvancedSecurityOptions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-opensearchservice-domain.html#cfn-opensearchservice-domain-advancedsecurityoptions", + "Required": false, + "Type": "AdvancedSecurityOptionsInput", + "UpdateType": "Immutable" + }, + "ClusterConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-opensearchservice-domain.html#cfn-opensearchservice-domain-clusterconfig", + "Required": false, + "Type": "ClusterConfig", + "UpdateType": "Mutable" + }, + "CognitoOptions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-opensearchservice-domain.html#cfn-opensearchservice-domain-cognitooptions", + "Required": false, + "Type": "CognitoOptions", + "UpdateType": "Mutable" + }, + "DomainEndpointOptions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-opensearchservice-domain.html#cfn-opensearchservice-domain-domainendpointoptions", + "Required": false, + "Type": "DomainEndpointOptions", + "UpdateType": "Mutable" + }, + "DomainName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-opensearchservice-domain.html#cfn-opensearchservice-domain-domainname", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "EBSOptions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-opensearchservice-domain.html#cfn-opensearchservice-domain-ebsoptions", + "Required": false, + "Type": "EBSOptions", + "UpdateType": "Mutable" + }, + "EncryptionAtRestOptions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-opensearchservice-domain.html#cfn-opensearchservice-domain-encryptionatrestoptions", + "Required": false, + "Type": "EncryptionAtRestOptions", + "UpdateType": "Mutable" + }, + "EngineVersion": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-opensearchservice-domain.html#cfn-opensearchservice-domain-engineversion", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "LogPublishingOptions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-opensearchservice-domain.html#cfn-opensearchservice-domain-logpublishingoptions", + "ItemType": "LogPublishingOption", + "Required": false, + "Type": "Map", + "UpdateType": "Mutable" + }, + "NodeToNodeEncryptionOptions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-opensearchservice-domain.html#cfn-opensearchservice-domain-nodetonodeencryptionoptions", + "Required": false, + "Type": "NodeToNodeEncryptionOptions", + "UpdateType": "Mutable" + }, + "SnapshotOptions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-opensearchservice-domain.html#cfn-opensearchservice-domain-snapshotoptions", + "Required": false, + "Type": "SnapshotOptions", + "UpdateType": "Mutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-opensearchservice-domain.html#cfn-opensearchservice-domain-tags", + "DuplicatesAllowed": false, + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "VPCOptions": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-opensearchservice-domain.html#cfn-opensearchservice-domain-vpcoptions", + "Required": false, + "Type": "VPCOptions", + "UpdateType": "Mutable" + } + } + }, "AWS::OpsWorks::App": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-opsworks-app.html", "Properties": { @@ -94380,6 +96615,12 @@ "Required": false, "UpdateType": "Mutable" }, + "Environment": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-robomaker-simulationapplication.html#cfn-robomaker-simulationapplication-environment", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, "Name": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-robomaker-simulationapplication.html#cfn-robomaker-simulationapplication-name", "PrimitiveType": "String", @@ -94388,7 +96629,7 @@ }, "RenderingEngine": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-robomaker-simulationapplication.html#cfn-robomaker-simulationapplication-renderingengine", - "Required": true, + "Required": false, "Type": "RenderingEngine", "UpdateType": "Mutable" }, @@ -94407,7 +96648,7 @@ "Sources": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-robomaker-simulationapplication.html#cfn-robomaker-simulationapplication-sources", "ItemType": "SourceConfig", - "Required": true, + "Required": false, "Type": "List", "UpdateType": "Mutable" }, @@ -96211,6 +98452,12 @@ "Required": false, "UpdateType": "Mutable" }, + "RedriveAllowPolicy": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sqs-queues.html#aws-sqs-queue-redriveallowpolicy", + "PrimitiveType": "Json", + "Required": false, + "UpdateType": "Mutable" + }, "RedrivePolicy": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sqs-queues.html#aws-sqs-queue-redrive", "PrimitiveType": "Json", @@ -96234,16 +98481,21 @@ } }, "AWS::SQS::QueuePolicy": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sqs-policy.html", + "Attributes": { + "Id": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sqs-queuepolicy.html", "Properties": { "PolicyDocument": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sqs-policy.html#cfn-sqs-queuepolicy-policydoc", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sqs-queuepolicy.html#cfn-sqs-queuepolicy-policydocument", "PrimitiveType": "Json", "Required": true, "UpdateType": "Mutable" }, "Queues": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sqs-policy.html#cfn-sqs-queuepolicy-queues", + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sqs-queuepolicy.html#cfn-sqs-queuepolicy-queues", "DuplicatesAllowed": true, "PrimitiveItemType": "String", "Required": true, @@ -96540,6 +98792,12 @@ "AWS::SSM::MaintenanceWindowTask": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ssm-maintenancewindowtask.html", "Properties": { + "CutoffBehavior": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ssm-maintenancewindowtask.html#cfn-ssm-maintenancewindowtask-cutoffbehavior", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, "Description": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ssm-maintenancewindowtask.html#cfn-ssm-maintenancewindowtask-description", "PrimitiveType": "String", diff --git a/packages/@aws-cdk/cfnspec/spec-source/000_sam.spec.json b/packages/@aws-cdk/cfnspec/spec-source/000_sam.spec.json index ae7bf4601634e..5510475b3e7d2 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/000_sam.spec.json +++ b/packages/@aws-cdk/cfnspec/spec-source/000_sam.spec.json @@ -491,12 +491,6 @@ "Required": true, "Type": "Destination", "UpdateType": "Immutable" - }, - "OnSuccess": { - "Documentation": "https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#destination-config-object", - "Required": true, - "Type": "Destination", - "UpdateType": "Immutable" } } }, @@ -615,7 +609,7 @@ "DestinationConfig": { "Documentation": "https://github.com/aws/serverless-application-model/blob/master/versions/2016-10-31.md#event-invoke-config-object", "Required": false, - "Type": "DestinationConfig", + "Type": "EventInvokeDestinationConfig", "UpdateType": "Immutable" }, "MaximumEventAgeInSeconds": { @@ -632,6 +626,23 @@ } } }, + "AWS::Serverless::Function.EventInvokeDestinationConfig": { + "Documentation": "https://github.com/aws/serverless-application-model/blob/master/versions/2016-10-31.md#event-invoke-destination-config-object", + "Properties": { + "OnFailure": { + "Documentation": "https://github.com/aws/serverless-application-model/blob/master/versions/2016-10-31.md#event-invoke-destination-config-object", + "Required": true, + "Type": "Destination", + "UpdateType": "Immutable" + }, + "OnSuccess": { + "Documentation": "https://github.com/aws/serverless-application-model/blob/master/versions/2016-10-31.md#event-invoke-destination-config-object", + "Required": true, + "Type": "Destination", + "UpdateType": "Immutable" + } + } + }, "AWS::Serverless::Function.EventSource": { "Documentation": "https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#event-source-object", "Properties": { diff --git a/packages/@aws-cdk/cfnspec/spec-source/902_Lightsail_Instance_patch.json b/packages/@aws-cdk/cfnspec/spec-source/902_Lightsail_Instance_patch.json new file mode 100644 index 0000000000000..2198e6445bc89 --- /dev/null +++ b/packages/@aws-cdk/cfnspec/spec-source/902_Lightsail_Instance_patch.json @@ -0,0 +1,16 @@ +{ + "PropertyTypes": { + "patch": { + "description": "Add type", + "operations": [ + { + "op": "add", + "path": "/AWS::Lightsail::Instance.Networking/Properties/MonthlyTransfer", + "value": { + "PrimitiveType": "Integer" + } + } + ] + } + } +} diff --git a/packages/@aws-cdk/cfnspec/test/augmentation.test.ts b/packages/@aws-cdk/cfnspec/test/augmentation.test.ts new file mode 100644 index 0000000000000..74931a754b3a7 --- /dev/null +++ b/packages/@aws-cdk/cfnspec/test/augmentation.test.ts @@ -0,0 +1,26 @@ +import * as fs from 'fs'; +import * as path from 'path'; +import * as cfnspec from '../lib'; +import { MetricType } from '../lib/schema'; + +function resourceAugmentationTest(resource: string) { + return () => { + const model = cfnspec.resourceAugmentation(resource); + + if (model.metrics) { + expect(typeof(model.metrics.namespace) === 'string').toBeTruthy(); + expect(typeof(model.metrics.dimensions) === 'object').toBeTruthy(); + for (const metric of model.metrics.metrics) { + expect(typeof metric.name === 'string').toBeTruthy(); + expect(typeof metric.documentation === 'string').toBeTruthy(); + expect(metric.type === undefined || [MetricType.Attrib, MetricType.Count, MetricType.Gauge].includes(metric.type)).toBeTruthy(); + } + } + }; +} + +const files = fs.readdirSync(path.resolve(__dirname, '../lib/augmentations')); +for (const file of files) { + const resource = file.replace(/\.json$/, '').replace(/_/g, '::'); + test(`Validate augmentation schema for ${resource}`, resourceAugmentationTest(resource)); +} diff --git a/packages/@aws-cdk/cfnspec/test/build.test.ts b/packages/@aws-cdk/cfnspec/test/build.test.ts new file mode 100644 index 0000000000000..6612fe9f15b43 --- /dev/null +++ b/packages/@aws-cdk/cfnspec/test/build.test.ts @@ -0,0 +1,63 @@ +import { massageSpec } from '../build-tools/massage-spec'; +import { schema } from '../lib'; + +test('dropTypelessAttributes works correctly', () => { + const spec: schema.Specification = { + Fingerprint: 'some-fingerprint', + PropertyTypes: { + 'CDK::Test::Property': { + Properties: { + Type: ({ + PrimitiveType: 'String', + } as schema.ScalarProperty), // ts is being weird and doesn't correctly match the type + }, + }, + }, + ResourceTypes: { + 'CDK::Test::Resource': { + Attributes: { + Attribute1: ({ + PrimitiveType: 'String', + } as schema.PrimitiveAttribute), // ts is being weird and doesn't correctly match the type + Attribute2: ({} as schema.PrimitiveAttribute), + }, + Documentation: 'https://documentation-url/cdk/test/resource', + Properties: { + ResourceArn: ({ + PrimitiveType: 'String', + } as schema.PrimitiveProperty), // ts is being weird and doesn't correctly match the type + }, + }, + }, + }; + + massageSpec(spec); + + expect(spec).toEqual({ + Fingerprint: 'some-fingerprint', + PropertyTypes: { + 'CDK::Test::Property': { + Properties: { + Type: ({ + PrimitiveType: 'String', + } as schema.ScalarProperty), // ts is being weird and doesn't correctly match the type + }, + }, + }, + ResourceTypes: { + 'CDK::Test::Resource': { + Attributes: { + Attribute1: ({ + PrimitiveType: 'String', + }), + }, + Documentation: 'https://documentation-url/cdk/test/resource', + Properties: { + ResourceArn: { + PrimitiveType: 'String', + }, + }, + }, + }, + }); +}); diff --git a/packages/@aws-cdk/cfnspec/test/canned-metrics.test.ts b/packages/@aws-cdk/cfnspec/test/canned-metrics.test.ts new file mode 100644 index 0000000000000..db884768588cf --- /dev/null +++ b/packages/@aws-cdk/cfnspec/test/canned-metrics.test.ts @@ -0,0 +1,31 @@ +import * as cfnspec from '../lib'; + +test('spot-check DynamoDB metrics', () => { + const metrics = cfnspec.cannedMetricsForService('AWS::DynamoDB'); + expect(metrics.length).toBeGreaterThan(0); + + const resLatency = metrics.find(m => m.metricName === 'SuccessfulRequestLatency'); + expect(resLatency).toBeTruthy(); + + expect(resLatency?.dimensions).toEqual([['Operation', 'TableName']]); +}); + +test('spot-check MediaStore metrics', () => { + const metrics = cfnspec.cannedMetricsForService('AWS::MediaStore'); + expect(metrics.length).toBeGreaterThan(0); +}); + +/** + * Test that we can read canned metrics for all namespaces in the spec without throwing an error + */ +for (const _namespace of cfnspec.namespaces()) { + const namespace = _namespace; + test(`Validate canned metrics for ${namespace}`, () => { + const metrics = cfnspec.cannedMetricsForService(namespace); + + // Check that there are no duplicates in these list (duplicates may occur because of duplicate + // dimensions, but those have readly been combined). + const uniqueMetricNames = new Set(metrics.map(m => `${m.namespace}/${m.metricName}`)); + expect(uniqueMetricNames.size).toEqual(metrics.length); + }); +}; \ No newline at end of file diff --git a/packages/@aws-cdk/cfnspec/test/cfnlint-annotations.test.ts b/packages/@aws-cdk/cfnspec/test/cfnlint-annotations.test.ts new file mode 100644 index 0000000000000..776cac3df6a1d --- /dev/null +++ b/packages/@aws-cdk/cfnspec/test/cfnlint-annotations.test.ts @@ -0,0 +1,19 @@ +import * as cfnspec from '../lib'; + +test('spot-check Bucket statefulness', () => { + const anno = cfnspec.cfnLintAnnotations('AWS::S3::Bucket'); + expect(anno.stateful).toBeTruthy(); + expect(anno.mustBeEmptyToDelete).toBeTruthy(); +}); + +test('spot-check Table statefulness', () => { + const anno = cfnspec.cfnLintAnnotations('AWS::DynamoDB::Table'); + expect(anno.stateful).toBeTruthy(); + expect(anno.mustBeEmptyToDelete).toBeFalsy(); +}); + +test('spot-check MediaStore metrics', () => { + const anno = cfnspec.cfnLintAnnotations('AWS::MediaStore::Thingy'); + expect(anno.stateful).toBeFalsy(); +}); + diff --git a/packages/@aws-cdk/cfnspec/test/filtered-specification.test.ts b/packages/@aws-cdk/cfnspec/test/filtered-specification.test.ts new file mode 100644 index 0000000000000..e9f18346699ea --- /dev/null +++ b/packages/@aws-cdk/cfnspec/test/filtered-specification.test.ts @@ -0,0 +1,24 @@ +import { filteredSpecification, resourceTypes, specification } from '../lib/index'; +import { validateSpecification } from './spec-validators'; + +test('filteredSpecification(/^AWS::S3::.*/)', () => { + const filteredSpec = filteredSpecification(/^AWS::S3::.*/); + expect(filteredSpec).not.toEqual(specification); + expect(filteredSpec.ResourceTypes).not.toEqual({}); +}); + +test('filteredSpecification(s => s.startsWith("AWS::S3::")', () => { + const filteredSpec = filteredSpecification(s => s.startsWith('AWS::S3::')); + expect(filteredSpec).not.toEqual(specification); + expect(filteredSpec.ResourceTypes).not.toEqual({}); +}); + +for (const name of resourceTypes().sort()) { + describe(`filteredSpecification(${JSON.stringify(name)})`, () => { + const filteredSpec = filteredSpecification(name); + expect(filteredSpec).not.toEqual(specification); + expect(filteredSpec.ResourceTypes).not.toEqual({}); + // Validate the spec is conform & coherent. + validateSpecification(filteredSpec); + }); +} diff --git a/packages/@aws-cdk/cfnspec/test/libary-creation.test.ts b/packages/@aws-cdk/cfnspec/test/libary-creation.test.ts new file mode 100644 index 0000000000000..354952325f314 --- /dev/null +++ b/packages/@aws-cdk/cfnspec/test/libary-creation.test.ts @@ -0,0 +1,59 @@ +import { createModuleDefinitionFromCfnNamespace } from '../lib'; + +describe('createModuleDefinitionFromCfnNamespace', () => { + + test('base case', () => { + const module = createModuleDefinitionFromCfnNamespace('AWS::EC2'); + + expect(module).toEqual({ + namespace: 'AWS::EC2', + moduleName: 'aws-ec2', + moduleFamily: 'AWS', + moduleBaseName: 'EC2', + packageName: '@aws-cdk/aws-ec2', + dotnetPackage: 'Amazon.CDK.AWS.EC2', + javaGroupId: 'software.amazon.awscdk', + javaPackage: 'services.ec2', + javaArtifactId: 'ec2', + pythonDistName: 'aws-cdk.aws-ec2', + pythonModuleName: 'aws_cdk.aws_ec2', + }); + }); + + test('Serverless is special-cased to SAM', () => { + const module = createModuleDefinitionFromCfnNamespace('AWS::Serverless'); + + expect(module).toEqual({ + namespace: 'AWS::Serverless', + moduleName: 'aws-sam', + moduleFamily: 'AWS', + moduleBaseName: 'SAM', + packageName: '@aws-cdk/aws-sam', + dotnetPackage: 'Amazon.CDK.AWS.SAM', + javaGroupId: 'software.amazon.awscdk', + javaPackage: 'services.sam', + javaArtifactId: 'sam', + pythonDistName: 'aws-cdk.aws-sam', + pythonModuleName: 'aws_cdk.aws_sam', + }); + }); + + test('Java artifacts use different package/artifact when module family is not AWS', () => { + const module = createModuleDefinitionFromCfnNamespace('Alexa::ASK'); + + expect(module).toEqual({ + namespace: 'Alexa::ASK', + moduleName: 'alexa-ask', + moduleFamily: 'Alexa', + moduleBaseName: 'ASK', + packageName: '@aws-cdk/alexa-ask', + dotnetPackage: 'Amazon.CDK.Alexa.ASK', + javaGroupId: 'software.amazon.awscdk', + javaPackage: 'alexa.ask', + javaArtifactId: 'alexa-ask', + pythonDistName: 'aws-cdk.alexa-ask', + pythonModuleName: 'aws_cdk.alexa_ask', + }); + }); + +}); diff --git a/packages/@aws-cdk/cfnspec/test/namespaces.test.ts b/packages/@aws-cdk/cfnspec/test/namespaces.test.ts new file mode 100644 index 0000000000000..860fd5ed15db9 --- /dev/null +++ b/packages/@aws-cdk/cfnspec/test/namespaces.test.ts @@ -0,0 +1,5 @@ +import { namespaces } from '../lib/index'; + +test('namespaces() includes some namespaces', () => { + expect(namespaces().length).toBeGreaterThan(10); +}); diff --git a/packages/@aws-cdk/cfnspec/test/scrutiny.test.ts b/packages/@aws-cdk/cfnspec/test/scrutiny.test.ts new file mode 100644 index 0000000000000..8343f0bdf1116 --- /dev/null +++ b/packages/@aws-cdk/cfnspec/test/scrutiny.test.ts @@ -0,0 +1,52 @@ +import { propertySpecification, resourceSpecification } from '../lib'; +import { PropertyScrutinyType, ResourceScrutinyType } from '../lib/schema'; + +test('spot-check IAM identity tags', () => { + const prop = propertySpecification('AWS::IAM::Role', 'Policies'); + expect(prop.ScrutinyType).toEqual(PropertyScrutinyType.InlineIdentityPolicies); +}); + +test('IAM AssumeRolePolicy', () => { + // AssumeRolePolicyDocument is a resource policy, because it applies to the Role itself! + const prop = propertySpecification('AWS::IAM::Role', 'AssumeRolePolicyDocument'); + expect(prop.ScrutinyType).toEqual(PropertyScrutinyType.InlineResourcePolicy); +}); + +test('spot-check IAM resource tags', () => { + const prop = propertySpecification('AWS::KMS::Key', 'KeyPolicy'); + expect(prop.ScrutinyType).toEqual(PropertyScrutinyType.InlineResourcePolicy); +}); + +test('spot-check resource policy resources', () => { + expect(resourceSpecification('AWS::S3::BucketPolicy').ScrutinyType).toEqual(ResourceScrutinyType.ResourcePolicyResource); +}); + +test('spot-check no misclassified tags', () => { + const prop = propertySpecification('AWS::SNS::Subscription', 'DeliveryPolicy'); + expect(prop.ScrutinyType).toEqual(PropertyScrutinyType.None); +}); + +test('check Lambda permission resource scrutiny', () => { + expect(resourceSpecification('AWS::Lambda::Permission').ScrutinyType).toEqual(ResourceScrutinyType.LambdaPermission); +}); + +test('check role managedpolicyarns', () => { + const prop = propertySpecification('AWS::IAM::Role', 'ManagedPolicyArns'); + expect(prop.ScrutinyType).toEqual(PropertyScrutinyType.ManagedPolicies); +}); + +test('check securityGroup scrutinies', () => { + const inProp = propertySpecification('AWS::EC2::SecurityGroup', 'SecurityGroupIngress'); + expect(inProp.ScrutinyType).toEqual(PropertyScrutinyType.IngressRules); + + const eProp = propertySpecification('AWS::EC2::SecurityGroup', 'SecurityGroupEgress'); + expect(eProp.ScrutinyType).toEqual(PropertyScrutinyType.EgressRules); +}); + +test('check securityGroupRule scrutinies', () => { + const inRes = resourceSpecification('AWS::EC2::SecurityGroupIngress'); + expect(inRes.ScrutinyType).toEqual(ResourceScrutinyType.IngressRuleResource); + + const eRes = resourceSpecification('AWS::EC2::SecurityGroupEgress'); + expect(eRes.ScrutinyType).toEqual(ResourceScrutinyType.EgressRuleResource); +}); \ No newline at end of file diff --git a/packages/@aws-cdk/cfnspec/test/spec-validators.ts b/packages/@aws-cdk/cfnspec/test/spec-validators.ts index c09fb7dc0e27f..c8993885332fb 100644 --- a/packages/@aws-cdk/cfnspec/test/spec-validators.ts +++ b/packages/@aws-cdk/cfnspec/test/spec-validators.ts @@ -1,154 +1,161 @@ -import { Test } from 'nodeunit'; +/* eslint-disable jest/no-export */ import * as schema from '../lib/schema'; -export function validateSpecification(test: Test, specification: schema.Specification) { - validateResourceTypes(test, specification); - validatePropertyTypes(test, specification); +export function validateSpecification(specification: schema.Specification) { + validateResourceTypes(specification); + validatePropertyTypes(specification); } -function validateResourceTypes(test: Test, specification: schema.Specification) { +function validateResourceTypes(specification: schema.Specification) { for (const typeName of Object.keys(specification.ResourceTypes)) { - test.ok(typeName, 'Resource type name is not empty'); - const type = specification.ResourceTypes[typeName]; - test.notEqual(type.Documentation, null, `${typeName} is documented`); - if (type.ScrutinyType) { - test.ok(schema.isResourceScrutinyType(type.ScrutinyType), `${typeName}.ScrutinyType is not a valid ResourceScrutinyType`); - } - if (type.Properties) { validateProperties(typeName, test, type.Properties, specification); } - if (type.Attributes) { validateAttributes(typeName, test, type.Attributes, specification); } + describe(typeName, () => { + expect(typeName).toBeTruthy(); + const type = specification.ResourceTypes[typeName]; + expect(type.Documentation).not.toBeNull(); + if (type.ScrutinyType) { + expect(schema.isResourceScrutinyType(type.ScrutinyType)).toBeTruthy(); + } + if (type.Properties) { validateProperties(typeName, type.Properties, specification); } + if (type.Attributes) { validateAttributes(typeName, type.Attributes, specification); } + }); } } -function validatePropertyTypes(test: Test, specification: schema.Specification) { +function validatePropertyTypes(specification: schema.Specification) { for (const typeName of Object.keys(specification.PropertyTypes)) { - test.ok(typeName, 'Property type name is not empty'); - const type = specification.PropertyTypes[typeName]; - if (schema.isRecordType(type)) { - validateProperties(typeName, test, type.Properties, specification); - } else { - validateProperties(typeName, test, { '': type }, specification); - } + describe(`PropertyType ${typeName}`, () => { + expect(typeName).toBeTruthy(); + const type = specification.PropertyTypes[typeName]; + if (schema.isRecordType(type)) { + validateProperties(typeName, type.Properties, specification); + } else { + validateProperties(typeName, { '': type }, specification); + } + }); } } function validateProperties( typeName: string, - test: Test, properties: { [name: string]: schema.Property }, specification: schema.Specification) { const expectedKeys = ['Documentation', 'Required', 'UpdateType', 'ScrutinyType']; for (const name of Object.keys(properties)) { - const property = properties[name]; - test.notEqual(property.Documentation, '', `${typeName}.Properties.${name} is documented`); - test.ok(!property.UpdateType || schema.isUpdateType(property.UpdateType), `${typeName}.Properties.${name} has valid UpdateType`); - if (property.ScrutinyType !== undefined) { - test.ok(schema.isPropertyScrutinyType(property.ScrutinyType), `${typeName}.Properties.${name} has valid ScrutinyType`); - } + test(`Property ${name}`, () => { + const property = properties[name]; + expect(property.Documentation).not.toEqual(''); + expect(!property.UpdateType || schema.isUpdateType(property.UpdateType)).toBeTruthy(); + if (property.ScrutinyType !== undefined) { + expect(schema.isPropertyScrutinyType(property.ScrutinyType)).toBeTruthy(); + } - if (schema.isPrimitiveProperty(property)) { - test.ok(schema.isPrimitiveType(property.PrimitiveType), `${typeName}.Properties.${name} has a valid PrimitiveType`); - expectedKeys.push('PrimitiveType'); + if (schema.isPrimitiveProperty(property)) { + expect(schema.isPrimitiveType(property.PrimitiveType)).toBeTruthy(); + expectedKeys.push('PrimitiveType'); - } else if (schema.isPrimitiveListProperty(property)) { - expectedKeys.push('Type', 'DuplicatesAllowed', 'PrimitiveItemType'); - test.ok(schema.isPrimitiveType(property.PrimitiveItemType), `${typeName}.Properties.${name} has a valid PrimitiveItemType`); + } else if (schema.isPrimitiveListProperty(property)) { + expectedKeys.push('Type', 'DuplicatesAllowed', 'PrimitiveItemType'); + expect(schema.isPrimitiveType(property.PrimitiveItemType)).toBeTruthy(); - } else if (schema.isPrimitiveMapProperty(property)) { - expectedKeys.push('Type', 'DuplicatesAllowed', 'PrimitiveItemType', 'Type'); - test.ok(schema.isPrimitiveType(property.PrimitiveItemType), `${typeName}.Properties.${name} has a valid PrimitiveItemType`); - test.ok(!property.DuplicatesAllowed, `${typeName}.Properties.${name} does not allow duplicates`); + } else if (schema.isPrimitiveMapProperty(property)) { + expectedKeys.push('Type', 'DuplicatesAllowed', 'PrimitiveItemType', 'Type'); + expect(schema.isPrimitiveType(property.PrimitiveItemType)).toBeTruthy(); + expect(property.DuplicatesAllowed).toBeFalsy(); - } else if (schema.isComplexListProperty(property)) { - expectedKeys.push('Type', 'DuplicatesAllowed', 'ItemType', 'Type'); - test.ok(property.ItemType, `${typeName}.Properties.${name} has a valid ItemType`); - if (property.ItemType !== 'Tag') { + } else if (schema.isComplexListProperty(property)) { + expectedKeys.push('Type', 'DuplicatesAllowed', 'ItemType', 'Type'); + expect(property.ItemType).toBeTruthy(); + if (property.ItemType !== 'Tag') { + const fqn = `${typeName.split('.')[0]}.${property.ItemType}`; + const resolvedType = specification.PropertyTypes && specification.PropertyTypes[fqn]; + expect(resolvedType).toBeTruthy(); + } + + } else if (schema.isMapOfStructsProperty(property)) { + expectedKeys.push('Type', 'DuplicatesAllowed', 'ItemType', 'Type'); + expect(property.ItemType).toBeTruthy(); const fqn = `${typeName.split('.')[0]}.${property.ItemType}`; const resolvedType = specification.PropertyTypes && specification.PropertyTypes[fqn]; - test.ok(resolvedType, `${typeName}.Properties.${name} ItemType (${fqn}) resolves`); - } - - } else if (schema.isMapOfStructsProperty(property)) { - expectedKeys.push('Type', 'DuplicatesAllowed', 'ItemType', 'Type'); - test.ok(property.ItemType, `${typeName}.Properties.${name} has a valid ItemType`); - const fqn = `${typeName.split('.')[0]}.${property.ItemType}`; - const resolvedType = specification.PropertyTypes && specification.PropertyTypes[fqn]; - test.ok(resolvedType, `${typeName}.Properties.${name} ItemType (${fqn}) resolves`); - test.ok(!property.DuplicatesAllowed, `${typeName}.Properties.${name} does not allow duplicates`); - - } else if (schema.isMapOfListsOfPrimitivesProperty(property)) { - expectedKeys.push('Type', 'DuplicatesAllowed', 'ItemType', 'PrimitiveItemItemType', 'Type'); - test.ok(schema.isPrimitiveType(property.PrimitiveItemItemType), `${typeName}.Properties.${name} has a valid PrimitiveItemItemType`); - test.ok(!property.DuplicatesAllowed, `${typeName}.Properties.${name} does not allow duplicates`); - - } else if (schema.isComplexProperty(property)) { - expectedKeys.push('Type'); - test.ok(property.Type, `${typeName}.Properties.${name} has a valid type`); - const fqn = `${typeName.split('.')[0]}.${property.Type}`; - const resolvedType = specification.PropertyTypes && specification.PropertyTypes[fqn]; - test.ok(resolvedType, `${typeName}.Properties.${name} type (${fqn}) resolves`); - - } else if (schema.isUnionProperty(property)) { - expectedKeys.push('PrimitiveTypes', 'PrimitiveItemTypes', 'ItemTypes', 'Types'); - if (property.PrimitiveTypes) { - for (const type of property.PrimitiveTypes) { - test.ok(schema.isPrimitiveType(type), `${typeName}.Properties.${name} has only valid PrimitiveTypes`); + expect(resolvedType).toBeTruthy(); + expect(property.DuplicatesAllowed).toBeFalsy(); + + } else if (schema.isMapOfListsOfPrimitivesProperty(property)) { + expectedKeys.push('Type', 'DuplicatesAllowed', 'ItemType', 'PrimitiveItemItemType', 'Type'); + expect(schema.isPrimitiveType(property.PrimitiveItemItemType)).toBeTruthy(); + expect(property.DuplicatesAllowed).toBeFalsy(); + + } else if (schema.isComplexProperty(property)) { + expectedKeys.push('Type'); + expect(property.Type).toBeTruthy(); + const fqn = `${typeName.split('.')[0]}.${property.Type}`; + const resolvedType = specification.PropertyTypes && specification.PropertyTypes[fqn]; + expect(resolvedType).toBeTruthy(); + + } else if (schema.isUnionProperty(property)) { + expectedKeys.push('PrimitiveTypes', 'PrimitiveItemTypes', 'ItemTypes', 'Types'); + if (property.PrimitiveTypes) { + for (const type of property.PrimitiveTypes) { + expect(schema.isPrimitiveType(type)).toBeTruthy(); + } } - } - if (property.ItemTypes) { - for (const type of property.ItemTypes) { - const fqn = `${typeName.split('.')[0]}.${type}`; - const resolvedType = specification.PropertyTypes && specification.PropertyTypes[fqn]; - test.ok(resolvedType, `${typeName}.Properties.${name} type (${fqn}) resolves`); + if (property.ItemTypes) { + for (const type of property.ItemTypes) { + const fqn = `${typeName.split('.')[0]}.${type}`; + const resolvedType = specification.PropertyTypes && specification.PropertyTypes[fqn]; + expect(resolvedType).toBeTruthy(); + } } - } - if (property.Types) { - for (const type of property.Types) { - const fqn = `${typeName.split('.')[0]}.${type}`; - const resolvedType = specification.PropertyTypes && specification.PropertyTypes[fqn]; - test.ok(resolvedType, `${typeName}.Properties.${name} type (${fqn}) resolves`); + if (property.Types) { + for (const type of property.Types) { + const fqn = `${typeName.split('.')[0]}.${type}`; + const resolvedType = specification.PropertyTypes && specification.PropertyTypes[fqn]; + expect(resolvedType).toBeTruthy(); + } } - } - } else { - test.ok(false, `${typeName}.Properties.${name} has known type`); - } + } else { + // eslint-disable-next-line no-console + console.error(`${typeName}.Properties.${name} does not declare a type.` + + `Property definition is: ${JSON.stringify(property, undefined, 2)}`); + expect(false).toBeTruthy(); + } - test.deepEqual( - without(Object.keys(property), expectedKeys), [], - `${typeName}.Properties.${name} has no extra properties`); + expect(without(Object.keys(property), expectedKeys)).toEqual([]); + }); } } function validateAttributes( typeName: string, - test: Test, attributes: { [name: string]: schema.Attribute }, specification: schema.Specification) { for (const name of Object.keys(attributes)) { - const attribute = attributes[name]; - test.ok(('Type' in attribute) !== ('PrimitiveType' in attribute), 'One of, and only one of, Type or PrimitiveType must be present'); - if (schema.isPrimitiveAttribute(attribute)) { - test.ok(!schema.isListAttribute(attribute), `${typeName}.Attributes.${name} is only a Primitive type`); - test.ok(schema.isPrimitiveType(attribute.PrimitiveType), `${typeName}.Attributes.${name} has a valid PrimitiveType`); - test.ok(!('PrimitiveItemType' in attribute), `${typeName}.Attributes.${name} has no PrimitiveItemType`); - test.ok(!('ItemType' in attribute), `${typeName}.Attributes.${name} has no ItemType`); - } else if (schema.isPrimitiveListAttribute(attribute)) { - test.ok(!schema.isComplexListAttribute(attribute), `${typeName}.Attributes.${name} is only a List type`); - test.ok(schema.isPrimitiveType(attribute.PrimitiveItemType), `${typeName}.Attributes.${name} has a valid PrimitiveItemType`); - test.ok(!('ItemType' in attribute), `${typeName}.Attributes.${name} has no ItemType`); - } else if (schema.isComplexListAttribute(attribute)) { - test.ok(attribute.ItemType, `${typeName}.Attributes.${name} is a valid List type`); - const fqn = `${typeName.split('.')[0]}.${attribute.ItemType}`; - const resolvedType = specification.PropertyTypes && specification.PropertyTypes[fqn]; - test.ok(resolvedType, `${typeName}.Attributes.${name} ItemType (${fqn}) resolves`); - test.ok(!('PrimitiveItemType' in attribute), `${typeName}.Attributes.${name} has no PrimitiveItemType`); - } else if (schema.isPrimitiveMapAttribute(attribute)) { - test.ok(schema.isPrimitiveType(attribute.PrimitiveItemType), `${typeName}.Attributes.${name} has a valid PrimitiveItemType`); - test.ok(!('ItemType' in attribute), `${typeName}.Attributes.${name} has no ItemType`); - } else { - test.ok(false, `${typeName}.Attributes.${name} has a valid type`); - } + test(`Attribute ${name}`, () => { + const attribute = attributes[name]; + expect(('Type' in attribute)).not.toEqual(('PrimitiveType' in attribute)); + if (schema.isPrimitiveAttribute(attribute)) { + expect(schema.isListAttribute(attribute)).toBeFalsy(); + expect(schema.isPrimitiveType(attribute.PrimitiveType)).toBeTruthy(); + expect(('PrimitiveItemType' in attribute)).toBeFalsy(); + expect(('ItemType' in attribute)).toBeFalsy(); + } else if (schema.isPrimitiveListAttribute(attribute)) { + expect(schema.isComplexListAttribute(attribute)).toBeFalsy(); + expect(schema.isPrimitiveType(attribute.PrimitiveItemType)).toBeTruthy(); + expect(('ItemType' in attribute)).toBeFalsy(); + } else if (schema.isComplexListAttribute(attribute)) { + expect(attribute.ItemType).toBeTruthy(); + const fqn = `${typeName.split('.')[0]}.${attribute.ItemType}`; + const resolvedType = specification.PropertyTypes && specification.PropertyTypes[fqn]; + expect(resolvedType).toBeTruthy(); + expect(('PrimitiveItemType' in attribute)).toBeFalsy(); + } else if (schema.isPrimitiveMapAttribute(attribute)) { + expect(schema.isPrimitiveType(attribute.PrimitiveItemType)).toBeTruthy(); + expect(('ItemType' in attribute)).toBeFalsy(); + } else { + expect(false).toBeTruthy(); // `${typeName}.Attributes.${name} has a valid type`); + } + }); } } diff --git a/packages/@aws-cdk/cfnspec/test/test.augmentation.ts b/packages/@aws-cdk/cfnspec/test/test.augmentation.ts deleted file mode 100644 index 34222c197d867..0000000000000 --- a/packages/@aws-cdk/cfnspec/test/test.augmentation.ts +++ /dev/null @@ -1,29 +0,0 @@ -import * as fs from 'fs'; -import * as path from 'path'; -import { Test } from 'nodeunit'; -import * as cfnspec from '../lib'; -import { MetricType } from '../lib/schema'; - -function resourceAugmentationTest(resource: string) { - return (test: Test) => { - const model = cfnspec.resourceAugmentation(resource); - - if (model.metrics) { - test.ok(typeof(model.metrics.namespace) === 'string', `namespace is invalid: ${model.metrics.namespace}`); - test.ok(typeof(model.metrics.dimensions) === 'object', `dimensions is invalid: ${model.metrics.dimensions}`); - for (const metric of model.metrics.metrics) { - test.ok(typeof metric.name === 'string', `name is invalid: ${metric.name}`); - test.ok(typeof metric.documentation === 'string', `documentation is invalid: ${metric.documentation}`); - test.ok(metric.type === undefined || [MetricType.Attrib, MetricType.Count, MetricType.Gauge].includes(metric.type), - `Metric Type is invalid: ${metric.type}`); - } - } - test.done(); - }; -} - -const files = fs.readdirSync(path.resolve(__dirname, '../lib/augmentations')); -for (const file of files) { - const resource = file.replace(/\.json$/, '').replace(/_/g, '::'); - exports[`Validate augmentation schema for ${resource}`] = resourceAugmentationTest(resource); -} diff --git a/packages/@aws-cdk/cfnspec/test/test.build.ts b/packages/@aws-cdk/cfnspec/test/test.build.ts deleted file mode 100644 index b0638fe3de2a4..0000000000000 --- a/packages/@aws-cdk/cfnspec/test/test.build.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { Test } from 'nodeunit'; -import { massageSpec } from '../build-tools/massage-spec'; -import { schema } from '../lib'; - -export = { - 'dropTypelessAttributes works correctly'(test: Test) { - const spec: schema.Specification = { - Fingerprint: 'some-fingerprint', - PropertyTypes: { - 'CDK::Test::Property': { - Properties: { - Type: ({ - PrimitiveType: 'String', - } as schema.ScalarProperty), // ts is being weird and doesn't correctly match the type - }, - }, - }, - ResourceTypes: { - 'CDK::Test::Resource': { - Attributes: { - Attribute1: ({ - PrimitiveType: 'String', - } as schema.PrimitiveAttribute), // ts is being weird and doesn't correctly match the type - Attribute2: ({} as schema.PrimitiveAttribute), - }, - Documentation: 'https://documentation-url/cdk/test/resource', - Properties: { - ResourceArn: ({ - PrimitiveType: 'String', - } as schema.PrimitiveProperty), // ts is being weird and doesn't correctly match the type - }, - }, - }, - }; - - massageSpec(spec); - - test.deepEqual(spec, { - Fingerprint: 'some-fingerprint', - PropertyTypes: { - 'CDK::Test::Property': { - Properties: { - Type: ({ - PrimitiveType: 'String', - } as schema.ScalarProperty), // ts is being weird and doesn't correctly match the type - }, - }, - }, - ResourceTypes: { - 'CDK::Test::Resource': { - Attributes: { - Attribute1: ({ - PrimitiveType: 'String', - }), - }, - Documentation: 'https://documentation-url/cdk/test/resource', - Properties: { - ResourceArn: { - PrimitiveType: 'String', - }, - }, - }, - }, - }); - - test.done(); - }, -}; diff --git a/packages/@aws-cdk/cfnspec/test/test.canned-metrics.ts b/packages/@aws-cdk/cfnspec/test/test.canned-metrics.ts deleted file mode 100644 index ff14500769c8d..0000000000000 --- a/packages/@aws-cdk/cfnspec/test/test.canned-metrics.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { Test } from 'nodeunit'; -import * as cfnspec from '../lib'; - -module.exports = { - 'spot-check DynamoDB metrics'(test: Test) { - const metrics = cfnspec.cannedMetricsForService('AWS::DynamoDB'); - test.ok(metrics.length > 0); - - const resLatency = metrics.find(m => m.metricName === 'SuccessfulRequestLatency'); - test.ok(resLatency); - - test.deepEqual(resLatency?.dimensions, [['Operation', 'TableName']]); - - test.done(); - }, - - 'spot-check MediaStore metrics'(test: Test) { - const metrics = cfnspec.cannedMetricsForService('AWS::MediaStore'); - test.ok(metrics.length > 0); - - test.done(); - }, -}; - -/** - * Test that we can read canned metrics for all namespaces in the spec without throwing an error - */ -for (const _namespace of cfnspec.namespaces()) { - const namespace = _namespace; - module.exports[`Validate canned metrics for ${namespace}`] = (test: Test) => { - const metrics = cfnspec.cannedMetricsForService(namespace); - - // Check that there are no duplicates in these list (duplicates may occur because of duplicate - // dimensions, but those have readly been combined). - const uniqueMetricNames = new Set(metrics.map(m => `${m.namespace}/${m.metricName}`)); - test.equal(uniqueMetricNames.size, metrics.length, 'There are metrics with duplicate names'); - - test.done(); - }; -} \ No newline at end of file diff --git a/packages/@aws-cdk/cfnspec/test/test.cfnlint-annotations.ts b/packages/@aws-cdk/cfnspec/test/test.cfnlint-annotations.ts deleted file mode 100644 index 04e0972893d12..0000000000000 --- a/packages/@aws-cdk/cfnspec/test/test.cfnlint-annotations.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { Test } from 'nodeunit'; -import * as cfnspec from '../lib'; - -module.exports = { - 'spot-check Bucket statefulness'(test: Test) { - const anno = cfnspec.cfnLintAnnotations('AWS::S3::Bucket'); - test.equal(anno.stateful, true); - test.equal(anno.mustBeEmptyToDelete, true); - - test.done(); - }, - - 'spot-check Table statefulness'(test: Test) { - const anno = cfnspec.cfnLintAnnotations('AWS::DynamoDB::Table'); - test.equal(anno.stateful, true); - test.equal(anno.mustBeEmptyToDelete, false); - - test.done(); - }, - - 'spot-check MediaStore metrics'(test: Test) { - const anno = cfnspec.cfnLintAnnotations('AWS::MediaStore::Thingy'); - test.equal(anno.stateful, false); - - test.done(); - }, -}; - diff --git a/packages/@aws-cdk/cfnspec/test/test.filtered-specification.ts b/packages/@aws-cdk/cfnspec/test/test.filtered-specification.ts deleted file mode 100644 index 90b56c3001ee6..0000000000000 --- a/packages/@aws-cdk/cfnspec/test/test.filtered-specification.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { Test, testCase } from 'nodeunit'; -import { filteredSpecification, resourceTypes, specification } from '../lib/index'; -import { validateSpecification } from './spec-validators'; - -const tests: any = { - 'filteredSpecification(/^AWS::S3::.*/)'(test: Test) { - const filteredSpec = filteredSpecification(/^AWS::S3::.*/); - test.notDeepEqual(filteredSpec, specification, 'The filteredSpecification result is not the whole specification'); - test.notDeepEqual(filteredSpec.ResourceTypes, {}, 'The filtered spec is not empty'); - test.done(); - }, - 'filteredSpecification(s => s.startsWith("AWS::S3::")'(test: Test) { - const filteredSpec = filteredSpecification(s => s.startsWith('AWS::S3::')); - test.notDeepEqual(filteredSpec, specification, 'The filteredSpecification result is not the whole specification'); - test.notDeepEqual(filteredSpec.ResourceTypes, {}, 'The filtered spec is not empty'); - test.done(); - }, -}; - -for (const name of resourceTypes().sort()) { - tests[`filteredSpecification(${JSON.stringify(name)})`] = (test: Test) => { - const filteredSpec = filteredSpecification(name); - test.notDeepEqual(filteredSpec, specification, 'The filteredSpecification result is not the whole specification'); - test.notDeepEqual(filteredSpec.ResourceTypes, {}, 'The filtered spec is not empty'); - // Validate the spec is conform & coherent. - validateSpecification(test, filteredSpec); - test.done(); - }; -} - -export = testCase(tests); diff --git a/packages/@aws-cdk/cfnspec/test/test.namespaces.ts b/packages/@aws-cdk/cfnspec/test/test.namespaces.ts deleted file mode 100644 index fea78b4520ce5..0000000000000 --- a/packages/@aws-cdk/cfnspec/test/test.namespaces.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Test, testCase } from 'nodeunit'; -import { namespaces } from '../lib/index'; - -export = testCase({ - 'namespaces() includes some namespaces'(test: Test) { - test.ok(namespaces().length > 10); - test.done(); - }, -}); diff --git a/packages/@aws-cdk/cfnspec/test/test.scrutiny.ts b/packages/@aws-cdk/cfnspec/test/test.scrutiny.ts deleted file mode 100644 index 8a90a6e21bd4d..0000000000000 --- a/packages/@aws-cdk/cfnspec/test/test.scrutiny.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { Test } from 'nodeunit'; -import { propertySpecification, resourceSpecification } from '../lib'; -import { PropertyScrutinyType, ResourceScrutinyType } from '../lib/schema'; - -export = { - 'spot-check IAM identity tags'(test: Test) { - const prop = propertySpecification('AWS::IAM::Role', 'Policies'); - test.equals(prop.ScrutinyType, PropertyScrutinyType.InlineIdentityPolicies); - - test.done(); - }, - - 'IAM AssumeRolePolicy'(test: Test) { - // AssumeRolePolicyDocument is a resource policy, because it applies to the Role itself! - const prop = propertySpecification('AWS::IAM::Role', 'AssumeRolePolicyDocument'); - test.equals(prop.ScrutinyType, PropertyScrutinyType.InlineResourcePolicy); - - test.done(); - }, - - 'spot-check IAM resource tags'(test: Test) { - const prop = propertySpecification('AWS::KMS::Key', 'KeyPolicy'); - test.equals(prop.ScrutinyType, PropertyScrutinyType.InlineResourcePolicy); - - test.done(); - }, - - 'spot-check resource policy resources'(test: Test) { - test.equals(resourceSpecification('AWS::S3::BucketPolicy').ScrutinyType, ResourceScrutinyType.ResourcePolicyResource); - - test.done(); - }, - - 'spot-check no misclassified tags'(test: Test) { - const prop = propertySpecification('AWS::SNS::Subscription', 'DeliveryPolicy'); - test.equals(prop.ScrutinyType, PropertyScrutinyType.None); - - test.done(); - }, - - 'check Lambda permission resource scrutiny'(test: Test) { - test.equals(resourceSpecification('AWS::Lambda::Permission').ScrutinyType, ResourceScrutinyType.LambdaPermission); - - test.done(); - }, - - 'check role managedpolicyarns'(test: Test) { - const prop = propertySpecification('AWS::IAM::Role', 'ManagedPolicyArns'); - test.equals(prop.ScrutinyType, PropertyScrutinyType.ManagedPolicies); - - test.done(); - }, - - 'check securityGroup scrutinies'(test: Test) { - const inProp = propertySpecification('AWS::EC2::SecurityGroup', 'SecurityGroupIngress'); - test.equals(inProp.ScrutinyType, PropertyScrutinyType.IngressRules); - - const eProp = propertySpecification('AWS::EC2::SecurityGroup', 'SecurityGroupEgress'); - test.equals(eProp.ScrutinyType, PropertyScrutinyType.EgressRules); - - test.done(); - }, - - 'check securityGroupRule scrutinies'(test: Test) { - const inRes = resourceSpecification('AWS::EC2::SecurityGroupIngress'); - test.equals(inRes.ScrutinyType, ResourceScrutinyType.IngressRuleResource); - - const eRes = resourceSpecification('AWS::EC2::SecurityGroupEgress'); - test.equals(eRes.ScrutinyType, ResourceScrutinyType.EgressRuleResource); - - test.done(); - }, -}; \ No newline at end of file diff --git a/packages/@aws-cdk/cloud-assembly-schema/.eslintrc.js b/packages/@aws-cdk/cloud-assembly-schema/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/cloud-assembly-schema/.eslintrc.js +++ b/packages/@aws-cdk/cloud-assembly-schema/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/cloud-assembly-schema/jest.config.js b/packages/@aws-cdk/cloud-assembly-schema/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/cloud-assembly-schema/jest.config.js +++ b/packages/@aws-cdk/cloud-assembly-schema/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/cloud-assembly-schema/package.json b/packages/@aws-cdk/cloud-assembly-schema/package.json index 98689e858a5f8..e6aee07a67f09 100644 --- a/packages/@aws-cdk/cloud-assembly-schema/package.json +++ b/packages/@aws-cdk/cloud-assembly-schema/package.json @@ -60,14 +60,14 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", "@types/mock-fs": "^4.13.1", - "@types/semver": "^7.3.7", - "cdk-build-tools": "0.0.0", + "@types/semver": "^7.3.8", "jest": "^26.6.3", "mock-fs": "^4.14.0", - "pkglint": "0.0.0", - "typescript-json-schema": "^0.50.1" + "typescript-json-schema": "^0.51.0" }, "repository": { "url": "https://github.com/aws/aws-cdk.git", @@ -98,9 +98,6 @@ "announce": false }, "maturity": "stable", - "cdk-build": { - "jest": true - }, "publishConfig": { "tag": "latest" } diff --git a/packages/@aws-cdk/cloudformation-diff/.eslintrc.js b/packages/@aws-cdk/cloudformation-diff/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/cloudformation-diff/.eslintrc.js +++ b/packages/@aws-cdk/cloudformation-diff/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/cloudformation-diff/jest.config.js b/packages/@aws-cdk/cloudformation-diff/jest.config.js index 2bf3bec36d750..e49f3262c4d91 100644 --- a/packages/@aws-cdk/cloudformation-diff/jest.config.js +++ b/packages/@aws-cdk/cloudformation-diff/jest.config.js @@ -1,4 +1,4 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = { ...baseConfig, coverageThreshold: { diff --git a/packages/@aws-cdk/cloudformation-diff/package.json b/packages/@aws-cdk/cloudformation-diff/package.json index 1fe5f51e907de..3a3ad220ff70f 100644 --- a/packages/@aws-cdk/cloudformation-diff/package.json +++ b/packages/@aws-cdk/cloudformation-diff/package.json @@ -28,16 +28,16 @@ "colors": "^1.4.0", "diff": "^5.0.0", "fast-deep-equal": "^3.1.3", - "string-width": "^4.2.2", - "table": "^6.7.1" + "string-width": "^4.2.3", + "table": "^6.7.2" }, "devDependencies": { + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", "@types/string-width": "^4.0.1", - "cdk-build-tools": "0.0.0", - "fast-check": "^2.17.0", + "fast-check": "^2.18.0", "jest": "^26.6.3", - "pkglint": "0.0.0", "ts-jest": "^26.5.6" }, "repository": { @@ -55,9 +55,6 @@ }, "stability": "stable", "maturity": "stable", - "cdk-build": { - "jest": true - }, "publishConfig": { "tag": "latest" } diff --git a/packages/@aws-cdk/cloudformation-include/.eslintrc.js b/packages/@aws-cdk/cloudformation-include/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/cloudformation-include/.eslintrc.js +++ b/packages/@aws-cdk/cloudformation-include/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/cloudformation-include/jest.config.js b/packages/@aws-cdk/cloudformation-include/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/cloudformation-include/jest.config.js +++ b/packages/@aws-cdk/cloudformation-include/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/cloudformation-include/package.json b/packages/@aws-cdk/cloudformation-include/package.json index b911414e71473..28e63ecaed94c 100644 --- a/packages/@aws-cdk/cloudformation-include/package.json +++ b/packages/@aws-cdk/cloudformation-include/package.json @@ -55,7 +55,6 @@ "pre": [ "node ./build.js" ], - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -83,6 +82,7 @@ "@aws-cdk/aws-apprunner": "0.0.0", "@aws-cdk/aws-appstream": "0.0.0", "@aws-cdk/aws-appsync": "0.0.0", + "@aws-cdk/aws-aps": "0.0.0", "@aws-cdk/aws-athena": "0.0.0", "@aws-cdk/aws-auditmanager": "0.0.0", "@aws-cdk/aws-autoscaling": "0.0.0", @@ -150,6 +150,7 @@ "@aws-cdk/aws-greengrassv2": "0.0.0", "@aws-cdk/aws-groundstation": "0.0.0", "@aws-cdk/aws-guardduty": "0.0.0", + "@aws-cdk/aws-healthlake": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-imagebuilder": "0.0.0", "@aws-cdk/aws-inspector": "0.0.0", @@ -171,6 +172,7 @@ "@aws-cdk/aws-lakeformation": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/aws-licensemanager": "0.0.0", + "@aws-cdk/aws-lightsail": "0.0.0", "@aws-cdk/aws-location": "0.0.0", "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-lookoutequipment": "0.0.0", @@ -183,6 +185,7 @@ "@aws-cdk/aws-medialive": "0.0.0", "@aws-cdk/aws-mediapackage": "0.0.0", "@aws-cdk/aws-mediastore": "0.0.0", + "@aws-cdk/aws-memorydb": "0.0.0", "@aws-cdk/aws-msk": "0.0.0", "@aws-cdk/aws-mwaa": "0.0.0", "@aws-cdk/aws-neptune": "0.0.0", @@ -254,6 +257,7 @@ "@aws-cdk/aws-apprunner": "0.0.0", "@aws-cdk/aws-appstream": "0.0.0", "@aws-cdk/aws-appsync": "0.0.0", + "@aws-cdk/aws-aps": "0.0.0", "@aws-cdk/aws-athena": "0.0.0", "@aws-cdk/aws-auditmanager": "0.0.0", "@aws-cdk/aws-autoscaling": "0.0.0", @@ -321,6 +325,7 @@ "@aws-cdk/aws-greengrassv2": "0.0.0", "@aws-cdk/aws-groundstation": "0.0.0", "@aws-cdk/aws-guardduty": "0.0.0", + "@aws-cdk/aws-healthlake": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-imagebuilder": "0.0.0", "@aws-cdk/aws-inspector": "0.0.0", @@ -342,6 +347,7 @@ "@aws-cdk/aws-lakeformation": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/aws-licensemanager": "0.0.0", + "@aws-cdk/aws-lightsail": "0.0.0", "@aws-cdk/aws-location": "0.0.0", "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-lookoutequipment": "0.0.0", @@ -354,6 +360,7 @@ "@aws-cdk/aws-medialive": "0.0.0", "@aws-cdk/aws-mediapackage": "0.0.0", "@aws-cdk/aws-mediastore": "0.0.0", + "@aws-cdk/aws-memorydb": "0.0.0", "@aws-cdk/aws-msk": "0.0.0", "@aws-cdk/aws-mwaa": "0.0.0", "@aws-cdk/aws-neptune": "0.0.0", @@ -408,13 +415,13 @@ "constructs": "^3.3.69" }, "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", "jest": "^26.6.3", - "pkglint": "0.0.0", - "ts-jest": "^26.5.6", - "@aws-cdk/assert-internal": "0.0.0" + "ts-jest": "^26.5.6" }, "bundledDependencies": [ "yaml" diff --git a/packages/@aws-cdk/core/.eslintrc.js b/packages/@aws-cdk/core/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/core/.eslintrc.js +++ b/packages/@aws-cdk/core/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/core/jest.config.js b/packages/@aws-cdk/core/jest.config.js index 9dd30a713dd6b..93246ea5102e5 100644 --- a/packages/@aws-cdk/core/jest.config.js +++ b/packages/@aws-cdk/core/jest.config.js @@ -1,4 +1,4 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = { ...baseConfig, coverageThreshold: { diff --git a/packages/@aws-cdk/core/lib/cfn-resource.ts b/packages/@aws-cdk/core/lib/cfn-resource.ts index d6be50b9149fb..f1b4d76a10563 100644 --- a/packages/@aws-cdk/core/lib/cfn-resource.ts +++ b/packages/@aws-cdk/core/lib/cfn-resource.ts @@ -101,6 +101,14 @@ export class CfnResource extends CfnRefElement { /** * Sets the deletion policy of the resource based on the removal policy specified. + * + * The Removal Policy controls what happens to this resource when it stops + * being managed by CloudFormation, either because you've removed it from the + * CDK application or because you've made a change that requires the resource + * to be replaced. + * + * The resource can be deleted (`RemovalPolicy.DESTROY`), or left in your AWS + * account for data recovery and cleanup later (`RemovalPolicy.RETAIN`). */ public applyRemovalPolicy(policy: RemovalPolicy | undefined, options: RemovalPolicyOptions = {}) { policy = policy || options.default || RemovalPolicy.RETAIN; diff --git a/packages/@aws-cdk/core/lib/fs/fingerprint.ts b/packages/@aws-cdk/core/lib/fs/fingerprint.ts index 4abfbe93c61bc..050240f821601 100644 --- a/packages/@aws-cdk/core/lib/fs/fingerprint.ts +++ b/packages/@aws-cdk/core/lib/fs/fingerprint.ts @@ -53,24 +53,26 @@ export function fingerprint(fileOrDirectory: string, options: FingerprintOptions return hash.digest('hex'); function _processFileOrDirectory(symbolicPath: string, isRootDir: boolean = false, realPath = symbolicPath) { - const relativePath = path.relative(fileOrDirectory, symbolicPath); - if (!isRootDir && ignoreStrategy.ignores(symbolicPath)) { return; } const stat = fs.lstatSync(realPath); + // Use relative path as hash component. Normalize it with forward slashes to ensure + // same hash on Windows and Linux. + const hashComponent = path.relative(fileOrDirectory, symbolicPath).replace(/\\/g, '/'); + if (stat.isSymbolicLink()) { const linkTarget = fs.readlinkSync(realPath); const resolvedLinkTarget = path.resolve(path.dirname(realPath), linkTarget); if (shouldFollow(follow, rootDirectory, resolvedLinkTarget)) { _processFileOrDirectory(symbolicPath, false, resolvedLinkTarget); } else { - _hashField(hash, `link:${relativePath}`, linkTarget); + _hashField(hash, `link:${hashComponent}`, linkTarget); } } else if (stat.isFile()) { - _hashField(hash, `file:${relativePath}`, contentFingerprint(realPath)); + _hashField(hash, `file:${hashComponent}`, contentFingerprint(realPath)); } else if (stat.isDirectory()) { for (const item of fs.readdirSync(realPath).sort()) { _processFileOrDirectory(path.join(symbolicPath, item), false, path.join(realPath, item)); diff --git a/packages/@aws-cdk/core/lib/resource.ts b/packages/@aws-cdk/core/lib/resource.ts index 65fcacd55bf25..c61e9ba69955e 100644 --- a/packages/@aws-cdk/core/lib/resource.ts +++ b/packages/@aws-cdk/core/lib/resource.ts @@ -203,7 +203,7 @@ export abstract class Resource extends CoreConstruct implements IResource { * CDK application or because you've made a change that requires the resource * to be replaced. * - * The resource can be deleted (`RemovalPolicy.DELETE`), or left in your AWS + * The resource can be deleted (`RemovalPolicy.DESTROY`), or left in your AWS * account for data recovery and cleanup later (`RemovalPolicy.RETAIN`). */ public applyRemovalPolicy(policy: RemovalPolicy) { diff --git a/packages/@aws-cdk/core/package.json b/packages/@aws-cdk/core/package.json index e8865fafd3dc2..f7cd653ca7e7f 100644 --- a/packages/@aws-cdk/core/package.json +++ b/packages/@aws-cdk/core/package.json @@ -141,7 +141,6 @@ "cdk-build": { "cloudformation": "AWS::CloudFormation", "cfn2ts-core-import": ".", - "jest": true, "pre": [ "rm -rf test/fs/fixtures", "cd test/fs", @@ -169,19 +168,19 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/aws-lambda": "^8.10.79", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/aws-lambda": "^8.10.84", "@types/fs-extra": "^8.1.2", "@types/jest": "^26.0.24", - "@types/lodash": "^4.14.171", + "@types/lodash": "^4.14.175", "@types/minimatch": "^3.0.5", "@types/node": "^10.17.60", "@types/sinon": "^9.0.11", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "fast-check": "^2.17.0", - "lodash": "^4.17.21", + "fast-check": "^2.18.0", "jest": "^26.6.3", - "pkglint": "0.0.0", + "lodash": "^4.17.21", "sinon": "^9.2.4", "ts-mock-imports": "^1.3.7" }, diff --git a/packages/@aws-cdk/core/test/fs/fs-fingerprint.test.ts b/packages/@aws-cdk/core/test/fs/fs-fingerprint.test.ts index 8187778de5453..f1d22f891a197 100644 --- a/packages/@aws-cdk/core/test/fs/fs-fingerprint.test.ts +++ b/packages/@aws-cdk/core/test/fs/fs-fingerprint.test.ts @@ -178,4 +178,22 @@ describe('fs fingerprint', () => { }); }); + + test('normalizes relative path', () => { + // Simulate a Windows path.relative() + const originalPathRelative = path.relative; + const pathRelativeSpy = jest.spyOn(path, 'relative').mockImplementation((from: string, to: string): string => { + return originalPathRelative(from, to).replace(/\//g, '\\'); + }); + + const hash1 = FileSystem.fingerprint(path.join(__dirname, 'fixtures', 'test1')); + + // Restore Linux behavior + pathRelativeSpy.mockRestore(); + + const hash2 = FileSystem.fingerprint(path.join(__dirname, 'fixtures', 'test1')); + + // Relative paths are normalized + expect(hash1).toEqual(hash2); + }); }); diff --git a/packages/@aws-cdk/core/test/stack.test.ts b/packages/@aws-cdk/core/test/stack.test.ts index 4473b99e0c2dc..7c67f545d4b87 100644 --- a/packages/@aws-cdk/core/test/stack.test.ts +++ b/packages/@aws-cdk/core/test/stack.test.ts @@ -1,5 +1,5 @@ import * as cxapi from '@aws-cdk/cx-api'; -import { testFutureBehavior, testLegacyBehavior } from 'cdk-build-tools/lib/feature-flag'; +import { testFutureBehavior, testLegacyBehavior } from '@aws-cdk/cdk-build-tools/lib/feature-flag'; import { App, CfnCondition, CfnInclude, CfnOutput, CfnParameter, CfnResource, Construct, Lazy, ScopedAws, Stack, validateString, diff --git a/packages/@aws-cdk/custom-resources/.eslintrc.js b/packages/@aws-cdk/custom-resources/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/custom-resources/.eslintrc.js +++ b/packages/@aws-cdk/custom-resources/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/custom-resources/README.md b/packages/@aws-cdk/custom-resources/README.md index ccf5765dea13e..8583e04bc087f 100644 --- a/packages/@aws-cdk/custom-resources/README.md +++ b/packages/@aws-cdk/custom-resources/README.md @@ -201,7 +201,7 @@ must return this name in `PhysicalResourceId` and make sure to handle replacement properly. The `S3File` example demonstrates this through the `objectKey` property. -### Handling Provider Framework Error +### When there are errors As mentioned above, if any of the user handlers fail (i.e. throws an exception) or times out (due to their AWS Lambda timing out), the framework will trap these @@ -225,6 +225,39 @@ lifecycle events: with the previous properties. * If a `Delete` event fails, CloudFormation will abandon this resource. +### Important cases to handle + +You should keep the following list in mind when writing custom resources to +make sure your custom resource behaves correctly in all cases: + +* During `Create`: + * If the create fails, the *provider framework* will make sure you + don't get a subsequent `Delete` event. If your create involves multiple distinct + operations, it is your responsibility to catch and rethrow and clean up + any partial updates that have already been performed. Make sure your + API call timeouts and Lambda timeouts allow for this. +* During `Update`: + * If the update fails, you will get a subsequent `Update` event + to roll back to the previous state (with `ResourceProperties` and + `OldResourceProperties` reversed). + * If you return a different `PhysicalResourceId`, you will subsequently + receive a `Delete` event to clean up the previous state of the resource. +* During `Delete`: + * If the behavior of your custom resource is tied to another AWS resource + (for example, it exists to clean the contents of a stateful resource), keep + in mind that your custom resource may be deleted independently of the other + resource and you must confirm that it is appropriate to perform the action. + * (only if you are *not* using the provider framework) a `Delete` event + may be caused by a failed `Create`. You must be able to handle the case + where the resource you are trying to delete hasn't even been created yet. +* If you update the code of your custom resource and change the format of the + resource properties, be aware that there may still be already-deployed + instances of your custom resource out there, and you may still receive + the *old* property format in `ResourceProperties` (during `Delete` and + rollback `Updates`) or in `OldResourceProperties` (during rollforward + `Update`). You must continue to handle all possible sets of properties + your custom resource could have ever been created with in the past. + ### Provider Framework Execution Policy Similarly to any AWS Lambda function, if the user-defined handlers require @@ -518,7 +551,7 @@ const getParameter = new AwsCustomResource(this, 'AssociateVPCWithHostedZone', { physicalResourceId: PhysicalResourceId.of('${vpcStack.SharedVpc.VpcId}-${vpcStack.Region}-${PrivateHostedZone.HostedZoneId}') }, //Will ignore any resource and use the assumedRoleArn as resource and 'sts:AssumeRole' for service:action - policy: AwsCustomResourcePolicy.fromSdkCalls({resources: AwsCustomResourcePolicy.ANY_RESOURCE}) + policy: AwsCustomResourcePolicy.fromSdkCalls({resources: AwsCustomResourcePolicy.ANY_RESOURCE}) }); ``` diff --git a/packages/@aws-cdk/custom-resources/jest.config.js b/packages/@aws-cdk/custom-resources/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/custom-resources/jest.config.js +++ b/packages/@aws-cdk/custom-resources/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/custom-resources/lib/provider-framework/provider.ts b/packages/@aws-cdk/custom-resources/lib/provider-framework/provider.ts index 8d99963627a4a..c2f7ef69c98bb 100644 --- a/packages/@aws-cdk/custom-resources/lib/provider-framework/provider.ts +++ b/packages/@aws-cdk/custom-resources/lib/provider-framework/provider.ts @@ -202,7 +202,7 @@ export class Provider extends CoreConstruct implements ICustomResourceProvider { const fn = new lambda.Function(this, `framework-${entrypoint}`, { code: lambda.Code.fromAsset(RUNTIME_HANDLER_PATH), description: `AWS CDK resource provider framework - ${entrypoint} (${this.node.path})`.slice(0, 256), - runtime: lambda.Runtime.NODEJS_14_X, + runtime: lambda.Runtime.NODEJS_12_X, handler: `framework.${entrypoint}`, timeout: FRAMEWORK_HANDLER_TIMEOUT, logRetention: this.logRetention, diff --git a/packages/@aws-cdk/custom-resources/package.json b/packages/@aws-cdk/custom-resources/package.json index d81b9a11edc0c..698596d6ae0c0 100644 --- a/packages/@aws-cdk/custom-resources/package.json +++ b/packages/@aws-cdk/custom-resources/package.json @@ -53,7 +53,6 @@ "build+test+extract": "yarn build+test && yarn rosetta:extract" }, "cdk-build": { - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,42 +72,42 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", + "@aws-cdk/assert-internal": "0.0.0", "@aws-cdk/aws-events": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/aws-ssm": "0.0.0", - "@types/aws-lambda": "^8.10.79", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/aws-lambda": "^8.10.84", "@types/fs-extra": "^8.1.2", + "@types/jest": "^26.0.24", "@types/sinon": "^9.0.11", "aws-sdk": "^2.848.0", - "aws-sdk-mock": "^5.2.1", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", + "aws-sdk-mock": "^5.4.0", "fs-extra": "^9.1.0", - "nock": "^13.1.1", - "pkglint": "0.0.0", - "sinon": "^9.2.4", - "@aws-cdk/assert-internal": "0.0.0" + "nock": "^13.1.3", + "sinon": "^9.2.4" }, "dependencies": { "@aws-cdk/aws-cloudformation": "0.0.0", + "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-sns": "0.0.0", - "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/core": "0.0.0", "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { "@aws-cdk/aws-cloudformation": "0.0.0", + "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-sns": "0.0.0", - "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/core": "0.0.0", "constructs": "^3.3.69" }, diff --git a/packages/@aws-cdk/custom-resources/test/provider-framework/integ.provider.expected.json b/packages/@aws-cdk/custom-resources/test/provider-framework/integ.provider.expected.json index b9a9edfe958cc..aa0407ca5b164 100644 --- a/packages/@aws-cdk/custom-resources/test/provider-framework/integ.provider.expected.json +++ b/packages/@aws-cdk/custom-resources/test/provider-framework/integ.provider.expected.json @@ -254,7 +254,7 @@ } }, "Handler": "framework.onEvent", - "Runtime": "nodejs14.x", + "Runtime": "nodejs12.x", "Timeout": 900 }, "DependsOn": [ @@ -643,7 +643,7 @@ } }, "Handler": "framework.onEvent", - "Runtime": "nodejs14.x", + "Runtime": "nodejs12.x", "Timeout": 900 }, "DependsOn": [ @@ -783,7 +783,7 @@ } }, "Handler": "framework.isComplete", - "Runtime": "nodejs14.x", + "Runtime": "nodejs12.x", "Timeout": 900 }, "DependsOn": [ @@ -923,7 +923,7 @@ } }, "Handler": "framework.onTimeout", - "Runtime": "nodejs14.x", + "Runtime": "nodejs12.x", "Timeout": 900 }, "DependsOn": [ diff --git a/packages/@aws-cdk/cx-api/.eslintrc.js b/packages/@aws-cdk/cx-api/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/cx-api/.eslintrc.js +++ b/packages/@aws-cdk/cx-api/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/cx-api/jest.config.js b/packages/@aws-cdk/cx-api/jest.config.js index 061fcef9a7451..095efaa522407 100644 --- a/packages/@aws-cdk/cx-api/jest.config.js +++ b/packages/@aws-cdk/cx-api/jest.config.js @@ -1,4 +1,4 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = { ...baseConfig, coverageThreshold: { diff --git a/packages/@aws-cdk/cx-api/package.json b/packages/@aws-cdk/cx-api/package.json index 8dd8ed3b24ff5..8d4293f2b5ee4 100644 --- a/packages/@aws-cdk/cx-api/package.json +++ b/packages/@aws-cdk/cx-api/package.json @@ -66,13 +66,13 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", "@types/mock-fs": "^4.13.1", - "@types/semver": "^7.3.7", - "cdk-build-tools": "0.0.0", + "@types/semver": "^7.3.8", "jest": "^26.6.3", - "mock-fs": "^4.14.0", - "pkglint": "0.0.0" + "mock-fs": "^4.14.0" }, "repository": { "url": "https://github.com/aws/aws-cdk.git", @@ -156,9 +156,6 @@ "awscdkio": { "announce": false }, - "cdk-build": { - "jest": true - }, "publishConfig": { "tag": "latest" } diff --git a/packages/@aws-cdk/cx-api/test/features.test.ts b/packages/@aws-cdk/cx-api/test/features.test.ts index 81b42773fd292..2aaa774b7b1c5 100644 --- a/packages/@aws-cdk/cx-api/test/features.test.ts +++ b/packages/@aws-cdk/cx-api/test/features.test.ts @@ -1,4 +1,4 @@ -import { testLegacyBehavior } from 'cdk-build-tools/lib/feature-flag'; +import { testLegacyBehavior } from '@aws-cdk/cdk-build-tools/lib/feature-flag'; import * as feats from '../lib/features'; test('all future flags have defaults configured', () => { @@ -9,4 +9,4 @@ test('all future flags have defaults configured', () => { testLegacyBehavior('FUTURE_FLAGS_EXPIRED must be empty in CDKv1', Object, () => { expect(feats.FUTURE_FLAGS_EXPIRED.length).toEqual(0); -}); \ No newline at end of file +}); diff --git a/packages/@aws-cdk/example-construct-library/.eslintrc.js b/packages/@aws-cdk/example-construct-library/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/example-construct-library/.eslintrc.js +++ b/packages/@aws-cdk/example-construct-library/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/example-construct-library/jest.config.js b/packages/@aws-cdk/example-construct-library/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/example-construct-library/jest.config.js +++ b/packages/@aws-cdk/example-construct-library/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/example-construct-library/package.json b/packages/@aws-cdk/example-construct-library/package.json index 7f66f7c22ee55..672ba0e4a50e2 100644 --- a/packages/@aws-cdk/example-construct-library/package.json +++ b/packages/@aws-cdk/example-construct-library/package.json @@ -67,11 +67,11 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-cloudwatch": "0.0.0", @@ -101,7 +101,6 @@ "announce": false }, "cdk-build": { - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } diff --git a/packages/@aws-cdk/example-construct-library/test/example-resource.test.ts b/packages/@aws-cdk/example-construct-library/test/example-resource.test.ts index 091c0c7d1f65a..db1e8d68d4830 100644 --- a/packages/@aws-cdk/example-construct-library/test/example-resource.test.ts +++ b/packages/@aws-cdk/example-construct-library/test/example-resource.test.ts @@ -56,7 +56,7 @@ describe('Example Resource', () => { 'Ref': 'ExampleResourceWaitConditionHandle9C53A8D3', }, // this is how you can check a given property is _not_ set - 'RandomProperty': Match.absentProperty(), + 'RandomProperty': Match.absent(), }); }); diff --git a/packages/@aws-cdk/lambda-layer-awscli/.eslintrc.js b/packages/@aws-cdk/lambda-layer-awscli/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/lambda-layer-awscli/.eslintrc.js +++ b/packages/@aws-cdk/lambda-layer-awscli/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/lambda-layer-awscli/jest.config.js b/packages/@aws-cdk/lambda-layer-awscli/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/lambda-layer-awscli/jest.config.js +++ b/packages/@aws-cdk/lambda-layer-awscli/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/lambda-layer-awscli/package.json b/packages/@aws-cdk/lambda-layer-awscli/package.json index 582ff94d18b4f..773e292d92020 100644 --- a/packages/@aws-cdk/lambda-layer-awscli/package.json +++ b/packages/@aws-cdk/lambda-layer-awscli/package.json @@ -66,12 +66,12 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-lambda": "0.0.0", @@ -96,7 +96,6 @@ "pre": [ "layer/build.sh" ], - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } diff --git a/packages/@aws-cdk/lambda-layer-kubectl/.eslintrc.js b/packages/@aws-cdk/lambda-layer-kubectl/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/lambda-layer-kubectl/.eslintrc.js +++ b/packages/@aws-cdk/lambda-layer-kubectl/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/lambda-layer-kubectl/jest.config.js b/packages/@aws-cdk/lambda-layer-kubectl/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/lambda-layer-kubectl/jest.config.js +++ b/packages/@aws-cdk/lambda-layer-kubectl/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/lambda-layer-kubectl/package.json b/packages/@aws-cdk/lambda-layer-kubectl/package.json index 514cc7071c299..11e287144b29f 100644 --- a/packages/@aws-cdk/lambda-layer-kubectl/package.json +++ b/packages/@aws-cdk/lambda-layer-kubectl/package.json @@ -66,12 +66,12 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "jest": "^26.6.3" }, "pkglint": { "attribution": [ @@ -102,7 +102,6 @@ "pre": [ "layer/build.sh" ], - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } diff --git a/packages/@aws-cdk/lambda-layer-node-proxy-agent/.eslintrc.js b/packages/@aws-cdk/lambda-layer-node-proxy-agent/.eslintrc.js new file mode 100644 index 0000000000000..2658ee8727166 --- /dev/null +++ b/packages/@aws-cdk/lambda-layer-node-proxy-agent/.eslintrc.js @@ -0,0 +1,3 @@ +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; +module.exports = baseConfig; diff --git a/packages/@aws-cdk/lambda-layer-node-proxy-agent/.gitignore b/packages/@aws-cdk/lambda-layer-node-proxy-agent/.gitignore new file mode 100644 index 0000000000000..a86aa21cbaad0 --- /dev/null +++ b/packages/@aws-cdk/lambda-layer-node-proxy-agent/.gitignore @@ -0,0 +1,20 @@ +*.js +*.js.map +*.d.ts +tsconfig.json +node_modules +*.generated.ts +dist +.jsii + +.LAST_BUILD +.nyc_output +coverage +nyc.config.js +.LAST_PACKAGE +*.snk +!.eslintrc.js +!jest.config.js + +junit.xml +lib/*.zip diff --git a/packages/@aws-cdk/lambda-layer-node-proxy-agent/.npmignore b/packages/@aws-cdk/lambda-layer-node-proxy-agent/.npmignore new file mode 100644 index 0000000000000..8934dbe25655a --- /dev/null +++ b/packages/@aws-cdk/lambda-layer-node-proxy-agent/.npmignore @@ -0,0 +1,32 @@ +# Don't include original .ts files when doing `npm pack` +*.ts +!*.d.ts +coverage +.nyc_output +*.tgz + +dist +.LAST_PACKAGE +.LAST_BUILD +!*.js + +# Include .jsii +!.jsii + +*.snk + +*.tsbuildinfo + +tsconfig.json +.eslintrc.js +jest.config.js + +# exclude cdk artifacts +**/cdk.out +junit.xml + +test/ + +!*.lit.ts + +layer/node_modules diff --git a/tools/eslint-plugin-cdk/LICENSE b/packages/@aws-cdk/lambda-layer-node-proxy-agent/LICENSE similarity index 100% rename from tools/eslint-plugin-cdk/LICENSE rename to packages/@aws-cdk/lambda-layer-node-proxy-agent/LICENSE diff --git a/tools/eslint-plugin-cdk/NOTICE b/packages/@aws-cdk/lambda-layer-node-proxy-agent/NOTICE similarity index 100% rename from tools/eslint-plugin-cdk/NOTICE rename to packages/@aws-cdk/lambda-layer-node-proxy-agent/NOTICE diff --git a/packages/@aws-cdk/lambda-layer-node-proxy-agent/README.md b/packages/@aws-cdk/lambda-layer-node-proxy-agent/README.md new file mode 100644 index 0000000000000..45187394cb8b2 --- /dev/null +++ b/packages/@aws-cdk/lambda-layer-node-proxy-agent/README.md @@ -0,0 +1,23 @@ +# AWS Lambda Layer with the NPM dependency proxy-agent + + +--- + +![cdk-constructs: Stable](https://img.shields.io/badge/cdk--constructs-stable-success.svg?style=for-the-badge) + +--- + + + +This module exports a single class called `NodeProxyAgentLayer` which is a `lambda.Layer` that bundles the NPM dependency [`proxy-agent`](https://www.npmjs.com/package/proxy-agent). + +> - proxy-agent Version: 5.0.0 + +Usage: + +```ts +const fn = new lambda.Function(...); +fn.addLayers(new NodeProxyAgentLayer(stack, 'NodeProxyAgentLayer')); +``` + +[`proxy-agent`](https://www.npmjs.com/package/proxy-agent) will be installed under `/opt/nodejs/node_modules`. diff --git a/packages/@aws-cdk/lambda-layer-node-proxy-agent/jest.config.js b/packages/@aws-cdk/lambda-layer-node-proxy-agent/jest.config.js new file mode 100644 index 0000000000000..3a2fd93a1228a --- /dev/null +++ b/packages/@aws-cdk/lambda-layer-node-proxy-agent/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/lambda-layer-node-proxy-agent/layer/.dockerignore b/packages/@aws-cdk/lambda-layer-node-proxy-agent/layer/.dockerignore new file mode 100644 index 0000000000000..69b73f61d249a --- /dev/null +++ b/packages/@aws-cdk/lambda-layer-node-proxy-agent/layer/.dockerignore @@ -0,0 +1,2 @@ +build.sh +.no-packagejson-validator diff --git a/tools/pkglint/lib/banners/l1.deprecated.md b/packages/@aws-cdk/lambda-layer-node-proxy-agent/layer/.no-packagejson-validator similarity index 100% rename from tools/pkglint/lib/banners/l1.deprecated.md rename to packages/@aws-cdk/lambda-layer-node-proxy-agent/layer/.no-packagejson-validator diff --git a/packages/@aws-cdk/lambda-layer-node-proxy-agent/layer/Dockerfile b/packages/@aws-cdk/lambda-layer-node-proxy-agent/layer/Dockerfile new file mode 100644 index 0000000000000..8c747a0e2b95f --- /dev/null +++ b/packages/@aws-cdk/lambda-layer-node-proxy-agent/layer/Dockerfile @@ -0,0 +1,33 @@ +# base lambda image +FROM public.ecr.aws/lambda/nodejs:latest + +USER root +RUN mkdir -p /opt +WORKDIR /tmp + +# +# tools +# + +RUN yum update -y \ + && yum install -y zip + +# +# install nodejs dependencies: proxy-agent +# + +RUN mkdir -p /opt/nodejs +COPY package.json /opt/nodejs +RUN cd /opt/nodejs && npm install + +# +# create the bundle +# + +RUN cd /opt \ + && zip --symlinks -r ../layer.zip * \ + && echo "/layer.zip is ready" \ + && ls -alh /layer.zip; + +WORKDIR / +ENTRYPOINT [ "/bin/bash" ] diff --git a/packages/@aws-cdk/lambda-layer-node-proxy-agent/layer/build.sh b/packages/@aws-cdk/lambda-layer-node-proxy-agent/layer/build.sh new file mode 100755 index 0000000000000..6a84896b9d991 --- /dev/null +++ b/packages/@aws-cdk/lambda-layer-node-proxy-agent/layer/build.sh @@ -0,0 +1,18 @@ +#!/bin/bash +set -euo pipefail + +cd $(dirname $0) + +echo ">> Building AWS Lambda layer inside a docker image..." + +TAG='aws-lambda-node-proxy-agent' + +docker build -t ${TAG} . + +echo ">> Extrating layer.zip from the build container..." +CONTAINER=$(docker run -d ${TAG} false) +docker cp ${CONTAINER}:/layer.zip ../lib/layer.zip + +echo ">> Stopping container..." +docker rm -f ${CONTAINER} +echo ">> lib/layer.zip is ready" diff --git a/packages/@aws-cdk/lambda-layer-node-proxy-agent/layer/package.json b/packages/@aws-cdk/lambda-layer-node-proxy-agent/layer/package.json new file mode 100644 index 0000000000000..102dd83c99391 --- /dev/null +++ b/packages/@aws-cdk/lambda-layer-node-proxy-agent/layer/package.json @@ -0,0 +1,9 @@ +{ + "name": "node-proxy-agent-layer", + "private": true, + "version": "0.0.1", + "license": "Apache-2.0", + "devDependencies": { + "proxy-agent": "^5.0.0" + } +} diff --git a/packages/@aws-cdk/lambda-layer-node-proxy-agent/lib/index.ts b/packages/@aws-cdk/lambda-layer-node-proxy-agent/lib/index.ts new file mode 100644 index 0000000000000..e18d71d317dce --- /dev/null +++ b/packages/@aws-cdk/lambda-layer-node-proxy-agent/lib/index.ts @@ -0,0 +1 @@ +export * from './node-proxy-agent-layer'; diff --git a/packages/@aws-cdk/lambda-layer-node-proxy-agent/lib/node-proxy-agent-layer.ts b/packages/@aws-cdk/lambda-layer-node-proxy-agent/lib/node-proxy-agent-layer.ts new file mode 100644 index 0000000000000..9e6471a2da2c6 --- /dev/null +++ b/packages/@aws-cdk/lambda-layer-node-proxy-agent/lib/node-proxy-agent-layer.ts @@ -0,0 +1,27 @@ +import * as crypto from 'crypto'; +import * as fs from 'fs'; +import * as path from 'path'; +import * as lambda from '@aws-cdk/aws-lambda'; +import { Construct } from 'constructs'; + +/** + * An AWS Lambda layer that includes the NPM dependency `proxy-agent`. + */ +export class NodeProxyAgentLayer extends lambda.LayerVersion { + constructor(scope: Construct, id: string) { + super(scope, id, { + code: lambda.Code.fromAsset(path.join(__dirname, 'layer.zip'), { + // we hash the package.json (it contains the tools versions) because hashing the zip is non-deterministic + assetHash: hashFile(path.join(__dirname, '..', 'layer', 'package.json')), + }), + description: '/opt/nodejs/node_modules/proxy-agent', + }); + } +} + +function hashFile(fileName: string) { + return crypto + .createHash('sha256') + .update(fs.readFileSync(fileName)) + .digest('hex'); +} diff --git a/packages/@aws-cdk/lambda-layer-node-proxy-agent/package.json b/packages/@aws-cdk/lambda-layer-node-proxy-agent/package.json new file mode 100644 index 0000000000000..46345afc7f796 --- /dev/null +++ b/packages/@aws-cdk/lambda-layer-node-proxy-agent/package.json @@ -0,0 +1,115 @@ +{ + "name": "@aws-cdk/lambda-layer-node-proxy-agent", + "private": false, + "version": "0.0.0", + "description": "An AWS Lambda layer that contains the `proxy-agent` NPM dependency", + "main": "lib/index.js", + "types": "lib/index.d.ts", + "jsii": { + "outdir": "dist", + "targets": { + "java": { + "package": "software.amazon.awscdk.lambda.layer.node.proxy.agent", + "maven": { + "groupId": "software.amazon.awscdk", + "artifactId": "cdk-lambda-layer-node-proxy-agent" + } + }, + "dotnet": { + "namespace": "Amazon.CDK.LambdaLayer.NodeProxyAgent", + "packageId": "Amazon.CDK.LambdaLayer.NodeProxyAgent", + "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png" + }, + "python": { + "distName": "aws-cdk.lambda-layer-node-proxy-agent", + "module": "aws_cdk.lambda_layer_node_proxy_agent", + "classifiers": [ + "Framework :: AWS CDK", + "Framework :: AWS CDK :: 1" + ] + } + }, + "projectReferences": true + }, + "repository": { + "type": "git", + "url": "https://github.com/aws/aws-cdk.git", + "directory": "packages/@aws-cdk/lambda-layer-node-proxy-agent" + }, + "scripts": { + "build": "cdk-build", + "watch": "cdk-watch", + "lint": "cdk-lint", + "test": "cdk-test", + "integ": "cdk-integ", + "pkglint": "pkglint -f", + "package": "cdk-package", + "awslint": "cdk-awslint", + "build+test": "yarn build && yarn test", + "build+test+package": "yarn build+test && yarn package", + "compat": "cdk-compat", + "rosetta:extract": "yarn --silent jsii-rosetta extract", + "build+extract": "yarn build && yarn rosetta:extract", + "build+test+extract": "yarn build+test && yarn rosetta:extract" + }, + "keywords": [ + "aws", + "cdk", + "example", + "construct", + "library" + ], + "author": { + "name": "Amazon Web Services", + "url": "https://aws.amazon.com", + "organization": true + }, + "license": "Apache-2.0", + "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24", + "jest": "^26.6.3" + }, + "dependencies": { + "@aws-cdk/aws-lambda": "0.0.0", + "@aws-cdk/core": "0.0.0", + "constructs": "^3.3.69" + }, + "homepage": "https://github.com/aws/aws-cdk", + "peerDependencies": { + "@aws-cdk/aws-lambda": "0.0.0", + "@aws-cdk/core": "0.0.0", + "constructs": "^3.3.69" + }, + "engines": { + "node": ">= 10.13.0 <13 || >=13.7.0" + }, + "stability": "stable", + "maturity": "stable", + "awscdkio": { + "announce": false + }, + "cdk-build": { + "pre": [ + "layer/build.sh" + ], + "env": { + "AWSLINT_BASE_CONSTRUCT": true + } + }, + "nozem": { + "ostools": [ + "dirname", + "docker" + ] + }, + "ubergen": { + "exclude": false + }, + "publishConfig": { + "tag": "latest" + } +} diff --git a/packages/@aws-cdk/lambda-layer-node-proxy-agent/test/proxy-agent-layer.test.ts b/packages/@aws-cdk/lambda-layer-node-proxy-agent/test/proxy-agent-layer.test.ts new file mode 100644 index 0000000000000..14264a8d080dc --- /dev/null +++ b/packages/@aws-cdk/lambda-layer-node-proxy-agent/test/proxy-agent-layer.test.ts @@ -0,0 +1,16 @@ +import { Stack } from '@aws-cdk/core'; +import { NodeProxyAgentLayer } from '../lib'; +import '@aws-cdk/assert-internal/jest'; + +test('synthesized to a layer version', () => { + //GIVEN + const stack = new Stack(); + + // WHEN + new NodeProxyAgentLayer(stack, 'MyLayer'); + + // THEN + expect(stack).toHaveResource('AWS::Lambda::LayerVersion', { + Description: '/opt/nodejs/node_modules/proxy-agent', + }); +}); diff --git a/packages/@aws-cdk/pipelines/.eslintrc.js b/packages/@aws-cdk/pipelines/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/pipelines/.eslintrc.js +++ b/packages/@aws-cdk/pipelines/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/pipelines/ORIGINAL_API.md b/packages/@aws-cdk/pipelines/ORIGINAL_API.md index 73ac108d9c67f..447e39bb09bc2 100644 --- a/packages/@aws-cdk/pipelines/ORIGINAL_API.md +++ b/packages/@aws-cdk/pipelines/ORIGINAL_API.md @@ -41,7 +41,9 @@ all commands necessary to do a full CDK build and synth, so do include installing dependencies and running the CDK CLI. For example, the old API: ```ts -SimpleSynthAction.standardNpmSynth({ +const sourceArtifact = new codepipeline.Artifact(); +const cloudAssemblyArtifact = new codepipeline.Artifact(); +pipelines.SimpleSynthAction.standardNpmSynth({ sourceArtifact, cloudAssemblyArtifact, @@ -54,8 +56,10 @@ SimpleSynthAction.standardNpmSynth({ Becomes: ```ts -new ShellStep('Synth', { - input: /* source */, +new pipelines.ShellStep('Synth', { + input: pipelines.CodePipelineSource.connection('my-org/my-app', 'main', { + connectionArn: 'arn:aws:codestar-connections:us-east-1:222222222222:connection/7d2469ff-514a-4e4f-9003-5ca4a43cdc41', // Created using the AWS console * });', + }), commands: [ 'npm ci', 'npm run build', @@ -71,7 +75,7 @@ You can use any of the factory functions on `CodePipelineSource`. For example, for a GitHub source, the following old API: ```ts -sourceAction: new codepipeline_actions.GitHubSourceAction({ +sourceAction: new cpactions.GitHubSourceAction({ actionName: 'GitHub', output: sourceArtifact, // Replace these with your actual GitHub project name @@ -84,8 +88,8 @@ sourceAction: new codepipeline_actions.GitHubSourceAction({ Translates into: ```ts -input: CodePipelineSource.gitHub('OWNER/REPO', 'main', { - authentication: SecretValue.secretsManager('GITHUB_TOKEN_NAME'), +input: pipelines.CodePipelineSource.gitHub('OWNER/REPO', 'main', { + authentication: cdk.SecretValue.secretsManager('GITHUB_TOKEN_NAME'), }), ``` @@ -111,8 +115,9 @@ putting manual approvals in `pre` steps, and automated approvals in `post` steps For example, specifying a manual approval on a stage deployment in old API: ```ts +declare const pipeline: pipelines.CdkPipeline; const stage = pipeline.addApplicationStage(...); -stage.addAction(new ManualApprovalAction({ +stage.addAction(new pipelines.ManualApprovalAction({ actionName: 'ManualApproval', runOrder: testingStage.nextSequentialRunOrder(), })); @@ -121,9 +126,10 @@ stage.addAction(new ManualApprovalAction({ Becomes: ```ts -pipeline.addStage(..., { +const stage = new MyApplicationStage(this, 'MyApplication'); +pipeline.addStage(stage, { pre: [ - new ManualApprovalStep('ManualApproval'), + new pipelines.ManualApprovalStep('ManualApproval'), ], }); ``` @@ -139,7 +145,7 @@ For example, specifying an automated approval after a stage is deployed in the f ```ts const stage = pipeline.addApplicationStage(...); -stage.addActions(new ShellScriptAction({ +stage.addActions(new pipelines.ShellScriptAction({ actionName: 'MyValidation', commands: ['curl -Ssf $VAR'], useOutputs: { @@ -153,10 +159,10 @@ stage.addActions(new ShellScriptAction({ Becomes: ```ts -const stage = new MyStage(...); +const stage = new MyApplicationStage(this, 'MyApplication'); pipeline.addStage(stage, { post: [ - new CodeBuildStep('MyValidation', { + new pipelines.CodeBuildStep('MyValidation', { commands: ['curl -Ssf $VAR'], envFromCfnOutput: { VAR: stage.cfnOutput, @@ -174,7 +180,19 @@ customizations (like `buildEnvironment`). #### Change set approvals In the old API, there were two properties that were used to add actions to the pipeline -in between the `CreateChangeSet` and `ExecuteChangeSet` actions: `manualApprovals` and `extraRunOrderSpace`. These are not supported in the new API. +in between the `CreateChangeSet` and `ExecuteChangeSet` actions: `manualApprovals` and `extraRunOrderSpace`. +This can be achieved in the modern API via the `stackSteps` property, which allows steps to be added +at the stack level: + +```ts +const stage = new MyApplicationStage(this, 'MyApplication'); +pipeline.addStage(stage, { + stackSteps: [{ + stack: stage.stack1, + changeSet: [new pipelines.ManualApprovalStep('ChangeSet Approval')], + }], +}); +``` ### Custom CodePipeline Actions @@ -190,7 +208,6 @@ artifacts: ```ts import { Construct, Stage, Stack, StackProps, StageProps } from '@aws-cdk/core'; -import { CdkPipeline } from '@aws-cdk/pipelines'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; /** @@ -203,20 +220,20 @@ class MyPipelineStack extends Stack { const sourceArtifact = new codepipeline.Artifact(); const cloudAssemblyArtifact = new codepipeline.Artifact(); - const pipeline = new CdkPipeline(this, 'Pipeline', { + const pipeline = new pipelines.CdkPipeline(this, 'Pipeline', { cloudAssemblyArtifact, - sourceAction: new codepipeline_actions.GitHubSourceAction({ + sourceAction: new cpactions.GitHubSourceAction({ actionName: 'GitHub', output: sourceArtifact, - oauthToken: SecretValue.secretsManager('GITHUB_TOKEN_NAME'), + oauthToken: cdk.SecretValue.secretsManager('GITHUB_TOKEN_NAME'), // Replace these with your actual GitHub project name owner: 'OWNER', repo: 'REPO', branch: 'main', // default: 'master' }), - synthAction: SimpleSynthAction.standardNpmSynth({ + synthAction: pipelines.SimpleSynthAction.standardNpmSynth({ sourceArtifact, cloudAssemblyArtifact, @@ -274,21 +291,21 @@ class MyPipelineStack extends Stack { const sourceArtifact = new codepipeline.Artifact(); const cloudAssemblyArtifact = new codepipeline.Artifact(); - const pipeline = new CdkPipeline(this, 'Pipeline', { + const pipeline = new pipelines.CdkPipeline(this, 'Pipeline', { pipelineName: 'MyAppPipeline', cloudAssemblyArtifact, - sourceAction: new codepipeline_actions.GitHubSourceAction({ + sourceAction: new cpactions.GitHubSourceAction({ actionName: 'GitHub', output: sourceArtifact, - oauthToken: SecretValue.secretsManager('GITHUB_TOKEN_NAME'), + oauthToken: cdk.SecretValue.secretsManager('GITHUB_TOKEN_NAME'), // Replace these with your actual GitHub project name owner: 'OWNER', repo: 'REPO', branch: 'main', // default: 'master' }), - synthAction: SimpleSynthAction.standardNpmSynth({ + synthAction: pipelines.SimpleSynthAction.standardNpmSynth({ sourceArtifact, cloudAssemblyArtifact, @@ -316,7 +333,7 @@ If you prefer more control over the underlying CodePipeline object, you can create one yourself, including custom Source and Build stages: ```ts -const codePipeline = new cp.Pipeline(pipelineStack, 'CodePipeline', { +const codePipeline = new codepipeline.Pipeline(pipelineStack, 'CodePipeline', { stages: [ { stageName: 'CustomSource', @@ -330,7 +347,7 @@ const codePipeline = new cp.Pipeline(pipelineStack, 'CodePipeline', { }); const app = new App(); -const cdkPipeline = new CdkPipeline(app, 'CdkPipeline', { +const cdkPipeline = new pipelines.CdkPipeline(app, 'CdkPipeline', { codePipeline, cloudAssemblyArtifact, }); @@ -360,9 +377,9 @@ using these, the source repository does not need to have a `buildspec.yml`. An e of using `SimpleSynthAction` to run a Maven build followed by a CDK synth: ```ts -const pipeline = new CdkPipeline(this, 'Pipeline', { +const pipeline = new pipelines.CdkPipeline(this, 'Pipeline', { // ... - synthAction: new SimpleSynthAction({ + synthAction: new pipelines.SimpleSynthAction({ sourceArtifact, cloudAssemblyArtifact, installCommands: ['npm install -g aws-cdk'], @@ -396,16 +413,16 @@ from the CA repo instead of NPM. class MyPipelineStack extends Stack { constructor(scope: Construct, id: string, props?: StackProps) { ... - const pipeline = new CdkPipeline(this, 'Pipeline', { + const pipeline = new pipelines.CdkPipeline(this, 'Pipeline', { ... - synthAction: SimpleSynthAction.standardNpmSynth({ + synthAction: pipelines.SimpleSynthAction.standardNpmSynth({ sourceArtifact, cloudAssemblyArtifact, // Use this to customize and a permissions required for the build // and synth rolePolicyStatements: [ - new PolicyStatement({ + new iam.PolicyStatement({ actions: ['codeartifact:*', 'sts:GetServiceBearerToken'], resources: ['arn:codeartifact:repo:arn'], }), @@ -477,7 +494,7 @@ const testingStage = pipeline.addApplicationStage(new MyApplication(this, 'Testi // Add a action -- in this case, a Manual Approval action // (for illustration purposes: testingStage.addManualApprovalAction() is a // convenience shorthand that does the same) -testingStage.addAction(new ManualApprovalAction({ +testingStage.addAction(new pipelines.ManualApprovalAction({ actionName: 'ManualApproval', runOrder: testingStage.nextSequentialRunOrder(), })); @@ -522,7 +539,7 @@ In its simplest form, adding validation actions looks like this: ```ts const stage = pipeline.addApplicationStage(new MyApplication(/* ... */)); -stage.addActions(new ShellScriptAction({ +stage.addActions(new pipelines.ShellScriptAction({ actionName: 'MyValidation', commands: ['curl -Ssf https://my.webservice.com/'], // Optionally specify a VPC if, for example, the service is deployed with a private load balancer @@ -563,7 +580,7 @@ const lbApp = new MyLbApplication(this, 'MyApp', { env: { /* ... */ } }); const stage = pipeline.addApplicationStage(lbApp); -stage.addActions(new ShellScriptAction({ +stage.addActions(new pipelines.ShellScriptAction({ // ... useOutputs: { // When the test is executed, this will make $URL contain the @@ -594,7 +611,7 @@ two ways. Either pass additional policy statements in the `rolePolicyStatements` property: ```ts -new ShellScriptAction({ +new pipelines.ShellScriptAction({ // ... rolePolicyStatements: [ new iam.PolicyStatement({ @@ -608,7 +625,7 @@ new ShellScriptAction({ The Action can also be used as a Grantable after having been added to a Pipeline: ```ts -const action = new ShellScriptAction({ /* ... */ }); +const action = new pipelines.ShellScriptAction({ /* ... */ }); pipeline.addStage('Test').addActions(action); bucket.grantRead(action); @@ -623,11 +640,11 @@ if they are executable shell scripts themselves). Pass the `sourceArtifact`: ```ts const sourceArtifact = new codepipeline.Artifact(); -const pipeline = new CdkPipeline(this, 'Pipeline', { +const pipeline = new pipelines.CdkPipeline(this, 'Pipeline', { // ... }); -const validationAction = new ShellScriptAction({ +const validationAction = new pipelines.ShellScriptAction({ actionName: 'TestUsingSourceArtifact', additionalArtifacts: [sourceArtifact], @@ -651,8 +668,8 @@ in the `ShellScriptAction`'s `additionalArtifacts`: const cloudAssemblyArtifact = new codepipeline.Artifact('CloudAsm'); const integTestsArtifact = new codepipeline.Artifact('IntegTests'); -const pipeline = new CdkPipeline(this, 'Pipeline', { - synthAction: SimpleSynthAction.standardNpmSynth({ +const pipeline = new pipelines.CdkPipeline(this, 'Pipeline', { + synthAction: pipelines.SimpleSynthAction.standardNpmSynth({ sourceArtifact, cloudAssemblyArtifact, buildCommands: ['npm run build'], @@ -666,7 +683,7 @@ const pipeline = new CdkPipeline(this, 'Pipeline', { // ... }); -const validationAction = new ShellScriptAction({ +const validationAction = new pipelines.ShellScriptAction({ actionName: 'TestUsingBuildArtifact', additionalArtifacts: [integTestsArtifact], // 'test.js' was produced from 'test/test.ts' during the synth step @@ -715,12 +732,11 @@ create an SNS Topic, subscribe your own email address, and pass it in via ```ts import * as sns from '@aws-cdk/aws-sns'; import * as subscriptions from '@aws-cdk/aws-sns-subscriptions'; -import * as pipelines from '@aws-cdk/pipelines'; const topic = new sns.Topic(this, 'SecurityChangesTopic'); topic.addSubscription(new subscriptions.EmailSubscription('test@email.com')); -const pipeline = new CdkPipeline(app, 'Pipeline', { /* ... */ }); +const pipeline = new pipelines.CdkPipeline(app, 'Pipeline', { /* ... */ }); const stage = pipeline.addApplicationStage(new MyApplication(this, 'PreProd'), { confirmBroadeningPermissions: true, securityNotificationTopic: topic, diff --git a/packages/@aws-cdk/pipelines/README.md b/packages/@aws-cdk/pipelines/README.md index 1e0df7a4b2c2a..bd6525542920b 100644 --- a/packages/@aws-cdk/pipelines/README.md +++ b/packages/@aws-cdk/pipelines/README.md @@ -43,14 +43,31 @@ CodePipeline engine, define a `CodePipeline` construct. The following example creates a CodePipeline that deploys an application from GitHub: ```ts -/** The stacks for our app are defined in my-stacks.ts. The internals of these +/** The stacks for our app are minimally defined here. The internals of these * stacks aren't important, except that DatabaseStack exposes an attribute * "table" for a database table it defines, and ComputeStack accepts a reference * to this table in its properties. */ -import { DatabaseStack, ComputeStack } from '../lib/my-stacks'; -import { Construct, Stage, Stack, StackProps, StageProps } from '@aws-cdk/core'; -import { CodePipeline, CodePipelineSource, ShellStep } from '@aws-cdk/pipelines'; +class DatabaseStack extends Stack { + public readonly table: dynamodb.Table; + + constructor(scope: Construct, id: string) { + super(scope, id); + this.table = new dynamodb.Table(this, 'Table', { + partitionKey: { name: 'id', type: dynamodb.AttributeType.STRING } + }); + } +} + +interface ComputeProps { + readonly table: dynamodb.Table; +} + +class ComputeStack extends Stack { + constructor(scope: Construct, id: string, props: ComputeProps) { + super(scope, id); + } +} /** * Stack to hold the pipeline @@ -59,11 +76,11 @@ class MyPipelineStack extends Stack { constructor(scope: Construct, id: string, props?: StackProps) { super(scope, id, props); - const pipeline = new CodePipeline(this, 'Pipeline', { - synth: new ShellStep('Synth', { + const pipeline = new pipelines.CodePipeline(this, 'Pipeline', { + synth: new pipelines.ShellStep('Synth', { // Use a connection created using the AWS console to authenticate to GitHub // Other sources are available. - input: CodePipelineSource.connection('my-org/my-app', 'main', { + input: pipelines.CodePipelineSource.connection('my-org/my-app', 'main', { connectionArn: 'arn:aws:codestar-connections:us-east-1:222222222222:connection/7d2469ff-514a-4e4f-9003-5ca4a43cdc41', // Created using the AWS console * });', }), commands: [ @@ -81,7 +98,7 @@ class MyPipelineStack extends Stack { env: { account: '123456789012', region: 'eu-west-1', - } + }, })); } } @@ -106,7 +123,7 @@ class MyApplication extends Stage { } // In your main file -new MyPipelineStack(app, 'PipelineStack', { +new MyPipelineStack(this, 'PipelineStack', { env: { account: '123456789012', region: 'eu-west-1', @@ -172,15 +189,25 @@ off temporarily, by passing `selfMutation: false` property, example: ```ts // Modern API -const pipeline = new CodePipeline(this, 'Pipeline', { +const modernPipeline = new pipelines.CodePipeline(this, 'Pipeline', { selfMutation: false, - ... + synth: new pipelines.ShellStep('Synth', { + input: pipelines.CodePipelineSource.connection('my-org/my-app', 'main', { + connectionArn: 'arn:aws:codestar-connections:us-east-1:222222222222:connection/7d2469ff-514a-4e4f-9003-5ca4a43cdc41', // Created using the AWS console * });', + }), + commands: [ + 'npm ci', + 'npm run build', + 'npx cdk synth', + ], + }), }); // Original API -const pipeline = new CdkPipeline(this, 'Pipeline', { +const cloudAssemblyArtifact = new codepipeline.Artifact(); +const originalPipeline = new pipelines.CdkPipeline(this, 'Pipeline', { selfMutating: false, - ... + cloudAssemblyArtifact, }); ``` @@ -204,10 +231,10 @@ commands required will depend on the programming language you are using. For a typical NPM-based project, the synth will look like this: ```ts -const source = /* the repository source */; +declare const source: pipelines.IFileSetProducer; // the repository source -const pipeline = new CodePipeline(this, 'Pipeline', { - synth: new ShellStep('Synth', { +const pipeline = new pipelines.CodePipeline(this, 'Pipeline', { + synth: new pipelines.ShellStep('Synth', { input: source, commands: [ 'npm ci', @@ -224,8 +251,10 @@ CDK project lives in a subdirectory, be sure to adjust the `primaryOutputDirectory` to match: ```ts -const pipeline = new CodePipeline(this, 'Pipeline', { - synth: new ShellStep('Synth', { +declare const source: pipelines.IFileSetProducer; // the repository source + +const pipeline = new pipelines.CodePipeline(this, 'Pipeline', { + synth: new pipelines.ShellStep('Synth', { input: source, commands: [ 'cd mysubdir', @@ -254,8 +283,10 @@ look like in a number of different situations. For Yarn, the install commands are different: ```ts -const pipeline = new CodePipeline(this, 'Pipeline', { - synth: new ShellStep('Synth', { +declare const source: pipelines.IFileSetProducer; // the repository source + +const pipeline = new pipelines.CodePipeline(this, 'Pipeline', { + synth: new pipelines.ShellStep('Synth', { input: source, commands: [ 'yarn install --frozen-lockfile', @@ -270,8 +301,10 @@ For Python projects, remember to install the CDK CLI globally (as there is no `package.json` to automatically install it for you): ```ts -const pipeline = new CodePipeline(this, 'Pipeline', { - synth: new ShellStep('Synth', { +declare const source: pipelines.IFileSetProducer; // the repository source + +const pipeline = new pipelines.CodePipeline(this, 'Pipeline', { + synth: new pipelines.ShellStep('Synth', { input: source, commands: [ 'pip install -r requirements.txt', @@ -288,8 +321,10 @@ and the Maven compilation step is automatically executed for you as you run `cdk synth`: ```ts -const pipeline = new CodePipeline(this, 'Pipeline', { - synth: new ShellStep('Synth', { +declare const source: pipelines.IFileSetProducer; // the repository source + +const pipeline = new pipelines.CodePipeline(this, 'Pipeline', { + synth: new pipelines.ShellStep('Synth', { input: source, commands: [ 'npm install -g aws-cdk', @@ -314,7 +349,7 @@ You will first use the AWS Console to authenticate to the source control provider, and then use the connection ARN in your pipeline definition: ```ts -CodePipelineSource.connection('org/repo', 'branch', { +pipelines.CodePipelineSource.connection('org/repo', 'branch', { connectionArn: 'arn:aws:codestar-connections:us-east-1:222222222222:connection/7d2469ff-514a-4e4f-9003-5ca4a43cdc41', }); ``` @@ -328,9 +363,9 @@ you can change the name. The token should have the **repo** and **admin:repo_hoo scopes. ```ts -CodePipelineSource.gitHub('org/repo', 'branch', { +pipelines.CodePipelineSource.gitHub('org/repo', 'branch', { // This is optional - authentication: SecretValue.secretsManager('my-token'), + authentication: cdk.SecretValue.secretsManager('my-token'), }); ``` @@ -341,8 +376,8 @@ that the CodeCommit repository and then use `CodePipelineSource.codeCommit` to reference it: ```ts -const repository = codecommit.fromRepositoryName(this, 'Repository', 'my-repository'); -CodePipelineSource.codeCommit(repository); +const repository = codecommit.Repository.fromRepositoryName(this, 'Repository', 'my-repository'); +pipelines.CodePipelineSource.codeCommit(repository, 'main'); ``` ##### S3 @@ -352,7 +387,7 @@ triggered every time the file in S3 is changed: ```ts const bucket = s3.Bucket.fromBucketName(this, 'Bucket', 'my-bucket'); -CodePipelineSource.s3(bucket, 'my/source.zip'); +pipelines.CodePipelineSource.s3(bucket, 'my/source.zip'); ``` #### Additional inputs @@ -363,17 +398,17 @@ output file set can be used as an input, such as a `CodePipelineSource`, but also other `ShellStep`: ```ts -const prebuild = new ShellStep('Prebuild', { - input: CodePipelineSource.gitHub('myorg/repo1'), +const prebuild = new pipelines.ShellStep('Prebuild', { + input: pipelines.CodePipelineSource.gitHub('myorg/repo1', 'main'), primaryOutputDirectory: './build', commands: ['./build.sh'], }); -const pipeline = new CodePipeline(this, 'Pipeline', { - synth: new ShellStep('Synth', { - input: CodePipelineSource.gitHub('myorg/repo2'), +const pipeline = new pipelines.CodePipeline(this, 'Pipeline', { + synth: new pipelines.ShellStep('Synth', { + input: pipelines.CodePipelineSource.gitHub('myorg/repo2', 'main'), additionalInputs: { - 'subdir': CodePipelineSource.gitHub('myorg/repo3'), + 'subdir': pipelines.CodePipelineSource.gitHub('myorg/repo3', 'main'), '../siblingdir': prebuild, }, @@ -389,6 +424,7 @@ more CDK `Stages` which will be deployed to their target environments. To do so, call `pipeline.addStage()` on the Stage object: ```ts +declare const pipeline: pipelines.CodePipeline; // Do this as many times as necessary with any account and region // Account and region may different from the pipeline's. pipeline.addStage(new MyApplicationStage(this, 'Prod', { @@ -421,6 +457,7 @@ deployed in sequence. For example, the following will deploy two copies of your application to `eu-west-1` and `eu-central-1` in parallel: ```ts +declare const pipeline: pipelines.CodePipeline; const europeWave = pipeline.addWave('Europe'); europeWave.addStage(new MyApplicationStage(this, 'Ireland', { env: { region: 'eu-west-1' } @@ -445,9 +482,19 @@ KMS key. Example: ```ts -const pipeline = new CodePipeline(this, 'Pipeline', { +const pipeline = new pipelines.CodePipeline(this, 'Pipeline', { // Encrypt artifacts, required for cross-account deployments crossAccountKeys: true, + synth: new pipelines.ShellStep('Synth', { + input: pipelines.CodePipelineSource.connection('my-org/my-app', 'main', { + connectionArn: 'arn:aws:codestar-connections:us-east-1:222222222222:connection/7d2469ff-514a-4e4f-9003-5ca4a43cdc41', // Created using the AWS console * });', + }), + commands: [ + 'npm ci', + 'npm run build', + 'npx cdk synth', + ], + }), }); ``` @@ -464,19 +511,20 @@ a manual approval in the form of a `ManualApprovalStep` added to the pipeline. B pass in order to promote from the `PreProd` to the `Prod` environment: ```ts -const preprod = new MyApplicationStage(this, 'PreProd', { ... }); -const prod = new MyApplicationStage(this, 'Prod', { ... }); +declare const pipeline: pipelines.CodePipeline; +const preprod = new MyApplicationStage(this, 'PreProd'); +const prod = new MyApplicationStage(this, 'Prod'); pipeline.addStage(preprod, { post: [ - new ShellStep('Validate Endpoint', { + new pipelines.ShellStep('Validate Endpoint', { commands: ['curl -Ssf https://my.webservice.com/'], }), ], }); pipeline.addStage(prod, { pre: [ - new ManualApprovalStep('PromoteToProd'), + new pipelines.ManualApprovalStep('PromoteToProd'), ], }); ``` @@ -484,15 +532,29 @@ pipeline.addStage(prod, { You can also specify steps to be executed at the stack level. To achieve this, you can specify the stack and step via the `stackSteps` property: ```ts +class MyStacksStage extends Stage { + public readonly stack1: Stack; + public readonly stack2: Stack; + + constructor(scope: Construct, id: string, props?: StageProps) { + super(scope, id, props); + this.stack1 = new Stack(this, 'stack1'); + this.stack2 = new Stack(this, 'stack2'); + } +} + +declare const pipeline: pipelines.CodePipeline; +const prod = new MyStacksStage(this, 'Prod'); + pipeline.addStage(prod, { stackSteps: [{ stack: prod.stack1, - pre: [new ManualApprovalStep('Pre-Stack Check')], // Executed before stack is prepared - changeSet: [new ManualApprovalStep('ChangeSet Approval')], // Executed after stack is prepared but before the stack is deployed - post: [new ManualApprovalStep('Post-Deploy Check')], // Executed after staack is deployed + pre: [new pipelines.ManualApprovalStep('Pre-Stack Check')], // Executed before stack is prepared + changeSet: [new pipelines.ManualApprovalStep('ChangeSet Approval')], // Executed after stack is prepared but before the stack is deployed + post: [new pipelines.ManualApprovalStep('Post-Deploy Check')], // Executed after staack is deployed }, { stack: prod.stack2, - post: [new ManualApprovalStep('Post-Deploy Check')], // Executed after staack is deployed + post: [new pipelines.ManualApprovalStep('Post-Deploy Check')], // Executed after staack is deployed }], }); ``` @@ -507,21 +569,26 @@ To use Stack Outputs, expose the `CfnOutput` object you're interested in, and pass it to `envFromCfnOutputs` of the `ShellStep`: ```ts -class MyApplicationStage extends Stage { +class MyOutputStage extends Stage { public readonly loadBalancerAddress: CfnOutput; - // ... + + constructor(scope: Construct, id: string, props?: StageProps) { + super(scope, id, props); + this.loadBalancerAddress = new CfnOutput(this, 'Output', {value: 'value'}); + } } -const lbApp = new MyApplicationStage(this, 'MyApp', { /* ... */ }); +const lbApp = new MyOutputStage(this, 'MyApp'); +declare const pipeline: pipelines.CodePipeline; pipeline.addStage(lbApp, { post: [ - new ShellStep('HitEndpoint', { + new pipelines.ShellStep('HitEndpoint', { envFromCfnOutputs: { // Make the load balancer address available as $URL inside the commands URL: lbApp.loadBalancerAddress, }, commands: ['curl -Ssf $URL'], - }); + }), ], }); ``` @@ -539,12 +606,13 @@ Here's an example that captures an additional output directory in the synth step and runs tests from there: ```ts -const synth = new ShellStep('Synth', { /* ... */ }); -const pipeline = new CodePipeline(this, 'Pipeline', { synth }); +declare const synth: pipelines.ShellStep; +const stage = new MyApplicationStage(this, 'MyApplication'); +const pipeline = new pipelines.CodePipeline(this, 'Pipeline', { synth }); -pipeline.addStage(/* ... */, { +pipeline.addStage(stage, { post: [ - new ShellStep('Approve', { + new pipelines.ShellStep('Approve', { // Use the contents of the 'integ' directory from the synth step as the input input: synth.addOutputDirectory('integ'), commands: ['cd integ && ./run.sh'], @@ -562,7 +630,9 @@ generated, use a `CodeBuildStep` instead of a `ShellStep`. This class has a numb of properties that allow you to customize various aspects of the projects: ```ts -new CodeBuildStep('Synth', { +declare const vpc: ec2.Vpc; +declare const mySecurityGroup: ec2.SecurityGroup; +new pipelines.CodeBuildStep('Synth', { // ...standard ShellStep props... commands: [/* ... */], env: { /* ... */ }, @@ -602,8 +672,20 @@ or just for the synth, asset publishing, and self-mutation projects by passing ` `assetPublishingCodeBuildDefaults`, or `selfMutationCodeBuildDefaults`: ```ts -new CodePipeline(this, 'Pipeline', { - // ... +declare const vpc: ec2.Vpc; +declare const mySecurityGroup: ec2.SecurityGroup; +new pipelines.CodePipeline(this, 'Pipeline', { + // Standard CodePipeline properties + synth: new pipelines.ShellStep('Synth', { + input: pipelines.CodePipelineSource.connection('my-org/my-app', 'main', { + connectionArn: 'arn:aws:codestar-connections:us-east-1:222222222222:connection/7d2469ff-514a-4e4f-9003-5ca4a43cdc41', // Created using the AWS console * });', + }), + commands: [ + 'npm ci', + 'npm run build', + 'npx cdk synth', + ], + }), // Defaults for all CodeBuild projects codeBuildDefaults: { @@ -644,15 +726,19 @@ doesn't have a matching class yet, you can define your own step class that exten Here's an example that adds a Jenkins step: ```ts -class MyJenkinsStep extends Step implements ICodePipelineActionFactory { - constructor(private readonly provider: codepipeline_actions.JenkinsProvider, private readonly input: FileSet) { +class MyJenkinsStep extends pipelines.Step implements pipelines.ICodePipelineActionFactory { + constructor( + private readonly provider: cpactions.JenkinsProvider, + private readonly input: pipelines.FileSet, + ) { + super('MyJenkinsStep'); } - public produceAction(stage: codepipeline.IStage, options: ProduceActionOptions): CodePipelineActionFactoryResult { + public produceAction(stage: codepipeline.IStage, options: pipelines.ProduceActionOptions): pipelines.CodePipelineActionFactoryResult { // This is where you control what type of Action gets added to the // CodePipeline - stage.addAction(new codepipeline_actions.JenkinsAction({ + stage.addAction(new cpactions.JenkinsAction({ // Copy 'actionName' and 'runOrder' from the options actionName: options.actionName, runOrder: options.runOrder, @@ -700,8 +786,13 @@ stacks the pipeline is deploying), for example by the use of `LinuxBuildImage.fr you need to pass `dockerEnabledForSelfMutation: true` to the pipeline. For example: ```ts -const pipeline = new CodePipeline(this, 'Pipeline', { - // ... +const pipeline = new pipelines.CodePipeline(this, 'Pipeline', { + synth: new pipelines.ShellStep('Synth', { + input: pipelines.CodePipelineSource.connection('my-org/my-app', 'main', { + connectionArn: 'arn:aws:codestar-connections:us-east-1:222222222222:connection/7d2469ff-514a-4e4f-9003-5ca4a43cdc41', // Created using the AWS console * });', + }), + commands: ['npm ci','npm run build','npx cdk synth'], + }), // Turn this on because the pipeline uses Docker image assets dockerEnabledForSelfMutation: true, @@ -709,16 +800,16 @@ const pipeline = new CodePipeline(this, 'Pipeline', { pipeline.addWave('MyWave', { post: [ - new CodeBuildStep('RunApproval', { + new pipelines.CodeBuildStep('RunApproval', { commands: ['command-from-image'], buildEnvironment: { // The user of a Docker image asset in the pipeline requires turning on // 'dockerEnabledForSelfMutation'. - buildImage: LinuxBuildImage.fromAsset(this, 'Image', { + buildImage: codebuild.LinuxBuildImage.fromAsset(this, 'Image', { directory: './docker-image', - }) + }), }, - }) + }), ], }); ``` @@ -734,8 +825,13 @@ if you add a construct like `@aws-cdk/aws-lambda-nodejs`), you need to pass `dockerEnabledForSynth: true` to the pipeline. For example: ```ts -const pipeline = new CodePipeline(this, 'Pipeline', { - // ... +const pipeline = new pipelines.CodePipeline(this, 'Pipeline', { + synth: new pipelines.ShellStep('Synth', { + input: pipelines.CodePipelineSource.connection('my-org/my-app', 'main', { + connectionArn: 'arn:aws:codestar-connections:us-east-1:222222222222:connection/7d2469ff-514a-4e4f-9003-5ca4a43cdc41', // Created using the AWS console * });', + }), + commands: ['npm ci','npm run build','npx cdk synth'], + }), // Turn this on because the application uses bundled file assets dockerEnabledForSynth: true, @@ -756,16 +852,21 @@ different environment (e.g., ECR repo) or to avoid throttling (e.g., DockerHub). ```ts const dockerHubSecret = secretsmanager.Secret.fromSecretCompleteArn(this, 'DHSecret', 'arn:aws:...'); const customRegSecret = secretsmanager.Secret.fromSecretCompleteArn(this, 'CRSecret', 'arn:aws:...'); -const repo1 = ecr.Repository.fromRepositoryArn(stack, 'Repo', 'arn:aws:ecr:eu-west-1:0123456789012:repository/Repo1'); -const repo2 = ecr.Repository.fromRepositoryArn(stack, 'Repo', 'arn:aws:ecr:eu-west-1:0123456789012:repository/Repo2'); +const repo1 = ecr.Repository.fromRepositoryArn(this, 'Repo', 'arn:aws:ecr:eu-west-1:0123456789012:repository/Repo1'); +const repo2 = ecr.Repository.fromRepositoryArn(this, 'Repo', 'arn:aws:ecr:eu-west-1:0123456789012:repository/Repo2'); -const pipeline = new CodePipeline(this, 'Pipeline', { +const pipeline = new pipelines.CodePipeline(this, 'Pipeline', { dockerCredentials: [ - DockerCredential.dockerHub(dockerHubSecret), - DockerCredential.customRegistry('dockerregistry.example.com', customRegSecret), - DockerCredential.ecr([repo1, repo2]); + pipelines.DockerCredential.dockerHub(dockerHubSecret), + pipelines.DockerCredential.customRegistry('dockerregistry.example.com', customRegSecret), + pipelines.DockerCredential.ecr([repo1, repo2]), ], - // ... + synth: new pipelines.ShellStep('Synth', { + input: pipelines.CodePipelineSource.connection('my-org/my-app', 'main', { + connectionArn: 'arn:aws:codestar-connections:us-east-1:222222222222:connection/7d2469ff-514a-4e4f-9003-5ca4a43cdc41', // Created using the AWS console * });', + }), + commands: ['npm ci','npm run build','npx cdk synth'], + }), }); ``` @@ -784,7 +885,7 @@ the **Synth**, **Self-Update**, and **Asset Publishing** actions within the ```ts const dockerHubSecret = secretsmanager.Secret.fromSecretCompleteArn(this, 'DHSecret', 'arn:aws:...'); // Only the image asset publishing actions will be granted read access to the secret. -const creds = DockerCredential.dockerHub(dockerHubSecret, { usages: [DockerCredentialUsage.ASSET_PUBLISHING] }); +const creds = pipelines.DockerCredential.dockerHub(dockerHubSecret, { usages: [pipelines.DockerCredentialUsage.ASSET_PUBLISHING] }); ``` ## CDK Environment Bootstrapping @@ -953,9 +1054,11 @@ give the synth CodeBuild execution role permissions to assume the bootstrapped lookup roles. As an example, doing so would look like this: ```ts -new CodePipeline(this, 'Pipeline', { - synth: new CodeBuildStep('Synth', { - input: // ...input... +new pipelines.CodePipeline(this, 'Pipeline', { + synth: new pipelines.CodeBuildStep('Synth', { + input: pipelines.CodePipelineSource.connection('my-org/my-app', 'main', { + connectionArn: 'arn:aws:codestar-connections:us-east-1:222222222222:connection/7d2469ff-514a-4e4f-9003-5ca4a43cdc41', // Created using the AWS console * });', + }), commands: [ // Commands to load cdk.context.json from somewhere here '...', @@ -1034,10 +1137,11 @@ Pipeline You can insert the security check by using a `ConfirmPermissionsBroadening` step: ```ts +declare const pipeline: pipelines.CodePipeline; const stage = new MyApplicationStage(this, 'MyApplication'); pipeline.addStage(stage, { pre: [ - new ConfirmPermissionsBroadening('Check', { stage }), + new pipelines.ConfirmPermissionsBroadening('Check', { stage }), ], }); ``` @@ -1047,17 +1151,14 @@ create an SNS Topic, subscribe your own email address, and pass it in as as the `notificationTopic` property: ```ts -import * as sns from '@aws-cdk/aws-sns'; -import * as subscriptions from '@aws-cdk/aws-sns-subscriptions'; -import * as pipelines from '@aws-cdk/pipelines'; - +declare const pipeline: pipelines.CodePipeline; const topic = new sns.Topic(this, 'SecurityChangesTopic'); topic.addSubscription(new subscriptions.EmailSubscription('test@email.com')); const stage = new MyApplicationStage(this, 'MyApplication'); pipeline.addStage(stage, { pre: [ - new ConfirmPermissionsBroadening('Check', { + new pipelines.ConfirmPermissionsBroadening('Check', { stage, notificationTopic: topic, }), @@ -1162,19 +1263,19 @@ that bundles asset using tools run via Docker, like `aws-lambda-nodejs`, `aws-la Make sure you set the `privileged` environment variable to `true` in the synth definition: -```typescript - const pipeline = new CdkPipeline(this, 'MyPipeline', { - ... - - synthAction: SimpleSynthAction.standardNpmSynth({ - sourceArtifact: ..., - cloudAssemblyArtifact: ..., - - environment: { - privileged: true, - }, - }), - }); +```ts +const sourceArtifact = new codepipeline.Artifact(); +const cloudAssemblyArtifact = new codepipeline.Artifact(); +const pipeline = new pipelines.CdkPipeline(this, 'MyPipeline', { + cloudAssemblyArtifact, + synthAction: pipelines.SimpleSynthAction.standardNpmSynth({ + sourceArtifact, + cloudAssemblyArtifact, + environment: { + privileged: true, + }, + }), +}); ``` After turning on `privilegedMode: true`, you will need to do a one-time manual cdk deploy of your @@ -1201,10 +1302,11 @@ This happens because the pipeline is not self-mutating and, as a consequence, th build projects get out-of-sync with the generated templates. To fix this, make sure the `selfMutating` property is set to `true`: -```typescript -const pipeline = new CdkPipeline(this, 'MyPipeline', { +```ts +const cloudAssemblyArtifact = new codepipeline.Artifact(); +const pipeline = new pipelines.CdkPipeline(this, 'MyPipeline', { selfMutating: true, - ... + cloudAssemblyArtifact, }); ``` @@ -1231,8 +1333,8 @@ A hypothetical recovery workflow would look something like this: ```sh $ env CDK_NEW_BOOTSTRAP=1 npx cdk bootstrap \ - --qualifier randchars1234 - --toolkit-stack-name CDKToolkitTemp + --qualifier random1234 \ + --toolkit-stack-name CDKToolkitTemp \ aws://111111111111/us-east-1 ``` @@ -1240,9 +1342,9 @@ $ env CDK_NEW_BOOTSTRAP=1 npx cdk bootstrap \ See https://docs.aws.amazon.com/cdk/latest/guide/bootstrapping.html for more info. ```ts -new MyStack(this, 'MyStack', { +new Stack(this, 'MyStack', { // Update this qualifier to match the one used above. - synthesizer: new DefaultStackSynthesizer({ + synthesizer: new cdk.DefaultStackSynthesizer({ qualifier: 'randchars1234', }), }); diff --git a/packages/@aws-cdk/pipelines/jest.config.js b/packages/@aws-cdk/pipelines/jest.config.js index ad27b218892cb..8ce875da0ea4c 100644 --- a/packages/@aws-cdk/pipelines/jest.config.js +++ b/packages/@aws-cdk/pipelines/jest.config.js @@ -1,4 +1,4 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = { ...baseConfig, coverageThreshold: { diff --git a/packages/@aws-cdk/pipelines/lib/blueprint/shell-step.ts b/packages/@aws-cdk/pipelines/lib/blueprint/shell-step.ts index 75c1883d92419..1f03105c78ee9 100644 --- a/packages/@aws-cdk/pipelines/lib/blueprint/shell-step.ts +++ b/packages/@aws-cdk/pipelines/lib/blueprint/shell-step.ts @@ -65,11 +65,11 @@ export interface ShellStepProps { * following configuration: * * ```ts - * const script = new ShellStep('MainScript', { - * // ... - * input: MyEngineSource.gitHub('org/source1'), + * const script = new pipelines.ShellStep('MainScript', { + * commands: ['npm ci','npm run build','npx cdk synth'], + * input: pipelines.CodePipelineSource.gitHub('org/source1', 'main'), * additionalInputs: { - * '../siblingdir': MyEngineSource.gitHub('org/source2'), + * '../siblingdir': pipelines.CodePipelineSource.gitHub('org/source2', 'main'), * } * }); * ``` diff --git a/packages/@aws-cdk/pipelines/lib/codepipeline/codepipeline-source.ts b/packages/@aws-cdk/pipelines/lib/codepipeline/codepipeline-source.ts index b6d10b03f2f67..382bed08028ff 100644 --- a/packages/@aws-cdk/pipelines/lib/codepipeline/codepipeline-source.ts +++ b/packages/@aws-cdk/pipelines/lib/codepipeline/codepipeline-source.ts @@ -26,7 +26,7 @@ export abstract class CodePipelineSource extends Step implements ICodePipelineAc * Pass in the owner and repository in a single string, like this: * * ```ts - * CodePipelineSource.gitHub('owner/repo', 'main'); + * pipelines.CodePipelineSource.gitHub('owner/repo', 'main'); * ``` * * Authentication will be done by a secret called `github-token` in AWS @@ -51,8 +51,8 @@ export abstract class CodePipelineSource extends Step implements ICodePipelineAc * Example: * * ```ts - * const bucket: IBucket = ... - * CodePipelineSource.s3(bucket, { + * declare const bucket: s3.Bucket; + * pipelines.CodePipelineSource.s3(bucket, { * key: 'path/to/file.zip', * }); * ``` @@ -74,7 +74,7 @@ export abstract class CodePipelineSource extends Step implements ICodePipelineAc * Example: * * ```ts - * CodePipelineSource.connection('owner/repo', 'main', { + * pipelines.CodePipelineSource.connection('owner/repo', 'main', { * connectionArn: 'arn:aws:codestar-connections:us-east-1:222222222222:connection/7d2469ff-514a-4e4f-9003-5ca4a43cdc41', // Created using the AWS console * }); * ``` @@ -131,7 +131,6 @@ export interface GitHubSourceOptions { * * ```ts * const oauth = cdk.SecretValue.secretsManager('my-github-token'); - * new GitHubSource(this, 'GitHubSource', { authentication: oauth, ... }); * ``` * * The GitHub Personal Access Token should have these scopes: diff --git a/packages/@aws-cdk/pipelines/lib/legacy/pipeline.ts b/packages/@aws-cdk/pipelines/lib/legacy/pipeline.ts index b8d7769ad3fc0..60f158f298fce 100644 --- a/packages/@aws-cdk/pipelines/lib/legacy/pipeline.ts +++ b/packages/@aws-cdk/pipelines/lib/legacy/pipeline.ts @@ -87,6 +87,19 @@ export interface CdkPipelineProps { readonly crossAccountKeys?: boolean; // @deprecated(v2): switch to default false + + /** + * Enables KMS key rotation for cross-account keys. + * + * Cannot be set if `crossAccountKeys` was set to `false`. + * + * Key rotation costs $1/month when enabled. + * + * @default - false (key rotation is disabled) + */ + readonly enableKeyRotation?: boolean; + + /** * CDK CLI version to use in pipeline * @@ -221,12 +234,16 @@ export class CdkPipeline extends CoreConstruct { if (props.crossAccountKeys !== undefined) { throw new Error('Cannot set \'crossAccountKeys\' if an existing CodePipeline is given using \'codePipeline\''); } + if (props.enableKeyRotation !== undefined) { + throw new Error('Cannot set \'enableKeyRotation\' if an existing CodePipeline is given using \'codePipeline\''); + } this._pipeline = props.codePipeline; } else { this._pipeline = new codepipeline.Pipeline(this, 'Pipeline', { pipelineName: props.pipelineName, crossAccountKeys: props.crossAccountKeys, + enableKeyRotation: props.enableKeyRotation, restartExecutionOnUpdate: true, }); } diff --git a/packages/@aws-cdk/pipelines/lib/main/pipeline-base.ts b/packages/@aws-cdk/pipelines/lib/main/pipeline-base.ts index d69c2a6c89ab1..2f90df9de6f1a 100644 --- a/packages/@aws-cdk/pipelines/lib/main/pipeline-base.ts +++ b/packages/@aws-cdk/pipelines/lib/main/pipeline-base.ts @@ -95,9 +95,11 @@ export abstract class PipelineBase extends CoreConstruct { * Example: * * ```ts + * declare const pipeline: pipelines.CodePipeline; + * * const wave = pipeline.addWave('MyWave'); - * wave.addStage(new MyStage('Stage1', ...)); - * wave.addStage(new MyStage('Stage2', ...)); + * wave.addStage(new MyApplicationStage(this, 'Stage1')); + * wave.addStage(new MyApplicationStage(this, 'Stage2')); * ``` */ public addWave(id: string, options?: WaveOptions) { diff --git a/packages/@aws-cdk/pipelines/lib/private/application-security-check.ts b/packages/@aws-cdk/pipelines/lib/private/application-security-check.ts index b8d7a7fd0d2bb..ad4ddbd76fdde 100644 --- a/packages/@aws-cdk/pipelines/lib/private/application-security-check.ts +++ b/packages/@aws-cdk/pipelines/lib/private/application-security-check.ts @@ -62,7 +62,7 @@ export class ApplicationSecurityCheck extends CoreConstruct { this.preApproveLambda = new lambda.Function(this, 'CDKPipelinesAutoApprove', { handler: 'index.handler', - runtime: lambda.Runtime.NODEJS_14_X, + runtime: lambda.Runtime.NODEJS_12_X, code: lambda.Code.fromAsset(path.resolve(__dirname, 'approve-lambda')), timeout: Duration.minutes(5), }); @@ -180,4 +180,4 @@ const ifElse = ({ condition, thenStatements, elseStatements }: ifElseOptions): s } return `${statement} fi`; -}; \ No newline at end of file +}; diff --git a/packages/@aws-cdk/pipelines/package.json b/packages/@aws-cdk/pipelines/package.json index 7daeb0589feb0..432dfba00c721 100644 --- a/packages/@aws-cdk/pipelines/package.json +++ b/packages/@aws-cdk/pipelines/package.json @@ -35,14 +35,14 @@ "@aws-cdk/assertions": "0.0.0", "@aws-cdk/aws-apigateway": "0.0.0", "@aws-cdk/aws-ecr-assets": "0.0.0", - "@aws-cdk/aws-sqs": "0.0.0", "@aws-cdk/aws-sns-subscriptions": "0.0.0", + "@aws-cdk/aws-sqs": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "aws-sdk": "^2.848.0", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "aws-sdk": "^2.848.0" }, "peerDependencies": { "@aws-cdk/aws-codebuild": "0.0.0", @@ -98,7 +98,6 @@ "stability": "stable", "maturity": "stable", "cdk-build": { - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } diff --git a/packages/@aws-cdk/pipelines/rosetta/default.ts-fixture b/packages/@aws-cdk/pipelines/rosetta/default.ts-fixture new file mode 100644 index 0000000000000..61a973840f007 --- /dev/null +++ b/packages/@aws-cdk/pipelines/rosetta/default.ts-fixture @@ -0,0 +1,29 @@ +// Fixture with packages imported, but nothing else +import { Construct, CfnOutput, Stage, Stack, StackProps, StageProps } from '@aws-cdk/core'; +import cdk = require('@aws-cdk/core'); +import codepipeline = require('@aws-cdk/aws-codepipeline'); +import cpactions = require('@aws-cdk/aws-codepipeline-actions'); +import codebuild = require('@aws-cdk/aws-codebuild'); +import codecommit = require('@aws-cdk/aws-codecommit'); +import dynamodb = require('@aws-cdk/aws-dynamodb'); +import ecr = require('@aws-cdk/aws-ecr'); +import ec2 = require('@aws-cdk/aws-ec2'); +import iam = require('@aws-cdk/aws-iam'); +import pipelines = require('@aws-cdk/pipelines'); +import secretsmanager = require('@aws-cdk/aws-secretsmanager'); +import sns = require('@aws-cdk/aws-sns'); +import subscriptions = require('@aws-cdk/aws-sns-subscriptions'); +import s3 = require('@aws-cdk/aws-s3'); + +class MyApplicationStage extends Stage { + constructor(scope: Construct, id: string, props?: StageProps) { + super(scope, id, props); + } +} + +class Fixture extends Stack { + constructor(scope: Construct, id: string) { + super(scope, id); + /// here + } +} diff --git a/packages/@aws-cdk/pipelines/test/codepipeline/codepipeline-existing.test.ts b/packages/@aws-cdk/pipelines/test/codepipeline/codepipeline-existing.test.ts new file mode 100644 index 0000000000000..09de231c8332c --- /dev/null +++ b/packages/@aws-cdk/pipelines/test/codepipeline/codepipeline-existing.test.ts @@ -0,0 +1,45 @@ +import * as codePipeline from '@aws-cdk/aws-codepipeline'; +import * as cdk from '@aws-cdk/core'; +import * as cdkp from '../../lib'; + +test('Does not allow setting a pipelineName if an existing CodePipeline is given', () => { + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'PipelineStack'); + const existingCodePipeline = new codePipeline.Pipeline(stack, 'CustomCodePipeline'); + + expect(() => { + new cdkp.CdkPipeline(stack, 'CDKPipeline', { + pipelineName: 'CustomPipelineName', + codePipeline: existingCodePipeline, + cloudAssemblyArtifact: new codePipeline.Artifact(), + }); + }).toThrow("Cannot set 'pipelineName' if an existing CodePipeline is given using 'codePipeline'"); +}); + +test('Does not allow enabling crossAccountKeys if an existing CodePipeline is given', () => { + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'PipelineStack'); + const existingCodePipeline = new codePipeline.Pipeline(stack, 'CustomCodePipeline'); + + expect(() => { + new cdkp.CdkPipeline(stack, 'CDKPipeline', { + crossAccountKeys: true, + codePipeline: existingCodePipeline, + cloudAssemblyArtifact: new codePipeline.Artifact(), + }); + }).toThrow("Cannot set 'crossAccountKeys' if an existing CodePipeline is given using 'codePipeline'"); +}); + +test('Does not allow enabling key rotation if an existing CodePipeline is given', () => { + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'PipelineStack'); + const existingCodePipeline = new codePipeline.Pipeline(stack, 'CustomCodePipeline'); + + expect(() => { + new cdkp.CdkPipeline(stack, 'CDKPipeline', { + enableKeyRotation: true, + codePipeline: existingCodePipeline, + cloudAssemblyArtifact: new codePipeline.Artifact(), + }); + }).toThrow("Cannot set 'enableKeyRotation' if an existing CodePipeline is given using 'codePipeline'"); +}); \ No newline at end of file diff --git a/packages/@aws-cdk/pipelines/test/integ.pipeline-security.expected.json b/packages/@aws-cdk/pipelines/test/integ.pipeline-security.expected.json index 82ad5c418fb70..b72a78754a1d2 100644 --- a/packages/@aws-cdk/pipelines/test/integ.pipeline-security.expected.json +++ b/packages/@aws-cdk/pipelines/test/integ.pipeline-security.expected.json @@ -1800,7 +1800,7 @@ ] }, "Handler": "index.handler", - "Runtime": "nodejs14.x", + "Runtime": "nodejs12.x", "Timeout": 300 }, "DependsOn": [ @@ -2111,7 +2111,7 @@ ] }, "Handler": "index.handler", - "Runtime": "nodejs14.x", + "Runtime": "nodejs12.x", "Timeout": 300 }, "DependsOn": [ diff --git a/packages/@aws-cdk/region-info/.eslintrc.js b/packages/@aws-cdk/region-info/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/region-info/.eslintrc.js +++ b/packages/@aws-cdk/region-info/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/region-info/jest.config.js b/packages/@aws-cdk/region-info/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/region-info/jest.config.js +++ b/packages/@aws-cdk/region-info/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/region-info/package.json b/packages/@aws-cdk/region-info/package.json index c86fae71c220a..a9e67db6c3be7 100644 --- a/packages/@aws-cdk/region-info/package.json +++ b/packages/@aws-cdk/region-info/package.json @@ -30,9 +30,6 @@ }, "projectReferences": true }, - "cdk-build": { - "jest": true - }, "scripts": { "gen": "bash build-tools/generate.sh", "build": "cdk-build", @@ -56,11 +53,11 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/fs-extra": "^8.1.2", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "fs-extra": "^9.1.0", - "pkglint": "0.0.0" + "fs-extra": "^9.1.0" }, "repository": { "url": "https://github.com/aws/aws-cdk.git", diff --git a/packages/@aws-cdk/yaml-cfn/.eslintrc.js b/packages/@aws-cdk/yaml-cfn/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/yaml-cfn/.eslintrc.js +++ b/packages/@aws-cdk/yaml-cfn/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/yaml-cfn/jest.config.js b/packages/@aws-cdk/yaml-cfn/jest.config.js index 19fd4653b47af..315f80405878f 100644 --- a/packages/@aws-cdk/yaml-cfn/jest.config.js +++ b/packages/@aws-cdk/yaml-cfn/jest.config.js @@ -1,4 +1,4 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = { ...baseConfig, }; diff --git a/packages/@aws-cdk/yaml-cfn/package.json b/packages/@aws-cdk/yaml-cfn/package.json index ed33f49235536..3a2a674586d84 100644 --- a/packages/@aws-cdk/yaml-cfn/package.json +++ b/packages/@aws-cdk/yaml-cfn/package.json @@ -69,19 +69,16 @@ "yaml": "1.10.2" }, "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", "@types/yaml": "^1.9.7", - "cdk-build-tools": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "jest": "^26.6.3" }, "bundledDependencies": [ "yaml" ], - "cdk-build": { - "jest": true - }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" }, diff --git a/packages/@monocdk-experiment/assert/.eslintrc.js b/packages/@monocdk-experiment/assert/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@monocdk-experiment/assert/.eslintrc.js +++ b/packages/@monocdk-experiment/assert/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@monocdk-experiment/assert/jest.config.js b/packages/@monocdk-experiment/assert/jest.config.js index 582b2b3040eb0..06408ea0581b8 100644 --- a/packages/@monocdk-experiment/assert/jest.config.js +++ b/packages/@monocdk-experiment/assert/jest.config.js @@ -1,4 +1,4 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = { ...baseConfig, coverageThreshold: { diff --git a/packages/@monocdk-experiment/assert/package.json b/packages/@monocdk-experiment/assert/package.json index fa3ae197cad03..4c6bff0534016 100644 --- a/packages/@monocdk-experiment/assert/package.json +++ b/packages/@monocdk-experiment/assert/package.json @@ -36,11 +36,11 @@ "@monocdk-experiment/rewrite-imports": "0.0.0", "@types/jest": "^26.0.24", "@types/node": "^10.17.60", - "cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", "constructs": "^3.3.69", "jest": "^26.6.3", "monocdk": "0.0.0", - "pkglint": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "ts-jest": "^26.5.6" }, "dependencies": { diff --git a/packages/@monocdk-experiment/rewrite-imports/.eslintrc.js b/packages/@monocdk-experiment/rewrite-imports/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@monocdk-experiment/rewrite-imports/.eslintrc.js +++ b/packages/@monocdk-experiment/rewrite-imports/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@monocdk-experiment/rewrite-imports/jest.config.js b/packages/@monocdk-experiment/rewrite-imports/jest.config.js index ac8c47076506a..6a8dc8ed67646 100644 --- a/packages/@monocdk-experiment/rewrite-imports/jest.config.js +++ b/packages/@monocdk-experiment/rewrite-imports/jest.config.js @@ -1,4 +1,4 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = { ...baseConfig, coverageThreshold: { diff --git a/packages/@monocdk-experiment/rewrite-imports/package.json b/packages/@monocdk-experiment/rewrite-imports/package.json index 71e1e67dbb146..7f602376d551a 100644 --- a/packages/@monocdk-experiment/rewrite-imports/package.json +++ b/packages/@monocdk-experiment/rewrite-imports/package.json @@ -19,9 +19,6 @@ "build+extract": "yarn build", "build+test+extract": "yarn build+test" }, - "cdk-build": { - "jest": true - }, "keywords": [ "aws", "cdk", @@ -34,15 +31,15 @@ }, "license": "Apache-2.0", "dependencies": { - "glob": "^7.1.7", + "glob": "^7.2.0", "typescript": "~3.9.10" }, "devDependencies": { "@types/glob": "^7.1.4", "@types/jest": "^26.0.24", "@types/node": "^10.17.60", - "cdk-build-tools": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0" }, "repository": { "type": "git", diff --git a/packages/aws-cdk-lib/.eslintrc.js b/packages/aws-cdk-lib/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/aws-cdk-lib/.eslintrc.js +++ b/packages/aws-cdk-lib/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/aws-cdk-lib/NOTICE b/packages/aws-cdk-lib/NOTICE index bf88ea022136c..df1053512a80b 100644 --- a/packages/aws-cdk-lib/NOTICE +++ b/packages/aws-cdk-lib/NOTICE @@ -806,4 +806,36 @@ The above copyright notice and this permission notice shall be included in all c THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----------------- \ No newline at end of file +---------------- + +** kubectl - https://github.com/kubernetes/kubectl +Copyright 2017 The Kubernetes Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +---------------- + +** helm - https://github.com/helm/helm +Copyright 2016 The Kubernetes Authors All Rights Reserved + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/packages/aws-cdk-lib/package.json b/packages/aws-cdk-lib/package.json index c4d46c68219d6..ad2aeeace6cd1 100644 --- a/packages/aws-cdk-lib/package.json +++ b/packages/aws-cdk-lib/package.json @@ -50,6 +50,10 @@ "jsii/java", "jsii/python", "jsii/dotnet" + ], + "attribution": [ + "kubectl", + "helm" ] }, "jsii": { @@ -115,8 +119,8 @@ "minimatch": "^3.0.4", "punycode": "^2.1.1", "semver": "^7.3.5", - "string-width": "^4.2.2", - "table": "^6.7.1", + "string-width": "^4.2.3", + "table": "^6.7.2", "yaml": "1.10.2" }, "devDependencies": { @@ -141,6 +145,7 @@ "@aws-cdk/aws-apprunner": "0.0.0", "@aws-cdk/aws-appstream": "0.0.0", "@aws-cdk/aws-appsync": "0.0.0", + "@aws-cdk/aws-aps": "0.0.0", "@aws-cdk/aws-athena": "0.0.0", "@aws-cdk/aws-auditmanager": "0.0.0", "@aws-cdk/aws-autoscaling": "0.0.0", @@ -221,6 +226,7 @@ "@aws-cdk/aws-greengrassv2": "0.0.0", "@aws-cdk/aws-groundstation": "0.0.0", "@aws-cdk/aws-guardduty": "0.0.0", + "@aws-cdk/aws-healthlake": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-imagebuilder": "0.0.0", "@aws-cdk/aws-inspector": "0.0.0", @@ -249,6 +255,7 @@ "@aws-cdk/aws-lambda-nodejs": "0.0.0", "@aws-cdk/aws-lambda-python": "0.0.0", "@aws-cdk/aws-licensemanager": "0.0.0", + "@aws-cdk/aws-lightsail": "0.0.0", "@aws-cdk/aws-location": "0.0.0", "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-logs-destinations": "0.0.0", @@ -262,6 +269,7 @@ "@aws-cdk/aws-medialive": "0.0.0", "@aws-cdk/aws-mediapackage": "0.0.0", "@aws-cdk/aws-mediastore": "0.0.0", + "@aws-cdk/aws-memorydb": "0.0.0", "@aws-cdk/aws-msk": "0.0.0", "@aws-cdk/aws-mwaa": "0.0.0", "@aws-cdk/aws-neptune": "0.0.0", @@ -320,6 +328,7 @@ "@aws-cdk/aws-wafv2": "0.0.0", "@aws-cdk/aws-workspaces": "0.0.0", "@aws-cdk/aws-xray": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cloud-assembly-schema": "0.0.0", "@aws-cdk/cloudformation-include": "0.0.0", "@aws-cdk/core": "0.0.0", @@ -327,17 +336,17 @@ "@aws-cdk/cx-api": "0.0.0", "@aws-cdk/lambda-layer-awscli": "0.0.0", "@aws-cdk/lambda-layer-kubectl": "0.0.0", + "@aws-cdk/lambda-layer-node-proxy-agent": "0.0.0", "@aws-cdk/pipelines": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@aws-cdk/region-info": "0.0.0", + "@aws-cdk/ubergen": "0.0.0", "@types/fs-extra": "^8.1.2", "@types/node": "^10.17.60", - "cdk-build-tools": "0.0.0", "constructs": "^3.3.69", "fs-extra": "^9.1.0", - "pkglint": "0.0.0", "ts-node": "^9.1.1", - "typescript": "~3.8.3", - "ubergen": "0.0.0" + "typescript": "~3.8.3" }, "peerDependencies": { "constructs": "^3.3.69" diff --git a/packages/aws-cdk-lib/scripts/verify-stripped-exp.ts b/packages/aws-cdk-lib/scripts/verify-stripped-exp.ts index 10e3da07b7f4d..6398852975c05 100644 --- a/packages/aws-cdk-lib/scripts/verify-stripped-exp.ts +++ b/packages/aws-cdk-lib/scripts/verify-stripped-exp.ts @@ -30,7 +30,7 @@ async function main(tempDir: string) { if (pkgJson.stability !== 'experimental') { continue; } - if (pkgJson['cdk-build'].cloudformation) { + if (pkgJson['cdk-build']?.cloudformation) { // if a cfn module, verify only the allowed files exists const files = await listAllFiles(path.join(installedAwsCdkLibPath, module)); const invalidFiles = new Array(); diff --git a/packages/aws-cdk-migration/.eslintrc.js b/packages/aws-cdk-migration/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/aws-cdk-migration/.eslintrc.js +++ b/packages/aws-cdk-migration/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/aws-cdk-migration/jest.config.js b/packages/aws-cdk-migration/jest.config.js index ac8c47076506a..6a8dc8ed67646 100644 --- a/packages/aws-cdk-migration/jest.config.js +++ b/packages/aws-cdk-migration/jest.config.js @@ -1,4 +1,4 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = { ...baseConfig, coverageThreshold: { diff --git a/packages/aws-cdk-migration/lib/rewrite.ts b/packages/aws-cdk-migration/lib/rewrite.ts index 970627e361aa2..2e17dfcb08130 100644 --- a/packages/aws-cdk-migration/lib/rewrite.ts +++ b/packages/aws-cdk-migration/lib/rewrite.ts @@ -8,6 +8,21 @@ export interface RewriteOptions { * Optional module names that should result in replacing to something different than just 'aws-cdk-lib'. */ readonly customModules?: { [moduleName: string]: string }; + + /** + * When true, this will rewrite imports of generated L1s to reference aws-cdk-lib. + * + * For example: + * import * as codestar from './codestar.generated';` + * becomes: + * import * as codestar from 'aws-cdk-lib/aws-codestar'; + */ + readonly rewriteCfnImports?: boolean; + + /** + * The unscoped name of the package, e.g. 'aws-kinesisfirehose'. + */ + readonly packageUnscopedName?: string; } /** @@ -38,7 +53,7 @@ export function rewriteImports(sourceText: string, fileName: string = 'index.ts' const visitor = (node: T): ts.VisitResult => { const moduleSpecifier = getModuleSpecifier(node); - const newTarget = moduleSpecifier && updatedLocationOf(moduleSpecifier.text, options); + const newTarget = moduleSpecifier && updatedLocationOf(moduleSpecifier.text, options, getImportedElements(node)); if (moduleSpecifier != null && newTarget != null) { replacements.push({ original: moduleSpecifier, updatedLocation: newTarget }); @@ -60,6 +75,14 @@ export function rewriteImports(sourceText: string, fileName: string = 'index.ts' return updatedSourceText; + /** + * Returns the module specifier (location) of an import statement in one of the following forms: + * import from 'location'; + * import * as name from 'location'; + * import { Type } = require('location'); + * import name = require('location'); + * require('location'); + */ function getModuleSpecifier(node: ts.Node): ts.StringLiteral | undefined { if (ts.isImportDeclaration(node)) { // import style @@ -100,15 +123,40 @@ export function rewriteImports(sourceText: string, fileName: string = 'index.ts' const EXEMPTIONS = new Set([ '@aws-cdk/cloudformation-diff', + // The dev-tools + '@aws-cdk/cdk-build-tools', + '@aws-cdk/cdk-integ-tools', + '@aws-cdk/cfn2ts', + '@aws-cdk/eslint-plugin', + '@aws-cdk/pkglint', ]); -function updatedLocationOf(modulePath: string, options: RewriteOptions): string | undefined { +function updatedLocationOf(modulePath: string, options: RewriteOptions, importedElements?: ts.NodeArray): string | undefined { const customModulePath = options.customModules?.[modulePath]; if (customModulePath) { + let awsCdkLibLocation = undefined; + importedElements?.forEach(e => { + if (e.name.text.startsWith('Cfn') || e.propertyName?.text.startsWith('Cfn')) { + // This is an L1 import, so don't return the customModulePath (which is the alpha module). + // Return the relevant aws-cdk-lib location. + awsCdkLibLocation = `aws-cdk-lib/${modulePath.substring('@aws-cdk/'.length)}`; + } + }); + if (awsCdkLibLocation) { + return awsCdkLibLocation; + } return customModulePath; } - if (!modulePath.startsWith('@aws-cdk/') || EXEMPTIONS.has(modulePath)) { + if (options.rewriteCfnImports && modulePath.endsWith(`${options.packageUnscopedName?.substr('aws-'.length)}.generated`)) { + return `aws-cdk-lib/${options.packageUnscopedName}`; + } + + if ( + !modulePath.startsWith('@aws-cdk/') + || EXEMPTIONS.has(modulePath) + || Array.from(EXEMPTIONS).some((ex) => modulePath.startsWith(`${ex}/`)) + ) { return undefined; } @@ -135,5 +183,22 @@ function updatedLocationOf(modulePath: string, options: RewriteOptions): string return '@aws-cdk/assert/jest'; } - return `aws-cdk-lib/${modulePath.substring(9)}`; + return `aws-cdk-lib/${modulePath.substring('@aws-cdk/'.length)}`; +} + +/** + * Returns the names of all types imported via named imports of the form: + * import { Type } from 'location' + */ +function getImportedElements(node: ts.Node): ts.NodeArray | undefined { + if ( + ts.isImportDeclaration(node) + && ts.isStringLiteral(node.moduleSpecifier) + && node.importClause + && node.importClause.namedBindings + && ts.isNamedImports(node.importClause.namedBindings) + ) { + return node.importClause.namedBindings.elements; + } + return undefined; } diff --git a/packages/aws-cdk-migration/package.json b/packages/aws-cdk-migration/package.json index 714dd26493897..1ce16c5670458 100644 --- a/packages/aws-cdk-migration/package.json +++ b/packages/aws-cdk-migration/package.json @@ -34,15 +34,15 @@ }, "license": "Apache-2.0", "dependencies": { - "glob": "^7.1.7", + "glob": "^7.2.0", "typescript": "~3.9.10" }, "devDependencies": { "@types/glob": "^7.1.4", "@types/jest": "^26.0.24", "@types/node": "^10.17.60", - "cdk-build-tools": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0" }, "repository": { "type": "git", diff --git a/packages/aws-cdk-migration/test/rewrite.test.ts b/packages/aws-cdk-migration/test/rewrite.test.ts index f9ff8b247d6ce..d4b5c919f5f53 100644 --- a/packages/aws-cdk-migration/test/rewrite.test.ts +++ b/packages/aws-cdk-migration/test/rewrite.test.ts @@ -88,4 +88,52 @@ describe(rewriteImports, () => { console.log('Look! I did something!');`); }); + + test('correctly rewrites Cfn imports', () => { + // Codestar example + const codestar = rewriteImports(` + // something before + import * as codestar from './codestar.generated'; + import { CfnY } from '../codestar.generated'; + import { CfnX } from '../lib/codestar.generated'; + // something after + + console.log('Look! I did something!');`, 'subject.ts', { + rewriteCfnImports: true, + packageUnscopedName: 'aws-codestar', + }); + + expect(codestar).toBe(` + // something before + import * as codestar from 'aws-cdk-lib/aws-codestar'; + import { CfnY } from 'aws-cdk-lib/aws-codestar'; + import { CfnX } from 'aws-cdk-lib/aws-codestar'; + // something after + + console.log('Look! I did something!');`); + }); + + test('correctly rewrites Cfn imports from an alpha module', () => { + const customModules = { + '@aws-cdk/aws-kinesisfirehose': 'aws-kinesisfirehose-alpha', + }; + const output = rewriteImports(` + // something before + import * as firehose from '@aws-cdk/aws-kinesisfirehose'; + import { CfnDeliveryStream } from '@aws-cdk/aws-kinesisfirehose'; + // something after + + console.log('Look! I did something!');`, 'subject.ts', { + rewriteCfnImports: true, + customModules: customModules, + }); + + expect(output).toBe(` + // something before + import * as firehose from 'aws-kinesisfirehose-alpha'; + import { CfnDeliveryStream } from 'aws-cdk-lib/aws-kinesisfirehose'; + // something after + + console.log('Look! I did something!');`); + }); }); diff --git a/packages/aws-cdk/.eslintrc.js b/packages/aws-cdk/.eslintrc.js index b5e0934b9d544..b5ea7218b5f48 100644 --- a/packages/aws-cdk/.eslintrc.js +++ b/packages/aws-cdk/.eslintrc.js @@ -1,4 +1,4 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.ignorePatterns.push('lib/init-templates/**/typescript/**/*.ts'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/aws-cdk/README.md b/packages/aws-cdk/README.md index 3a1b2882b2506..e4566b7bbb690 100644 --- a/packages/aws-cdk/README.md +++ b/packages/aws-cdk/README.md @@ -362,6 +362,8 @@ Hotswapping is currently supported for the following changes (additional changes will be supported in the future): - Code asset changes of AWS Lambda functions. +- Definition changes of AWS Step Functions State Machines. +- Container asset changes of AWS ECS Services. **⚠ Note #1**: This command deliberately introduces drift in CloudFormation stacks in order to speed up deployments. For this reason, only use it for development purposes. diff --git a/packages/aws-cdk/jest.config.js b/packages/aws-cdk/jest.config.js index 72f278bd0ba52..292f68b459252 100644 --- a/packages/aws-cdk/jest.config.js +++ b/packages/aws-cdk/jest.config.js @@ -1,4 +1,4 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = { ...baseConfig, coverageThreshold: { diff --git a/packages/aws-cdk/lib/api/aws-auth/sdk-provider.ts b/packages/aws-cdk/lib/api/aws-auth/sdk-provider.ts index d06fba8a59529..4621d171bc357 100644 --- a/packages/aws-cdk/lib/api/aws-auth/sdk-provider.ts +++ b/packages/aws-cdk/lib/api/aws-auth/sdk-provider.ts @@ -374,48 +374,35 @@ function parseHttpOptions(options: SdkHttpOptions) { } config.customUserAgent = userAgent; - const proxyAddress = options.proxyAddress || httpsProxyFromEnvironment(); const caBundlePath = options.caBundlePath || caBundlePathFromEnvironment(); - if (proxyAddress && caBundlePath) { - throw new Error(`At the moment, cannot specify Proxy (${proxyAddress}) and CA Bundle (${caBundlePath}) at the same time. See https://github.com/aws/aws-cdk/issues/5804`); + if (options.proxyAddress && caBundlePath) { + throw new Error(`At the moment, cannot specify Proxy (${options.proxyAddress}) and CA Bundle (${caBundlePath}) at the same time. See https://github.com/aws/aws-cdk/issues/5804`); // Maybe it's possible after all, but I've been staring at // https://github.com/TooTallNate/node-proxy-agent/blob/master/index.js#L79 // a while now trying to figure out what to pass in so that the underlying Agent // object will get the 'ca' argument. It's not trivial and I don't want to risk it. } - if (proxyAddress) { // Ignore empty string on purpose - // https://aws.amazon.com/blogs/developer/using-the-aws-sdk-for-javascript-from-behind-a-proxy/ - debug('Using proxy server: %s', proxyAddress); - // eslint-disable-next-line @typescript-eslint/no-require-imports - const ProxyAgent: any = require('proxy-agent'); - config.httpOptions.agent = new ProxyAgent(proxyAddress); - } if (caBundlePath) { debug('Using CA bundle path: %s', caBundlePath); config.httpOptions.agent = new https.Agent({ ca: readIfPossible(caBundlePath), keepAlive: true, }); + } else { + // Configure the proxy agent. By default, this will use HTTPS?_PROXY and + // NO_PROXY environment variables to determine which proxy to use for each + // request. + // + // eslint-disable-next-line @typescript-eslint/no-require-imports + const ProxyAgent: any = require('proxy-agent'); + config.httpOptions.agent = new ProxyAgent(); } return config; } -/** - * Find and return the configured HTTPS proxy address - */ -function httpsProxyFromEnvironment(): string | undefined { - if (process.env.https_proxy) { - return process.env.https_proxy; - } - if (process.env.HTTPS_PROXY) { - return process.env.HTTPS_PROXY; - } - return undefined; -} - /** * Find and return a CA certificate bundle path to be passed into the SDK. */ diff --git a/packages/aws-cdk/lib/api/aws-auth/sdk.ts b/packages/aws-cdk/lib/api/aws-auth/sdk.ts index 0f1468b4d08b8..91fcdc2fede7d 100644 --- a/packages/aws-cdk/lib/api/aws-auth/sdk.ts +++ b/packages/aws-cdk/lib/api/aws-auth/sdk.ts @@ -29,9 +29,11 @@ export interface ISDK { s3(): AWS.S3; route53(): AWS.Route53; ecr(): AWS.ECR; + ecs(): AWS.ECS; elbv2(): AWS.ELBv2; secretsManager(): AWS.SecretsManager; kms(): AWS.KMS; + stepFunctions(): AWS.StepFunctions; } /** @@ -116,6 +118,10 @@ export class SDK implements ISDK { return this.wrapServiceErrorHandling(new AWS.ECR(this.config)); } + public ecs(): AWS.ECS { + return this.wrapServiceErrorHandling(new AWS.ECS(this.config)); + } + public elbv2(): AWS.ELBv2 { return this.wrapServiceErrorHandling(new AWS.ELBv2(this.config)); } @@ -128,6 +134,10 @@ export class SDK implements ISDK { return this.wrapServiceErrorHandling(new AWS.KMS(this.config)); } + public stepFunctions(): AWS.StepFunctions { + return this.wrapServiceErrorHandling(new AWS.StepFunctions(this.config)); + } + public async currentAccount(): Promise { // Get/refresh if necessary before we can access `accessKeyId` await this.forceCredentialRetrieval(); diff --git a/packages/aws-cdk/lib/api/deploy-stack.ts b/packages/aws-cdk/lib/api/deploy-stack.ts index b0770ebdf8ea7..f58f441560e3e 100644 --- a/packages/aws-cdk/lib/api/deploy-stack.ts +++ b/packages/aws-cdk/lib/api/deploy-stack.ts @@ -10,6 +10,7 @@ import { publishAssets } from '../util/asset-publishing'; import { contentHash } from '../util/content-hash'; import { ISDK, SdkProvider } from './aws-auth'; import { tryHotswapDeployment } from './hotswap-deployments'; +import { CfnEvaluationException } from './hotswap/evaluate-cloudformation-template'; import { ToolkitInfo } from './toolkit-info'; import { changeSetHasNoChanges, CloudFormationStack, TemplateParameters, waitForChangeSet, @@ -252,15 +253,22 @@ export async function deployStack(options: DeployStackOptions): Promise { - const currentTemplate = await cloudFormationStack.template(); - const stackChanges = cfn_diff.diffTemplate(currentTemplate, stackArtifact.template); - // resolve the environment, so we can substitute things like AWS::Region in CFN expressions const resolvedEnv = await sdkProvider.resolveEnvironment(stackArtifact.environment); - const hotswappableChanges = findAllHotswappableChanges(stackChanges, { - ...assetParams, - 'AWS::Region': resolvedEnv.region, - 'AWS::AccountId': resolvedEnv.account, + // create a new SDK using the CLI credentials, because the default one will not work for new-style synthesis - + // it assumes the bootstrap deploy Role, which doesn't have permissions to update Lambda functions + const sdk = await sdkProvider.forEnvironment(resolvedEnv, Mode.ForWriting); + // The current resources of the Stack. + // We need them to figure out the physical name of a resource in case it wasn't specified by the user. + // We fetch it lazily, to save a service call, in case all hotswapped resources have their physical names set. + const listStackResources = new LazyListStackResources(sdk, stackArtifact.stackName); + const evaluateCfnTemplate = new EvaluateCloudFormationTemplate({ + stackArtifact, + parameters: assetParams, + account: resolvedEnv.account, + region: resolvedEnv.region, + // ToDo make this better: + partition: 'aws', + // ToDo make this better: + urlSuffix: 'amazonaws.com', + listStackResources, }); + + const currentTemplate = await cloudFormationStack.template(); + const stackChanges = cfn_diff.diffTemplate(currentTemplate, stackArtifact.template); + const hotswappableChanges = await findAllHotswappableChanges(stackChanges, evaluateCfnTemplate); if (!hotswappableChanges) { // this means there were changes to the template that cannot be short-circuited return undefined; } - // create a new SDK using the CLI credentials, because the default one will not work for new-style synthesis - - // it assumes the bootstrap deploy Role, which doesn't have permissions to update Lambda functions - const sdk = await sdkProvider.forEnvironment(resolvedEnv, Mode.ForWriting); // apply the short-circuitable changes - await applyAllHotswappableChanges(sdk, stackArtifact, hotswappableChanges); + await applyAllHotswappableChanges(sdk, hotswappableChanges); return { noOp: hotswappableChanges.length === 0, stackArn: cloudFormationStack.stackId, outputs: cloudFormationStack.outputs, stackArtifact }; } -function findAllHotswappableChanges( - stackChanges: cfn_diff.TemplateDiff, assetParamsWithEnv: { [key: string]: string }, -): HotswapOperation[] | undefined { - const hotswappableResources = new Array(); +async function findAllHotswappableChanges( + stackChanges: cfn_diff.TemplateDiff, evaluateCfnTemplate: EvaluateCloudFormationTemplate, +): Promise { let foundNonHotswappableChange = false; + const promises: Array>> = []; + + // gather the results of the detector functions stackChanges.resources.forEachDifference((logicalId: string, change: cfn_diff.ResourceDifference) => { - const lambdaFunctionShortCircuitChange = isHotswappableLambdaFunctionChange(logicalId, change, assetParamsWithEnv); - if (lambdaFunctionShortCircuitChange === ChangeHotswapImpact.REQUIRES_FULL_DEPLOYMENT) { + const resourceHotswapEvaluation = isCandidateForHotswapping(change); + + if (resourceHotswapEvaluation === ChangeHotswapImpact.REQUIRES_FULL_DEPLOYMENT) { foundNonHotswappableChange = true; - } else if (lambdaFunctionShortCircuitChange === ChangeHotswapImpact.IRRELEVANT) { + } else if (resourceHotswapEvaluation === ChangeHotswapImpact.IRRELEVANT) { // empty 'if' just for flow-aware typing to kick in... } else { - hotswappableResources.push(lambdaFunctionShortCircuitChange); + promises.push([ + isHotswappableLambdaFunctionChange(logicalId, resourceHotswapEvaluation, evaluateCfnTemplate), + isHotswappableStateMachineChange(logicalId, resourceHotswapEvaluation, evaluateCfnTemplate), + isHotswappableEcsServiceChange(logicalId, resourceHotswapEvaluation, evaluateCfnTemplate), + ]); } }); + + const changesDetectionResults: Array> = []; + for (const detectorResultPromises of promises) { + const hotswapDetectionResults = await Promise.all(detectorResultPromises); + changesDetectionResults.push(hotswapDetectionResults); + } + + const hotswappableResources = new Array(); + + // resolve all detector results + for (const hotswapDetectionResults of changesDetectionResults) { + const perChangeHotswappableResources = new Array(); + + for (const result of hotswapDetectionResults) { + if (typeof result !== 'string') { + perChangeHotswappableResources.push(result); + } + } + + // if we found any hotswappable changes, return now + if (perChangeHotswappableResources.length > 0) { + hotswappableResources.push(...perChangeHotswappableResources); + continue; + } + + // no hotswappable changes found, so any REQUIRES_FULL_DEPLOYMENTs imply a non-hotswappable change + for (const result of hotswapDetectionResults) { + if (result === ChangeHotswapImpact.REQUIRES_FULL_DEPLOYMENT) { + foundNonHotswappableChange = true; + } + } + // no REQUIRES_FULL_DEPLOYMENT implies that all results are IRRELEVANT + } + return foundNonHotswappableChange ? undefined : hotswappableResources; } +/** + * returns `ChangeHotswapImpact.REQUIRES_FULL_DEPLOYMENT` if a resource was deleted, or a change that we cannot short-circuit occured. + * Returns `ChangeHotswapImpact.IRRELEVANT` if a change that does not impact shortcircuiting occured, such as a metadata change. + */ +export function isCandidateForHotswapping(change: cfn_diff.ResourceDifference): HotswappableChangeCandidate | ChangeHotswapImpact { + // a resource has been removed OR a resource has been added; we can't short-circuit that change + if (!change.newValue || !change.oldValue) { + return ChangeHotswapImpact.REQUIRES_FULL_DEPLOYMENT; + } + + // Ignore Metadata changes + if (change.newValue.Type === 'AWS::CDK::Metadata') { + return ChangeHotswapImpact.IRRELEVANT; + } + + return { + newValue: change.newValue, + propertyUpdates: change.propertyUpdates, + }; +} + async function applyAllHotswappableChanges( - sdk: ISDK, stackArtifact: cxapi.CloudFormationStackArtifact, hotswappableChanges: HotswapOperation[], + sdk: ISDK, hotswappableChanges: HotswapOperation[], ): Promise { - // The current resources of the Stack. - // We need them to figure out the physical name of a function in case it wasn't specified by the user. - // We fetch it lazily, to save a service call, in case all updated Lambdas have their names set. - const listStackResources = new LazyListStackResources(sdk, stackArtifact.stackName); - - return Promise.all(hotswappableChanges.map(hotswapOperation => hotswapOperation.apply(sdk, listStackResources))); + return Promise.all(hotswappableChanges.map(hotswapOperation => { + return hotswapOperation.apply(sdk); + })); } class LazyListStackResources implements ListStackResources { @@ -79,12 +152,12 @@ class LazyListStackResources implements ListStackResources { async listStackResources(): Promise { if (this.stackResources === undefined) { - this.stackResources = await this.getStackResource(); + this.stackResources = await this.getStackResources(); } return this.stackResources; } - private async getStackResource(): Promise { + private async getStackResources(): Promise { const ret = new Array(); let nextToken: string | undefined; do { diff --git a/packages/aws-cdk/lib/api/hotswap/common.ts b/packages/aws-cdk/lib/api/hotswap/common.ts index d509c32b4c781..1e482d112aef4 100644 --- a/packages/aws-cdk/lib/api/hotswap/common.ts +++ b/packages/aws-cdk/lib/api/hotswap/common.ts @@ -1,7 +1,7 @@ import * as cfn_diff from '@aws-cdk/cloudformation-diff'; import { CloudFormation } from 'aws-sdk'; import { ISDK } from '../aws-auth'; -import { evaluateCfn } from '../util/cloudformation/evaluate-cfn'; +import { CfnEvaluationException, EvaluateCloudFormationTemplate } from './evaluate-cloudformation-template'; export interface ListStackResources { listStackResources(): Promise; @@ -11,7 +11,7 @@ export interface ListStackResources { * An interface that represents a change that can be deployed in a short-circuit manner. */ export interface HotswapOperation { - apply(sdk: ISDK, stackResources: ListStackResources): Promise; + apply(sdk: ISDK): Promise; } /** @@ -35,23 +35,42 @@ export enum ChangeHotswapImpact { export type ChangeHotswapResult = HotswapOperation | ChangeHotswapImpact; /** - * For old-style synthesis which uses CFN Parameters, - * the Code properties can have the values of complex CFN expressions. - * For new-style synthesis of env-agnostic stacks, - * the Fn::Sub expression is used for the Asset bucket. - * Evaluate the CFN expressions to concrete string values which we need for the - * updateFunctionCode() service call. + * Represents a change that can be hotswapped. */ -export function stringifyPotentialCfnExpression(value: any, assetParamsWithEnv: { [key: string]: string }): string { - // if we already have a string, nothing to do - if (value == null || typeof value === 'string') { - return value; +export class HotswappableChangeCandidate { + /** + * The value the resource is being updated to. + */ + public readonly newValue: cfn_diff.Resource; + + /** + * The changes made to the resource properties. + */ + public readonly propertyUpdates: { [key: string]: cfn_diff.PropertyDifference }; + + public constructor(newValue: cfn_diff.Resource, propertyUpdates: { [key: string]: cfn_diff.PropertyDifference }) { + this.newValue = newValue; + this.propertyUpdates = propertyUpdates; } +} - // otherwise, we assume this is a CloudFormation expression that we need to evaluate - return evaluateCfn(value, assetParamsWithEnv); +export async function establishResourcePhysicalName( + logicalId: string, physicalNameInCfnTemplate: any, evaluateCfnTemplate: EvaluateCloudFormationTemplate, +): Promise { + if (physicalNameInCfnTemplate != null) { + try { + return await evaluateCfnTemplate.evaluateCfnExpression(physicalNameInCfnTemplate); + } catch (e) { + // If we can't evaluate the resource's name CloudFormation expression, + // just look it up in the currently deployed Stack + if (!(e instanceof CfnEvaluationException)) { + throw e; + } + } + } + return evaluateCfnTemplate.findPhysicalNameFor(logicalId); } -export function assetMetadataChanged(change: cfn_diff.ResourceDifference): boolean { +export function assetMetadataChanged(change: HotswappableChangeCandidate): boolean { return !!change.newValue?.Metadata['aws:asset:path']; } diff --git a/packages/aws-cdk/lib/api/hotswap/ecs-services.ts b/packages/aws-cdk/lib/api/hotswap/ecs-services.ts new file mode 100644 index 0000000000000..f5bb06b7255c1 --- /dev/null +++ b/packages/aws-cdk/lib/api/hotswap/ecs-services.ts @@ -0,0 +1,187 @@ +import * as AWS from 'aws-sdk'; +import { ISDK } from '../aws-auth'; +import { ChangeHotswapImpact, ChangeHotswapResult, establishResourcePhysicalName, HotswapOperation, HotswappableChangeCandidate } from './common'; +import { EvaluateCloudFormationTemplate } from './evaluate-cloudformation-template'; + +export async function isHotswappableEcsServiceChange( + logicalId: string, change: HotswappableChangeCandidate, evaluateCfnTemplate: EvaluateCloudFormationTemplate, +): Promise { + // the only resource change we should allow is an ECS TaskDefinition + if (change.newValue.Type !== 'AWS::ECS::TaskDefinition') { + return ChangeHotswapImpact.REQUIRES_FULL_DEPLOYMENT; + } + + for (const updatedPropName in change.propertyUpdates) { + // We only allow a change in the ContainerDefinitions of the TaskDefinition for now - + // it contains the image and environment variables, so seems like a safe bet for now. + // We might revisit this decision in the future though! + if (updatedPropName !== 'ContainerDefinitions') { + return ChangeHotswapImpact.REQUIRES_FULL_DEPLOYMENT; + } + const containerDefinitionsDifference = (change.propertyUpdates)[updatedPropName]; + if (containerDefinitionsDifference.newValue === undefined) { + return ChangeHotswapImpact.REQUIRES_FULL_DEPLOYMENT; + } + } + // at this point, we know the TaskDefinition can be hotswapped + + // find all ECS Services that reference the TaskDefinition that changed + const resourcesReferencingTaskDef = evaluateCfnTemplate.findReferencesTo(logicalId); + const ecsServiceResourcesReferencingTaskDef = resourcesReferencingTaskDef.filter(r => r.Type === 'AWS::ECS::Service'); + const ecsServicesReferencingTaskDef = new Array(); + for (const ecsServiceResource of ecsServiceResourcesReferencingTaskDef) { + const serviceArn = await evaluateCfnTemplate.findPhysicalNameFor(ecsServiceResource.LogicalId); + if (serviceArn) { + ecsServicesReferencingTaskDef.push({ serviceArn }); + } + } + if (ecsServicesReferencingTaskDef.length === 0 || + resourcesReferencingTaskDef.length > ecsServicesReferencingTaskDef.length) { + // if there are either no resources referencing the TaskDefinition, + // or something besides an ECS Service is referencing it, + // hotswap is not possible + return ChangeHotswapImpact.REQUIRES_FULL_DEPLOYMENT; + } + + const taskDefinitionResource = change.newValue.Properties; + // first, let's get the name of the family + const familyNameOrArn = await establishResourcePhysicalName(logicalId, taskDefinitionResource?.Family, evaluateCfnTemplate); + if (!familyNameOrArn) { + // if the Family property has not bee provided, and we can't find it in the current Stack, + // this means hotswapping is not possible + return ChangeHotswapImpact.REQUIRES_FULL_DEPLOYMENT; + } + // the physical name of the Task Definition in CloudFormation includes its current revision number at the end, + // remove it if needed + const familyNameOrArnParts = familyNameOrArn.split(':'); + const family = familyNameOrArnParts.length > 1 + // familyNameOrArn is actually an ARN, of the format 'arn:aws:ecs:region:account:task-definition/:' + // so, take the 6th element, at index 5, and split it on '/' + ? familyNameOrArnParts[5].split('/')[1] + // otherwise, familyNameOrArn is just the simple name evaluated from the CloudFormation template + : familyNameOrArn; + // then, let's evaluate the body of the remainder of the TaskDef (without the Family property) + const evaluatedTaskDef = { + ...await evaluateCfnTemplate.evaluateCfnExpression({ + ...(taskDefinitionResource ?? {}), + Family: undefined, + }), + Family: family, + }; + return new EcsServiceHotswapOperation(evaluatedTaskDef, ecsServicesReferencingTaskDef); +} + +interface EcsService { + readonly serviceArn: string; +} + +class EcsServiceHotswapOperation implements HotswapOperation { + constructor( + private readonly taskDefinitionResource: any, + private readonly servicesReferencingTaskDef: EcsService[], + ) {} + + public async apply(sdk: ISDK): Promise { + // Step 1 - update the changed TaskDefinition, creating a new TaskDefinition Revision + // we need to lowercase the evaluated TaskDef from CloudFormation, + // as the AWS SDK uses lowercase property names for these + const lowercasedTaskDef = lowerCaseFirstCharacterOfObjectKeys(this.taskDefinitionResource); + const registerTaskDefResponse = await sdk.ecs().registerTaskDefinition(lowercasedTaskDef).promise(); + const taskDefRevArn = registerTaskDefResponse.taskDefinition?.taskDefinitionArn; + + // Step 2 - update the services using that TaskDefinition to point to the new TaskDefinition Revision + const servicePerClusterUpdates: { [cluster: string]: Array<{ promise: Promise, ecsService: EcsService }> } = {}; + for (const ecsService of this.servicesReferencingTaskDef) { + const clusterName = ecsService.serviceArn.split('/')[1]; + + const existingClusterPromises = servicePerClusterUpdates[clusterName]; + let clusterPromises: Array<{ promise: Promise, ecsService: EcsService }>; + if (existingClusterPromises) { + clusterPromises = existingClusterPromises; + } else { + clusterPromises = []; + servicePerClusterUpdates[clusterName] = clusterPromises; + } + + clusterPromises.push({ + promise: sdk.ecs().updateService({ + service: ecsService.serviceArn, + taskDefinition: taskDefRevArn, + cluster: clusterName, + forceNewDeployment: true, + deploymentConfiguration: { + minimumHealthyPercent: 0, + }, + }).promise(), + ecsService: ecsService, + }); + } + await Promise.all(Object.values(servicePerClusterUpdates) + .map(clusterUpdates => { + return Promise.all(clusterUpdates.map(serviceUpdate => serviceUpdate.promise)); + }), + ); + + // Step 3 - wait for the service deployments triggered in Step 2 to finish + // configure a custom Waiter + (sdk.ecs() as any).api.waiters.deploymentToFinish = { + name: 'DeploymentToFinish', + operation: 'describeServices', + delay: 10, + maxAttempts: 60, + acceptors: [ + { + matcher: 'pathAny', + argument: 'failures[].reason', + expected: 'MISSING', + state: 'failure', + }, + { + matcher: 'pathAny', + argument: 'services[].status', + expected: 'DRAINING', + state: 'failure', + }, + { + matcher: 'pathAny', + argument: 'services[].status', + expected: 'INACTIVE', + state: 'failure', + }, + { + matcher: 'path', + argument: "length(services[].deployments[? status == 'PRIMARY' && runningCount < desiredCount][]) == `0`", + expected: true, + state: 'success', + }, + ], + }; + // create a custom Waiter that uses the deploymentToFinish configuration added above + const deploymentWaiter = new (AWS as any).ResourceWaiter(sdk.ecs(), 'deploymentToFinish'); + // wait for all of the waiters to finish + return Promise.all(Object.entries(servicePerClusterUpdates).map(([clusterName, serviceUpdates]) => { + return deploymentWaiter.wait({ + cluster: clusterName, + services: serviceUpdates.map(serviceUpdate => serviceUpdate.ecsService.serviceArn), + }).promise(); + })); + } +} + +function lowerCaseFirstCharacterOfObjectKeys(val: any): any { + if (val == null || typeof val !== 'object') { + return val; + } + if (Array.isArray(val)) { + return val.map(lowerCaseFirstCharacterOfObjectKeys); + } + const ret: { [k: string]: any; } = {}; + for (const [k, v] of Object.entries(val)) { + ret[lowerCaseFirstCharacter(k)] = lowerCaseFirstCharacterOfObjectKeys(v); + } + return ret; +} + +function lowerCaseFirstCharacter(str: string): string { + return str.length > 0 ? `${str[0].toLowerCase()}${str.substr(1)}` : str; +} diff --git a/packages/aws-cdk/lib/api/hotswap/evaluate-cloudformation-template.ts b/packages/aws-cdk/lib/api/hotswap/evaluate-cloudformation-template.ts new file mode 100644 index 0000000000000..59d8d7df19445 --- /dev/null +++ b/packages/aws-cdk/lib/api/hotswap/evaluate-cloudformation-template.ts @@ -0,0 +1,299 @@ +import * as cxapi from '@aws-cdk/cx-api'; +import * as AWS from 'aws-sdk'; +import { ListStackResources } from './common'; + +export class CfnEvaluationException extends Error {} + +export interface ResourceDefinition { + readonly LogicalId: string; + readonly Type: string; + readonly Properties: { [p: string]: any }; +} + +export interface EvaluateCloudFormationTemplateProps { + readonly stackArtifact: cxapi.CloudFormationStackArtifact; + readonly parameters: { [parameterName: string]: string }; + readonly account: string; + readonly region: string; + readonly partition: string; + readonly urlSuffix: string; + readonly listStackResources: ListStackResources; +} + +export class EvaluateCloudFormationTemplate { + private readonly stackResources: ListStackResources; + private readonly template: { [section: string]: { [headings: string]: any } }; + private readonly context: { [k: string]: string }; + private readonly account: string; + private readonly region: string; + private readonly partition: string; + + constructor(props: EvaluateCloudFormationTemplateProps) { + this.stackResources = props.listStackResources; + this.template = props.stackArtifact.template; + this.context = { + 'AWS::AccountId': props.account, + 'AWS::Region': props.region, + 'AWS::Partition': props.partition, + 'AWS::URLSuffix': props.urlSuffix, + ...props.parameters, + }; + this.account = props.account; + this.region = props.region; + this.partition = props.partition; + } + + public async findPhysicalNameFor(logicalId: string): Promise { + const stackResources = await this.stackResources.listStackResources(); + return stackResources.find(sr => sr.LogicalResourceId === logicalId)?.PhysicalResourceId; + } + + public findReferencesTo(logicalId: string): Array { + const ret = new Array(); + for (const [resourceLogicalId, resourceDef] of Object.entries(this.template?.Resources ?? {})) { + if (logicalId !== resourceLogicalId && this.references(logicalId, resourceDef)) { + ret.push({ + ...(resourceDef as any), + LogicalId: resourceLogicalId, + }); + } + } + return ret; + } + + public async evaluateCfnExpression(cfnExpression: any): Promise { + const self = this; + class CfnIntrinsics { + public evaluateIntrinsic(intrinsic: Intrinsic): any { + const intrinsicFunc = (this as any)[intrinsic.name]; + if (!intrinsicFunc) { + throw new CfnEvaluationException(`CloudFormation function ${intrinsic.name} is not supported`); + } + + const argsAsArray = Array.isArray(intrinsic.args) ? intrinsic.args : [intrinsic.args]; + + return intrinsicFunc.apply(this, argsAsArray); + } + + async 'Fn::Join'(separator: string, args: any[]): Promise { + const evaluatedArgs = await self.evaluateCfnExpression(args); + return evaluatedArgs.join(separator); + } + + async 'Fn::Split'(separator: string, args: any): Promise { + const evaluatedArgs = await self.evaluateCfnExpression(args); + return evaluatedArgs.split(separator); + } + + async 'Fn::Select'(index: number, args: any[]): Promise { + const evaluatedArgs = await self.evaluateCfnExpression(args); + return evaluatedArgs[index]; + } + + async 'Ref'(logicalId: string): Promise { + const refTarget = await self.findRefTarget(logicalId); + if (refTarget) { + return refTarget; + } else { + throw new CfnEvaluationException(`Parameter or resource '${logicalId}' could not be found for evaluation`); + } + } + + async 'Fn::GetAtt'(logicalId: string, attributeName: string): Promise { + // ToDo handle the 'logicalId.attributeName' form of Fn::GetAtt + const attrValue = await self.findGetAttTarget(logicalId, attributeName); + if (attrValue) { + return attrValue; + } else { + throw new CfnEvaluationException(`Attribute '${attributeName}' of resource '${logicalId}' could not be found for evaluation`); + } + } + + async 'Fn::Sub'(template: string, explicitPlaceholders?: { [variable: string]: string }): Promise { + const placeholders = explicitPlaceholders + ? await self.evaluateCfnExpression(explicitPlaceholders) + : {}; + + return asyncGlobalReplace(template, /\${([^}]*)}/g, key => { + if (key in placeholders) { + return placeholders[key]; + } else { + const splitKey = key.split('.'); + return splitKey.length === 1 + ? this.Ref(key) + : this['Fn::GetAtt'](splitKey[0], splitKey.slice(1).join('.')); + } + }); + } + } + + if (cfnExpression == null) { + return cfnExpression; + } + + if (Array.isArray(cfnExpression)) { + return Promise.all(cfnExpression.map(expr => this.evaluateCfnExpression(expr))); + } + + if (typeof cfnExpression === 'object') { + const intrinsic = this.parseIntrinsic(cfnExpression); + if (intrinsic) { + return new CfnIntrinsics().evaluateIntrinsic(intrinsic); + } else { + const ret: { [key: string]: any } = {}; + for (const [key, val] of Object.entries(cfnExpression)) { + ret[key] = await this.evaluateCfnExpression(val); + } + return ret; + } + } + + return cfnExpression; + } + + private references(logicalId: string, templateElement: any): boolean { + if (typeof templateElement === 'string') { + return logicalId === templateElement; + } + + if (templateElement == null) { + return false; + } + + if (Array.isArray(templateElement)) { + return templateElement.some(el => this.references(logicalId, el)); + } + + if (typeof templateElement === 'object') { + return Object.values(templateElement).some(el => this.references(logicalId, el)); + } + + return false; + } + + private parseIntrinsic(x: any): Intrinsic | undefined { + const keys = Object.keys(x); + if (keys.length === 1 && (keys[0].startsWith('Fn::') || keys[0] === 'Ref')) { + return { + name: keys[0], + args: x[keys[0]], + }; + } + return undefined; + } + + private async findRefTarget(logicalId: string): Promise { + // first, check to see if the Ref is a Parameter who's value we have + const parameterTarget = this.context[logicalId]; + if (parameterTarget) { + return parameterTarget; + } + // if it's not a Parameter, we need to search in the current Stack resources + return this.findGetAttTarget(logicalId); + } + + private async findGetAttTarget(logicalId: string, attribute?: string): Promise { + const stackResources = await this.stackResources.listStackResources(); + const foundResource = stackResources.find(sr => sr.LogicalResourceId === logicalId); + if (!foundResource) { + return undefined; + } + // now, we need to format the appropriate identifier depending on the resource type, + // and the requested attribute name + return this.formatResourceAttribute(foundResource, attribute); + } + + private formatResourceAttribute(resource: AWS.CloudFormation.StackResourceSummary, attribute: string | undefined): string | undefined { + const physicalId = resource.PhysicalResourceId; + + // no attribute means Ref expression, for which we use the physical ID directly + if (!attribute) { + return physicalId; + } + + const resourceTypeFormats = RESOURCE_TYPE_ATTRIBUTES_FORMATS[resource.ResourceType]; + if (!resourceTypeFormats) { + throw new CfnEvaluationException(`We don't support attributes of the '${resource.ResourceType}' resource. This is a CDK limitation. ` + + 'Please report it at https://github.com/aws/aws-cdk/issues/new/choose'); + } + const attributeFmtFunc = resourceTypeFormats[attribute]; + if (!attributeFmtFunc) { + throw new CfnEvaluationException(`We don't support the '${attribute}' attribute of the '${resource.ResourceType}' resource. This is a CDK limitation. ` + + 'Please report it at https://github.com/aws/aws-cdk/issues/new/choose'); + } + const service = this.getServiceOfResource(resource); + const resourceTypeArnPart = this.getResourceTypeArnPartOfResource(resource); + return attributeFmtFunc({ + partition: this.partition, + service, + region: this.region, + account: this.account, + resourceType: resourceTypeArnPart, + resourceName: physicalId!, + }); + } + + private getServiceOfResource(resource: AWS.CloudFormation.StackResourceSummary): string { + return resource.ResourceType.split('::')[1].toLowerCase(); + } + + private getResourceTypeArnPartOfResource(resource: AWS.CloudFormation.StackResourceSummary): string { + return resource.ResourceType.split('::')[2].toLowerCase(); + } +} + +interface ArnParts { + readonly partition: string; + readonly service: string; + readonly region: string; + readonly account: string; + readonly resourceType: string; + readonly resourceName: string; +} + +const RESOURCE_TYPE_ATTRIBUTES_FORMATS: { [type: string]: { [attribute: string]: (parts: ArnParts) => string } } = { + 'AWS::IAM::Role': { Arn: iamArnFmt }, + 'AWS::IAM::User': { Arn: iamArnFmt }, + 'AWS::IAM::Group': { Arn: iamArnFmt }, + 'AWS::S3::Bucket': { Arn: s3ArnFmt }, + 'AWS::Lambda::Function': { Arn: stdColonResourceArnFmt }, +}; + +function iamArnFmt(parts: ArnParts): string { + // we skip region for IAM resources + return `arn:${parts.partition}:${parts.service}::${parts.account}:${parts.resourceType}/${parts.resourceName}`; +} + +function s3ArnFmt(parts: ArnParts): string { + // we skip account, region and resourceType for S3 resources + return `arn:${parts.partition}:${parts.service}:::${parts.resourceName}`; +} + +function stdColonResourceArnFmt(parts: ArnParts): string { + // this is a standard format for ARNs like: arn:aws:service:region:account:resourceType:resourceName + return `arn:${parts.partition}:${parts.service}:${parts.region}:${parts.account}:${parts.resourceType}:${parts.resourceName}`; +} + +interface Intrinsic { + readonly name: string; + readonly args: any; +} + +async function asyncGlobalReplace(str: string, regex: RegExp, cb: (x: string) => Promise): Promise { + if (!regex.global) { throw new Error('Regex must be created with /g flag'); } + + const ret = new Array(); + let start = 0; + while (true) { + const match = regex.exec(str); + if (!match) { break; } + + ret.push(str.substring(start, match.index)); + ret.push(await cb(match[1])); + + start = regex.lastIndex; + } + ret.push(str.substr(start)); + + return ret.join(''); +} diff --git a/packages/aws-cdk/lib/api/hotswap/lambda-functions.ts b/packages/aws-cdk/lib/api/hotswap/lambda-functions.ts index 73b4c529188c5..6aae68738acca 100644 --- a/packages/aws-cdk/lib/api/hotswap/lambda-functions.ts +++ b/packages/aws-cdk/lib/api/hotswap/lambda-functions.ts @@ -1,6 +1,6 @@ -import * as cfn_diff from '@aws-cdk/cloudformation-diff'; import { ISDK } from '../aws-auth'; -import { assetMetadataChanged, ChangeHotswapImpact, ChangeHotswapResult, HotswapOperation, ListStackResources, stringifyPotentialCfnExpression } from './common'; +import { assetMetadataChanged, ChangeHotswapImpact, ChangeHotswapResult, HotswapOperation, HotswappableChangeCandidate, establishResourcePhysicalName } from './common'; +import { EvaluateCloudFormationTemplate } from './evaluate-cloudformation-template'; /** * Returns `false` if the change cannot be short-circuited, @@ -8,10 +8,10 @@ import { assetMetadataChanged, ChangeHotswapImpact, ChangeHotswapResult, Hotswap * (like a change to CDKMetadata), * or a LambdaFunctionResource if the change can be short-circuited. */ -export function isHotswappableLambdaFunctionChange( - logicalId: string, change: cfn_diff.ResourceDifference, assetParamsWithEnv: { [key: string]: string }, -): ChangeHotswapResult { - const lambdaCodeChange = isLambdaFunctionCodeOnlyChange(change, assetParamsWithEnv); +export async function isHotswappableLambdaFunctionChange( + logicalId: string, change: HotswappableChangeCandidate, evaluateCfnTemplate: EvaluateCloudFormationTemplate, +): Promise { + const lambdaCodeChange = await isLambdaFunctionCodeOnlyChange(change, evaluateCfnTemplate); if (typeof lambdaCodeChange === 'string') { return lambdaCodeChange; } else { @@ -23,57 +23,34 @@ export function isHotswappableLambdaFunctionChange( return ChangeHotswapImpact.REQUIRES_FULL_DEPLOYMENT; } - let functionPhysicalName: string | undefined; - try { - functionPhysicalName = stringifyPotentialCfnExpression(change.newValue?.Properties?.FunctionName, assetParamsWithEnv); - } catch (e) { - // It's possible we can't evaluate the function's name - - // for example, it can use a Ref to a different resource, - // which we wouldn't have in `assetParamsWithEnv`. - // That's fine though - ignore any errors, - // and treat this case the same way as if the name wasn't provided at all, - // which means it will be looked up using the listStackResources() call - // by the later phase (which actually does the Lambda function update) - functionPhysicalName = undefined; + const functionName = await establishResourcePhysicalName(logicalId, change.newValue.Properties?.FunctionName, evaluateCfnTemplate); + if (!functionName) { + return ChangeHotswapImpact.REQUIRES_FULL_DEPLOYMENT; } return new LambdaFunctionHotswapOperation({ - logicalId, - physicalName: functionPhysicalName, + physicalName: functionName, code: lambdaCodeChange, }); } } /** - * Returns `true` if the change is not for a AWS::Lambda::Function, + * Returns `ChangeHotswapImpact.IRRELEVANT` if the change is not for a AWS::Lambda::Function, * but doesn't prevent short-circuiting * (like a change to CDKMetadata resource), - * `false` if the change is to a AWS::Lambda::Function, + * `ChangeHotswapImpact.REQUIRES_FULL_DEPLOYMENT` if the change is to a AWS::Lambda::Function, * but not only to its Code property, * or a LambdaFunctionCode if the change is to a AWS::Lambda::Function, * and only affects its Code property. */ -function isLambdaFunctionCodeOnlyChange( - change: cfn_diff.ResourceDifference, assetParamsWithEnv: { [key: string]: string }, -): LambdaFunctionCode | ChangeHotswapImpact { - if (!change.newValue) { - return ChangeHotswapImpact.REQUIRES_FULL_DEPLOYMENT; - } +async function isLambdaFunctionCodeOnlyChange( + change: HotswappableChangeCandidate, evaluateCfnTemplate: EvaluateCloudFormationTemplate, +): Promise { const newResourceType = change.newValue.Type; - // Ignore Metadata changes - if (newResourceType === 'AWS::CDK::Metadata') { - return ChangeHotswapImpact.IRRELEVANT; - } - // The only other resource change we should see is a Lambda function if (newResourceType !== 'AWS::Lambda::Function') { return ChangeHotswapImpact.REQUIRES_FULL_DEPLOYMENT; } - if (change.oldValue?.Type == null) { - // this means this is a brand-new Lambda function - - // obviously, we can't short-circuit that! - return ChangeHotswapImpact.REQUIRES_FULL_DEPLOYMENT; - } /* * On first glance, we would want to initialize these using the "previous" values (change.oldValue), @@ -92,18 +69,15 @@ function isLambdaFunctionCodeOnlyChange( const propertyUpdates = change.propertyUpdates; for (const updatedPropName in propertyUpdates) { const updatedProp = propertyUpdates[updatedPropName]; - if (updatedProp.newValue === undefined) { - return ChangeHotswapImpact.REQUIRES_FULL_DEPLOYMENT; - } for (const newPropName in updatedProp.newValue) { switch (newPropName) { case 'S3Bucket': foundCodeDifference = true; - s3Bucket = stringifyPotentialCfnExpression(updatedProp.newValue[newPropName], assetParamsWithEnv); + s3Bucket = await evaluateCfnTemplate.evaluateCfnExpression(updatedProp.newValue[newPropName]); break; case 'S3Key': foundCodeDifference = true; - s3Key = stringifyPotentialCfnExpression(updatedProp.newValue[newPropName], assetParamsWithEnv); + s3Key = await evaluateCfnTemplate.evaluateCfnExpression(updatedProp.newValue[newPropName]); break; default: return ChangeHotswapImpact.REQUIRES_FULL_DEPLOYMENT; @@ -125,8 +99,7 @@ interface LambdaFunctionCode { } interface LambdaFunctionResource { - readonly logicalId: string; - readonly physicalName?: string; + readonly physicalName: string; readonly code: LambdaFunctionCode; } @@ -134,24 +107,9 @@ class LambdaFunctionHotswapOperation implements HotswapOperation { constructor(private readonly lambdaFunctionResource: LambdaFunctionResource) { } - public async apply(sdk: ISDK, stackResources: ListStackResources): Promise { - let functionPhysicalName: string; - if (this.lambdaFunctionResource.physicalName) { - functionPhysicalName = this.lambdaFunctionResource.physicalName; - } else { - const stackResourceList = await stackResources.listStackResources(); - const foundFunctionName = stackResourceList - .find(resSummary => resSummary.LogicalResourceId === this.lambdaFunctionResource.logicalId) - ?.PhysicalResourceId; - if (!foundFunctionName) { - // if we couldn't find the function in the current stack, we can't update it - return; - } - functionPhysicalName = foundFunctionName; - } - + public async apply(sdk: ISDK): Promise { return sdk.lambda().updateFunctionCode({ - FunctionName: functionPhysicalName, + FunctionName: this.lambdaFunctionResource.physicalName, S3Bucket: this.lambdaFunctionResource.code.s3Bucket, S3Key: this.lambdaFunctionResource.code.s3Key, }).promise(); diff --git a/packages/aws-cdk/lib/api/hotswap/stepfunctions-state-machines.ts b/packages/aws-cdk/lib/api/hotswap/stepfunctions-state-machines.ts new file mode 100644 index 0000000000000..c4a7a4eae8750 --- /dev/null +++ b/packages/aws-cdk/lib/api/hotswap/stepfunctions-state-machines.ts @@ -0,0 +1,62 @@ +import { ISDK } from '../aws-auth'; +import { ChangeHotswapImpact, ChangeHotswapResult, HotswapOperation, HotswappableChangeCandidate, establishResourcePhysicalName } from './common'; +import { EvaluateCloudFormationTemplate } from './evaluate-cloudformation-template'; + +export async function isHotswappableStateMachineChange( + logicalId: string, change: HotswappableChangeCandidate, evaluateCfnTemplate: EvaluateCloudFormationTemplate, +): Promise { + const stateMachineDefinitionChange = await isStateMachineDefinitionOnlyChange(change, evaluateCfnTemplate); + if (stateMachineDefinitionChange === ChangeHotswapImpact.REQUIRES_FULL_DEPLOYMENT || + stateMachineDefinitionChange === ChangeHotswapImpact.IRRELEVANT) { + return stateMachineDefinitionChange; + } + + const machineNameInCfnTemplate = change.newValue?.Properties?.StateMachineName; + const machineName = await establishResourcePhysicalName(logicalId, machineNameInCfnTemplate, evaluateCfnTemplate); + if (!machineName) { + return ChangeHotswapImpact.REQUIRES_FULL_DEPLOYMENT; + } + + return new StateMachineHotswapOperation({ + definition: stateMachineDefinitionChange, + stateMachineName: machineName, + }); +} + +async function isStateMachineDefinitionOnlyChange( + change: HotswappableChangeCandidate, evaluateCfnTemplate: EvaluateCloudFormationTemplate, +): Promise { + const newResourceType = change.newValue.Type; + if (newResourceType !== 'AWS::StepFunctions::StateMachine') { + return ChangeHotswapImpact.REQUIRES_FULL_DEPLOYMENT; + } + + const propertyUpdates = change.propertyUpdates; + for (const updatedPropName in propertyUpdates) { + // ensure that only changes to the definition string result in a hotswap + if (updatedPropName !== 'DefinitionString') { + return ChangeHotswapImpact.REQUIRES_FULL_DEPLOYMENT; + } + } + + return evaluateCfnTemplate.evaluateCfnExpression(propertyUpdates.DefinitionString.newValue); +} + +interface StateMachineResource { + readonly stateMachineName: string; + readonly definition: string; +} + +class StateMachineHotswapOperation implements HotswapOperation { + constructor(private readonly stepFunctionResource: StateMachineResource) { + } + + public async apply(sdk: ISDK): Promise { + // not passing the optional properties leaves them unchanged + return sdk.stepFunctions().updateStateMachine({ + // even though the name of the property is stateMachineArn, passing the name of the state machine is allowed here + stateMachineArn: this.stepFunctionResource.stateMachineName, + definition: this.stepFunctionResource.definition, + }).promise(); + } +} diff --git a/packages/aws-cdk/lib/api/util/cloudformation/evaluate-cfn.ts b/packages/aws-cdk/lib/api/util/cloudformation/evaluate-cfn.ts deleted file mode 100644 index bdc395df83814..0000000000000 --- a/packages/aws-cdk/lib/api/util/cloudformation/evaluate-cfn.ts +++ /dev/null @@ -1,89 +0,0 @@ -export function evaluateCfn(object: any, context: { [key: string]: string }): any { - const intrinsicFns: any = { - 'Fn::Join'(separator: string, args: string[]): string { - return evaluate(args).map(evaluate).join(separator); - }, - - 'Fn::Split'(separator: string, args: string): string { - return evaluate(args).split(separator); - }, - - 'Fn::Select'(index: number, args: string[]): string { - return evaluate(args).map(evaluate)[index]; - }, - - 'Ref'(logicalId: string): string { - if (logicalId in context) { - return context[logicalId]; - } else { - throw new Error(`Reference target '${logicalId}' was not found`); - } - }, - - 'Fn::Sub'(template: string, explicitPlaceholders?: { [variable: string]: string }): string { - const placeholders = explicitPlaceholders - ? { ...context, ...evaluate(explicitPlaceholders) } - : context; - - return template.replace(/\${([^}]*)}/g, (_: string, key: string) => { - if (key in placeholders) { - return placeholders[key]; - } else { - throw new Error(`Fn::Sub target '${key}' was not found`); - } - }); - }, - }; - - return evaluate(object); - - function evaluate(obj: any): any { - if (Array.isArray(obj)) { - return obj.map(evaluate); - } - - if (typeof obj === 'object') { - const intrinsic = parseIntrinsic(obj); - if (intrinsic) { - return evaluateIntrinsic(intrinsic); - } - - const ret: { [key: string]: any } = {}; - for (const key of Object.keys(obj)) { - ret[key] = evaluate(obj[key]); - } - return ret; - } - - return obj; - } - - function evaluateIntrinsic(intrinsic: Intrinsic) { - if (!(intrinsic.name in intrinsicFns)) { - throw new Error(`Intrinsic ${intrinsic.name} not supported here`); - } - - const argsAsArray = Array.isArray(intrinsic.args) ? intrinsic.args : [intrinsic.args]; - - return intrinsicFns[intrinsic.name].apply(intrinsicFns, argsAsArray); - } -} - -interface Intrinsic { - readonly name: string; - readonly args: any; -} - -function parseIntrinsic(x: any): Intrinsic | undefined { - if (typeof x !== 'object' || x === null) { - return undefined; - } - const keys = Object.keys(x); - if (keys.length === 1 && (keys[0].startsWith('Fn::') || keys[0] === 'Ref')) { - return { - name: keys[0], - args: x[keys[0]], - }; - } - return undefined; -} diff --git a/packages/aws-cdk/lib/api/util/cloudformation/stack-activity-monitor.ts b/packages/aws-cdk/lib/api/util/cloudformation/stack-activity-monitor.ts index 98277d3339fa1..73075a41fee27 100644 --- a/packages/aws-cdk/lib/api/util/cloudformation/stack-activity-monitor.ts +++ b/packages/aws-cdk/lib/api/util/cloudformation/stack-activity-monitor.ts @@ -524,7 +524,7 @@ export class HistoryActivityPrinter extends ActivityPrinterBase { this.stream.write( util.format( ' %s%s | %s | %s | %s %s%s%s\n', - (progress !== false ? ` ${this.progress()} |` : ''), + (progress !== false ? ` ${this.progress()} | ` : ''), new Date(e.Timestamp).toLocaleTimeString(), color(padRight(STATUS_WIDTH, (e.ResourceStatus || '').substr(0, STATUS_WIDTH))), // pad left and trim padRight(this.props.resourceTypeColumnWidth, e.ResourceType || ''), diff --git a/packages/aws-cdk/lib/init-templates/v2/app/csharp/src/%name.PascalCased%/%name.PascalCased%.template.csproj b/packages/aws-cdk/lib/init-templates/v2/app/csharp/src/%name.PascalCased%/%name.PascalCased%.template.csproj index 0ac3cc0a4c6cb..a839c9651027a 100644 --- a/packages/aws-cdk/lib/init-templates/v2/app/csharp/src/%name.PascalCased%/%name.PascalCased%.template.csproj +++ b/packages/aws-cdk/lib/init-templates/v2/app/csharp/src/%name.PascalCased%/%name.PascalCased%.template.csproj @@ -10,6 +10,7 @@ + + + + [\s\S]+/gm, ''); + return fs.writeFile( destination, - await rewriteReadmeImports(source), + newReadme, { encoding: 'utf8' }, ); } else { diff --git a/tools/ubergen/package.json b/tools/@aws-cdk/ubergen/package.json similarity index 78% rename from tools/ubergen/package.json rename to tools/@aws-cdk/ubergen/package.json index 8cd1057e51ffd..1f00f627e4c46 100644 --- a/tools/ubergen/package.json +++ b/tools/@aws-cdk/ubergen/package.json @@ -1,12 +1,12 @@ { - "name": "ubergen", + "name": "@aws-cdk/ubergen", "private": true, "version": "0.0.0", "description": "Generate an uber CDK package from all individual CDK construct libraries", "repository": { "type": "git", "url": "https://github.com/aws/aws-cdk.git", - "directory": "tools/ubergen" + "directory": "tools/@aws-cdk/ubergen" }, "bin": { "ubergen": "bin/ubergen" @@ -29,14 +29,15 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/fs-extra": "^8.1.2", - "cdk-build-tools": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/fs-extra": "^8.1.2" }, "dependencies": { + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/cfnspec": "0.0.0", "fs-extra": "^9.1.0", - "typescript": "~3.9.10", - "cfn2ts": "0.0.0" + "typescript": "~3.9.10" }, "keywords": [ "aws", diff --git a/tools/ubergen/tsconfig.json b/tools/@aws-cdk/ubergen/tsconfig.json similarity index 100% rename from tools/ubergen/tsconfig.json rename to tools/@aws-cdk/ubergen/tsconfig.json diff --git a/tools/@aws-cdk/yarn-cling/.eslintrc.js b/tools/@aws-cdk/yarn-cling/.eslintrc.js new file mode 100644 index 0000000000000..2658ee8727166 --- /dev/null +++ b/tools/@aws-cdk/yarn-cling/.eslintrc.js @@ -0,0 +1,3 @@ +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; +module.exports = baseConfig; diff --git a/tools/yarn-cling/.gitignore b/tools/@aws-cdk/yarn-cling/.gitignore similarity index 100% rename from tools/yarn-cling/.gitignore rename to tools/@aws-cdk/yarn-cling/.gitignore diff --git a/tools/yarn-cling/.npmignore b/tools/@aws-cdk/yarn-cling/.npmignore similarity index 100% rename from tools/yarn-cling/.npmignore rename to tools/@aws-cdk/yarn-cling/.npmignore diff --git a/tools/@aws-cdk/yarn-cling/LICENSE b/tools/@aws-cdk/yarn-cling/LICENSE new file mode 100644 index 0000000000000..28e4bdcec77ec --- /dev/null +++ b/tools/@aws-cdk/yarn-cling/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/tools/@aws-cdk/yarn-cling/NOTICE b/tools/@aws-cdk/yarn-cling/NOTICE new file mode 100644 index 0000000000000..5fc3826926b5b --- /dev/null +++ b/tools/@aws-cdk/yarn-cling/NOTICE @@ -0,0 +1,2 @@ +AWS Cloud Development Kit (AWS CDK) +Copyright 2018-2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/tools/yarn-cling/README.md b/tools/@aws-cdk/yarn-cling/README.md similarity index 100% rename from tools/yarn-cling/README.md rename to tools/@aws-cdk/yarn-cling/README.md diff --git a/tools/yarn-cling/bin/yarn-cling b/tools/@aws-cdk/yarn-cling/bin/yarn-cling similarity index 100% rename from tools/yarn-cling/bin/yarn-cling rename to tools/@aws-cdk/yarn-cling/bin/yarn-cling diff --git a/tools/yarn-cling/bin/yarn-cling.ts b/tools/@aws-cdk/yarn-cling/bin/yarn-cling.ts similarity index 100% rename from tools/yarn-cling/bin/yarn-cling.ts rename to tools/@aws-cdk/yarn-cling/bin/yarn-cling.ts diff --git a/tools/yarn-cling/jest.config.js b/tools/@aws-cdk/yarn-cling/jest.config.js similarity index 100% rename from tools/yarn-cling/jest.config.js rename to tools/@aws-cdk/yarn-cling/jest.config.js diff --git a/tools/yarn-cling/lib/hoisting.ts b/tools/@aws-cdk/yarn-cling/lib/hoisting.ts similarity index 100% rename from tools/yarn-cling/lib/hoisting.ts rename to tools/@aws-cdk/yarn-cling/lib/hoisting.ts diff --git a/tools/yarn-cling/lib/index.ts b/tools/@aws-cdk/yarn-cling/lib/index.ts similarity index 100% rename from tools/yarn-cling/lib/index.ts rename to tools/@aws-cdk/yarn-cling/lib/index.ts diff --git a/tools/yarn-cling/lib/types.ts b/tools/@aws-cdk/yarn-cling/lib/types.ts similarity index 100% rename from tools/yarn-cling/lib/types.ts rename to tools/@aws-cdk/yarn-cling/lib/types.ts diff --git a/tools/yarn-cling/package.json b/tools/@aws-cdk/yarn-cling/package.json similarity index 90% rename from tools/yarn-cling/package.json rename to tools/@aws-cdk/yarn-cling/package.json index 9d86cc671b4d4..b8c930eb66867 100644 --- a/tools/yarn-cling/package.json +++ b/tools/@aws-cdk/yarn-cling/package.json @@ -1,5 +1,5 @@ { - "name": "yarn-cling", + "name": "@aws-cdk/yarn-cling", "private": true, "version": "0.0.0", "description": "Tool for generating npm-shrinkwrap from yarn.lock", @@ -7,7 +7,7 @@ "repository": { "type": "git", "url": "https://github.com/aws/aws-cdk.git", - "directory": "tools/yarn-cling" + "directory": "tools/@aws-cdk/yarn-cling" }, "bin": { "yarn-cling": "bin/yarn-cling" @@ -22,9 +22,6 @@ "build+extract": "yarn build", "build+test+extract": "yarn build+test" }, - "cdk-build": { - "jest": true - }, "author": { "name": "Amazon Web Services", "url": "https://aws.amazon.com", @@ -40,12 +37,12 @@ ] }, "devDependencies": { + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", "@types/node": "^10.17.60", + "@types/semver": "^7.3.8", "@types/yarnpkg__lockfile": "^1.1.5", - "@types/semver": "^7.3.7", "jest": "^26.6.3", - "pkglint": "0.0.0", "typescript": "~3.9.10" }, "dependencies": { diff --git a/tools/yarn-cling/test/cling.test.ts b/tools/@aws-cdk/yarn-cling/test/cling.test.ts similarity index 100% rename from tools/yarn-cling/test/cling.test.ts rename to tools/@aws-cdk/yarn-cling/test/cling.test.ts diff --git a/tools/yarn-cling/test/hoisting.test.ts b/tools/@aws-cdk/yarn-cling/test/hoisting.test.ts similarity index 100% rename from tools/yarn-cling/test/hoisting.test.ts rename to tools/@aws-cdk/yarn-cling/test/hoisting.test.ts diff --git a/tools/yarn-cling/test/test-fixture/.gitignore b/tools/@aws-cdk/yarn-cling/test/test-fixture/.gitignore similarity index 100% rename from tools/yarn-cling/test/test-fixture/.gitignore rename to tools/@aws-cdk/yarn-cling/test/test-fixture/.gitignore diff --git a/tools/yarn-cling/test/test-fixture/.no-packagejson-validator b/tools/@aws-cdk/yarn-cling/test/test-fixture/.no-packagejson-validator similarity index 100% rename from tools/yarn-cling/test/test-fixture/.no-packagejson-validator rename to tools/@aws-cdk/yarn-cling/test/test-fixture/.no-packagejson-validator diff --git a/tools/yarn-cling/test/test-fixture/cdk/package.json b/tools/@aws-cdk/yarn-cling/test/test-fixture/cdk/package.json similarity index 100% rename from tools/yarn-cling/test/test-fixture/cdk/package.json rename to tools/@aws-cdk/yarn-cling/test/test-fixture/cdk/package.json diff --git a/tools/yarn-cling/test/test-fixture/jsii/node_modules/aws-cdk-lib/package.json b/tools/@aws-cdk/yarn-cling/test/test-fixture/jsii/node_modules/aws-cdk-lib/package.json similarity index 100% rename from tools/yarn-cling/test/test-fixture/jsii/node_modules/aws-cdk-lib/package.json rename to tools/@aws-cdk/yarn-cling/test/test-fixture/jsii/node_modules/aws-cdk-lib/package.json diff --git a/tools/yarn-cling/test/test-fixture/jsii/node_modules/aws-cdk/package.json b/tools/@aws-cdk/yarn-cling/test/test-fixture/jsii/node_modules/aws-cdk/package.json similarity index 100% rename from tools/yarn-cling/test/test-fixture/jsii/node_modules/aws-cdk/package.json rename to tools/@aws-cdk/yarn-cling/test/test-fixture/jsii/node_modules/aws-cdk/package.json diff --git a/tools/yarn-cling/test/test-fixture/jsii/node_modules/cdk b/tools/@aws-cdk/yarn-cling/test/test-fixture/jsii/node_modules/cdk similarity index 100% rename from tools/yarn-cling/test/test-fixture/jsii/node_modules/cdk rename to tools/@aws-cdk/yarn-cling/test/test-fixture/jsii/node_modules/cdk diff --git a/tools/yarn-cling/test/test-fixture/jsii/package.json b/tools/@aws-cdk/yarn-cling/test/test-fixture/jsii/package.json similarity index 100% rename from tools/yarn-cling/test/test-fixture/jsii/package.json rename to tools/@aws-cdk/yarn-cling/test/test-fixture/jsii/package.json diff --git a/tools/yarn-cling/test/test-fixture/yarn.lock b/tools/@aws-cdk/yarn-cling/test/test-fixture/yarn.lock similarity index 100% rename from tools/yarn-cling/test/test-fixture/yarn.lock rename to tools/@aws-cdk/yarn-cling/test/test-fixture/yarn.lock diff --git a/tools/yarn-cling/tsconfig.json b/tools/@aws-cdk/yarn-cling/tsconfig.json similarity index 100% rename from tools/yarn-cling/tsconfig.json rename to tools/@aws-cdk/yarn-cling/tsconfig.json diff --git a/tools/eslint-plugin-cdk/test/rules/fixtures.test.ts b/tools/eslint-plugin-cdk/test/rules/fixtures.test.ts deleted file mode 100644 index bf1c03f359047..0000000000000 --- a/tools/eslint-plugin-cdk/test/rules/fixtures.test.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { ESLint } from 'eslint'; -import * as fs from 'fs-extra'; -import * as path from 'path'; - -const rulesDirPlugin = require('eslint-plugin-rulesdir'); -rulesDirPlugin.RULES_DIR = path.join(__dirname, '../../lib/rules'); - -let linter: ESLint; - -const outputRoot = path.join(process.cwd(), '.test-output'); -fs.mkdirpSync(outputRoot); - -const fixturesRoot = path.join(__dirname, 'fixtures'); - -fs.readdirSync(fixturesRoot).filter(f => fs.lstatSync(path.join(fixturesRoot, f)).isDirectory()).forEach(d => { - describe(d, () => { - const fixturesDir = path.join(fixturesRoot, d); - - beforeAll(() => { - linter = new ESLint({ - baseConfig: { - parser: '@typescript-eslint/parser', - }, - overrideConfigFile: path.join(fixturesDir, 'eslintrc.js'), - rulePaths: [ - path.join(__dirname, '../../lib/rules'), - ], - fix: true, - }); - }); - - const outputDir = path.join(outputRoot, d); - fs.mkdirpSync(outputDir); - - const fixtureFiles = fs.readdirSync(fixturesDir).filter(f => f.endsWith('.ts') && !f.endsWith('.expected.ts')); - - fixtureFiles.forEach(f => { - test(f, async (done) => { - const actualFile = await lintAndFix(path.join(fixturesDir, f), outputDir); - const expectedFile = path.join(fixturesDir, `${path.basename(f, '.ts')}.expected.ts`); - if (!fs.existsSync(expectedFile)) { - done.fail(`Expected file not found. Generated output at ${actualFile}`); - } - const actual = await fs.readFile(actualFile, { encoding: 'utf8' }); - const expected = await fs.readFile(expectedFile, { encoding: 'utf8' }); - if (actual !== expected) { - done.fail(`Linted file did not match expectations. Expected: ${expectedFile}. Actual: ${actualFile}`); - } - done(); - }); - }); - }); -}); - -async function lintAndFix(file: string, outputDir: string) { - const newPath = path.join(outputDir, path.basename(file)) - let result = await linter.lintFiles(file); - const hasFixes = result.find(r => typeof(r.output) === 'string') !== undefined; - if (hasFixes) { - await ESLint.outputFixes(result.map(r => { - r.filePath = newPath; - return r; - })); - } else { - // If there are no fixes, copy the input file as output - await fs.copyFile(file, newPath); - } - return newPath; -} diff --git a/tools/ubergen/.eslintrc.js b/tools/ubergen/.eslintrc.js deleted file mode 100644 index 61dd8dd001f63..0000000000000 --- a/tools/ubergen/.eslintrc.js +++ /dev/null @@ -1,3 +0,0 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); -baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; -module.exports = baseConfig; diff --git a/tools/yarn-cling/.eslintrc.js b/tools/yarn-cling/.eslintrc.js deleted file mode 100644 index 61dd8dd001f63..0000000000000 --- a/tools/yarn-cling/.eslintrc.js +++ /dev/null @@ -1,3 +0,0 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); -baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; -module.exports = baseConfig; diff --git a/version.v1.json b/version.v1.json index 77e24208bd94a..c24ba0065c588 100644 --- a/version.v1.json +++ b/version.v1.json @@ -1,3 +1,3 @@ { - "version": "1.123.0" + "version": "1.128.0" } \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index e9744b94014b6..3fc7477ad872b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,60 +2,62 @@ # yarn lockfile v1 -"@actions/core@^1.4.0": - version "1.4.0" - resolved "https://registry.yarnpkg.com/@actions/core/-/core-1.4.0.tgz#cf2e6ee317e314b03886adfeb20e448d50d6e524" - integrity sha512-CGx2ilGq5i7zSLgiiGUtBCxhRRxibJYU6Fim0Q1Wg2aQL2LTnF27zbqZOrxfvFQ55eSBW0L8uVStgtKMpa0Qlg== +"@actions/core@^1.6.0": + version "1.6.0" + resolved "https://registry.npmjs.org/@actions/core/-/core-1.6.0.tgz#0568e47039bfb6a9170393a73f3b7eb3b22462cb" + integrity sha512-NB1UAZomZlCV/LmJqkLhNTqtKfFXJZAUPcfl/zqG7EfsQdeUJtaWO98SGbuQ3pydJ3fHl2CvI/51OKYlCYYcaw== + dependencies: + "@actions/http-client" "^1.0.11" "@actions/github@^2.2.0": version "2.2.0" - resolved "https://registry.yarnpkg.com/@actions/github/-/github-2.2.0.tgz#8952fe96b12b881fa39340f0e7202b04dc5c3e71" + resolved "https://registry.npmjs.org/@actions/github/-/github-2.2.0.tgz#8952fe96b12b881fa39340f0e7202b04dc5c3e71" integrity sha512-9UAZqn8ywdR70n3GwVle4N8ALosQs4z50N7XMXrSTUVOmVpaBC5kE3TRTT7qQdi3OaQV24mjGuJZsHUmhD+ZXw== dependencies: "@actions/http-client" "^1.0.3" "@octokit/graphql" "^4.3.1" "@octokit/rest" "^16.43.1" -"@actions/http-client@^1.0.3": +"@actions/http-client@^1.0.11", "@actions/http-client@^1.0.3": version "1.0.11" - resolved "https://registry.yarnpkg.com/@actions/http-client/-/http-client-1.0.11.tgz#c58b12e9aa8b159ee39e7dd6cbd0e91d905633c0" + resolved "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.11.tgz#c58b12e9aa8b159ee39e7dd6cbd0e91d905633c0" integrity sha512-VRYHGQV1rqnROJqdMvGUbY/Kn8vriQe/F9HR2AlYHzmKuM/p3kjNuXhmdBfcVgsvRWTz5C5XW5xvndZrVBuAYg== dependencies: tunnel "0.0.6" "@babel/code-frame@7.12.11": version "7.12.11" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.11.tgz#f4ad435aa263db935b8f10f2c552d23fb716a63f" + resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz#f4ad435aa263db935b8f10f2c552d23fb716a63f" integrity sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw== dependencies: "@babel/highlight" "^7.10.4" -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.14.5.tgz#23b08d740e83f49c5e59945fbf1b43e80bbf4edb" - integrity sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw== +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.14.5", "@babel/code-frame@^7.15.8": + version "7.15.8" + resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.15.8.tgz#45990c47adadb00c03677baa89221f7cc23d2503" + integrity sha512-2IAnmn8zbvC/jKYhq5Ki9I+DwjlrtMPUCH/CpHvqI4dNnlwHwsxoIhlc8WcYY5LSYknXQtAlFYuHfqAFCvQ4Wg== dependencies: "@babel/highlight" "^7.14.5" -"@babel/compat-data@^7.14.5": - version "7.14.7" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.14.7.tgz#7b047d7a3a89a67d2258dc61f604f098f1bc7e08" - integrity sha512-nS6dZaISCXJ3+518CWiBfEr//gHyMO02uDxBkXTKZDN5POruCnOZ1N4YBRZDCabwF8nZMWBpRxIicmXtBs+fvw== +"@babel/compat-data@^7.15.0": + version "7.15.0" + resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.15.0.tgz#2dbaf8b85334796cafbb0f5793a90a2fc010b176" + integrity sha512-0NqAC1IJE0S0+lL1SWFMxMkz1pKCNCjI4tr2Zx4LJSXxCLAdr6KyArnY+sno5m3yH9g737ygOyPABDsnXkpxiA== "@babel/core@^7.1.0", "@babel/core@^7.7.5": - version "7.14.8" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.14.8.tgz#20cdf7c84b5d86d83fac8710a8bc605a7ba3f010" - integrity sha512-/AtaeEhT6ErpDhInbXmjHcUQXH0L0TEgscfcxk1qbOvLuKCa5aZT0SOOtDKFY96/CLROwbLSKyFor6idgNaU4Q== - dependencies: - "@babel/code-frame" "^7.14.5" - "@babel/generator" "^7.14.8" - "@babel/helper-compilation-targets" "^7.14.5" - "@babel/helper-module-transforms" "^7.14.8" - "@babel/helpers" "^7.14.8" - "@babel/parser" "^7.14.8" - "@babel/template" "^7.14.5" - "@babel/traverse" "^7.14.8" - "@babel/types" "^7.14.8" + version "7.15.8" + resolved "https://registry.npmjs.org/@babel/core/-/core-7.15.8.tgz#195b9f2bffe995d2c6c159e72fe525b4114e8c10" + integrity sha512-3UG9dsxvYBMYwRv+gS41WKHno4K60/9GPy1CJaH6xy3Elq8CTtvtjT5R5jmNhXfCYLX2mTw+7/aq5ak/gOE0og== + dependencies: + "@babel/code-frame" "^7.15.8" + "@babel/generator" "^7.15.8" + "@babel/helper-compilation-targets" "^7.15.4" + "@babel/helper-module-transforms" "^7.15.8" + "@babel/helpers" "^7.15.4" + "@babel/parser" "^7.15.8" + "@babel/template" "^7.15.4" + "@babel/traverse" "^7.15.4" + "@babel/types" "^7.15.6" convert-source-map "^1.7.0" debug "^4.1.0" gensync "^1.0.0-beta.2" @@ -63,282 +65,294 @@ semver "^6.3.0" source-map "^0.5.0" -"@babel/generator@^7.14.8", "@babel/generator@^7.4.0": - version "7.14.8" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.14.8.tgz#bf86fd6af96cf3b74395a8ca409515f89423e070" - integrity sha512-cYDUpvIzhBVnMzRoY1fkSEhK/HmwEVwlyULYgn/tMQYd6Obag3ylCjONle3gdErfXBW61SVTlR9QR7uWlgeIkg== +"@babel/generator@^7.15.4", "@babel/generator@^7.15.8": + version "7.15.8" + resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.15.8.tgz#fa56be6b596952ceb231048cf84ee499a19c0cd1" + integrity sha512-ECmAKstXbp1cvpTTZciZCgfOt6iN64lR0d+euv3UZisU5awfRawOvg07Utn/qBGuH4bRIEZKrA/4LzZyXhZr8g== dependencies: - "@babel/types" "^7.14.8" + "@babel/types" "^7.15.6" jsesc "^2.5.1" source-map "^0.5.0" -"@babel/helper-compilation-targets@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.14.5.tgz#7a99c5d0967911e972fe2c3411f7d5b498498ecf" - integrity sha512-v+QtZqXEiOnpO6EYvlImB6zCD2Lel06RzOPzmkz/D/XgQiUu3C/Jb1LOqSt/AIA34TYi/Q+KlT8vTQrgdxkbLw== +"@babel/helper-compilation-targets@^7.15.4": + version "7.15.4" + resolved "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.15.4.tgz#cf6d94f30fbefc139123e27dd6b02f65aeedb7b9" + integrity sha512-rMWPCirulnPSe4d+gwdWXLfAXTTBj8M3guAf5xFQJ0nvFY7tfNAFnWdqaHegHlgDZOCT4qvhF3BYlSJag8yhqQ== dependencies: - "@babel/compat-data" "^7.14.5" + "@babel/compat-data" "^7.15.0" "@babel/helper-validator-option" "^7.14.5" browserslist "^4.16.6" semver "^6.3.0" -"@babel/helper-function-name@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.14.5.tgz#89e2c474972f15d8e233b52ee8c480e2cfcd50c4" - integrity sha512-Gjna0AsXWfFvrAuX+VKcN/aNNWonizBj39yGwUzVDVTlMYJMK2Wp6xdpy72mfArFq5uK+NOuexfzZlzI1z9+AQ== +"@babel/helper-function-name@^7.15.4": + version "7.15.4" + resolved "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.15.4.tgz#845744dafc4381a4a5fb6afa6c3d36f98a787ebc" + integrity sha512-Z91cOMM4DseLIGOnog+Z8OI6YseR9bua+HpvLAQ2XayUGU+neTtX+97caALaLdyu53I/fjhbeCnWnRH1O3jFOw== dependencies: - "@babel/helper-get-function-arity" "^7.14.5" - "@babel/template" "^7.14.5" - "@babel/types" "^7.14.5" + "@babel/helper-get-function-arity" "^7.15.4" + "@babel/template" "^7.15.4" + "@babel/types" "^7.15.4" -"@babel/helper-get-function-arity@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.14.5.tgz#25fbfa579b0937eee1f3b805ece4ce398c431815" - integrity sha512-I1Db4Shst5lewOM4V+ZKJzQ0JGGaZ6VY1jYvMghRjqs6DWgxLCIyFt30GlnKkfUeFLpJt2vzbMVEXVSXlIFYUg== +"@babel/helper-get-function-arity@^7.15.4": + version "7.15.4" + resolved "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.15.4.tgz#098818934a137fce78b536a3e015864be1e2879b" + integrity sha512-1/AlxSF92CmGZzHnC515hm4SirTxtpDnLEJ0UyEMgTMZN+6bxXKg04dKhiRx5Enel+SUA1G1t5Ed/yQia0efrA== dependencies: - "@babel/types" "^7.14.5" + "@babel/types" "^7.15.4" -"@babel/helper-hoist-variables@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.14.5.tgz#e0dd27c33a78e577d7c8884916a3e7ef1f7c7f8d" - integrity sha512-R1PXiz31Uc0Vxy4OEOm07x0oSjKAdPPCh3tPivn/Eo8cvz6gveAeuyUUPB21Hoiif0uoPQSSdhIPS3352nvdyQ== +"@babel/helper-hoist-variables@^7.15.4": + version "7.15.4" + resolved "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.15.4.tgz#09993a3259c0e918f99d104261dfdfc033f178df" + integrity sha512-VTy085egb3jUGVK9ycIxQiPbquesq0HUQ+tPO0uv5mPEBZipk+5FkRKiWq5apuyTE9FUrjENB0rCf8y+n+UuhA== dependencies: - "@babel/types" "^7.14.5" + "@babel/types" "^7.15.4" -"@babel/helper-member-expression-to-functions@^7.14.5": - version "7.14.7" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.14.7.tgz#97e56244beb94211fe277bd818e3a329c66f7970" - integrity sha512-TMUt4xKxJn6ccjcOW7c4hlwyJArizskAhoSTOCkA0uZ+KghIaci0Qg9R043kUMWI9mtQfgny+NQ5QATnZ+paaA== +"@babel/helper-member-expression-to-functions@^7.15.4": + version "7.15.4" + resolved "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.15.4.tgz#bfd34dc9bba9824a4658b0317ec2fd571a51e6ef" + integrity sha512-cokOMkxC/BTyNP1AlY25HuBWM32iCEsLPI4BHDpJCHHm1FU2E7dKWWIXJgQgSFiu4lp8q3bL1BIKwqkSUviqtA== dependencies: - "@babel/types" "^7.14.5" + "@babel/types" "^7.15.4" -"@babel/helper-module-imports@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.14.5.tgz#6d1a44df6a38c957aa7c312da076429f11b422f3" - integrity sha512-SwrNHu5QWS84XlHwGYPDtCxcA0hrSlL2yhWYLgeOc0w7ccOl2qv4s/nARI0aYZW+bSwAL5CukeXA47B/1NKcnQ== - dependencies: - "@babel/types" "^7.14.5" - -"@babel/helper-module-transforms@^7.14.8": - version "7.14.8" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.14.8.tgz#d4279f7e3fd5f4d5d342d833af36d4dd87d7dc49" - integrity sha512-RyE+NFOjXn5A9YU1dkpeBaduagTlZ0+fccnIcAGbv1KGUlReBj7utF7oEth8IdIBQPcux0DDgW5MFBH2xu9KcA== - dependencies: - "@babel/helper-module-imports" "^7.14.5" - "@babel/helper-replace-supers" "^7.14.5" - "@babel/helper-simple-access" "^7.14.8" - "@babel/helper-split-export-declaration" "^7.14.5" - "@babel/helper-validator-identifier" "^7.14.8" - "@babel/template" "^7.14.5" - "@babel/traverse" "^7.14.8" - "@babel/types" "^7.14.8" - -"@babel/helper-optimise-call-expression@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.14.5.tgz#f27395a8619e0665b3f0364cddb41c25d71b499c" - integrity sha512-IqiLIrODUOdnPU9/F8ib1Fx2ohlgDhxnIDU7OEVi+kAbEZcyiF7BLU8W6PfvPi9LzztjS7kcbzbmL7oG8kD6VA== +"@babel/helper-module-imports@^7.15.4": + version "7.15.4" + resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.15.4.tgz#e18007d230632dea19b47853b984476e7b4e103f" + integrity sha512-jeAHZbzUwdW/xHgHQ3QmWR4Jg6j15q4w/gCfwZvtqOxoo5DKtLHk8Bsf4c5RZRC7NmLEs+ohkdq8jFefuvIxAA== + dependencies: + "@babel/types" "^7.15.4" + +"@babel/helper-module-transforms@^7.15.8": + version "7.15.8" + resolved "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.15.8.tgz#d8c0e75a87a52e374a8f25f855174786a09498b2" + integrity sha512-DfAfA6PfpG8t4S6npwzLvTUpp0sS7JrcuaMiy1Y5645laRJIp/LiLGIBbQKaXSInK8tiGNI7FL7L8UvB8gdUZg== + dependencies: + "@babel/helper-module-imports" "^7.15.4" + "@babel/helper-replace-supers" "^7.15.4" + "@babel/helper-simple-access" "^7.15.4" + "@babel/helper-split-export-declaration" "^7.15.4" + "@babel/helper-validator-identifier" "^7.15.7" + "@babel/template" "^7.15.4" + "@babel/traverse" "^7.15.4" + "@babel/types" "^7.15.6" + +"@babel/helper-optimise-call-expression@^7.15.4": + version "7.15.4" + resolved "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.15.4.tgz#f310a5121a3b9cc52d9ab19122bd729822dee171" + integrity sha512-E/z9rfbAOt1vDW1DR7k4SzhzotVV5+qMciWV6LaG1g4jeFrkDlJedjtV4h0i4Q/ITnUu+Pk08M7fczsB9GXBDw== dependencies: - "@babel/types" "^7.14.5" + "@babel/types" "^7.15.4" "@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.8.0": version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz#5ac822ce97eec46741ab70a517971e443a70c5a9" + resolved "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz#5ac822ce97eec46741ab70a517971e443a70c5a9" integrity sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ== -"@babel/helper-replace-supers@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.14.5.tgz#0ecc0b03c41cd567b4024ea016134c28414abb94" - integrity sha512-3i1Qe9/8x/hCHINujn+iuHy+mMRLoc77b2nI9TB0zjH1hvn9qGlXjWlggdwUcju36PkPCy/lpM7LLUdcTyH4Ow== +"@babel/helper-replace-supers@^7.15.4": + version "7.15.4" + resolved "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.15.4.tgz#52a8ab26ba918c7f6dee28628b07071ac7b7347a" + integrity sha512-/ztT6khaXF37MS47fufrKvIsiQkx1LBRvSJNzRqmbyeZnTwU9qBxXYLaaT/6KaxfKhjs2Wy8kG8ZdsFUuWBjzw== dependencies: - "@babel/helper-member-expression-to-functions" "^7.14.5" - "@babel/helper-optimise-call-expression" "^7.14.5" - "@babel/traverse" "^7.14.5" - "@babel/types" "^7.14.5" + "@babel/helper-member-expression-to-functions" "^7.15.4" + "@babel/helper-optimise-call-expression" "^7.15.4" + "@babel/traverse" "^7.15.4" + "@babel/types" "^7.15.4" -"@babel/helper-simple-access@^7.14.8": - version "7.14.8" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.14.8.tgz#82e1fec0644a7e775c74d305f212c39f8fe73924" - integrity sha512-TrFN4RHh9gnWEU+s7JloIho2T76GPwRHhdzOWLqTrMnlas8T9O7ec+oEDNsRXndOmru9ymH9DFrEOxpzPoSbdg== +"@babel/helper-simple-access@^7.15.4": + version "7.15.4" + resolved "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.15.4.tgz#ac368905abf1de8e9781434b635d8f8674bcc13b" + integrity sha512-UzazrDoIVOZZcTeHHEPYrr1MvTR/K+wgLg6MY6e1CJyaRhbibftF6fR2KU2sFRtI/nERUZR9fBd6aKgBlIBaPg== dependencies: - "@babel/types" "^7.14.8" + "@babel/types" "^7.15.4" -"@babel/helper-split-export-declaration@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.14.5.tgz#22b23a54ef51c2b7605d851930c1976dd0bc693a" - integrity sha512-hprxVPu6e5Kdp2puZUmvOGjaLv9TCe58E/Fl6hRq4YiVQxIcNvuq6uTM2r1mT/oPskuS9CgR+I94sqAYv0NGKA== +"@babel/helper-split-export-declaration@^7.15.4": + version "7.15.4" + resolved "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.15.4.tgz#aecab92dcdbef6a10aa3b62ab204b085f776e257" + integrity sha512-HsFqhLDZ08DxCpBdEVtKmywj6PQbwnF6HHybur0MAnkAKnlS6uHkwnmRIkElB2Owpfb4xL4NwDmDLFubueDXsw== dependencies: - "@babel/types" "^7.14.5" + "@babel/types" "^7.15.4" -"@babel/helper-validator-identifier@^7.14.5", "@babel/helper-validator-identifier@^7.14.8": - version "7.14.8" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.8.tgz#32be33a756f29e278a0d644fa08a2c9e0f88a34c" - integrity sha512-ZGy6/XQjllhYQrNw/3zfWRwZCTVSiBLZ9DHVZxn9n2gip/7ab8mv2TWlKPIBk26RwedCBoWdjLmn+t9na2Gcow== +"@babel/helper-validator-identifier@^7.14.5", "@babel/helper-validator-identifier@^7.14.9", "@babel/helper-validator-identifier@^7.15.7": + version "7.15.7" + resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz#220df993bfe904a4a6b02ab4f3385a5ebf6e2389" + integrity sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w== "@babel/helper-validator-option@^7.14.5": version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz#6e72a1fff18d5dfcb878e1e62f1a021c4b72d5a3" + resolved "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz#6e72a1fff18d5dfcb878e1e62f1a021c4b72d5a3" integrity sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow== -"@babel/helpers@^7.14.8": - version "7.14.8" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.14.8.tgz#839f88f463025886cff7f85a35297007e2da1b77" - integrity sha512-ZRDmI56pnV+p1dH6d+UN6GINGz7Krps3+270qqI9UJ4wxYThfAIcI5i7j5vXC4FJ3Wap+S9qcebxeYiqn87DZw== +"@babel/helpers@^7.15.4": + version "7.15.4" + resolved "https://registry.npmjs.org/@babel/helpers/-/helpers-7.15.4.tgz#5f40f02050a3027121a3cf48d497c05c555eaf43" + integrity sha512-V45u6dqEJ3w2rlryYYXf6i9rQ5YMNu4FLS6ngs8ikblhu2VdR1AqAd6aJjBzmf2Qzh6KOLqKHxEN9+TFbAkAVQ== dependencies: - "@babel/template" "^7.14.5" - "@babel/traverse" "^7.14.8" - "@babel/types" "^7.14.8" + "@babel/template" "^7.15.4" + "@babel/traverse" "^7.15.4" + "@babel/types" "^7.15.4" "@babel/highlight@^7.10.4", "@babel/highlight@^7.14.5": version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.14.5.tgz#6861a52f03966405001f6aa534a01a24d99e8cd9" + resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz#6861a52f03966405001f6aa534a01a24d99e8cd9" integrity sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg== dependencies: "@babel/helper-validator-identifier" "^7.14.5" chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/parser@^7.1.0", "@babel/parser@^7.14.5", "@babel/parser@^7.14.8", "@babel/parser@^7.4.3": - version "7.14.8" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.14.8.tgz#66fd41666b2d7b840bd5ace7f7416d5ac60208d4" - integrity sha512-syoCQFOoo/fzkWDeM0dLEZi5xqurb5vuyzwIMNZRNun+N/9A4cUZeQaE7dTrB8jGaKuJRBtEOajtnmw0I5hvvA== +"@babel/parser@^7.1.0", "@babel/parser@^7.15.4", "@babel/parser@^7.15.8": + version "7.15.8" + resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.15.8.tgz#7bacdcbe71bdc3ff936d510c15dcea7cf0b99016" + integrity sha512-BRYa3wcQnjS/nqI8Ac94pYYpJfojHVvVXJ97+IDCImX4Jc8W8Xv1+47enbruk+q1etOpsQNwnfFcNGw+gtPGxA== "@babel/plugin-syntax-async-generators@^7.8.4": version "7.8.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== dependencies: "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-bigint@^7.8.3": version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz#4c9a6f669f5d0cdf1b90a1671e9a146be5300cea" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz#4c9a6f669f5d0cdf1b90a1671e9a146be5300cea" integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== dependencies: "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-class-properties@^7.8.3": version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== dependencies: "@babel/helper-plugin-utils" "^7.12.13" "@babel/plugin-syntax-import-meta@^7.8.3": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-json-strings@^7.8.3": version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== dependencies: "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-logical-assignment-operators@^7.8.3": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== dependencies: "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-numeric-separator@^7.8.3": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-object-rest-spread@^7.8.3": version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== dependencies: "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-optional-catch-binding@^7.8.3": version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== dependencies: "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-optional-chaining@^7.8.3": version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== dependencies: "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-top-level-await@^7.8.3": version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/template@^7.14.5", "@babel/template@^7.3.3", "@babel/template@^7.4.0": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.14.5.tgz#a9bc9d8b33354ff6e55a9c60d1109200a68974f4" - integrity sha512-6Z3Po85sfxRGachLULUhOmvAaOo7xCvqGQtxINai2mEGPFm6pQ4z5QInFnUrRpfoSV60BnjyF5F3c+15fxFV1g== +"@babel/template@^7.15.4", "@babel/template@^7.3.3": + version "7.15.4" + resolved "https://registry.npmjs.org/@babel/template/-/template-7.15.4.tgz#51898d35dcf3faa670c4ee6afcfd517ee139f194" + integrity sha512-UgBAfEa1oGuYgDIPM2G+aHa4Nlo9Lh6mGD2bDBGMTbYnc38vulXPuC1MGjYILIEmlwl6Rd+BPR9ee3gm20CBtg== dependencies: "@babel/code-frame" "^7.14.5" - "@babel/parser" "^7.14.5" - "@babel/types" "^7.14.5" + "@babel/parser" "^7.15.4" + "@babel/types" "^7.15.4" -"@babel/traverse@^7.1.0", "@babel/traverse@^7.14.5", "@babel/traverse@^7.14.8", "@babel/traverse@^7.4.3": - version "7.14.8" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.14.8.tgz#c0253f02677c5de1a8ff9df6b0aacbec7da1a8ce" - integrity sha512-kexHhzCljJcFNn1KYAQ6A5wxMRzq9ebYpEDV4+WdNyr3i7O44tanbDOR/xjiG2F3sllan+LgwK+7OMk0EmydHg== +"@babel/traverse@^7.1.0", "@babel/traverse@^7.15.4": + version "7.15.4" + resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.15.4.tgz#ff8510367a144bfbff552d9e18e28f3e2889c22d" + integrity sha512-W6lQD8l4rUbQR/vYgSuCAE75ADyyQvOpFVsvPPdkhf6lATXAsQIG9YdtOcu8BB1dZ0LKu+Zo3c1wEcbKeuhdlA== dependencies: "@babel/code-frame" "^7.14.5" - "@babel/generator" "^7.14.8" - "@babel/helper-function-name" "^7.14.5" - "@babel/helper-hoist-variables" "^7.14.5" - "@babel/helper-split-export-declaration" "^7.14.5" - "@babel/parser" "^7.14.8" - "@babel/types" "^7.14.8" + "@babel/generator" "^7.15.4" + "@babel/helper-function-name" "^7.15.4" + "@babel/helper-hoist-variables" "^7.15.4" + "@babel/helper-split-export-declaration" "^7.15.4" + "@babel/parser" "^7.15.4" + "@babel/types" "^7.15.4" debug "^4.1.0" globals "^11.1.0" -"@babel/types@^7.0.0", "@babel/types@^7.14.5", "@babel/types@^7.14.8", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.0": - version "7.14.8" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.14.8.tgz#38109de8fcadc06415fbd9b74df0065d4d41c728" - integrity sha512-iob4soQa7dZw8nodR/KlOQkPh9S4I8RwCxwRIFuiMRYjOzH/KJzdUfDgz6cGi5dDaclXF4P2PAhCdrBJNIg68Q== +"@babel/types@^7.0.0", "@babel/types@^7.15.4", "@babel/types@^7.15.6", "@babel/types@^7.3.0", "@babel/types@^7.3.3": + version "7.15.6" + resolved "https://registry.npmjs.org/@babel/types/-/types-7.15.6.tgz#99abdc48218b2881c058dd0a7ab05b99c9be758f" + integrity sha512-BPU+7QhqNjmWyDO0/vitH/CuhpV8ZmK1wpKva8nuyNF5MJfuRNWMc+hc14+u9xT93kvykMdncrJT19h74uB1Ig== dependencies: - "@babel/helper-validator-identifier" "^7.14.8" + "@babel/helper-validator-identifier" "^7.14.9" to-fast-properties "^2.0.0" "@balena/dockerignore@^1.0.2": version "1.0.2" - resolved "https://registry.yarnpkg.com/@balena/dockerignore/-/dockerignore-1.0.2.tgz#9ffe4726915251e8eb69f44ef3547e0da2c03e0d" + resolved "https://registry.npmjs.org/@balena/dockerignore/-/dockerignore-1.0.2.tgz#9ffe4726915251e8eb69f44ef3547e0da2c03e0d" integrity sha512-wMue2Sy4GAVTk6Ic4tJVcnfdau+gx2EnG7S+uAEe+TWJFqE4YoWN4/H8MSLj4eYJKxGg26lZwboEniNiNwZQ6Q== "@bcoe/v8-coverage@^0.2.3": version "0.2.3" - resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" + resolved "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== "@cnakazawa/watch@^1.0.3": version "1.0.4" - resolved "https://registry.yarnpkg.com/@cnakazawa/watch/-/watch-1.0.4.tgz#f864ae85004d0fcab6f50be9141c4da368d1656a" + resolved "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.4.tgz#f864ae85004d0fcab6f50be9141c4da368d1656a" integrity sha512-v9kIhKwjeZThiWrLmj0y17CWoyddASLj9O2yvbZkbvw/N3rWOYy9zkV66ursAoVr0mV15bL8g0c4QZUE6cdDoQ== dependencies: exec-sh "^0.3.2" minimist "^1.2.0" +"@cspotcode/source-map-consumer@0.8.0": + version "0.8.0" + resolved "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz#33bf4b7b39c178821606f669bbc447a6a629786b" + integrity sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg== + +"@cspotcode/source-map-support@0.7.0": + version "0.7.0" + resolved "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz#4789840aa859e46d2f3173727ab707c66bf344f5" + integrity sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA== + dependencies: + "@cspotcode/source-map-consumer" "0.8.0" + "@eslint/eslintrc@^0.4.3": version "0.4.3" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.3.tgz#9e42981ef035beb3dd49add17acb96e8ff6f394c" + resolved "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz#9e42981ef035beb3dd49add17acb96e8ff6f394c" integrity sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw== dependencies: ajv "^6.12.4" @@ -351,9 +365,14 @@ minimatch "^3.0.4" strip-json-comments "^3.1.1" +"@gar/promisify@^1.0.1": + version "1.1.2" + resolved "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.2.tgz#30aa825f11d438671d585bd44e7fd564535fc210" + integrity sha512-82cpyJyKRoQoRi+14ibCeGPu0CwypgtBAdBhq1WfvagpCZNKqwXbKwXllYSMG91DhmG4jt9gN8eP6lGOtozuaw== + "@humanwhocodes/config-array@^0.5.0": version "0.5.0" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.5.0.tgz#1407967d4c6eecd7388f83acf1eaf4d0c6e58ef9" + resolved "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz#1407967d4c6eecd7388f83acf1eaf4d0c6e58ef9" integrity sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg== dependencies: "@humanwhocodes/object-schema" "^1.2.0" @@ -362,17 +381,17 @@ "@humanwhocodes/object-schema@^1.2.0": version "1.2.0" - resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz#87de7af9c231826fdd68ac7258f77c429e0e5fcf" + resolved "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz#87de7af9c231826fdd68ac7258f77c429e0e5fcf" integrity sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w== "@hutson/parse-repository-url@^3.0.0": version "3.0.2" - resolved "https://registry.yarnpkg.com/@hutson/parse-repository-url/-/parse-repository-url-3.0.2.tgz#98c23c950a3d9b6c8f0daed06da6c3af06981340" + resolved "https://registry.npmjs.org/@hutson/parse-repository-url/-/parse-repository-url-3.0.2.tgz#98c23c950a3d9b6c8f0daed06da6c3af06981340" integrity sha512-H9XAx3hc0BQHY6l+IFSWHDySypcXsvsuLhgYLUGywmJ5pswRVQJUHpOsobnLYp2ZUaUlKiKDrgWWhosOwAEM8Q== "@istanbuljs/load-nyc-config@^1.0.0": version "1.1.0" - resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" + resolved "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== dependencies: camelcase "^5.3.1" @@ -383,12 +402,12 @@ "@istanbuljs/schema@^0.1.2": version "0.1.3" - resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" + resolved "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== "@jest/console@^26.6.2": version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/console/-/console-26.6.2.tgz#4e04bc464014358b03ab4937805ee36a0aeb98f2" + resolved "https://registry.npmjs.org/@jest/console/-/console-26.6.2.tgz#4e04bc464014358b03ab4937805ee36a0aeb98f2" integrity sha512-IY1R2i2aLsLr7Id3S6p2BA82GNWryt4oSvEXLAKc+L2zdi89dSkE8xC1C+0kpATG4JhBJREnQOH7/zmccM2B0g== dependencies: "@jest/types" "^26.6.2" @@ -400,7 +419,7 @@ "@jest/core@^26.6.3": version "26.6.3" - resolved "https://registry.yarnpkg.com/@jest/core/-/core-26.6.3.tgz#7639fcb3833d748a4656ada54bde193051e45fad" + resolved "https://registry.npmjs.org/@jest/core/-/core-26.6.3.tgz#7639fcb3833d748a4656ada54bde193051e45fad" integrity sha512-xvV1kKbhfUqFVuZ8Cyo+JPpipAHHAV3kcDBftiduK8EICXmTFddryy3P7NfZt8Pv37rA9nEJBKCCkglCPt/Xjw== dependencies: "@jest/console" "^26.6.2" @@ -434,7 +453,7 @@ "@jest/environment@^26.6.2": version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-26.6.2.tgz#ba364cc72e221e79cc8f0a99555bf5d7577cf92c" + resolved "https://registry.npmjs.org/@jest/environment/-/environment-26.6.2.tgz#ba364cc72e221e79cc8f0a99555bf5d7577cf92c" integrity sha512-nFy+fHl28zUrRsCeMB61VDThV1pVTtlEokBRgqPrcT1JNq4yRNIyTHfyht6PqtUvY9IsuLGTrbG8kPXjSZIZwA== dependencies: "@jest/fake-timers" "^26.6.2" @@ -444,7 +463,7 @@ "@jest/fake-timers@^26.6.2": version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-26.6.2.tgz#459c329bcf70cee4af4d7e3f3e67848123535aad" + resolved "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-26.6.2.tgz#459c329bcf70cee4af4d7e3f3e67848123535aad" integrity sha512-14Uleatt7jdzefLPYM3KLcnUl1ZNikaKq34enpb5XG9i81JpppDb5muZvonvKyrl7ftEHkKS5L5/eB/kxJ+bvA== dependencies: "@jest/types" "^26.6.2" @@ -456,7 +475,7 @@ "@jest/globals@^26.6.2": version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-26.6.2.tgz#5b613b78a1aa2655ae908eba638cc96a20df720a" + resolved "https://registry.npmjs.org/@jest/globals/-/globals-26.6.2.tgz#5b613b78a1aa2655ae908eba638cc96a20df720a" integrity sha512-85Ltnm7HlB/KesBUuALwQ68YTU72w9H2xW9FjZ1eL1U3lhtefjjl5c2MiUbpXt/i6LaPRvoOFJ22yCBSfQ0JIA== dependencies: "@jest/environment" "^26.6.2" @@ -465,7 +484,7 @@ "@jest/reporters@^26.6.2": version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-26.6.2.tgz#1f518b99637a5f18307bd3ecf9275f6882a667f6" + resolved "https://registry.npmjs.org/@jest/reporters/-/reporters-26.6.2.tgz#1f518b99637a5f18307bd3ecf9275f6882a667f6" integrity sha512-h2bW53APG4HvkOnVMo8q3QXa6pcaNt1HkwVsOPMBV6LD/q9oSpxNSYZQYkAnjdMjrJ86UuYeLo+aEZClV6opnw== dependencies: "@bcoe/v8-coverage" "^0.2.3" @@ -497,7 +516,7 @@ "@jest/source-map@^26.6.2": version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-26.6.2.tgz#29af5e1e2e324cafccc936f218309f54ab69d535" + resolved "https://registry.npmjs.org/@jest/source-map/-/source-map-26.6.2.tgz#29af5e1e2e324cafccc936f218309f54ab69d535" integrity sha512-YwYcCwAnNmOVsZ8mr3GfnzdXDAl4LaenZP5z+G0c8bzC9/dugL8zRmxZzdoTl4IaS3CryS1uWnROLPFmb6lVvA== dependencies: callsites "^3.0.0" @@ -506,7 +525,7 @@ "@jest/test-result@^26.6.2": version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-26.6.2.tgz#55da58b62df134576cc95476efa5f7949e3f5f18" + resolved "https://registry.npmjs.org/@jest/test-result/-/test-result-26.6.2.tgz#55da58b62df134576cc95476efa5f7949e3f5f18" integrity sha512-5O7H5c/7YlojphYNrK02LlDIV2GNPYisKwHm2QTKjNZeEzezCbwYs9swJySv2UfPMyZ0VdsmMv7jIlD/IKYQpQ== dependencies: "@jest/console" "^26.6.2" @@ -516,7 +535,7 @@ "@jest/test-sequencer@^26.6.3": version "26.6.3" - resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-26.6.3.tgz#98e8a45100863886d074205e8ffdc5a7eb582b17" + resolved "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-26.6.3.tgz#98e8a45100863886d074205e8ffdc5a7eb582b17" integrity sha512-YHlVIjP5nfEyjlrSr8t/YdNfU/1XEt7c5b4OxcXCjyRhjzLYu/rO69/WHPuYcbCWkz8kAeZVZp2N2+IOLLEPGw== dependencies: "@jest/test-result" "^26.6.2" @@ -527,7 +546,7 @@ "@jest/transform@^26.6.2": version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-26.6.2.tgz#5ac57c5fa1ad17b2aae83e73e45813894dcf2e4b" + resolved "https://registry.npmjs.org/@jest/transform/-/transform-26.6.2.tgz#5ac57c5fa1ad17b2aae83e73e45813894dcf2e4b" integrity sha512-E9JjhUgNzvuQ+vVAL21vlyfy12gP0GhazGgJC4h6qUt1jSdUXGWJ1wfu/X7Sd8etSgxV4ovT1pb9v5D6QW4XgA== dependencies: "@babel/core" "^7.1.0" @@ -548,7 +567,7 @@ "@jest/types@^26.6.2": version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-26.6.2.tgz#bef5a532030e1d88a2f5a6d933f84e97226ed48e" + resolved "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz#bef5a532030e1d88a2f5a6d933f84e97226ed48e" integrity sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ== dependencies: "@types/istanbul-lib-coverage" "^2.0.0" @@ -557,39 +576,24 @@ "@types/yargs" "^15.0.0" chalk "^4.0.0" -"@jsii/check-node@1.33.0": - version "1.33.0" - resolved "https://registry.yarnpkg.com/@jsii/check-node/-/check-node-1.33.0.tgz#55d75cbef1c84e2012c67ab8d6de63f773be4a9b" - integrity sha512-Bajxa09dhkuQ8bM1ve6qtm2oFNhW9/+GaKRh4Deewsk/G86ovLXI/rRS6TfCsSw4E0TGPFWzWy0tBeJuEDo7sw== +"@jsii/check-node@1.39.0": + version "1.39.0" + resolved "https://registry.npmjs.org/@jsii/check-node/-/check-node-1.39.0.tgz#31a22f6270c790b5f2bb0f7d2950511e6d7c0c9e" + integrity sha512-tqx5o0Zw6WrVKmB9S1X0E8AajfXjWu9yoOUtUdYVCR6NAdi8mY/NQ3uYJ8II0AF1MtC0PdASOjb/6i3h02komw== dependencies: chalk "^4.1.2" semver "^7.3.5" -"@jsii/check-node@1.34.0": - version "1.34.0" - resolved "https://registry.yarnpkg.com/@jsii/check-node/-/check-node-1.34.0.tgz#24da38da36e18639c84787dabd464b8474ddee22" - integrity sha512-Z+eGyIoV6B6RNFCR+Z/p0ANnZA++bmCXhoU1RIwGh9RG39PAT38KkZZNr9ZHNTTQbVoTJMSatoX/9WQ33pQxAw== - dependencies: - chalk "^4.1.2" - semver "^7.3.5" - -"@jsii/spec@^1.31.0": - version "1.31.0" - resolved "https://registry.yarnpkg.com/@jsii/spec/-/spec-1.31.0.tgz#9298dc163fdae0bab4006b817592235a29922871" - integrity sha512-qpJqZ+xj4lnKfk/HJYdYURDmHzh9aBIVOTgwd314AxKmwubDAajlAup+D2F9z9kylAB7GsQiva/SXgUlFjBeQw== - dependencies: - jsonschema "^1.4.0" - -"@jsii/spec@^1.34.0": - version "1.34.0" - resolved "https://registry.yarnpkg.com/@jsii/spec/-/spec-1.34.0.tgz#8b78adf07518f567d2c44bf6c98c426e5c18e0cf" - integrity sha512-yAK8FrTRrZ3lQ+DmdyAFZuHmsTJ1ej0719+sVgjr5ahE9i64huStaraX/jJM+PniuUQwE7N+B49ue6X9qj7vJA== +"@jsii/spec@^1.39.0": + version "1.39.0" + resolved "https://registry.npmjs.org/@jsii/spec/-/spec-1.39.0.tgz#17b2d55f8261da3ed4a670e9a4c5dfa18a7e050a" + integrity sha512-NbCmAYOB938uyWHwXj6fhdeIzznhHbxLmvl4Jtwe08Nrz5Gs4n79snV29XWIQulDMa4HYkNh1yqhBXOHkd+GAg== dependencies: jsonschema "^1.4.0" "@lerna/add@4.0.0": version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/add/-/add-4.0.0.tgz#c36f57d132502a57b9e7058d1548b7a565ef183f" + resolved "https://registry.npmjs.org/@lerna/add/-/add-4.0.0.tgz#c36f57d132502a57b9e7058d1548b7a565ef183f" integrity sha512-cpmAH1iS3k8JBxNvnMqrGTTjbY/ZAiKa1ChJzFevMYY3eeqbvhsBKnBcxjRXtdrJ6bd3dCQM+ZtK+0i682Fhng== dependencies: "@lerna/bootstrap" "4.0.0" @@ -605,7 +609,7 @@ "@lerna/bootstrap@4.0.0": version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/bootstrap/-/bootstrap-4.0.0.tgz#5f5c5e2c6cfc8fcec50cb2fbe569a8c607101891" + resolved "https://registry.npmjs.org/@lerna/bootstrap/-/bootstrap-4.0.0.tgz#5f5c5e2c6cfc8fcec50cb2fbe569a8c607101891" integrity sha512-RkS7UbeM2vu+kJnHzxNRCLvoOP9yGNgkzRdy4UV2hNalD7EP41bLvRVOwRYQ7fhc2QcbhnKNdOBihYRL0LcKtw== dependencies: "@lerna/command" "4.0.0" @@ -633,7 +637,7 @@ "@lerna/changed@4.0.0": version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/changed/-/changed-4.0.0.tgz#b9fc76cea39b9292a6cd263f03eb57af85c9270b" + resolved "https://registry.npmjs.org/@lerna/changed/-/changed-4.0.0.tgz#b9fc76cea39b9292a6cd263f03eb57af85c9270b" integrity sha512-cD+KuPRp6qiPOD+BO6S6SN5cARspIaWSOqGBpGnYzLb4uWT8Vk4JzKyYtc8ym1DIwyoFXHosXt8+GDAgR8QrgQ== dependencies: "@lerna/collect-updates" "4.0.0" @@ -643,7 +647,7 @@ "@lerna/check-working-tree@4.0.0": version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/check-working-tree/-/check-working-tree-4.0.0.tgz#257e36a602c00142e76082a19358e3e1ae8dbd58" + resolved "https://registry.npmjs.org/@lerna/check-working-tree/-/check-working-tree-4.0.0.tgz#257e36a602c00142e76082a19358e3e1ae8dbd58" integrity sha512-/++bxM43jYJCshBiKP5cRlCTwSJdRSxVmcDAXM+1oUewlZJVSVlnks5eO0uLxokVFvLhHlC5kHMc7gbVFPHv6Q== dependencies: "@lerna/collect-uncommitted" "4.0.0" @@ -652,7 +656,7 @@ "@lerna/child-process@4.0.0": version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/child-process/-/child-process-4.0.0.tgz#341b96a57dffbd9705646d316e231df6fa4df6e1" + resolved "https://registry.npmjs.org/@lerna/child-process/-/child-process-4.0.0.tgz#341b96a57dffbd9705646d316e231df6fa4df6e1" integrity sha512-XtCnmCT9eyVsUUHx6y/CTBYdV9g2Cr/VxyseTWBgfIur92/YKClfEtJTbOh94jRT62hlKLqSvux/UhxXVh613Q== dependencies: chalk "^4.1.0" @@ -661,7 +665,7 @@ "@lerna/clean@4.0.0": version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/clean/-/clean-4.0.0.tgz#8f778b6f2617aa2a936a6b5e085ae62498e57dc5" + resolved "https://registry.npmjs.org/@lerna/clean/-/clean-4.0.0.tgz#8f778b6f2617aa2a936a6b5e085ae62498e57dc5" integrity sha512-uugG2iN9k45ITx2jtd8nEOoAtca8hNlDCUM0N3lFgU/b1mEQYAPRkqr1qs4FLRl/Y50ZJ41wUz1eazS+d/0osA== dependencies: "@lerna/command" "4.0.0" @@ -675,7 +679,7 @@ "@lerna/cli@4.0.0": version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/cli/-/cli-4.0.0.tgz#8eabd334558836c1664df23f19acb95e98b5bbf3" + resolved "https://registry.npmjs.org/@lerna/cli/-/cli-4.0.0.tgz#8eabd334558836c1664df23f19acb95e98b5bbf3" integrity sha512-Neaw3GzFrwZiRZv2g7g6NwFjs3er1vhraIniEs0jjVLPMNC4eata0na3GfE5yibkM/9d3gZdmihhZdZ3EBdvYA== dependencies: "@lerna/global-options" "4.0.0" @@ -685,7 +689,7 @@ "@lerna/collect-uncommitted@4.0.0": version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/collect-uncommitted/-/collect-uncommitted-4.0.0.tgz#855cd64612969371cfc2453b90593053ff1ba779" + resolved "https://registry.npmjs.org/@lerna/collect-uncommitted/-/collect-uncommitted-4.0.0.tgz#855cd64612969371cfc2453b90593053ff1ba779" integrity sha512-ufSTfHZzbx69YNj7KXQ3o66V4RC76ffOjwLX0q/ab//61bObJ41n03SiQEhSlmpP+gmFbTJ3/7pTe04AHX9m/g== dependencies: "@lerna/child-process" "4.0.0" @@ -694,7 +698,7 @@ "@lerna/collect-updates@4.0.0": version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/collect-updates/-/collect-updates-4.0.0.tgz#8e208b1bafd98a372ff1177f7a5e288f6bea8041" + resolved "https://registry.npmjs.org/@lerna/collect-updates/-/collect-updates-4.0.0.tgz#8e208b1bafd98a372ff1177f7a5e288f6bea8041" integrity sha512-bnNGpaj4zuxsEkyaCZLka9s7nMs58uZoxrRIPJ+nrmrZYp1V5rrd+7/NYTuunOhY2ug1sTBvTAxj3NZQ+JKnOw== dependencies: "@lerna/child-process" "4.0.0" @@ -705,7 +709,7 @@ "@lerna/command@4.0.0": version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/command/-/command-4.0.0.tgz#991c7971df8f5bf6ae6e42c808869a55361c1b98" + resolved "https://registry.npmjs.org/@lerna/command/-/command-4.0.0.tgz#991c7971df8f5bf6ae6e42c808869a55361c1b98" integrity sha512-LM9g3rt5FsPNFqIHUeRwWXLNHJ5NKzOwmVKZ8anSp4e1SPrv2HNc1V02/9QyDDZK/w+5POXH5lxZUI1CHaOK/A== dependencies: "@lerna/child-process" "4.0.0" @@ -721,7 +725,7 @@ "@lerna/conventional-commits@4.0.0": version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/conventional-commits/-/conventional-commits-4.0.0.tgz#660fb2c7b718cb942ead70110df61f18c6f99750" + resolved "https://registry.npmjs.org/@lerna/conventional-commits/-/conventional-commits-4.0.0.tgz#660fb2c7b718cb942ead70110df61f18c6f99750" integrity sha512-CSUQRjJHFrH8eBn7+wegZLV3OrNc0Y1FehYfYGhjLE2SIfpCL4bmfu/ViYuHh9YjwHaA+4SX6d3hR+xkeseKmw== dependencies: "@lerna/validation-error" "4.0.0" @@ -738,7 +742,7 @@ "@lerna/create-symlink@4.0.0": version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/create-symlink/-/create-symlink-4.0.0.tgz#8c5317ce5ae89f67825443bd7651bf4121786228" + resolved "https://registry.npmjs.org/@lerna/create-symlink/-/create-symlink-4.0.0.tgz#8c5317ce5ae89f67825443bd7651bf4121786228" integrity sha512-I0phtKJJdafUiDwm7BBlEUOtogmu8+taxq6PtIrxZbllV9hWg59qkpuIsiFp+no7nfRVuaasNYHwNUhDAVQBig== dependencies: cmd-shim "^4.1.0" @@ -747,7 +751,7 @@ "@lerna/create@4.0.0": version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/create/-/create-4.0.0.tgz#b6947e9b5dfb6530321952998948c3e63d64d730" + resolved "https://registry.npmjs.org/@lerna/create/-/create-4.0.0.tgz#b6947e9b5dfb6530321952998948c3e63d64d730" integrity sha512-mVOB1niKByEUfxlbKTM1UNECWAjwUdiioIbRQZEeEabtjCL69r9rscIsjlGyhGWCfsdAG5wfq4t47nlDXdLLag== dependencies: "@lerna/child-process" "4.0.0" @@ -771,7 +775,7 @@ "@lerna/describe-ref@4.0.0": version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/describe-ref/-/describe-ref-4.0.0.tgz#53c53b4ea65fdceffa072a62bfebe6772c45d9ec" + resolved "https://registry.npmjs.org/@lerna/describe-ref/-/describe-ref-4.0.0.tgz#53c53b4ea65fdceffa072a62bfebe6772c45d9ec" integrity sha512-eTU5+xC4C5Gcgz+Ey4Qiw9nV2B4JJbMulsYJMW8QjGcGh8zudib7Sduj6urgZXUYNyhYpRs+teci9M2J8u+UvQ== dependencies: "@lerna/child-process" "4.0.0" @@ -779,7 +783,7 @@ "@lerna/diff@4.0.0": version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/diff/-/diff-4.0.0.tgz#6d3071817aaa4205a07bf77cfc6e932796d48b92" + resolved "https://registry.npmjs.org/@lerna/diff/-/diff-4.0.0.tgz#6d3071817aaa4205a07bf77cfc6e932796d48b92" integrity sha512-jYPKprQVg41+MUMxx6cwtqsNm0Yxx9GDEwdiPLwcUTFx+/qKCEwifKNJ1oGIPBxyEHX2PFCOjkK39lHoj2qiag== dependencies: "@lerna/child-process" "4.0.0" @@ -789,7 +793,7 @@ "@lerna/exec@4.0.0": version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/exec/-/exec-4.0.0.tgz#eb6cb95cb92d42590e9e2d628fcaf4719d4a8be6" + resolved "https://registry.npmjs.org/@lerna/exec/-/exec-4.0.0.tgz#eb6cb95cb92d42590e9e2d628fcaf4719d4a8be6" integrity sha512-VGXtL/b/JfY84NB98VWZpIExfhLOzy0ozm/0XaS4a2SmkAJc5CeUfrhvHxxkxiTBLkU+iVQUyYEoAT0ulQ8PCw== dependencies: "@lerna/child-process" "4.0.0" @@ -802,7 +806,7 @@ "@lerna/filter-options@4.0.0": version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/filter-options/-/filter-options-4.0.0.tgz#ac94cc515d7fa3b47e2f7d74deddeabb1de5e9e6" + resolved "https://registry.npmjs.org/@lerna/filter-options/-/filter-options-4.0.0.tgz#ac94cc515d7fa3b47e2f7d74deddeabb1de5e9e6" integrity sha512-vV2ANOeZhOqM0rzXnYcFFCJ/kBWy/3OA58irXih9AMTAlQLymWAK0akWybl++sUJ4HB9Hx12TOqaXbYS2NM5uw== dependencies: "@lerna/collect-updates" "4.0.0" @@ -812,7 +816,7 @@ "@lerna/filter-packages@4.0.0": version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/filter-packages/-/filter-packages-4.0.0.tgz#b1f70d70e1de9cdd36a4e50caa0ac501f8d012f2" + resolved "https://registry.npmjs.org/@lerna/filter-packages/-/filter-packages-4.0.0.tgz#b1f70d70e1de9cdd36a4e50caa0ac501f8d012f2" integrity sha512-+4AJIkK7iIiOaqCiVTYJxh/I9qikk4XjNQLhE3kixaqgMuHl1NQ99qXRR0OZqAWB9mh8Z1HA9bM5K1HZLBTOqA== dependencies: "@lerna/validation-error" "4.0.0" @@ -821,14 +825,14 @@ "@lerna/get-npm-exec-opts@4.0.0": version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/get-npm-exec-opts/-/get-npm-exec-opts-4.0.0.tgz#dc955be94a4ae75c374ef9bce91320887d34608f" + resolved "https://registry.npmjs.org/@lerna/get-npm-exec-opts/-/get-npm-exec-opts-4.0.0.tgz#dc955be94a4ae75c374ef9bce91320887d34608f" integrity sha512-yvmkerU31CTWS2c7DvmAWmZVeclPBqI7gPVr5VATUKNWJ/zmVcU4PqbYoLu92I9Qc4gY1TuUplMNdNuZTSL7IQ== dependencies: npmlog "^4.1.2" "@lerna/get-packed@4.0.0": version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/get-packed/-/get-packed-4.0.0.tgz#0989d61624ac1f97e393bdad2137c49cd7a37823" + resolved "https://registry.npmjs.org/@lerna/get-packed/-/get-packed-4.0.0.tgz#0989d61624ac1f97e393bdad2137c49cd7a37823" integrity sha512-rfWONRsEIGyPJTxFzC8ECb3ZbsDXJbfqWYyeeQQDrJRPnEJErlltRLPLgC2QWbxFgFPsoDLeQmFHJnf0iDfd8w== dependencies: fs-extra "^9.1.0" @@ -837,7 +841,7 @@ "@lerna/github-client@4.0.0": version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/github-client/-/github-client-4.0.0.tgz#2ced67721363ef70f8e12ffafce4410918f4a8a4" + resolved "https://registry.npmjs.org/@lerna/github-client/-/github-client-4.0.0.tgz#2ced67721363ef70f8e12ffafce4410918f4a8a4" integrity sha512-2jhsldZtTKXYUBnOm23Lb0Fx8G4qfSXF9y7UpyUgWUj+YZYd+cFxSuorwQIgk5P4XXrtVhsUesIsli+BYSThiw== dependencies: "@lerna/child-process" "4.0.0" @@ -848,7 +852,7 @@ "@lerna/gitlab-client@4.0.0": version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/gitlab-client/-/gitlab-client-4.0.0.tgz#00dad73379c7b38951d4b4ded043504c14e2b67d" + resolved "https://registry.npmjs.org/@lerna/gitlab-client/-/gitlab-client-4.0.0.tgz#00dad73379c7b38951d4b4ded043504c14e2b67d" integrity sha512-OMUpGSkeDWFf7BxGHlkbb35T7YHqVFCwBPSIR6wRsszY8PAzCYahtH3IaJzEJyUg6vmZsNl0FSr3pdA2skhxqA== dependencies: node-fetch "^2.6.1" @@ -857,12 +861,12 @@ "@lerna/global-options@4.0.0": version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/global-options/-/global-options-4.0.0.tgz#c7d8b0de6a01d8a845e2621ea89e7f60f18c6a5f" + resolved "https://registry.npmjs.org/@lerna/global-options/-/global-options-4.0.0.tgz#c7d8b0de6a01d8a845e2621ea89e7f60f18c6a5f" integrity sha512-TRMR8afAHxuYBHK7F++Ogop2a82xQjoGna1dvPOY6ltj/pEx59pdgcJfYcynYqMkFIk8bhLJJN9/ndIfX29FTQ== "@lerna/has-npm-version@4.0.0": version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/has-npm-version/-/has-npm-version-4.0.0.tgz#d3fc3292c545eb28bd493b36e6237cf0279f631c" + resolved "https://registry.npmjs.org/@lerna/has-npm-version/-/has-npm-version-4.0.0.tgz#d3fc3292c545eb28bd493b36e6237cf0279f631c" integrity sha512-LQ3U6XFH8ZmLCsvsgq1zNDqka0Xzjq5ibVN+igAI5ccRWNaUsE/OcmsyMr50xAtNQMYMzmpw5GVLAivT2/YzCg== dependencies: "@lerna/child-process" "4.0.0" @@ -870,7 +874,7 @@ "@lerna/import@4.0.0": version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/import/-/import-4.0.0.tgz#bde656c4a451fa87ae41733ff8a8da60547c5465" + resolved "https://registry.npmjs.org/@lerna/import/-/import-4.0.0.tgz#bde656c4a451fa87ae41733ff8a8da60547c5465" integrity sha512-FaIhd+4aiBousKNqC7TX1Uhe97eNKf5/SC7c5WZANVWtC7aBWdmswwDt3usrzCNpj6/Wwr9EtEbYROzxKH8ffg== dependencies: "@lerna/child-process" "4.0.0" @@ -884,7 +888,7 @@ "@lerna/info@4.0.0": version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/info/-/info-4.0.0.tgz#b9fb0e479d60efe1623603958a831a88b1d7f1fc" + resolved "https://registry.npmjs.org/@lerna/info/-/info-4.0.0.tgz#b9fb0e479d60efe1623603958a831a88b1d7f1fc" integrity sha512-8Uboa12kaCSZEn4XRfPz5KU9XXoexSPS4oeYGj76s2UQb1O1GdnEyfjyNWoUl1KlJ2i/8nxUskpXIftoFYH0/Q== dependencies: "@lerna/command" "4.0.0" @@ -893,7 +897,7 @@ "@lerna/init@4.0.0": version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/init/-/init-4.0.0.tgz#dadff67e6dfb981e8ccbe0e6a310e837962f6c7a" + resolved "https://registry.npmjs.org/@lerna/init/-/init-4.0.0.tgz#dadff67e6dfb981e8ccbe0e6a310e837962f6c7a" integrity sha512-wY6kygop0BCXupzWj5eLvTUqdR7vIAm0OgyV9WHpMYQGfs1V22jhztt8mtjCloD/O0nEe4tJhdG62XU5aYmPNQ== dependencies: "@lerna/child-process" "4.0.0" @@ -904,7 +908,7 @@ "@lerna/link@4.0.0": version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/link/-/link-4.0.0.tgz#c3a38aabd44279d714e90f2451e31b63f0fb65ba" + resolved "https://registry.npmjs.org/@lerna/link/-/link-4.0.0.tgz#c3a38aabd44279d714e90f2451e31b63f0fb65ba" integrity sha512-KlvPi7XTAcVOByfaLlOeYOfkkDcd+bejpHMCd1KcArcFTwijOwXOVi24DYomIeHvy6HsX/IUquJ4PPUJIeB4+w== dependencies: "@lerna/command" "4.0.0" @@ -915,7 +919,7 @@ "@lerna/list@4.0.0": version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/list/-/list-4.0.0.tgz#24b4e6995bd73f81c556793fe502b847efd9d1d7" + resolved "https://registry.npmjs.org/@lerna/list/-/list-4.0.0.tgz#24b4e6995bd73f81c556793fe502b847efd9d1d7" integrity sha512-L2B5m3P+U4Bif5PultR4TI+KtW+SArwq1i75QZ78mRYxPc0U/piau1DbLOmwrdqr99wzM49t0Dlvl6twd7GHFg== dependencies: "@lerna/command" "4.0.0" @@ -925,7 +929,7 @@ "@lerna/listable@4.0.0": version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/listable/-/listable-4.0.0.tgz#d00d6cb4809b403f2b0374fc521a78e318b01214" + resolved "https://registry.npmjs.org/@lerna/listable/-/listable-4.0.0.tgz#d00d6cb4809b403f2b0374fc521a78e318b01214" integrity sha512-/rPOSDKsOHs5/PBLINZOkRIX1joOXUXEtyUs5DHLM8q6/RP668x/1lFhw6Dx7/U+L0+tbkpGtZ1Yt0LewCLgeQ== dependencies: "@lerna/query-graph" "4.0.0" @@ -934,7 +938,7 @@ "@lerna/log-packed@4.0.0": version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/log-packed/-/log-packed-4.0.0.tgz#95168fe2e26ac6a71e42f4be857519b77e57a09f" + resolved "https://registry.npmjs.org/@lerna/log-packed/-/log-packed-4.0.0.tgz#95168fe2e26ac6a71e42f4be857519b77e57a09f" integrity sha512-+dpCiWbdzgMAtpajLToy9PO713IHoE6GV/aizXycAyA07QlqnkpaBNZ8DW84gHdM1j79TWockGJo9PybVhrrZQ== dependencies: byte-size "^7.0.0" @@ -944,7 +948,7 @@ "@lerna/npm-conf@4.0.0": version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/npm-conf/-/npm-conf-4.0.0.tgz#b259fd1e1cee2bf5402b236e770140ff9ade7fd2" + resolved "https://registry.npmjs.org/@lerna/npm-conf/-/npm-conf-4.0.0.tgz#b259fd1e1cee2bf5402b236e770140ff9ade7fd2" integrity sha512-uS7H02yQNq3oejgjxAxqq/jhwGEE0W0ntr8vM3EfpCW1F/wZruwQw+7bleJQ9vUBjmdXST//tk8mXzr5+JXCfw== dependencies: config-chain "^1.1.12" @@ -952,7 +956,7 @@ "@lerna/npm-dist-tag@4.0.0": version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/npm-dist-tag/-/npm-dist-tag-4.0.0.tgz#d1e99b4eccd3414142f0548ad331bf2d53f3257a" + resolved "https://registry.npmjs.org/@lerna/npm-dist-tag/-/npm-dist-tag-4.0.0.tgz#d1e99b4eccd3414142f0548ad331bf2d53f3257a" integrity sha512-F20sg28FMYTgXqEQihgoqSfwmq+Id3zT23CnOwD+XQMPSy9IzyLf1fFVH319vXIw6NF6Pgs4JZN2Qty6/CQXGw== dependencies: "@lerna/otplease" "4.0.0" @@ -962,7 +966,7 @@ "@lerna/npm-install@4.0.0": version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/npm-install/-/npm-install-4.0.0.tgz#31180be3ab3b7d1818a1a0c206aec156b7094c78" + resolved "https://registry.npmjs.org/@lerna/npm-install/-/npm-install-4.0.0.tgz#31180be3ab3b7d1818a1a0c206aec156b7094c78" integrity sha512-aKNxq2j3bCH3eXl3Fmu4D54s/YLL9WSwV8W7X2O25r98wzrO38AUN6AB9EtmAx+LV/SP15et7Yueg9vSaanRWg== dependencies: "@lerna/child-process" "4.0.0" @@ -975,7 +979,7 @@ "@lerna/npm-publish@4.0.0": version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/npm-publish/-/npm-publish-4.0.0.tgz#84eb62e876fe949ae1fd62c60804423dbc2c4472" + resolved "https://registry.npmjs.org/@lerna/npm-publish/-/npm-publish-4.0.0.tgz#84eb62e876fe949ae1fd62c60804423dbc2c4472" integrity sha512-vQb7yAPRo5G5r77DRjHITc9piR9gvEKWrmfCH7wkfBnGWEqu7n8/4bFQ7lhnkujvc8RXOsYpvbMQkNfkYibD/w== dependencies: "@lerna/otplease" "4.0.0" @@ -989,7 +993,7 @@ "@lerna/npm-run-script@4.0.0": version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/npm-run-script/-/npm-run-script-4.0.0.tgz#dfebf4f4601442e7c0b5214f9fb0d96c9350743b" + resolved "https://registry.npmjs.org/@lerna/npm-run-script/-/npm-run-script-4.0.0.tgz#dfebf4f4601442e7c0b5214f9fb0d96c9350743b" integrity sha512-Jmyh9/IwXJjOXqKfIgtxi0bxi1pUeKe5bD3S81tkcy+kyng/GNj9WSqD5ZggoNP2NP//s4CLDAtUYLdP7CU9rA== dependencies: "@lerna/child-process" "4.0.0" @@ -998,21 +1002,21 @@ "@lerna/otplease@4.0.0": version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/otplease/-/otplease-4.0.0.tgz#84972eb43448f8a1077435ba1c5e59233b725850" + resolved "https://registry.npmjs.org/@lerna/otplease/-/otplease-4.0.0.tgz#84972eb43448f8a1077435ba1c5e59233b725850" integrity sha512-Sgzbqdk1GH4psNiT6hk+BhjOfIr/5KhGBk86CEfHNJTk9BK4aZYyJD4lpDbDdMjIV4g03G7pYoqHzH765T4fxw== dependencies: "@lerna/prompt" "4.0.0" "@lerna/output@4.0.0": version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/output/-/output-4.0.0.tgz#b1d72215c0e35483e4f3e9994debc82c621851f2" + resolved "https://registry.npmjs.org/@lerna/output/-/output-4.0.0.tgz#b1d72215c0e35483e4f3e9994debc82c621851f2" integrity sha512-Un1sHtO1AD7buDQrpnaYTi2EG6sLF+KOPEAMxeUYG5qG3khTs2Zgzq5WE3dt2N/bKh7naESt20JjIW6tBELP0w== dependencies: npmlog "^4.1.2" "@lerna/pack-directory@4.0.0": version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/pack-directory/-/pack-directory-4.0.0.tgz#8b617db95d20792f043aaaa13a9ccc0e04cb4c74" + resolved "https://registry.npmjs.org/@lerna/pack-directory/-/pack-directory-4.0.0.tgz#8b617db95d20792f043aaaa13a9ccc0e04cb4c74" integrity sha512-NJrmZNmBHS+5aM+T8N6FVbaKFScVqKlQFJNY2k7nsJ/uklNKsLLl6VhTQBPwMTbf6Tf7l6bcKzpy7aePuq9UiQ== dependencies: "@lerna/get-packed" "4.0.0" @@ -1025,7 +1029,7 @@ "@lerna/package-graph@4.0.0": version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/package-graph/-/package-graph-4.0.0.tgz#16a00253a8ac810f72041481cb46bcee8d8123dd" + resolved "https://registry.npmjs.org/@lerna/package-graph/-/package-graph-4.0.0.tgz#16a00253a8ac810f72041481cb46bcee8d8123dd" integrity sha512-QED2ZCTkfXMKFoTGoccwUzjHtZMSf3UKX14A4/kYyBms9xfFsesCZ6SLI5YeySEgcul8iuIWfQFZqRw+Qrjraw== dependencies: "@lerna/prerelease-id-from-version" "4.0.0" @@ -1036,7 +1040,7 @@ "@lerna/package@4.0.0": version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/package/-/package-4.0.0.tgz#1b4c259c4bcff45c876ee1d591a043aacbc0d6b7" + resolved "https://registry.npmjs.org/@lerna/package/-/package-4.0.0.tgz#1b4c259c4bcff45c876ee1d591a043aacbc0d6b7" integrity sha512-l0M/izok6FlyyitxiQKr+gZLVFnvxRQdNhzmQ6nRnN9dvBJWn+IxxpM+cLqGACatTnyo9LDzNTOj2Db3+s0s8Q== dependencies: load-json-file "^6.2.0" @@ -1045,14 +1049,14 @@ "@lerna/prerelease-id-from-version@4.0.0": version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/prerelease-id-from-version/-/prerelease-id-from-version-4.0.0.tgz#c7e0676fcee1950d85630e108eddecdd5b48c916" + resolved "https://registry.npmjs.org/@lerna/prerelease-id-from-version/-/prerelease-id-from-version-4.0.0.tgz#c7e0676fcee1950d85630e108eddecdd5b48c916" integrity sha512-GQqguzETdsYRxOSmdFZ6zDBXDErIETWOqomLERRY54f4p+tk4aJjoVdd9xKwehC9TBfIFvlRbL1V9uQGHh1opg== dependencies: semver "^7.3.4" "@lerna/profiler@4.0.0": version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/profiler/-/profiler-4.0.0.tgz#8a53ab874522eae15d178402bff90a14071908e9" + resolved "https://registry.npmjs.org/@lerna/profiler/-/profiler-4.0.0.tgz#8a53ab874522eae15d178402bff90a14071908e9" integrity sha512-/BaEbqnVh1LgW/+qz8wCuI+obzi5/vRE8nlhjPzdEzdmWmZXuCKyWSEzAyHOJWw1ntwMiww5dZHhFQABuoFz9Q== dependencies: fs-extra "^9.1.0" @@ -1061,7 +1065,7 @@ "@lerna/project@4.0.0", "@lerna/project@^4.0.0": version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/project/-/project-4.0.0.tgz#ff84893935833533a74deff30c0e64ddb7f0ba6b" + resolved "https://registry.npmjs.org/@lerna/project/-/project-4.0.0.tgz#ff84893935833533a74deff30c0e64ddb7f0ba6b" integrity sha512-o0MlVbDkD5qRPkFKlBZsXZjoNTWPyuL58564nSfZJ6JYNmgAptnWPB2dQlAc7HWRZkmnC2fCkEdoU+jioPavbg== dependencies: "@lerna/package" "4.0.0" @@ -1079,7 +1083,7 @@ "@lerna/prompt@4.0.0": version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/prompt/-/prompt-4.0.0.tgz#5ec69a803f3f0db0ad9f221dad64664d3daca41b" + resolved "https://registry.npmjs.org/@lerna/prompt/-/prompt-4.0.0.tgz#5ec69a803f3f0db0ad9f221dad64664d3daca41b" integrity sha512-4Ig46oCH1TH5M7YyTt53fT6TuaKMgqUUaqdgxvp6HP6jtdak6+amcsqB8YGz2eQnw/sdxunx84DfI9XpoLj4bQ== dependencies: inquirer "^7.3.3" @@ -1087,7 +1091,7 @@ "@lerna/publish@4.0.0": version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/publish/-/publish-4.0.0.tgz#f67011305adeba120066a3b6d984a5bb5fceef65" + resolved "https://registry.npmjs.org/@lerna/publish/-/publish-4.0.0.tgz#f67011305adeba120066a3b6d984a5bb5fceef65" integrity sha512-K8jpqjHrChH22qtkytA5GRKIVFEtqBF6JWj1I8dWZtHs4Jywn8yB1jQ3BAMLhqmDJjWJtRck0KXhQQKzDK2UPg== dependencies: "@lerna/check-working-tree" "4.0.0" @@ -1121,21 +1125,21 @@ "@lerna/pulse-till-done@4.0.0": version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/pulse-till-done/-/pulse-till-done-4.0.0.tgz#04bace7d483a8205c187b806bcd8be23d7bb80a3" + resolved "https://registry.npmjs.org/@lerna/pulse-till-done/-/pulse-till-done-4.0.0.tgz#04bace7d483a8205c187b806bcd8be23d7bb80a3" integrity sha512-Frb4F7QGckaybRhbF7aosLsJ5e9WuH7h0KUkjlzSByVycxY91UZgaEIVjS2oN9wQLrheLMHl6SiFY0/Pvo0Cxg== dependencies: npmlog "^4.1.2" "@lerna/query-graph@4.0.0": version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/query-graph/-/query-graph-4.0.0.tgz#09dd1c819ac5ee3f38db23931143701f8a6eef63" + resolved "https://registry.npmjs.org/@lerna/query-graph/-/query-graph-4.0.0.tgz#09dd1c819ac5ee3f38db23931143701f8a6eef63" integrity sha512-YlP6yI3tM4WbBmL9GCmNDoeQyzcyg1e4W96y/PKMZa5GbyUvkS2+Jc2kwPD+5KcXou3wQZxSPzR3Te5OenaDdg== dependencies: "@lerna/package-graph" "4.0.0" "@lerna/resolve-symlink@4.0.0": version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/resolve-symlink/-/resolve-symlink-4.0.0.tgz#6d006628a210c9b821964657a9e20a8c9a115e14" + resolved "https://registry.npmjs.org/@lerna/resolve-symlink/-/resolve-symlink-4.0.0.tgz#6d006628a210c9b821964657a9e20a8c9a115e14" integrity sha512-RtX8VEUzqT+uLSCohx8zgmjc6zjyRlh6i/helxtZTMmc4+6O4FS9q5LJas2uGO2wKvBlhcD6siibGt7dIC3xZA== dependencies: fs-extra "^9.1.0" @@ -1144,7 +1148,7 @@ "@lerna/rimraf-dir@4.0.0": version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/rimraf-dir/-/rimraf-dir-4.0.0.tgz#2edf3b62d4eb0ef4e44e430f5844667d551ec25a" + resolved "https://registry.npmjs.org/@lerna/rimraf-dir/-/rimraf-dir-4.0.0.tgz#2edf3b62d4eb0ef4e44e430f5844667d551ec25a" integrity sha512-QNH9ABWk9mcMJh2/muD9iYWBk1oQd40y6oH+f3wwmVGKYU5YJD//+zMiBI13jxZRtwBx0vmBZzkBkK1dR11cBg== dependencies: "@lerna/child-process" "4.0.0" @@ -1154,7 +1158,7 @@ "@lerna/run-lifecycle@4.0.0": version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/run-lifecycle/-/run-lifecycle-4.0.0.tgz#e648a46f9210a9bcd7c391df6844498cb5079334" + resolved "https://registry.npmjs.org/@lerna/run-lifecycle/-/run-lifecycle-4.0.0.tgz#e648a46f9210a9bcd7c391df6844498cb5079334" integrity sha512-IwxxsajjCQQEJAeAaxF8QdEixfI7eLKNm4GHhXHrgBu185JcwScFZrj9Bs+PFKxwb+gNLR4iI5rpUdY8Y0UdGQ== dependencies: "@lerna/npm-conf" "4.0.0" @@ -1163,7 +1167,7 @@ "@lerna/run-topologically@4.0.0": version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/run-topologically/-/run-topologically-4.0.0.tgz#af846eeee1a09b0c2be0d1bfb5ef0f7b04bb1827" + resolved "https://registry.npmjs.org/@lerna/run-topologically/-/run-topologically-4.0.0.tgz#af846eeee1a09b0c2be0d1bfb5ef0f7b04bb1827" integrity sha512-EVZw9hGwo+5yp+VL94+NXRYisqgAlj0jWKWtAIynDCpghRxCE5GMO3xrQLmQgqkpUl9ZxQFpICgYv5DW4DksQA== dependencies: "@lerna/query-graph" "4.0.0" @@ -1171,7 +1175,7 @@ "@lerna/run@4.0.0": version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/run/-/run-4.0.0.tgz#4bc7fda055a729487897c23579694f6183c91262" + resolved "https://registry.npmjs.org/@lerna/run/-/run-4.0.0.tgz#4bc7fda055a729487897c23579694f6183c91262" integrity sha512-9giulCOzlMPzcZS/6Eov6pxE9gNTyaXk0Man+iCIdGJNMrCnW7Dme0Z229WWP/UoxDKg71F2tMsVVGDiRd8fFQ== dependencies: "@lerna/command" "4.0.0" @@ -1186,7 +1190,7 @@ "@lerna/symlink-binary@4.0.0": version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/symlink-binary/-/symlink-binary-4.0.0.tgz#21009f62d53a425f136cb4c1a32c6b2a0cc02d47" + resolved "https://registry.npmjs.org/@lerna/symlink-binary/-/symlink-binary-4.0.0.tgz#21009f62d53a425f136cb4c1a32c6b2a0cc02d47" integrity sha512-zualodWC4q1QQc1pkz969hcFeWXOsVYZC5AWVtAPTDfLl+TwM7eG/O6oP+Rr3fFowspxo6b1TQ6sYfDV6HXNWA== dependencies: "@lerna/create-symlink" "4.0.0" @@ -1196,7 +1200,7 @@ "@lerna/symlink-dependencies@4.0.0": version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/symlink-dependencies/-/symlink-dependencies-4.0.0.tgz#8910eca084ae062642d0490d8972cf2d98e9ebbd" + resolved "https://registry.npmjs.org/@lerna/symlink-dependencies/-/symlink-dependencies-4.0.0.tgz#8910eca084ae062642d0490d8972cf2d98e9ebbd" integrity sha512-BABo0MjeUHNAe2FNGty1eantWp8u83BHSeIMPDxNq0MuW2K3CiQRaeWT3EGPAzXpGt0+hVzBrA6+OT0GPn7Yuw== dependencies: "@lerna/create-symlink" "4.0.0" @@ -1208,19 +1212,19 @@ "@lerna/timer@4.0.0": version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/timer/-/timer-4.0.0.tgz#a52e51bfcd39bfd768988049ace7b15c1fd7a6da" + resolved "https://registry.npmjs.org/@lerna/timer/-/timer-4.0.0.tgz#a52e51bfcd39bfd768988049ace7b15c1fd7a6da" integrity sha512-WFsnlaE7SdOvjuyd05oKt8Leg3ENHICnvX3uYKKdByA+S3g+TCz38JsNs7OUZVt+ba63nC2nbXDlUnuT2Xbsfg== "@lerna/validation-error@4.0.0": version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/validation-error/-/validation-error-4.0.0.tgz#af9d62fe8304eaa2eb9a6ba1394f9aa807026d35" + resolved "https://registry.npmjs.org/@lerna/validation-error/-/validation-error-4.0.0.tgz#af9d62fe8304eaa2eb9a6ba1394f9aa807026d35" integrity sha512-1rBOM5/koiVWlRi3V6dB863E1YzJS8v41UtsHgMr6gB2ncJ2LsQtMKlJpi3voqcgh41H8UsPXR58RrrpPpufyw== dependencies: npmlog "^4.1.2" "@lerna/version@4.0.0": version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/version/-/version-4.0.0.tgz#532659ec6154d8a8789c5ab53878663e244e3228" + resolved "https://registry.npmjs.org/@lerna/version/-/version-4.0.0.tgz#532659ec6154d8a8789c5ab53878663e244e3228" integrity sha512-otUgiqs5W9zGWJZSCCMRV/2Zm2A9q9JwSDS7s/tlKq4mWCYriWo7+wsHEA/nPTMDyYyBO5oyZDj+3X50KDUzeA== dependencies: "@lerna/check-working-tree" "4.0.0" @@ -1252,7 +1256,7 @@ "@lerna/write-log-file@4.0.0": version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/write-log-file/-/write-log-file-4.0.0.tgz#18221a38a6a307d6b0a5844dd592ad53fa27091e" + resolved "https://registry.npmjs.org/@lerna/write-log-file/-/write-log-file-4.0.0.tgz#18221a38a6a307d6b0a5844dd592ad53fa27091e" integrity sha512-XRG5BloiArpXRakcnPHmEHJp+4AtnhRtpDIHSghmXD5EichI1uD73J7FgPp30mm2pDRq3FdqB0NbwSEsJ9xFQg== dependencies: npmlog "^4.1.2" @@ -1260,7 +1264,7 @@ "@nodelib/fs.scandir@2.1.5": version "2.1.5" - resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + resolved "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== dependencies: "@nodelib/fs.stat" "2.0.5" @@ -1268,12 +1272,12 @@ "@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": version "2.0.5" - resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== "@nodelib/fs.walk@^1.2.3": version "1.2.8" - resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + resolved "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== dependencies: "@nodelib/fs.scandir" "2.1.5" @@ -1281,12 +1285,20 @@ "@npmcli/ci-detect@^1.0.0": version "1.3.0" - resolved "https://registry.yarnpkg.com/@npmcli/ci-detect/-/ci-detect-1.3.0.tgz#6c1d2c625fb6ef1b9dea85ad0a5afcbef85ef22a" + resolved "https://registry.npmjs.org/@npmcli/ci-detect/-/ci-detect-1.3.0.tgz#6c1d2c625fb6ef1b9dea85ad0a5afcbef85ef22a" integrity sha512-oN3y7FAROHhrAt7Rr7PnTSwrHrZVRTS2ZbyxeQwSSYD0ifwM3YNgQqbaRmjcWoPyq77MjchusjJDspbzMmip1Q== +"@npmcli/fs@^1.0.0": + version "1.0.0" + resolved "https://registry.npmjs.org/@npmcli/fs/-/fs-1.0.0.tgz#589612cfad3a6ea0feafcb901d29c63fd52db09f" + integrity sha512-8ltnOpRR/oJbOp8vaGUnipOi3bqkcW+sLHFlyXIr08OGHmVJLB1Hn7QtGXbYcpVtH1gAYZTlmDXtE4YV0+AMMQ== + dependencies: + "@gar/promisify" "^1.0.1" + semver "^7.3.5" + "@npmcli/git@^2.1.0": version "2.1.0" - resolved "https://registry.yarnpkg.com/@npmcli/git/-/git-2.1.0.tgz#2fbd77e147530247d37f325930d457b3ebe894f6" + resolved "https://registry.npmjs.org/@npmcli/git/-/git-2.1.0.tgz#2fbd77e147530247d37f325930d457b3ebe894f6" integrity sha512-/hBFX/QG1b+N7PZBFs0bi+evgRZcK9nWBxQKZkGoXUT5hJSwl5c4d7y8/hm+NQZRPhQ67RzFaj5UM9YeyKoryw== dependencies: "@npmcli/promise-spawn" "^1.3.2" @@ -1300,7 +1312,7 @@ "@npmcli/installed-package-contents@^1.0.6": version "1.0.7" - resolved "https://registry.yarnpkg.com/@npmcli/installed-package-contents/-/installed-package-contents-1.0.7.tgz#ab7408c6147911b970a8abe261ce512232a3f4fa" + resolved "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-1.0.7.tgz#ab7408c6147911b970a8abe261ce512232a3f4fa" integrity sha512-9rufe0wnJusCQoLpV9ZPKIVP55itrM5BxOXs10DmdbRfgWtHy1LDyskbwRnBghuB0PrF7pNPOqREVtpz4HqzKw== dependencies: npm-bundled "^1.1.1" @@ -1308,45 +1320,44 @@ "@npmcli/move-file@^1.0.1": version "1.1.2" - resolved "https://registry.yarnpkg.com/@npmcli/move-file/-/move-file-1.1.2.tgz#1a82c3e372f7cae9253eb66d72543d6b8685c674" + resolved "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz#1a82c3e372f7cae9253eb66d72543d6b8685c674" integrity sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg== dependencies: mkdirp "^1.0.4" rimraf "^3.0.2" "@npmcli/node-gyp@^1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@npmcli/node-gyp/-/node-gyp-1.0.2.tgz#3cdc1f30e9736dbc417373ed803b42b1a0a29ede" - integrity sha512-yrJUe6reVMpktcvagumoqD9r08fH1iRo01gn1u0zoCApa9lnZGEigVKUd2hzsCId4gdtkZZIVscLhNxMECKgRg== + version "1.0.3" + resolved "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-1.0.3.tgz#a912e637418ffc5f2db375e93b85837691a43a33" + integrity sha512-fnkhw+fmX65kiLqk6E3BFLXNC26rUhK90zVwe2yncPliVT/Qos3xjhTLE59Df8KnPlcwIERXKVlU1bXoUQ+liA== "@npmcli/promise-spawn@^1.2.0", "@npmcli/promise-spawn@^1.3.2": version "1.3.2" - resolved "https://registry.yarnpkg.com/@npmcli/promise-spawn/-/promise-spawn-1.3.2.tgz#42d4e56a8e9274fba180dabc0aea6e38f29274f5" + resolved "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-1.3.2.tgz#42d4e56a8e9274fba180dabc0aea6e38f29274f5" integrity sha512-QyAGYo/Fbj4MXeGdJcFzZ+FkDkomfRBrPM+9QYJSg+PxgAUL+LU3FneQk37rKR2/zjqkCV1BLHccX98wRXG3Sg== dependencies: infer-owner "^1.0.4" "@npmcli/run-script@^1.8.2": - version "1.8.5" - resolved "https://registry.yarnpkg.com/@npmcli/run-script/-/run-script-1.8.5.tgz#f250a0c5e1a08a792d775a315d0ff42fc3a51e1d" - integrity sha512-NQspusBCpTjNwNRFMtz2C5MxoxyzlbuJ4YEhxAKrIonTiirKDtatsZictx9RgamQIx6+QuHMNmPl0wQdoESs9A== + version "1.8.6" + resolved "https://registry.npmjs.org/@npmcli/run-script/-/run-script-1.8.6.tgz#18314802a6660b0d4baa4c3afe7f1ad39d8c28b7" + integrity sha512-e42bVZnC6VluBZBAFEr3YrdqSspG3bgilyg4nSLBJ7TRGNCzxHa92XAHxQBLYg0BmgwO4b2mf3h/l5EkEWRn3g== dependencies: "@npmcli/node-gyp" "^1.0.2" "@npmcli/promise-spawn" "^1.3.2" - infer-owner "^1.0.4" node-gyp "^7.1.0" read-package-json-fast "^2.0.1" "@octokit/auth-token@^2.4.0", "@octokit/auth-token@^2.4.4": - version "2.4.5" - resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-2.4.5.tgz#568ccfb8cb46f36441fac094ce34f7a875b197f3" - integrity sha512-BpGYsPgJt05M7/L/5FoE1PiAbdxXFZkX/3kDYcsvd1v6UhlnE5e96dTDr0ezX/EFwciQxf3cNV0loipsURU+WA== + version "2.5.0" + resolved "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz#27c37ea26c205f28443402477ffd261311f21e36" + integrity sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g== dependencies: "@octokit/types" "^6.0.3" -"@octokit/core@^3.5.0": +"@octokit/core@^3.5.1": version "3.5.1" - resolved "https://registry.yarnpkg.com/@octokit/core/-/core-3.5.1.tgz#8601ceeb1ec0e1b1b8217b960a413ed8e947809b" + resolved "https://registry.npmjs.org/@octokit/core/-/core-3.5.1.tgz#8601ceeb1ec0e1b1b8217b960a413ed8e947809b" integrity sha512-omncwpLVxMP+GLpLPgeGJBF6IWJFjXDS5flY5VbppePYX9XehevbDykRH9PdCdvqt9TS5AOTiDide7h0qrkHjw== dependencies: "@octokit/auth-token" "^2.4.4" @@ -1359,7 +1370,7 @@ "@octokit/endpoint@^6.0.1": version "6.0.12" - resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-6.0.12.tgz#3b4d47a4b0e79b1027fb8d75d4221928b2d05658" + resolved "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.12.tgz#3b4d47a4b0e79b1027fb8d75d4221928b2d05658" integrity sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA== dependencies: "@octokit/types" "^6.0.3" @@ -1367,62 +1378,62 @@ universal-user-agent "^6.0.0" "@octokit/graphql@^4.3.1", "@octokit/graphql@^4.5.8": - version "4.6.4" - resolved "https://registry.yarnpkg.com/@octokit/graphql/-/graphql-4.6.4.tgz#0c3f5bed440822182e972317122acb65d311a5ed" - integrity sha512-SWTdXsVheRmlotWNjKzPOb6Js6tjSqA2a8z9+glDJng0Aqjzti8MEWOtuT8ZSu6wHnci7LZNuarE87+WJBG4vg== + version "4.8.0" + resolved "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.8.0.tgz#664d9b11c0e12112cbf78e10f49a05959aa22cc3" + integrity sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg== dependencies: "@octokit/request" "^5.6.0" "@octokit/types" "^6.0.3" universal-user-agent "^6.0.0" -"@octokit/openapi-types@^9.0.0": - version "9.0.0" - resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-9.0.0.tgz#05d33f999326785445c915d25167d68bd5eddb24" - integrity sha512-GSpv5VUFqarOXZl6uWPsDnjChkKCxnaMALmQhzvCWGiMxONQxX7ZwlomCMS+wB1KqxLPCA5n6gYt016oEMkHmQ== +"@octokit/openapi-types@^11.2.0": + version "11.2.0" + resolved "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-11.2.0.tgz#b38d7fc3736d52a1e96b230c1ccd4a58a2f400a6" + integrity sha512-PBsVO+15KSlGmiI8QAzaqvsNlZlrDlyAJYcrXBCvVUxCp7VnXjkwPoFHgjEJXx3WF9BAwkA6nfCUA7i9sODzKA== "@octokit/plugin-enterprise-rest@^6.0.1": version "6.0.1" - resolved "https://registry.yarnpkg.com/@octokit/plugin-enterprise-rest/-/plugin-enterprise-rest-6.0.1.tgz#e07896739618dab8da7d4077c658003775f95437" + resolved "https://registry.npmjs.org/@octokit/plugin-enterprise-rest/-/plugin-enterprise-rest-6.0.1.tgz#e07896739618dab8da7d4077c658003775f95437" integrity sha512-93uGjlhUD+iNg1iWhUENAtJata6w5nE+V4urXOAlIXdco6xNZtUSfYY8dzp3Udy74aqO/B5UZL80x/YMa5PKRw== "@octokit/plugin-paginate-rest@^1.1.1": version "1.1.2" - resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-1.1.2.tgz#004170acf8c2be535aba26727867d692f7b488fc" + resolved "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-1.1.2.tgz#004170acf8c2be535aba26727867d692f7b488fc" integrity sha512-jbsSoi5Q1pj63sC16XIUboklNw+8tL9VOnJsWycWYR78TKss5PVpIPb1TUUcMQ+bBh7cY579cVAWmf5qG+dw+Q== dependencies: "@octokit/types" "^2.0.1" -"@octokit/plugin-paginate-rest@^2.6.2": - version "2.14.0" - resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.14.0.tgz#f469cb4a908792fb44679c5973d8bba820c88b0f" - integrity sha512-S2uEu2uHeI7Vf+Lvj8tv3O5/5TCAa8GHS0dUQN7gdM7vKA6ZHAbR6HkAVm5yMb1mbedLEbxOuQ+Fa0SQ7tCDLA== +"@octokit/plugin-paginate-rest@^2.16.8": + version "2.17.0" + resolved "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.17.0.tgz#32e9c7cab2a374421d3d0de239102287d791bce7" + integrity sha512-tzMbrbnam2Mt4AhuyCHvpRkS0oZ5MvwwcQPYGtMv4tUa5kkzG58SVB0fcsLulOZQeRnOgdkZWkRUiyBlh0Bkyw== dependencies: - "@octokit/types" "^6.18.0" + "@octokit/types" "^6.34.0" -"@octokit/plugin-request-log@^1.0.0", "@octokit/plugin-request-log@^1.0.2": +"@octokit/plugin-request-log@^1.0.0", "@octokit/plugin-request-log@^1.0.4": version "1.0.4" - resolved "https://registry.yarnpkg.com/@octokit/plugin-request-log/-/plugin-request-log-1.0.4.tgz#5e50ed7083a613816b1e4a28aeec5fb7f1462e85" + resolved "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.4.tgz#5e50ed7083a613816b1e4a28aeec5fb7f1462e85" integrity sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA== "@octokit/plugin-rest-endpoint-methods@2.4.0": version "2.4.0" - resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-2.4.0.tgz#3288ecf5481f68c494dd0602fc15407a59faf61e" + resolved "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-2.4.0.tgz#3288ecf5481f68c494dd0602fc15407a59faf61e" integrity sha512-EZi/AWhtkdfAYi01obpX0DF7U6b1VRr30QNQ5xSFPITMdLSfhcBqjamE3F+sKcxPbD7eZuMHu3Qkk2V+JGxBDQ== dependencies: "@octokit/types" "^2.0.1" deprecation "^2.3.1" -"@octokit/plugin-rest-endpoint-methods@5.4.2": - version "5.4.2" - resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.4.2.tgz#d090e93ee68ec09985e1ff0a1d2d28581cc883a5" - integrity sha512-imNDDvUMy9YzECcP6zTcKNjwutSwqCYGMZjLPnBHF0kdb3V9URrHWmalD0ZvNEYjwbpm2zw8RPewj3ebCpMBRw== +"@octokit/plugin-rest-endpoint-methods@^5.12.0": + version "5.13.0" + resolved "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.13.0.tgz#8c46109021a3412233f6f50d28786f8e552427ba" + integrity sha512-uJjMTkN1KaOIgNtUPMtIXDOjx6dGYysdIFhgA52x4xSadQCz3b/zJexvITDVpANnfKPW/+E0xkOvLntqMYpviA== dependencies: - "@octokit/types" "^6.19.1" + "@octokit/types" "^6.34.0" deprecation "^2.3.1" "@octokit/request-error@^1.0.2": version "1.2.1" - resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-1.2.1.tgz#ede0714c773f32347576c25649dc013ae6b31801" + resolved "https://registry.npmjs.org/@octokit/request-error/-/request-error-1.2.1.tgz#ede0714c773f32347576c25649dc013ae6b31801" integrity sha512-+6yDyk1EES6WK+l3viRDElw96MvwfJxCt45GvmjDUKWjYIb3PJZQkq3i46TwGwoPD4h8NmTrENmtyA1FwbmhRA== dependencies: "@octokit/types" "^2.0.0" @@ -1431,7 +1442,7 @@ "@octokit/request-error@^2.0.5", "@octokit/request-error@^2.1.0": version "2.1.0" - resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-2.1.0.tgz#9e150357831bfc788d13a4fd4b1913d60c74d677" + resolved "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.1.0.tgz#9e150357831bfc788d13a4fd4b1913d60c74d677" integrity sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg== dependencies: "@octokit/types" "^6.0.3" @@ -1439,9 +1450,9 @@ once "^1.4.0" "@octokit/request@^5.2.0", "@octokit/request@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@octokit/request/-/request-5.6.0.tgz#6084861b6e4fa21dc40c8e2a739ec5eff597e672" - integrity sha512-4cPp/N+NqmaGQwbh3vUsYqokQIzt7VjsgTYVXiwpUP2pxd5YiZB2XuTedbb0SPtv9XS7nzAKjAuQxmY8/aZkiA== + version "5.6.2" + resolved "https://registry.npmjs.org/@octokit/request/-/request-5.6.2.tgz#1aa74d5da7b9e04ac60ef232edd9a7438dcf32d8" + integrity sha512-je66CvSEVf0jCpRISxkUcCa0UkxmFs6eGDRSbfJtAVwbLH5ceqF+YEyC8lj8ystKyZTy8adWr0qmkY52EfOeLA== dependencies: "@octokit/endpoint" "^6.0.1" "@octokit/request-error" "^2.1.0" @@ -1452,7 +1463,7 @@ "@octokit/rest@^16.43.1": version "16.43.2" - resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-16.43.2.tgz#c53426f1e1d1044dee967023e3279c50993dd91b" + resolved "https://registry.npmjs.org/@octokit/rest/-/rest-16.43.2.tgz#c53426f1e1d1044dee967023e3279c50993dd91b" integrity sha512-ngDBevLbBTFfrHZeiS7SAMAZ6ssuVmXuya+F/7RaVvlysgGa1JKJkKWY+jV6TCJYcW0OALfJ7nTIGXcBXzycfQ== dependencies: "@octokit/auth-token" "^2.4.0" @@ -1472,54 +1483,54 @@ once "^1.4.0" universal-user-agent "^4.0.0" -"@octokit/rest@^18.1.0", "@octokit/rest@^18.6.8": - version "18.6.8" - resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-18.6.8.tgz#f73ef3b59686df18206183551c2a835d1db1424f" - integrity sha512-n2aT0mJL9N/idCPmnBynCino1qNScfRHvr8OeskQdBNhUYAMc7cxoc8KLlv1DMWxlZUNhed+5kVdu7majVdVag== +"@octokit/rest@^18.1.0", "@octokit/rest@^18.12.0": + version "18.12.0" + resolved "https://registry.npmjs.org/@octokit/rest/-/rest-18.12.0.tgz#f06bc4952fc87130308d810ca9d00e79f6988881" + integrity sha512-gDPiOHlyGavxr72y0guQEhLsemgVjwRePayJ+FcKc2SJqKUbxbkvf5kAZEWA/MKvsfYlQAMVzNJE3ezQcxMJ2Q== dependencies: - "@octokit/core" "^3.5.0" - "@octokit/plugin-paginate-rest" "^2.6.2" - "@octokit/plugin-request-log" "^1.0.2" - "@octokit/plugin-rest-endpoint-methods" "5.4.2" + "@octokit/core" "^3.5.1" + "@octokit/plugin-paginate-rest" "^2.16.8" + "@octokit/plugin-request-log" "^1.0.4" + "@octokit/plugin-rest-endpoint-methods" "^5.12.0" "@octokit/types@^2.0.0", "@octokit/types@^2.0.1": version "2.16.2" - resolved "https://registry.yarnpkg.com/@octokit/types/-/types-2.16.2.tgz#4c5f8da3c6fecf3da1811aef678fda03edac35d2" + resolved "https://registry.npmjs.org/@octokit/types/-/types-2.16.2.tgz#4c5f8da3c6fecf3da1811aef678fda03edac35d2" integrity sha512-O75k56TYvJ8WpAakWwYRN8Bgu60KrmX0z1KqFp1kNiFNkgW+JW+9EBKZ+S33PU6SLvbihqd+3drvPxKK68Ee8Q== dependencies: "@types/node" ">= 8" -"@octokit/types@^6.0.3", "@octokit/types@^6.16.1", "@octokit/types@^6.18.0", "@octokit/types@^6.19.1": - version "6.19.1" - resolved "https://registry.yarnpkg.com/@octokit/types/-/types-6.19.1.tgz#6ea5f759d8d37e892e59c0a65f10892789b84a25" - integrity sha512-hMI2EokQzMG8ABWcnvcrabqQFuFHqUdN0HUOG4DPTaOtnf/jqhzhK1SHOGu5vDlI/x+hWJ60e28VxB7QhOP0CQ== +"@octokit/types@^6.0.3", "@octokit/types@^6.16.1", "@octokit/types@^6.34.0": + version "6.34.0" + resolved "https://registry.npmjs.org/@octokit/types/-/types-6.34.0.tgz#c6021333334d1ecfb5d370a8798162ddf1ae8218" + integrity sha512-s1zLBjWhdEI2zwaoSgyOFoKSl109CUcVBCc7biPJ3aAf6LGLU6szDvi31JPU7bxfla2lqfhjbbg/5DdFNxOwHw== dependencies: - "@octokit/openapi-types" "^9.0.0" + "@octokit/openapi-types" "^11.2.0" "@sinonjs/commons@^1.6.0", "@sinonjs/commons@^1.7.0", "@sinonjs/commons@^1.8.1", "@sinonjs/commons@^1.8.3": version "1.8.3" - resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.3.tgz#3802ddd21a50a949b6721ddd72da36e67e7f1b2d" + resolved "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz#3802ddd21a50a949b6721ddd72da36e67e7f1b2d" integrity sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ== dependencies: type-detect "4.0.8" "@sinonjs/fake-timers@^6.0.0", "@sinonjs/fake-timers@^6.0.1": version "6.0.1" - resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz#293674fccb3262ac782c7aadfdeca86b10c75c40" + resolved "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz#293674fccb3262ac782c7aadfdeca86b10c75c40" integrity sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA== dependencies: "@sinonjs/commons" "^1.7.0" -"@sinonjs/fake-timers@^7.0.4", "@sinonjs/fake-timers@^7.1.0": +"@sinonjs/fake-timers@^7.0.4", "@sinonjs/fake-timers@^7.1.2": version "7.1.2" - resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-7.1.2.tgz#2524eae70c4910edccf99b2f4e6efc5894aff7b5" + resolved "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-7.1.2.tgz#2524eae70c4910edccf99b2f4e6efc5894aff7b5" integrity sha512-iQADsW4LBMISqZ6Ci1dupJL9pprqwcVFTcOsEmQOEhW+KLCVn/Y4Jrvg2k19fIHCp+iFprriYPTdRcQR8NbUPg== dependencies: "@sinonjs/commons" "^1.7.0" "@sinonjs/samsam@^5.3.1": version "5.3.1" - resolved "https://registry.yarnpkg.com/@sinonjs/samsam/-/samsam-5.3.1.tgz#375a45fe6ed4e92fca2fb920e007c48232a6507f" + resolved "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-5.3.1.tgz#375a45fe6ed4e92fca2fb920e007c48232a6507f" integrity sha512-1Hc0b1TtyfBu8ixF/tpfSHTVWKwCBLY4QJbkgnE7HcwyvT2xArDxb4K7dMgqRm3szI+LJbzmW/s4xxEhv6hwDg== dependencies: "@sinonjs/commons" "^1.6.0" @@ -1528,7 +1539,7 @@ "@sinonjs/samsam@^6.0.2": version "6.0.2" - resolved "https://registry.yarnpkg.com/@sinonjs/samsam/-/samsam-6.0.2.tgz#a0117d823260f282c04bff5f8704bdc2ac6910bb" + resolved "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-6.0.2.tgz#a0117d823260f282c04bff5f8704bdc2ac6910bb" integrity sha512-jxPRPp9n93ci7b8hMfJOFDPRLFYadN6FSpeROFTR4UNF4i5b+EK6m4QXPO46BDhFgRy1JuS87zAnFOzCUwMJcQ== dependencies: "@sinonjs/commons" "^1.6.0" @@ -1537,30 +1548,50 @@ "@sinonjs/text-encoding@^0.7.1": version "0.7.1" - resolved "https://registry.yarnpkg.com/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz#8da5c6530915653f3a1f38fd5f101d8c3f8079c5" + resolved "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz#8da5c6530915653f3a1f38fd5f101d8c3f8079c5" integrity sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ== "@tootallnate/once@1": version "1.1.2" - resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" + resolved "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== +"@tsconfig/node10@^1.0.7": + version "1.0.8" + resolved "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz#c1e4e80d6f964fbecb3359c43bd48b40f7cadad9" + integrity sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg== + +"@tsconfig/node12@^1.0.7": + version "1.0.9" + resolved "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz#62c1f6dee2ebd9aead80dc3afa56810e58e1a04c" + integrity sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw== + +"@tsconfig/node14@^1.0.0": + version "1.0.1" + resolved "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz#95f2d167ffb9b8d2068b0b235302fafd4df711f2" + integrity sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg== + +"@tsconfig/node16@^1.0.2": + version "1.0.2" + resolved "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz#423c77877d0569db20e1fc80885ac4118314010e" + integrity sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA== + "@types/archiver@^5.3.0": version "5.3.0" - resolved "https://registry.yarnpkg.com/@types/archiver/-/archiver-5.3.0.tgz#2b34ba56d4d7102d256b922c7e91e09eab79db6f" + resolved "https://registry.npmjs.org/@types/archiver/-/archiver-5.3.0.tgz#2b34ba56d4d7102d256b922c7e91e09eab79db6f" integrity sha512-qJ79qsmq7O/k9FYwsF6O1xVA1PeLV+9Bh3TYkVCu3VzMR6vN9JQkgEOh/rrQ0R+F4Ta+R3thHGewxQtFglwVfg== dependencies: "@types/glob" "*" -"@types/aws-lambda@^8.10.79": - version "8.10.79" - resolved "https://registry.yarnpkg.com/@types/aws-lambda/-/aws-lambda-8.10.79.tgz#c87fcc10500d0524f583b7fd7828025d8aa834fd" - integrity sha512-YgpllvHcDrPfzyf8/a2+ScRoEtJQjAP0pSgIneWcVpfqHGmiAaS2oMO3e4y3InJMgrMyuxGPde72CBZS/X8vJA== +"@types/aws-lambda@^8.10.84": + version "8.10.84" + resolved "https://registry.npmjs.org/@types/aws-lambda/-/aws-lambda-8.10.84.tgz#b1f391ceeb6908b28d8416d93f27afe8d1348d4e" + integrity sha512-5V78eLtmN0d4RA14hKDwcsMQRl3JotQJlhGFDBo/jdE2TyDFRaYwB/UmMUC4SzhSvRGn+YMkh7jGPnXi8COAng== "@types/babel__core@^7.0.0", "@types/babel__core@^7.1.7": - version "7.1.15" - resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.15.tgz#2ccfb1ad55a02c83f8e0ad327cbc332f55eb1024" - integrity sha512-bxlMKPDbY8x5h6HBwVzEOk2C8fb6SLfYQ5Jw3uBYuYF1lfWk/kbLd81la82vrIkBb0l+JdmrZaDikPrNxpS/Ew== + version "7.1.16" + resolved "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.16.tgz#bc12c74b7d65e82d29876b5d0baf5c625ac58702" + integrity sha512-EAEHtisTMM+KaKwfWdC3oyllIqswlznXCIVCt7/oRNrh+DhgT4UEBNC/jlADNjvw7UnfbcdkGQcPVZ1xYiLcrQ== dependencies: "@babel/parser" "^7.1.0" "@babel/types" "^7.0.0" @@ -1570,14 +1601,14 @@ "@types/babel__generator@*": version "7.6.3" - resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.3.tgz#f456b4b2ce79137f768aa130d2423d2f0ccfaba5" + resolved "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.3.tgz#f456b4b2ce79137f768aa130d2423d2f0ccfaba5" integrity sha512-/GWCmzJWqV7diQW54smJZzWbSFf4QYtF71WCKhcx6Ru/tFyQIY2eiiITcCAeuPbNSvT9YCGkVMqqvSk2Z0mXiA== dependencies: "@babel/types" "^7.0.0" "@types/babel__template@*": version "7.4.1" - resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.1.tgz#3d1a48fd9d6c0edfd56f2ff578daed48f36c8969" + resolved "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz#3d1a48fd9d6c0edfd56f2ff578daed48f36c8969" integrity sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g== dependencies: "@babel/parser" "^7.1.0" @@ -1585,41 +1616,46 @@ "@types/babel__traverse@*", "@types/babel__traverse@^7.0.4", "@types/babel__traverse@^7.0.6": version "7.14.2" - resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.14.2.tgz#ffcd470bbb3f8bf30481678fb5502278ca833a43" + resolved "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.14.2.tgz#ffcd470bbb3f8bf30481678fb5502278ca833a43" integrity sha512-K2waXdXBi2302XUdcHcR1jCeU0LL4TD9HRs/gk0N2Xvrht+G/BfJa4QObBQZfhMdxiCpV3COl5Nfq4uKTeTnJA== dependencies: "@babel/types" "^7.3.0" -"@types/eslint@^7.28.0": - version "7.28.0" - resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-7.28.0.tgz#7e41f2481d301c68e14f483fe10b017753ce8d5a" - integrity sha512-07XlgzX0YJUn4iG1ocY4IX9DzKSmMGUs6ESKlxWhZRaa0fatIWaHWUVapcuGa8r5HFnTqzj+4OCjd5f7EZ/i/A== +"@types/changelog-parser@^2.7.1": + version "2.7.1" + resolved "https://registry.npmjs.org/@types/changelog-parser/-/changelog-parser-2.7.1.tgz#da124373fc8abfb6951fef83718ea5f041fea527" + integrity sha512-OFZB7OlG6nrkcnvJhcyV2Zm/PUGk40oHyfaEBRjlm+ghrKxbFQI+xao/IzYL0G72fpLCTGGs3USrhe38/FF6QQ== + +"@types/eslint@^7.28.1": + version "7.28.1" + resolved "https://registry.npmjs.org/@types/eslint/-/eslint-7.28.1.tgz#50b07747f1f84c2ba8cd394cf0fe0ba07afce320" + integrity sha512-XhZKznR3i/W5dXqUhgU9fFdJekufbeBd5DALmkuXoeFcjbQcPk+2cL+WLHf6Q81HWAnM2vrslIHpGVyCAviRwg== dependencies: "@types/estree" "*" "@types/json-schema" "*" "@types/estree@*": version "0.0.50" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.50.tgz#1e0caa9364d3fccd2931c3ed96fdbeaa5d4cca83" + resolved "https://registry.npmjs.org/@types/estree/-/estree-0.0.50.tgz#1e0caa9364d3fccd2931c3ed96fdbeaa5d4cca83" integrity sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw== "@types/fs-extra@^8.1.2": version "8.1.2" - resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-8.1.2.tgz#7125cc2e4bdd9bd2fc83005ffdb1d0ba00cca61f" + resolved "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.1.2.tgz#7125cc2e4bdd9bd2fc83005ffdb1d0ba00cca61f" integrity sha512-SvSrYXfWSc7R4eqnOzbQF4TZmfpNSM9FrSWLU3EUnWBuyZqNBOrv1B1JA3byUDPUl9z4Ab3jeZG2eDdySlgNMg== dependencies: "@types/node" "*" -"@types/fs-extra@^9.0.12": - version "9.0.12" - resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-9.0.12.tgz#9b8f27973df8a7a3920e8461517ebf8a7d4fdfaf" - integrity sha512-I+bsBr67CurCGnSenZZ7v94gd3tc3+Aj2taxMT4yu4ABLuOgOjeFxX3dokG24ztSRg5tnT00sL8BszO7gSMoIw== +"@types/fs-extra@^9.0.13": + version "9.0.13" + resolved "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.13.tgz#7594fbae04fe7f1918ce8b3d213f74ff44ac1f45" + integrity sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA== dependencies: "@types/node" "*" "@types/glob@*", "@types/glob@^7.1.4": version "7.1.4" - resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.4.tgz#ea59e21d2ee5c517914cb4bc8e4153b99e566672" + resolved "https://registry.npmjs.org/@types/glob/-/glob-7.1.4.tgz#ea59e21d2ee5c517914cb4bc8e4153b99e566672" integrity sha512-w+LsMxKyYQm347Otw+IfBXOv9UWVjpHpCDdbBMt8Kz/xbvCYNjP+0qPh91Km3iKfSRLBB0P7fAMf0KHrPu+MyA== dependencies: "@types/minimatch" "*" @@ -1627,293 +1663,289 @@ "@types/graceful-fs@^4.1.2": version "4.1.5" - resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.5.tgz#21ffba0d98da4350db64891f92a9e5db3cdb4e15" + resolved "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz#21ffba0d98da4350db64891f92a9e5db3cdb4e15" integrity sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw== dependencies: "@types/node" "*" "@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": version "2.0.3" - resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz#4ba8ddb720221f432e443bd5f9117fd22cfd4762" + resolved "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz#4ba8ddb720221f432e443bd5f9117fd22cfd4762" integrity sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw== "@types/istanbul-lib-report@*": version "3.0.0" - resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#c14c24f18ea8190c118ee7562b7ff99a36552686" + resolved "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#c14c24f18ea8190c118ee7562b7ff99a36552686" integrity sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg== dependencies: "@types/istanbul-lib-coverage" "*" "@types/istanbul-reports@^3.0.0": version "3.0.1" - resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz#9153fe98bba2bd565a63add9436d6f0d7f8468ff" + resolved "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz#9153fe98bba2bd565a63add9436d6f0d7f8468ff" integrity sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw== dependencies: "@types/istanbul-lib-report" "*" -"@types/jest@^26.0.22", "@types/jest@^26.0.24": +"@types/jest@^26.0.24": version "26.0.24" - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-26.0.24.tgz#943d11976b16739185913a1936e0de0c4a7d595a" + resolved "https://registry.npmjs.org/@types/jest/-/jest-26.0.24.tgz#943d11976b16739185913a1936e0de0c4a7d595a" integrity sha512-E/X5Vib8BWqZNRlDxj9vYXhsDwPYbPINqKF9BsnSoon4RQ0D9moEuLD8txgyypFLH7J4+Lho9Nr/c8H0Fi+17w== dependencies: jest-diff "^26.0.0" pretty-format "^26.0.0" -"@types/json-schema@*", "@types/json-schema@^7.0.7": - version "7.0.8" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.8.tgz#edf1bf1dbf4e04413ca8e5b17b3b7d7d54b59818" - integrity sha512-YSBPTLTVm2e2OoQIDYx8HaeWJ5tTToLH67kXR7zYNGupXMEHa2++G8k+DczX2cFVgalypqtyZIcU19AFcmOpmg== +"@types/json-schema@*", "@types/json-schema@^7.0.7", "@types/json-schema@^7.0.9": + version "7.0.9" + resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d" + integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ== -"@types/lodash@^4.14.171": - version "4.14.171" - resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.171.tgz#f01b3a5fe3499e34b622c362a46a609fdb23573b" - integrity sha512-7eQ2xYLLI/LsicL2nejW9Wyko3lcpN6O/z0ZLHrEQsg280zIdCv1t/0m6UtBjUHokCGBQ3gYTbHzDkZ1xOBwwg== +"@types/json5@^0.0.29": + version "0.0.29" + resolved "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" + integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= + +"@types/lodash@^4.14.175": + version "4.14.175" + resolved "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.175.tgz#b78dfa959192b01fae0ad90e166478769b215f45" + integrity sha512-XmdEOrKQ8a1Y/yxQFOMbC47G/V2VDO1GvMRnl4O75M4GW/abC5tnfzadQYkqEveqRM1dEJGFFegfPNA2vvx2iw== "@types/md5@^2.3.1": version "2.3.1" - resolved "https://registry.yarnpkg.com/@types/md5/-/md5-2.3.1.tgz#010bcf3bb50a2cff3a574cb1c0b4051a9c67d6bc" + resolved "https://registry.npmjs.org/@types/md5/-/md5-2.3.1.tgz#010bcf3bb50a2cff3a574cb1c0b4051a9c67d6bc" integrity sha512-OK3oe+ALIoPSo262lnhAYwpqFNXbiwH2a+0+Z5YBnkQEwWD8fk5+PIeRhYA48PzvX9I4SGNpWy+9bLj8qz92RQ== dependencies: "@types/node" "*" "@types/mime@^2.0.3": version "2.0.3" - resolved "https://registry.yarnpkg.com/@types/mime/-/mime-2.0.3.tgz#c893b73721db73699943bfc3653b1deb7faa4a3a" + resolved "https://registry.npmjs.org/@types/mime/-/mime-2.0.3.tgz#c893b73721db73699943bfc3653b1deb7faa4a3a" integrity sha512-Jus9s4CDbqwocc5pOAnh8ShfrnMcPHuJYzVcSUU7lrh8Ni5HuIqX3oilL86p3dlTrk0LzHRCgA/GQ7uNCw6l2Q== "@types/minimatch@*", "@types/minimatch@^3.0.3", "@types/minimatch@^3.0.5": version "3.0.5" - resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.5.tgz#1001cc5e6a3704b83c236027e77f2f58ea010f40" + resolved "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz#1001cc5e6a3704b83c236027e77f2f58ea010f40" integrity sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ== "@types/minimist@^1.2.0": version "1.2.2" - resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.2.tgz#ee771e2ba4b3dc5b372935d549fd9617bf345b8c" + resolved "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz#ee771e2ba4b3dc5b372935d549fd9617bf345b8c" integrity sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ== "@types/mock-fs@^4.13.1": version "4.13.1" - resolved "https://registry.yarnpkg.com/@types/mock-fs/-/mock-fs-4.13.1.tgz#9201554ceb23671badbfa8ac3f1fa9e0706305be" + resolved "https://registry.npmjs.org/@types/mock-fs/-/mock-fs-4.13.1.tgz#9201554ceb23671badbfa8ac3f1fa9e0706305be" integrity sha512-m6nFAJ3lBSnqbvDZioawRvpLXSaPyn52Srf7OfzjubYbYX8MTUdIgDxQl0wEapm4m/pNYSd9TXocpQ0TvZFlYA== dependencies: "@types/node" "*" "@types/mockery@^1.4.30": version "1.4.30" - resolved "https://registry.yarnpkg.com/@types/mockery/-/mockery-1.4.30.tgz#25f07fa7340371c7ee0fb9239511a34e0a19d5b7" + resolved "https://registry.npmjs.org/@types/mockery/-/mockery-1.4.30.tgz#25f07fa7340371c7ee0fb9239511a34e0a19d5b7" integrity sha512-uv53RrNdhbkV/3VmVCtfImfYCWC3GTTRn3R11Whni3EJ+gb178tkZBVNj2edLY5CMrB749dQi+SJkg87jsN8UQ== -"@types/node@*", "@types/node@>= 8": - version "16.4.0" - resolved "https://registry.yarnpkg.com/@types/node/-/node-16.4.0.tgz#2c219eaa3b8d1e4d04f4dd6e40bc68c7467d5272" - integrity sha512-HrJuE7Mlqcjj+00JqMWpZ3tY8w7EUd+S0U3L1+PQSWiXZbOgyQDvi+ogoUxaHApPJq5diKxYBQwA3iIlNcPqOg== +"@types/node@*", "@types/node@>= 8", "@types/node@^16.9.2": + version "16.10.5" + resolved "https://registry.npmjs.org/@types/node/-/node-16.10.5.tgz#7fe4123b061753f1a58a6cd077ff0bb069ee752d" + integrity sha512-9iI3OOlkyOjLQQ9s+itIJNMRepDhB/96jW3fqduJ2FTPQj1dJjw6Q3QCImF9FE1wmdBs5QSun4FjDSFS8d8JLw== "@types/node@^10.17.60": version "10.17.60" - resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.60.tgz#35f3d6213daed95da7f0f73e75bcc6980e90597b" + resolved "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz#35f3d6213daed95da7f0f73e75bcc6980e90597b" integrity sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw== -"@types/node@^14.14.33": - version "14.17.5" - resolved "https://registry.yarnpkg.com/@types/node/-/node-14.17.5.tgz#b59daf6a7ffa461b5648456ca59050ba8e40ed54" - integrity sha512-bjqH2cX/O33jXT/UmReo2pM7DIJREPMnarixbQ57DOOzzFaI6D2+IcwaJQaJpv0M1E9TIhPCYVxrkcityLjlqA== - -"@types/nodeunit@^0.0.32": - version "0.0.32" - resolved "https://registry.yarnpkg.com/@types/nodeunit/-/nodeunit-0.0.32.tgz#a41a76b0da07a2a79882e613f4b9fb4c4d123cc1" - integrity sha512-9n61KESiLGaKPpgp6ccSkpx0HVPe+ZNqxVdLMF2BaiQfbJIi0HIwboxmE3OxwgYqH7xsjuk/iCpSE4VVqC4w+Q== - "@types/normalize-package-data@^2.4.0": version "2.4.1" - resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz#d3357479a0fdfdd5907fe67e17e0a85c906e1301" + resolved "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz#d3357479a0fdfdd5907fe67e17e0a85c906e1301" integrity sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw== "@types/parse-json@^4.0.0": version "4.0.0" - resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" + resolved "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== "@types/prettier@^2.0.0": - version "2.3.2" - resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.3.2.tgz#fc8c2825e4ed2142473b4a81064e6e081463d1b3" - integrity sha512-eI5Yrz3Qv4KPUa/nSIAi0h+qX0XyewOliug5F2QAtuRg6Kjg6jfmxe1GIwoIRhZspD1A0RP8ANrPwvEXXtRFog== + version "2.4.1" + resolved "https://registry.npmjs.org/@types/prettier/-/prettier-2.4.1.tgz#e1303048d5389563e130f5bdd89d37a99acb75eb" + integrity sha512-Fo79ojj3vdEZOHg3wR9ksAMRz4P3S5fDB5e/YWZiFnyFQI1WY2Vftu9XoXVVtJfxB7Bpce/QTqWSSntkz2Znrw== "@types/promptly@^3.0.2": version "3.0.2" - resolved "https://registry.yarnpkg.com/@types/promptly/-/promptly-3.0.2.tgz#598674d4b78b3dffcb2d756b344f28a2cf7459f8" + resolved "https://registry.npmjs.org/@types/promptly/-/promptly-3.0.2.tgz#598674d4b78b3dffcb2d756b344f28a2cf7459f8" integrity sha512-cJFwE7d8GlraY+DJoZ0NhpoJ55slkcbNsGIKMY0H+5h0xaGqXBqXz9zeu+Ey9KfN1UiHQXiIT0GroxyPYMPP/w== dependencies: "@types/node" "*" "@types/proxyquire@^1.3.28": version "1.3.28" - resolved "https://registry.yarnpkg.com/@types/proxyquire/-/proxyquire-1.3.28.tgz#05a647bb0d8fe48fc8edcc193e43cc79310faa7d" + resolved "https://registry.npmjs.org/@types/proxyquire/-/proxyquire-1.3.28.tgz#05a647bb0d8fe48fc8edcc193e43cc79310faa7d" integrity sha512-SQaNzWQ2YZSr7FqAyPPiA3FYpux2Lqh3HWMZQk47x3xbMCqgC/w0dY3dw9rGqlweDDkrySQBcaScXWeR+Yb11Q== "@types/punycode@^2.1.0": version "2.1.0" - resolved "https://registry.yarnpkg.com/@types/punycode/-/punycode-2.1.0.tgz#89e4f3d09b3f92e87a80505af19be7e0c31d4e83" + resolved "https://registry.npmjs.org/@types/punycode/-/punycode-2.1.0.tgz#89e4f3d09b3f92e87a80505af19be7e0c31d4e83" integrity sha512-PG5aLpW6PJOeV2fHRslP4IOMWn+G+Uq8CfnyJ+PDS8ndCbU+soO+fB3NKCKo0p/Jh2Y4aPaiQZsrOXFdzpcA6g== -"@types/semver@^7.3.7": - version "7.3.7" - resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.7.tgz#b9eb89d7dfa70d5d1ce525bc1411a35347f533a3" - integrity sha512-4g1jrL98mdOIwSOUh6LTlB0Cs9I0dQPwINUhBg7C6pN4HLr8GS8xsksJxilW6S6dQHVi2K/o+lQuQcg7LroCnw== +"@types/semver@^7.3.8": + version "7.3.8" + resolved "https://registry.npmjs.org/@types/semver/-/semver-7.3.8.tgz#508a27995498d7586dcecd77c25e289bfaf90c59" + integrity sha512-D/2EJvAlCEtYFEYmmlGwbGXuK886HzyCc3nZX/tkFTQdEU8jZDAgiv08P162yB17y4ZXZoq7yFAnW4GDBb9Now== "@types/sinon@^9.0.11": version "9.0.11" - resolved "https://registry.yarnpkg.com/@types/sinon/-/sinon-9.0.11.tgz#7af202dda5253a847b511c929d8b6dda170562eb" + resolved "https://registry.npmjs.org/@types/sinon/-/sinon-9.0.11.tgz#7af202dda5253a847b511c929d8b6dda170562eb" integrity sha512-PwP4UY33SeeVKodNE37ZlOsR9cReypbMJOhZ7BVE0lB+Hix3efCOxiJWiE5Ia+yL9Cn2Ch72EjFTRze8RZsNtg== dependencies: "@types/sinonjs__fake-timers" "*" "@types/sinonjs__fake-timers@*": - version "6.0.3" - resolved "https://registry.yarnpkg.com/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-6.0.3.tgz#79df6f358ae8f79e628fe35a63608a0ea8e7cf08" - integrity sha512-E1dU4fzC9wN2QK2Cr1MLCfyHM8BoNnRFvuf45LYMPNDA+WqbNzC45S4UzPxvp1fFJ1rvSGU0bPvdd35VLmXG8g== + version "6.0.4" + resolved "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-6.0.4.tgz#0ecc1b9259b76598ef01942f547904ce61a6a77d" + integrity sha512-IFQTJARgMUBF+xVd2b+hIgXWrZEjND3vJtRCvIelcFB5SIXfjV4bOHbHJ0eXKh+0COrBRc8MqteKAz/j88rE0A== "@types/stack-utils@^2.0.0": version "2.0.1" - resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c" + resolved "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c" integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw== "@types/string-width@^4.0.1": version "4.0.1" - resolved "https://registry.yarnpkg.com/@types/string-width/-/string-width-4.0.1.tgz#a02e22c305d0b550f8d8da12b5b13e05123dc7b8" + resolved "https://registry.npmjs.org/@types/string-width/-/string-width-4.0.1.tgz#a02e22c305d0b550f8d8da12b5b13e05123dc7b8" integrity sha512-zsZXP4RSmw3TOXf2eut1xxb7Gto7I+BrB0WxwdRaEdCBnUbAQa57yZf/OWcAfop9m7t6Zd0pw9tV2ghpJXJPZg== dependencies: string-width "*" "@types/table@^6.0.0": version "6.3.2" - resolved "https://registry.yarnpkg.com/@types/table/-/table-6.3.2.tgz#e18ad2594400d81c3da28c31b342eb5a0d87a8e7" + resolved "https://registry.npmjs.org/@types/table/-/table-6.3.2.tgz#e18ad2594400d81c3da28c31b342eb5a0d87a8e7" integrity sha512-GJ82z3vQbx2BhiUo12w2A3lyBpXPJrGHjQ7iS5aH925098w8ojqiWBhgOUy97JS2PKLmRCTLT0sI+gJI4futig== dependencies: table "*" "@types/uuid@^8.3.1": version "8.3.1" - resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.1.tgz#1a32969cf8f0364b3d8c8af9cc3555b7805df14f" + resolved "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.1.tgz#1a32969cf8f0364b3d8c8af9cc3555b7805df14f" integrity sha512-Y2mHTRAbqfFkpjldbkHGY8JIzRN6XqYRliG8/24FcHm2D2PwW24fl5xMRTVGdrb7iMrwCaIEbLWerGIkXuFWVg== "@types/wrap-ansi@^3.0.0": version "3.0.0" - resolved "https://registry.yarnpkg.com/@types/wrap-ansi/-/wrap-ansi-3.0.0.tgz#18b97a972f94f60a679fd5c796d96421b9abb9fd" + resolved "https://registry.npmjs.org/@types/wrap-ansi/-/wrap-ansi-3.0.0.tgz#18b97a972f94f60a679fd5c796d96421b9abb9fd" integrity sha512-ltIpx+kM7g/MLRZfkbL7EsCEjfzCcScLpkg37eXEtx5kmrAKBkTJwd1GIAjDSL8wTpM6Hzn5YO4pSb91BEwu1g== "@types/yaml@1.9.6": version "1.9.6" - resolved "https://registry.yarnpkg.com/@types/yaml/-/yaml-1.9.6.tgz#9e30a14aecbba978ad7156d03201ecd97478a712" + resolved "https://registry.npmjs.org/@types/yaml/-/yaml-1.9.6.tgz#9e30a14aecbba978ad7156d03201ecd97478a712" integrity sha512-VKOCuDN57wngmyQnRqcn4vuGWCXViISHv+UCCjrKcf1yt4zyfMmOGlZDI2ucTHK72V8ki+sd7h21OZL6O5S52A== dependencies: yaml "*" "@types/yaml@1.9.7", "@types/yaml@^1.9.7": version "1.9.7" - resolved "https://registry.yarnpkg.com/@types/yaml/-/yaml-1.9.7.tgz#2331f36e0aac91311a63d33eb026c21687729679" + resolved "https://registry.npmjs.org/@types/yaml/-/yaml-1.9.7.tgz#2331f36e0aac91311a63d33eb026c21687729679" integrity sha512-8WMXRDD1D+wCohjfslHDgICd2JtMATZU8CkhH8LVJqcJs6dyYj5TGptzP8wApbmEullGBSsCEzzap73DQ1HJaA== dependencies: yaml "*" "@types/yargs-parser@*": version "20.2.1" - resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-20.2.1.tgz#3b9ce2489919d9e4fea439b76916abc34b2df129" + resolved "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.1.tgz#3b9ce2489919d9e4fea439b76916abc34b2df129" integrity sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw== "@types/yargs@^15.0.0", "@types/yargs@^15.0.14": version "15.0.14" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-15.0.14.tgz#26d821ddb89e70492160b66d10a0eb6df8f6fb06" + resolved "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.14.tgz#26d821ddb89e70492160b66d10a0eb6df8f6fb06" integrity sha512-yEJzHoxf6SyQGhBhIYGXQDSCkJjB6HohDShto7m8vaKg9Yp0Yn8+71J9eakh2bnPg6BfsH9PRMhiRTZnd4eXGQ== dependencies: "@types/yargs-parser" "*" "@types/yarnpkg__lockfile@^1.1.5": version "1.1.5" - resolved "https://registry.yarnpkg.com/@types/yarnpkg__lockfile/-/yarnpkg__lockfile-1.1.5.tgz#9639020e1fb65120a2f4387db8f1e8b63efdf229" + resolved "https://registry.npmjs.org/@types/yarnpkg__lockfile/-/yarnpkg__lockfile-1.1.5.tgz#9639020e1fb65120a2f4387db8f1e8b63efdf229" integrity sha512-8NYnGOctzsI4W0ApsP/BIHD/LnxpJ6XaGf2AZmz4EyDYJMxtprN4279dLNI1CPZcwC9H18qYcaFv4bXi0wmokg== -"@typescript-eslint/eslint-plugin@^4.28.4": - version "4.28.4" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.28.4.tgz#e73c8cabbf3f08dee0e1bda65ed4e622ae8f8921" - integrity sha512-s1oY4RmYDlWMlcV0kKPBaADn46JirZzvvH7c2CtAqxCY96S538JRBAzt83RrfkDheV/+G/vWNK0zek+8TB3Gmw== +"@typescript-eslint/eslint-plugin@^4.33.0": + version "4.33.0" + resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.33.0.tgz#c24dc7c8069c7706bc40d99f6fa87edcb2005276" + integrity sha512-aINiAxGVdOl1eJyVjaWn/YcVAq4Gi/Yo35qHGCnqbWVz61g39D0h23veY/MA0rFFGfxK7TySg2uwDeNv+JgVpg== dependencies: - "@typescript-eslint/experimental-utils" "4.28.4" - "@typescript-eslint/scope-manager" "4.28.4" + "@typescript-eslint/experimental-utils" "4.33.0" + "@typescript-eslint/scope-manager" "4.33.0" debug "^4.3.1" functional-red-black-tree "^1.0.1" + ignore "^5.1.8" regexpp "^3.1.0" semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/experimental-utils@4.28.4", "@typescript-eslint/experimental-utils@^4.0.1": - version "4.28.4" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.28.4.tgz#9c70c35ebed087a5c70fb0ecd90979547b7fec96" - integrity sha512-OglKWOQRWTCoqMSy6pm/kpinEIgdcXYceIcH3EKWUl4S8xhFtN34GQRaAvTIZB9DD94rW7d/U7tUg3SYeDFNHA== +"@typescript-eslint/experimental-utils@4.33.0", "@typescript-eslint/experimental-utils@^4.0.1": + version "4.33.0" + resolved "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.33.0.tgz#6f2a786a4209fa2222989e9380b5331b2810f7fd" + integrity sha512-zeQjOoES5JFjTnAhI5QY7ZviczMzDptls15GFsI6jyUOq0kOf9+WonkhtlIhh0RgHRnqj5gdNxW5j1EvAyYg6Q== dependencies: "@types/json-schema" "^7.0.7" - "@typescript-eslint/scope-manager" "4.28.4" - "@typescript-eslint/types" "4.28.4" - "@typescript-eslint/typescript-estree" "4.28.4" + "@typescript-eslint/scope-manager" "4.33.0" + "@typescript-eslint/types" "4.33.0" + "@typescript-eslint/typescript-estree" "4.33.0" eslint-scope "^5.1.1" eslint-utils "^3.0.0" -"@typescript-eslint/parser@^4.28.4": - version "4.28.4" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.28.4.tgz#bc462dc2779afeefdcf49082516afdc3e7b96fab" - integrity sha512-4i0jq3C6n+og7/uCHiE6q5ssw87zVdpUj1k6VlVYMonE3ILdFApEzTWgppSRG4kVNB/5jxnH+gTeKLMNfUelQA== +"@typescript-eslint/parser@^4.33.0": + version "4.33.0" + resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.33.0.tgz#dfe797570d9694e560528d18eecad86c8c744899" + integrity sha512-ZohdsbXadjGBSK0/r+d87X0SBmKzOq4/S5nzK6SBgJspFo9/CUDJ7hjayuze+JK7CZQLDMroqytp7pOcFKTxZA== dependencies: - "@typescript-eslint/scope-manager" "4.28.4" - "@typescript-eslint/types" "4.28.4" - "@typescript-eslint/typescript-estree" "4.28.4" + "@typescript-eslint/scope-manager" "4.33.0" + "@typescript-eslint/types" "4.33.0" + "@typescript-eslint/typescript-estree" "4.33.0" debug "^4.3.1" -"@typescript-eslint/scope-manager@4.28.4": - version "4.28.4" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.28.4.tgz#bdbce9b6a644e34f767bd68bc17bb14353b9fe7f" - integrity sha512-ZJBNs4usViOmlyFMt9X9l+X0WAFcDH7EdSArGqpldXu7aeZxDAuAzHiMAeI+JpSefY2INHrXeqnha39FVqXb8w== +"@typescript-eslint/scope-manager@4.33.0": + version "4.33.0" + resolved "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.33.0.tgz#d38e49280d983e8772e29121cf8c6e9221f280a3" + integrity sha512-5IfJHpgTsTZuONKbODctL4kKuQje/bzBRkwHE8UOZ4f89Zeddg+EGZs8PD8NcN4LdM3ygHWYB3ukPAYjvl/qbQ== dependencies: - "@typescript-eslint/types" "4.28.4" - "@typescript-eslint/visitor-keys" "4.28.4" + "@typescript-eslint/types" "4.33.0" + "@typescript-eslint/visitor-keys" "4.33.0" -"@typescript-eslint/types@4.28.4": - version "4.28.4" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.28.4.tgz#41acbd79b5816b7c0dd7530a43d97d020d3aeb42" - integrity sha512-3eap4QWxGqkYuEmVebUGULMskR6Cuoc/Wii0oSOddleP4EGx1tjLnZQ0ZP33YRoMDCs5O3j56RBV4g14T4jvww== +"@typescript-eslint/types@4.33.0": + version "4.33.0" + resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.33.0.tgz#a1e59036a3b53ae8430ceebf2a919dc7f9af6d72" + integrity sha512-zKp7CjQzLQImXEpLt2BUw1tvOMPfNoTAfb8l51evhYbOEEzdWyQNmHWWGPR6hwKJDAi+1VXSBmnhL9kyVTTOuQ== -"@typescript-eslint/typescript-estree@4.28.4": - version "4.28.4" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.28.4.tgz#252e6863278dc0727244be9e371eb35241c46d00" - integrity sha512-z7d8HK8XvCRyN2SNp+OXC2iZaF+O2BTquGhEYLKLx5k6p0r05ureUtgEfo5f6anLkhCxdHtCf6rPM1p4efHYDQ== +"@typescript-eslint/typescript-estree@4.33.0": + version "4.33.0" + resolved "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.33.0.tgz#0dfb51c2908f68c5c08d82aefeaf166a17c24609" + integrity sha512-rkWRY1MPFzjwnEVHsxGemDzqqddw2QbTJlICPD9p9I9LfsO8fdmfQPOX3uKfUaGRDFJbfrtm/sXhVXN4E+bzCA== dependencies: - "@typescript-eslint/types" "4.28.4" - "@typescript-eslint/visitor-keys" "4.28.4" + "@typescript-eslint/types" "4.33.0" + "@typescript-eslint/visitor-keys" "4.33.0" debug "^4.3.1" globby "^11.0.3" is-glob "^4.0.1" semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/visitor-keys@4.28.4": - version "4.28.4" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.28.4.tgz#92dacfefccd6751cbb0a964f06683bfd72d0c4d3" - integrity sha512-NIAXAdbz1XdOuzqkJHjNKXKj8QQ4cv5cxR/g0uQhCYf/6//XrmfpaYsM7PnBcNbfvTDLUkqQ5TPNm1sozDdTWg== +"@typescript-eslint/visitor-keys@4.33.0": + version "4.33.0" + resolved "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.33.0.tgz#2a22f77a41604289b7a186586e9ec48ca92ef1dd" + integrity sha512-uqi/2aSz9g2ftcHWf8uLPJA70rUv6yuMW5Bohw+bwcuzaxQIHaKFZCKGoGXIrc9vkTJ3+0txM73K0Hq3d5wgIg== dependencies: - "@typescript-eslint/types" "4.28.4" + "@typescript-eslint/types" "4.33.0" eslint-visitor-keys "^2.0.0" -"@xmldom/xmldom@^0.7.0": - version "0.7.3" - resolved "https://registry.yarnpkg.com/@xmldom/xmldom/-/xmldom-0.7.3.tgz#55de695f77afd3cc0e5bee0aa900040bc63c0f63" - integrity sha512-8XmJdPut2XGtfFcsNsqEsvMUmAwk7xLq7m+E/GcsU9b5qyFFIsiX4Fvnb5UoQ4wo12Wlm07YFJERoyWUYdbIpw== +"@xmldom/xmldom@^0.7.5": + version "0.7.5" + resolved "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.7.5.tgz#09fa51e356d07d0be200642b0e4f91d8e6dd408d" + integrity sha512-V3BIhmY36fXZ1OtVcI9W+FxQqxVLsPKcNjWigIaa81dLC9IolJl5Mt4Cvhmr0flUnjSpTdrbMTSbXqYqV5dT6A== "@yarnpkg/lockfile@^1.1.0": version "1.1.0" - resolved "https://registry.yarnpkg.com/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz#e77a97fbd345b76d83245edcd17d393b1b41fb31" + resolved "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz#e77a97fbd345b76d83245edcd17d393b1b41fb31" integrity sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ== JSONStream@^1.0.4: version "1.3.5" - resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0" + resolved "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0" integrity sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ== dependencies: jsonparse "^1.2.0" @@ -1921,17 +1953,17 @@ JSONStream@^1.0.4: abab@^2.0.3, abab@^2.0.5: version "2.0.5" - resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.5.tgz#c0b678fb32d60fc1219c784d6a826fe385aeb79a" + resolved "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz#c0b678fb32d60fc1219c784d6a826fe385aeb79a" integrity sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q== abbrev@1: version "1.1.1" - resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + resolved "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== acorn-globals@^6.0.0: version "6.0.0" - resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-6.0.0.tgz#46cdd39f0f8ff08a876619b55f5ac8a6dc770b45" + resolved "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz#46cdd39f0f8ff08a876619b55f5ac8a6dc770b45" integrity sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg== dependencies: acorn "^7.1.1" @@ -1939,39 +1971,44 @@ acorn-globals@^6.0.0: acorn-jsx@^5.3.1: version "5.3.2" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== acorn-walk@^7.1.1: version "7.2.0" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc" + resolved "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc" integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== +acorn-walk@^8.1.1: + version "8.2.0" + resolved "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" + integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== + acorn@^7.1.1, acorn@^7.4.0: version "7.4.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" + resolved "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== -acorn@^8.2.4: - version "8.4.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.4.1.tgz#56c36251fc7cabc7096adc18f05afe814321a28c" - integrity sha512-asabaBSkEKosYKMITunzX177CXxQ4Q8BSSzMTKD+FefUhipQC70gfW5SiUDhYQ3vk8G+81HqQk7Fv9OXwwn9KA== +acorn@^8.2.4, acorn@^8.4.1: + version "8.5.0" + resolved "https://registry.npmjs.org/acorn/-/acorn-8.5.0.tgz#4512ccb99b3698c752591e9bb4472e38ad43cee2" + integrity sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q== add-stream@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/add-stream/-/add-stream-1.0.0.tgz#6a7990437ca736d5e1288db92bd3266d5f5cb2aa" + resolved "https://registry.npmjs.org/add-stream/-/add-stream-1.0.0.tgz#6a7990437ca736d5e1288db92bd3266d5f5cb2aa" integrity sha1-anmQQ3ynNtXhKI25K9MmbV9csqo= agent-base@6, agent-base@^6.0.0, agent-base@^6.0.2: version "6.0.2" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" + resolved "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== dependencies: debug "4" agentkeepalive@^4.1.3: version "4.1.4" - resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.1.4.tgz#d928028a4862cb11718e55227872e842a44c945b" + resolved "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.1.4.tgz#d928028a4862cb11718e55227872e842a44c945b" integrity sha512-+V/rGa3EuU74H6wR04plBb7Ks10FbtUQgRj/FQOG7uUIEuaINI+AiqJR1k6t3SVNs7o7ZjIdus6706qqzVq8jQ== dependencies: debug "^4.1.0" @@ -1980,7 +2017,7 @@ agentkeepalive@^4.1.3: aggregate-error@^3.0.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" + resolved "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA== dependencies: clean-stack "^2.0.0" @@ -1988,7 +2025,7 @@ aggregate-error@^3.0.0: ajv@^6.10.0, ajv@^6.12.3, ajv@^6.12.4: version "6.12.6" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== dependencies: fast-deep-equal "^3.1.1" @@ -1997,9 +2034,9 @@ ajv@^6.10.0, ajv@^6.12.3, ajv@^6.12.4: uri-js "^4.2.2" ajv@^8.0.1: - version "8.6.2" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.6.2.tgz#2fb45e0e5fcbc0813326c1c3da535d1881bb0571" - integrity sha512-9807RlWAgT564wT+DjeyU5OFMPjmzxVobvDFmNAhY+5zD6A2ly3jDp6sgnfyDtlIQ+7H97oc/DGCzzfu9rjw9w== + version "8.6.3" + resolved "https://registry.npmjs.org/ajv/-/ajv-8.6.3.tgz#11a66527761dc3e9a3845ea775d2d3c0414e8764" + integrity sha512-SMJOdDP6LqTkD0Uq8qLi+gMwSt0imXLSV080qFVwJCpH9U6Mb+SUGHAXM0KNbcBPguytWyvFxcHgMLe2D2XSpw== dependencies: fast-deep-equal "^3.1.1" json-schema-traverse "^1.0.0" @@ -2008,48 +2045,48 @@ ajv@^8.0.1: ansi-colors@^4.1.1: version "4.1.1" - resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" + resolved "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== ansi-escapes@^4.2.1: version "4.3.2" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== dependencies: type-fest "^0.21.3" ansi-regex@^2.0.0: version "2.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= ansi-regex@^4.1.0: version "4.1.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== -ansi-regex@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" - integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== +ansi-regex@^5.0.0, ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== -ansi-styles@^3.2.0, ansi-styles@^3.2.1: +ansi-styles@^3.2.1: version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== dependencies: color-convert "^1.9.0" ansi-styles@^4.0.0, ansi-styles@^4.1.0: version "4.3.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== dependencies: color-convert "^2.0.1" anymatch@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" + resolved "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" integrity sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw== dependencies: micromatch "^3.1.4" @@ -2057,39 +2094,37 @@ anymatch@^2.0.0: anymatch@^3.0.3: version "3.1.2" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" + resolved "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== dependencies: normalize-path "^3.0.0" picomatch "^2.0.4" -append-transform@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/append-transform/-/append-transform-1.0.0.tgz#046a52ae582a228bd72f58acfbe2967c678759ab" - integrity sha512-P009oYkeHyU742iSZJzZZywj4QRJdnTWffaKuJQLablCZ1uz6/cW4yaRgcDaoQ+uwOxxnt0gRUcwfsNP2ri0gw== - dependencies: - default-require-extensions "^2.0.0" +app-root-path@^2.2.1: + version "2.2.1" + resolved "https://registry.npmjs.org/app-root-path/-/app-root-path-2.2.1.tgz#d0df4a682ee408273583d43f6f79e9892624bc9a" + integrity sha512-91IFKeKk7FjfmezPKkwtaRvSpnUc4gDwPAjA1YZ9Gn0q0PPeW+vbeUsZuyDwjI7+QTHhcLen2v25fi/AmhvbJA== append-transform@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/append-transform/-/append-transform-2.0.0.tgz#99d9d29c7b38391e6f428d28ce136551f0b77e12" + resolved "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz#99d9d29c7b38391e6f428d28ce136551f0b77e12" integrity sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg== dependencies: default-require-extensions "^3.0.0" aproba@^1.0.3: version "1.2.0" - resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" + resolved "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== aproba@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc" + resolved "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc" integrity sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ== archiver-utils@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/archiver-utils/-/archiver-utils-2.1.0.tgz#e8a460e94b693c3e3da182a098ca6285ba9249e2" + resolved "https://registry.npmjs.org/archiver-utils/-/archiver-utils-2.1.0.tgz#e8a460e94b693c3e3da182a098ca6285ba9249e2" integrity sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw== dependencies: glob "^7.1.4" @@ -2105,7 +2140,7 @@ archiver-utils@^2.1.0: archiver@^5.3.0: version "5.3.0" - resolved "https://registry.yarnpkg.com/archiver/-/archiver-5.3.0.tgz#dd3e097624481741df626267564f7dd8640a45ba" + resolved "https://registry.npmjs.org/archiver/-/archiver-5.3.0.tgz#dd3e097624481741df626267564f7dd8640a45ba" integrity sha512-iUw+oDwK0fgNpvveEsdQ0Ase6IIKztBJU2U0E9MzszMfmVVUyv1QJhS2ITW9ZCqx8dktAxVAjWWkKehuZE8OPg== dependencies: archiver-utils "^2.1.0" @@ -2118,191 +2153,176 @@ archiver@^5.3.0: archy@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40" + resolved "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40" integrity sha1-+cjBN1fMHde8N5rHeyxipcKGjEA= are-we-there-yet@~1.1.2: - version "1.1.5" - resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" - integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w== + version "1.1.7" + resolved "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz#b15474a932adab4ff8a50d9adfa7e4e926f21146" + integrity sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g== dependencies: delegates "^1.0.0" readable-stream "^2.0.6" arg@^4.1.0: version "4.1.3" - resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" + resolved "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== argparse@^1.0.7: version "1.0.10" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + resolved "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== dependencies: sprintf-js "~1.0.2" argparse@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + resolved "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== arr-diff@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" + resolved "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= arr-flatten@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" + resolved "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== arr-union@^3.1.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" + resolved "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= array-differ@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-3.0.0.tgz#3cbb3d0f316810eafcc47624734237d6aee4ae6b" + resolved "https://registry.npmjs.org/array-differ/-/array-differ-3.0.0.tgz#3cbb3d0f316810eafcc47624734237d6aee4ae6b" integrity sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg== array-ify@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/array-ify/-/array-ify-1.0.0.tgz#9e528762b4a9066ad163a6962a364418e9626ece" + resolved "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz#9e528762b4a9066ad163a6962a364418e9626ece" integrity sha1-nlKHYrSpBmrRY6aWKjZEGOlibs4= -array-includes@^3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.3.tgz#c7f619b382ad2afaf5326cddfdc0afc61af7690a" - integrity sha512-gcem1KlBU7c9rB+Rq8/3PPKsK2kjqeEBa3bD5kkQo4nYlOHQCJqIJFqBXDEfwaRuYTT4E+FxA9xez7Gf/e3Q7A== +array-includes@^3.1.4: + version "3.1.4" + resolved "https://registry.npmjs.org/array-includes/-/array-includes-3.1.4.tgz#f5b493162c760f3539631f005ba2bb46acb45ba9" + integrity sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw== dependencies: call-bind "^1.0.2" define-properties "^1.1.3" - es-abstract "^1.18.0-next.2" + es-abstract "^1.19.1" get-intrinsic "^1.1.1" - is-string "^1.0.5" + is-string "^1.0.7" array-union@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + resolved "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== array-unique@^0.3.2: version "0.3.2" - resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" + resolved "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= -array.prototype.flat@^1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.2.4.tgz#6ef638b43312bd401b4c6199fdec7e2dc9e9a123" - integrity sha512-4470Xi3GAPAjZqFcljX2xzckv1qeKPizoNkiS0+O4IoPR2ZNpcjE0pkhdihlDouK+x6QOast26B4Q/O9DJnwSg== +array.prototype.flat@^1.2.5: + version "1.2.5" + resolved "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.5.tgz#07e0975d84bbc7c48cd1879d609e682598d33e13" + integrity sha512-KaYU+S+ndVqyUnignHftkwc58o3uVU1jzczILJ1tN2YaIZpFIKBiP/x/j97E5MVPsaCloPbqWLB/8qCTVvT2qg== dependencies: - call-bind "^1.0.0" + call-bind "^1.0.2" define-properties "^1.1.3" - es-abstract "^1.18.0-next.1" + es-abstract "^1.19.0" arrify@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" + resolved "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0= arrify@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/arrify/-/arrify-2.0.1.tgz#c9655e9331e0abcd588d2a7cad7e9956f66701fa" + resolved "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz#c9655e9331e0abcd588d2a7cad7e9956f66701fa" integrity sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug== asap@^2.0.0: version "2.0.6" - resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" + resolved "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY= asn1@~0.2.3: version "0.2.4" - resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" + resolved "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg== dependencies: safer-buffer "~2.1.0" assert-plus@1.0.0, assert-plus@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + resolved "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= assign-symbols@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" + resolved "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= ast-types@^0.13.2: version "0.13.4" - resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.13.4.tgz#ee0d77b343263965ecc3fb62da16e7222b2b6782" + resolved "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz#ee0d77b343263965ecc3fb62da16e7222b2b6782" integrity sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w== dependencies: tslib "^2.0.1" astral-regex@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" + resolved "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== async@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/async/-/async-3.2.0.tgz#b3a2685c5ebb641d3de02d161002c60fc9f85720" - integrity sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw== + version "3.2.1" + resolved "https://registry.npmjs.org/async/-/async-3.2.1.tgz#d3274ec66d107a47476a4c49136aacdb00665fc8" + integrity sha512-XdD5lRO/87udXCMC9meWdYiR+Nq6ZjUfXidViUZGu2F1MO4T3XwZ1et0hb2++BgLfhyJwy44BGB/yx80ABx8hg== asynckit@^0.4.0: version "0.4.0" - resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= at-least-node@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" + resolved "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg== atob-lite@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/atob-lite/-/atob-lite-2.0.0.tgz#0fef5ad46f1bd7a8502c65727f0367d5ee43d696" + resolved "https://registry.npmjs.org/atob-lite/-/atob-lite-2.0.0.tgz#0fef5ad46f1bd7a8502c65727f0367d5ee43d696" integrity sha1-D+9a1G8b16hQLGVyfwNn1e5D1pY= atob@^2.1.2: version "2.1.2" - resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" + resolved "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== -available-typed-arrays@^1.0.2: - version "1.0.4" - resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.4.tgz#9e0ae84ecff20caae6a94a1c3bc39b955649b7a9" - integrity sha512-SA5mXJWrId1TaQjfxUYghbqQ/hYioKmLJvPJyDuYRtXXenFNMjj4hSSt1Cf1xsuXSXrtxrVC5Ot4eU6cOtBDdA== +available-typed-arrays@^1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" + integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== -aws-sdk-mock@^5.2.1: - version "5.2.1" - resolved "https://registry.yarnpkg.com/aws-sdk-mock/-/aws-sdk-mock-5.2.1.tgz#126d4d5362c96b7d1d0bd87708a99d626c19ffd4" - integrity sha512-dY7zA1p/lX335V4/aOJ2L8ggXC3a5zokTJFZlZVW3uU+Zej7u+V7WrEcN5TVaJAnk4auT263T6EK/OHW4WjKhw== +aws-sdk-mock@^5.4.0: + version "5.4.0" + resolved "https://registry.npmjs.org/aws-sdk-mock/-/aws-sdk-mock-5.4.0.tgz#1c7abbcb128972f0a3a475d08eff9c67b82a04a9" + integrity sha512-lAks83rzszMBNJ91YYGZT/NEaXUlW1rzeBNPFY4i4ImoL3Xx26Ro4sBUb9TwTnU+8LDCMgVigSEELMPFfTUkmA== dependencies: aws-sdk "^2.928.0" sinon "^11.1.1" traverse "^0.6.6" -aws-sdk@^2.848.0, aws-sdk@^2.928.0: - version "2.950.0" - resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.950.0.tgz#cffb65590c50de9479c87ed04df57d355d1d8a22" - integrity sha512-iFC5fKLuFLEV27xeKmxDHDZzIDj4upm5+Ts3NpYYRbwPlOG0nE0gZzf9fRYkLkLgTr0TQq26CbKorgeo+6ailw== - dependencies: - buffer "4.9.2" - events "1.1.1" - ieee754 "1.1.13" - jmespath "0.15.0" - querystring "0.2.0" - sax "1.2.1" - url "0.10.3" - uuid "3.3.2" - xml2js "0.4.19" - -aws-sdk@^2.979.0: - version "2.979.0" - resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.979.0.tgz#d0104fec763cc3eafb123e709f94866790109da4" - integrity sha512-pKKhpYZwmihCvuH3757WHY8JQI9g2wvtF3s0aiyH2xCUmX/6uekhExz/utD4uqZP3m3PwKZPGQkQkH30DtHrPw== +aws-sdk@^2.596.0, aws-sdk@^2.848.0, aws-sdk@^2.928.0, aws-sdk@^2.979.0: + version "2.1006.0" + resolved "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1006.0.tgz#fc2f7e267d19a6297f732e19449461bb944682af" + integrity sha512-lwXAy706+1HVQqMnHaahdeBZZbdu6TWrtTY0ydeG0qanwldTFNMLczwnETTZWYsqNAU+wjl1VzmFdMO4gePLNQ== dependencies: buffer "4.9.2" events "1.1.1" @@ -2316,24 +2336,24 @@ aws-sdk@^2.979.0: aws-sign2@~0.7.0: version "0.7.0" - resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" + resolved "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= aws4@^1.8.0: version "1.11.0" - resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59" + resolved "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59" integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA== axios@^0.21.1: version "0.21.4" - resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.4.tgz#c67b90dc0568e5c1cf2b0b858c43ba28e2eda575" + resolved "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz#c67b90dc0568e5c1cf2b0b858c43ba28e2eda575" integrity sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg== dependencies: follow-redirects "^1.14.0" babel-jest@^26.6.3: version "26.6.3" - resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-26.6.3.tgz#d87d25cb0037577a0c89f82e5755c5d293c01056" + resolved "https://registry.npmjs.org/babel-jest/-/babel-jest-26.6.3.tgz#d87d25cb0037577a0c89f82e5755c5d293c01056" integrity sha512-pl4Q+GAVOHwvjrck6jKjvmGhnO3jHX/xuB9d27f+EJZ/6k+6nMuPjorrYp7s++bKKdANwzElBWnLWaObvTnaZA== dependencies: "@jest/transform" "^26.6.2" @@ -2347,7 +2367,7 @@ babel-jest@^26.6.3: babel-plugin-istanbul@^6.0.0: version "6.0.0" - resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz#e159ccdc9af95e0b570c75b4573b7c34d671d765" + resolved "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz#e159ccdc9af95e0b570c75b4573b7c34d671d765" integrity sha512-AF55rZXpe7trmEylbaE1Gv54wn6rwU03aptvRoVIGP8YykoSxqdVLV1TfwflBCE/QtHmqtP8SWlTENqbK8GCSQ== dependencies: "@babel/helper-plugin-utils" "^7.0.0" @@ -2358,7 +2378,7 @@ babel-plugin-istanbul@^6.0.0: babel-plugin-jest-hoist@^26.6.2: version "26.6.2" - resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-26.6.2.tgz#8185bd030348d254c6d7dd974355e6a28b21e62d" + resolved "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-26.6.2.tgz#8185bd030348d254c6d7dd974355e6a28b21e62d" integrity sha512-PO9t0697lNTmcEHH69mdtYiOIkkOlj9fySqfO3K1eCcdISevLAE0xY59VLLUj0SoiPiTX/JU2CYFpILydUa5Lw== dependencies: "@babel/template" "^7.3.3" @@ -2368,7 +2388,7 @@ babel-plugin-jest-hoist@^26.6.2: babel-preset-current-node-syntax@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz#b4399239b89b2a011f9ddbe3e4f401fc40cff73b" + resolved "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz#b4399239b89b2a011f9ddbe3e4f401fc40cff73b" integrity sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ== dependencies: "@babel/plugin-syntax-async-generators" "^7.8.4" @@ -2386,7 +2406,7 @@ babel-preset-current-node-syntax@^1.0.0: babel-preset-jest@^26.6.2: version "26.6.2" - resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-26.6.2.tgz#747872b1171df032252426586881d62d31798fee" + resolved "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-26.6.2.tgz#747872b1171df032252426586881d62d31798fee" integrity sha512-YvdtlVm9t3k777c5NPQIv6cxFFFapys25HiUmuSgHwIZhfifweR5c5Sf5nwE3MAbfu327CYSvps8Yx6ANLyleQ== dependencies: babel-plugin-jest-hoist "^26.6.2" @@ -2394,17 +2414,17 @@ babel-preset-jest@^26.6.2: balanced-match@^1.0.0: version "1.0.2" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== base64-js@^1.0.2, base64-js@^1.3.1: version "1.5.1" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== base@^0.11.1: version "0.11.2" - resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" + resolved "https://registry.npmjs.org/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== dependencies: cache-base "^1.0.1" @@ -2417,24 +2437,19 @@ base@^0.11.1: bcrypt-pbkdf@^1.0.0: version "1.0.2" - resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" + resolved "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= dependencies: tweetnacl "^0.14.3" before-after-hook@^2.0.0, before-after-hook@^2.2.0: version "2.2.2" - resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.2.2.tgz#a6e8ca41028d90ee2c24222f201c90956091613e" + resolved "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.2.tgz#a6e8ca41028d90ee2c24222f201c90956091613e" integrity sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ== -bind-obj-methods@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/bind-obj-methods/-/bind-obj-methods-2.0.2.tgz#ea603b0f2455dce76d177c69747751b40c815897" - integrity sha512-bUkRdEOppT1Xg/jG0+bp0JSjUD9U0r7skxb/42WeBUjfBpW6COQTIgQmKX5J2Z3aMXcORKgN2N+d7IQwTK3pag== - bl@^4.0.3: version "4.1.0" - resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" + resolved "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w== dependencies: buffer "^5.5.0" @@ -2443,12 +2458,12 @@ bl@^4.0.3: bluebird@^3.5.0: version "3.7.2" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" + resolved "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== brace-expansion@^1.1.7: version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== dependencies: balanced-match "^1.0.0" @@ -2456,7 +2471,7 @@ brace-expansion@^1.1.7: braces@^2.3.1: version "2.3.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" + resolved "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== dependencies: arr-flatten "^1.1.0" @@ -2472,59 +2487,59 @@ braces@^2.3.1: braces@^3.0.1: version "3.0.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + resolved "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== dependencies: fill-range "^7.0.1" browser-process-hrtime@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" + resolved "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== browserslist@^4.16.6: - version "4.16.6" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.16.6.tgz#d7901277a5a88e554ed305b183ec9b0c08f66fa2" - integrity sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ== + version "4.17.3" + resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.17.3.tgz#2844cd6eebe14d12384b0122d217550160d2d624" + integrity sha512-59IqHJV5VGdcJZ+GZ2hU5n4Kv3YiASzW6Xk5g9tf5a/MAzGeFwgGWU39fVzNIOVcgB3+Gp+kiQu0HEfTVU/3VQ== dependencies: - caniuse-lite "^1.0.30001219" - colorette "^1.2.2" - electron-to-chromium "^1.3.723" + caniuse-lite "^1.0.30001264" + electron-to-chromium "^1.3.857" escalade "^3.1.1" - node-releases "^1.1.71" + node-releases "^1.1.77" + picocolors "^0.2.1" bs-logger@0.x: version "0.2.6" - resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" + resolved "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" integrity sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog== dependencies: fast-json-stable-stringify "2.x" bser@2.1.1: version "2.1.1" - resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" + resolved "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== dependencies: node-int64 "^0.4.0" btoa-lite@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/btoa-lite/-/btoa-lite-1.0.0.tgz#337766da15801210fdd956c22e9c6891ab9d0337" + resolved "https://registry.npmjs.org/btoa-lite/-/btoa-lite-1.0.0.tgz#337766da15801210fdd956c22e9c6891ab9d0337" integrity sha1-M3dm2hWAEhD92VbCLpxokaudAzc= buffer-crc32@^0.2.1, buffer-crc32@^0.2.13: version "0.2.13" - resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" + resolved "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI= buffer-from@1.x, buffer-from@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" - integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== + version "1.1.2" + resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== buffer@4.9.2: version "4.9.2" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.2.tgz#230ead344002988644841ab0244af8c44bbe3ef8" + resolved "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz#230ead344002988644841ab0244af8c44bbe3ef8" integrity sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg== dependencies: base64-js "^1.0.2" @@ -2533,7 +2548,7 @@ buffer@4.9.2: buffer@^5.5.0: version "5.7.1" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" + resolved "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== dependencies: base64-js "^1.3.1" @@ -2541,29 +2556,30 @@ buffer@^5.5.0: builtins@^1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/builtins/-/builtins-1.0.3.tgz#cb94faeb61c8696451db36534e1422f94f0aee88" + resolved "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz#cb94faeb61c8696451db36534e1422f94f0aee88" integrity sha1-y5T662HIaWRR2zZTThQi+U8K7og= byline@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/byline/-/byline-5.0.0.tgz#741c5216468eadc457b03410118ad77de8c1ddb1" + resolved "https://registry.npmjs.org/byline/-/byline-5.0.0.tgz#741c5216468eadc457b03410118ad77de8c1ddb1" integrity sha1-dBxSFkaOrcRXsDQQEYrXfejB3bE= byte-size@^7.0.0: version "7.0.1" - resolved "https://registry.yarnpkg.com/byte-size/-/byte-size-7.0.1.tgz#b1daf3386de7ab9d706b941a748dbfc71130dee3" + resolved "https://registry.npmjs.org/byte-size/-/byte-size-7.0.1.tgz#b1daf3386de7ab9d706b941a748dbfc71130dee3" integrity sha512-crQdqyCwhokxwV1UyDzLZanhkugAgft7vt0qbbdt60C6Zf3CAiGmtUCylbtYwrU6loOUw3euGrNtW1J651ot1A== bytes@3.1.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" + resolved "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== cacache@^15.0.5, cacache@^15.2.0: - version "15.2.0" - resolved "https://registry.yarnpkg.com/cacache/-/cacache-15.2.0.tgz#73af75f77c58e72d8c630a7a2858cb18ef523389" - integrity sha512-uKoJSHmnrqXgthDFx/IU6ED/5xd+NNGe+Bb+kLZy7Ku4P+BaiWEUflAKPZ7eAzsYGcsAGASJZsybXp+quEcHTw== + version "15.3.0" + resolved "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz#dc85380fb2f556fe3dda4c719bfa0ec875a7f1eb" + integrity sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ== dependencies: + "@npmcli/fs" "^1.0.0" "@npmcli/move-file" "^1.0.1" chownr "^2.0.0" fs-minipass "^2.0.0" @@ -2584,7 +2600,7 @@ cacache@^15.0.5, cacache@^15.2.0: cache-base@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" + resolved "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== dependencies: collection-visit "^1.0.0" @@ -2597,19 +2613,9 @@ cache-base@^1.0.1: union-value "^1.0.0" unset-value "^1.0.0" -caching-transform@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/caching-transform/-/caching-transform-3.0.2.tgz#601d46b91eca87687a281e71cef99791b0efca70" - integrity sha512-Mtgcv3lh3U0zRii/6qVgQODdPA4G3zhG+jtbCWj39RXuUFTMzH0vcdMtaJS1jPowd+It2Pqr6y3NJMQqOqCE2w== - dependencies: - hasha "^3.0.0" - make-dir "^2.0.0" - package-hash "^3.0.0" - write-file-atomic "^2.4.2" - caching-transform@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/caching-transform/-/caching-transform-4.0.0.tgz#00d297a4206d71e2163c39eaffa8157ac0651f0f" + resolved "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz#00d297a4206d71e2163c39eaffa8157ac0651f0f" integrity sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA== dependencies: hasha "^5.0.0" @@ -2619,7 +2625,7 @@ caching-transform@^4.0.0: call-bind@^1.0.0, call-bind@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" + resolved "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== dependencies: function-bind "^1.1.1" @@ -2627,12 +2633,12 @@ call-bind@^1.0.0, call-bind@^1.0.2: callsites@^3.0.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + resolved "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== camelcase-keys@^6.2.2: version "6.2.2" - resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-6.2.2.tgz#5e755d6ba51aa223ec7d3d52f25778210f9dc3c0" + resolved "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz#5e755d6ba51aa223ec7d3d52f25778210f9dc3c0" integrity sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg== dependencies: camelcase "^5.3.1" @@ -2641,51 +2647,46 @@ camelcase-keys@^6.2.2: camelcase@^5.0.0, camelcase@^5.3.1: version "5.3.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + resolved "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== camelcase@^6.0.0, camelcase@^6.2.0: version "6.2.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.2.0.tgz#924af881c9d525ac9d87f40d964e5cea982a1809" + resolved "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz#924af881c9d525ac9d87f40d964e5cea982a1809" integrity sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg== -caniuse-lite@^1.0.30001219: - version "1.0.30001246" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001246.tgz#fe17d9919f87124d6bb416ef7b325356d69dc76c" - integrity sha512-Tc+ff0Co/nFNbLOrziBXmMVtpt9S2c2Y+Z9Nk9Khj09J+0zR9ejvIW5qkZAErCbOrVODCx/MN+GpB5FNBs5GFA== +caniuse-lite@^1.0.30001264: + version "1.0.30001265" + resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001265.tgz#0613c9e6c922e422792e6fcefdf9a3afeee4f8c3" + integrity sha512-YzBnspggWV5hep1m9Z6sZVLOt7vrju8xWooFAgN6BA5qvy98qPAPb7vNUzypFaoh2pb3vlfzbDO8tB57UPGbtw== capture-exit@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-2.0.0.tgz#fb953bfaebeb781f62898239dabb426d08a509a4" + resolved "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz#fb953bfaebeb781f62898239dabb426d08a509a4" integrity sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g== dependencies: rsvp "^4.8.4" -capture-stack-trace@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/capture-stack-trace/-/capture-stack-trace-1.0.1.tgz#a6c0bbe1f38f3aa0b92238ecb6ff42c344d4135d" - integrity sha512-mYQLZnx5Qt1JgB1WEiMCf2647plpGeQ2NMR/5L0HNZzGQo4fuSPnK+wjfPnKZV0aiJDgzmWqqkV/g7JD+DW0qw== - case@1.6.3, case@^1.6.3: version "1.6.3" - resolved "https://registry.yarnpkg.com/case/-/case-1.6.3.tgz#0a4386e3e9825351ca2e6216c60467ff5f1ea1c9" + resolved "https://registry.npmjs.org/case/-/case-1.6.3.tgz#0a4386e3e9825351ca2e6216c60467ff5f1ea1c9" integrity sha512-mzDSXIPaFwVDvZAHqZ9VlbyF4yyXRuX6IvB06WvPYkqJVO24kX1PPhv9bfpKNFZyxYFmmgo03HUiD8iklmJYRQ== caseless@~0.12.0: version "0.12.0" - resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" + resolved "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= cdk8s-plus@^0.33.0: version "0.33.0" - resolved "https://registry.yarnpkg.com/cdk8s-plus/-/cdk8s-plus-0.33.0.tgz#b2dc56b417ab8261cd4a796f080f04dcd4fe0f66" + resolved "https://registry.npmjs.org/cdk8s-plus/-/cdk8s-plus-0.33.0.tgz#b2dc56b417ab8261cd4a796f080f04dcd4fe0f66" integrity sha512-CnvuNTQS9DH1MYEDizUObMZ3PG7BqshJaG7kkuThmwNgC8QkVGmOkLC9YP8UBDr1mKW+zfV12HCIw93SteRr3g== dependencies: minimatch "^3.0.4" cdk8s@^0.33.0: version "0.33.0" - resolved "https://registry.yarnpkg.com/cdk8s/-/cdk8s-0.33.0.tgz#503b60b98de5fe82b22ac5dee2c351a4ba102deb" + resolved "https://registry.npmjs.org/cdk8s/-/cdk8s-0.33.0.tgz#503b60b98de5fe82b22ac5dee2c351a4ba102deb" integrity sha512-Yoo6RZWZPk6K2JZLiJA22faNVWqTE6Nv+VNgmTFTq4AC8c+eCvq6/xHKcpn78HhTLEPBmczaja7q2MiRc9LTBQ== dependencies: follow-redirects "^1.11.0" @@ -2694,67 +2695,67 @@ cdk8s@^0.33.0: chalk@^2.0.0, chalk@^2.4.2: version "2.4.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== dependencies: ansi-styles "^3.2.1" escape-string-regexp "^1.0.5" supports-color "^5.3.0" -chalk@^4.0.0, chalk@^4.1.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.1.tgz#c80b3fab28bf6371e6863325eee67e618b77e6ad" - integrity sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - -chalk@^4.1.2: +chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2: version "4.1.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== dependencies: ansi-styles "^4.1.0" supports-color "^7.1.0" +changelog-parser@^2.8.0: + version "2.8.0" + resolved "https://registry.npmjs.org/changelog-parser/-/changelog-parser-2.8.0.tgz#c14293e3e8fab797913c722de965480198650108" + integrity sha512-ZtSwN0hY7t+WpvaXqqXz98RHCNhWX9HsvCRAv1aBLlqJ7BpKtqdM6Nu6JOiUhRAWR7Gov0aN0fUnmflTz0WgZg== + dependencies: + line-reader "^0.2.4" + remove-markdown "^0.2.2" + char-regex@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" + resolved "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== chardet@^0.7.0: version "0.7.0" - resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" + resolved "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== charenc@0.0.2: version "0.0.2" - resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" + resolved "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" integrity sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc= chownr@^1.1.4: version "1.1.4" - resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" + resolved "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== chownr@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" + resolved "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== ci-info@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" + resolved "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== cjs-module-lexer@^0.6.0: version "0.6.0" - resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-0.6.0.tgz#4186fcca0eae175970aee870b9fe2d6cf8d5655f" + resolved "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-0.6.0.tgz#4186fcca0eae175970aee870b9fe2d6cf8d5655f" integrity sha512-uc2Vix1frTfnuzxxu1Hp4ktSvM3QaI4oXl4ZUqL1wjTu/BGki9TrCWoqLTg/drR1KwAEarXuRFCG2Svr1GxPFw== class-utils@^0.3.5: version "0.3.6" - resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" + resolved "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== dependencies: arr-union "^3.1.0" @@ -2764,45 +2765,31 @@ class-utils@^0.3.5: clean-stack@^2.0.0: version "2.2.0" - resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" + resolved "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== -clean-yaml-object@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/clean-yaml-object/-/clean-yaml-object-0.1.0.tgz#63fb110dc2ce1a84dc21f6d9334876d010ae8b68" - integrity sha1-Y/sRDcLOGoTcIfbZM0h20BCui2g= - cli-color@~0.1.6: version "0.1.7" - resolved "https://registry.yarnpkg.com/cli-color/-/cli-color-0.1.7.tgz#adc3200fa471cc211b0da7f566b71e98b9d67347" + resolved "https://registry.npmjs.org/cli-color/-/cli-color-0.1.7.tgz#adc3200fa471cc211b0da7f566b71e98b9d67347" integrity sha1-rcMgD6RxzCEbDaf1ZrcemLnWc0c= dependencies: es5-ext "0.8.x" cli-cursor@^3.1.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" + resolved "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== dependencies: restore-cursor "^3.1.0" cli-width@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" + resolved "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw== -cliui@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" - integrity sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA== - dependencies: - string-width "^3.1.0" - strip-ansi "^5.2.0" - wrap-ansi "^5.1.0" - cliui@^6.0.0: version "6.0.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1" + resolved "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1" integrity sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ== dependencies: string-width "^4.2.0" @@ -2811,7 +2798,7 @@ cliui@^6.0.0: cliui@^7.0.2: version "7.0.4" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" + resolved "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== dependencies: string-width "^4.2.0" @@ -2820,7 +2807,7 @@ cliui@^7.0.2: clone-deep@^4.0.1: version "4.0.1" - resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387" + resolved "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387" integrity sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ== dependencies: is-plain-object "^2.0.4" @@ -2829,52 +2816,43 @@ clone-deep@^4.0.1: clone@^1.0.2: version "1.0.4" - resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" + resolved "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4= clone@^2.1.2: version "2.1.2" - resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" + resolved "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" integrity sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18= cmd-shim@^4.1.0: version "4.1.0" - resolved "https://registry.yarnpkg.com/cmd-shim/-/cmd-shim-4.1.0.tgz#b3a904a6743e9fede4148c6f3800bf2a08135bdd" + resolved "https://registry.npmjs.org/cmd-shim/-/cmd-shim-4.1.0.tgz#b3a904a6743e9fede4148c6f3800bf2a08135bdd" integrity sha512-lb9L7EM4I/ZRVuljLPEtUJOP+xiQVknZ4ZMpMgEp4JzNldPb27HU03hi6K1/6CoIuit/Zm/LQXySErFeXxDprw== dependencies: mkdirp-infer-owner "^2.0.0" co@^4.6.0: version "4.6.0" - resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + resolved "https://registry.npmjs.org/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= -codemaker@^1.31.0: - version "1.31.0" - resolved "https://registry.yarnpkg.com/codemaker/-/codemaker-1.31.0.tgz#1987d8d2dcb39883844134d50c85f33f29f0cb62" - integrity sha512-gyWhtZ4YU5b+pIijCfOZkGrH0DCkUQXyRG3BQtDlnwFJuXyJnDoz+dpM5ErkJuDD9w6Qns4aryyG/bU78huaSg== - dependencies: - camelcase "^6.2.0" - decamelize "^5.0.0" - fs-extra "^9.1.0" - -codemaker@^1.34.0: - version "1.34.0" - resolved "https://registry.yarnpkg.com/codemaker/-/codemaker-1.34.0.tgz#dba5dbd9ca6d1d9d9af64d64f17bde45882b0aa0" - integrity sha512-NHwy6TxMh21ygch7+K/OwtdN3BjxhAMoP5QXqzkkR0TDP2kEdKCNc31EChz3Xcmxk1qkdJN5CpXMnLjo7f07sQ== +codemaker@^1.39.0: + version "1.39.0" + resolved "https://registry.npmjs.org/codemaker/-/codemaker-1.39.0.tgz#d8103f4b587210b1d6aa073d62ffb510ac20bc42" + integrity sha512-1PPD7ZCC05nrkN47elPcno3zm4Md7XSkG52CvIbNsEcXddc0Ma2xgoMZnWPu+Ab6801FunSqov9X4O+OZle95A== dependencies: camelcase "^6.2.0" - decamelize "^5.0.0" + decamelize "^5.0.1" fs-extra "^9.1.0" collect-v8-coverage@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz#cc2c8e94fc18bbdffe64d6534570c8a673b27f59" + resolved "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz#cc2c8e94fc18bbdffe64d6534570c8a673b27f59" integrity sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg== collection-visit@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" + resolved "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= dependencies: map-visit "^1.0.0" @@ -2882,46 +2860,36 @@ collection-visit@^1.0.0: color-convert@^1.9.0: version "1.9.3" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== dependencies: color-name "1.1.3" color-convert@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== dependencies: color-name "~1.1.4" color-name@1.1.3: version "1.1.3" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= color-name@~1.1.4: version "1.1.4" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== -color-support@^1.1.0: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2" - integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== - -colorette@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.2.tgz#cbcc79d5e99caea2dbf10eb3a26fd8b3e6acfa94" - integrity sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w== - colors@^1.4.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" + resolved "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA== columnify@^1.5.4: version "1.5.4" - resolved "https://registry.yarnpkg.com/columnify/-/columnify-1.5.4.tgz#4737ddf1c7b69a8a7c340570782e947eec8e78bb" + resolved "https://registry.npmjs.org/columnify/-/columnify-1.5.4.tgz#4737ddf1c7b69a8a7c340570782e947eec8e78bb" integrity sha1-Rzfd8ce2mop8NAVweC6UfuyOeLs= dependencies: strip-ansi "^3.0.0" @@ -2929,24 +2897,24 @@ columnify@^1.5.4: combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6: version "1.0.8" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== dependencies: delayed-stream "~1.0.0" -commander@~7.1.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-7.1.0.tgz#f2eaecf131f10e36e07d894698226e36ae0eb5ff" - integrity sha512-pRxBna3MJe6HKnBGsDyMv8ETbptw3axEdYHoqNh7gu5oDcew8fs0xnivZGm06Ogk8zGAJ9VX+OPEr2GXEQK4dg== +commander@~8.2.0: + version "8.2.0" + resolved "https://registry.npmjs.org/commander/-/commander-8.2.0.tgz#37fe2bde301d87d47a53adeff8b5915db1381ca8" + integrity sha512-LLKxDvHeL91/8MIyTAD5BFMNtoIwztGPMiM/7Bl8rIPmHCZXRxmSWr91h57dpOpnQ6jIUqEWdXE/uBYMfiVZDA== commondir@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" + resolved "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= commonmark@^0.30.0: version "0.30.0" - resolved "https://registry.yarnpkg.com/commonmark/-/commonmark-0.30.0.tgz#38811dc7bbf0f59d277ae09054d4d73a332f2e45" + resolved "https://registry.npmjs.org/commonmark/-/commonmark-0.30.0.tgz#38811dc7bbf0f59d277ae09054d4d73a332f2e45" integrity sha512-j1yoUo4gxPND1JWV9xj5ELih0yMv1iCWDG6eEQIPLSWLxzCXiFoyS7kvB+WwU+tZMf4snwJMMtaubV0laFpiBA== dependencies: entities "~2.0" @@ -2956,7 +2924,7 @@ commonmark@^0.30.0: compare-func@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/compare-func/-/compare-func-2.0.0.tgz#fb65e75edbddfd2e568554e8b5b05fff7a51fcb3" + resolved "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz#fb65e75edbddfd2e568554e8b5b05fff7a51fcb3" integrity sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA== dependencies: array-ify "^1.0.0" @@ -2964,12 +2932,12 @@ compare-func@^2.0.0: component-emitter@^1.2.1: version "1.3.0" - resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" + resolved "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== compress-commons@^4.1.0: version "4.1.1" - resolved "https://registry.yarnpkg.com/compress-commons/-/compress-commons-4.1.1.tgz#df2a09a7ed17447642bad10a85cc9a19e5c42a7d" + resolved "https://registry.npmjs.org/compress-commons/-/compress-commons-4.1.1.tgz#df2a09a7ed17447642bad10a85cc9a19e5c42a7d" integrity sha512-QLdDLCKNV2dtoTorqgxngQCMA+gWXkM/Nwu7FpeBhk/RdkzimqC3jueb/FDmaZeXh+uby1jkBqE3xArsLBE5wQ== dependencies: buffer-crc32 "^0.2.13" @@ -2979,12 +2947,12 @@ compress-commons@^4.1.0: concat-map@0.0.1: version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= concat-stream@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-2.0.0.tgz#414cf5af790a48c60ab9be4527d56d5e41133cb1" + resolved "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz#414cf5af790a48c60ab9be4527d56d5e41133cb1" integrity sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A== dependencies: buffer-from "^1.0.0" @@ -2994,7 +2962,7 @@ concat-stream@^2.0.0: config-chain@^1.1.12: version "1.1.13" - resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.13.tgz#fad0795aa6a6cdaff9ed1b68e9dff94372c232f4" + resolved "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz#fad0795aa6a6cdaff9ed1b68e9dff94372c232f4" integrity sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ== dependencies: ini "^1.3.4" @@ -3002,32 +2970,32 @@ config-chain@^1.1.12: console-control-strings@^1.0.0, console-control-strings@~1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + resolved "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= constructs@^3.3.69: - version "3.3.99" - resolved "https://registry.yarnpkg.com/constructs/-/constructs-3.3.99.tgz#e614595cb0a1f7986f72597a4d9b98572a4ada8d" - integrity sha512-uX3bZtp6Zn53Utyurp4DrKolIDUuiDddHVTgsQ39KhVRkQ8TRMtl0nyXllysMtu78t8zLo9QygeyQ0QOBy3LHw== + version "3.3.161" + resolved "https://registry.npmjs.org/constructs/-/constructs-3.3.161.tgz#9726b1d450f3b9aca7907230f2248e3fd4058ce4" + integrity sha512-/27vW3fo0iyb3py4vKI1BduEYmv8vv8uJgLXvI+5F0Jbnn0/E+As2wkGMa7bumhzCd0Ckv/USkAXstGYVXTYQA== conventional-changelog-angular@^5.0.12: - version "5.0.12" - resolved "https://registry.yarnpkg.com/conventional-changelog-angular/-/conventional-changelog-angular-5.0.12.tgz#c979b8b921cbfe26402eb3da5bbfda02d865a2b9" - integrity sha512-5GLsbnkR/7A89RyHLvvoExbiGbd9xKdKqDTrArnPbOqBqG/2wIosu0fHwpeIRI8Tl94MhVNBXcLJZl92ZQ5USw== + version "5.0.13" + resolved "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-5.0.13.tgz#896885d63b914a70d4934b59d2fe7bde1832b28c" + integrity sha512-i/gipMxs7s8L/QeuavPF2hLnJgH6pEZAttySB6aiQLWcX3puWDL3ACVmvBhJGxnAy52Qc15ua26BufY6KpmrVA== dependencies: compare-func "^2.0.0" q "^1.5.1" conventional-changelog-atom@^2.0.8: version "2.0.8" - resolved "https://registry.yarnpkg.com/conventional-changelog-atom/-/conventional-changelog-atom-2.0.8.tgz#a759ec61c22d1c1196925fca88fe3ae89fd7d8de" + resolved "https://registry.npmjs.org/conventional-changelog-atom/-/conventional-changelog-atom-2.0.8.tgz#a759ec61c22d1c1196925fca88fe3ae89fd7d8de" integrity sha512-xo6v46icsFTK3bb7dY/8m2qvc8sZemRgdqLb/bjpBsH2UyOS8rKNTgcb5025Hri6IpANPApbXMg15QLb1LJpBw== dependencies: q "^1.5.1" conventional-changelog-cli@^2.1.1: version "2.1.1" - resolved "https://registry.yarnpkg.com/conventional-changelog-cli/-/conventional-changelog-cli-2.1.1.tgz#7a11980bc399938e0509d2adf8e7a0e213eb994e" + resolved "https://registry.npmjs.org/conventional-changelog-cli/-/conventional-changelog-cli-2.1.1.tgz#7a11980bc399938e0509d2adf8e7a0e213eb994e" integrity sha512-xMGQdKJ+4XFDDgfX5aK7UNFduvJMbvF5BB+g0OdVhA3rYdYyhctrIE2Al+WYdZeKTdg9YzMWF2iFPT8MupIwng== dependencies: add-stream "^1.0.0" @@ -3038,19 +3006,19 @@ conventional-changelog-cli@^2.1.1: conventional-changelog-codemirror@^2.0.8: version "2.0.8" - resolved "https://registry.yarnpkg.com/conventional-changelog-codemirror/-/conventional-changelog-codemirror-2.0.8.tgz#398e9530f08ce34ec4640af98eeaf3022eb1f7dc" + resolved "https://registry.npmjs.org/conventional-changelog-codemirror/-/conventional-changelog-codemirror-2.0.8.tgz#398e9530f08ce34ec4640af98eeaf3022eb1f7dc" integrity sha512-z5DAsn3uj1Vfp7po3gpt2Boc+Bdwmw2++ZHa5Ak9k0UKsYAO5mH1UBTN0qSCuJZREIhX6WU4E1p3IW2oRCNzQw== dependencies: q "^1.5.1" conventional-changelog-config-spec@2.1.0, conventional-changelog-config-spec@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/conventional-changelog-config-spec/-/conventional-changelog-config-spec-2.1.0.tgz#874a635287ef8b581fd8558532bf655d4fb59f2d" + resolved "https://registry.npmjs.org/conventional-changelog-config-spec/-/conventional-changelog-config-spec-2.1.0.tgz#874a635287ef8b581fd8558532bf655d4fb59f2d" integrity sha512-IpVePh16EbbB02V+UA+HQnnPIohgXvJRxHcS5+Uwk4AT5LjzCZJm5sp/yqs5C6KZJ1jMsV4paEV13BN1pvDuxQ== conventional-changelog-conventionalcommits@4.5.0: version "4.5.0" - resolved "https://registry.yarnpkg.com/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-4.5.0.tgz#a02e0b06d11d342fdc0f00c91d78265ed0bc0a62" + resolved "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-4.5.0.tgz#a02e0b06d11d342fdc0f00c91d78265ed0bc0a62" integrity sha512-buge9xDvjjOxJlyxUnar/+6i/aVEVGA7EEh4OafBCXPlLUQPGbRUBhBUveWRxzvR8TEjhKEP4BdepnpG2FSZXw== dependencies: compare-func "^2.0.0" @@ -3058,18 +3026,18 @@ conventional-changelog-conventionalcommits@4.5.0: q "^1.5.1" conventional-changelog-conventionalcommits@^4.5.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-4.6.0.tgz#7fc17211dbca160acf24687bd2fdd5fd767750eb" - integrity sha512-sj9tj3z5cnHaSJCYObA9nISf7eq/YjscLPoq6nmew4SiOjxqL2KRpK20fjnjVbpNDjJ2HR3MoVcWKXwbVvzS0A== + version "4.6.1" + resolved "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-4.6.1.tgz#f4c0921937050674e578dc7875f908351ccf4014" + integrity sha512-lzWJpPZhbM1R0PIzkwzGBCnAkH5RKJzJfFQZcl/D+2lsJxAwGnDKBqn/F4C1RD31GJNn8NuKWQzAZDAVXPp2Mw== dependencies: compare-func "^2.0.0" lodash "^4.17.15" q "^1.5.1" conventional-changelog-core@^4.2.1, conventional-changelog-core@^4.2.2: - version "4.2.3" - resolved "https://registry.yarnpkg.com/conventional-changelog-core/-/conventional-changelog-core-4.2.3.tgz#ce44d4bbba4032e3dc14c00fcd5b53fc00b66433" - integrity sha512-MwnZjIoMRL3jtPH5GywVNqetGILC7g6RQFvdb8LRU/fA/338JbeWAku3PZ8yQ+mtVRViiISqJlb0sOz0htBZig== + version "4.2.4" + resolved "https://registry.npmjs.org/conventional-changelog-core/-/conventional-changelog-core-4.2.4.tgz#e50d047e8ebacf63fac3dc67bf918177001e1e9f" + integrity sha512-gDVS+zVJHE2v4SLc6B0sLsPiloR0ygU7HaDW14aNJE1v4SlqJPILPl/aJC7YdtRE4CybBf8gDwObBvKha8Xlyg== dependencies: add-stream "^1.0.0" conventional-changelog-writer "^5.0.0" @@ -3088,35 +3056,35 @@ conventional-changelog-core@^4.2.1, conventional-changelog-core@^4.2.2: conventional-changelog-ember@^2.0.9: version "2.0.9" - resolved "https://registry.yarnpkg.com/conventional-changelog-ember/-/conventional-changelog-ember-2.0.9.tgz#619b37ec708be9e74a220f4dcf79212ae1c92962" + resolved "https://registry.npmjs.org/conventional-changelog-ember/-/conventional-changelog-ember-2.0.9.tgz#619b37ec708be9e74a220f4dcf79212ae1c92962" integrity sha512-ulzIReoZEvZCBDhcNYfDIsLTHzYHc7awh+eI44ZtV5cx6LVxLlVtEmcO+2/kGIHGtw+qVabJYjdI5cJOQgXh1A== dependencies: q "^1.5.1" conventional-changelog-eslint@^3.0.9: version "3.0.9" - resolved "https://registry.yarnpkg.com/conventional-changelog-eslint/-/conventional-changelog-eslint-3.0.9.tgz#689bd0a470e02f7baafe21a495880deea18b7cdb" + resolved "https://registry.npmjs.org/conventional-changelog-eslint/-/conventional-changelog-eslint-3.0.9.tgz#689bd0a470e02f7baafe21a495880deea18b7cdb" integrity sha512-6NpUCMgU8qmWmyAMSZO5NrRd7rTgErjrm4VASam2u5jrZS0n38V7Y9CzTtLT2qwz5xEChDR4BduoWIr8TfwvXA== dependencies: q "^1.5.1" conventional-changelog-express@^2.0.6: version "2.0.6" - resolved "https://registry.yarnpkg.com/conventional-changelog-express/-/conventional-changelog-express-2.0.6.tgz#420c9d92a347b72a91544750bffa9387665a6ee8" + resolved "https://registry.npmjs.org/conventional-changelog-express/-/conventional-changelog-express-2.0.6.tgz#420c9d92a347b72a91544750bffa9387665a6ee8" integrity sha512-SDez2f3iVJw6V563O3pRtNwXtQaSmEfTCaTBPCqn0oG0mfkq0rX4hHBq5P7De2MncoRixrALj3u3oQsNK+Q0pQ== dependencies: q "^1.5.1" conventional-changelog-jquery@^3.0.11: version "3.0.11" - resolved "https://registry.yarnpkg.com/conventional-changelog-jquery/-/conventional-changelog-jquery-3.0.11.tgz#d142207400f51c9e5bb588596598e24bba8994bf" + resolved "https://registry.npmjs.org/conventional-changelog-jquery/-/conventional-changelog-jquery-3.0.11.tgz#d142207400f51c9e5bb588596598e24bba8994bf" integrity sha512-x8AWz5/Td55F7+o/9LQ6cQIPwrCjfJQ5Zmfqi8thwUEKHstEn4kTIofXub7plf1xvFA2TqhZlq7fy5OmV6BOMw== dependencies: q "^1.5.1" conventional-changelog-jshint@^2.0.9: version "2.0.9" - resolved "https://registry.yarnpkg.com/conventional-changelog-jshint/-/conventional-changelog-jshint-2.0.9.tgz#f2d7f23e6acd4927a238555d92c09b50fe3852ff" + resolved "https://registry.npmjs.org/conventional-changelog-jshint/-/conventional-changelog-jshint-2.0.9.tgz#f2d7f23e6acd4927a238555d92c09b50fe3852ff" integrity sha512-wMLdaIzq6TNnMHMy31hql02OEQ8nCQfExw1SE0hYL5KvU+JCTuPaDO+7JiogGT2gJAxiUGATdtYYfh+nT+6riA== dependencies: compare-func "^2.0.0" @@ -3124,12 +3092,12 @@ conventional-changelog-jshint@^2.0.9: conventional-changelog-preset-loader@^2.3.4: version "2.3.4" - resolved "https://registry.yarnpkg.com/conventional-changelog-preset-loader/-/conventional-changelog-preset-loader-2.3.4.tgz#14a855abbffd59027fd602581f1f34d9862ea44c" + resolved "https://registry.npmjs.org/conventional-changelog-preset-loader/-/conventional-changelog-preset-loader-2.3.4.tgz#14a855abbffd59027fd602581f1f34d9862ea44c" integrity sha512-GEKRWkrSAZeTq5+YjUZOYxdHq+ci4dNwHvpaBC3+ENalzFWuCWa9EZXSuZBpkr72sMdKB+1fyDV4takK1Lf58g== conventional-changelog-writer@^4.1.0: version "4.1.0" - resolved "https://registry.yarnpkg.com/conventional-changelog-writer/-/conventional-changelog-writer-4.1.0.tgz#1ca7880b75aa28695ad33312a1f2366f4b12659f" + resolved "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-4.1.0.tgz#1ca7880b75aa28695ad33312a1f2366f4b12659f" integrity sha512-WwKcUp7WyXYGQmkLsX4QmU42AZ1lqlvRW9mqoyiQzdD+rJWbTepdWoKJuwXTS+yq79XKnQNa93/roViPQrAQgw== dependencies: compare-func "^2.0.0" @@ -3145,7 +3113,7 @@ conventional-changelog-writer@^4.1.0: conventional-changelog-writer@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/conventional-changelog-writer/-/conventional-changelog-writer-5.0.0.tgz#c4042f3f1542f2f41d7d2e0d6cad23aba8df8eec" + resolved "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-5.0.0.tgz#c4042f3f1542f2f41d7d2e0d6cad23aba8df8eec" integrity sha512-HnDh9QHLNWfL6E1uHz6krZEQOgm8hN7z/m7tT16xwd802fwgMN0Wqd7AQYVkhpsjDUx/99oo+nGgvKF657XP5g== dependencies: conventional-commits-filter "^2.0.7" @@ -3160,7 +3128,7 @@ conventional-changelog-writer@^5.0.0: conventional-changelog@3.1.24, conventional-changelog@^3.1.24: version "3.1.24" - resolved "https://registry.yarnpkg.com/conventional-changelog/-/conventional-changelog-3.1.24.tgz#ebd180b0fd1b2e1f0095c4b04fd088698348a464" + resolved "https://registry.npmjs.org/conventional-changelog/-/conventional-changelog-3.1.24.tgz#ebd180b0fd1b2e1f0095c4b04fd088698348a464" integrity sha512-ed6k8PO00UVvhExYohroVPXcOJ/K1N0/drJHx/faTH37OIZthlecuLIRX/T6uOp682CAoVoFpu+sSEaeuH6Asg== dependencies: conventional-changelog-angular "^5.0.12" @@ -3177,28 +3145,15 @@ conventional-changelog@3.1.24, conventional-changelog@^3.1.24: conventional-commits-filter@^2.0.7: version "2.0.7" - resolved "https://registry.yarnpkg.com/conventional-commits-filter/-/conventional-commits-filter-2.0.7.tgz#f8d9b4f182fce00c9af7139da49365b136c8a0b3" + resolved "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-2.0.7.tgz#f8d9b4f182fce00c9af7139da49365b136c8a0b3" integrity sha512-ASS9SamOP4TbCClsRHxIHXRfcGCnIoQqkvAzCSbZzTFLfcTqJVugB0agRgsEELsqaeWgsXv513eS116wnlSSPA== dependencies: lodash.ismatch "^4.4.0" modify-values "^1.0.0" -conventional-commits-parser@^3.2.0, conventional-commits-parser@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/conventional-commits-parser/-/conventional-commits-parser-3.2.1.tgz#ba44f0b3b6588da2ee9fd8da508ebff50d116ce2" - integrity sha512-OG9kQtmMZBJD/32NEw5IhN5+HnBqVjy03eC+I71I0oQRFA5rOgA4OtPOYG7mz1GkCfCNxn3gKIX8EiHJYuf1cA== - dependencies: - JSONStream "^1.0.4" - is-text-path "^1.0.1" - lodash "^4.17.15" - meow "^8.0.0" - split2 "^3.0.0" - through2 "^4.0.0" - trim-off-newlines "^1.0.0" - -conventional-commits-parser@^3.2.2: +conventional-commits-parser@^3.2.0, conventional-commits-parser@^3.2.2: version "3.2.2" - resolved "https://registry.yarnpkg.com/conventional-commits-parser/-/conventional-commits-parser-3.2.2.tgz#190fb9900c6e02be0c0bca9b03d57e24982639fd" + resolved "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-3.2.2.tgz#190fb9900c6e02be0c0bca9b03d57e24982639fd" integrity sha512-Jr9KAKgqAkwXMRHjxDwO/zOCDKod1XdAESHAGuJX38iZ7ZzVti/tvVoysO0suMsdAObp9NQ2rHSsSbnAqZ5f5g== dependencies: JSONStream "^1.0.4" @@ -3210,7 +3165,7 @@ conventional-commits-parser@^3.2.2: conventional-recommended-bump@6.1.0, conventional-recommended-bump@^6.1.0: version "6.1.0" - resolved "https://registry.yarnpkg.com/conventional-recommended-bump/-/conventional-recommended-bump-6.1.0.tgz#cfa623285d1de554012f2ffde70d9c8a22231f55" + resolved "https://registry.npmjs.org/conventional-recommended-bump/-/conventional-recommended-bump-6.1.0.tgz#cfa623285d1de554012f2ffde70d9c8a22231f55" integrity sha512-uiApbSiNGM/kkdL9GTOLAqC4hbptObFo4wW2QRyHsKciGAfQuLU1ShZ1BIVI/+K2BE/W1AWYQMCXAsv4dyKPaw== dependencies: concat-stream "^2.0.0" @@ -3224,25 +3179,30 @@ conventional-recommended-bump@6.1.0, conventional-recommended-bump@^6.1.0: convert-source-map@^1.4.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0: version "1.8.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369" + resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369" integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA== dependencies: safe-buffer "~5.1.1" copy-descriptor@^0.1.0: version "0.1.1" - resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" + resolved "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= -core-util-is@1.0.2, core-util-is@~1.0.0: +core-util-is@1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= +core-util-is@~1.0.0: + version "1.0.3" + resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" + integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== + cosmiconfig@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.0.0.tgz#ef9b44d773959cae63ddecd122de23853b60f8d3" - integrity sha512-pondGvTuVYDk++upghXJabWzL6Kxu6f26ljFw64Swq9v6sQPUL3EUlVDV56diOjpCayKihL6hVe8exIACU4XcA== + version "7.0.1" + resolved "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz#714d756522cace867867ccb4474c5d01bbae5d6d" + integrity sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ== dependencies: "@types/parse-json" "^4.0.0" import-fresh "^3.2.1" @@ -3250,31 +3210,9 @@ cosmiconfig@^7.0.0: path-type "^4.0.0" yaml "^1.10.0" -coveralls@^3.0.2: - version "3.1.1" - resolved "https://registry.yarnpkg.com/coveralls/-/coveralls-3.1.1.tgz#f5d4431d8b5ae69c5079c8f8ca00d64ac77cf081" - integrity sha512-+dxnG2NHncSD1NrqbSM3dn/lE57O6Qf/koe9+I7c+wzkqRmEvcp0kgJdxKInzYzkICKkFMZsX3Vct3++tsF9ww== - dependencies: - js-yaml "^3.13.1" - lcov-parse "^1.0.0" - log-driver "^1.2.7" - minimist "^1.2.5" - request "^2.88.2" - -cp-file@^6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/cp-file/-/cp-file-6.2.0.tgz#40d5ea4a1def2a9acdd07ba5c0b0246ef73dc10d" - integrity sha512-fmvV4caBnofhPe8kOcitBwSn2f39QLjnAnGq3gO9dfd75mUytzKNZB1hde6QHunW2Rt+OwuBOMc3i1tNElbszA== - dependencies: - graceful-fs "^4.1.2" - make-dir "^2.0.0" - nested-error-stacks "^2.0.0" - pify "^4.0.1" - safe-buffer "^5.0.1" - crc-32@^1.2.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/crc-32/-/crc-32-1.2.0.tgz#cb2db6e29b88508e32d9dd0ec1693e7b41a18208" + resolved "https://registry.npmjs.org/crc-32/-/crc-32-1.2.0.tgz#cb2db6e29b88508e32d9dd0ec1693e7b41a18208" integrity sha512-1uBwHxF+Y/4yF5G48fwnKq6QsIXheor3ZLPT80yGBV1oEUwpPojlEhQbWKVw1VwcTQyMGHK1/XMmTjmlsmTTGA== dependencies: exit-on-epipe "~1.0.1" @@ -3282,7 +3220,7 @@ crc-32@^1.2.0: crc32-stream@^4.0.2: version "4.0.2" - resolved "https://registry.yarnpkg.com/crc32-stream/-/crc32-stream-4.0.2.tgz#c922ad22b38395abe9d3870f02fa8134ed709007" + resolved "https://registry.npmjs.org/crc32-stream/-/crc32-stream-4.0.2.tgz#c922ad22b38395abe9d3870f02fa8134ed709007" integrity sha512-DxFZ/Hk473b/muq1VJ///PMNLj0ZMnzye9thBpmjpJKCc5eMgB95aK8zCGrGfQ90cWo561Te6HK9D+j4KPdM6w== dependencies: crc-32 "^1.2.0" @@ -3290,20 +3228,12 @@ crc32-stream@^4.0.2: create-require@^1.1.0: version "1.1.1" - resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" + resolved "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== -cross-spawn@^4: - version "4.0.2" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-4.0.2.tgz#7b9247621c23adfdd3856004a823cbe397424d41" - integrity sha1-e5JHYhwjrf3ThWAEqCPL45dCTUE= - dependencies: - lru-cache "^4.0.1" - which "^1.2.9" - cross-spawn@^6.0.0, cross-spawn@^6.0.5: version "6.0.5" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== dependencies: nice-try "^1.0.4" @@ -3314,7 +3244,7 @@ cross-spawn@^6.0.0, cross-spawn@^6.0.5: cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: version "7.0.3" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== dependencies: path-key "^3.1.0" @@ -3323,46 +3253,46 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: crypt@0.0.2: version "0.0.2" - resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b" + resolved "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b" integrity sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs= cssom@^0.4.4: version "0.4.4" - resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.4.4.tgz#5a66cf93d2d0b661d80bf6a44fb65f5c2e4e0a10" + resolved "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz#5a66cf93d2d0b661d80bf6a44fb65f5c2e4e0a10" integrity sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw== cssom@~0.3.6: version "0.3.8" - resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a" + resolved "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a" integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg== cssstyle@^2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-2.3.0.tgz#ff665a0ddbdc31864b09647f34163443d90b0852" + resolved "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz#ff665a0ddbdc31864b09647f34163443d90b0852" integrity sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A== dependencies: cssom "~0.3.6" dargs@^7.0.0: version "7.0.0" - resolved "https://registry.yarnpkg.com/dargs/-/dargs-7.0.0.tgz#04015c41de0bcb69ec84050f3d9be0caf8d6d5cc" + resolved "https://registry.npmjs.org/dargs/-/dargs-7.0.0.tgz#04015c41de0bcb69ec84050f3d9be0caf8d6d5cc" integrity sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg== dashdash@^1.12.0: version "1.14.1" - resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + resolved "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= dependencies: assert-plus "^1.0.0" data-uri-to-buffer@3: version "3.0.1" - resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-3.0.1.tgz#594b8973938c5bc2c33046535785341abc4f3636" + resolved "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-3.0.1.tgz#594b8973938c5bc2c33046535785341abc4f3636" integrity sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og== data-urls@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-2.0.0.tgz#156485a72963a970f5d5821aaf642bef2bf2db9b" + resolved "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz#156485a72963a970f5d5821aaf642bef2bf2db9b" integrity sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ== dependencies: abab "^2.0.3" @@ -3371,48 +3301,48 @@ data-urls@^2.0.0: date-format@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/date-format/-/date-format-2.1.0.tgz#31d5b5ea211cf5fd764cd38baf9d033df7e125cf" + resolved "https://registry.npmjs.org/date-format/-/date-format-2.1.0.tgz#31d5b5ea211cf5fd764cd38baf9d033df7e125cf" integrity sha512-bYQuGLeFxhkxNOF3rcMtiZxvCBAquGzZm6oWA1oZ0g2THUzivaRhv8uOhdr19LmoobSOLoIAxeUK2RdbM8IFTA== date-format@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/date-format/-/date-format-3.0.0.tgz#eb8780365c7d2b1511078fb491e6479780f3ad95" + resolved "https://registry.npmjs.org/date-format/-/date-format-3.0.0.tgz#eb8780365c7d2b1511078fb491e6479780f3ad95" integrity sha512-eyTcpKOcamdhWJXj56DpQMo1ylSQpcGtGKXcU0Tb97+K56/CF5amAqqqNj0+KvA0iw2ynxtHWFsPDSClCxe48w== dateformat@^3.0.0: version "3.0.3" - resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae" + resolved "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae" integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q== debug@4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1: version "4.3.2" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b" + resolved "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b" integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw== dependencies: ms "2.1.2" debug@^2.2.0, debug@^2.3.3, debug@^2.6.9: version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== dependencies: ms "2.0.0" debug@^3.2.7: version "3.2.7" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" + resolved "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== dependencies: ms "^2.1.1" debuglog@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492" + resolved "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492" integrity sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI= decamelize-keys@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/decamelize-keys/-/decamelize-keys-1.1.0.tgz#d171a87933252807eb3cb61dc1c1445d078df2d9" + resolved "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz#d171a87933252807eb3cb61dc1c1445d078df2d9" integrity sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk= dependencies: decamelize "^1.1.0" @@ -3420,32 +3350,32 @@ decamelize-keys@^1.1.0: decamelize@^1.1.0, decamelize@^1.2.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + resolved "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= -decamelize@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-5.0.0.tgz#88358157b010ef133febfd27c18994bd80c6215b" - integrity sha512-U75DcT5hrio3KNtvdULAWnLiAPbFUC4191ldxMmj4FA/mRuBnmDwU0boNfPyFRhnan+Jm+haLeSn3P0afcBn4w== +decamelize@^5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/decamelize/-/decamelize-5.0.1.tgz#db11a92e58c741ef339fb0a2868d8a06a9a7b1e9" + integrity sha512-VfxadyCECXgQlkoEAjeghAr5gY3Hf+IKjKb+X8tGVDtveCjN+USwprd2q3QXBR9T1+x2DG0XZF5/w+7HAtSaXA== decimal.js@^10.2.1: version "10.3.1" - resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.3.1.tgz#d8c3a444a9c6774ba60ca6ad7261c3a94fd5e783" + resolved "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz#d8c3a444a9c6774ba60ca6ad7261c3a94fd5e783" integrity sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ== decode-uri-component@^0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" + resolved "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= dedent@^0.7.0: version "0.7.0" - resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" + resolved "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" integrity sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw= deep-equal@^2.0.5: version "2.0.5" - resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-2.0.5.tgz#55cd2fe326d83f9cbf7261ef0e060b3f724c5cb9" + resolved "https://registry.npmjs.org/deep-equal/-/deep-equal-2.0.5.tgz#55cd2fe326d83f9cbf7261ef0e060b3f724c5cb9" integrity sha512-nPiRgmbAtm1a3JsnLCf6/SLfXcjyN5v8L1TXzdCmHrXJ4hx+gW/w1YCcn7z8gJtSiDArZCgYtbao3QqLm/N1Sw== dependencies: call-bind "^1.0.0" @@ -3466,64 +3396,57 @@ deep-equal@^2.0.5: deep-extend@^0.6.0, deep-extend@~0.6.0: version "0.6.0" - resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" + resolved "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== deep-is@^0.1.3, deep-is@~0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" - integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= + version "0.1.4" + resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== deepmerge@^4.2.2: version "4.2.2" - resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" + resolved "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== -default-require-extensions@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-2.0.0.tgz#f5f8fbb18a7d6d50b21f641f649ebb522cfe24f7" - integrity sha1-9fj7sYp9bVCyH2QfZJ67Uiz+JPc= - dependencies: - strip-bom "^3.0.0" - default-require-extensions@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-3.0.0.tgz#e03f93aac9b2b6443fc52e5e4a37b3ad9ad8df96" + resolved "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.0.tgz#e03f93aac9b2b6443fc52e5e4a37b3ad9ad8df96" integrity sha512-ek6DpXq/SCpvjhpFsLFRVtIxJCRw6fUR42lYMVZuUMK7n8eMz4Uh5clckdBjEpLhn/gEBZo7hDJnJcwdKLKQjg== dependencies: strip-bom "^4.0.0" defaults@^1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" + resolved "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" integrity sha1-xlYFHpgX2f8I7YgUd/P+QBnz730= dependencies: clone "^1.0.2" define-properties@^1.1.3: version "1.1.3" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" + resolved "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== dependencies: object-keys "^1.0.12" define-property@^0.2.5: version "0.2.5" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" + resolved "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= dependencies: is-descriptor "^0.1.0" define-property@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" + resolved "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= dependencies: is-descriptor "^1.0.0" define-property@^2.0.2: version "2.0.2" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" + resolved "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== dependencies: is-descriptor "^1.0.2" @@ -3531,7 +3454,7 @@ define-property@^2.0.2: degenerator@^3.0.1: version "3.0.1" - resolved "https://registry.yarnpkg.com/degenerator/-/degenerator-3.0.1.tgz#7ef78ec0c8577a544477308ddf1d2d6e88d51f5b" + resolved "https://registry.npmjs.org/degenerator/-/degenerator-3.0.1.tgz#7ef78ec0c8577a544477308ddf1d2d6e88d51f5b" integrity sha512-LFsIFEeLPlKvAKXu7j3ssIG6RT0TbI7/GhsqrI0DnHASEQjXQ0LUSYcjJteGgRGmZbl1TnMSxpNQIAiJ7Du5TQ== dependencies: ast-types "^0.13.2" @@ -3541,52 +3464,52 @@ degenerator@^3.0.1: delay@5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/delay/-/delay-5.0.0.tgz#137045ef1b96e5071060dd5be60bf9334436bd1d" + resolved "https://registry.npmjs.org/delay/-/delay-5.0.0.tgz#137045ef1b96e5071060dd5be60bf9334436bd1d" integrity sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw== delayed-stream@~1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= delegates@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + resolved "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= depd@^1.1.2, depd@~1.1.2: version "1.1.2" - resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + resolved "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= deprecation@^2.0.0, deprecation@^2.3.1: version "2.3.1" - resolved "https://registry.yarnpkg.com/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919" + resolved "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919" integrity sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ== detect-indent@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-5.0.0.tgz#3871cc0a6a002e8c3e5b3cf7f336264675f06b9d" + resolved "https://registry.npmjs.org/detect-indent/-/detect-indent-5.0.0.tgz#3871cc0a6a002e8c3e5b3cf7f336264675f06b9d" integrity sha1-OHHMCmoALow+Wzz38zYmRnXwa50= detect-indent@^6.0.0, detect-indent@^6.1.0: version "6.1.0" - resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-6.1.0.tgz#592485ebbbf6b3b1ab2be175c8393d04ca0d57e6" + resolved "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz#592485ebbbf6b3b1ab2be175c8393d04ca0d57e6" integrity sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA== detect-newline@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-2.1.0.tgz#f41f1c10be4b00e87b5f13da680759f2c5bfd3e2" + resolved "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz#f41f1c10be4b00e87b5f13da680759f2c5bfd3e2" integrity sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I= detect-newline@^3.0.0, detect-newline@^3.1.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" + resolved "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== dezalgo@^1.0.0: version "1.0.3" - resolved "https://registry.yarnpkg.com/dezalgo/-/dezalgo-1.0.3.tgz#7f742de066fc748bc8db820569dddce49bf0d456" + resolved "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.3.tgz#7f742de066fc748bc8db820569dddce49bf0d456" integrity sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY= dependencies: asap "^2.0.0" @@ -3594,76 +3517,81 @@ dezalgo@^1.0.0: diff-sequences@^26.6.2: version "26.6.2" - resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-26.6.2.tgz#48ba99157de1923412eed41db6b6d4aa9ca7c0b1" + resolved "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz#48ba99157de1923412eed41db6b6d4aa9ca7c0b1" integrity sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q== diff@^4.0.1, diff@^4.0.2: version "4.0.2" - resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" + resolved "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== diff@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b" + resolved "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b" integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w== difflib@~0.2.1: version "0.2.4" - resolved "https://registry.yarnpkg.com/difflib/-/difflib-0.2.4.tgz#b5e30361a6db023176d562892db85940a718f47e" + resolved "https://registry.npmjs.org/difflib/-/difflib-0.2.4.tgz#b5e30361a6db023176d562892db85940a718f47e" integrity sha1-teMDYabbAjF21WKJLbhZQKcY9H4= dependencies: heap ">= 0.2.0" dir-glob@^3.0.1: version "3.0.1" - resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" + resolved "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== dependencies: path-type "^4.0.0" doctrine@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" + resolved "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== dependencies: esutils "^2.0.2" doctrine@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + resolved "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== dependencies: esutils "^2.0.2" -domain-browser@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" - integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA== - domexception@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/domexception/-/domexception-2.0.1.tgz#fb44aefba793e1574b0af6aed2801d057529f304" + resolved "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz#fb44aefba793e1574b0af6aed2801d057529f304" integrity sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg== dependencies: webidl-conversions "^5.0.0" dot-prop@^5.1.0: version "5.3.0" - resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.3.0.tgz#90ccce708cd9cd82cc4dc8c3ddd9abdd55b20e88" + resolved "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz#90ccce708cd9cd82cc4dc8c3ddd9abdd55b20e88" integrity sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q== dependencies: is-obj "^2.0.0" dot-prop@^6.0.1: version "6.0.1" - resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-6.0.1.tgz#fc26b3cf142b9e59b74dbd39ed66ce620c681083" + resolved "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz#fc26b3cf142b9e59b74dbd39ed66ce620c681083" integrity sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA== dependencies: is-obj "^2.0.0" +dotenv-json@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/dotenv-json/-/dotenv-json-1.0.0.tgz#fc7f672aafea04bed33818733b9f94662332815c" + integrity sha512-jAssr+6r4nKhKRudQ0HOzMskOFFi9+ubXWwmrSGJFgTvpjyPXCXsCsYbjif6mXp7uxA7xY3/LGaiTQukZzSbOQ== + +dotenv@^8.0.0: + version "8.6.0" + resolved "https://registry.npmjs.org/dotenv/-/dotenv-8.6.0.tgz#061af664d19f7f4d8fc6e4ff9b584ce237adcb8b" + integrity sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g== + dotgitignore@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/dotgitignore/-/dotgitignore-2.1.0.tgz#a4b15a4e4ef3cf383598aaf1dfa4a04bcc089b7b" + resolved "https://registry.npmjs.org/dotgitignore/-/dotgitignore-2.1.0.tgz#a4b15a4e4ef3cf383598aaf1dfa4a04bcc089b7b" integrity sha512-sCm11ak2oY6DglEPpCB8TixLjWAxd3kJTs6UIcSasNYxXdFPV+YKlye92c8H4kKFqV5qYMIh7d+cYecEg0dIkA== dependencies: find-up "^3.0.0" @@ -3671,113 +3599,112 @@ dotgitignore@^2.1.0: dreamopt@~0.6.0: version "0.6.0" - resolved "https://registry.yarnpkg.com/dreamopt/-/dreamopt-0.6.0.tgz#d813ccdac8d39d8ad526775514a13dda664d6b4b" + resolved "https://registry.npmjs.org/dreamopt/-/dreamopt-0.6.0.tgz#d813ccdac8d39d8ad526775514a13dda664d6b4b" integrity sha1-2BPM2sjTnYrVJndVFKE92mZNa0s= dependencies: wordwrap ">=0.0.2" duplexer@^0.1.1: version "0.1.2" - resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6" + resolved "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6" integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg== ecc-jsbn@~0.1.1: version "0.1.2" - resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" + resolved "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= dependencies: jsbn "~0.1.0" safer-buffer "^2.1.0" -ejs@^2.5.2: - version "2.7.4" - resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.7.4.tgz#48661287573dcc53e366c7a1ae52c3a120eec9ba" - integrity sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA== - -electron-to-chromium@^1.3.723: - version "1.3.782" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.782.tgz#522740fe6b4b5255ca754c68d9c406a17b0998e2" - integrity sha512-6AI2se1NqWA1SBf/tlD6tQD/6ZOt+yAhqmrTlh4XZw4/g0Mt3p6JhTQPZxRPxPZiOg0o7ss1EBP/CpYejfnoIA== +electron-to-chromium@^1.3.857: + version "1.3.867" + resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.867.tgz#7cb484db4b57c28da0b65c51e434c3a1f3f9aa0d" + integrity sha512-WbTXOv7hsLhjJyl7jBfDkioaY++iVVZomZ4dU6TMe/SzucV6mUAs2VZn/AehBwuZMiNEQDaPuTGn22YK5o+aDw== emittery@^0.7.1: version "0.7.2" - resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.7.2.tgz#25595908e13af0f5674ab419396e2fb394cdfa82" + resolved "https://registry.npmjs.org/emittery/-/emittery-0.7.2.tgz#25595908e13af0f5674ab419396e2fb394cdfa82" integrity sha512-A8OG5SR/ij3SsJdWDJdkkSYUjQdCUx6APQXem0SaEePBSRg4eymGYwBkKo1Y6DU+af/Jn2dBQqDBvjnr9Vi8nQ== emoji-regex@^8.0.0: version "8.0.0" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== encoding@^0.1.12: version "0.1.13" - resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9" + resolved "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9" integrity sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A== dependencies: iconv-lite "^0.6.2" end-of-stream@^1.1.0, end-of-stream@^1.4.1: version "1.4.4" - resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" + resolved "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== dependencies: once "^1.4.0" enquirer@^2.3.5: version "2.3.6" - resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d" + resolved "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d" integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg== dependencies: ansi-colors "^4.1.1" entities@~2.0: version "2.0.3" - resolved "https://registry.yarnpkg.com/entities/-/entities-2.0.3.tgz#5c487e5742ab93c15abb5da22759b8590ec03b7f" + resolved "https://registry.npmjs.org/entities/-/entities-2.0.3.tgz#5c487e5742ab93c15abb5da22759b8590ec03b7f" integrity sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ== entities@~2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/entities/-/entities-2.1.0.tgz#992d3129cf7df6870b96c57858c249a120f8b8b5" + resolved "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz#992d3129cf7df6870b96c57858c249a120f8b8b5" integrity sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w== env-paths@^2.2.0: version "2.2.1" - resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2" + resolved "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2" integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A== envinfo@^7.7.4: version "7.8.1" - resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.8.1.tgz#06377e3e5f4d379fea7ac592d5ad8927e0c4d475" + resolved "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz#06377e3e5f4d379fea7ac592d5ad8927e0c4d475" integrity sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw== err-code@^2.0.2: version "2.0.3" - resolved "https://registry.yarnpkg.com/err-code/-/err-code-2.0.3.tgz#23c2f3b756ffdfc608d30e27c9a941024807e7f9" + resolved "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz#23c2f3b756ffdfc608d30e27c9a941024807e7f9" integrity sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA== error-ex@^1.3.1: version "1.3.2" - resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + resolved "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== dependencies: is-arrayish "^0.2.1" -es-abstract@^1.18.0-next.1, es-abstract@^1.18.0-next.2, es-abstract@^1.18.2: - version "1.18.3" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.18.3.tgz#25c4c3380a27aa203c44b2b685bba94da31b63e0" - integrity sha512-nQIr12dxV7SSxE6r6f1l3DtAeEYdsGpps13dR0TwJg1S8gyp4ZPgy3FZcHBgbiQqnoqSTb+oC+kO4UQ0C/J8vw== +es-abstract@^1.18.5, es-abstract@^1.19.0, es-abstract@^1.19.1: + version "1.19.1" + resolved "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz#d4885796876916959de78edaa0df456627115ec3" + integrity sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w== dependencies: call-bind "^1.0.2" es-to-primitive "^1.2.1" function-bind "^1.1.1" get-intrinsic "^1.1.1" + get-symbol-description "^1.0.0" has "^1.0.3" has-symbols "^1.0.2" - is-callable "^1.2.3" + internal-slot "^1.0.3" + is-callable "^1.2.4" is-negative-zero "^2.0.1" - is-regex "^1.1.3" - is-string "^1.0.6" - object-inspect "^1.10.3" + is-regex "^1.1.4" + is-shared-array-buffer "^1.0.1" + is-string "^1.0.7" + is-weakref "^1.0.1" + object-inspect "^1.11.0" object-keys "^1.1.1" object.assign "^4.1.2" string.prototype.trimend "^1.0.4" @@ -3786,7 +3713,7 @@ es-abstract@^1.18.0-next.1, es-abstract@^1.18.0-next.2, es-abstract@^1.18.2: es-get-iterator@^1.1.1: version "1.1.2" - resolved "https://registry.yarnpkg.com/es-get-iterator/-/es-get-iterator-1.1.2.tgz#9234c54aba713486d7ebde0220864af5e2b283f7" + resolved "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.2.tgz#9234c54aba713486d7ebde0220864af5e2b283f7" integrity sha512-+DTO8GYwbMCwbywjimwZMHp8AuYXOS2JZFWoi2AlPOS3ebnII9w/NLpNZtA7A0YLaVDw+O7KFCeoIV7OPvM7hQ== dependencies: call-bind "^1.0.2" @@ -3800,7 +3727,7 @@ es-get-iterator@^1.1.1: es-to-primitive@^1.2.1: version "1.2.1" - resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" + resolved "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== dependencies: is-callable "^1.1.4" @@ -3809,42 +3736,139 @@ es-to-primitive@^1.2.1: es5-ext@0.8.x: version "0.8.2" - resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.8.2.tgz#aba8d9e1943a895ac96837a62a39b3f55ecd94ab" + resolved "https://registry.npmjs.org/es5-ext/-/es5-ext-0.8.2.tgz#aba8d9e1943a895ac96837a62a39b3f55ecd94ab" integrity sha1-q6jZ4ZQ6iVrJaDemKjmz9V7NlKs= es6-error@^4.0.1: version "4.1.1" - resolved "https://registry.yarnpkg.com/es6-error/-/es6-error-4.1.1.tgz#9e3af407459deed47e9a91f9b885a84eb05c561d" + resolved "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz#9e3af407459deed47e9a91f9b885a84eb05c561d" integrity sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg== -esbuild@^0.12.15: - version "0.12.15" - resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.12.15.tgz#9d99cf39aeb2188265c5983e983e236829f08af0" - integrity sha512-72V4JNd2+48eOVCXx49xoSWHgC3/cCy96e7mbXKY+WOWghN00cCmlGnwVLRhRHorvv0dgCyuMYBZlM2xDM5OQw== +esbuild-android-arm64@0.13.5: + version "0.13.5" + resolved "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.13.5.tgz#a299a18fd8a016ae19fd948fc659b3f65d1b992f" + integrity sha512-xaNH58b9XRAWT5q0rwA2GNTgJynb51JhdotlNKdLmSCyKXPVlF87yqNLNdmlX/zndzRDrZdtpCWSALdn/J63Ug== + +esbuild-darwin-64@0.13.5: + version "0.13.5" + resolved "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.13.5.tgz#01359f2c6921bd2704d0a895f5603ab33f2eeb1b" + integrity sha512-ClGQeUObXIxEpZviGzjTinDikXy9XodojP9jLKwqLCBpZ9wdV3MW7JOmw60fgXgnbNRvkZCqM6uEi+ur8p80Ow== + +esbuild-darwin-arm64@0.13.5: + version "0.13.5" + resolved "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.13.5.tgz#1dbe362ebc9afcdab4f9af9bb320dacd73e2aedc" + integrity sha512-qro6M/qzs1dBPh14Ca+5moIkLo2KE3ll3dOpiN7aAususkM1HmqQptCEchi0XwX+6nfqWI96YvVqPJ3DfUUK5A== + +esbuild-freebsd-64@0.13.5: + version "0.13.5" + resolved "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.13.5.tgz#fecee59fa491a3f544c731b0c0319bd5a9da7d50" + integrity sha512-vklf7L7fghREEvS1sjAFcxcw/Qqt+Z+L0ySN+pEeb7rA8nPLfRBSFdXAru8UNuHsMWns6CrcZ5eDOKTerZZ5ng== + +esbuild-freebsd-arm64@0.13.5: + version "0.13.5" + resolved "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.13.5.tgz#4e98c0e33ed19a63ffd4db87314986b9d93850b5" + integrity sha512-kJoouhbZt4QvjiPak7/Lz57Azok0CgFnNtixiOsqEQXTabIaKmMmnq4qgjD6EBFeU/hvSXDrPe6U8dWhBZOrWQ== + +esbuild-linux-32@0.13.5: + version "0.13.5" + resolved "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.13.5.tgz#00083740af7f1416951c634a461e3d01ed812cd0" + integrity sha512-/QufG6tTGKAf42pIYkOVZzKBPxF01xH1kCPyOFJZukZBV/Tk3TeOZfhJIAf7pxl4jhfa+c4Jcdp7CvIAjXrmJg== + +esbuild-linux-64@0.13.5: + version "0.13.5" + resolved "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.13.5.tgz#49bd1648fd2070594fe3aad31925108ee2916216" + integrity sha512-NmNFMXEthuFJTFaD4cLhAHCxg+y3uXzo7nqH/WNNSZ8PPY11jbeOvMbdArYlbo2Wy1N/mTHXMcK1synSJj+4Iw== + +esbuild-linux-arm64@0.13.5: + version "0.13.5" + resolved "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.13.5.tgz#78ef0f20d2b175403552075cc6d6af80f55a22d8" + integrity sha512-dOS5EZsZj8Lw0TgEj3zy1/slTBbfBw4v7uHEqZXP34dUaRq2oltNaUYIj735CtgB7I5/MXrXEUYkXLqcVfzJQQ== + +esbuild-linux-arm@0.13.5: + version "0.13.5" + resolved "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.13.5.tgz#27c4e92a6597376a8c3fe8c79177d72ba77f8500" + integrity sha512-69nQmbKLBRaAxf88diyaOyarrI7yIdBkZ8bmVzQ7XVWneY+nYIcGtugTSOs5znNGfPqGOElAjh1lX+0sGYHNpA== + +esbuild-linux-mips64le@0.13.5: + version "0.13.5" + resolved "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.13.5.tgz#4061cbef41f96e4a176bebf7e7b2d6d397e05e86" + integrity sha512-dmKA8ZI/nHwpxIQW/L5crk7Ac4wJJ2Kquvdo1CdXPW1UljMyKUDuHc4K7D1Iws5igqJmNO6U5vdRUKrdnIov6Q== + +esbuild-linux-ppc64le@0.13.5: + version "0.13.5" + resolved "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.13.5.tgz#290a5caca6751b8c80c5d075cafe857102263118" + integrity sha512-HkVGKkPL3XOhJqNOJ752Q1li5zeidrJHv+XWX6qCnCipNsVuGqaAGfxeWbL/+A/giolMlP7wvAuiKgoe+a5UAw== + +esbuild-openbsd-64@0.13.5: + version "0.13.5" + resolved "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.13.5.tgz#223eb2730a6fede7930a2b44b0b1d5b067a3cef5" + integrity sha512-BuOZzmdsdreSs0qDgbuiEhSbUDDW2Wyp4VtpNGBmaLwPMHftdprOJXLkeFud3HlnRB2n9qdiTVKg1B8YqMogSw== + +esbuild-sunos-64@0.13.5: + version "0.13.5" + resolved "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.13.5.tgz#6f121ac285c298f09467748607cc0496ebbfd23e" + integrity sha512-YJNB6Og1QYAPikvYDbqvk5xCqr6WL2i5cRWPGGgWOEItQPnq6gFsWogS3DiYM8TQKe50KRiD3Lwu7eNYsdPO4w== + +esbuild-windows-32@0.13.5: + version "0.13.5" + resolved "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.13.5.tgz#0da6d240152f76f3dd764c0bb0391d894acd403f" + integrity sha512-CigOlBSKsZ61IS+FyhD3luqCpl7LN9ntDaBZXumls/0IZ/8BJ5txqw4a6pv4LtnfIgt0ixGHSH7kAUmApw/HAw== + +esbuild-windows-64@0.13.5: + version "0.13.5" + resolved "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.13.5.tgz#330266a2c95b26c2f949e9de9b0c366924fec53f" + integrity sha512-pg2BZXLpcPcrIcmToGapLRExzj6sm0VmQlqlmnMOtIJh0YQV9c0CRbhfIT0gYvJqCz5JEGiRvYpArRlxWADN3Q== + +esbuild-windows-arm64@0.13.5: + version "0.13.5" + resolved "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.13.5.tgz#e0501e82b88f4165cce7cd017db83428f459f775" + integrity sha512-KKRDmUOIE4oCvJp0I4p4QyazK2X79spF29vsZr2U8qHhmxbTLSQWvYmb2WlF5Clb1URRsX0L013rhwHx1SEu0w== + +esbuild@^0.13.5: + version "0.13.5" + resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.13.5.tgz#f9add2c2c899a9023dd7f7b64c452320f008aa79" + integrity sha512-Q9/f1njsZaO+Qqe3dqAdtu4zGHNZIbcEtdg44/NooyPhqCerns4FeC1UPYeB4pKD08iDuWcmyINFJTqpdN+pqg== + optionalDependencies: + esbuild-android-arm64 "0.13.5" + esbuild-darwin-64 "0.13.5" + esbuild-darwin-arm64 "0.13.5" + esbuild-freebsd-64 "0.13.5" + esbuild-freebsd-arm64 "0.13.5" + esbuild-linux-32 "0.13.5" + esbuild-linux-64 "0.13.5" + esbuild-linux-arm "0.13.5" + esbuild-linux-arm64 "0.13.5" + esbuild-linux-mips64le "0.13.5" + esbuild-linux-ppc64le "0.13.5" + esbuild-openbsd-64 "0.13.5" + esbuild-sunos-64 "0.13.5" + esbuild-windows-32 "0.13.5" + esbuild-windows-64 "0.13.5" + esbuild-windows-arm64 "0.13.5" escalade@^3.1.1: version "3.1.1" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== escape-string-regexp@^1.0.5: version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= escape-string-regexp@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== escape-string-regexp@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== escodegen@^1.8.1: version "1.14.3" - resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.14.3.tgz#4e7b81fba61581dc97582ed78cab7f0e8d63f503" + resolved "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz#4e7b81fba61581dc97582ed78cab7f0e8d63f503" integrity sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw== dependencies: esprima "^4.0.1" @@ -3856,7 +3880,7 @@ escodegen@^1.8.1: escodegen@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-2.0.0.tgz#5e32b12833e8aa8fa35e1bf0befa89380484c7dd" + resolved "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz#5e32b12833e8aa8fa35e1bf0befa89380484c7dd" integrity sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw== dependencies: esprima "^4.0.1" @@ -3866,102 +3890,136 @@ escodegen@^2.0.0: optionalDependencies: source-map "~0.6.1" -eslint-import-resolver-node@^0.3.4: - version "0.3.4" - resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz#85ffa81942c25012d8231096ddf679c03042c717" - integrity sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA== +eslint-config-standard@^14.1.1: + version "14.1.1" + resolved "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-14.1.1.tgz#830a8e44e7aef7de67464979ad06b406026c56ea" + integrity sha512-Z9B+VR+JIXRxz21udPTL9HpFMyoMUEeX1G251EQ6e05WD9aPVtVBn09XUmZ259wCMlCDmYDSZG62Hhm+ZTJcUg== + +eslint-import-resolver-node@^0.3.6: + version "0.3.6" + resolved "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz#4048b958395da89668252001dbd9eca6b83bacbd" + integrity sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw== dependencies: - debug "^2.6.9" - resolve "^1.13.1" + debug "^3.2.7" + resolve "^1.20.0" -eslint-import-resolver-typescript@^2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-2.4.0.tgz#ec1e7063ebe807f0362a7320543aaed6fe1100e1" - integrity sha512-useJKURidCcldRLCNKWemr1fFQL1SzB3G4a0li6lFGvlc5xGe1hY343bvG07cbpCzPuM/lK19FIJB3XGFSkplA== +eslint-import-resolver-typescript@^2.5.0: + version "2.5.0" + resolved "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-2.5.0.tgz#07661966b272d14ba97f597b51e1a588f9722f0a" + integrity sha512-qZ6e5CFr+I7K4VVhQu3M/9xGv9/YmwsEXrsm3nimw8vWaVHRDrQRp26BgCypTxBp3vUp4o5aVEJRiy0F2DFddQ== dependencies: - debug "^4.1.1" - glob "^7.1.6" + debug "^4.3.1" + glob "^7.1.7" is-glob "^4.0.1" - resolve "^1.17.0" + resolve "^1.20.0" tsconfig-paths "^3.9.0" -eslint-module-utils@^2.6.1: - version "2.6.1" - resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.6.1.tgz#b51be1e473dd0de1c5ea638e22429c2490ea8233" - integrity sha512-ZXI9B8cxAJIH4nfkhTwcRTEAnrVfobYqwjWy/QMCZ8rHkZHFjf9yO4BzpiF9kCSfNlMG54eKigISHpX0+AaT4A== +eslint-module-utils@^2.7.0: + version "2.7.0" + resolved "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.0.tgz#9e97c12688113401259b39d960e6a1f09f966435" + integrity sha512-hqSE88MmHl3ru9SYvDyGrlo0JwROlf9fiEMplEV7j/EAuq9iSlIlyCFbBT6pdULQBSnBYtYKiMLps+hKkyP7Gg== dependencies: debug "^3.2.7" + find-up "^2.1.0" pkg-dir "^2.0.0" -eslint-plugin-import@^2.23.4: - version "2.23.4" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.23.4.tgz#8dceb1ed6b73e46e50ec9a5bb2411b645e7d3d97" - integrity sha512-6/wP8zZRsnQFiR3iaPFgh5ImVRM1WN5NUWfTIRqwOdeiGJlBcSk82o1FEVq8yXmy4lkIzTo7YhHCIxlU/2HyEQ== +eslint-plugin-es@^3.0.0: + version "3.0.1" + resolved "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz#75a7cdfdccddc0589934aeeb384175f221c57893" + integrity sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ== + dependencies: + eslint-utils "^2.0.0" + regexpp "^3.0.0" + +eslint-plugin-import@^2.25.2: + version "2.25.2" + resolved "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.25.2.tgz#b3b9160efddb702fc1636659e71ba1d10adbe9e9" + integrity sha512-qCwQr9TYfoBHOFcVGKY9C9unq05uOxxdklmBXLVvcwo68y5Hta6/GzCZEMx2zQiu0woKNEER0LE7ZgaOfBU14g== dependencies: - array-includes "^3.1.3" - array.prototype.flat "^1.2.4" + array-includes "^3.1.4" + array.prototype.flat "^1.2.5" debug "^2.6.9" doctrine "^2.1.0" - eslint-import-resolver-node "^0.3.4" - eslint-module-utils "^2.6.1" - find-up "^2.0.0" + eslint-import-resolver-node "^0.3.6" + eslint-module-utils "^2.7.0" has "^1.0.3" - is-core-module "^2.4.0" + is-core-module "^2.7.0" + is-glob "^4.0.3" minimatch "^3.0.4" - object.values "^1.1.3" - pkg-up "^2.0.0" - read-pkg-up "^3.0.0" + object.values "^1.1.5" resolve "^1.20.0" - tsconfig-paths "^3.9.0" + tsconfig-paths "^3.11.0" -eslint-plugin-jest@^24.3.7: - version "24.3.7" - resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-24.3.7.tgz#a4deaa9e88182b92533a9c25cc4f3c369d7f33eb" - integrity sha512-pXED2NA4q2M/5mxlN6GyuUXAFJndT0uosOkQCHaUED9pqgBPd89ZzpcZEU6c5HtZNahC00M36FkwLdDHMDqaHw== +eslint-plugin-jest@^24.7.0: + version "24.7.0" + resolved "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-24.7.0.tgz#206ac0833841e59e375170b15f8d0955219c4889" + integrity sha512-wUxdF2bAZiYSKBclsUMrYHH6WxiBreNjyDxbRv345TIvPeoCEgPNEn3Sa+ZrSqsf1Dl9SqqSREXMHExlMMu1DA== dependencies: "@typescript-eslint/experimental-utils" "^4.0.1" +eslint-plugin-node@^11.1.0: + version "11.1.0" + resolved "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz#c95544416ee4ada26740a30474eefc5402dc671d" + integrity sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g== + dependencies: + eslint-plugin-es "^3.0.0" + eslint-utils "^2.0.0" + ignore "^5.1.1" + minimatch "^3.0.4" + resolve "^1.10.1" + semver "^6.1.0" + +eslint-plugin-promise@^4.3.1: + version "4.3.1" + resolved "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-4.3.1.tgz#61485df2a359e03149fdafc0a68b0e030ad2ac45" + integrity sha512-bY2sGqyptzFBDLh/GMbAxfdJC+b0f23ME63FOE4+Jao0oZ3E1LEwFtWJX/1pGMJLiTtrSSern2CRM/g+dfc0eQ== + eslint-plugin-rulesdir@^0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-rulesdir/-/eslint-plugin-rulesdir-0.2.0.tgz#0d729e3f11bcb1a18d9b724a29a6d1a082ac2d62" + resolved "https://registry.npmjs.org/eslint-plugin-rulesdir/-/eslint-plugin-rulesdir-0.2.0.tgz#0d729e3f11bcb1a18d9b724a29a6d1a082ac2d62" integrity sha512-PPQPCsPkzF3upl1862swPA1bmDAAHKHmJJ4JTHJ11JCVCU4sycB0K5LLA/Rwr6r4VbnpScvUvHV4hqfdjvFmhQ== +eslint-plugin-standard@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/eslint-plugin-standard/-/eslint-plugin-standard-4.1.0.tgz#0c3bf3a67e853f8bbbc580fb4945fbf16f41b7c5" + integrity sha512-ZL7+QRixjTR6/528YNGyDotyffm5OQst/sGxKDwGb9Uqs4In5Egi4+jbobhqJoyoCM6/7v/1A5fhQ7ScMtDjaQ== + eslint-scope@^5.1.1: version "5.1.1" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" + resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== dependencies: esrecurse "^4.3.0" estraverse "^4.1.1" -eslint-utils@^2.1.0: +eslint-utils@^2.0.0, eslint-utils@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27" + resolved "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27" integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg== dependencies: eslint-visitor-keys "^1.1.0" eslint-utils@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" + resolved "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== dependencies: eslint-visitor-keys "^2.0.0" eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0: version "1.3.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" + resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== eslint-visitor-keys@^2.0.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" + resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== -eslint@^7.31.0: - version "7.31.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.31.0.tgz#f972b539424bf2604907a970860732c5d99d3aca" - integrity sha512-vafgJpSh2ia8tnTkNUkwxGmnumgckLh5aAbLa1xRmIn9+owi8qBNGKL+B881kNKNTy7FFqTEkpNkUvmw0n6PkA== +eslint@^7.32.0: + version "7.32.0" + resolved "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz#c6d328a14be3fb08c8d1d21e12c02fdb7a2a812d" + integrity sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA== dependencies: "@babel/code-frame" "7.12.11" "@eslint/eslintrc" "^0.4.3" @@ -4004,14 +4062,9 @@ eslint@^7.31.0: text-table "^0.2.0" v8-compile-cache "^2.0.3" -esm@^3.2.5: - version "3.2.25" - resolved "https://registry.yarnpkg.com/esm/-/esm-3.2.25.tgz#342c18c29d56157688ba5ce31f8431fbb795cc10" - integrity sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA== - espree@^7.3.0, espree@^7.3.1: version "7.3.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-7.3.1.tgz#f2df330b752c6f55019f8bd89b7660039c1bbbb6" + resolved "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz#f2df330b752c6f55019f8bd89b7660039c1bbbb6" integrity sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g== dependencies: acorn "^7.4.0" @@ -4020,61 +4073,56 @@ espree@^7.3.0, espree@^7.3.1: esprima@^4.0.0, esprima@^4.0.1: version "4.0.1" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== esquery@^1.4.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" + resolved "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w== dependencies: estraverse "^5.1.0" esrecurse@^4.3.0: version "4.3.0" - resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + resolved "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== dependencies: estraverse "^5.2.0" estraverse@^4.1.1, estraverse@^4.2.0: version "4.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + resolved "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== estraverse@^5.1.0, estraverse@^5.2.0: version "5.2.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880" + resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880" integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ== esutils@^2.0.2: version "2.0.3" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== eventemitter3@^4.0.4: version "4.0.7" - resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" + resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== -events-to-array@^1.0.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/events-to-array/-/events-to-array-1.1.2.tgz#2d41f563e1fe400ed4962fe1a4d5c6a7539df7f6" - integrity sha1-LUH1Y+H+QA7Uli/hpNXGp1Od9/Y= - events@1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" + resolved "https://registry.npmjs.org/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" integrity sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ= exec-sh@^0.3.2: version "0.3.6" - resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.3.6.tgz#ff264f9e325519a60cb5e273692943483cca63bc" + resolved "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.6.tgz#ff264f9e325519a60cb5e273692943483cca63bc" integrity sha512-nQn+hI3yp+oD0huYhKwvYI32+JFeq+XkNcD1GAo3Y/MjxsfVGmrrzrnzjWiNY6f+pUCP440fThsFh5gZrRAU/w== execa@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" + resolved "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA== dependencies: cross-spawn "^6.0.0" @@ -4087,7 +4135,7 @@ execa@^1.0.0: execa@^4.0.0: version "4.1.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-4.1.0.tgz#4e5491ad1572f2f17a77d388c6c857135b22847a" + resolved "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz#4e5491ad1572f2f17a77d388c6c857135b22847a" integrity sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA== dependencies: cross-spawn "^7.0.0" @@ -4102,7 +4150,7 @@ execa@^4.0.0: execa@^5.0.0: version "5.1.1" - resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" + resolved "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== dependencies: cross-spawn "^7.0.3" @@ -4117,17 +4165,17 @@ execa@^5.0.0: exit-on-epipe@~1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz#0bdd92e87d5285d267daa8171d0eb06159689692" + resolved "https://registry.npmjs.org/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz#0bdd92e87d5285d267daa8171d0eb06159689692" integrity sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw== exit@^0.1.2: version "0.1.2" - resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" + resolved "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" integrity sha1-BjJjj42HfMghB9MKD/8aF8uhzQw= expand-brackets@^2.1.4: version "2.1.4" - resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" + resolved "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= dependencies: debug "^2.3.3" @@ -4140,7 +4188,7 @@ expand-brackets@^2.1.4: expect@^26.6.2: version "26.6.2" - resolved "https://registry.yarnpkg.com/expect/-/expect-26.6.2.tgz#c6b996bf26bf3fe18b67b2d0f51fc981ba934417" + resolved "https://registry.npmjs.org/expect/-/expect-26.6.2.tgz#c6b996bf26bf3fe18b67b2d0f51fc981ba934417" integrity sha512-9/hlOBkQl2l/PLHJx6JjoDF6xPKcJEsUlWKb23rKE7KzeDqUZKXKNMW27KIue5JMdBV9HgmoJPcc8HtO85t9IA== dependencies: "@jest/types" "^26.6.2" @@ -4152,14 +4200,14 @@ expect@^26.6.2: extend-shallow@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" + resolved "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= dependencies: is-extendable "^0.1.0" extend-shallow@^3.0.0, extend-shallow@^3.0.2: version "3.0.2" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" + resolved "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= dependencies: assign-symbols "^1.0.0" @@ -4167,12 +4215,12 @@ extend-shallow@^3.0.0, extend-shallow@^3.0.2: extend@~3.0.2: version "3.0.2" - resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" + resolved "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== external-editor@^3.0.3: version "3.1.0" - resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" + resolved "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== dependencies: chardet "^0.7.0" @@ -4181,7 +4229,7 @@ external-editor@^3.0.3: extglob@^2.0.4: version "2.0.4" - resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" + resolved "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== dependencies: array-unique "^0.3.2" @@ -4195,34 +4243,34 @@ extglob@^2.0.4: extsprintf@1.3.0: version "1.3.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" + resolved "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= extsprintf@^1.2.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" + resolved "https://registry.npmjs.org/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= -fast-check@^2.17.0: - version "2.17.0" - resolved "https://registry.yarnpkg.com/fast-check/-/fast-check-2.17.0.tgz#9b9637684332be386219a5f73a4799874da7461c" - integrity sha512-fNNKkxNEJP+27QMcEzF6nbpOYoSZIS0p+TyB+xh/jXqRBxRhLkiZSREly4ruyV8uJi7nwH1YWAhi7OOK5TubRw== +fast-check@^2.18.0: + version "2.18.0" + resolved "https://registry.npmjs.org/fast-check/-/fast-check-2.18.0.tgz#0337d82e7d7cb4eed5806c42b9e61ed0fb6592b2" + integrity sha512-7KKUw0wtAJOVrJ1DgmFILd9EmeqMLGtfe5HoEtkYZfYIxohm6Zy7zPq1Zl8t6tPL8A3e86YZrheyGg2m5j8cLA== dependencies: pure-rand "^5.0.0" fast-deep-equal@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" + resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk= fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: version "3.1.3" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== fast-glob@^3.1.1: version "3.2.7" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.7.tgz#fd6cb7a2d7e9aa7a7846111e85a196d6b2f766a1" + resolved "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz#fd6cb7a2d7e9aa7a7846111e85a196d6b2f766a1" integrity sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q== dependencies: "@nodelib/fs.stat" "^2.0.2" @@ -4233,62 +4281,62 @@ fast-glob@^3.1.1: fast-json-patch@^2.2.1: version "2.2.1" - resolved "https://registry.yarnpkg.com/fast-json-patch/-/fast-json-patch-2.2.1.tgz#18150d36c9ab65c7209e7d4eb113f4f8eaabe6d9" + resolved "https://registry.npmjs.org/fast-json-patch/-/fast-json-patch-2.2.1.tgz#18150d36c9ab65c7209e7d4eb113f4f8eaabe6d9" integrity sha512-4j5uBaTnsYAV5ebkidvxiLUYOwjQ+JSFljeqfTxCrH9bDmlCQaOJFS84oDJ2rAXZq2yskmk3ORfoP9DCwqFNig== dependencies: fast-deep-equal "^2.0.1" -fast-json-patch@^3.0.0-1: - version "3.0.0-1" - resolved "https://registry.yarnpkg.com/fast-json-patch/-/fast-json-patch-3.0.0-1.tgz#4c68f2e7acfbab6d29d1719c44be51899c93dabb" - integrity sha512-6pdFb07cknxvPzCeLsFHStEy+MysPJPgZQ9LbQ/2O67unQF93SNqfdSqnPPl71YMHX+AD8gbl7iuoGFzHEdDuw== +fast-json-patch@^3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/fast-json-patch/-/fast-json-patch-3.1.0.tgz#ec8cd9b9c4c564250ec8b9140ef7a55f70acaee6" + integrity sha512-IhpytlsVTRndz0hU5t0/MGzS/etxLlfrpG5V5M9mVbuj9TrJLWaMfsox9REM5rkuGX0T+5qjpe8XA1o0gZ42nA== fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6: version "2.0.6" - resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= fastq@^1.6.0: - version "1.11.1" - resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.11.1.tgz#5d8175aae17db61947f8b162cfc7f63264d22807" - integrity sha512-HOnr8Mc60eNYl1gzwp6r5RoUyAn5/glBolUzP/Ez6IFVPMPirxn/9phgL6zhOtaTy7ISwPvQ+wT+hfcRZh/bzw== + version "1.13.0" + resolved "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c" + integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw== dependencies: reusify "^1.0.4" fb-watchman@^2.0.0: version "2.0.1" - resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.1.tgz#fc84fb39d2709cf3ff6d743706157bb5708a8a85" + resolved "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz#fc84fb39d2709cf3ff6d743706157bb5708a8a85" integrity sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg== dependencies: bser "2.1.1" figures@^3.0.0, figures@^3.1.0: version "3.2.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" + resolved "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== dependencies: escape-string-regexp "^1.0.5" file-entry-cache@^6.0.1: version "6.0.1" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" + resolved "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== dependencies: flat-cache "^3.0.4" file-uri-to-path@2: version "2.0.0" - resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-2.0.0.tgz#7b415aeba227d575851e0a5b0c640d7656403fba" + resolved "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-2.0.0.tgz#7b415aeba227d575851e0a5b0c640d7656403fba" integrity sha512-hjPFI8oE/2iQPVe4gbrJ73Pp+Xfub2+WI2LlXDbsaJBwT5wuMh35WNWVYYTpnz895shtwfyutMFLFywpQAFdLg== fill-keys@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/fill-keys/-/fill-keys-1.0.2.tgz#9a8fa36f4e8ad634e3bf6b4f3c8882551452eb20" + resolved "https://registry.npmjs.org/fill-keys/-/fill-keys-1.0.2.tgz#9a8fa36f4e8ad634e3bf6b4f3c8882551452eb20" integrity sha1-mo+jb06K1jTjv2tPPIiCVRRS6yA= dependencies: is-object "~1.0.1" @@ -4296,7 +4344,7 @@ fill-keys@^1.0.2: fill-range@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" + resolved "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= dependencies: extend-shallow "^2.0.1" @@ -4306,29 +4354,20 @@ fill-range@^4.0.0: fill-range@^7.0.1: version "7.0.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + resolved "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== dependencies: to-regex-range "^5.0.1" filter-obj@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/filter-obj/-/filter-obj-1.1.0.tgz#9b311112bc6c6127a16e016c6c5d7f19e0805c5b" + resolved "https://registry.npmjs.org/filter-obj/-/filter-obj-1.1.0.tgz#9b311112bc6c6127a16e016c6c5d7f19e0805c5b" integrity sha1-mzERErxsYSehbgFsbF1/GeCAXFs= -find-cache-dir@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-2.1.0.tgz#8d0f94cd13fe43c6c7c261a0d86115ca918c05f7" - integrity sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ== - dependencies: - commondir "^1.0.1" - make-dir "^2.0.0" - pkg-dir "^3.0.0" - find-cache-dir@^3.2.0: - version "3.3.1" - resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.3.1.tgz#89b33fad4a4670daa94f855f7fbe31d6d84fe880" - integrity sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ== + version "3.3.2" + resolved "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz#b30c5b6eff0730731aea9bbd9dbecbd80256d64b" + integrity sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig== dependencies: commondir "^1.0.1" make-dir "^3.0.2" @@ -4336,21 +4375,21 @@ find-cache-dir@^3.2.0: find-up@^2.0.0, find-up@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" + resolved "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= dependencies: locate-path "^2.0.0" find-up@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" + resolved "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== dependencies: locate-path "^3.0.0" find-up@^4.0.0, find-up@^4.1.0: version "4.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + resolved "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== dependencies: locate-path "^5.0.0" @@ -4358,7 +4397,7 @@ find-up@^4.0.0, find-up@^4.1.0: find-up@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + resolved "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== dependencies: locate-path "^6.0.0" @@ -4366,14 +4405,14 @@ find-up@^5.0.0: find-yarn-workspace-root@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/find-yarn-workspace-root/-/find-yarn-workspace-root-2.0.0.tgz#f47fb8d239c900eb78179aa81b66673eac88f7bd" + resolved "https://registry.npmjs.org/find-yarn-workspace-root/-/find-yarn-workspace-root-2.0.0.tgz#f47fb8d239c900eb78179aa81b66673eac88f7bd" integrity sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ== dependencies: micromatch "^4.0.2" flat-cache@^3.0.4: version "3.0.4" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" + resolved "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== dependencies: flatted "^3.1.0" @@ -4381,40 +4420,32 @@ flat-cache@^3.0.4: flatted@^2.0.1: version "2.0.2" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138" + resolved "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138" integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA== flatted@^3.1.0: - version "3.2.1" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.1.tgz#bbef080d95fca6709362c73044a1634f7c6e7d05" - integrity sha512-OMQjaErSFHmHqZe+PSidH5n8j3O0F2DdnVh8JB4j4eUQ2k6KvB0qGfrKIhapvez5JerBbmWkaLYUYWISaESoXg== + version "3.2.2" + resolved "https://registry.npmjs.org/flatted/-/flatted-3.2.2.tgz#64bfed5cb68fe3ca78b3eb214ad97b63bedce561" + integrity sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA== follow-redirects@^1.11.0, follow-redirects@^1.14.0: - version "1.14.3" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.3.tgz#6ada78118d8d24caee595595accdc0ac6abd022e" - integrity sha512-3MkHxknWMUtb23apkgz/83fDoe+y+qr0TdgacGIA7bew+QLBo3vdgEN2xEsuXNivpFy4CyDhBBZnNZOtalmenw== + version "1.14.4" + resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.4.tgz#838fdf48a8bbdd79e52ee51fb1c94e3ed98b9379" + integrity sha512-zwGkiSXC1MUJG/qmeIFH2HBJx9u0V46QGUe3YR1fXG8bXQxq7fLj0RjLZQ5nubr9qNJUZrH+xUcwXEoXNpfS+g== for-in@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + resolved "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= foreach@^2.0.5: version "2.0.5" - resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" + resolved "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" integrity sha1-C+4AUBiusmDQo6865ljdATbsG5k= -foreground-child@^1.3.3, foreground-child@^1.5.6: - version "1.5.6" - resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-1.5.6.tgz#4fd71ad2dfde96789b980a5c0a295937cb2f5ce9" - integrity sha1-T9ca0t/elnibmApcCilZN8svXOk= - dependencies: - cross-spawn "^4" - signal-exit "^3.0.0" - foreground-child@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-2.0.0.tgz#71b32800c9f15aa8f2f83f4a6bd9bff35d861a53" + resolved "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz#71b32800c9f15aa8f2f83f4a6bd9bff35d861a53" integrity sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA== dependencies: cross-spawn "^7.0.0" @@ -4422,12 +4453,12 @@ foreground-child@^2.0.0: forever-agent@~0.6.1: version "0.6.1" - resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + resolved "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= form-data@^3.0.0: version "3.0.1" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f" + resolved "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f" integrity sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg== dependencies: asynckit "^0.4.0" @@ -4436,7 +4467,7 @@ form-data@^3.0.0: form-data@~2.3.2: version "2.3.3" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" + resolved "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== dependencies: asynckit "^0.4.0" @@ -4445,36 +4476,31 @@ form-data@~2.3.2: fragment-cache@^0.2.1: version "0.2.1" - resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" + resolved "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= dependencies: map-cache "^0.2.2" fromentries@^1.2.0: version "1.3.2" - resolved "https://registry.yarnpkg.com/fromentries/-/fromentries-1.3.2.tgz#e4bca6808816bf8f93b52750f1127f5a6fd86e3a" + resolved "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz#e4bca6808816bf8f93b52750f1127f5a6fd86e3a" integrity sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg== fs-access@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/fs-access/-/fs-access-1.0.1.tgz#d6a87f262271cefebec30c553407fb995da8777a" + resolved "https://registry.npmjs.org/fs-access/-/fs-access-1.0.1.tgz#d6a87f262271cefebec30c553407fb995da8777a" integrity sha1-1qh/JiJxzv6+wwxVNAf7mV2od3o= dependencies: null-check "^1.0.0" fs-constants@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" + resolved "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== -fs-exists-cached@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs-exists-cached/-/fs-exists-cached-1.0.0.tgz#cf25554ca050dc49ae6656b41de42258989dcbce" - integrity sha1-zyVVTKBQ3EmuZla0HeQiWJidy84= - fs-extra@^7.0.1: version "7.0.1" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" + resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw== dependencies: graceful-fs "^4.1.2" @@ -4483,7 +4509,7 @@ fs-extra@^7.0.1: fs-extra@^8.1.0: version "8.1.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" + resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== dependencies: graceful-fs "^4.2.0" @@ -4492,7 +4518,7 @@ fs-extra@^8.1.0: fs-extra@^9.1.0: version "9.1.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d" + resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d" integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ== dependencies: at-least-node "^1.0.0" @@ -4502,31 +4528,31 @@ fs-extra@^9.1.0: fs-minipass@^1.2.7: version "1.2.7" - resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.7.tgz#ccff8570841e7fe4265693da88936c55aed7f7c7" + resolved "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz#ccff8570841e7fe4265693da88936c55aed7f7c7" integrity sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA== dependencies: minipass "^2.6.0" fs-minipass@^2.0.0, fs-minipass@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" + resolved "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg== dependencies: minipass "^3.0.0" fs.realpath@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= fsevents@^2.1.2: version "2.3.2" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" + resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== ftp@^0.3.10: version "0.3.10" - resolved "https://registry.yarnpkg.com/ftp/-/ftp-0.3.10.tgz#9197d861ad8142f3e63d5a83bfe4c59f7330885d" + resolved "https://registry.npmjs.org/ftp/-/ftp-0.3.10.tgz#9197d861ad8142f3e63d5a83bfe4c59f7330885d" integrity sha1-kZfYYa2BQvPmPVqDv+TFn3MwiF0= dependencies: readable-stream "1.1.x" @@ -4534,22 +4560,17 @@ ftp@^0.3.10: function-bind@^1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== -function-loop@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/function-loop/-/function-loop-1.0.2.tgz#16b93dd757845eacfeca1a8061a6a65c106e0cb2" - integrity sha512-Iw4MzMfS3udk/rqxTiDDCllhGwlOrsr50zViTOO/W6lS/9y6B1J0BD2VZzrnWUYBJsl3aeqjgR5v7bWWhZSYbA== - functional-red-black-tree@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" + resolved "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= gauge@~2.7.3: version "2.7.4" - resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" + resolved "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c= dependencies: aproba "^1.0.3" @@ -4563,17 +4584,17 @@ gauge@~2.7.3: gensync@^1.0.0-beta.2: version "1.0.0-beta.2" - resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + resolved "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== get-caller-file@^2.0.1, get-caller-file@^2.0.5: version "2.0.5" - resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== get-intrinsic@^1.0.1, get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6" + resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6" integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q== dependencies: function-bind "^1.1.1" @@ -4582,51 +4603,59 @@ get-intrinsic@^1.0.1, get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@ get-package-type@^0.1.0: version "0.1.0" - resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" + resolved "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== get-pkg-repo@^4.0.0: - version "4.1.2" - resolved "https://registry.yarnpkg.com/get-pkg-repo/-/get-pkg-repo-4.1.2.tgz#c4ffd60015cf091be666a0212753fc158f01a4c0" - integrity sha512-/FjamZL9cBYllEbReZkxF2IMh80d8TJoC4e3bmLNif8ibHw95aj0N/tzqK0kZz9eU/3w3dL6lF4fnnX/sDdW3A== + version "4.2.1" + resolved "https://registry.npmjs.org/get-pkg-repo/-/get-pkg-repo-4.2.1.tgz#75973e1c8050c73f48190c52047c4cee3acbf385" + integrity sha512-2+QbHjFRfGB74v/pYWjd5OhU3TDIC2Gv/YKUTk/tCvAz0pkn/Mz6P3uByuBimLOcPvN2jYdScl3xGFSrx0jEcA== dependencies: "@hutson/parse-repository-url" "^3.0.0" hosted-git-info "^4.0.0" - meow "^7.0.0" through2 "^2.0.0" + yargs "^16.2.0" get-port@^5.1.1: version "5.1.1" - resolved "https://registry.yarnpkg.com/get-port/-/get-port-5.1.1.tgz#0469ed07563479de6efb986baf053dcd7d4e3193" + resolved "https://registry.npmjs.org/get-port/-/get-port-5.1.1.tgz#0469ed07563479de6efb986baf053dcd7d4e3193" integrity sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ== get-stdin@~8.0.0: version "8.0.0" - resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-8.0.0.tgz#cbad6a73feb75f6eeb22ba9e01f89aa28aa97a53" + resolved "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz#cbad6a73feb75f6eeb22ba9e01f89aa28aa97a53" integrity sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg== get-stream@^4.0.0: version "4.1.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" + resolved "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== dependencies: pump "^3.0.0" get-stream@^5.0.0: version "5.2.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" + resolved "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA== dependencies: pump "^3.0.0" get-stream@^6.0.0: version "6.0.1" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + resolved "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== +get-symbol-description@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" + integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.1" + get-uri@3: version "3.0.2" - resolved "https://registry.yarnpkg.com/get-uri/-/get-uri-3.0.2.tgz#f0ef1356faabc70e1f9404fa3b66b2ba9bfc725c" + resolved "https://registry.npmjs.org/get-uri/-/get-uri-3.0.2.tgz#f0ef1356faabc70e1f9404fa3b66b2ba9bfc725c" integrity sha512-+5s0SJbGoyiJTZZ2JTpFPLMPSch72KEqGOTvQsBqg0RBWvwhWUSYZFAtz3TPW0GXJuLBJPts1E241iHg+VRfhg== dependencies: "@tootallnate/once" "1" @@ -4638,19 +4667,19 @@ get-uri@3: get-value@^2.0.3, get-value@^2.0.6: version "2.0.6" - resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" + resolved "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= getpass@^0.1.1: version "0.1.7" - resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" + resolved "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= dependencies: assert-plus "^1.0.0" git-raw-commits@^2.0.10, git-raw-commits@^2.0.8: version "2.0.10" - resolved "https://registry.yarnpkg.com/git-raw-commits/-/git-raw-commits-2.0.10.tgz#e2255ed9563b1c9c3ea6bd05806410290297bbc1" + resolved "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-2.0.10.tgz#e2255ed9563b1c9c3ea6bd05806410290297bbc1" integrity sha512-sHhX5lsbG9SOO6yXdlwgEMQ/ljIn7qMpAbJZCGfXX2fq5T8M5SrDnpYk9/4HswTildcIqatsWa91vty6VhWSaQ== dependencies: dargs "^7.0.0" @@ -4661,7 +4690,7 @@ git-raw-commits@^2.0.10, git-raw-commits@^2.0.8: git-remote-origin-url@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/git-remote-origin-url/-/git-remote-origin-url-2.0.0.tgz#5282659dae2107145a11126112ad3216ec5fa65f" + resolved "https://registry.npmjs.org/git-remote-origin-url/-/git-remote-origin-url-2.0.0.tgz#5282659dae2107145a11126112ad3216ec5fa65f" integrity sha1-UoJlna4hBxRaERJhEq0yFuxfpl8= dependencies: gitconfiglocal "^1.0.0" @@ -4669,7 +4698,7 @@ git-remote-origin-url@^2.0.0: git-semver-tags@^4.0.0, git-semver-tags@^4.1.1: version "4.1.1" - resolved "https://registry.yarnpkg.com/git-semver-tags/-/git-semver-tags-4.1.1.tgz#63191bcd809b0ec3e151ba4751c16c444e5b5780" + resolved "https://registry.npmjs.org/git-semver-tags/-/git-semver-tags-4.1.1.tgz#63191bcd809b0ec3e151ba4751c16c444e5b5780" integrity sha512-OWyMt5zBe7xFs8vglMmhM9lRQzCWL3WjHtxNNfJTMngGym7pC1kh8sP6jevfydJ6LP3ZvGxfb6ABYgPUM0mtsA== dependencies: meow "^8.0.0" @@ -4677,29 +4706,29 @@ git-semver-tags@^4.0.0, git-semver-tags@^4.1.1: git-up@^4.0.0: version "4.0.5" - resolved "https://registry.yarnpkg.com/git-up/-/git-up-4.0.5.tgz#e7bb70981a37ea2fb8fe049669800a1f9a01d759" + resolved "https://registry.npmjs.org/git-up/-/git-up-4.0.5.tgz#e7bb70981a37ea2fb8fe049669800a1f9a01d759" integrity sha512-YUvVDg/vX3d0syBsk/CKUTib0srcQME0JyHkL5BaYdwLsiCslPWmDSi8PUMo9pXYjrryMcmsCoCgsTpSCJEQaA== dependencies: is-ssh "^1.3.0" parse-url "^6.0.0" git-url-parse@^11.4.4: - version "11.5.0" - resolved "https://registry.yarnpkg.com/git-url-parse/-/git-url-parse-11.5.0.tgz#acaaf65239cb1536185b19165a24bbc754b3f764" - integrity sha512-TZYSMDeM37r71Lqg1mbnMlOqlHd7BSij9qN7XwTkRqSAYFMihGLGhfHwgqQob3GUhEneKnV4nskN9rbQw2KGxA== + version "11.6.0" + resolved "https://registry.npmjs.org/git-url-parse/-/git-url-parse-11.6.0.tgz#c634b8de7faa66498a2b88932df31702c67df605" + integrity sha512-WWUxvJs5HsyHL6L08wOusa/IXYtMuCAhrMmnTjQPpBU0TTHyDhnOATNH3xNQz7YOQUsqIIPTGr4xiVti1Hsk5g== dependencies: git-up "^4.0.0" gitconfiglocal@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/gitconfiglocal/-/gitconfiglocal-1.0.0.tgz#41d045f3851a5ea88f03f24ca1c6178114464b9b" + resolved "https://registry.npmjs.org/gitconfiglocal/-/gitconfiglocal-1.0.0.tgz#41d045f3851a5ea88f03f24ca1c6178114464b9b" integrity sha1-QdBF84UaXqiPA/JMocYXgRRGS5s= dependencies: ini "^1.3.2" github-api@^3.4.0: version "3.4.0" - resolved "https://registry.yarnpkg.com/github-api/-/github-api-3.4.0.tgz#5da2f56442d4839d324e9faf0ffb2cf30f7650b8" + resolved "https://registry.npmjs.org/github-api/-/github-api-3.4.0.tgz#5da2f56442d4839d324e9faf0ffb2cf30f7650b8" integrity sha512-2yYqYS6Uy4br1nw0D3VrlYWxtGTkUhIZrumBrcBwKdBOzMT8roAe8IvI6kjIOkxqxapKR5GkEsHtz3Du/voOpA== dependencies: axios "^0.21.1" @@ -4709,15 +4738,15 @@ github-api@^3.4.0: glob-parent@^5.1.1, glob-parent@^5.1.2: version "5.1.2" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== dependencies: is-glob "^4.0.1" -glob@^7.0.5, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glob@^7.1.7, glob@~7.1.6: - version "7.1.7" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" - integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== +glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glob@^7.1.7, glob@^7.2.0, glob@~7.2.0: + version "7.2.0" + resolved "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" + integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" @@ -4728,19 +4757,19 @@ glob@^7.0.5, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, gl globals@^11.1.0: version "11.12.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + resolved "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== globals@^13.6.0, globals@^13.9.0: - version "13.10.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.10.0.tgz#60ba56c3ac2ca845cfbf4faeca727ad9dd204676" - integrity sha512-piHC3blgLGFjvOuMmWZX60f+na1lXFDhQXBf1UYp2fXPXqvEUbOhNwi6BsQ0bQishwedgnjkwv1d9zKf+MWw3g== + version "13.11.0" + resolved "https://registry.npmjs.org/globals/-/globals-13.11.0.tgz#40ef678da117fe7bd2e28f1fab24951bd0255be7" + integrity sha512-08/xrJ7wQjK9kkkRoI3OFUBbLx4f+6x3SGwcPvQ0QH6goFDrOU2oyAWrmh3dJezu65buo+HBMzAMQy6rovVC3g== dependencies: type-fest "^0.20.2" globby@^11.0.2, globby@^11.0.3: version "11.0.4" - resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.4.tgz#2cbaff77c2f2a62e71e9b2813a67b97a3a3001a5" + resolved "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz#2cbaff77c2f2a62e71e9b2813a67b97a3a3001a5" integrity sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg== dependencies: array-union "^2.1.0" @@ -4750,19 +4779,19 @@ globby@^11.0.2, globby@^11.0.3: merge2 "^1.3.0" slash "^3.0.0" -graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.2, graceful-fs@^4.2.3, graceful-fs@^4.2.4, graceful-fs@^4.2.6: - version "4.2.6" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.6.tgz#ff040b2b0853b23c3d31027523706f1885d76bee" - integrity sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ== +graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.2, graceful-fs@^4.2.3, graceful-fs@^4.2.4, graceful-fs@^4.2.8: + version "4.2.8" + resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz#e412b8d33f5e006593cbd3cee6df9f2cebbe802a" + integrity sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg== growly@^1.3.0: version "1.3.0" - resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" + resolved "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" integrity sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE= handlebars@^4.7.6: version "4.7.7" - resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.7.tgz#9ce33416aad02dbd6c8fafa8240d5d98004945a1" + resolved "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz#9ce33416aad02dbd6c8fafa8240d5d98004945a1" integrity sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA== dependencies: minimist "^1.2.5" @@ -4774,12 +4803,12 @@ handlebars@^4.7.6: har-schema@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" + resolved "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= har-validator@~5.1.3: version "5.1.5" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.5.tgz#1f0803b9f8cb20c0fa13822df1ecddb36bde1efd" + resolved "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz#1f0803b9f8cb20c0fa13822df1ecddb36bde1efd" integrity sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w== dependencies: ajv "^6.12.3" @@ -4787,37 +4816,44 @@ har-validator@~5.1.3: hard-rejection@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/hard-rejection/-/hard-rejection-2.1.0.tgz#1c6eda5c1685c63942766d79bb40ae773cecd883" + resolved "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz#1c6eda5c1685c63942766d79bb40ae773cecd883" integrity sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA== has-bigints@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.1.tgz#64fe6acb020673e3b78db035a5af69aa9d07b113" + resolved "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz#64fe6acb020673e3b78db035a5af69aa9d07b113" integrity sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA== has-flag@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= has-flag@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== has-symbols@^1.0.1, has-symbols@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.2.tgz#165d3070c00309752a1236a479331e3ac56f1423" + resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz#165d3070c00309752a1236a479331e3ac56f1423" integrity sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw== +has-tostringtag@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" + integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== + dependencies: + has-symbols "^1.0.2" + has-unicode@^2.0.0, has-unicode@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + resolved "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= has-value@^0.3.1: version "0.3.1" - resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" + resolved "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= dependencies: get-value "^2.0.3" @@ -4826,7 +4862,7 @@ has-value@^0.3.1: has-value@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" + resolved "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= dependencies: get-value "^2.0.6" @@ -4835,12 +4871,12 @@ has-value@^1.0.0: has-values@^0.1.4: version "0.1.4" - resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" + resolved "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E= has-values@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" + resolved "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= dependencies: is-number "^3.0.0" @@ -4848,21 +4884,14 @@ has-values@^1.0.0: has@^1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + resolved "https://registry.npmjs.org/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== dependencies: function-bind "^1.1.1" -hasha@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/hasha/-/hasha-3.0.0.tgz#52a32fab8569d41ca69a61ff1a214f8eb7c8bd39" - integrity sha1-UqMvq4Vp1BymmmH/GiFPjrfIvTk= - dependencies: - is-stream "^1.0.1" - hasha@^5.0.0: version "5.2.2" - resolved "https://registry.yarnpkg.com/hasha/-/hasha-5.2.2.tgz#a48477989b3b327aea3c04f53096d816d97522a1" + resolved "https://registry.npmjs.org/hasha/-/hasha-5.2.2.tgz#a48477989b3b327aea3c04f53096d816d97522a1" integrity sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ== dependencies: is-stream "^2.0.0" @@ -4870,41 +4899,41 @@ hasha@^5.0.0: "heap@>= 0.2.0": version "0.2.6" - resolved "https://registry.yarnpkg.com/heap/-/heap-0.2.6.tgz#087e1f10b046932fc8594dd9e6d378afc9d1e5ac" + resolved "https://registry.npmjs.org/heap/-/heap-0.2.6.tgz#087e1f10b046932fc8594dd9e6d378afc9d1e5ac" integrity sha1-CH4fELBGky/IWU3Z5tN4r8nR5aw= hosted-git-info@^2.1.4: version "2.8.9" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9" + resolved "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9" integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw== hosted-git-info@^4.0.0, hosted-git-info@^4.0.1: version "4.0.2" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-4.0.2.tgz#5e425507eede4fea846b7262f0838456c4209961" + resolved "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.0.2.tgz#5e425507eede4fea846b7262f0838456c4209961" integrity sha512-c9OGXbZ3guC/xOlCg1Ci/VgWlwsqDv1yMQL1CWqXDL0hDjXuNcq0zuR4xqPSuasI3kqFDhqSyTjREz5gzq0fXg== dependencies: lru-cache "^6.0.0" html-encoding-sniffer@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz#42a6dc4fd33f00281176e8b23759ca4e4fa185f3" + resolved "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz#42a6dc4fd33f00281176e8b23759ca4e4fa185f3" integrity sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ== dependencies: whatwg-encoding "^1.0.5" html-escaper@^2.0.0: version "2.0.2" - resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" + resolved "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== http-cache-semantics@^4.1.0: version "4.1.0" - resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390" + resolved "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390" integrity sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ== http-errors@1.7.3: version "1.7.3" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06" + resolved "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06" integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw== dependencies: depd "~1.1.2" @@ -4915,7 +4944,7 @@ http-errors@1.7.3: http-proxy-agent@^4.0.0, http-proxy-agent@^4.0.1: version "4.0.1" - resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a" + resolved "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a" integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg== dependencies: "@tootallnate/once" "1" @@ -4924,7 +4953,7 @@ http-proxy-agent@^4.0.0, http-proxy-agent@^4.0.1: http-signature@~1.2.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" + resolved "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= dependencies: assert-plus "^1.0.0" @@ -4933,7 +4962,7 @@ http-signature@~1.2.0: https-proxy-agent@5, https-proxy-agent@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2" + resolved "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2" integrity sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA== dependencies: agent-base "6" @@ -4941,101 +4970,101 @@ https-proxy-agent@5, https-proxy-agent@^5.0.0: human-signals@^1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" + resolved "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw== human-signals@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" + resolved "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== humanize-ms@^1.2.1: version "1.2.1" - resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" + resolved "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" integrity sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0= dependencies: ms "^2.0.0" iconv-lite@0.4.24, iconv-lite@^0.4.24: version "0.4.24" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== dependencies: safer-buffer ">= 2.1.2 < 3" iconv-lite@^0.6.2: version "0.6.3" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" + resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== dependencies: safer-buffer ">= 2.1.2 < 3.0.0" ieee754@1.1.13: version "1.1.13" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84" + resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84" integrity sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg== ieee754@^1.1.13, ieee754@^1.1.4: version "1.2.1" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== ignore-walk@^3.0.3: version "3.0.4" - resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.4.tgz#c9a09f69b7c7b479a5d74ac1a3c0d4236d2a6335" + resolved "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.4.tgz#c9a09f69b7c7b479a5d74ac1a3c0d4236d2a6335" integrity sha512-PY6Ii8o1jMRA1z4F2hRkH/xN59ox43DavKvD3oDpfurRlOJyAHpifIwpbdv1n4jt4ov0jSpw3kQ4GhJnpBL6WQ== dependencies: minimatch "^3.0.4" ignore@^4.0.6: version "4.0.6" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" + resolved "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== -ignore@^5.1.4, ignore@^5.1.8, ignore@~5.1.8: +ignore@^5.1.1, ignore@^5.1.4, ignore@^5.1.8, ignore@~5.1.8: version "5.1.8" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57" + resolved "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57" integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw== immediate@~3.0.5: version "3.0.6" - resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" + resolved "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" integrity sha1-nbHb0Pr43m++D13V5Wu2BigN5ps= import-fresh@^3.0.0, import-fresh@^3.2.1: version "3.3.0" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + resolved "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== dependencies: parent-module "^1.0.0" resolve-from "^4.0.0" import-local@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.0.2.tgz#a8cfd0431d1de4a2199703d003e3e62364fa6db6" - integrity sha512-vjL3+w0oulAVZ0hBHnxa/Nm5TAurf9YLQJDhqRZyqb+VKGOB6LU8t9H1Nr5CIo16vh9XfJTOoHwU0B71S557gA== + version "3.0.3" + resolved "https://registry.npmjs.org/import-local/-/import-local-3.0.3.tgz#4d51c2c495ca9393da259ec66b62e022920211e0" + integrity sha512-bE9iaUY3CXH8Cwfan/abDKAxe1KGT9kyGsBPqf6DMK/z0a2OzAsrukeYNgIH6cH5Xr452jb1TUL8rSfCLjZ9uA== dependencies: pkg-dir "^4.2.0" resolve-cwd "^3.0.0" imurmurhash@^0.1.4: version "0.1.4" - resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= indent-string@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" + resolved "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== infer-owner@^1.0.4: version "1.0.4" - resolved "https://registry.yarnpkg.com/infer-owner/-/infer-owner-1.0.4.tgz#c4cefcaa8e51051c2a40ba2ce8a3d27295af9467" + resolved "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz#c4cefcaa8e51051c2a40ba2ce8a3d27295af9467" integrity sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A== inflight@^1.0.4: version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= dependencies: once "^1.3.0" @@ -5043,31 +5072,35 @@ inflight@^1.0.4: inherits@2, inherits@2.0.4, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3: version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== -ini@^1.3.2, ini@^1.3.4, ini@~1.3.0: +ini@^1.3.2, ini@^1.3.4: version "1.3.8" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" + resolved "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== +ini@~2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz#e5fd556ecdd5726be978fa1001862eacb0a94bc5" + integrity sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA== + init-package-json@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/init-package-json/-/init-package-json-2.0.3.tgz#c8ae4f2a4ad353bcbc089e5ffe98a8f1a314e8fd" - integrity sha512-tk/gAgbMMxR6fn1MgMaM1HpU1ryAmBWWitnxG5OhuNXeX0cbpbgV5jA4AIpQJVNoyOfOevTtO6WX+rPs+EFqaQ== + version "2.0.5" + resolved "https://registry.npmjs.org/init-package-json/-/init-package-json-2.0.5.tgz#78b85f3c36014db42d8f32117252504f68022646" + integrity sha512-u1uGAtEFu3VA6HNl/yUWw57jmKEMx8SKOxHhxjGnOFUiIlFnohKDFg4ZrPpv9wWqk44nDxGJAtqjdQFm+9XXQA== dependencies: - glob "^7.1.1" - npm-package-arg "^8.1.2" + npm-package-arg "^8.1.5" promzard "^0.3.0" read "~1.0.1" - read-package-json "^3.0.1" + read-package-json "^4.1.1" semver "^7.3.5" validate-npm-package-license "^3.0.4" validate-npm-package-name "^3.0.0" inquirer@^7.3.3: version "7.3.3" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.3.3.tgz#04d176b2af04afc157a83fd7c100e98ee0aad003" + resolved "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz#04d176b2af04afc157a83fd7c100e98ee0aad003" integrity sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA== dependencies: ansi-escapes "^4.2.1" @@ -5084,95 +5117,110 @@ inquirer@^7.3.3: strip-ansi "^6.0.0" through "^2.3.6" +internal-slot@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c" + integrity sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA== + dependencies: + get-intrinsic "^1.1.0" + has "^1.0.3" + side-channel "^1.0.4" + ip@^1.1.5: version "1.1.5" - resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" + resolved "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo= is-accessor-descriptor@^0.1.6: version "0.1.6" - resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" + resolved "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= dependencies: kind-of "^3.0.2" is-accessor-descriptor@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" + resolved "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== dependencies: kind-of "^6.0.0" is-arguments@^1.0.4, is-arguments@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.0.tgz#62353031dfbee07ceb34656a6bde59efecae8dd9" - integrity sha512-1Ij4lOMPl/xB5kBDn7I+b2ttPMKa8szhEIrXDuXQD/oe3HJLTLhqhgGspwgyGd6MOywBUqVvYicF72lkgDnIHg== + version "1.1.1" + resolved "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" + integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== dependencies: - call-bind "^1.0.0" + call-bind "^1.0.2" + has-tostringtag "^1.0.0" is-arrayish@^0.2.1: version "0.2.1" - resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= is-bigint@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.2.tgz#ffb381442503235ad245ea89e45b3dbff040ee5a" - integrity sha512-0JV5+SOCQkIdzjBK9buARcV804Ddu7A0Qet6sHi3FimE9ne6m4BGQZfRn+NZiXbBk4F4XmHfDZIipLj9pX8dSA== + version "1.0.4" + resolved "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" + integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== + dependencies: + has-bigints "^1.0.1" is-boolean-object@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.1.tgz#3c0878f035cb821228d350d2e1e36719716a3de8" - integrity sha512-bXdQWkECBUIAcCkeH1unwJLIpZYaa5VvuygSyS/c2lf719mTKZDU5UdDRlpd01UjADgmW8RfqaP+mRaVPdr/Ng== + version "1.1.2" + resolved "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" + integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== dependencies: call-bind "^1.0.2" + has-tostringtag "^1.0.0" is-buffer@^1.1.5, is-buffer@~1.1.6: version "1.1.6" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + resolved "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== -is-callable@^1.1.4, is-callable@^1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.3.tgz#8b1e0500b73a1d76c70487636f368e519de8db8e" - integrity sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ== +is-callable@^1.1.4, is-callable@^1.2.4: + version "1.2.4" + resolved "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz#47301d58dd0259407865547853df6d61fe471945" + integrity sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w== is-ci@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" + resolved "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" integrity sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w== dependencies: ci-info "^2.0.0" -is-core-module@^2.2.0, is-core-module@^2.4.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.5.0.tgz#f754843617c70bfd29b7bd87327400cda5c18491" - integrity sha512-TXCMSDsEHMEEZ6eCA8rwRDbLu55MRGmrctljsBX/2v1d9/GzqHOxW5c5oPSgrUt2vBFXebu9rGqckXGPWOlYpg== +is-core-module@^2.2.0, is-core-module@^2.5.0, is-core-module@^2.7.0: + version "2.7.0" + resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.7.0.tgz#3c0ef7d31b4acfc574f80c58409d568a836848e3" + integrity sha512-ByY+tjCciCr+9nLryBYcSD50EOGWt95c7tIsKTG1J2ixKKXPvF7Ej3AVd+UfDydAJom3biBGDBALaO79ktwgEQ== dependencies: has "^1.0.3" is-data-descriptor@^0.1.4: version "0.1.4" - resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" + resolved "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= dependencies: kind-of "^3.0.2" is-data-descriptor@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" + resolved "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== dependencies: kind-of "^6.0.0" is-date-object@^1.0.1, is-date-object@^1.0.2: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.4.tgz#550cfcc03afada05eea3dd30981c7b09551f73e5" - integrity sha512-/b4ZVsG7Z5XVtIxs/h9W8nvfLgSAyKYdtGWQLbqy6jA1icmgjf8WCoTKgeS4wy5tYaPePouzFMANbnj94c2Z+A== + version "1.0.5" + resolved "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" + integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== + dependencies: + has-tostringtag "^1.0.0" is-descriptor@^0.1.0: version "0.1.6" - resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" + resolved "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== dependencies: is-accessor-descriptor "^0.1.6" @@ -5181,7 +5229,7 @@ is-descriptor@^0.1.0: is-descriptor@^1.0.0, is-descriptor@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" + resolved "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== dependencies: is-accessor-descriptor "^1.0.0" @@ -5190,276 +5238,267 @@ is-descriptor@^1.0.0, is-descriptor@^1.0.2: is-docker@^2.0.0: version "2.2.1" - resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" + resolved "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== is-extendable@^0.1.0, is-extendable@^0.1.1: version "0.1.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + resolved "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= is-extendable@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" + resolved "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== dependencies: is-plain-object "^2.0.4" is-extglob@^2.1.1: version "2.1.1" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= is-fullwidth-code-point@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== is-generator-fn@^2.0.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" + resolved "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== -is-glob@^4.0.0, is-glob@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" - integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: + version "4.0.3" + resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== dependencies: is-extglob "^2.1.1" is-lambda@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/is-lambda/-/is-lambda-1.0.1.tgz#3d9877899e6a53efc0160504cde15f82e6f061d5" + resolved "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz#3d9877899e6a53efc0160504cde15f82e6f061d5" integrity sha1-PZh3iZ5qU+/AFgUEzeFfgubwYdU= is-map@^2.0.1, is-map@^2.0.2: version "2.0.2" - resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.2.tgz#00922db8c9bf73e81b7a335827bc2a43f2b91127" + resolved "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz#00922db8c9bf73e81b7a335827bc2a43f2b91127" integrity sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg== is-negative-zero@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.1.tgz#3de746c18dda2319241a53675908d8f766f11c24" + resolved "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz#3de746c18dda2319241a53675908d8f766f11c24" integrity sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w== is-number-object@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.5.tgz#6edfaeed7950cff19afedce9fbfca9ee6dd289eb" - integrity sha512-RU0lI/n95pMoUKu9v1BZP5MBcZuNSVJkMkAG2dJqC4z2GlkGUNeH68SuHuBKBD/XFe+LHZ+f9BKkLET60Niedw== + version "1.0.6" + resolved "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz#6a7aaf838c7f0686a50b4553f7e54a96494e89f0" + integrity sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g== + dependencies: + has-tostringtag "^1.0.0" is-number@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" + resolved "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU= dependencies: kind-of "^3.0.2" is-number@^7.0.0: version "7.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== is-obj@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" + resolved "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== is-object@~1.0.1: version "1.0.2" - resolved "https://registry.yarnpkg.com/is-object/-/is-object-1.0.2.tgz#a56552e1c665c9e950b4a025461da87e72f86fcf" + resolved "https://registry.npmjs.org/is-object/-/is-object-1.0.2.tgz#a56552e1c665c9e950b4a025461da87e72f86fcf" integrity sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA== is-plain-obj@^1.0.0, is-plain-obj@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" + resolved "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4= is-plain-obj@^2.0.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" + resolved "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== is-plain-object@^2.0.3, is-plain-object@^2.0.4: version "2.0.4" - resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + resolved "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== dependencies: isobject "^3.0.1" is-plain-object@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344" + resolved "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344" integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q== is-potential-custom-element-name@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" + resolved "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== -is-regex@^1.1.1, is-regex@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.3.tgz#d029f9aff6448b93ebbe3f33dac71511fdcbef9f" - integrity sha512-qSVXFz28HM7y+IWX6vLCsexdlvzT1PJNFSBuaQLQ5o0IEw8UDYW6/2+eCMVyIsbM8CNLX2a/QWmSpyxYEHY7CQ== +is-regex@^1.1.1, is-regex@^1.1.4: + version "1.1.4" + resolved "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" + integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== dependencies: call-bind "^1.0.2" - has-symbols "^1.0.2" + has-tostringtag "^1.0.0" is-set@^2.0.1, is-set@^2.0.2: version "2.0.2" - resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.2.tgz#90755fa4c2562dc1c5d4024760d6119b94ca18ec" + resolved "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz#90755fa4c2562dc1c5d4024760d6119b94ca18ec" integrity sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g== +is-shared-array-buffer@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz#97b0c85fbdacb59c9c446fe653b82cf2b5b7cfe6" + integrity sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA== + is-ssh@^1.3.0: version "1.3.3" - resolved "https://registry.yarnpkg.com/is-ssh/-/is-ssh-1.3.3.tgz#7f133285ccd7f2c2c7fc897b771b53d95a2b2c7e" + resolved "https://registry.npmjs.org/is-ssh/-/is-ssh-1.3.3.tgz#7f133285ccd7f2c2c7fc897b771b53d95a2b2c7e" integrity sha512-NKzJmQzJfEEma3w5cJNcUMxoXfDjz0Zj0eyCalHn2E6VOwlzjZo0yuO2fcBSf8zhFuVCL/82/r5gRcoi6aEPVQ== dependencies: protocols "^1.1.0" -is-stream@^1.0.1, is-stream@^1.1.0: +is-stream@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + resolved "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= is-stream@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.0.tgz#bde9c32680d6fae04129d6ac9d921ce7815f78e3" - integrity sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw== + version "2.0.1" + resolved "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== -is-string@^1.0.5, is-string@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.6.tgz#3fe5d5992fb0d93404f32584d4b0179a71b54a5f" - integrity sha512-2gdzbKUuqtQ3lYNrUTQYoClPhm7oQu4UdpSZMp1/DGgkHBT8E2Z1l0yMdb6D4zNAxwDiMv8MdulKROJGNl0Q0w== +is-string@^1.0.5, is-string@^1.0.7: + version "1.0.7" + resolved "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" + integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== + dependencies: + has-tostringtag "^1.0.0" is-symbol@^1.0.2, is-symbol@^1.0.3: version "1.0.4" - resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" + resolved "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== dependencies: has-symbols "^1.0.2" is-text-path@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/is-text-path/-/is-text-path-1.0.1.tgz#4e1aa0fb51bfbcb3e92688001397202c1775b66e" + resolved "https://registry.npmjs.org/is-text-path/-/is-text-path-1.0.1.tgz#4e1aa0fb51bfbcb3e92688001397202c1775b66e" integrity sha1-Thqg+1G/vLPpJogAE5cgLBd1tm4= dependencies: text-extensions "^1.0.0" -is-typed-array@^1.1.3: - version "1.1.5" - resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.5.tgz#f32e6e096455e329eb7b423862456aa213f0eb4e" - integrity sha512-S+GRDgJlR3PyEbsX/Fobd9cqpZBuvUS+8asRqYDMLCb2qMzt1oz5m5oxQCxOgUDxiWsOVNi4yaF+/uvdlHlYug== +is-typed-array@^1.1.7: + version "1.1.8" + resolved "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.8.tgz#cbaa6585dc7db43318bc5b89523ea384a6f65e79" + integrity sha512-HqH41TNZq2fgtGT8WHVFVJhBVGuY3AnP3Q36K8JKXUxSxRgk/d+7NjmwG2vo2mYmXK8UYZKu0qH8bVP5gEisjA== dependencies: - available-typed-arrays "^1.0.2" + available-typed-arrays "^1.0.5" call-bind "^1.0.2" - es-abstract "^1.18.0-next.2" + es-abstract "^1.18.5" foreach "^2.0.5" - has-symbols "^1.0.1" + has-tostringtag "^1.0.0" is-typedarray@^1.0.0, is-typedarray@~1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + resolved "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= is-weakmap@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.1.tgz#5008b59bdc43b698201d18f62b37b2ca243e8cf2" + resolved "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz#5008b59bdc43b698201d18f62b37b2ca243e8cf2" integrity sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA== +is-weakref@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.1.tgz#842dba4ec17fa9ac9850df2d6efbc1737274f2a2" + integrity sha512-b2jKc2pQZjaeFYWEf7ScFj+Be1I+PXmlu572Q8coTXZ+LD/QQZ7ShPMst8h16riVgyXTQwUsFEl74mDvc/3MHQ== + dependencies: + call-bind "^1.0.0" + is-weakset@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/is-weakset/-/is-weakset-2.0.1.tgz#e9a0af88dbd751589f5e50d80f4c98b780884f83" + resolved "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.1.tgz#e9a0af88dbd751589f5e50d80f4c98b780884f83" integrity sha512-pi4vhbhVHGLxohUw7PhGsueT4vRGFoXhP7+RGN0jKIv9+8PWYCQTqtADngrxOm2g46hoH0+g8uZZBzMrvVGDmw== is-windows@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + resolved "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== is-wsl@^2.1.1, is-wsl@^2.2.0: version "2.2.0" - resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" + resolved "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== dependencies: is-docker "^2.0.0" isarray@0.0.1: version "0.0.1" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + resolved "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= isarray@^2.0.5: version "2.0.5" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" + resolved "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== isexe@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= isobject@^2.0.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + resolved "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= dependencies: isarray "1.0.0" isobject@^3.0.0, isobject@^3.0.1: version "3.0.1" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + resolved "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= isstream@~0.1.2: version "0.1.2" - resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + resolved "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= -istanbul-lib-coverage@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz#675f0ab69503fad4b1d849f736baaca803344f49" - integrity sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA== - istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.0.0-alpha.1: - version "3.0.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz#f5944a37c70b550b02a78a5c3b2055b280cec8ec" - integrity sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg== - -istanbul-lib-hook@^2.0.7: - version "2.0.7" - resolved "https://registry.yarnpkg.com/istanbul-lib-hook/-/istanbul-lib-hook-2.0.7.tgz#c95695f383d4f8f60df1f04252a9550e15b5b133" - integrity sha512-vrRztU9VRRFDyC+aklfLoeXyNdTfga2EI3udDGn4cZ6fpSXpHLV9X6CHvfoMCPtggg8zvDDmC4b9xfu0z6/llA== - dependencies: - append-transform "^1.0.0" + version "3.0.2" + resolved "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.2.tgz#36786d4d82aad2ea5911007e255e2da6b5f80d86" + integrity sha512-o5+eTUYzCJ11/+JhW5/FUCdfsdoYVdQ/8I/OveE2XsjehYn5DdeSnNQAbjYaO8gQ6hvGTN6GM6ddQqpTVG5j8g== istanbul-lib-hook@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz#8f84c9434888cc6b1d0a9d7092a76d239ebf0cc6" + resolved "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz#8f84c9434888cc6b1d0a9d7092a76d239ebf0cc6" integrity sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ== dependencies: append-transform "^2.0.0" -istanbul-lib-instrument@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz#a5f63d91f0bbc0c3e479ef4c5de027335ec6d630" - integrity sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA== - dependencies: - "@babel/generator" "^7.4.0" - "@babel/parser" "^7.4.3" - "@babel/template" "^7.4.0" - "@babel/traverse" "^7.4.3" - "@babel/types" "^7.4.0" - istanbul-lib-coverage "^2.0.5" - semver "^6.0.0" - istanbul-lib-instrument@^4.0.0, istanbul-lib-instrument@^4.0.3: version "4.0.3" - resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz#873c6fff897450118222774696a3f28902d77c1d" + resolved "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz#873c6fff897450118222774696a3f28902d77c1d" integrity sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ== dependencies: "@babel/core" "^7.7.5" @@ -5469,7 +5508,7 @@ istanbul-lib-instrument@^4.0.0, istanbul-lib-instrument@^4.0.3: istanbul-lib-processinfo@^2.0.2: version "2.0.2" - resolved "https://registry.yarnpkg.com/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.2.tgz#e1426514662244b2f25df728e8fd1ba35fe53b9c" + resolved "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.2.tgz#e1426514662244b2f25df728e8fd1ba35fe53b9c" integrity sha512-kOwpa7z9hme+IBPZMzQ5vdQj8srYgAtaRqeI48NGmAQ+/5yKiHLV0QbYqQpxsdEF0+w14SoB8YbnHKcXE2KnYw== dependencies: archy "^1.0.0" @@ -5480,62 +5519,35 @@ istanbul-lib-processinfo@^2.0.2: rimraf "^3.0.0" uuid "^3.3.3" -istanbul-lib-report@^2.0.8: - version "2.0.8" - resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-2.0.8.tgz#5a8113cd746d43c4889eba36ab10e7d50c9b4f33" - integrity sha512-fHBeG573EIihhAblwgxrSenp0Dby6tJMFR/HvlerBsrCTD5bkUuoNtn3gVh29ZCS824cGGBPn7Sg7cNk+2xUsQ== - dependencies: - istanbul-lib-coverage "^2.0.5" - make-dir "^2.1.0" - supports-color "^6.1.0" - istanbul-lib-report@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#7518fe52ea44de372f460a76b5ecda9ffb73d8a6" + resolved "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#7518fe52ea44de372f460a76b5ecda9ffb73d8a6" integrity sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw== dependencies: istanbul-lib-coverage "^3.0.0" make-dir "^3.0.0" supports-color "^7.1.0" -istanbul-lib-source-maps@^3.0.6: - version "3.0.6" - resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz#284997c48211752ec486253da97e3879defba8c8" - integrity sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw== - dependencies: - debug "^4.1.1" - istanbul-lib-coverage "^2.0.5" - make-dir "^2.1.0" - rimraf "^2.6.3" - source-map "^0.6.1" - istanbul-lib-source-maps@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz#75743ce6d96bb86dc7ee4352cf6366a23f0b1ad9" - integrity sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg== + version "4.0.1" + resolved "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz#895f3a709fcfba34c6de5a42939022f3e4358551" + integrity sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw== dependencies: debug "^4.1.1" istanbul-lib-coverage "^3.0.0" source-map "^0.6.1" -istanbul-reports@^2.2.4: - version "2.2.7" - resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-2.2.7.tgz#5d939f6237d7b48393cc0959eab40cd4fd056931" - integrity sha512-uu1F/L1o5Y6LzPVSVZXNOoD/KXpJue9aeLRd0sM9uMXfZvzomB0WxVamWb5ue8kA2vVWEmW7EG+A5n3f1kqHKg== - dependencies: - html-escaper "^2.0.0" - istanbul-reports@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.0.2.tgz#d593210e5000683750cb09fc0644e4b6e27fd53b" - integrity sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw== + version "3.0.4" + resolved "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.4.tgz#5c38ce8136edf484c0fcfbf7514aafb0363ed1db" + integrity sha512-bFjUnc95rHjdCR63WMHUS7yfJJh8T9IPSWavvR02hhjVwezWALZ5axF9EqjmwZHpXqkzbgAMP8DmAtiyNxrdrQ== dependencies: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" jest-changed-files@^26.6.2: version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-26.6.2.tgz#f6198479e1cc66f22f9ae1e22acaa0b429c042d0" + resolved "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-26.6.2.tgz#f6198479e1cc66f22f9ae1e22acaa0b429c042d0" integrity sha512-fDS7szLcY9sCtIip8Fjry9oGf3I2ht/QT21bAHm5Dmf0mD4X3ReNUf17y+bO6fR8WgbIZTlbyG1ak/53cbRzKQ== dependencies: "@jest/types" "^26.6.2" @@ -5544,7 +5556,7 @@ jest-changed-files@^26.6.2: jest-cli@^26.6.3: version "26.6.3" - resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-26.6.3.tgz#43117cfef24bc4cd691a174a8796a532e135e92a" + resolved "https://registry.npmjs.org/jest-cli/-/jest-cli-26.6.3.tgz#43117cfef24bc4cd691a174a8796a532e135e92a" integrity sha512-GF9noBSa9t08pSyl3CY4frMrqp+aQXFGFkf5hEPbh/pIUFYWMK6ZLTfbmadxJVcJrdRoChlWQsA2VkJcDFK8hg== dependencies: "@jest/core" "^26.6.3" @@ -5563,7 +5575,7 @@ jest-cli@^26.6.3: jest-config@^26.6.3: version "26.6.3" - resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-26.6.3.tgz#64f41444eef9eb03dc51d5c53b75c8c71f645349" + resolved "https://registry.npmjs.org/jest-config/-/jest-config-26.6.3.tgz#64f41444eef9eb03dc51d5c53b75c8c71f645349" integrity sha512-t5qdIj/bCj2j7NFVHb2nFB4aUdfucDn3JRKgrZnplb8nieAirAzRSHP8uDEd+qV6ygzg9Pz4YG7UTJf94LPSyg== dependencies: "@babel/core" "^7.1.0" @@ -5587,7 +5599,7 @@ jest-config@^26.6.3: jest-diff@^26.0.0, jest-diff@^26.6.2: version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-26.6.2.tgz#1aa7468b52c3a68d7d5c5fdcdfcd5e49bd164394" + resolved "https://registry.npmjs.org/jest-diff/-/jest-diff-26.6.2.tgz#1aa7468b52c3a68d7d5c5fdcdfcd5e49bd164394" integrity sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA== dependencies: chalk "^4.0.0" @@ -5597,14 +5609,14 @@ jest-diff@^26.0.0, jest-diff@^26.6.2: jest-docblock@^26.0.0: version "26.0.0" - resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-26.0.0.tgz#3e2fa20899fc928cb13bd0ff68bd3711a36889b5" + resolved "https://registry.npmjs.org/jest-docblock/-/jest-docblock-26.0.0.tgz#3e2fa20899fc928cb13bd0ff68bd3711a36889b5" integrity sha512-RDZ4Iz3QbtRWycd8bUEPxQsTlYazfYn/h5R65Fc6gOfwozFhoImx+affzky/FFBuqISPTqjXomoIGJVKBWoo0w== dependencies: detect-newline "^3.0.0" jest-each@^26.6.2: version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-26.6.2.tgz#02526438a77a67401c8a6382dfe5999952c167cb" + resolved "https://registry.npmjs.org/jest-each/-/jest-each-26.6.2.tgz#02526438a77a67401c8a6382dfe5999952c167cb" integrity sha512-Mer/f0KaATbjl8MCJ+0GEpNdqmnVmDYqCTJYTvoo7rqmRiDllmp2AYN+06F93nXcY3ur9ShIjS+CO/uD+BbH4A== dependencies: "@jest/types" "^26.6.2" @@ -5615,7 +5627,7 @@ jest-each@^26.6.2: jest-environment-jsdom@^26.6.2: version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-26.6.2.tgz#78d09fe9cf019a357009b9b7e1f101d23bd1da3e" + resolved "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-26.6.2.tgz#78d09fe9cf019a357009b9b7e1f101d23bd1da3e" integrity sha512-jgPqCruTlt3Kwqg5/WVFyHIOJHsiAvhcp2qiR2QQstuG9yWox5+iHpU3ZrcBxW14T4fe5Z68jAfLRh7joCSP2Q== dependencies: "@jest/environment" "^26.6.2" @@ -5628,7 +5640,7 @@ jest-environment-jsdom@^26.6.2: jest-environment-node@^26.6.2: version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-26.6.2.tgz#824e4c7fb4944646356f11ac75b229b0035f2b0c" + resolved "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-26.6.2.tgz#824e4c7fb4944646356f11ac75b229b0035f2b0c" integrity sha512-zhtMio3Exty18dy8ee8eJ9kjnRyZC1N4C1Nt/VShN1apyXc8rWGtJ9lI7vqiWcyyXS4BVSEn9lxAM2D+07/Tag== dependencies: "@jest/environment" "^26.6.2" @@ -5640,12 +5652,12 @@ jest-environment-node@^26.6.2: jest-get-type@^26.3.0: version "26.3.0" - resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-26.3.0.tgz#e97dc3c3f53c2b406ca7afaed4493b1d099199e0" + resolved "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz#e97dc3c3f53c2b406ca7afaed4493b1d099199e0" integrity sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig== jest-haste-map@^26.6.2: version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-26.6.2.tgz#dd7e60fe7dc0e9f911a23d79c5ff7fb5c2cafeaa" + resolved "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-26.6.2.tgz#dd7e60fe7dc0e9f911a23d79c5ff7fb5c2cafeaa" integrity sha512-easWIJXIw71B2RdR8kgqpjQrbMRWQBgiBwXYEhtGUTaX+doCjBheluShdDMeR8IMfJiTqH4+zfhtg29apJf/8w== dependencies: "@jest/types" "^26.6.2" @@ -5666,7 +5678,7 @@ jest-haste-map@^26.6.2: jest-jasmine2@^26.6.3: version "26.6.3" - resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-26.6.3.tgz#adc3cf915deacb5212c93b9f3547cd12958f2edd" + resolved "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-26.6.3.tgz#adc3cf915deacb5212c93b9f3547cd12958f2edd" integrity sha512-kPKUrQtc8aYwBV7CqBg5pu+tmYXlvFlSFYn18ev4gPFtrRzB15N2gW/Roew3187q2w2eHuu0MU9TJz6w0/nPEg== dependencies: "@babel/traverse" "^7.1.0" @@ -5690,7 +5702,7 @@ jest-jasmine2@^26.6.3: jest-junit@^11.1.0: version "11.1.0" - resolved "https://registry.yarnpkg.com/jest-junit/-/jest-junit-11.1.0.tgz#79cd53948e44d62b2b30fa23ea0d7a899d2c8d7a" + resolved "https://registry.npmjs.org/jest-junit/-/jest-junit-11.1.0.tgz#79cd53948e44d62b2b30fa23ea0d7a899d2c8d7a" integrity sha512-c2LFOyKY7+ZxL5zSu+WHmHfsJ2wqbOpeYJ4Uu26yMhFxny2J2NQj6AVS7M+Eaxji9Q/oIDDK5tQy0DGzDp9xOw== dependencies: mkdirp "^1.0.4" @@ -5698,10 +5710,10 @@ jest-junit@^11.1.0: uuid "^3.3.3" xml "^1.0.1" -jest-junit@^12.2.0: - version "12.2.0" - resolved "https://registry.yarnpkg.com/jest-junit/-/jest-junit-12.2.0.tgz#cff7f9516e84f8e30f6bdea04cd84db6b095a376" - integrity sha512-ecGzF3KEQwLbMP5xMO7wqmgmyZlY/5yWDvgE/vFa+/uIT0KsU5nluf0D2fjIlOKB+tb6DiuSSpZuGpsmwbf7Fw== +jest-junit@^12.3.0: + version "12.3.0" + resolved "https://registry.npmjs.org/jest-junit/-/jest-junit-12.3.0.tgz#ee41a74e439eecdc8965f163f83035cce5998d6d" + integrity sha512-+NmE5ogsEjFppEl90GChrk7xgz8xzvF0f+ZT5AnhW6suJC93gvQtmQjfyjDnE0Z2nXJqEkxF0WXlvjG/J+wn/g== dependencies: mkdirp "^1.0.4" strip-ansi "^5.2.0" @@ -5710,7 +5722,7 @@ jest-junit@^12.2.0: jest-leak-detector@^26.6.2: version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-26.6.2.tgz#7717cf118b92238f2eba65054c8a0c9c653a91af" + resolved "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-26.6.2.tgz#7717cf118b92238f2eba65054c8a0c9c653a91af" integrity sha512-i4xlXpsVSMeKvg2cEKdfhh0H39qlJlP5Ex1yQxwF9ubahboQYMgTtz5oML35AVA3B4Eu+YsmwaiKVev9KCvLxg== dependencies: jest-get-type "^26.3.0" @@ -5718,7 +5730,7 @@ jest-leak-detector@^26.6.2: jest-matcher-utils@^26.6.2: version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-26.6.2.tgz#8e6fd6e863c8b2d31ac6472eeb237bc595e53e7a" + resolved "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-26.6.2.tgz#8e6fd6e863c8b2d31ac6472eeb237bc595e53e7a" integrity sha512-llnc8vQgYcNqDrqRDXWwMr9i7rS5XFiCwvh6DTP7Jqa2mqpcCBBlpCbn+trkG0KNhPu/h8rzyBkriOtBstvWhw== dependencies: chalk "^4.0.0" @@ -5728,7 +5740,7 @@ jest-matcher-utils@^26.6.2: jest-message-util@^26.6.2: version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-26.6.2.tgz#58173744ad6fc0506b5d21150b9be56ef001ca07" + resolved "https://registry.npmjs.org/jest-message-util/-/jest-message-util-26.6.2.tgz#58173744ad6fc0506b5d21150b9be56ef001ca07" integrity sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA== dependencies: "@babel/code-frame" "^7.0.0" @@ -5743,7 +5755,7 @@ jest-message-util@^26.6.2: jest-mock@^26.6.2: version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-26.6.2.tgz#d6cb712b041ed47fe0d9b6fc3474bc6543feb302" + resolved "https://registry.npmjs.org/jest-mock/-/jest-mock-26.6.2.tgz#d6cb712b041ed47fe0d9b6fc3474bc6543feb302" integrity sha512-YyFjePHHp1LzpzYcmgqkJ0nm0gg/lJx2aZFzFy1S6eUqNjXsOqTK10zNRff2dNfssgokjkG65OlWNcIlgd3zew== dependencies: "@jest/types" "^26.6.2" @@ -5751,17 +5763,17 @@ jest-mock@^26.6.2: jest-pnp-resolver@^1.2.2: version "1.2.2" - resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz#b704ac0ae028a89108a4d040b3f919dfddc8e33c" + resolved "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz#b704ac0ae028a89108a4d040b3f919dfddc8e33c" integrity sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w== jest-regex-util@^26.0.0: version "26.0.0" - resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-26.0.0.tgz#d25e7184b36e39fd466c3bc41be0971e821fee28" + resolved "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-26.0.0.tgz#d25e7184b36e39fd466c3bc41be0971e821fee28" integrity sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A== jest-resolve-dependencies@^26.6.3: version "26.6.3" - resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-26.6.3.tgz#6680859ee5d22ee5dcd961fe4871f59f4c784fb6" + resolved "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-26.6.3.tgz#6680859ee5d22ee5dcd961fe4871f59f4c784fb6" integrity sha512-pVwUjJkxbhe4RY8QEWzN3vns2kqyuldKpxlxJlzEYfKSvY6/bMvxoFrYYzUO1Gx28yKWN37qyV7rIoIp2h8fTg== dependencies: "@jest/types" "^26.6.2" @@ -5770,7 +5782,7 @@ jest-resolve-dependencies@^26.6.3: jest-resolve@^26.6.2: version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-26.6.2.tgz#a3ab1517217f469b504f1b56603c5bb541fbb507" + resolved "https://registry.npmjs.org/jest-resolve/-/jest-resolve-26.6.2.tgz#a3ab1517217f469b504f1b56603c5bb541fbb507" integrity sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ== dependencies: "@jest/types" "^26.6.2" @@ -5784,7 +5796,7 @@ jest-resolve@^26.6.2: jest-runner@^26.6.3: version "26.6.3" - resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-26.6.3.tgz#2d1fed3d46e10f233fd1dbd3bfaa3fe8924be159" + resolved "https://registry.npmjs.org/jest-runner/-/jest-runner-26.6.3.tgz#2d1fed3d46e10f233fd1dbd3bfaa3fe8924be159" integrity sha512-atgKpRHnaA2OvByG/HpGA4g6CSPS/1LK0jK3gATJAoptC1ojltpmVlYC3TYgdmGp+GLuhzpH30Gvs36szSL2JQ== dependencies: "@jest/console" "^26.6.2" @@ -5810,7 +5822,7 @@ jest-runner@^26.6.3: jest-runtime@^26.6.3: version "26.6.3" - resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-26.6.3.tgz#4f64efbcfac398331b74b4b3c82d27d401b8fa2b" + resolved "https://registry.npmjs.org/jest-runtime/-/jest-runtime-26.6.3.tgz#4f64efbcfac398331b74b4b3c82d27d401b8fa2b" integrity sha512-lrzyR3N8sacTAMeonbqpnSka1dHNux2uk0qqDXVkMv2c/A3wYnvQ4EXuI013Y6+gSKSCxdaczvf4HF0mVXHRdw== dependencies: "@jest/console" "^26.6.2" @@ -5843,7 +5855,7 @@ jest-runtime@^26.6.3: jest-serializer@^26.6.2: version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-26.6.2.tgz#d139aafd46957d3a448f3a6cdabe2919ba0742d1" + resolved "https://registry.npmjs.org/jest-serializer/-/jest-serializer-26.6.2.tgz#d139aafd46957d3a448f3a6cdabe2919ba0742d1" integrity sha512-S5wqyz0DXnNJPd/xfIzZ5Xnp1HrJWBczg8mMfMpN78OJ5eDxXyf+Ygld9wX1DnUWbIbhM1YDY95NjR4CBXkb2g== dependencies: "@types/node" "*" @@ -5851,7 +5863,7 @@ jest-serializer@^26.6.2: jest-snapshot@^26.6.2: version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-26.6.2.tgz#f3b0af1acb223316850bd14e1beea9837fb39c84" + resolved "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-26.6.2.tgz#f3b0af1acb223316850bd14e1beea9837fb39c84" integrity sha512-OLhxz05EzUtsAmOMzuupt1lHYXCNib0ECyuZ/PZOx9TrZcC8vL0x+DUG3TL+GLX3yHG45e6YGjIm0XwDc3q3og== dependencies: "@babel/types" "^7.0.0" @@ -5873,7 +5885,7 @@ jest-snapshot@^26.6.2: jest-util@^26.1.0, jest-util@^26.6.2: version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-26.6.2.tgz#907535dbe4d5a6cb4c47ac9b926f6af29576cbc1" + resolved "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz#907535dbe4d5a6cb4c47ac9b926f6af29576cbc1" integrity sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q== dependencies: "@jest/types" "^26.6.2" @@ -5885,7 +5897,7 @@ jest-util@^26.1.0, jest-util@^26.6.2: jest-validate@^26.6.2: version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-26.6.2.tgz#23d380971587150467342911c3d7b4ac57ab20ec" + resolved "https://registry.npmjs.org/jest-validate/-/jest-validate-26.6.2.tgz#23d380971587150467342911c3d7b4ac57ab20ec" integrity sha512-NEYZ9Aeyj0i5rQqbq+tpIOom0YS1u2MVu6+euBsvpgIme+FOfRmoC4R5p0JiAUpaFvFy24xgrpMknarR/93XjQ== dependencies: "@jest/types" "^26.6.2" @@ -5897,7 +5909,7 @@ jest-validate@^26.6.2: jest-watcher@^26.6.2: version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-26.6.2.tgz#a5b683b8f9d68dbcb1d7dae32172d2cca0592975" + resolved "https://registry.npmjs.org/jest-watcher/-/jest-watcher-26.6.2.tgz#a5b683b8f9d68dbcb1d7dae32172d2cca0592975" integrity sha512-WKJob0P/Em2csiVthsI68p6aGKTIcsfjH9Gsx1f0A3Italz43e3ho0geSAVsmj09RWOELP1AZ/DXyJgOgDKxXQ== dependencies: "@jest/test-result" "^26.6.2" @@ -5910,7 +5922,7 @@ jest-watcher@^26.6.2: jest-worker@^26.6.2: version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.6.2.tgz#7f72cbc4d643c365e27b9fd775f9d0eaa9c7a8ed" + resolved "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz#7f72cbc4d643c365e27b9fd775f9d0eaa9c7a8ed" integrity sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ== dependencies: "@types/node" "*" @@ -5919,7 +5931,7 @@ jest-worker@^26.6.2: jest@^26.6.3: version "26.6.3" - resolved "https://registry.yarnpkg.com/jest/-/jest-26.6.3.tgz#40e8fdbe48f00dfa1f0ce8121ca74b88ac9148ef" + resolved "https://registry.npmjs.org/jest/-/jest-26.6.3.tgz#40e8fdbe48f00dfa1f0ce8121ca74b88ac9148ef" integrity sha512-lGS5PXGAzR4RF7V5+XObhqz2KZIDUA1yD0DG6pBVmy10eh0ZIXQImRuzocsI/N2XZ1GrLFwTS27In2i2jlpq1Q== dependencies: "@jest/core" "^26.6.3" @@ -5928,43 +5940,43 @@ jest@^26.6.3: jmespath@0.15.0: version "0.15.0" - resolved "https://registry.yarnpkg.com/jmespath/-/jmespath-0.15.0.tgz#a3f222a9aae9f966f5d27c796510e28091764217" + resolved "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz#a3f222a9aae9f966f5d27c796510e28091764217" integrity sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc= js-base64@^2.1.9: version "2.6.4" - resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.6.4.tgz#f4e686c5de1ea1f867dbcad3d46d969428df98c4" + resolved "https://registry.npmjs.org/js-base64/-/js-base64-2.6.4.tgz#f4e686c5de1ea1f867dbcad3d46d969428df98c4" integrity sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ== js-tokens@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== -js-yaml@^3.13.1, js-yaml@^3.2.7: +js-yaml@^3.13.1: version "3.14.1" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" + resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== dependencies: argparse "^1.0.7" esprima "^4.0.0" -js-yaml@^4.0.0: +js-yaml@^4.1.0: version "4.1.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== dependencies: argparse "^2.0.1" jsbn@~0.1.0: version "0.1.1" - resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" + resolved "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= jsdom@^16.4.0: - version "16.6.0" - resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.6.0.tgz#f79b3786682065492a3da6a60a4695da983805ac" - integrity sha512-Ty1vmF4NHJkolaEmdjtxTfSfkdb8Ywarwf63f+F8/mDD1uLSSWDxDuMiZxiPhwunLrn9LOSVItWj4bLYsLN3Dg== + version "16.7.0" + resolved "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz#918ae71965424b197c819f8183a754e18977b710" + integrity sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw== dependencies: abab "^2.0.5" acorn "^8.2.4" @@ -5991,107 +6003,78 @@ jsdom@^16.4.0: whatwg-encoding "^1.0.5" whatwg-mimetype "^2.3.0" whatwg-url "^8.5.0" - ws "^7.4.5" + ws "^7.4.6" xml-name-validator "^3.0.0" jsesc@^2.5.1: version "2.5.2" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + resolved "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== -jsii-diff@^1.34.0: - version "1.34.0" - resolved "https://registry.yarnpkg.com/jsii-diff/-/jsii-diff-1.34.0.tgz#86742f21f5ab809df2ce8b6902f390c6379a9a39" - integrity sha512-fPVBoixNjo3kQs8WgjNeE7M5HxcK3jqfgM/IC6fpzrsGDjjqnH7emtVH3gvS18uQxUfYKKkXEKbkHsywQe6EkA== +jsii-diff@^1.39.0: + version "1.39.0" + resolved "https://registry.npmjs.org/jsii-diff/-/jsii-diff-1.39.0.tgz#e6dc9ffc5689bfcfa2bcd9532829054003547470" + integrity sha512-O49YB3IElNIyP7zbBXLTYmLPwxxJY4Zs4rcZ4zpO73Yv373edT+TmoKkZV05DhKNcU79nFPB+axr6sKP6ElzFw== dependencies: - "@jsii/check-node" "1.34.0" - "@jsii/spec" "^1.34.0" + "@jsii/check-node" "1.39.0" + "@jsii/spec" "^1.39.0" fs-extra "^9.1.0" - jsii-reflect "^1.34.0" + jsii-reflect "^1.39.0" log4js "^6.3.0" typescript "~3.9.10" yargs "^16.2.0" -jsii-pacmak@^1.34.0: - version "1.34.0" - resolved "https://registry.yarnpkg.com/jsii-pacmak/-/jsii-pacmak-1.34.0.tgz#7fc6a79fb72bd791a0cac5877339253fd26e14e3" - integrity sha512-OngbNHieb5g7B1VkRSZkZq1vgoflhjX4heTJnQJZYbG59j2qVgD7E/o/Dl2OTBLrGRms8e2oCsYc7XROt2htSA== +jsii-pacmak@^1.39.0: + version "1.39.0" + resolved "https://registry.npmjs.org/jsii-pacmak/-/jsii-pacmak-1.39.0.tgz#b5c66eb32a62390e02c0273f6edca3871600cc74" + integrity sha512-+B2Z62v/MQ8fQcvd1nhKUWv+ZoNEArwa6OiTSvAuMsRoZpZ7Uvabscu71Uu3zq1XzJ6WQStw90ENHkw40l/o7w== dependencies: - "@jsii/check-node" "1.34.0" - "@jsii/spec" "^1.34.0" + "@jsii/check-node" "1.39.0" + "@jsii/spec" "^1.39.0" clone "^2.1.2" - codemaker "^1.34.0" + codemaker "^1.39.0" commonmark "^0.30.0" escape-string-regexp "^4.0.0" fs-extra "^9.1.0" - jsii-reflect "^1.34.0" - jsii-rosetta "^1.34.0" + jsii-reflect "^1.39.0" + jsii-rosetta "^1.39.0" semver "^7.3.5" spdx-license-list "^6.4.0" xmlbuilder "^15.1.1" yargs "^16.2.0" -jsii-reflect@^1.31.0: - version "1.31.0" - resolved "https://registry.yarnpkg.com/jsii-reflect/-/jsii-reflect-1.31.0.tgz#83acdae835071c734bb8847cf3cad7ccc4497540" - integrity sha512-jKc3tryVeEyEBZFv5bDB8rOaEgW+yBPh0DE4GQCKQQLdkp76Lm9ZSkrnJk5e0gEuAWsmuc1DUs35OcVNr8QRWg== +jsii-reflect@^1.39.0: + version "1.39.0" + resolved "https://registry.npmjs.org/jsii-reflect/-/jsii-reflect-1.39.0.tgz#c35a395b7ec14c4e94aef8bf195a0ff329311534" + integrity sha512-HEMpGHJBDtUbhdnfYUH0M/NTrYxaXrb0B2DXglzN/EYzKJsdp4FAmDPzpKEwnGVK3ReJLZ68YRogTq3msyuQDQ== dependencies: - "@jsii/spec" "^1.31.0" + "@jsii/check-node" "1.39.0" + "@jsii/spec" "^1.39.0" colors "^1.4.0" fs-extra "^9.1.0" - oo-ascii-tree "^1.31.0" + oo-ascii-tree "^1.39.0" yargs "^16.2.0" -jsii-reflect@^1.34.0: - version "1.34.0" - resolved "https://registry.yarnpkg.com/jsii-reflect/-/jsii-reflect-1.34.0.tgz#3d5c8f7c2e8310df2c8dea3aad5bef487fe1d0d9" - integrity sha512-IOEdwgeDCOq821PM3OfRro1Pgu0QzHFW7zQy3aN7/w5Fcb/tSYGxI9+Ykr6JCdg681LFzcMEgwJpCUHnfi/shw== +jsii-rosetta@^1.39.0: + version "1.39.0" + resolved "https://registry.npmjs.org/jsii-rosetta/-/jsii-rosetta-1.39.0.tgz#b4251bb9b0295d2a8c2c7a7d8b1d8d744f432305" + integrity sha512-Fx+kQ+IDEMILQvTESW9TMXLxzQa7h/nm4EKXuDKAeglr5RNhzvTvhsgJy+WshJoMsNcT9ImCV8gmvqAqdSBrWA== dependencies: - "@jsii/check-node" "1.34.0" - "@jsii/spec" "^1.34.0" - colors "^1.4.0" - fs-extra "^9.1.0" - oo-ascii-tree "^1.34.0" - yargs "^16.2.0" - -jsii-rosetta@^1.34.0: - version "1.34.0" - resolved "https://registry.yarnpkg.com/jsii-rosetta/-/jsii-rosetta-1.34.0.tgz#64b1233726a98a992be5cffd1d0f4b824346dbef" - integrity sha512-GOGAy5b+zCGeyYziBoNVXgamL2CEZKMj5moeemkyN4AUHUqugNk3fSul2Zdbxs2S13Suk0D9iYAgChDxew0bOw== - dependencies: - "@jsii/check-node" "1.34.0" - "@jsii/spec" "^1.34.0" - "@xmldom/xmldom" "^0.7.0" + "@jsii/check-node" "1.39.0" + "@jsii/spec" "^1.39.0" + "@xmldom/xmldom" "^0.7.5" commonmark "^0.30.0" fs-extra "^9.1.0" typescript "~3.9.10" yargs "^16.2.0" -jsii@^1.31.0: - version "1.31.0" - resolved "https://registry.yarnpkg.com/jsii/-/jsii-1.31.0.tgz#513ff04581eae233accef2e2ce06a19d9bd4d972" - integrity sha512-q/p5a6OLO9V0pIcyzS5sygkU9lPskY57KM7KbmppLDPVi5nIqpsRyFfsbPnGWFfDBMk//nkcfj+dbKJIplVkgg== +jsii@^1.39.0: + version "1.39.0" + resolved "https://registry.npmjs.org/jsii/-/jsii-1.39.0.tgz#68554dd5c20ac4b7da118f748d5297e5f9e58384" + integrity sha512-2ReD7t6rGhT+c41xovFoAMc4XU5/O2VqGRh3Ud/wN+Nn1ISjZFQa4doQ1xtZLFb1065Vxyv5VCqWp80t6Xw2iA== dependencies: - "@jsii/spec" "^1.31.0" - case "^1.6.3" - colors "^1.4.0" - deep-equal "^2.0.5" - fs-extra "^9.1.0" - log4js "^6.3.0" - semver "^7.3.5" - semver-intersect "^1.4.0" - sort-json "^2.0.0" - spdx-license-list "^6.4.0" - typescript "~3.9.9" - yargs "^16.2.0" - -jsii@^1.34.0: - version "1.34.0" - resolved "https://registry.yarnpkg.com/jsii/-/jsii-1.34.0.tgz#d009d7ae36f069819f97dcade4203722a5ec524f" - integrity sha512-z/p8cuWdRntQzdZ1Fq/hvXHPjq/HjZhQzTF/GmYrH3s7Wsb14LphHGAENTZwICBaSovoqSRIboOb2FbPLsCjoA== - dependencies: - "@jsii/check-node" "1.34.0" - "@jsii/spec" "^1.34.0" + "@jsii/check-node" "1.39.0" + "@jsii/spec" "^1.39.0" case "^1.6.3" colors "^1.4.0" deep-equal "^2.0.5" @@ -6106,7 +6089,7 @@ jsii@^1.34.0: json-diff@^0.5.4: version "0.5.4" - resolved "https://registry.yarnpkg.com/json-diff/-/json-diff-0.5.4.tgz#7bc8198c441756632aab66c7d9189d365a7a035a" + resolved "https://registry.npmjs.org/json-diff/-/json-diff-0.5.4.tgz#7bc8198c441756632aab66c7d9189d365a7a035a" integrity sha512-q5Xmx9QXNOzOzIlMoYtLrLiu4Jl/Ce2bn0CNcv54PhyH89CI4GWlGVDye8ei2Ijt9R3U+vsWPsXpLUNob8bs8Q== dependencies: cli-color "~0.1.6" @@ -6115,68 +6098,75 @@ json-diff@^0.5.4: json-parse-better-errors@^1.0.1: version "1.0.2" - resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" + resolved "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== json-parse-even-better-errors@^2.3.0: version "2.3.1" - resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + resolved "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== json-schema-traverse@^0.4.1: version "0.4.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== json-schema-traverse@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" + resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== json-schema@0.2.3: version "0.2.3" - resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" + resolved "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= json-stable-stringify-without-jsonify@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + resolved "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= json-stable-stringify@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" + resolved "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" integrity sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8= dependencies: jsonify "~0.0.0" json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1: version "5.0.1" - resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + resolved "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= -json5@2.x, json5@^2.1.2, json5@^2.2.0: +json5@2.x, json5@^2.1.2: version "2.2.0" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3" + resolved "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3" integrity sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA== dependencies: minimist "^1.2.5" +json5@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" + integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow== + dependencies: + minimist "^1.2.0" + jsonc-parser@~3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.0.0.tgz#abdd785701c7e7eaca8a9ec8cf070ca51a745a22" + resolved "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.0.0.tgz#abdd785701c7e7eaca8a9ec8cf070ca51a745a22" integrity sha512-fQzRfAbIBnR0IQvftw9FJveWiHp72Fg20giDrHz6TdfB12UH/uue0D3hm57UB5KgAVuniLMCaS8P1IMj9NR7cA== jsonfile@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" + resolved "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= optionalDependencies: graceful-fs "^4.1.6" jsonfile@^6.0.1: version "6.1.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" + resolved "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== dependencies: universalify "^2.0.0" @@ -6185,22 +6175,22 @@ jsonfile@^6.0.1: jsonify@~0.0.0: version "0.0.0" - resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" + resolved "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" integrity sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM= jsonparse@^1.2.0, jsonparse@^1.3.1: version "1.3.1" - resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" + resolved "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" integrity sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA= jsonschema@^1.4.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/jsonschema/-/jsonschema-1.4.0.tgz#1afa34c4bc22190d8e42271ec17ac8b3404f87b2" + resolved "https://registry.npmjs.org/jsonschema/-/jsonschema-1.4.0.tgz#1afa34c4bc22190d8e42271ec17ac8b3404f87b2" integrity sha512-/YgW6pRMr6M7C+4o8kS+B/2myEpHCrxO4PEWnqJNBFMjn7EWXqlQ4tGwL6xTHeRplwuZmcAncdvfOad1nT2yMw== jsprim@^1.2.2: version "1.4.1" - resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" + resolved "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI= dependencies: assert-plus "1.0.0" @@ -6208,9 +6198,9 @@ jsprim@^1.2.2: json-schema "0.2.3" verror "1.10.0" -jszip@^3.7.0: +jszip@^3.7.1: version "3.7.1" - resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.7.1.tgz#bd63401221c15625a1228c556ca8a68da6fda3d9" + resolved "https://registry.npmjs.org/jszip/-/jszip-3.7.1.tgz#bd63401221c15625a1228c556ca8a68da6fda3d9" integrity sha512-ghL0tz1XG9ZEmRMcEN2vt7xabrDdqHHeykgARpmZ0BiIctWxM47Vt63ZO2dnp4QYt/xJVLLy5Zv1l/xRdh2byg== dependencies: lie "~3.3.0" @@ -6220,60 +6210,73 @@ jszip@^3.7.0: just-extend@^4.0.2: version "4.2.1" - resolved "https://registry.yarnpkg.com/just-extend/-/just-extend-4.2.1.tgz#ef5e589afb61e5d66b24eca749409a8939a8c744" + resolved "https://registry.npmjs.org/just-extend/-/just-extend-4.2.1.tgz#ef5e589afb61e5d66b24eca749409a8939a8c744" integrity sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg== kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: version "3.2.2" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + resolved "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= dependencies: is-buffer "^1.1.5" kind-of@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" + resolved "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc= dependencies: is-buffer "^1.1.5" kind-of@^5.0.0: version "5.1.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" + resolved "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== kind-of@^6.0.0, kind-of@^6.0.2, kind-of@^6.0.3: version "6.0.3" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" + resolved "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== klaw-sync@^6.0.0: version "6.0.0" - resolved "https://registry.yarnpkg.com/klaw-sync/-/klaw-sync-6.0.0.tgz#1fd2cfd56ebb6250181114f0a581167099c2b28c" + resolved "https://registry.npmjs.org/klaw-sync/-/klaw-sync-6.0.0.tgz#1fd2cfd56ebb6250181114f0a581167099c2b28c" integrity sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ== dependencies: graceful-fs "^4.1.11" kleur@^3.0.3: version "3.0.3" - resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" + resolved "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== +lambda-leak@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/lambda-leak/-/lambda-leak-2.0.0.tgz#771985d3628487f6e885afae2b54510dcfb2cd7e" + integrity sha1-dxmF02KEh/boha+uK1RRDc+yzX4= + +lambda-tester@^3.6.0: + version "3.6.0" + resolved "https://registry.npmjs.org/lambda-tester/-/lambda-tester-3.6.0.tgz#ceb7d4f4f0da768487a05cff37dcd088508b5247" + integrity sha512-F2ZTGWCLyIR95o/jWK46V/WnOCFAEUG/m/V7/CLhPJ7PCM+pror1rZ6ujP3TkItSGxUfpJi0kqwidw+M/nEqWw== + dependencies: + app-root-path "^2.2.1" + dotenv "^8.0.0" + dotenv-json "^1.0.0" + lambda-leak "^2.0.0" + semver "^6.1.1" + uuid "^3.3.2" + vandium-utils "^1.1.1" + lazystream@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/lazystream/-/lazystream-1.0.0.tgz#f6995fe0f820392f61396be89462407bb77168e4" + resolved "https://registry.npmjs.org/lazystream/-/lazystream-1.0.0.tgz#f6995fe0f820392f61396be89462407bb77168e4" integrity sha1-9plf4PggOS9hOWvolGJAe7dxaOQ= dependencies: readable-stream "^2.0.5" -lcov-parse@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/lcov-parse/-/lcov-parse-1.0.0.tgz#eb0d46b54111ebc561acb4c408ef9363bdc8f7e0" - integrity sha1-6w1GtUER68VhrLTECO+TY73I9+A= - lerna@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/lerna/-/lerna-4.0.0.tgz#b139d685d50ea0ca1be87713a7c2f44a5b678e9e" + resolved "https://registry.npmjs.org/lerna/-/lerna-4.0.0.tgz#b139d685d50ea0ca1be87713a7c2f44a5b678e9e" integrity sha512-DD/i1znurfOmNJb0OBw66NmNqiM8kF6uIrzrJ0wGE3VNdzeOhz9ziWLYiRaZDGGwgbcjOo6eIfcx9O5Qynz+kg== dependencies: "@lerna/add" "4.0.0" @@ -6297,12 +6300,12 @@ lerna@^4.0.0: leven@^3.1.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" + resolved "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== levn@^0.4.1: version "0.4.1" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + resolved "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== dependencies: prelude-ls "^1.2.1" @@ -6310,7 +6313,7 @@ levn@^0.4.1: levn@~0.3.0: version "0.3.0" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + resolved "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= dependencies: prelude-ls "~1.1.2" @@ -6318,7 +6321,7 @@ levn@~0.3.0: libnpmaccess@^4.0.1: version "4.0.3" - resolved "https://registry.yarnpkg.com/libnpmaccess/-/libnpmaccess-4.0.3.tgz#dfb0e5b0a53c315a2610d300e46b4ddeb66e7eec" + resolved "https://registry.npmjs.org/libnpmaccess/-/libnpmaccess-4.0.3.tgz#dfb0e5b0a53c315a2610d300e46b4ddeb66e7eec" integrity sha512-sPeTSNImksm8O2b6/pf3ikv4N567ERYEpeKRPSmqlNt1dTZbvgpJIzg5vAhXHpw2ISBsELFRelk0jEahj1c6nQ== dependencies: aproba "^2.0.0" @@ -6328,7 +6331,7 @@ libnpmaccess@^4.0.1: libnpmpublish@^4.0.0: version "4.0.2" - resolved "https://registry.yarnpkg.com/libnpmpublish/-/libnpmpublish-4.0.2.tgz#be77e8bf5956131bcb45e3caa6b96a842dec0794" + resolved "https://registry.npmjs.org/libnpmpublish/-/libnpmpublish-4.0.2.tgz#be77e8bf5956131bcb45e3caa6b96a842dec0794" integrity sha512-+AD7A2zbVeGRCFI2aO//oUmapCwy7GHqPXFJh3qpToSRNU+tXKJ2YFUgjt04LPPAf2dlEH95s6EhIHM1J7bmOw== dependencies: normalize-package-data "^3.0.2" @@ -6339,26 +6342,31 @@ libnpmpublish@^4.0.0: lie@~3.3.0: version "3.3.0" - resolved "https://registry.yarnpkg.com/lie/-/lie-3.3.0.tgz#dcf82dee545f46074daf200c7c1c5a08e0f40f6a" + resolved "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz#dcf82dee545f46074daf200c7c1c5a08e0f40f6a" integrity sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ== dependencies: immediate "~3.0.5" +line-reader@^0.2.4: + version "0.2.4" + resolved "https://registry.npmjs.org/line-reader/-/line-reader-0.2.4.tgz#c4392b587dea38580c9678570e6e8e49fce52622" + integrity sha1-xDkrWH3qOFgMlnhXDm6OSfzlJiI= + lines-and-columns@^1.1.6: version "1.1.6" - resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" + resolved "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA= linkify-it@^3.0.1: - version "3.0.2" - resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-3.0.2.tgz#f55eeb8bc1d3ae754049e124ab3bb56d97797fb8" - integrity sha512-gDBO4aHNZS6coiZCKVhSNh43F9ioIL4JwRjLZPkoLIY4yZFwg264Y5lu2x6rb1Js42Gh6Yqm2f6L2AJcnkzinQ== + version "3.0.3" + resolved "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz#a98baf44ce45a550efb4d49c769d07524cc2fa2e" + integrity sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ== dependencies: uc.micro "^1.0.1" load-json-file@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b" + resolved "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b" integrity sha1-L19Fq5HjMhYjT9U62rZo607AmTs= dependencies: graceful-fs "^4.1.2" @@ -6368,7 +6376,7 @@ load-json-file@^4.0.0: load-json-file@^6.2.0: version "6.2.0" - resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-6.2.0.tgz#5c7770b42cafa97074ca2848707c61662f4251a1" + resolved "https://registry.npmjs.org/load-json-file/-/load-json-file-6.2.0.tgz#5c7770b42cafa97074ca2848707c61662f4251a1" integrity sha512-gUD/epcRms75Cw8RT1pUdHugZYM5ce64ucs2GEISABwkRsOQr0q2wm/MV2TKThycIe5e0ytRweW2RZxclogCdQ== dependencies: graceful-fs "^4.1.15" @@ -6378,7 +6386,7 @@ load-json-file@^6.2.0: locate-path@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" + resolved "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= dependencies: p-locate "^2.0.0" @@ -6386,7 +6394,7 @@ locate-path@^2.0.0: locate-path@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" + resolved "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== dependencies: p-locate "^3.0.0" @@ -6394,81 +6402,81 @@ locate-path@^3.0.0: locate-path@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + resolved "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== dependencies: p-locate "^4.1.0" locate-path@^6.0.0: version "6.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + resolved "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== dependencies: p-locate "^5.0.0" lodash._reinterpolate@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" + resolved "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" integrity sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0= lodash.clonedeep@^4.5.0: version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" + resolved "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8= lodash.defaults@^4.2.0: version "4.2.0" - resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" + resolved "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" integrity sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw= lodash.difference@^4.5.0: version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.difference/-/lodash.difference-4.5.0.tgz#9ccb4e505d486b91651345772885a2df27fd017c" + resolved "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz#9ccb4e505d486b91651345772885a2df27fd017c" integrity sha1-nMtOUF1Ia5FlE0V3KIWi3yf9AXw= lodash.differencewith@~4.5.0: version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.differencewith/-/lodash.differencewith-4.5.0.tgz#bafafbc918b55154e179176a00bb0aefaac854b7" + resolved "https://registry.npmjs.org/lodash.differencewith/-/lodash.differencewith-4.5.0.tgz#bafafbc918b55154e179176a00bb0aefaac854b7" integrity sha1-uvr7yRi1UVTheRdqALsK76rIVLc= lodash.flatten@^4.4.0, lodash.flatten@~4.4.0: version "4.4.0" - resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f" + resolved "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f" integrity sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8= lodash.flattendeep@^4.4.0: version "4.4.0" - resolved "https://registry.yarnpkg.com/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz#fb030917f86a3134e5bc9bec0d69e0013ddfedb2" + resolved "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz#fb030917f86a3134e5bc9bec0d69e0013ddfedb2" integrity sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI= lodash.get@^4.4.2: version "4.4.2" - resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" + resolved "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" integrity sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk= lodash.ismatch@^4.4.0: version "4.4.0" - resolved "https://registry.yarnpkg.com/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz#756cb5150ca3ba6f11085a78849645f188f85f37" + resolved "https://registry.npmjs.org/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz#756cb5150ca3ba6f11085a78849645f188f85f37" integrity sha1-dWy1FQyjum8RCFp4hJZF8Yj4Xzc= lodash.isplainobject@^4.0.6: version "4.0.6" - resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" + resolved "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" integrity sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs= lodash.merge@^4.6.2: version "4.6.2" - resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== lodash.set@^4.3.2: version "4.3.2" - resolved "https://registry.yarnpkg.com/lodash.set/-/lodash.set-4.3.2.tgz#d8757b1da807dde24816b0d6a84bea1a76230b23" + resolved "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz#d8757b1da807dde24816b0d6a84bea1a76230b23" integrity sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM= lodash.template@^4.5.0: version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.5.0.tgz#f976195cf3f347d0d5f52483569fe8031ccce8ab" + resolved "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz#f976195cf3f347d0d5f52483569fe8031ccce8ab" integrity sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A== dependencies: lodash._reinterpolate "^3.0.0" @@ -6476,39 +6484,34 @@ lodash.template@^4.5.0: lodash.templatesettings@^4.0.0: version "4.2.0" - resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz#e481310f049d3cf6d47e912ad09313b154f0fb33" + resolved "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz#e481310f049d3cf6d47e912ad09313b154f0fb33" integrity sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ== dependencies: lodash._reinterpolate "^3.0.0" lodash.truncate@^4.4.2: version "4.4.2" - resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193" + resolved "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193" integrity sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM= lodash.union@^4.6.0: version "4.6.0" - resolved "https://registry.yarnpkg.com/lodash.union/-/lodash.union-4.6.0.tgz#48bb5088409f16f1821666641c44dd1aaae3cd88" + resolved "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz#48bb5088409f16f1821666641c44dd1aaae3cd88" integrity sha1-SLtQiECfFvGCFmZkHETdGqrjzYg= lodash.uniq@^4.5.0: version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" + resolved "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= lodash@4.x, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.21, lodash@^4.7.0: version "4.17.21" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== -log-driver@^1.2.7: - version "1.2.7" - resolved "https://registry.yarnpkg.com/log-driver/-/log-driver-1.2.7.tgz#63b95021f0702fedfa2c9bb0a24e7797d71871d8" - integrity sha512-U7KCmLdqsGHBLeWqYlFA0V0Sl6P08EE1ZrmA9cxjUE0WVqT9qnyVDPz1kzpFEP0jdJuFnasWIfSd7fsaNXkpbg== - log4js@^6.3.0: version "6.3.0" - resolved "https://registry.yarnpkg.com/log4js/-/log4js-6.3.0.tgz#10dfafbb434351a3e30277a00b9879446f715bcb" + resolved "https://registry.npmjs.org/log4js/-/log4js-6.3.0.tgz#10dfafbb434351a3e30277a00b9879446f715bcb" integrity sha512-Mc8jNuSFImQUIateBFwdOQcmC6Q5maU0VVvdC2R6XMb66/VnT+7WS4D/0EeNMZu1YODmJe5NIn2XftCzEocUgw== dependencies: date-format "^3.0.0" @@ -6517,36 +6520,28 @@ log4js@^6.3.0: rfdc "^1.1.4" streamroller "^2.2.4" -lru-cache@^4.0.1: - version "4.1.5" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" - integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g== - dependencies: - pseudomap "^1.0.2" - yallist "^2.1.2" - lru-cache@^5.1.1: version "5.1.1" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== dependencies: yallist "^3.0.2" lru-cache@^6.0.0: version "6.0.0" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== dependencies: yallist "^4.0.0" macos-release@^2.2.0: version "2.5.0" - resolved "https://registry.yarnpkg.com/macos-release/-/macos-release-2.5.0.tgz#067c2c88b5f3fb3c56a375b2ec93826220fa1ff2" + resolved "https://registry.npmjs.org/macos-release/-/macos-release-2.5.0.tgz#067c2c88b5f3fb3c56a375b2ec93826220fa1ff2" integrity sha512-EIgv+QZ9r+814gjJj0Bt5vSLJLzswGmSUbUpbi9AIr/fsN2IWFBl2NucV9PAiek+U1STK468tEkxmVYUtuAN3g== -make-dir@^2.0.0, make-dir@^2.1.0: +make-dir@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" + resolved "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== dependencies: pify "^4.0.1" @@ -6554,19 +6549,19 @@ make-dir@^2.0.0, make-dir@^2.1.0: make-dir@^3.0.0, make-dir@^3.0.2: version "3.1.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" + resolved "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== dependencies: semver "^6.0.0" make-error@1.x, make-error@^1.1.1: version "1.3.6" - resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" + resolved "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== make-fetch-happen@^8.0.9: version "8.0.14" - resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-8.0.14.tgz#aaba73ae0ab5586ad8eaa68bd83332669393e222" + resolved "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-8.0.14.tgz#aaba73ae0ab5586ad8eaa68bd83332669393e222" integrity sha512-EsS89h6l4vbfJEtBZnENTOFk8mCRpY5ru36Xe5bcX1KYIli2mkSHqoFsp5O1wMDvTJJzxe/4THpCTtygjeeGWQ== dependencies: agentkeepalive "^4.1.3" @@ -6586,9 +6581,9 @@ make-fetch-happen@^8.0.9: ssri "^8.0.0" make-fetch-happen@^9.0.1: - version "9.0.4" - resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-9.0.4.tgz#ceaa100e60e0ef9e8d1ede94614bb2ba83c8bb24" - integrity sha512-sQWNKMYqSmbAGXqJg2jZ+PmHh5JAybvwu0xM8mZR/bsTjGiTASj3ldXJV7KFHy1k/IJIBkjxQFoWIVsv9+PQMg== + version "9.1.0" + resolved "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz#53085a09e7971433e6765f7971bf63f4e05cb968" + integrity sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg== dependencies: agentkeepalive "^4.1.3" cacache "^15.2.0" @@ -6604,12 +6599,12 @@ make-fetch-happen@^9.0.1: minipass-pipeline "^1.2.4" negotiator "^0.6.2" promise-retry "^2.0.1" - socks-proxy-agent "^5.0.0" + socks-proxy-agent "^6.0.0" ssri "^8.0.0" make-runnable@^1.3.10: version "1.3.10" - resolved "https://registry.yarnpkg.com/make-runnable/-/make-runnable-1.3.10.tgz#c89f89e35ffd2dd88fd0ec1b06650e8357577c87" + resolved "https://registry.npmjs.org/make-runnable/-/make-runnable-1.3.10.tgz#c89f89e35ffd2dd88fd0ec1b06650e8357577c87" integrity sha512-ec9hxTJip4ncG3TqZrkoR69oKdxFyJDq40A4sGNwGYVtl4Q10V4BhqnTGLUyJxQIxobhTqwxkgEFbGh77RmV7A== dependencies: bluebird "^3.5.0" @@ -6617,37 +6612,37 @@ make-runnable@^1.3.10: makeerror@1.0.x: version "1.0.11" - resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" + resolved "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" integrity sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw= dependencies: tmpl "1.0.x" map-cache@^0.2.2: version "0.2.2" - resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" + resolved "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= map-obj@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" + resolved "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" integrity sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0= map-obj@^4.0.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-4.2.1.tgz#e4ea399dbc979ae735c83c863dd31bdf364277b7" - integrity sha512-+WA2/1sPmDj1dlvvJmB5G6JKfY9dpn7EVBUL06+y6PoljPkh+6V1QihwxNkbcGxCRjt2b0F9K0taiCuo7MbdFQ== + version "4.3.0" + resolved "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz#9304f906e93faae70880da102a9f1df0ea8bb05a" + integrity sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ== map-visit@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" + resolved "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= dependencies: object-visit "^1.0.0" -markdown-it@12.0.4: - version "12.0.4" - resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-12.0.4.tgz#eec8247d296327eac3ba9746bdeec9cfcc751e33" - integrity sha512-34RwOXZT8kyuOJy25oJNJoulO8L0bTHYWXcdZBYZqFnjIy3NgjeoM3FmPXIOFQ26/lSHYMr8oc62B6adxXcb3Q== +markdown-it@12.2.0: + version "12.2.0" + resolved "https://registry.npmjs.org/markdown-it/-/markdown-it-12.2.0.tgz#091f720fd5db206f80de7a8d1f1a7035fd0d38db" + integrity sha512-Wjws+uCrVQRqOoJvze4HCqkKl1AsSh95iFAeQDwnyfxM09divCBSXlDR1uTvyUP3Grzpn4Ru8GeCxYPM8vkCQg== dependencies: argparse "^2.0.1" entities "~2.1.0" @@ -6655,41 +6650,41 @@ markdown-it@12.0.4: mdurl "^1.0.1" uc.micro "^1.0.5" -markdownlint-cli@^0.27.1: - version "0.27.1" - resolved "https://registry.yarnpkg.com/markdownlint-cli/-/markdownlint-cli-0.27.1.tgz#8fa095eea94936b6dea891f9db7f269c60e6d6fa" - integrity sha512-p1VV6aSbGrDlpUWzHizAnSNEQAweVR3qUI/AIUubxW7BGPXziSXkIED+uRtSohUlRS/jmqp3Wi4es5j6fIrdeQ== +markdownlint-cli@^0.29.0: + version "0.29.0" + resolved "https://registry.npmjs.org/markdownlint-cli/-/markdownlint-cli-0.29.0.tgz#3c56686fd00ace4b68c9cfa3a34a7a9dfdef1417" + integrity sha512-SEXRUT1ri9sXV8xQK88vjGAgmz2X9rxEG2tXdDZMljzW8e++LNTO9zzBBStx3JQWrTDoGTPHNrcurbuiyF97gw== dependencies: - commander "~7.1.0" + commander "~8.2.0" deep-extend "~0.6.0" get-stdin "~8.0.0" - glob "~7.1.6" + glob "~7.2.0" ignore "~5.1.8" - js-yaml "^4.0.0" + js-yaml "^4.1.0" jsonc-parser "~3.0.0" lodash.differencewith "~4.5.0" lodash.flatten "~4.4.0" - markdownlint "~0.23.1" - markdownlint-rule-helpers "~0.14.0" + markdownlint "~0.24.0" + markdownlint-rule-helpers "~0.15.0" minimatch "~3.0.4" minimist "~1.2.5" - rc "~1.2.8" + run-con "~1.2.10" -markdownlint-rule-helpers@~0.14.0: - version "0.14.0" - resolved "https://registry.yarnpkg.com/markdownlint-rule-helpers/-/markdownlint-rule-helpers-0.14.0.tgz#4d0e1ae320e85559d8cbed1490934855791627bb" - integrity sha512-vRTPqSU4JK8vVXmjICHSBhwXUvbfh/VJo+j7hvxqe15tLJyomv3FLgFdFgb8kpj0Fe8SsJa/TZUAXv7/sN+N7A== +markdownlint-rule-helpers@~0.15.0: + version "0.15.0" + resolved "https://registry.npmjs.org/markdownlint-rule-helpers/-/markdownlint-rule-helpers-0.15.0.tgz#11434c573649b9235ae70b967314f5711f7d8fa8" + integrity sha512-A+9mswc3m/kkqpJCqntmte/1VKhDJ+tjZsERLz5L4h/Qr7ht2/BkGkgY5E7/wsxIhcpl+ctIfz+oS3PQrMOB2w== -markdownlint@~0.23.1: - version "0.23.1" - resolved "https://registry.yarnpkg.com/markdownlint/-/markdownlint-0.23.1.tgz#98292b5d340d01e9c113f3d7fb3b2ccf89628dc2" - integrity sha512-iOEwhDfNmq2IJlaA8mzEkHYUi/Hwoa6Ss+HO5jkwUR6wQ4quFr0WzSx+Z9rsWZKUaPbyirIdL1zGmJRkWawr4Q== +markdownlint@~0.24.0: + version "0.24.0" + resolved "https://registry.npmjs.org/markdownlint/-/markdownlint-0.24.0.tgz#224b53f671367a237d40c8be1745c7be9a322671" + integrity sha512-OJIGsGFV/rC9irI5E1FMy6v9hdACSwaa+EN3224Y5KG8zj2EYzdHOw0pOJovIYmjNfEZ9BtxUY4P7uYHTSNnbQ== dependencies: - markdown-it "12.0.4" + markdown-it "12.2.0" md5@^2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/md5/-/md5-2.3.0.tgz#c3da9a6aae3a30b46b7b0c349b87b110dc3bda4f" + resolved "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz#c3da9a6aae3a30b46b7b0c349b87b110dc3bda4f" integrity sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g== dependencies: charenc "0.0.2" @@ -6698,29 +6693,12 @@ md5@^2.3.0: mdurl@^1.0.1, mdurl@~1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" + resolved "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" integrity sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4= -meow@^7.0.0: - version "7.1.1" - resolved "https://registry.yarnpkg.com/meow/-/meow-7.1.1.tgz#7c01595e3d337fcb0ec4e8eed1666ea95903d306" - integrity sha512-GWHvA5QOcS412WCo8vwKDlTelGLsCGBVevQB5Kva961rmNfun0PCbv5+xta2kUMFJyR8/oWnn7ddeKdosbAPbA== - dependencies: - "@types/minimist" "^1.2.0" - camelcase-keys "^6.2.2" - decamelize-keys "^1.1.0" - hard-rejection "^2.1.0" - minimist-options "4.1.0" - normalize-package-data "^2.5.0" - read-pkg-up "^7.0.1" - redent "^3.0.0" - trim-newlines "^3.0.0" - type-fest "^0.13.1" - yargs-parser "^18.1.3" - meow@^8.0.0: version "8.1.2" - resolved "https://registry.yarnpkg.com/meow/-/meow-8.1.2.tgz#bcbe45bda0ee1729d350c03cffc8395a36c4e897" + resolved "https://registry.npmjs.org/meow/-/meow-8.1.2.tgz#bcbe45bda0ee1729d350c03cffc8395a36c4e897" integrity sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q== dependencies: "@types/minimist" "^1.2.0" @@ -6737,29 +6715,22 @@ meow@^8.0.0: merge-descriptors@~1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + resolved "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= -merge-source-map@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/merge-source-map/-/merge-source-map-1.1.0.tgz#2fdde7e6020939f70906a68f2d7ae685e4c8c646" - integrity sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw== - dependencies: - source-map "^0.6.1" - merge-stream@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + resolved "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== merge2@^1.3.0: version "1.4.1" - resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + resolved "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== micromatch@^3.1.4: version "3.1.10" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" + resolved "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== dependencies: arr-diff "^4.0.0" @@ -6778,49 +6749,49 @@ micromatch@^3.1.4: micromatch@^4.0.2, micromatch@^4.0.4: version "4.0.4" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9" + resolved "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9" integrity sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg== dependencies: braces "^3.0.1" picomatch "^2.2.3" -mime-db@1.48.0: - version "1.48.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.48.0.tgz#e35b31045dd7eada3aaad537ed88a33afbef2d1d" - integrity sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ== +mime-db@1.50.0: + version "1.50.0" + resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.50.0.tgz#abd4ac94e98d3c0e185016c67ab45d5fde40c11f" + integrity sha512-9tMZCDlYHqeERXEHO9f/hKfNXhre5dK2eE/krIvUjZbS2KPcqGDfNShIWS1uW9XOTKQKqK6qbeOci18rbfW77A== mime-types@^2.1.12, mime-types@~2.1.19: - version "2.1.31" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.31.tgz#a00d76b74317c61f9c2db2218b8e9f8e9c5c9e6b" - integrity sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg== + version "2.1.33" + resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.33.tgz#1fa12a904472fafd068e48d9e8401f74d3f70edb" + integrity sha512-plLElXp7pRDd0bNZHw+nMd52vRYjLwQjygaNg7ddJ2uJtTlmnTCjWuPKxVu6//AdaRuME84SvLW91sIkBqGT0g== dependencies: - mime-db "1.48.0" + mime-db "1.50.0" mime@^2.5.2: version "2.5.2" - resolved "https://registry.yarnpkg.com/mime/-/mime-2.5.2.tgz#6e3dc6cc2b9510643830e5f19d5cb753da5eeabe" + resolved "https://registry.npmjs.org/mime/-/mime-2.5.2.tgz#6e3dc6cc2b9510643830e5f19d5cb753da5eeabe" integrity sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg== mimic-fn@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== min-indent@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" + resolved "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== minimatch@>=3.0, minimatch@^3.0.4, minimatch@~3.0.4: version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== dependencies: brace-expansion "^1.1.7" minimist-options@4.1.0: version "4.1.0" - resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-4.1.0.tgz#c0655713c53a8a2ebd77ffa247d342c40f010619" + resolved "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz#c0655713c53a8a2ebd77ffa247d342c40f010619" integrity sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A== dependencies: arrify "^1.0.1" @@ -6829,20 +6800,20 @@ minimist-options@4.1.0: minimist@>=1.2.2, minimist@^1.1.1, minimist@^1.2.0, minimist@^1.2.5, minimist@~1.2.5: version "1.2.5" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" + resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== minipass-collect@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/minipass-collect/-/minipass-collect-1.0.2.tgz#22b813bf745dc6edba2576b940022ad6edc8c617" + resolved "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz#22b813bf745dc6edba2576b940022ad6edc8c617" integrity sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA== dependencies: minipass "^3.0.0" minipass-fetch@^1.3.0, minipass-fetch@^1.3.2: - version "1.3.4" - resolved "https://registry.yarnpkg.com/minipass-fetch/-/minipass-fetch-1.3.4.tgz#63f5af868a38746ca7b33b03393ddf8c291244fe" - integrity sha512-TielGogIzbUEtd1LsjZFs47RWuHHfhl6TiCx1InVxApBAmQ8bL0dL5ilkLGcRvuyW/A9nE+Lvn855Ewz8S0PnQ== + version "1.4.1" + resolved "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-1.4.1.tgz#d75e0091daac1b0ffd7e9d41629faff7d0c1f1b6" + integrity sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw== dependencies: minipass "^3.1.0" minipass-sized "^1.0.3" @@ -6852,14 +6823,14 @@ minipass-fetch@^1.3.0, minipass-fetch@^1.3.2: minipass-flush@^1.0.5: version "1.0.5" - resolved "https://registry.yarnpkg.com/minipass-flush/-/minipass-flush-1.0.5.tgz#82e7135d7e89a50ffe64610a787953c4c4cbb373" + resolved "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz#82e7135d7e89a50ffe64610a787953c4c4cbb373" integrity sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw== dependencies: minipass "^3.0.0" minipass-json-stream@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz#7edbb92588fbfc2ff1db2fc10397acb7b6b44aa7" + resolved "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz#7edbb92588fbfc2ff1db2fc10397acb7b6b44aa7" integrity sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg== dependencies: jsonparse "^1.3.1" @@ -6867,43 +6838,43 @@ minipass-json-stream@^1.0.1: minipass-pipeline@^1.2.2, minipass-pipeline@^1.2.4: version "1.2.4" - resolved "https://registry.yarnpkg.com/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz#68472f79711c084657c067c5c6ad93cddea8214c" + resolved "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz#68472f79711c084657c067c5c6ad93cddea8214c" integrity sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A== dependencies: minipass "^3.0.0" minipass-sized@^1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/minipass-sized/-/minipass-sized-1.0.3.tgz#70ee5a7c5052070afacfbc22977ea79def353b70" + resolved "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz#70ee5a7c5052070afacfbc22977ea79def353b70" integrity sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g== dependencies: minipass "^3.0.0" -minipass@^2.2.0, minipass@^2.3.5, minipass@^2.6.0, minipass@^2.9.0: +minipass@^2.6.0, minipass@^2.9.0: version "2.9.0" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.9.0.tgz#e713762e7d3e32fed803115cf93e04bca9fcc9a6" + resolved "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz#e713762e7d3e32fed803115cf93e04bca9fcc9a6" integrity sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg== dependencies: safe-buffer "^5.1.2" yallist "^3.0.0" minipass@^3.0.0, minipass@^3.1.0, minipass@^3.1.1, minipass@^3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.1.3.tgz#7d42ff1f39635482e15f9cdb53184deebd5815fd" - integrity sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg== + version "3.1.5" + resolved "https://registry.npmjs.org/minipass/-/minipass-3.1.5.tgz#71f6251b0a33a49c01b3cf97ff77eda030dff732" + integrity sha512-+8NzxD82XQoNKNrl1d/FSi+X8wAEWR+sbYAfIvub4Nz0d22plFG72CEVVaufV8PNf4qSslFTD8VMOxNVhHCjTw== dependencies: yallist "^4.0.0" minizlib@^1.3.3: version "1.3.3" - resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.3.3.tgz#2290de96818a34c29551c8a8d301216bd65a861d" + resolved "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz#2290de96818a34c29551c8a8d301216bd65a861d" integrity sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q== dependencies: minipass "^2.9.0" minizlib@^2.0.0, minizlib@^2.1.1: version "2.1.2" - resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" + resolved "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg== dependencies: minipass "^3.0.0" @@ -6911,7 +6882,7 @@ minizlib@^2.0.0, minizlib@^2.1.1: mixin-deep@^1.2.0: version "1.3.2" - resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" + resolved "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== dependencies: for-in "^1.0.2" @@ -6919,7 +6890,7 @@ mixin-deep@^1.2.0: mkdirp-infer-owner@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/mkdirp-infer-owner/-/mkdirp-infer-owner-2.0.0.tgz#55d3b368e7d89065c38f32fd38e638f0ab61d316" + resolved "https://registry.npmjs.org/mkdirp-infer-owner/-/mkdirp-infer-owner-2.0.0.tgz#55d3b368e7d89065c38f32fd38e638f0ab61d316" integrity sha512-sdqtiFt3lkOaYvTXSRIUjkIdPTcxgv5+fgqYE/5qgwdw12cOrAuzzgzvVExIkH/ul1oeHN3bCLOWSG3XOqbKKw== dependencies: chownr "^2.0.0" @@ -6928,54 +6899,54 @@ mkdirp-infer-owner@^2.0.0: mkdirp@1.x, mkdirp@^1.0.3, mkdirp@^1.0.4: version "1.0.4" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" + resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== -mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@^0.5.5: +mkdirp@^0.5.1, mkdirp@^0.5.5: version "0.5.5" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" + resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== dependencies: minimist "^1.2.5" mock-fs@^4.14.0: version "4.14.0" - resolved "https://registry.yarnpkg.com/mock-fs/-/mock-fs-4.14.0.tgz#ce5124d2c601421255985e6e94da80a7357b1b18" + resolved "https://registry.npmjs.org/mock-fs/-/mock-fs-4.14.0.tgz#ce5124d2c601421255985e6e94da80a7357b1b18" integrity sha512-qYvlv/exQ4+svI3UOvPUpLDF0OMX5euvUH0Ny4N5QyRyhNdgAgUrVH3iUINSzEPLvx0kbo/Bp28GJKIqvE7URw== mockery@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/mockery/-/mockery-2.1.0.tgz#5b0aef1ff564f0f8139445e165536c7909713470" + resolved "https://registry.npmjs.org/mockery/-/mockery-2.1.0.tgz#5b0aef1ff564f0f8139445e165536c7909713470" integrity sha512-9VkOmxKlWXoDO/h1jDZaS4lH33aWfRiJiNT/tKj+8OGzrcFDLo8d0syGdbsc3Bc4GvRXPb+NMMvojotmuGJTvA== modify-values@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/modify-values/-/modify-values-1.0.1.tgz#b3939fa605546474e3e3e3c63d64bd43b4ee6022" + resolved "https://registry.npmjs.org/modify-values/-/modify-values-1.0.1.tgz#b3939fa605546474e3e3e3c63d64bd43b4ee6022" integrity sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw== module-not-found-error@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/module-not-found-error/-/module-not-found-error-1.0.1.tgz#cf8b4ff4f29640674d6cdd02b0e3bc523c2bbdc0" + resolved "https://registry.npmjs.org/module-not-found-error/-/module-not-found-error-1.0.1.tgz#cf8b4ff4f29640674d6cdd02b0e3bc523c2bbdc0" integrity sha1-z4tP9PKWQGdNbN0CsOO8UjwrvcA= ms@2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= ms@2.1.2: version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== ms@^2.0.0, ms@^2.1.1: version "2.1.3" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== multimatch@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/multimatch/-/multimatch-5.0.0.tgz#932b800963cea7a31a033328fa1e0c3a1874dbe6" + resolved "https://registry.npmjs.org/multimatch/-/multimatch-5.0.0.tgz#932b800963cea7a31a033328fa1e0c3a1874dbe6" integrity sha512-ypMKuglUrZUD99Tk2bUQ+xNQj43lPEfAeX2o9cTteAmShXy2VHDJpuwu1o0xqoKCt9jLVAvwyFKdLTPXKAfJyA== dependencies: "@types/minimatch" "^3.0.3" @@ -6986,12 +6957,12 @@ multimatch@^5.0.0: mute-stream@0.0.8, mute-stream@~0.0.4: version "0.0.8" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" + resolved "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== nanomatch@^1.2.9: version "1.2.13" - resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" + resolved "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== dependencies: arr-diff "^4.0.0" @@ -7008,37 +6979,32 @@ nanomatch@^1.2.9: natural-compare@^1.4.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= negotiator@^0.6.2: version "0.6.2" - resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" + resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== neo-async@^2.6.0: version "2.6.2" - resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" + resolved "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== -nested-error-stacks@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/nested-error-stacks/-/nested-error-stacks-2.1.0.tgz#0fbdcf3e13fe4994781280524f8b96b0cdff9c61" - integrity sha512-AO81vsIO1k1sM4Zrd6Hu7regmJN1NSiAja10gc4bX3F0wd+9rQmcuHQaHVQCYIEC8iFXnE+mavh23GOt7wBgug== - netmask@^2.0.1: version "2.0.2" - resolved "https://registry.yarnpkg.com/netmask/-/netmask-2.0.2.tgz#8b01a07644065d536383835823bc52004ebac5e7" + resolved "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz#8b01a07644065d536383835823bc52004ebac5e7" integrity sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg== nice-try@^1.0.4: version "1.0.5" - resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" + resolved "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== nise@^4.0.4: version "4.1.0" - resolved "https://registry.yarnpkg.com/nise/-/nise-4.1.0.tgz#8fb75a26e90b99202fa1e63f448f58efbcdedaf6" + resolved "https://registry.npmjs.org/nise/-/nise-4.1.0.tgz#8fb75a26e90b99202fa1e63f448f58efbcdedaf6" integrity sha512-eQMEmGN/8arp0xsvGoQ+B1qvSkR73B1nWSCh7nOt5neMCtwcQVYQGdzQMhcNscktTsWB54xnlSQFzOAPJD8nXA== dependencies: "@sinonjs/commons" "^1.7.0" @@ -7049,7 +7015,7 @@ nise@^4.0.4: nise@^5.1.0: version "5.1.0" - resolved "https://registry.yarnpkg.com/nise/-/nise-5.1.0.tgz#713ef3ed138252daef20ec035ab62b7a28be645c" + resolved "https://registry.npmjs.org/nise/-/nise-5.1.0.tgz#713ef3ed138252daef20ec035ab62b7a28be645c" integrity sha512-W5WlHu+wvo3PaKLsJJkgPup2LrsXCcm7AWwyNZkUnn5rwPkuPBi3Iwk5SQtN0mv+K65k7nKKjwNQ30wg3wLAQQ== dependencies: "@sinonjs/commons" "^1.7.0" @@ -7058,10 +7024,10 @@ nise@^5.1.0: just-extend "^4.0.2" path-to-regexp "^1.7.0" -nock@^13.1.1: - version "13.1.1" - resolved "https://registry.yarnpkg.com/nock/-/nock-13.1.1.tgz#3c830129d4560957f59b6f480a41ddbaf9cf57af" - integrity sha512-YKTR9MjfK3kS9/l4nuTxyYm30cgOExRHzkLNhL8nhEUyU4f8Za/dRxOqjhVT1vGs0svWo3dDnJTUX1qxYeWy5w== +nock@^13.1.3: + version "13.1.3" + resolved "https://registry.npmjs.org/nock/-/nock-13.1.3.tgz#110b005965654a8ffb798e87bad18b467bff15f9" + integrity sha512-YKj0rKQWMGiiIO+Y65Ut8OEgYM3PplLU2+GAhnPmqZdBd6z5IskgdBqWmjzA6lH3RF0S2a3wiAlrMOF5Iv2Jeg== dependencies: debug "^4.1.0" json-stringify-safe "^5.0.1" @@ -7069,13 +7035,15 @@ nock@^13.1.1: propagate "^2.0.0" node-fetch@^2.6.1: - version "2.6.1" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" - integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== + version "2.6.5" + resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.5.tgz#42735537d7f080a7e5f78b6c549b7146be1742fd" + integrity sha512-mmlIVHJEu5rnIxgEgez6b9GgWXbkZj5YZ7fx+2r94a2E+Uirsp6HsPTPlomfdHtpt/B0cdKviwkoaM6pyvUOpQ== + dependencies: + whatwg-url "^5.0.0" node-gyp@^5.0.2: version "5.1.1" - resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-5.1.1.tgz#eb915f7b631c937d282e33aed44cb7a025f62a3e" + resolved "https://registry.npmjs.org/node-gyp/-/node-gyp-5.1.1.tgz#eb915f7b631c937d282e33aed44cb7a025f62a3e" integrity sha512-WH0WKGi+a4i4DUt2mHnvocex/xPLp9pYt5R6M2JdFB7pJ7Z34hveZ4nDTGTiLXCkitA9T8HFZjhinBCiVHYcWw== dependencies: env-paths "^2.2.0" @@ -7092,7 +7060,7 @@ node-gyp@^5.0.2: node-gyp@^7.1.0: version "7.1.2" - resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-7.1.2.tgz#21a810aebb187120251c3bcec979af1587b188ae" + resolved "https://registry.npmjs.org/node-gyp/-/node-gyp-7.1.2.tgz#21a810aebb187120251c3bcec979af1587b188ae" integrity sha512-CbpcIo7C3eMu3dL1c3d0xw449fHIGALIJsRP4DDPHpyiW8vcriNY7ubh9TE4zEKfSxscY7PjeFnshE7h75ynjQ== dependencies: env-paths "^2.2.0" @@ -7108,17 +7076,17 @@ node-gyp@^7.1.0: node-int64@^0.4.0: version "0.4.0" - resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + resolved "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" integrity sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs= node-modules-regexp@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz#8d9dbe28964a4ac5712e9131642107c71e90ec40" + resolved "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz#8d9dbe28964a4ac5712e9131642107c71e90ec40" integrity sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA= node-notifier@^8.0.0: version "8.0.2" - resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-8.0.2.tgz#f3167a38ef0d2c8a866a83e318c1ba0efeb702c5" + resolved "https://registry.npmjs.org/node-notifier/-/node-notifier-8.0.2.tgz#f3167a38ef0d2c8a866a83e318c1ba0efeb702c5" integrity sha512-oJP/9NAdd9+x2Q+rfphB2RJCHjod70RcRLjosiPMMu5gjIfwVnOUGq2nbTjTUbmy0DJ/tFIVT30+Qe3nzl4TJg== dependencies: growly "^1.3.0" @@ -7130,27 +7098,19 @@ node-notifier@^8.0.0: node-preload@^0.2.1: version "0.2.1" - resolved "https://registry.yarnpkg.com/node-preload/-/node-preload-0.2.1.tgz#c03043bb327f417a18fee7ab7ee57b408a144301" + resolved "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz#c03043bb327f417a18fee7ab7ee57b408a144301" integrity sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ== dependencies: process-on-spawn "^1.0.0" -node-releases@^1.1.71: - version "1.1.73" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.73.tgz#dd4e81ddd5277ff846b80b52bb40c49edf7a7b20" - integrity sha512-uW7fodD6pyW2FZNZnp/Z3hvWKeEW1Y8R1+1CnErE8cXFXzl5blBOoVB41CvMer6P6Q0S5FXDwcHgFd1Wj0U9zg== - -nodeunit@^0.11.3: - version "0.11.3" - resolved "https://registry.yarnpkg.com/nodeunit/-/nodeunit-0.11.3.tgz#313afae26cd11b407b731ff774b8e35e5d6f9568" - integrity sha512-gDNxrDWpx07BxYNO/jn1UrGI1vNhDQZrIFphbHMcTCDc5mrrqQBWfQMXPHJ5WSgbFwD1D6bv4HOsqtTrPG03AA== - dependencies: - ejs "^2.5.2" - tap "^12.0.1" +node-releases@^1.1.77: + version "1.1.77" + resolved "https://registry.npmjs.org/node-releases/-/node-releases-1.1.77.tgz#50b0cfede855dd374e7585bf228ff34e57c1c32e" + integrity sha512-rB1DUFUNAN4Gn9keO2K1efO35IDK7yKHCdCaIMvFO7yUYmmZYeDjnGKle26G4rwj+LKRQpjyUUvMkPglwGCYNQ== nopt@^4.0.1: version "4.0.3" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.3.tgz#a375cad9d02fd921278d954c2254d5aa57e15e48" + resolved "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz#a375cad9d02fd921278d954c2254d5aa57e15e48" integrity sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg== dependencies: abbrev "1" @@ -7158,14 +7118,14 @@ nopt@^4.0.1: nopt@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88" + resolved "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88" integrity sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ== dependencies: abbrev "1" normalize-package-data@^2.0.0, normalize-package-data@^2.3.2, normalize-package-data@^2.5.0: version "2.5.0" - resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" + resolved "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== dependencies: hosted-git-info "^2.1.4" @@ -7174,49 +7134,49 @@ normalize-package-data@^2.0.0, normalize-package-data@^2.3.2, normalize-package- validate-npm-package-license "^3.0.1" normalize-package-data@^3.0.0, normalize-package-data@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-3.0.2.tgz#cae5c410ae2434f9a6c1baa65d5bc3b9366c8699" - integrity sha512-6CdZocmfGaKnIHPVFhJJZ3GuR8SsLKvDANFp47Jmy51aKIr8akjAWTSxtpI+MBgBFdSMRyo4hMpDlT6dTffgZg== + version "3.0.3" + resolved "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz#dbcc3e2da59509a0983422884cd172eefdfa525e" + integrity sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA== dependencies: hosted-git-info "^4.0.1" - resolve "^1.20.0" + is-core-module "^2.5.0" semver "^7.3.4" validate-npm-package-license "^3.0.1" normalize-path@^2.1.1: version "2.1.1" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= dependencies: remove-trailing-separator "^1.0.1" normalize-path@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== normalize-url@^6.1.0: version "6.1.0" - resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a" + resolved "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a" integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A== npm-bundled@^1.1.1, npm-bundled@^1.1.2: version "1.1.2" - resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.1.2.tgz#944c78789bd739035b70baa2ca5cc32b8d860bc1" + resolved "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.2.tgz#944c78789bd739035b70baa2ca5cc32b8d860bc1" integrity sha512-x5DHup0SuyQcmL3s7Rx/YQ8sbw/Hzg0rj48eN0dV7hf5cmQq5PXIeioroH3raV1QC1yh3uTYuMThvEQF3iKgGQ== dependencies: npm-normalize-package-bin "^1.0.1" npm-install-checks@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/npm-install-checks/-/npm-install-checks-4.0.0.tgz#a37facc763a2fde0497ef2c6d0ac7c3fbe00d7b4" + resolved "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-4.0.0.tgz#a37facc763a2fde0497ef2c6d0ac7c3fbe00d7b4" integrity sha512-09OmyDkNLYwqKPOnbI8exiOZU2GVVmQp7tgez2BPi5OZC8M82elDAps7sxC4l//uSUtotWqoEIDwjRvWH4qz8w== dependencies: semver "^7.1.1" npm-lifecycle@^3.1.5: version "3.1.5" - resolved "https://registry.yarnpkg.com/npm-lifecycle/-/npm-lifecycle-3.1.5.tgz#9882d3642b8c82c815782a12e6a1bfeed0026309" + resolved "https://registry.npmjs.org/npm-lifecycle/-/npm-lifecycle-3.1.5.tgz#9882d3642b8c82c815782a12e6a1bfeed0026309" integrity sha512-lDLVkjfZmvmfvpvBzA4vzee9cn+Me4orq0QF8glbswJVEbIcSNWib7qGOffolysc3teCqbbPZZkzbr3GQZTL1g== dependencies: byline "^5.0.0" @@ -7230,12 +7190,12 @@ npm-lifecycle@^3.1.5: npm-normalize-package-bin@^1.0.0, npm-normalize-package-bin@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz#6e79a41f23fd235c0623218228da7d9c23b8f6e2" + resolved "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz#6e79a41f23fd235c0623218228da7d9c23b8f6e2" integrity sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA== -npm-package-arg@^8.0.0, npm-package-arg@^8.0.1, npm-package-arg@^8.1.0, npm-package-arg@^8.1.2: +npm-package-arg@^8.0.0, npm-package-arg@^8.0.1, npm-package-arg@^8.1.0, npm-package-arg@^8.1.2, npm-package-arg@^8.1.5: version "8.1.5" - resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-8.1.5.tgz#3369b2d5fe8fdc674baa7f1786514ddc15466e44" + resolved "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-8.1.5.tgz#3369b2d5fe8fdc674baa7f1786514ddc15466e44" integrity sha512-LhgZrg0n0VgvzVdSm1oiZworPbTxYHUJCgtsJW8mGvlDpxTM1vSJc3m5QZeUkhAHIzbz3VCHd/R4osi1L1Tg/Q== dependencies: hosted-git-info "^4.0.1" @@ -7244,7 +7204,7 @@ npm-package-arg@^8.0.0, npm-package-arg@^8.0.1, npm-package-arg@^8.1.0, npm-pack npm-packlist@^2.1.4: version "2.2.2" - resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-2.2.2.tgz#076b97293fa620f632833186a7a8f65aaa6148c8" + resolved "https://registry.npmjs.org/npm-packlist/-/npm-packlist-2.2.2.tgz#076b97293fa620f632833186a7a8f65aaa6148c8" integrity sha512-Jt01acDvJRhJGthnUJVF/w6gumWOZxO7IkpY/lsX9//zqQgnF7OJaxgQXcerd4uQOLu7W5bkb4mChL9mdfm+Zg== dependencies: glob "^7.1.6" @@ -7254,7 +7214,7 @@ npm-packlist@^2.1.4: npm-pick-manifest@^6.0.0, npm-pick-manifest@^6.1.1: version "6.1.1" - resolved "https://registry.yarnpkg.com/npm-pick-manifest/-/npm-pick-manifest-6.1.1.tgz#7b5484ca2c908565f43b7f27644f36bb816f5148" + resolved "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-6.1.1.tgz#7b5484ca2c908565f43b7f27644f36bb816f5148" integrity sha512-dBsdBtORT84S8V8UTad1WlUyKIY9iMsAmqxHbLdeEeBNMLQDlDWWra3wYUx9EBEIiG/YwAy0XyNHDd2goAsfuA== dependencies: npm-install-checks "^4.0.0" @@ -7264,7 +7224,7 @@ npm-pick-manifest@^6.0.0, npm-pick-manifest@^6.1.1: npm-registry-fetch@^11.0.0: version "11.0.0" - resolved "https://registry.yarnpkg.com/npm-registry-fetch/-/npm-registry-fetch-11.0.0.tgz#68c1bb810c46542760d62a6a965f85a702d43a76" + resolved "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-11.0.0.tgz#68c1bb810c46542760d62a6a965f85a702d43a76" integrity sha512-jmlgSxoDNuhAtxUIG6pVwwtz840i994dL14FoNVZisrmZW5kWd63IUTNv1m/hyRSGSqWjCUp/YZlS1BJyNp9XA== dependencies: make-fetch-happen "^9.0.1" @@ -7276,7 +7236,7 @@ npm-registry-fetch@^11.0.0: npm-registry-fetch@^9.0.0: version "9.0.0" - resolved "https://registry.yarnpkg.com/npm-registry-fetch/-/npm-registry-fetch-9.0.0.tgz#86f3feb4ce00313bc0b8f1f8f69daae6face1661" + resolved "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-9.0.0.tgz#86f3feb4ce00313bc0b8f1f8f69daae6face1661" integrity sha512-PuFYYtnQ8IyVl6ib9d3PepeehcUeHN9IO5N/iCRhyg9tStQcqGQBRVHmfmMWPDERU3KwZoHFvbJ4FPXPspvzbA== dependencies: "@npmcli/ci-detect" "^1.0.0" @@ -7290,21 +7250,21 @@ npm-registry-fetch@^9.0.0: npm-run-path@^2.0.0: version "2.0.2" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" + resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= dependencies: path-key "^2.0.0" npm-run-path@^4.0.0, npm-run-path@^4.0.1: version "4.0.1" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== dependencies: path-key "^3.0.0" npmlog@^4.1.2: version "4.1.2" - resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" + resolved "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== dependencies: are-we-there-yet "~1.1.2" @@ -7314,48 +7274,17 @@ npmlog@^4.1.2: null-check@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/null-check/-/null-check-1.0.0.tgz#977dffd7176012b9ec30d2a39db5cf72a0439edd" + resolved "https://registry.npmjs.org/null-check/-/null-check-1.0.0.tgz#977dffd7176012b9ec30d2a39db5cf72a0439edd" integrity sha1-l33/1xdgErnsMNKjnbXPcqBDnt0= nwsapi@^2.2.0: version "2.2.0" - resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.0.tgz#204879a9e3d068ff2a55139c2c772780681a38b7" + resolved "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz#204879a9e3d068ff2a55139c2c772780681a38b7" integrity sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ== -nyc@^14.0.0: - version "14.1.1" - resolved "https://registry.yarnpkg.com/nyc/-/nyc-14.1.1.tgz#151d64a6a9f9f5908a1b73233931e4a0a3075eeb" - integrity sha512-OI0vm6ZGUnoGZv/tLdZ2esSVzDwUC88SNs+6JoSOMVxA+gKMB8Tk7jBwgemLx4O40lhhvZCVw1C+OYLOBOPXWw== - dependencies: - archy "^1.0.0" - caching-transform "^3.0.2" - convert-source-map "^1.6.0" - cp-file "^6.2.0" - find-cache-dir "^2.1.0" - find-up "^3.0.0" - foreground-child "^1.5.6" - glob "^7.1.3" - istanbul-lib-coverage "^2.0.5" - istanbul-lib-hook "^2.0.7" - istanbul-lib-instrument "^3.3.0" - istanbul-lib-report "^2.0.8" - istanbul-lib-source-maps "^3.0.6" - istanbul-reports "^2.2.4" - js-yaml "^3.13.1" - make-dir "^2.1.0" - merge-source-map "^1.1.0" - resolve-from "^4.0.0" - rimraf "^2.6.3" - signal-exit "^3.0.2" - spawn-wrap "^1.4.2" - test-exclude "^5.2.3" - uuid "^3.3.2" - yargs "^13.2.2" - yargs-parser "^13.0.0" - nyc@^15.1.0: version "15.1.0" - resolved "https://registry.yarnpkg.com/nyc/-/nyc-15.1.0.tgz#1335dae12ddc87b6e249d5a1994ca4bdaea75f02" + resolved "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz#1335dae12ddc87b6e249d5a1994ca4bdaea75f02" integrity sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A== dependencies: "@istanbuljs/load-nyc-config" "^1.0.0" @@ -7388,31 +7317,31 @@ nyc@^15.1.0: oauth-sign@~0.9.0: version "0.9.0" - resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" + resolved "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== object-assign@^4.1.0: version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= object-copy@^0.1.0: version "0.1.0" - resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" + resolved "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= dependencies: copy-descriptor "^0.1.0" define-property "^0.2.5" kind-of "^3.0.3" -object-inspect@^1.10.3, object-inspect@^1.9.0: +object-inspect@^1.11.0, object-inspect@^1.9.0: version "1.11.0" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.11.0.tgz#9dceb146cedd4148a0d9e51ab88d34cf509922b1" + resolved "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz#9dceb146cedd4148a0d9e51ab88d34cf509922b1" integrity sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg== object-is@^1.1.4: version "1.1.5" - resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.5.tgz#b9deeaa5fc7f1846a0faecdceec138e5778f53ac" + resolved "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz#b9deeaa5fc7f1846a0faecdceec138e5778f53ac" integrity sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw== dependencies: call-bind "^1.0.2" @@ -7420,19 +7349,19 @@ object-is@^1.1.4: object-keys@^1.0.12, object-keys@^1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + resolved "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== object-visit@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" + resolved "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= dependencies: isobject "^3.0.0" object.assign@^4.1.2: version "4.1.2" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940" + resolved "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940" integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ== dependencies: call-bind "^1.0.0" @@ -7441,75 +7370,65 @@ object.assign@^4.1.2: object-keys "^1.1.1" object.getownpropertydescriptors@^2.0.3: - version "2.1.2" - resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.2.tgz#1bd63aeacf0d5d2d2f31b5e393b03a7c601a23f7" - integrity sha512-WtxeKSzfBjlzL+F9b7M7hewDzMwy+C8NRssHd1YrNlzHzIDrXcXiNOMrezdAEM4UXixgV+vvnyBeN7Rygl2ttQ== + version "2.1.3" + resolved "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.3.tgz#b223cf38e17fefb97a63c10c91df72ccb386df9e" + integrity sha512-VdDoCwvJI4QdC6ndjpqFmoL3/+HxffFBbcJzKi5hwLLqqx3mdbedRpfZDdK0SrOSauj8X4GzBvnDZl4vTN7dOw== dependencies: call-bind "^1.0.2" define-properties "^1.1.3" - es-abstract "^1.18.0-next.2" + es-abstract "^1.19.1" object.pick@^1.3.0: version "1.3.0" - resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" + resolved "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= dependencies: isobject "^3.0.1" -object.values@^1.1.3: - version "1.1.4" - resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.4.tgz#0d273762833e816b693a637d30073e7051535b30" - integrity sha512-TnGo7j4XSnKQoK3MfvkzqKCi0nVe/D9I9IjwTNYdb/fxYHpjrluHVOgw0AF6jrRFGMPHdfuidR09tIDiIvnaSg== +object.values@^1.1.5: + version "1.1.5" + resolved "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz#959f63e3ce9ef108720333082131e4a459b716ac" + integrity sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg== dependencies: call-bind "^1.0.2" define-properties "^1.1.3" - es-abstract "^1.18.2" + es-abstract "^1.19.1" octokit-pagination-methods@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/octokit-pagination-methods/-/octokit-pagination-methods-1.1.0.tgz#cf472edc9d551055f9ef73f6e42b4dbb4c80bea4" + resolved "https://registry.npmjs.org/octokit-pagination-methods/-/octokit-pagination-methods-1.1.0.tgz#cf472edc9d551055f9ef73f6e42b4dbb4c80bea4" integrity sha512-fZ4qZdQ2nxJvtcasX7Ghl+WlWS/d9IgnBIwFZXVNNZUmzpno91SX5bc5vuxiuKoCtK78XxGGNuSCrDC7xYB3OQ== once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= dependencies: wrappy "1" onetime@^5.1.0, onetime@^5.1.2: version "5.1.2" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + resolved "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== dependencies: mimic-fn "^2.1.0" -oo-ascii-tree@^1.31.0: - version "1.31.0" - resolved "https://registry.yarnpkg.com/oo-ascii-tree/-/oo-ascii-tree-1.31.0.tgz#36e10dcad35ba767db41c2d2050ff2174f3d5e6f" - integrity sha512-gNb2MyP1ZcF7cX0WgsAjYe4gZcx7BMLBWKE2TJZZbQ9/j4D8gbJh5Aq6RlXBgev74ODlgAVVcPr2wKU4Dufhqg== - -oo-ascii-tree@^1.34.0: - version "1.34.0" - resolved "https://registry.yarnpkg.com/oo-ascii-tree/-/oo-ascii-tree-1.34.0.tgz#5528a52d92ef18b3860d0e784383007e476c18b3" - integrity sha512-gAY+yfKCskAk7mkfI8nOhkP12iTGE7b8UxnQuscN80vghrozt/E/2rLeKKMJFagJlm/NnnUmBA0tBQZ3oPHEKg== +oo-ascii-tree@^1.39.0: + version "1.39.0" + resolved "https://registry.npmjs.org/oo-ascii-tree/-/oo-ascii-tree-1.39.0.tgz#7dfc1fc11e0c7c7bf34d0b91591db9bfe0406cbb" + integrity sha512-a0g33GTdCizt5jnQzY9j6cRNyx5xITmZb+b3C21+KNweaERltcR1BQO/tLUuuVEFRVWvZcUqrFDVa8f8nqOafA== open@^7.4.2: version "7.4.2" - resolved "https://registry.yarnpkg.com/open/-/open-7.4.2.tgz#b8147e26dcf3e426316c730089fd71edd29c2321" + resolved "https://registry.npmjs.org/open/-/open-7.4.2.tgz#b8147e26dcf3e426316c730089fd71edd29c2321" integrity sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q== dependencies: is-docker "^2.0.0" is-wsl "^2.1.1" -opener@^1.5.1: - version "1.5.2" - resolved "https://registry.yarnpkg.com/opener/-/opener-1.5.2.tgz#5d37e1f35077b9dcac4301372271afdeb2a13598" - integrity sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A== - optionator@^0.8.1: version "0.8.3" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" + resolved "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== dependencies: deep-is "~0.1.3" @@ -7521,7 +7440,7 @@ optionator@^0.8.1: optionator@^0.9.1: version "0.9.1" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" + resolved "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== dependencies: deep-is "^0.1.3" @@ -7531,14 +7450,14 @@ optionator@^0.9.1: type-check "^0.4.0" word-wrap "^1.2.3" -os-homedir@^1.0.0, os-homedir@^1.0.1, os-homedir@^1.0.2: +os-homedir@^1.0.0: version "1.0.2" - resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + resolved "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= os-name@^3.1.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/os-name/-/os-name-3.1.0.tgz#dec19d966296e1cd62d701a5a66ee1ddeae70801" + resolved "https://registry.npmjs.org/os-name/-/os-name-3.1.0.tgz#dec19d966296e1cd62d701a5a66ee1ddeae70801" integrity sha512-h8L+8aNjNcMpo/mAIBPn5PXCM16iyPGjHNWo6U1YO8sJTMHtEtyczI6QJnLoplswm6goopQkqc7OAnjhWcugVg== dependencies: macos-release "^2.2.0" @@ -7546,115 +7465,103 @@ os-name@^3.1.0: os-tmpdir@^1.0.0, os-tmpdir@~1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + resolved "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= osenv@^0.1.4: version "0.1.5" - resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" + resolved "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g== dependencies: os-homedir "^1.0.0" os-tmpdir "^1.0.0" -own-or-env@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/own-or-env/-/own-or-env-1.0.1.tgz#54ce601d3bf78236c5c65633aa1c8ec03f8007e4" - integrity sha512-y8qULRbRAlL6x2+M0vIe7jJbJx/kmUTzYonRAa2ayesR2qWLswninkVyeJe4x3IEXhdgoNodzjQRKAoEs6Fmrw== - dependencies: - own-or "^1.0.0" - -own-or@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/own-or/-/own-or-1.0.0.tgz#4e877fbeda9a2ec8000fbc0bcae39645ee8bf8dc" - integrity sha1-Tod/vtqaLsgAD7wLyuOWRe6L+Nw= - p-each-series@^2.1.0: version "2.2.0" - resolved "https://registry.yarnpkg.com/p-each-series/-/p-each-series-2.2.0.tgz#105ab0357ce72b202a8a8b94933672657b5e2a9a" + resolved "https://registry.npmjs.org/p-each-series/-/p-each-series-2.2.0.tgz#105ab0357ce72b202a8a8b94933672657b5e2a9a" integrity sha512-ycIL2+1V32th+8scbpTvyHNaHe02z0sjgh91XXjAk+ZeXoPN4Z46DVUnzdso0aX4KckKw0FNNFHdjZ2UsZvxiA== p-finally@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + resolved "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= p-limit@^1.1.0: version "1.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" + resolved "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== dependencies: p-try "^1.0.0" p-limit@^2.0.0, p-limit@^2.2.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== dependencies: p-try "^2.0.0" p-limit@^3.0.2: version "3.1.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + resolved "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== dependencies: yocto-queue "^0.1.0" p-locate@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" + resolved "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= dependencies: p-limit "^1.1.0" p-locate@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" + resolved "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== dependencies: p-limit "^2.0.0" p-locate@^4.1.0: version "4.1.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + resolved "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== dependencies: p-limit "^2.2.0" p-locate@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + resolved "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== dependencies: p-limit "^3.0.2" p-map-series@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/p-map-series/-/p-map-series-2.1.0.tgz#7560d4c452d9da0c07e692fdbfe6e2c81a2a91f2" + resolved "https://registry.npmjs.org/p-map-series/-/p-map-series-2.1.0.tgz#7560d4c452d9da0c07e692fdbfe6e2c81a2a91f2" integrity sha512-RpYIIK1zXSNEOdwxcfe7FdvGcs7+y5n8rifMhMNWvaxRNMPINJHF5GDeuVxWqnfrcHPSCnp7Oo5yNXHId9Av2Q== p-map@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/p-map/-/p-map-3.0.0.tgz#d704d9af8a2ba684e2600d9a215983d4141a979d" + resolved "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz#d704d9af8a2ba684e2600d9a215983d4141a979d" integrity sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ== dependencies: aggregate-error "^3.0.0" p-map@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" + resolved "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ== dependencies: aggregate-error "^3.0.0" p-pipe@^3.1.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/p-pipe/-/p-pipe-3.1.0.tgz#48b57c922aa2e1af6a6404cb7c6bf0eb9cc8e60e" + resolved "https://registry.npmjs.org/p-pipe/-/p-pipe-3.1.0.tgz#48b57c922aa2e1af6a6404cb7c6bf0eb9cc8e60e" integrity sha512-08pj8ATpzMR0Y80x50yJHn37NF6vjrqHutASaX5LiH5npS9XPvrUmscd9MF5R4fuYRHOxQR1FfMIlF7AzwoPqw== p-queue@^6.6.2: version "6.6.2" - resolved "https://registry.yarnpkg.com/p-queue/-/p-queue-6.6.2.tgz#2068a9dcf8e67dd0ec3e7a2bcb76810faa85e426" + resolved "https://registry.npmjs.org/p-queue/-/p-queue-6.6.2.tgz#2068a9dcf8e67dd0ec3e7a2bcb76810faa85e426" integrity sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ== dependencies: eventemitter3 "^4.0.4" @@ -7662,36 +7569,36 @@ p-queue@^6.6.2: p-reduce@^2.0.0, p-reduce@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/p-reduce/-/p-reduce-2.1.0.tgz#09408da49507c6c274faa31f28df334bc712b64a" + resolved "https://registry.npmjs.org/p-reduce/-/p-reduce-2.1.0.tgz#09408da49507c6c274faa31f28df334bc712b64a" integrity sha512-2USApvnsutq8uoxZBGbbWM0JIYLiEMJ9RlaN7fAzVNb9OZN0SHjjTTfIcb667XynS5Y1VhwDJVDa72TnPzAYWw== p-timeout@^3.2.0: version "3.2.0" - resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-3.2.0.tgz#c7e17abc971d2a7962ef83626b35d635acf23dfe" + resolved "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz#c7e17abc971d2a7962ef83626b35d635acf23dfe" integrity sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg== dependencies: p-finally "^1.0.0" p-try@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" + resolved "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= p-try@^2.0.0: version "2.2.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + resolved "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== p-waterfall@^2.1.1: version "2.1.1" - resolved "https://registry.yarnpkg.com/p-waterfall/-/p-waterfall-2.1.1.tgz#63153a774f472ccdc4eb281cdb2967fcf158b2ee" + resolved "https://registry.npmjs.org/p-waterfall/-/p-waterfall-2.1.1.tgz#63153a774f472ccdc4eb281cdb2967fcf158b2ee" integrity sha512-RRTnDb2TBG/epPRI2yYXsimO0v3BXC8Yd3ogr1545IaqKK17VGhbWVeGGN+XfCm/08OK8635nH31c8bATkHuSw== dependencies: p-reduce "^2.0.0" pac-proxy-agent@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/pac-proxy-agent/-/pac-proxy-agent-5.0.0.tgz#b718f76475a6a5415c2efbe256c1c971c84f635e" + resolved "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-5.0.0.tgz#b718f76475a6a5415c2efbe256c1c971c84f635e" integrity sha512-CcFG3ZtnxO8McDigozwE3AqAw15zDvGH+OjXO4kzf7IkEKkQ4gxQ+3sdF50WmhQ4P/bVusXcqNE2S3XrNURwzQ== dependencies: "@tootallnate/once" "1" @@ -7706,26 +7613,16 @@ pac-proxy-agent@^5.0.0: pac-resolver@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/pac-resolver/-/pac-resolver-5.0.0.tgz#1d717a127b3d7a9407a16d6e1b012b13b9ba8dc0" + resolved "https://registry.npmjs.org/pac-resolver/-/pac-resolver-5.0.0.tgz#1d717a127b3d7a9407a16d6e1b012b13b9ba8dc0" integrity sha512-H+/A6KitiHNNW+bxBKREk2MCGSxljfqRX76NjummWEYIat7ldVXRU3dhRIE3iXZ0nvGBk6smv3nntxKkzRL8NA== dependencies: degenerator "^3.0.1" ip "^1.1.5" netmask "^2.0.1" -package-hash@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/package-hash/-/package-hash-3.0.0.tgz#50183f2d36c9e3e528ea0a8605dff57ce976f88e" - integrity sha512-lOtmukMDVvtkL84rJHI7dpTYq+0rli8N2wlnqUcBuDWCfVhRUfOmnR9SsoHFMLpACvEV60dX7rd0rFaYDZI+FA== - dependencies: - graceful-fs "^4.1.15" - hasha "^3.0.0" - lodash.flattendeep "^4.4.0" - release-zalgo "^1.0.0" - package-hash@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/package-hash/-/package-hash-4.0.0.tgz#3537f654665ec3cc38827387fc904c163c54f506" + resolved "https://registry.npmjs.org/package-hash/-/package-hash-4.0.0.tgz#3537f654665ec3cc38827387fc904c163c54f506" integrity sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ== dependencies: graceful-fs "^4.1.15" @@ -7735,7 +7632,7 @@ package-hash@^4.0.0: pacote@^11.2.6: version "11.3.5" - resolved "https://registry.yarnpkg.com/pacote/-/pacote-11.3.5.tgz#73cf1fc3772b533f575e39efa96c50be8c3dc9d2" + resolved "https://registry.npmjs.org/pacote/-/pacote-11.3.5.tgz#73cf1fc3772b533f575e39efa96c50be8c3dc9d2" integrity sha512-fT375Yczn4zi+6Hkk2TBe1x1sP8FgFsEIZ2/iWaXY2r/NkhDJfxbcn5paz1+RTFCyNf+dPnaoBDJoAxXSU8Bkg== dependencies: "@npmcli/git" "^2.1.0" @@ -7760,19 +7657,19 @@ pacote@^11.2.6: pako@~1.0.2: version "1.0.11" - resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" + resolved "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== parent-module@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + resolved "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== dependencies: callsites "^3.0.0" parse-json@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" + resolved "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" integrity sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA= dependencies: error-ex "^1.3.1" @@ -7780,7 +7677,7 @@ parse-json@^4.0.0: parse-json@^5.0.0: version "5.2.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" + resolved "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== dependencies: "@babel/code-frame" "^7.0.0" @@ -7790,7 +7687,7 @@ parse-json@^5.0.0: parse-path@^4.0.0: version "4.0.3" - resolved "https://registry.yarnpkg.com/parse-path/-/parse-path-4.0.3.tgz#82d81ec3e071dcc4ab49aa9f2c9c0b8966bb22bf" + resolved "https://registry.npmjs.org/parse-path/-/parse-path-4.0.3.tgz#82d81ec3e071dcc4ab49aa9f2c9c0b8966bb22bf" integrity sha512-9Cepbp2asKnWTJ9x2kpw6Fe8y9JDbqwahGCTvklzd/cEq5C5JC59x2Xb0Kx+x0QZ8bvNquGO8/BWP0cwBHzSAA== dependencies: is-ssh "^1.3.0" @@ -7800,7 +7697,7 @@ parse-path@^4.0.0: parse-url@^6.0.0: version "6.0.0" - resolved "https://registry.yarnpkg.com/parse-url/-/parse-url-6.0.0.tgz#f5dd262a7de9ec00914939220410b66cff09107d" + resolved "https://registry.npmjs.org/parse-url/-/parse-url-6.0.0.tgz#f5dd262a7de9ec00914939220410b66cff09107d" integrity sha512-cYyojeX7yIIwuJzledIHeLUBVJ6COVLeT4eF+2P6aKVzwvgKQPndCBv3+yQ7pcWjqToYwaligxzSYNNmGoMAvw== dependencies: is-ssh "^1.3.0" @@ -7810,17 +7707,17 @@ parse-url@^6.0.0: parse5@6.0.1: version "6.0.1" - resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" + resolved "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== pascalcase@^0.1.1: version "0.1.1" - resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" + resolved "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= patch-package@^6.4.7: version "6.4.7" - resolved "https://registry.yarnpkg.com/patch-package/-/patch-package-6.4.7.tgz#2282d53c397909a0d9ef92dae3fdeb558382b148" + resolved "https://registry.npmjs.org/patch-package/-/patch-package-6.4.7.tgz#2282d53c397909a0d9ef92dae3fdeb558382b148" integrity sha512-S0vh/ZEafZ17hbhgqdnpunKDfzHQibQizx9g8yEf5dcVk3KOflOfdufRXQX8CSEkyOQwuM/bNz1GwKvFj54kaQ== dependencies: "@yarnpkg/lockfile" "^1.1.0" @@ -7839,136 +7736,127 @@ patch-package@^6.4.7: path-exists@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + resolved "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= path-exists@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + resolved "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== path-is-absolute@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= path-key@^2.0.0, path-key@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + resolved "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= path-key@^3.0.0, path-key@^3.1.0: version "3.1.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== path-parse@^1.0.6: version "1.0.7" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== path-to-regexp@^1.7.0: version "1.8.0" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.8.0.tgz#887b3ba9d84393e87a0a0b9f4cb756198b53548a" + resolved "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz#887b3ba9d84393e87a0a0b9f4cb756198b53548a" integrity sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA== dependencies: isarray "0.0.1" path-type@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" + resolved "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" integrity sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg== dependencies: pify "^3.0.0" path-type@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + resolved "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== performance-now@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + resolved "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= +picocolors@^0.2.1: + version "0.2.1" + resolved "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz#570670f793646851d1ba135996962abad587859f" + integrity sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA== + picomatch@^2.0.4, picomatch@^2.2.3: version "2.3.0" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972" + resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972" integrity sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw== pify@^2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + resolved "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= pify@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" + resolved "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= pify@^4.0.1: version "4.0.1" - resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" + resolved "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== pify@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-5.0.0.tgz#1f5eca3f5e87ebec28cc6d54a0e4aaf00acc127f" + resolved "https://registry.npmjs.org/pify/-/pify-5.0.0.tgz#1f5eca3f5e87ebec28cc6d54a0e4aaf00acc127f" integrity sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA== pirates@^4.0.1: version "4.0.1" - resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.1.tgz#643a92caf894566f91b2b986d2c66950a8e2fb87" + resolved "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz#643a92caf894566f91b2b986d2c66950a8e2fb87" integrity sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA== dependencies: node-modules-regexp "^1.0.0" pkg-dir@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b" + resolved "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b" integrity sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s= dependencies: find-up "^2.1.0" -pkg-dir@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3" - integrity sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw== - dependencies: - find-up "^3.0.0" - pkg-dir@^4.1.0, pkg-dir@^4.2.0: version "4.2.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + resolved "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== dependencies: find-up "^4.0.0" -pkg-up@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-2.0.0.tgz#c819ac728059a461cab1c3889a2be3c49a004d7f" - integrity sha1-yBmscoBZpGHKscOImivjxJoATX8= - dependencies: - find-up "^2.1.0" - posix-character-classes@^0.1.0: version "0.1.1" - resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" + resolved "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= prelude-ls@^1.2.1: version "1.2.1" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== prelude-ls@~1.1.2: version "1.1.2" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= pretty-format@^26.0.0, pretty-format@^26.6.2: version "26.6.2" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-26.6.2.tgz#e35c2705f14cb7fe2fe94fa078345b444120fc93" + resolved "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz#e35c2705f14cb7fe2fe94fa078345b444120fc93" integrity sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg== dependencies: "@jest/types" "^26.6.2" @@ -7978,34 +7866,34 @@ pretty-format@^26.0.0, pretty-format@^26.6.2: printj@~1.1.0: version "1.1.2" - resolved "https://registry.yarnpkg.com/printj/-/printj-1.1.2.tgz#d90deb2975a8b9f600fb3a1c94e3f4c53c78a222" + resolved "https://registry.npmjs.org/printj/-/printj-1.1.2.tgz#d90deb2975a8b9f600fb3a1c94e3f4c53c78a222" integrity sha512-zA2SmoLaxZyArQTOPj5LXecR+RagfPSU5Kw1qP+jkWeNlrq+eJZyY2oS68SU1Z/7/myXM4lo9716laOFAVStCQ== process-nextick-args@~2.0.0: version "2.0.1" - resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== process-on-spawn@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/process-on-spawn/-/process-on-spawn-1.0.0.tgz#95b05a23073d30a17acfdc92a440efd2baefdc93" + resolved "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz#95b05a23073d30a17acfdc92a440efd2baefdc93" integrity sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg== dependencies: fromentries "^1.2.0" progress@^2.0.0: version "2.0.3" - resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" + resolved "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== promise-inflight@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" + resolved "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM= promise-retry@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/promise-retry/-/promise-retry-2.0.1.tgz#ff747a13620ab57ba688f5fc67855410c370da22" + resolved "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz#ff747a13620ab57ba688f5fc67855410c370da22" integrity sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g== dependencies: err-code "^2.0.2" @@ -8013,44 +7901,44 @@ promise-retry@^2.0.1: promptly@^3.2.0: version "3.2.0" - resolved "https://registry.yarnpkg.com/promptly/-/promptly-3.2.0.tgz#a5517fbbf59bd31c1751d4e1d9bef1714f42b9d8" + resolved "https://registry.npmjs.org/promptly/-/promptly-3.2.0.tgz#a5517fbbf59bd31c1751d4e1d9bef1714f42b9d8" integrity sha512-WnR9obtgW+rG4oUV3hSnNGl1pHm3V1H/qD9iJBumGSmVsSC5HpZOLuu8qdMb6yCItGfT7dcRszejr/5P3i9Pug== dependencies: read "^1.0.4" prompts@^2.0.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.1.tgz#befd3b1195ba052f9fd2fde8a486c4e82ee77f61" - integrity sha512-EQyfIuO2hPDsX1L/blblV+H7I0knhgAd82cVneCwcdND9B8AuCDuRcBH6yIcG4dFzlOUqbazQqwGjx5xmsNLuQ== + version "2.4.2" + resolved "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" + integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== dependencies: kleur "^3.0.3" sisteransi "^1.0.5" promzard@^0.3.0: version "0.3.0" - resolved "https://registry.yarnpkg.com/promzard/-/promzard-0.3.0.tgz#26a5d6ee8c7dee4cb12208305acfb93ba382a9ee" + resolved "https://registry.npmjs.org/promzard/-/promzard-0.3.0.tgz#26a5d6ee8c7dee4cb12208305acfb93ba382a9ee" integrity sha1-JqXW7ox97kyxIggwWs+5O6OCqe4= dependencies: read "1" propagate@^2.0.0: version "2.0.1" - resolved "https://registry.yarnpkg.com/propagate/-/propagate-2.0.1.tgz#40cdedab18085c792334e64f0ac17256d38f9a45" + resolved "https://registry.npmjs.org/propagate/-/propagate-2.0.1.tgz#40cdedab18085c792334e64f0ac17256d38f9a45" integrity sha512-vGrhOavPSTz4QVNuBNdcNXePNdNMaO1xj9yBeH1ScQPjk/rhg9sSlCXPhMkFuaNNW/syTvYqsnbIJxMBfRbbag== proto-list@~1.2.1: version "1.2.4" - resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" + resolved "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" integrity sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk= protocols@^1.1.0, protocols@^1.4.0: version "1.4.8" - resolved "https://registry.yarnpkg.com/protocols/-/protocols-1.4.8.tgz#48eea2d8f58d9644a4a32caae5d5db290a075ce8" + resolved "https://registry.npmjs.org/protocols/-/protocols-1.4.8.tgz#48eea2d8f58d9644a4a32caae5d5db290a075ce8" integrity sha512-IgjKyaUSjsROSO8/D49Ab7hP8mJgTYcqApOqdPhLoPxAplXmkp+zRvsrSQjFn5by0rhm4VH0GAUELIPpx7B1yg== proxy-agent@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/proxy-agent/-/proxy-agent-5.0.0.tgz#d31405c10d6e8431fde96cba7a0c027ce01d633b" + resolved "https://registry.npmjs.org/proxy-agent/-/proxy-agent-5.0.0.tgz#d31405c10d6e8431fde96cba7a0c027ce01d633b" integrity sha512-gkH7BkvLVkSfX9Dk27W6TyNOWWZWRilRfk1XxGNWOYJ2TuedAv1yFpCaU9QSBmBe716XOTNpYNOzhysyw8xn7g== dependencies: agent-base "^6.0.0" @@ -8064,31 +7952,26 @@ proxy-agent@^5.0.0: proxy-from-env@^1.0.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" + resolved "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== proxyquire@^2.1.3: version "2.1.3" - resolved "https://registry.yarnpkg.com/proxyquire/-/proxyquire-2.1.3.tgz#2049a7eefa10a9a953346a18e54aab2b4268df39" + resolved "https://registry.npmjs.org/proxyquire/-/proxyquire-2.1.3.tgz#2049a7eefa10a9a953346a18e54aab2b4268df39" integrity sha512-BQWfCqYM+QINd+yawJz23tbBM40VIGXOdDw3X344KcclI/gtBbdWF6SlQ4nK/bYhF9d27KYug9WzljHC6B9Ysg== dependencies: fill-keys "^1.0.2" module-not-found-error "^1.0.1" resolve "^1.11.1" -pseudomap@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" - integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= - psl@^1.1.28, psl@^1.1.33: version "1.8.0" - resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" + resolved "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ== pump@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" + resolved "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== dependencies: end-of-stream "^1.1.0" @@ -8096,39 +7979,39 @@ pump@^3.0.0: punycode@1.3.2: version "1.3.2" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" + resolved "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0= -punycode@^2.0.0, punycode@^2.1.0, punycode@^2.1.1: +punycode@^2.1.0, punycode@^2.1.1: version "2.1.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + resolved "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== pure-rand@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-5.0.0.tgz#87f5bdabeadbd8904e316913a5c0b8caac517b37" + resolved "https://registry.npmjs.org/pure-rand/-/pure-rand-5.0.0.tgz#87f5bdabeadbd8904e316913a5c0b8caac517b37" integrity sha512-lD2/y78q+7HqBx2SaT6OT4UcwtvXNRfEpzYEzl0EQ+9gZq2Qi3fa0HDnYPeqQwhlHJFBUhT7AO3mLU3+8bynHA== q@^1.5.1: version "1.5.1" - resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" + resolved "https://registry.npmjs.org/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc= qs@^6.9.4: version "6.10.1" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.10.1.tgz#4931482fa8d647a5aab799c5271d2133b981fb6a" + resolved "https://registry.npmjs.org/qs/-/qs-6.10.1.tgz#4931482fa8d647a5aab799c5271d2133b981fb6a" integrity sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg== dependencies: side-channel "^1.0.4" qs@~6.5.2: version "6.5.2" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" + resolved "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== query-string@^6.13.8: version "6.14.1" - resolved "https://registry.yarnpkg.com/query-string/-/query-string-6.14.1.tgz#7ac2dca46da7f309449ba0f86b1fd28255b0c86a" + resolved "https://registry.npmjs.org/query-string/-/query-string-6.14.1.tgz#7ac2dca46da7f309449ba0f86b1fd28255b0c86a" integrity sha512-XDxAeVmpfu1/6IjyT/gXHOl+S0vQ9owggJ30hhWKdHAsNPOcasn5o9BW0eejZqL2e4vMjhAxoW3jVHcD6mbcYw== dependencies: decode-uri-component "^0.2.0" @@ -8138,22 +8021,22 @@ query-string@^6.13.8: querystring@0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" + resolved "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= queue-microtask@^1.2.2: version "1.2.3" - resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + resolved "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== quick-lru@^4.0.1: version "4.0.1" - resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-4.0.1.tgz#5b8878f113a58217848c6482026c73e1ba57727f" + resolved "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz#5b8878f113a58217848c6482026c73e1ba57727f" integrity sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g== raw-body@^2.2.0: version "2.4.1" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.1.tgz#30ac82f98bb5ae8c152e67149dac8d55153b168c" + resolved "https://registry.npmjs.org/raw-body/-/raw-body-2.4.1.tgz#30ac82f98bb5ae8c152e67149dac8d55153b168c" integrity sha512-9WmIKF6mkvA0SLmA2Knm9+qj89e+j1zqgyn8aXGd7+nAduPoqgI9lO57SAZNn/Byzo5P7JhXTyg9PzaJbH73bA== dependencies: bytes "3.1.0" @@ -8161,37 +8044,27 @@ raw-body@^2.2.0: iconv-lite "0.4.24" unpipe "1.0.0" -rc@~1.2.8: - version "1.2.8" - resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" - integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== - dependencies: - deep-extend "^0.6.0" - ini "~1.3.0" - minimist "^1.2.0" - strip-json-comments "~2.0.1" - react-is@^17.0.1: version "17.0.2" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" + resolved "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== read-cmd-shim@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/read-cmd-shim/-/read-cmd-shim-2.0.0.tgz#4a50a71d6f0965364938e9038476f7eede3928d9" + resolved "https://registry.npmjs.org/read-cmd-shim/-/read-cmd-shim-2.0.0.tgz#4a50a71d6f0965364938e9038476f7eede3928d9" integrity sha512-HJpV9bQpkl6KwjxlJcBoqu9Ba0PQg8TqSNIOrulGt54a0uup0HtevreFHzYzkm0lpnleRdNBzXznKrgxglEHQw== read-package-json-fast@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/read-package-json-fast/-/read-package-json-fast-2.0.2.tgz#2dcb24d9e8dd50fb322042c8c35a954e6cc7ac9e" - integrity sha512-5fyFUyO9B799foVk4n6ylcoAktG/FbE3jwRKxvwaeSrIunaoMc0u81dzXxjeAFKOce7O5KncdfwpGvvs6r5PsQ== + version "2.0.3" + resolved "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-2.0.3.tgz#323ca529630da82cb34b36cc0b996693c98c2b83" + integrity sha512-W/BKtbL+dUjTuRL2vziuYhp76s5HZ9qQhd/dKfWIZveD0O40453QNyZhC0e63lqZrAQ4jiOapVoeJ7JrszenQQ== dependencies: json-parse-even-better-errors "^2.3.0" npm-normalize-package-bin "^1.0.1" read-package-json@^2.0.0: version "2.1.2" - resolved "https://registry.yarnpkg.com/read-package-json/-/read-package-json-2.1.2.tgz#6992b2b66c7177259feb8eaac73c3acd28b9222a" + resolved "https://registry.npmjs.org/read-package-json/-/read-package-json-2.1.2.tgz#6992b2b66c7177259feb8eaac73c3acd28b9222a" integrity sha512-D1KmuLQr6ZSJS0tW8hf3WGpRlwszJOXZ3E8Yd/DNRaM5d+1wVRZdHlpGBLAuovjr28LbWvjpWkBHMxpRGGjzNA== dependencies: glob "^7.1.1" @@ -8199,9 +8072,9 @@ read-package-json@^2.0.0: normalize-package-data "^2.0.0" npm-normalize-package-bin "^1.0.0" -read-package-json@^3.0.0, read-package-json@^3.0.1: +read-package-json@^3.0.0: version "3.0.1" - resolved "https://registry.yarnpkg.com/read-package-json/-/read-package-json-3.0.1.tgz#c7108f0b9390257b08c21e3004d2404c806744b9" + resolved "https://registry.npmjs.org/read-package-json/-/read-package-json-3.0.1.tgz#c7108f0b9390257b08c21e3004d2404c806744b9" integrity sha512-aLcPqxovhJTVJcsnROuuzQvv6oziQx4zd3JvG0vGCL5MjTONUc4uJ90zCBC6R7W7oUKBNoR/F8pkyfVwlbxqng== dependencies: glob "^7.1.1" @@ -8209,9 +8082,19 @@ read-package-json@^3.0.0, read-package-json@^3.0.1: normalize-package-data "^3.0.0" npm-normalize-package-bin "^1.0.0" +read-package-json@^4.1.1: + version "4.1.1" + resolved "https://registry.npmjs.org/read-package-json/-/read-package-json-4.1.1.tgz#153be72fce801578c1c86b8ef2b21188df1b9eea" + integrity sha512-P82sbZJ3ldDrWCOSKxJT0r/CXMWR0OR3KRh55SgKo3p91GSIEEC32v3lSHAvO/UcH3/IoL7uqhOFBduAnwdldw== + dependencies: + glob "^7.1.1" + json-parse-even-better-errors "^2.3.0" + normalize-package-data "^3.0.0" + npm-normalize-package-bin "^1.0.0" + read-package-tree@^5.3.1: version "5.3.1" - resolved "https://registry.yarnpkg.com/read-package-tree/-/read-package-tree-5.3.1.tgz#a32cb64c7f31eb8a6f31ef06f9cedf74068fe636" + resolved "https://registry.npmjs.org/read-package-tree/-/read-package-tree-5.3.1.tgz#a32cb64c7f31eb8a6f31ef06f9cedf74068fe636" integrity sha512-mLUDsD5JVtlZxjSlPPx1RETkNjjvQYuweKwNVt1Sn8kP5Jh44pvYuUHCp6xSVDZWbNxVxG5lyZJ921aJH61sTw== dependencies: read-package-json "^2.0.0" @@ -8220,23 +8103,15 @@ read-package-tree@^5.3.1: read-pkg-up@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-3.0.0.tgz#3ed496685dba0f8fe118d0691dc51f4a1ff96f07" + resolved "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz#3ed496685dba0f8fe118d0691dc51f4a1ff96f07" integrity sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc= dependencies: find-up "^2.0.0" read-pkg "^3.0.0" -read-pkg-up@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-4.0.0.tgz#1b221c6088ba7799601c808f91161c66e58f8978" - integrity sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA== - dependencies: - find-up "^3.0.0" - read-pkg "^3.0.0" - read-pkg-up@^7.0.1: version "7.0.1" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507" + resolved "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507" integrity sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg== dependencies: find-up "^4.1.0" @@ -8245,7 +8120,7 @@ read-pkg-up@^7.0.1: read-pkg@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389" + resolved "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389" integrity sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k= dependencies: load-json-file "^4.0.0" @@ -8254,7 +8129,7 @@ read-pkg@^3.0.0: read-pkg@^5.2.0: version "5.2.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc" + resolved "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc" integrity sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg== dependencies: "@types/normalize-package-data" "^2.4.0" @@ -8264,14 +8139,14 @@ read-pkg@^5.2.0: read@1, read@^1.0.4, read@~1.0.1: version "1.0.7" - resolved "https://registry.yarnpkg.com/read/-/read-1.0.7.tgz#b3da19bd052431a97671d44a42634adf710b40c4" + resolved "https://registry.npmjs.org/read/-/read-1.0.7.tgz#b3da19bd052431a97671d44a42634adf710b40c4" integrity sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ= dependencies: mute-stream "~0.0.4" readable-stream@1.1.x: version "1.1.14" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" integrity sha1-fPTFTvZI44EwhMY23SB54WbAgdk= dependencies: core-util-is "~1.0.0" @@ -8281,7 +8156,7 @@ readable-stream@1.1.x: readable-stream@3, readable-stream@^3.0.0, readable-stream@^3.0.2, readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0: version "3.6.0" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== dependencies: inherits "^2.0.3" @@ -8290,7 +8165,7 @@ readable-stream@3, readable-stream@^3.0.0, readable-stream@^3.0.2, readable-stre readable-stream@^2.0.0, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@~2.3.6: version "2.3.7" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== dependencies: core-util-is "~1.0.0" @@ -8303,14 +8178,14 @@ readable-stream@^2.0.0, readable-stream@^2.0.5, readable-stream@^2.0.6, readable readdir-glob@^1.0.0: version "1.1.1" - resolved "https://registry.yarnpkg.com/readdir-glob/-/readdir-glob-1.1.1.tgz#f0e10bb7bf7bfa7e0add8baffdc54c3f7dbee6c4" + resolved "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.1.tgz#f0e10bb7bf7bfa7e0add8baffdc54c3f7dbee6c4" integrity sha512-91/k1EzZwDx6HbERR+zucygRFfiPl2zkIYZtv3Jjr6Mn7SkKcVct8aVO+sSRiGMc6fLf72du3d92/uY63YPdEA== dependencies: minimatch "^3.0.4" readdir-scoped-modules@^1.0.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz#8d45407b4f870a0dcaebc0e28670d18e74514309" + resolved "https://registry.npmjs.org/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz#8d45407b4f870a0dcaebc0e28670d18e74514309" integrity sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw== dependencies: debuglog "^1.0.1" @@ -8320,7 +8195,7 @@ readdir-scoped-modules@^1.0.0: redent@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/redent/-/redent-3.0.0.tgz#e557b7998316bb53c9f1f56fa626352c6963059f" + resolved "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz#e557b7998316bb53c9f1f56fa626352c6963059f" integrity sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg== dependencies: indent-string "^4.0.0" @@ -8328,7 +8203,7 @@ redent@^3.0.0: regex-not@^1.0.0, regex-not@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" + resolved "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== dependencies: extend-shallow "^3.0.2" @@ -8336,42 +8211,47 @@ regex-not@^1.0.0, regex-not@^1.0.2: regexp.prototype.flags@^1.3.0: version "1.3.1" - resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz#7ef352ae8d159e758c0eadca6f8fcb4eef07be26" + resolved "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz#7ef352ae8d159e758c0eadca6f8fcb4eef07be26" integrity sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA== dependencies: call-bind "^1.0.2" define-properties "^1.1.3" -regexpp@^3.1.0: +regexpp@^3.0.0, regexpp@^3.1.0: version "3.2.0" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" + resolved "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== release-zalgo@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/release-zalgo/-/release-zalgo-1.0.0.tgz#09700b7e5074329739330e535c5a90fb67851730" + resolved "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz#09700b7e5074329739330e535c5a90fb67851730" integrity sha1-CXALflB0Mpc5Mw5TXFqQ+2eFFzA= dependencies: es6-error "^4.0.1" +remove-markdown@^0.2.2: + version "0.2.2" + resolved "https://registry.npmjs.org/remove-markdown/-/remove-markdown-0.2.2.tgz#66b0ceeba9fb77ca9636bb1b0307ce21a32a12a6" + integrity sha1-ZrDO66n7d8qWNrsbAwfOIaMqEqY= + remove-trailing-separator@^1.0.1: version "1.1.0" - resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" + resolved "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= repeat-element@^1.1.2: version "1.1.4" - resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.4.tgz#be681520847ab58c7568ac75fbfad28ed42d39e9" + resolved "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz#be681520847ab58c7568ac75fbfad28ed42d39e9" integrity sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ== repeat-string@^1.6.1: version "1.6.1" - resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + resolved "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= request@^2.88.0, request@^2.88.2: version "2.88.2" - resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" + resolved "https://registry.npmjs.org/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== dependencies: aws-sign2 "~0.7.0" @@ -8397,44 +8277,44 @@ request@^2.88.0, request@^2.88.2: require-directory@^2.1.1: version "2.1.1" - resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= require-from-string@^2.0.2: version "2.0.2" - resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + resolved "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== require-main-filename@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" + resolved "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== resolve-cwd@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" + resolved "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== dependencies: resolve-from "^5.0.0" resolve-from@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== resolve-from@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== resolve-url@^0.2.1: version "0.2.1" - resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" + resolved "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= -resolve@^1.10.0, resolve@^1.11.1, resolve@^1.13.1, resolve@^1.17.0, resolve@^1.18.1, resolve@^1.20.0: +resolve@^1.10.0, resolve@^1.10.1, resolve@^1.11.1, resolve@^1.18.1, resolve@^1.20.0: version "1.20.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" + resolved "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A== dependencies: is-core-module "^2.2.0" @@ -8442,7 +8322,7 @@ resolve@^1.10.0, resolve@^1.11.1, resolve@^1.13.1, resolve@^1.17.0, resolve@^1.1 restore-cursor@^3.1.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" + resolved "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== dependencies: onetime "^5.1.0" @@ -8450,87 +8330,97 @@ restore-cursor@^3.1.0: ret@~0.1.10: version "0.1.15" - resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" + resolved "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== retry@^0.12.0: version "0.12.0" - resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" + resolved "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" integrity sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs= reusify@^1.0.4: version "1.0.4" - resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + resolved "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== rfdc@^1.1.4: version "1.3.0" - resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b" + resolved "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b" integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA== -rimraf@^2.6.2, rimraf@^2.6.3: +rimraf@^2.6.3: version "2.7.1" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" + resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== dependencies: glob "^7.1.3" rimraf@^3.0.0, rimraf@^3.0.2: version "3.0.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + resolved "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== dependencies: glob "^7.1.3" rsvp@^4.8.4: version "4.8.5" - resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734" + resolved "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734" integrity sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA== run-async@^2.4.0: version "2.4.1" - resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" + resolved "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== +run-con@~1.2.10: + version "1.2.10" + resolved "https://registry.npmjs.org/run-con/-/run-con-1.2.10.tgz#90de9d43d20274d00478f4c000495bd72f417d22" + integrity sha512-n7PZpYmMM26ZO21dd8y3Yw1TRtGABjRtgPSgFS/nhzfvbJMXFtJhJVyEgayMiP+w/23craJjsnfDvx4W4ue/HQ== + dependencies: + deep-extend "^0.6.0" + ini "~2.0.0" + minimist "^1.2.5" + strip-json-comments "~3.1.1" + run-parallel@^1.1.9: version "1.2.0" - resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + resolved "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== dependencies: queue-microtask "^1.2.2" rxjs@^6.6.0: version "6.6.7" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9" + resolved "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9" integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ== dependencies: tslib "^1.9.0" safe-buffer@^5.0.1, safe-buffer@^5.1.2, safe-buffer@^5.2.1, safe-buffer@~5.2.0: version "5.2.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== safe-regex@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" + resolved "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= dependencies: ret "~0.1.10" "safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: version "2.1.2" - resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== sane@^4.0.3: version "4.1.0" - resolved "https://registry.yarnpkg.com/sane/-/sane-4.1.0.tgz#ed881fd922733a6c461bc189dc2b6c006f3ffded" + resolved "https://registry.npmjs.org/sane/-/sane-4.1.0.tgz#ed881fd922733a6c461bc189dc2b6c006f3ffded" integrity sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA== dependencies: "@cnakazawa/watch" "^1.0.3" @@ -8545,58 +8435,58 @@ sane@^4.0.3: sax@1.2.1: version "1.2.1" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.1.tgz#7b8e656190b228e81a66aea748480d828cd2d37a" + resolved "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz#7b8e656190b228e81a66aea748480d828cd2d37a" integrity sha1-e45lYZCyKOgaZq6nSEgNgozS03o= sax@>=0.6.0, sax@^1.2.4: version "1.2.4" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + resolved "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== saxes@^5.0.1: version "5.0.1" - resolved "https://registry.yarnpkg.com/saxes/-/saxes-5.0.1.tgz#eebab953fa3b7608dbe94e5dadb15c888fa6696d" + resolved "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz#eebab953fa3b7608dbe94e5dadb15c888fa6696d" integrity sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw== dependencies: xmlchars "^2.2.0" semver-intersect@^1.4.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/semver-intersect/-/semver-intersect-1.4.0.tgz#bdd9c06bedcdd2fedb8cd352c3c43ee8c61321f3" + resolved "https://registry.npmjs.org/semver-intersect/-/semver-intersect-1.4.0.tgz#bdd9c06bedcdd2fedb8cd352c3c43ee8c61321f3" integrity sha512-d8fvGg5ycKAq0+I6nfWeCx6ffaWJCsBYU0H2Rq56+/zFePYfT8mXkB3tWBSjR5BerkHNZ5eTPIk1/LBYas35xQ== dependencies: semver "^5.0.0" "semver@2 || 3 || 4 || 5", semver@^5.0.0, semver@^5.5.0, semver@^5.6.0, semver@^5.7.1: version "5.7.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + resolved "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== semver@7.x, semver@^7.1.1, semver@^7.1.3, semver@^7.2.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5: version "7.3.5" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" + resolved "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== dependencies: lru-cache "^6.0.0" -semver@^6.0.0, semver@^6.3.0: +semver@^6.0.0, semver@^6.1.0, semver@^6.1.1, semver@^6.3.0: version "6.3.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + resolved "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== set-blocking@^2.0.0, set-blocking@~2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + resolved "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= set-immediate-shim@~1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" + resolved "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" integrity sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E= set-value@^2.0.0, set-value@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" + resolved "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw== dependencies: extend-shallow "^2.0.1" @@ -8606,48 +8496,48 @@ set-value@^2.0.0, set-value@^2.0.1: setprototypeof@1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" + resolved "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw== shallow-clone@^3.0.0: version "3.0.1" - resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3" + resolved "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3" integrity sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA== dependencies: kind-of "^6.0.2" shebang-command@^1.2.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= dependencies: shebang-regex "^1.0.0" shebang-command@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== dependencies: shebang-regex "^3.0.0" shebang-regex@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= shebang-regex@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== shellwords@^0.1.1: version "0.1.1" - resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" + resolved "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" integrity sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww== side-channel@^1.0.3, side-channel@^1.0.4: version "1.0.4" - resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" + resolved "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== dependencies: call-bind "^1.0.0" @@ -8655,17 +8545,17 @@ side-channel@^1.0.3, side-channel@^1.0.4: object-inspect "^1.9.0" signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" - integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== + version "3.0.5" + resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.5.tgz#9e3e8cc0c75a99472b44321033a7702e7738252f" + integrity sha512-KWcOiKeQj6ZyXx7zq4YxSMgHRlod4czeBQZrPb8OKcohcqAXShm7E20kEMle9WBt26hFcAf0qLOcp5zmY7kOqQ== sinon@^11.1.1: - version "11.1.1" - resolved "https://registry.yarnpkg.com/sinon/-/sinon-11.1.1.tgz#99a295a8b6f0fadbbb7e004076f3ae54fc6eab91" - integrity sha512-ZSSmlkSyhUWbkF01Z9tEbxZLF/5tRC9eojCdFh33gtQaP7ITQVaMWQHGuFM7Cuf/KEfihuh1tTl3/ABju3AQMg== + version "11.1.2" + resolved "https://registry.npmjs.org/sinon/-/sinon-11.1.2.tgz#9e78850c747241d5c59d1614d8f9cbe8840e8674" + integrity sha512-59237HChms4kg7/sXhiRcUzdSkKuydDeTiamT/jesUVHshBgL8XAmhgFo0GfK6RruMDM/iRSij1EybmMog9cJw== dependencies: "@sinonjs/commons" "^1.8.3" - "@sinonjs/fake-timers" "^7.1.0" + "@sinonjs/fake-timers" "^7.1.2" "@sinonjs/samsam" "^6.0.2" diff "^5.0.0" nise "^5.1.0" @@ -8673,7 +8563,7 @@ sinon@^11.1.1: sinon@^9.2.4: version "9.2.4" - resolved "https://registry.yarnpkg.com/sinon/-/sinon-9.2.4.tgz#e55af4d3b174a4443a8762fa8421c2976683752b" + resolved "https://registry.npmjs.org/sinon/-/sinon-9.2.4.tgz#e55af4d3b174a4443a8762fa8421c2976683752b" integrity sha512-zljcULZQsJxVra28qIAL6ow1Z9tpattkCTEJR4RBP3TGc00FcttsP5pK284Nas5WjMZU5Yzy3kAIp3B3KRf5Yg== dependencies: "@sinonjs/commons" "^1.8.1" @@ -8685,22 +8575,22 @@ sinon@^9.2.4: sisteransi@^1.0.5: version "1.0.5" - resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" + resolved "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== slash@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" + resolved "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A== slash@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== slice-ansi@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" + resolved "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ== dependencies: ansi-styles "^4.0.0" @@ -8709,17 +8599,17 @@ slice-ansi@^4.0.0: slide@^1.1.6: version "1.1.6" - resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" + resolved "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" integrity sha1-VusCfWW00tzmyy4tMsTUr8nh1wc= smart-buffer@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.1.0.tgz#91605c25d91652f4661ea69ccf45f1b331ca21ba" - integrity sha512-iVICrxOzCynf/SNaBQCw34eM9jROU/s5rzIhpOvzhzuYHfJR/DhZfDkXiZSgKXfgv26HT3Yni3AV/DGw0cGnnw== + version "4.2.0" + resolved "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae" + integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg== snapdragon-node@^2.0.1: version "2.1.1" - resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" + resolved "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== dependencies: define-property "^1.0.0" @@ -8728,14 +8618,14 @@ snapdragon-node@^2.0.1: snapdragon-util@^3.0.1: version "3.0.1" - resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" + resolved "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== dependencies: kind-of "^3.2.0" snapdragon@^0.8.1: version "0.8.2" - resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" + resolved "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== dependencies: base "^0.11.1" @@ -8749,16 +8639,25 @@ snapdragon@^0.8.1: socks-proxy-agent@5, socks-proxy-agent@^5.0.0: version "5.0.1" - resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-5.0.1.tgz#032fb583048a29ebffec2e6a73fca0761f48177e" + resolved "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-5.0.1.tgz#032fb583048a29ebffec2e6a73fca0761f48177e" integrity sha512-vZdmnjb9a2Tz6WEQVIurybSwElwPxMZaIc7PzqbJTrezcKNznv6giT7J7tZDZ1BojVaa1jvO/UiUdhDVB0ACoQ== dependencies: agent-base "^6.0.2" debug "4" socks "^2.3.3" -socks@^2.3.3: +socks-proxy-agent@^6.0.0: + version "6.1.0" + resolved "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.1.0.tgz#869cf2d7bd10fea96c7ad3111e81726855e285c3" + integrity sha512-57e7lwCN4Tzt3mXz25VxOErJKXlPfXmkMLnk310v/jwW20jWRVcgsOit+xNkN3eIEdB47GwnfAEBLacZ/wVIKg== + dependencies: + agent-base "^6.0.2" + debug "^4.3.1" + socks "^2.6.1" + +socks@^2.3.3, socks@^2.6.1: version "2.6.1" - resolved "https://registry.yarnpkg.com/socks/-/socks-2.6.1.tgz#989e6534a07cf337deb1b1c94aaa44296520d30e" + resolved "https://registry.npmjs.org/socks/-/socks-2.6.1.tgz#989e6534a07cf337deb1b1c94aaa44296520d30e" integrity sha512-kLQ9N5ucj8uIcxrDwjm0Jsqk06xdpBjGNQtpXy4Q8/QY2k+fY7nZH8CARy+hkbG+SGAovmzzuauCpBlb8FrnBA== dependencies: ip "^1.1.5" @@ -8766,7 +8665,7 @@ socks@^2.3.3: sort-json@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/sort-json/-/sort-json-2.0.0.tgz#a7030d8875adbd4a5ea39a000567ed94c1aa3c50" + resolved "https://registry.npmjs.org/sort-json/-/sort-json-2.0.0.tgz#a7030d8875adbd4a5ea39a000567ed94c1aa3c50" integrity sha512-OgXPErPJM/rBK5OhzIJ+etib/BmLQ1JY55Nb/ElhoWUec62pXNF/X6DrecHq3NW5OAGX0KxYD7m0HtgB9dvGeA== dependencies: detect-indent "^5.0.0" @@ -8775,21 +8674,21 @@ sort-json@^2.0.0: sort-keys@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-2.0.0.tgz#658535584861ec97d730d6cf41822e1f56684128" + resolved "https://registry.npmjs.org/sort-keys/-/sort-keys-2.0.0.tgz#658535584861ec97d730d6cf41822e1f56684128" integrity sha1-ZYU1WEhh7JfXMNbPQYIuH1ZoQSg= dependencies: is-plain-obj "^1.0.0" sort-keys@^4.0.0: version "4.2.0" - resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-4.2.0.tgz#6b7638cee42c506fff8c1cecde7376d21315be18" + resolved "https://registry.npmjs.org/sort-keys/-/sort-keys-4.2.0.tgz#6b7638cee42c506fff8c1cecde7376d21315be18" integrity sha512-aUYIEU/UviqPgc8mHR6IW1EGxkAXpeRETYcrzg8cLAvUPZcpAlleSXHV2mY7G12GphSH6Gzv+4MMVSSkbdteHg== dependencies: is-plain-obj "^2.0.0" source-map-resolve@^0.5.0: version "0.5.3" - resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" + resolved "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" integrity sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw== dependencies: atob "^2.1.2" @@ -8798,49 +8697,37 @@ source-map-resolve@^0.5.0: source-map-url "^0.4.0" urix "^0.1.0" -source-map-support@^0.5.10, source-map-support@^0.5.17, source-map-support@^0.5.19, source-map-support@^0.5.6: - version "0.5.19" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" - integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw== +source-map-support@^0.5.17, source-map-support@^0.5.20, source-map-support@^0.5.6: + version "0.5.20" + resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.20.tgz#12166089f8f5e5e8c56926b377633392dd2cb6c9" + integrity sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw== dependencies: buffer-from "^1.0.0" source-map "^0.6.0" source-map-url@^0.4.0: version "0.4.1" - resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.1.tgz#0af66605a745a5a2f91cf1bbf8a7afbc283dec56" + resolved "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz#0af66605a745a5a2f91cf1bbf8a7afbc283dec56" integrity sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw== source-map@^0.5.0, source-map@^0.5.6: version "0.5.7" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + resolved "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: version "0.6.1" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== source-map@^0.7.3: version "0.7.3" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" + resolved "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== -spawn-wrap@^1.4.2: - version "1.4.3" - resolved "https://registry.yarnpkg.com/spawn-wrap/-/spawn-wrap-1.4.3.tgz#81b7670e170cca247d80bf5faf0cfb713bdcf848" - integrity sha512-IgB8md0QW/+tWqcavuFgKYR/qIRvJkRLPJDFaoXtLLUaVcCDK0+HeFTkmQHj3eprcYhc+gOl0aEA1w7qZlYezw== - dependencies: - foreground-child "^1.5.6" - mkdirp "^0.5.0" - os-homedir "^1.0.1" - rimraf "^2.6.2" - signal-exit "^3.0.2" - which "^1.3.0" - spawn-wrap@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/spawn-wrap/-/spawn-wrap-2.0.0.tgz#103685b8b8f9b79771318827aa78650a610d457e" + resolved "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz#103685b8b8f9b79771318827aa78650a610d457e" integrity sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg== dependencies: foreground-child "^2.0.0" @@ -8852,7 +8739,7 @@ spawn-wrap@^2.0.0: spdx-correct@^3.0.0: version "3.1.1" - resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9" + resolved "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9" integrity sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w== dependencies: spdx-expression-parse "^3.0.0" @@ -8860,61 +8747,61 @@ spdx-correct@^3.0.0: spdx-exceptions@^2.1.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz#3f28ce1a77a00372683eade4a433183527a2163d" + resolved "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz#3f28ce1a77a00372683eade4a433183527a2163d" integrity sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A== spdx-expression-parse@^3.0.0: version "3.0.1" - resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679" + resolved "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679" integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q== dependencies: spdx-exceptions "^2.1.0" spdx-license-ids "^3.0.0" spdx-license-ids@^3.0.0: - version "3.0.9" - resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.9.tgz#8a595135def9592bda69709474f1cbeea7c2467f" - integrity sha512-Ki212dKK4ogX+xDo4CtOZBVIwhsKBEfsEEcwmJfLQzirgc2jIWdzg40Unxz/HzEUqM1WFzVlQSMF9kZZ2HboLQ== + version "3.0.10" + resolved "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.10.tgz#0d9becccde7003d6c658d487dd48a32f0bf3014b" + integrity sha512-oie3/+gKf7QtpitB0LYLETe+k8SifzsX4KixvpOsbI6S0kRiRQ5MKOio8eMSAKQ17N06+wdEOXRiId+zOxo0hA== spdx-license-list@^6.4.0: version "6.4.0" - resolved "https://registry.yarnpkg.com/spdx-license-list/-/spdx-license-list-6.4.0.tgz#9850c3699c1d35745285607d064d2a5145049d12" + resolved "https://registry.npmjs.org/spdx-license-list/-/spdx-license-list-6.4.0.tgz#9850c3699c1d35745285607d064d2a5145049d12" integrity sha512-4BxgJ1IZxTJuX1YxMGu2cRYK46Bk9zJNTK2/R0wNZR0cm+6SVl26/uG7FQmQtxoJQX1uZ0EpTi2L7zvMLboaBA== split-on-first@^1.0.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/split-on-first/-/split-on-first-1.1.0.tgz#f610afeee3b12bce1d0c30425e76398b78249a5f" + resolved "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz#f610afeee3b12bce1d0c30425e76398b78249a5f" integrity sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw== split-string@^3.0.1, split-string@^3.0.2: version "3.1.0" - resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" + resolved "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== dependencies: extend-shallow "^3.0.0" split2@^3.0.0: version "3.2.2" - resolved "https://registry.yarnpkg.com/split2/-/split2-3.2.2.tgz#bf2cf2a37d838312c249c89206fd7a17dd12365f" + resolved "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz#bf2cf2a37d838312c249c89206fd7a17dd12365f" integrity sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg== dependencies: readable-stream "^3.0.0" split@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/split/-/split-1.0.1.tgz#605bd9be303aa59fb35f9229fbea0ddec9ea07d9" + resolved "https://registry.npmjs.org/split/-/split-1.0.1.tgz#605bd9be303aa59fb35f9229fbea0ddec9ea07d9" integrity sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg== dependencies: through "2" sprintf-js@~1.0.2: version "1.0.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= sshpk@^1.7.0: version "1.16.1" - resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877" + resolved "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877" integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg== dependencies: asn1 "~0.2.3" @@ -8929,28 +8816,21 @@ sshpk@^1.7.0: ssri@^8.0.0, ssri@^8.0.1: version "8.0.1" - resolved "https://registry.yarnpkg.com/ssri/-/ssri-8.0.1.tgz#638e4e439e2ffbd2cd289776d5ca457c4f51a2af" + resolved "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz#638e4e439e2ffbd2cd289776d5ca457c4f51a2af" integrity sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ== dependencies: minipass "^3.1.1" -stack-utils@^1.0.2: - version "1.0.5" - resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-1.0.5.tgz#a19b0b01947e0029c8e451d5d61a498f5bb1471b" - integrity sha512-KZiTzuV3CnSnSvgMRrARVCj+Ht7rMbauGDK0LdVFRGyenwdylpajAp4Q0i6SX8rEmbTpMMf6ryq2gb8pPq2WgQ== - dependencies: - escape-string-regexp "^2.0.0" - stack-utils@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.3.tgz#cd5f030126ff116b78ccb3c027fe302713b61277" - integrity sha512-gL//fkxfWUsIlFL2Tl42Cl6+HFALEaB1FU76I/Fy+oZjRreP7OPMXFlGbxM7NQsI0ZpUfw76sHnv0WNYuTb7Iw== + version "2.0.5" + resolved "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz#d25265fca995154659dbbfba3b49254778d2fdd5" + integrity sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA== dependencies: escape-string-regexp "^2.0.0" standard-version@^9.3.1: version "9.3.1" - resolved "https://registry.yarnpkg.com/standard-version/-/standard-version-9.3.1.tgz#786c16c318847f58a31a2434f97e8db33a635853" + resolved "https://registry.npmjs.org/standard-version/-/standard-version-9.3.1.tgz#786c16c318847f58a31a2434f97e8db33a635853" integrity sha512-5qMxXw/FxLouC5nANyx/5RY1kiorJx9BppUso8gN07MG64q2uLRmrPb4KfXp3Ql4s/gxjZwZ89e0FwxeLubGww== dependencies: chalk "^2.4.2" @@ -8971,7 +8851,7 @@ standard-version@^9.3.1: static-extend@^0.1.1: version "0.1.2" - resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" + resolved "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= dependencies: define-property "^0.2.5" @@ -8979,12 +8859,12 @@ static-extend@^0.1.1: "statuses@>= 1.5.0 < 2": version "1.5.0" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + resolved "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= streamroller@^2.2.4: version "2.2.4" - resolved "https://registry.yarnpkg.com/streamroller/-/streamroller-2.2.4.tgz#c198ced42db94086a6193608187ce80a5f2b0e53" + resolved "https://registry.npmjs.org/streamroller/-/streamroller-2.2.4.tgz#c198ced42db94086a6193608187ce80a5f2b0e53" integrity sha512-OG79qm3AujAM9ImoqgWEY1xG4HX+Lw+yY6qZj9R1K2mhF5bEmQ849wvrb+4vt4jLMLzwXttJlQbOdPOQVRv7DQ== dependencies: date-format "^2.1.0" @@ -8993,34 +8873,34 @@ streamroller@^2.2.4: strict-uri-encode@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546" + resolved "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546" integrity sha1-ucczDHBChi9rFC3CdLvMWGbONUY= string-length@^4.0.1: version "4.0.2" - resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" + resolved "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" integrity sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ== dependencies: char-regex "^1.0.2" strip-ansi "^6.0.0" -string-width@*, string-width@^1.0.1, "string-width@^1.0.2 || 2", string-width@^3.0.0, string-width@^3.1.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.2.tgz#dafd4f9559a7585cfba529c6a0a4f73488ebd4c5" - integrity sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA== +string-width@*, string-width@^1.0.1, "string-width@^1.0.2 || 2", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== dependencies: emoji-regex "^8.0.0" is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.0" + strip-ansi "^6.0.1" string.prototype.repeat@^0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/string.prototype.repeat/-/string.prototype.repeat-0.2.0.tgz#aba36de08dcee6a5a337d49b2ea1da1b28fc0ecf" + resolved "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-0.2.0.tgz#aba36de08dcee6a5a337d49b2ea1da1b28fc0ecf" integrity sha1-q6Nt4I3O5qWjN9SbLqHaGyj8Ds8= string.prototype.trimend@^1.0.4: version "1.0.4" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz#e75ae90c2942c63504686c18b287b4a0b1a45f80" + resolved "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz#e75ae90c2942c63504686c18b287b4a0b1a45f80" integrity sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A== dependencies: call-bind "^1.0.2" @@ -9028,7 +8908,7 @@ string.prototype.trimend@^1.0.4: string.prototype.trimstart@^1.0.4: version "1.0.4" - resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz#b36399af4ab2999b4c9c648bd7a3fb2bb26feeed" + resolved "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz#b36399af4ab2999b4c9c648bd7a3fb2bb26feeed" integrity sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw== dependencies: call-bind "^1.0.2" @@ -9036,89 +8916,84 @@ string.prototype.trimstart@^1.0.4: string_decoder@^1.1.1: version "1.3.0" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== dependencies: safe-buffer "~5.2.0" string_decoder@~0.10.x: version "0.10.31" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ= string_decoder@~1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== dependencies: safe-buffer "~5.1.0" stringify-package@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/stringify-package/-/stringify-package-1.0.1.tgz#e5aa3643e7f74d0f28628b72f3dad5cecfc3ba85" + resolved "https://registry.npmjs.org/stringify-package/-/stringify-package-1.0.1.tgz#e5aa3643e7f74d0f28628b72f3dad5cecfc3ba85" integrity sha512-sa4DUQsYciMP1xhKWGuFM04fB0LG/9DlluZoSVywUMRNvzid6XucHK0/90xGxRoHrAaROrcHK1aPKaijCtSrhg== strip-ansi@^3.0.0, strip-ansi@^3.0.1: version "3.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= dependencies: ansi-regex "^2.0.0" -strip-ansi@^5.0.0, strip-ansi@^5.2.0: +strip-ansi@^5.2.0: version "5.2.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== dependencies: ansi-regex "^4.1.0" -strip-ansi@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" - integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w== +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== dependencies: - ansi-regex "^5.0.0" + ansi-regex "^5.0.1" strip-bom@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= strip-bom@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" + resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== strip-eof@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + resolved "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= strip-final-newline@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + resolved "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== strip-indent@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-3.0.0.tgz#c32e1cee940b6b3432c771bc2c54bcce73cd3001" + resolved "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz#c32e1cee940b6b3432c771bc2c54bcce73cd3001" integrity sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ== dependencies: min-indent "^1.0.0" -strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: +strip-json-comments@^3.1.0, strip-json-comments@^3.1.1, strip-json-comments@~3.1.1: version "3.1.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== -strip-json-comments@~2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" - integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= - strong-log-transformer@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/strong-log-transformer/-/strong-log-transformer-2.1.0.tgz#0f5ed78d325e0421ac6f90f7f10e691d6ae3ae10" + resolved "https://registry.npmjs.org/strong-log-transformer/-/strong-log-transformer-2.1.0.tgz#0f5ed78d325e0421ac6f90f7f10e691d6ae3ae10" integrity sha512-B3Hgul+z0L9a236FAUC9iZsL+nVHgoCJnqCbN588DjYxvGXaXaaFbfmQ/JhvKjZwsOukuR72XbHv71Qkug0HxA== dependencies: duplexer "^0.1.1" @@ -9127,28 +9002,21 @@ strong-log-transformer@^2.1.0: supports-color@^5.3.0: version "5.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== dependencies: has-flag "^3.0.0" -supports-color@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3" - integrity sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ== - dependencies: - has-flag "^3.0.0" - supports-color@^7.0.0, supports-color@^7.1.0, supports-color@^7.2.0: version "7.2.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== dependencies: has-flag "^4.0.0" supports-hyperlinks@^2.0.0: version "2.2.0" - resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz#4f77b42488765891774b70c79babd87f9bd594bb" + resolved "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz#4f77b42488765891774b70c79babd87f9bd594bb" integrity sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ== dependencies: has-flag "^4.0.0" @@ -9156,103 +9024,24 @@ supports-hyperlinks@^2.0.0: symbol-tree@^3.2.4: version "3.2.4" - resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" + resolved "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== -table@*, table@^6.0.9, table@^6.7.1: - version "6.7.1" - resolved "https://registry.yarnpkg.com/table/-/table-6.7.1.tgz#ee05592b7143831a8c94f3cee6aae4c1ccef33e2" - integrity sha512-ZGum47Yi6KOOFDE8m223td53ath2enHcYLgOCjGr5ngu8bdIARQk6mN/wRMv4yMRcHnCSnHbCEha4sobQx5yWg== +table@*, table@^6.0.9, table@^6.7.2: + version "6.7.2" + resolved "https://registry.npmjs.org/table/-/table-6.7.2.tgz#a8d39b9f5966693ca8b0feba270a78722cbaf3b0" + integrity sha512-UFZK67uvyNivLeQbVtkiUs8Uuuxv24aSL4/Vil2PJVtMgU8Lx0CYkP12uCGa3kjyQzOSgV1+z9Wkb82fCGsO0g== dependencies: ajv "^8.0.1" lodash.clonedeep "^4.5.0" lodash.truncate "^4.4.2" slice-ansi "^4.0.0" - string-width "^4.2.0" - strip-ansi "^6.0.0" - -tap-mocha-reporter@^3.0.9, tap-mocha-reporter@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/tap-mocha-reporter/-/tap-mocha-reporter-5.0.1.tgz#74f00be2ddd2a380adad45e085795137bc39497a" - integrity sha512-1knFWOwd4khx/7uSEnUeaP9IPW3w+sqTgJMhrwah6t46nZ8P25atOKAjSvVDsT67lOPu0nfdOqUwoyKn+3E5pA== - dependencies: - color-support "^1.1.0" - debug "^4.1.1" - diff "^4.0.1" - escape-string-regexp "^2.0.0" - glob "^7.0.5" - tap-parser "^10.0.0" - tap-yaml "^1.0.0" - unicode-length "^2.0.2" - -tap-parser@^10.0.0: - version "10.1.0" - resolved "https://registry.yarnpkg.com/tap-parser/-/tap-parser-10.1.0.tgz#7b1aac40dbcaa4716c0b58952686eae65d2b74ad" - integrity sha512-FujQeciDaOiOvaIVGS1Rpb0v4R6XkOjvWCWowlz5oKuhPkEJ8U6pxgqt38xuzYhPt8dWEnfHn2jqpZdJEkW7pA== - dependencies: - events-to-array "^1.0.1" - minipass "^3.0.0" - tap-yaml "^1.0.0" - -tap-parser@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/tap-parser/-/tap-parser-7.0.0.tgz#54db35302fda2c2ccc21954ad3be22b2cba42721" - integrity sha512-05G8/LrzqOOFvZhhAk32wsGiPZ1lfUrl+iV7+OkKgfofZxiceZWMHkKmow71YsyVQ8IvGBP2EjcIjE5gL4l5lA== - dependencies: - events-to-array "^1.0.1" - js-yaml "^3.2.7" - minipass "^2.2.0" - -tap-yaml@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/tap-yaml/-/tap-yaml-1.0.0.tgz#4e31443a5489e05ca8bbb3e36cef71b5dec69635" - integrity sha512-Rxbx4EnrWkYk0/ztcm5u3/VznbyFJpyXO12dDBHKWiDVxy7O2Qw6MRrwO5H6Ww0U5YhRY/4C/VzWmFPhBQc4qQ== - dependencies: - yaml "^1.5.0" - -tap@^12.0.1: - version "12.7.0" - resolved "https://registry.yarnpkg.com/tap/-/tap-12.7.0.tgz#6e0c40eb7ec1347a9311aa3ce9dee098dc41b566" - integrity sha512-SjglJmRv0pqrQQ7d5ZBEY8ZOqv3nYDBXEX51oyycOH7piuhn82JKT/yDNewwmOsodTD/RZL9MccA96EjDgK+Eg== - dependencies: - bind-obj-methods "^2.0.0" - browser-process-hrtime "^1.0.0" - capture-stack-trace "^1.0.0" - clean-yaml-object "^0.1.0" - color-support "^1.1.0" - coveralls "^3.0.2" - domain-browser "^1.2.0" - esm "^3.2.5" - foreground-child "^1.3.3" - fs-exists-cached "^1.0.0" - function-loop "^1.0.1" - glob "^7.1.3" - isexe "^2.0.0" - js-yaml "^3.13.1" - minipass "^2.3.5" - mkdirp "^0.5.1" - nyc "^14.0.0" - opener "^1.5.1" - os-homedir "^1.0.2" - own-or "^1.0.0" - own-or-env "^1.0.1" - rimraf "^2.6.3" - signal-exit "^3.0.0" - source-map-support "^0.5.10" - stack-utils "^1.0.2" - tap-mocha-reporter "^3.0.9" - tap-parser "^7.0.0" - tmatch "^4.0.0" - trivial-deferred "^1.0.1" - ts-node "^8.0.2" - tsame "^2.0.1" - typescript "^3.3.3" - write-file-atomic "^2.4.2" - yapool "^1.0.0" + string-width "^4.2.3" + strip-ansi "^6.0.1" tar-stream@^2.2.0: version "2.2.0" - resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287" + resolved "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287" integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ== dependencies: bl "^4.0.3" @@ -9263,7 +9052,7 @@ tar-stream@^2.2.0: tar@^4.4.12: version "4.4.19" - resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.19.tgz#2e4d7263df26f2b914dee10c825ab132123742f3" + resolved "https://registry.npmjs.org/tar/-/tar-4.4.19.tgz#2e4d7263df26f2b914dee10c825ab132123742f3" integrity sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA== dependencies: chownr "^1.1.4" @@ -9275,9 +9064,9 @@ tar@^4.4.12: yallist "^3.1.1" tar@^6.0.2, tar@^6.1.0: - version "6.1.8" - resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.8.tgz#4fc50cfe56511c538ce15b71e05eebe66530cbd4" - integrity sha512-sb9b0cp855NbkMJcskdSYA7b11Q8JsX4qe4pyUAfHp+Y6jBjJeek2ZVlwEfWayshEIwlIzXx0Fain3QG9JPm2A== + version "6.1.11" + resolved "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz#6760a38f003afa1b2ffd0ffe9e9abbd0eab3d621" + integrity sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA== dependencies: chownr "^2.0.0" fs-minipass "^2.0.0" @@ -9288,17 +9077,17 @@ tar@^6.0.2, tar@^6.1.0: temp-dir@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/temp-dir/-/temp-dir-1.0.0.tgz#0a7c0ea26d3a39afa7e0ebea9c1fc0bc4daa011d" + resolved "https://registry.npmjs.org/temp-dir/-/temp-dir-1.0.0.tgz#0a7c0ea26d3a39afa7e0ebea9c1fc0bc4daa011d" integrity sha1-CnwOom06Oa+n4OvqnB/AvE2qAR0= temp-dir@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/temp-dir/-/temp-dir-2.0.0.tgz#bde92b05bdfeb1516e804c9c00ad45177f31321e" + resolved "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz#bde92b05bdfeb1516e804c9c00ad45177f31321e" integrity sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg== temp-write@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/temp-write/-/temp-write-4.0.0.tgz#cd2e0825fc826ae72d201dc26eef3bf7e6fc9320" + resolved "https://registry.npmjs.org/temp-write/-/temp-write-4.0.0.tgz#cd2e0825fc826ae72d201dc26eef3bf7e6fc9320" integrity sha512-HIeWmj77uOOHb0QX7siN3OtwV3CTntquin6TNVg6SHOqCP3hYKmox90eeFOGaY1MqJ9WYDDjkyZrW6qS5AWpbw== dependencies: graceful-fs "^4.1.15" @@ -9309,7 +9098,7 @@ temp-write@^4.0.0: tempfile@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/tempfile/-/tempfile-3.0.0.tgz#5376a3492de7c54150d0cc0612c3f00e2cdaf76c" + resolved "https://registry.npmjs.org/tempfile/-/tempfile-3.0.0.tgz#5376a3492de7c54150d0cc0612c3f00e2cdaf76c" integrity sha512-uNFCg478XovRi85iD42egu+eSFUmmka750Jy7L5tfHI5hQKKtbPnxaSaXAbBqCDYrw3wx4tXjKwci4/QmsZJxw== dependencies: temp-dir "^2.0.0" @@ -9317,25 +9106,15 @@ tempfile@^3.0.0: terminal-link@^2.0.0: version "2.1.1" - resolved "https://registry.yarnpkg.com/terminal-link/-/terminal-link-2.1.1.tgz#14a64a27ab3c0df933ea546fba55f2d078edc994" + resolved "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz#14a64a27ab3c0df933ea546fba55f2d078edc994" integrity sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ== dependencies: ansi-escapes "^4.2.1" supports-hyperlinks "^2.0.0" -test-exclude@^5.2.3: - version "5.2.3" - resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-5.2.3.tgz#c3d3e1e311eb7ee405e092dac10aefd09091eac0" - integrity sha512-M+oxtseCFO3EDtAaGH7iiej3CBkzXqFMbzqYAACdzKui4eZA+pq3tZEwChvOdNfa7xxy8BfbmgJSIr43cC/+2g== - dependencies: - glob "^7.1.3" - minimatch "^3.0.4" - read-pkg-up "^4.0.0" - require-main-filename "^2.0.0" - test-exclude@^6.0.0: version "6.0.0" - resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" + resolved "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== dependencies: "@istanbuljs/schema" "^0.1.2" @@ -9344,22 +9123,22 @@ test-exclude@^6.0.0: text-extensions@^1.0.0: version "1.9.0" - resolved "https://registry.yarnpkg.com/text-extensions/-/text-extensions-1.9.0.tgz#1853e45fee39c945ce6f6c36b2d659b5aabc2a26" + resolved "https://registry.npmjs.org/text-extensions/-/text-extensions-1.9.0.tgz#1853e45fee39c945ce6f6c36b2d659b5aabc2a26" integrity sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ== text-table@^0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= throat@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/throat/-/throat-5.0.0.tgz#c5199235803aad18754a667d659b5e72ce16764b" + resolved "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz#c5199235803aad18754a667d659b5e72ce16764b" integrity sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA== through2@^2.0.0: version "2.0.5" - resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" + resolved "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== dependencies: readable-stream "~2.3.6" @@ -9367,48 +9146,43 @@ through2@^2.0.0: through2@^4.0.0: version "4.0.2" - resolved "https://registry.yarnpkg.com/through2/-/through2-4.0.2.tgz#a7ce3ac2a7a8b0b966c80e7c49f0484c3b239764" + resolved "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz#a7ce3ac2a7a8b0b966c80e7c49f0484c3b239764" integrity sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw== dependencies: readable-stream "3" through@2, "through@>=2.2.7 <3", through@^2.3.4, through@^2.3.6: version "2.3.8" - resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + resolved "https://registry.npmjs.org/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= -tmatch@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/tmatch/-/tmatch-4.0.0.tgz#ba178007f30bf6a70f37c643fca5045fb2f8c448" - integrity sha512-Ynn2Gsp+oCvYScQXeV+cCs7citRDilq0qDXA6tuvFwDgiYyyaq7D5vKUlAPezzZR5NDobc/QMeN6e5guOYmvxg== - tmp@^0.0.33: version "0.0.33" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + resolved "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== dependencies: os-tmpdir "~1.0.2" tmpl@1.0.x: - version "1.0.4" - resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" - integrity sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE= + version "1.0.5" + resolved "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" + integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== to-fast-properties@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= to-object-path@^0.3.0: version "0.3.0" - resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" + resolved "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= dependencies: kind-of "^3.0.2" to-regex-range@^2.1.0: version "2.1.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" + resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= dependencies: is-number "^3.0.0" @@ -9416,14 +9190,14 @@ to-regex-range@^2.1.0: to-regex-range@^5.0.1: version "5.0.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== dependencies: is-number "^7.0.0" to-regex@^3.0.1, to-regex@^3.0.2: version "3.0.2" - resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" + resolved "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== dependencies: define-property "^2.0.2" @@ -9433,12 +9207,12 @@ to-regex@^3.0.1, to-regex@^3.0.2: toidentifier@1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" + resolved "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== tough-cookie@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.0.0.tgz#d822234eeca882f991f0f908824ad2622ddbece4" + resolved "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz#d822234eeca882f991f0f908824ad2622ddbece4" integrity sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg== dependencies: psl "^1.1.33" @@ -9447,7 +9221,7 @@ tough-cookie@^4.0.0: tough-cookie@~2.5.0: version "2.5.0" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" + resolved "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== dependencies: psl "^1.1.28" @@ -9455,34 +9229,29 @@ tough-cookie@~2.5.0: tr46@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-2.1.0.tgz#fa87aa81ca5d5941da8cbf1f9b749dc969a4e240" + resolved "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz#fa87aa81ca5d5941da8cbf1f9b749dc969a4e240" integrity sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw== dependencies: punycode "^2.1.1" +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o= + traverse@^0.6.6: version "0.6.6" - resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.6.6.tgz#cbdf560fd7b9af632502fed40f918c157ea97137" + resolved "https://registry.npmjs.org/traverse/-/traverse-0.6.6.tgz#cbdf560fd7b9af632502fed40f918c157ea97137" integrity sha1-y99WD9e5r2MlAv7UD5GMFX6pcTc= trim-newlines@^3.0.0: version "3.0.1" - resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-3.0.1.tgz#260a5d962d8b752425b32f3a7db0dcacd176c144" + resolved "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz#260a5d962d8b752425b32f3a7db0dcacd176c144" integrity sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw== -trim-off-newlines@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/trim-off-newlines/-/trim-off-newlines-1.0.1.tgz#9f9ba9d9efa8764c387698bcbfeb2c848f11adb3" - integrity sha1-n5up2e+odkw4dpi8v+sshI8RrbM= - -trivial-deferred@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/trivial-deferred/-/trivial-deferred-1.0.1.tgz#376d4d29d951d6368a6f7a0ae85c2f4d5e0658f3" - integrity sha1-N21NKdlR1jaKb3oK6FwvTV4GWPM= - ts-jest@^26.5.6: version "26.5.6" - resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-26.5.6.tgz#c32e0746425274e1dfe333f43cd3c800e014ec35" + resolved "https://registry.npmjs.org/ts-jest/-/ts-jest-26.5.6.tgz#c32e0746425274e1dfe333f43cd3c800e014ec35" integrity sha512-rua+rCP8DxpA8b4DQD/6X2HQS8Zy/xzViVYfEs2OQu68tkCuKLV0Md8pmX55+W24uRIyAsf/BajRfxOs+R2MKA== dependencies: bs-logger "0.x" @@ -9498,23 +9267,30 @@ ts-jest@^26.5.6: ts-mock-imports@^1.3.7: version "1.3.7" - resolved "https://registry.yarnpkg.com/ts-mock-imports/-/ts-mock-imports-1.3.7.tgz#8c3210a641f40fd5cadbd1c9c88574b51df59bde" + resolved "https://registry.npmjs.org/ts-mock-imports/-/ts-mock-imports-1.3.7.tgz#8c3210a641f40fd5cadbd1c9c88574b51df59bde" integrity sha512-zy4B3QSGaOhjaX9j0h9YKwM1oHG4Kd1KIUJBeXlXIQrFnATNLgh4+NyRcaAHsPeqwe3TWeRtHXkNXPxySEKk3w== -ts-node@^8.0.2: - version "8.10.2" - resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-8.10.2.tgz#eee03764633b1234ddd37f8db9ec10b75ec7fb8d" - integrity sha512-ISJJGgkIpDdBhWVu3jufsWpK3Rzo7bdiIXJjQc0ynKxVOVcg2oIrf2H2cejminGrptVc6q6/uynAHNCuWGbpVA== - dependencies: +ts-node@^10.2.1: + version "10.3.0" + resolved "https://registry.npmjs.org/ts-node/-/ts-node-10.3.0.tgz#a797f2ed3ff50c9a5d814ce400437cb0c1c048b4" + integrity sha512-RYIy3i8IgpFH45AX4fQHExrT8BxDeKTdC83QFJkNzkvt8uFB6QJ8XMyhynYiKMLxt9a7yuXaDBZNOYS3XjDcYw== + dependencies: + "@cspotcode/source-map-support" "0.7.0" + "@tsconfig/node10" "^1.0.7" + "@tsconfig/node12" "^1.0.7" + "@tsconfig/node14" "^1.0.0" + "@tsconfig/node16" "^1.0.2" + acorn "^8.4.1" + acorn-walk "^8.1.1" arg "^4.1.0" + create-require "^1.1.0" diff "^4.0.1" make-error "^1.1.1" - source-map-support "^0.5.17" yn "3.1.1" ts-node@^9.1.1: version "9.1.1" - resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-9.1.1.tgz#51a9a450a3e959401bda5f004a72d54b936d376d" + resolved "https://registry.npmjs.org/ts-node/-/ts-node-9.1.1.tgz#51a9a450a3e959401bda5f004a72d54b936d376d" integrity sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg== dependencies: arg "^4.1.0" @@ -9524,171 +9300,162 @@ ts-node@^9.1.1: source-map-support "^0.5.17" yn "3.1.1" -tsame@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/tsame/-/tsame-2.0.1.tgz#70410ddbefcd29c61e2d68549b3347b0444d613f" - integrity sha512-jxyxgKVKa4Bh5dPcO42TJL22lIvfd9LOVJwdovKOnJa4TLLrHxquK+DlGm4rkGmrcur+GRx+x4oW00O2pY/fFw== - -tsconfig-paths@^3.9.0: - version "3.10.1" - resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.10.1.tgz#79ae67a68c15289fdf5c51cb74f397522d795ed7" - integrity sha512-rETidPDgCpltxF7MjBZlAFPUHv5aHH2MymyPvh+vEyWAED4Eb/WeMbsnD/JDr4OKPOA1TssDHgIcpTN5Kh0p6Q== +tsconfig-paths@^3.11.0, tsconfig-paths@^3.9.0: + version "3.11.0" + resolved "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.11.0.tgz#954c1fe973da6339c78e06b03ce2e48810b65f36" + integrity sha512-7ecdYDnIdmv639mmDwslG6KQg1Z9STTz1j7Gcz0xa+nshh/gKDAHcPxRbWOsA3SPp0tXP2leTcY9Kw+NAkfZzA== dependencies: - json5 "^2.2.0" + "@types/json5" "^0.0.29" + json5 "^1.0.1" minimist "^1.2.0" strip-bom "^3.0.0" tslib@^1.8.1, tslib@^1.9.0: version "1.14.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" + resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== tslib@^2.0.1: - version "2.3.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.0.tgz#803b8cdab3e12ba581a4ca41c8839bbb0dacb09e" - integrity sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg== + version "2.3.1" + resolved "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" + integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== tsutils@^3.21.0: version "3.21.0" - resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" + resolved "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== dependencies: tslib "^1.8.1" tunnel-agent@^0.6.0: version "0.6.0" - resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + resolved "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= dependencies: safe-buffer "^5.0.1" tunnel@0.0.6: version "0.0.6" - resolved "https://registry.yarnpkg.com/tunnel/-/tunnel-0.0.6.tgz#72f1314b34a5b192db012324df2cc587ca47f92c" + resolved "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz#72f1314b34a5b192db012324df2cc587ca47f92c" integrity sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg== tweetnacl@^0.14.3, tweetnacl@~0.14.0: version "0.14.5" - resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + resolved "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + resolved "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== dependencies: prelude-ls "^1.2.1" type-check@~0.3.2: version "0.3.2" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + resolved "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= dependencies: prelude-ls "~1.1.2" type-detect@4.0.8, type-detect@^4.0.8: version "4.0.8" - resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" + resolved "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== -type-fest@^0.13.1: - version "0.13.1" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.13.1.tgz#0172cb5bce80b0bd542ea348db50c7e21834d934" - integrity sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg== - type-fest@^0.18.0: version "0.18.1" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.18.1.tgz#db4bc151a4a2cf4eebf9add5db75508db6cc841f" + resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz#db4bc151a4a2cf4eebf9add5db75508db6cc841f" integrity sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw== type-fest@^0.20.2: version "0.20.2" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" + resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== type-fest@^0.21.3: version "0.21.3" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" + resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== type-fest@^0.4.1: version "0.4.1" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.4.1.tgz#8bdf77743385d8a4f13ba95f610f5ccd68c728f8" + resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.4.1.tgz#8bdf77743385d8a4f13ba95f610f5ccd68c728f8" integrity sha512-IwzA/LSfD2vC1/YDYMv/zHP4rDF1usCwllsDpbolT3D4fUepIO7f9K70jjmUewU/LmGUKJcwcVtDCpnKk4BPMw== type-fest@^0.6.0: version "0.6.0" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b" + resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b" integrity sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg== type-fest@^0.8.0, type-fest@^0.8.1: version "0.8.1" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" + resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== typedarray-to-buffer@^3.1.5: version "3.1.5" - resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" + resolved "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== dependencies: is-typedarray "^1.0.0" typedarray@^0.0.6: version "0.0.6" - resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + resolved "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= -typescript-json-schema@^0.50.1: - version "0.50.1" - resolved "https://registry.yarnpkg.com/typescript-json-schema/-/typescript-json-schema-0.50.1.tgz#48041eb9f6efbdf4ba88c3e3af9433601f7a2b47" - integrity sha512-GCof/SDoiTDl0qzPonNEV4CHyCsZEIIf+mZtlrjoD8vURCcEzEfa2deRuxYid8Znp/e27eDR7Cjg8jgGrimBCA== +typescript-json-schema@^0.51.0: + version "0.51.0" + resolved "https://registry.npmjs.org/typescript-json-schema/-/typescript-json-schema-0.51.0.tgz#e2abff69b8564c98c0edef2c13d55ef10fd71427" + integrity sha512-POhWbUNs2oaBti1W9k/JwS+uDsaZD9J/KQiZ/iXRQEOD0lTn9VmshIls9tn+A9X6O+smPjeEz5NEy6WTkCCzrQ== dependencies: - "@types/json-schema" "^7.0.7" - "@types/node" "^14.14.33" - glob "^7.1.6" + "@types/json-schema" "^7.0.9" + "@types/node" "^16.9.2" + glob "^7.1.7" json-stable-stringify "^1.0.1" - ts-node "^9.1.1" + ts-node "^10.2.1" typescript "~4.2.3" - yargs "^16.2.0" - -typescript@^3.3.3, typescript@~3.9.10, typescript@~3.9.9: - version "3.9.10" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.10.tgz#70f3910ac7a51ed6bef79da7800690b19bf778b8" - integrity sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q== + yargs "^17.1.1" typescript@~3.8.3: version "3.8.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.8.3.tgz#409eb8544ea0335711205869ec458ab109ee1061" + resolved "https://registry.npmjs.org/typescript/-/typescript-3.8.3.tgz#409eb8544ea0335711205869ec458ab109ee1061" integrity sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w== +typescript@~3.9.10: + version "3.9.10" + resolved "https://registry.npmjs.org/typescript/-/typescript-3.9.10.tgz#70f3910ac7a51ed6bef79da7800690b19bf778b8" + integrity sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q== + typescript@~4.2.3: version "4.2.4" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.2.4.tgz#8610b59747de028fda898a8aef0e103f156d0961" + resolved "https://registry.npmjs.org/typescript/-/typescript-4.2.4.tgz#8610b59747de028fda898a8aef0e103f156d0961" integrity sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg== uc.micro@^1.0.1, uc.micro@^1.0.5: version "1.0.6" - resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac" + resolved "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac" integrity sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA== uglify-js@^3.1.4: - version "3.13.10" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.13.10.tgz#a6bd0d28d38f592c3adb6b180ea6e07e1e540a8d" - integrity sha512-57H3ACYFXeo1IaZ1w02sfA71wI60MGco/IQFjOqK+WtKoprh7Go2/yvd2HPtoJILO2Or84ncLccI4xoHMTSbGg== + version "3.14.2" + resolved "https://registry.npmjs.org/uglify-js/-/uglify-js-3.14.2.tgz#d7dd6a46ca57214f54a2d0a43cad0f35db82ac99" + integrity sha512-rtPMlmcO4agTUfz10CbgJ1k6UAoXM2gWb3GoMPPZB/+/Ackf8lNWk11K4rYi2D0apgoFRLtQOZhb+/iGNJq26A== uid-number@0.0.6: version "0.0.6" - resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" + resolved "https://registry.npmjs.org/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" integrity sha1-DqEOgDXo61uOREnwbaHHMGY7qoE= umask@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/umask/-/umask-1.1.0.tgz#f29cebf01df517912bb58ff9c4e50fde8e33320d" + resolved "https://registry.npmjs.org/umask/-/umask-1.1.0.tgz#f29cebf01df517912bb58ff9c4e50fde8e33320d" integrity sha1-8pzr8B31F5ErtY/5xOUP3o4zMg0= unbox-primitive@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.1.tgz#085e215625ec3162574dc8859abee78a59b14471" + resolved "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz#085e215625ec3162574dc8859abee78a59b14471" integrity sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw== dependencies: function-bind "^1.1.1" @@ -9696,17 +9463,9 @@ unbox-primitive@^1.0.1: has-symbols "^1.0.2" which-boxed-primitive "^1.0.2" -unicode-length@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/unicode-length/-/unicode-length-2.0.2.tgz#e5eb4c0d523fdf7bebb59ca261c9ca1cf732da96" - integrity sha512-Ph/j1VbS3/r77nhoY2WU0GWGjVYOHL3xpKp0y/Eq2e5r0mT/6b649vm7KFO6RdAdrZkYLdxphYVgvODxPB+Ebg== - dependencies: - punycode "^2.0.0" - strip-ansi "^3.0.1" - union-value@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" + resolved "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg== dependencies: arr-union "^3.1.0" @@ -9716,48 +9475,48 @@ union-value@^1.0.0: unique-filename@^1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230" + resolved "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230" integrity sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ== dependencies: unique-slug "^2.0.0" unique-slug@^2.0.0: version "2.0.2" - resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.2.tgz#baabce91083fc64e945b0f3ad613e264f7cd4e6c" + resolved "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz#baabce91083fc64e945b0f3ad613e264f7cd4e6c" integrity sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w== dependencies: imurmurhash "^0.1.4" universal-user-agent@^4.0.0: version "4.0.1" - resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-4.0.1.tgz#fd8d6cb773a679a709e967ef8288a31fcc03e557" + resolved "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-4.0.1.tgz#fd8d6cb773a679a709e967ef8288a31fcc03e557" integrity sha512-LnST3ebHwVL2aNe4mejI9IQh2HfZ1RLo8Io2HugSif8ekzD1TlWpHpColOB/eh8JHMLkGH3Akqf040I+4ylNxg== dependencies: os-name "^3.1.0" universal-user-agent@^6.0.0: version "6.0.0" - resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-6.0.0.tgz#3381f8503b251c0d9cd21bc1de939ec9df5480ee" + resolved "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz#3381f8503b251c0d9cd21bc1de939ec9df5480ee" integrity sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w== universalify@^0.1.0, universalify@^0.1.2: version "0.1.2" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + resolved "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== universalify@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" + resolved "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== unpipe@1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + resolved "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= unset-value@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" + resolved "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= dependencies: has-value "^0.3.1" @@ -9765,24 +9524,24 @@ unset-value@^1.0.0: upath@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/upath/-/upath-2.0.1.tgz#50c73dea68d6f6b990f51d279ce6081665d61a8b" + resolved "https://registry.npmjs.org/upath/-/upath-2.0.1.tgz#50c73dea68d6f6b990f51d279ce6081665d61a8b" integrity sha512-1uEe95xksV1O0CYKXo8vQvN1JEbtJp7lb7C5U9HMsIp6IVwntkH/oNUzyVNQSd4S1sYk2FpSSW44FqMc8qee5w== uri-js@^4.2.2: version "4.4.1" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + resolved "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== dependencies: punycode "^2.1.0" urix@^0.1.0: version "0.1.0" - resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" + resolved "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= url@0.10.3: version "0.10.3" - resolved "https://registry.yarnpkg.com/url/-/url-0.10.3.tgz#021e4d9c7705f21bbf37d03ceb58767402774c64" + resolved "https://registry.npmjs.org/url/-/url-0.10.3.tgz#021e4d9c7705f21bbf37d03ceb58767402774c64" integrity sha1-Ah5NnHcF8hu/N9A861h2dAJ3TGQ= dependencies: punycode "1.3.2" @@ -9790,49 +9549,49 @@ url@0.10.3: use@^3.1.0: version "3.1.1" - resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" + resolved "https://registry.npmjs.org/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== utf8@^2.1.1: version "2.1.2" - resolved "https://registry.yarnpkg.com/utf8/-/utf8-2.1.2.tgz#1fa0d9270e9be850d9b05027f63519bf46457d96" + resolved "https://registry.npmjs.org/utf8/-/utf8-2.1.2.tgz#1fa0d9270e9be850d9b05027f63519bf46457d96" integrity sha1-H6DZJw6b6FDZsFAn9jUZv0ZFfZY= util-deprecate@^1.0.1, util-deprecate@~1.0.1: version "1.0.2" - resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= util-promisify@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/util-promisify/-/util-promisify-2.1.0.tgz#3c2236476c4d32c5ff3c47002add7c13b9a82a53" + resolved "https://registry.npmjs.org/util-promisify/-/util-promisify-2.1.0.tgz#3c2236476c4d32c5ff3c47002add7c13b9a82a53" integrity sha1-PCI2R2xNMsX/PEcAKt18E7moKlM= dependencies: object.getownpropertydescriptors "^2.0.3" uuid@3.3.2: version "3.3.2" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" + resolved "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA== uuid@^3.3.2, uuid@^3.3.3: version "3.4.0" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" + resolved "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== uuid@^8.3.0, uuid@^8.3.2: version "8.3.2" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + resolved "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== v8-compile-cache@^2.0.3: version "2.3.0" - resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" + resolved "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== v8-to-istanbul@^7.0.0: version "7.1.2" - resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-7.1.2.tgz#30898d1a7fa0c84d225a2c1434fb958f290883c1" + resolved "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-7.1.2.tgz#30898d1a7fa0c84d225a2c1434fb958f290883c1" integrity sha512-TxNb7YEUwkLXCQYeudi6lgQ/SZrzNO4kMdlqVxaZPUIUjCv6iSSypUQX70kNBSERpQ8fk48+d61FXk+tgqcWow== dependencies: "@types/istanbul-lib-coverage" "^2.0.1" @@ -9841,7 +9600,7 @@ v8-to-istanbul@^7.0.0: validate-npm-package-license@^3.0.1, validate-npm-package-license@^3.0.4: version "3.0.4" - resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" + resolved "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== dependencies: spdx-correct "^3.0.0" @@ -9849,14 +9608,19 @@ validate-npm-package-license@^3.0.1, validate-npm-package-license@^3.0.4: validate-npm-package-name@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz#5fa912d81eb7d0c74afc140de7317f0ca7df437e" + resolved "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz#5fa912d81eb7d0c74afc140de7317f0ca7df437e" integrity sha1-X6kS2B630MdK/BQN5zF/DKffQ34= dependencies: builtins "^1.0.3" +vandium-utils@^1.1.1: + version "1.2.0" + resolved "https://registry.npmjs.org/vandium-utils/-/vandium-utils-1.2.0.tgz#44735de4b7641a05de59ebe945f174e582db4f59" + integrity sha1-RHNd5LdkGgXeWevpRfF05YLbT1k= + verror@1.10.0: version "1.10.0" - resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" + resolved "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= dependencies: assert-plus "^1.0.0" @@ -9864,63 +9628,76 @@ verror@1.10.0: extsprintf "^1.2.0" vm2@^3.9.3: - version "3.9.3" - resolved "https://registry.yarnpkg.com/vm2/-/vm2-3.9.3.tgz#29917f6cc081cc43a3f580c26c5b553fd3c91f40" - integrity sha512-smLS+18RjXYMl9joyJxMNI9l4w7biW8ilSDaVRvFBDwOH8P0BK1ognFQTpg0wyQ6wIKLTblHJvROW692L/E53Q== + version "3.9.4" + resolved "https://registry.npmjs.org/vm2/-/vm2-3.9.4.tgz#2e118290fefe7bd8ea09ebe2f5faf53730dbddaa" + integrity sha512-sOdharrJ7KEePIpHekiWaY1DwgueuiBeX/ZBJUPgETsVlJsXuEx0K0/naATq2haFvJrvZnRiORQRubR0b7Ye6g== w3c-hr-time@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd" + resolved "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd" integrity sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ== dependencies: browser-process-hrtime "^1.0.0" w3c-xmlserializer@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz#3e7104a05b75146cc60f564380b7f683acf1020a" + resolved "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz#3e7104a05b75146cc60f564380b7f683acf1020a" integrity sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA== dependencies: xml-name-validator "^3.0.0" walker@^1.0.7, walker@~1.0.5: version "1.0.7" - resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" + resolved "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" integrity sha1-L3+bj9ENZ3JisYqITijRlhjgKPs= dependencies: makeerror "1.0.x" wcwidth@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" + resolved "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" integrity sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g= dependencies: defaults "^1.0.3" +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + integrity sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE= + webidl-conversions@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-5.0.0.tgz#ae59c8a00b121543a2acc65c0434f57b0fc11aff" + resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz#ae59c8a00b121543a2acc65c0434f57b0fc11aff" integrity sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA== webidl-conversions@^6.1.0: version "6.1.0" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-6.1.0.tgz#9111b4d7ea80acd40f5270d666621afa78b69514" + resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz#9111b4d7ea80acd40f5270d666621afa78b69514" integrity sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w== whatwg-encoding@^1.0.5: version "1.0.5" - resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0" + resolved "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0" integrity sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw== dependencies: iconv-lite "0.4.24" whatwg-mimetype@^2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" + resolved "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== +whatwg-url@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" + integrity sha1-lmRU6HZUYuN2RNNib2dCzotwll0= + dependencies: + tr46 "~0.0.3" + webidl-conversions "^3.0.0" + whatwg-url@^8.0.0, whatwg-url@^8.4.0, whatwg-url@^8.5.0: version "8.7.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-8.7.0.tgz#656a78e510ff8f3937bc0bcbe9f5c0ac35941b77" + resolved "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz#656a78e510ff8f3937bc0bcbe9f5c0ac35941b77" integrity sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg== dependencies: lodash "^4.7.0" @@ -9929,7 +9706,7 @@ whatwg-url@^8.0.0, whatwg-url@^8.4.0, whatwg-url@^8.5.0: which-boxed-primitive@^1.0.1, which-boxed-primitive@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" + resolved "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== dependencies: is-bigint "^1.0.1" @@ -9940,7 +9717,7 @@ which-boxed-primitive@^1.0.1, which-boxed-primitive@^1.0.2: which-collection@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/which-collection/-/which-collection-1.0.1.tgz#70eab71ebbbd2aefaf32f917082fc62cdcb70906" + resolved "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz#70eab71ebbbd2aefaf32f917082fc62cdcb70906" integrity sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A== dependencies: is-map "^2.0.1" @@ -9950,72 +9727,62 @@ which-collection@^1.0.1: which-module@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" + resolved "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= which-typed-array@^1.1.2: - version "1.1.4" - resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.4.tgz#8fcb7d3ee5adf2d771066fba7cf37e32fe8711ff" - integrity sha512-49E0SpUe90cjpoc7BOJwyPHRqSAd12c10Qm2amdEZrJPCY2NDxaW01zHITrem+rnETY3dwrbH3UUrUwagfCYDA== + version "1.1.7" + resolved "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.7.tgz#2761799b9a22d4b8660b3c1b40abaa7739691793" + integrity sha512-vjxaB4nfDqwKI0ws7wZpxIlde1XrLX5uB0ZjpfshgmapJMD7jJWhZI+yToJTqaFByF0eNBcYxbjmCzoRP7CfEw== dependencies: - available-typed-arrays "^1.0.2" - call-bind "^1.0.0" - es-abstract "^1.18.0-next.1" + available-typed-arrays "^1.0.5" + call-bind "^1.0.2" + es-abstract "^1.18.5" foreach "^2.0.5" - function-bind "^1.1.1" - has-symbols "^1.0.1" - is-typed-array "^1.1.3" + has-tostringtag "^1.0.0" + is-typed-array "^1.1.7" -which@^1.2.9, which@^1.3.0, which@^1.3.1: +which@^1.2.9, which@^1.3.1: version "1.3.1" - resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + resolved "https://registry.npmjs.org/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== dependencies: isexe "^2.0.0" which@^2.0.1, which@^2.0.2: version "2.0.2" - resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== dependencies: isexe "^2.0.0" wide-align@^1.1.0: version "1.1.3" - resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" + resolved "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== dependencies: string-width "^1.0.2 || 2" windows-release@^3.1.0: version "3.3.3" - resolved "https://registry.yarnpkg.com/windows-release/-/windows-release-3.3.3.tgz#1c10027c7225743eec6b89df160d64c2e0293999" + resolved "https://registry.npmjs.org/windows-release/-/windows-release-3.3.3.tgz#1c10027c7225743eec6b89df160d64c2e0293999" integrity sha512-OSOGH1QYiW5yVor9TtmXKQvt2vjQqbYS+DqmsZw+r7xDwLXEeT3JGW0ZppFmHx4diyXmxt238KFR3N9jzevBRg== dependencies: execa "^1.0.0" word-wrap@^1.2.3, word-wrap@~1.2.3: version "1.2.3" - resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" + resolved "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== wordwrap@>=0.0.2, wordwrap@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= -wrap-ansi@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" - integrity sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q== - dependencies: - ansi-styles "^3.2.0" - string-width "^3.0.0" - strip-ansi "^5.0.0" - wrap-ansi@^6.2.0: version "6.2.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA== dependencies: ansi-styles "^4.0.0" @@ -10024,7 +9791,7 @@ wrap-ansi@^6.2.0: wrap-ansi@^7.0.0: version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== dependencies: ansi-styles "^4.0.0" @@ -10033,12 +9800,12 @@ wrap-ansi@^7.0.0: wrappy@1: version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= write-file-atomic@^2.4.2: version "2.4.3" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.4.3.tgz#1fd2e9ae1df3e75b8d8c367443c692d4ca81f481" + resolved "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz#1fd2e9ae1df3e75b8d8c367443c692d4ca81f481" integrity sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ== dependencies: graceful-fs "^4.1.11" @@ -10047,7 +9814,7 @@ write-file-atomic@^2.4.2: write-file-atomic@^3.0.0, write-file-atomic@^3.0.3: version "3.0.3" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8" + resolved "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8" integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q== dependencies: imurmurhash "^0.1.4" @@ -10057,7 +9824,7 @@ write-file-atomic@^3.0.0, write-file-atomic@^3.0.3: write-json-file@^3.2.0: version "3.2.0" - resolved "https://registry.yarnpkg.com/write-json-file/-/write-json-file-3.2.0.tgz#65bbdc9ecd8a1458e15952770ccbadfcff5fe62a" + resolved "https://registry.npmjs.org/write-json-file/-/write-json-file-3.2.0.tgz#65bbdc9ecd8a1458e15952770ccbadfcff5fe62a" integrity sha512-3xZqT7Byc2uORAatYiP3DHUUAVEkNOswEWNs9H5KXiicRTvzYzYqKjYc4G7p+8pltvAw641lVByKVtMpf+4sYQ== dependencies: detect-indent "^5.0.0" @@ -10069,7 +9836,7 @@ write-json-file@^3.2.0: write-json-file@^4.3.0: version "4.3.0" - resolved "https://registry.yarnpkg.com/write-json-file/-/write-json-file-4.3.0.tgz#908493d6fd23225344af324016e4ca8f702dd12d" + resolved "https://registry.npmjs.org/write-json-file/-/write-json-file-4.3.0.tgz#908493d6fd23225344af324016e4ca8f702dd12d" integrity sha512-PxiShnxf0IlnQuMYOPPhPkhExoCQuTUNPOa/2JWCYTmBquU9njyyDuwRKN26IZBlp4yn1nt+Agh2HOOBl+55HQ== dependencies: detect-indent "^6.0.0" @@ -10081,33 +9848,33 @@ write-json-file@^4.3.0: write-pkg@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/write-pkg/-/write-pkg-4.0.0.tgz#675cc04ef6c11faacbbc7771b24c0abbf2a20039" + resolved "https://registry.npmjs.org/write-pkg/-/write-pkg-4.0.0.tgz#675cc04ef6c11faacbbc7771b24c0abbf2a20039" integrity sha512-v2UQ+50TNf2rNHJ8NyWttfm/EJUBWMJcx6ZTYZr6Qp52uuegWw/lBkCtCbnYZEmPRNL61m+u67dAmGxo+HTULA== dependencies: sort-keys "^2.0.0" type-fest "^0.4.1" write-json-file "^3.2.0" -ws@^7.4.5: - version "7.5.3" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.3.tgz#160835b63c7d97bfab418fc1b8a9fced2ac01a74" - integrity sha512-kQ/dHIzuLrS6Je9+uv81ueZomEwH0qVYstcAQ4/Z93K8zeko9gtAbttJWzoC5ukqXY1PpoouV3+VSOqEAFt5wg== +ws@^7.4.6: + version "7.5.5" + resolved "https://registry.npmjs.org/ws/-/ws-7.5.5.tgz#8b4bc4af518cfabd0473ae4f99144287b33eb881" + integrity sha512-BAkMFcAzl8as1G/hArkxOxq3G7pjUqQ3gzYbLL0/5zNkph70e+lCoxBGnm6AW1+/aiNeV4fnKqZ8m4GZewmH2w== xml-js@^1.6.11: version "1.6.11" - resolved "https://registry.yarnpkg.com/xml-js/-/xml-js-1.6.11.tgz#927d2f6947f7f1c19a316dd8eea3614e8b18f8e9" + resolved "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz#927d2f6947f7f1c19a316dd8eea3614e8b18f8e9" integrity sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g== dependencies: sax "^1.2.4" xml-name-validator@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" + resolved "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== xml2js@0.4.19: version "0.4.19" - resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.19.tgz#686c20f213209e94abf0d1bcf1efaa291c7827a7" + resolved "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz#686c20f213209e94abf0d1bcf1efaa291c7827a7" integrity sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q== dependencies: sax ">=0.6.0" @@ -10115,119 +9882,85 @@ xml2js@0.4.19: xml@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/xml/-/xml-1.0.1.tgz#78ba72020029c5bc87b8a81a3cfcd74b4a2fc1e5" + resolved "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz#78ba72020029c5bc87b8a81a3cfcd74b4a2fc1e5" integrity sha1-eLpyAgApxbyHuKgaPPzXS0ovweU= xmlbuilder@^15.1.1: version "15.1.1" - resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-15.1.1.tgz#9dcdce49eea66d8d10b42cae94a79c3c8d0c2ec5" + resolved "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz#9dcdce49eea66d8d10b42cae94a79c3c8d0c2ec5" integrity sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg== xmlbuilder@~9.0.1: version "9.0.7" - resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.7.tgz#132ee63d2ec5565c557e20f4c22df9aca686b10d" + resolved "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz#132ee63d2ec5565c557e20f4c22df9aca686b10d" integrity sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0= xmlchars@^2.2.0: version "2.2.0" - resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" + resolved "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== xregexp@2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/xregexp/-/xregexp-2.0.0.tgz#52a63e56ca0b84a7f3a5f3d61872f126ad7a5943" + resolved "https://registry.npmjs.org/xregexp/-/xregexp-2.0.0.tgz#52a63e56ca0b84a7f3a5f3d61872f126ad7a5943" integrity sha1-UqY+VsoLhKfzpfPWGHLxJq16WUM= xtend@~4.0.1: version "4.0.2" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" + resolved "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== y18n@^4.0.0: version "4.0.3" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf" + resolved "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf" integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ== y18n@^5.0.5: version "5.0.8" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== -yallist@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" - integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= - yallist@^3.0.0, yallist@^3.0.2, yallist@^3.1.1: version "3.1.1" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + resolved "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== yallist@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + resolved "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== -yaml@*, yaml@1.10.2, yaml@^1.10.0, yaml@^1.5.0: +yaml@*, yaml@1.10.2, yaml@^1.10.0: version "1.10.2" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" + resolved "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== yaml@2.0.0-1: version "2.0.0-1" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.0.0-1.tgz#8c3029b3ee2028306d5bcf396980623115ff8d18" + resolved "https://registry.npmjs.org/yaml/-/yaml-2.0.0-1.tgz#8c3029b3ee2028306d5bcf396980623115ff8d18" integrity sha512-W7h5dEhywMKenDJh2iX/LABkbFnBxasD27oyXWDS/feDsxiw0dD5ncXdYXgkvAsXIY2MpW/ZKkr9IU30DBdMNQ== -yapool@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/yapool/-/yapool-1.0.0.tgz#f693f29a315b50d9a9da2646a7a6645c96985b6a" - integrity sha1-9pPymjFbUNmp2iZGp6ZkXJaYW2o= - yargs-parser@20.2.4: version "20.2.4" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54" + resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54" integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA== yargs-parser@20.x, yargs-parser@^20.2.2, yargs-parser@^20.2.3: version "20.2.9" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" + resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== -yargs-parser@^13.0.0, yargs-parser@^13.1.2: - version "13.1.2" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38" - integrity sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg== - dependencies: - camelcase "^5.0.0" - decamelize "^1.2.0" - -yargs-parser@^18.1.2, yargs-parser@^18.1.3: +yargs-parser@^18.1.2: version "18.1.3" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" + resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ== dependencies: camelcase "^5.0.0" decamelize "^1.2.0" -yargs@^13.2.2: - version "13.3.2" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd" - integrity sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw== - dependencies: - cliui "^5.0.0" - find-up "^3.0.0" - get-caller-file "^2.0.1" - require-directory "^2.1.1" - require-main-filename "^2.0.0" - set-blocking "^2.0.0" - string-width "^3.0.0" - which-module "^2.0.0" - y18n "^4.0.0" - yargs-parser "^13.1.2" - yargs@^15.0.2, yargs@^15.4.1: version "15.4.1" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8" + resolved "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8" integrity sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A== dependencies: cliui "^6.0.0" @@ -10244,7 +9977,7 @@ yargs@^15.0.2, yargs@^15.4.1: yargs@^16.0.0, yargs@^16.2.0: version "16.2.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" + resolved "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== dependencies: cliui "^7.0.2" @@ -10255,19 +9988,32 @@ yargs@^16.0.0, yargs@^16.2.0: y18n "^5.0.5" yargs-parser "^20.2.2" +yargs@^17.1.1: + version "17.2.1" + resolved "https://registry.npmjs.org/yargs/-/yargs-17.2.1.tgz#e2c95b9796a0e1f7f3bf4427863b42e0418191ea" + integrity sha512-XfR8du6ua4K6uLGm5S6fA+FIJom/MdJcFNVY8geLlp2v8GYbOXD4EB1tPNZsRn4vBzKGMgb5DRZMeWuFc2GO8Q== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.0" + y18n "^5.0.5" + yargs-parser "^20.2.2" + yn@3.1.1: version "3.1.1" - resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" + resolved "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== yocto-queue@^0.1.0: version "0.1.0" - resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== zip-stream@^4.1.0: version "4.1.0" - resolved "https://registry.yarnpkg.com/zip-stream/-/zip-stream-4.1.0.tgz#51dd326571544e36aa3f756430b313576dc8fc79" + resolved "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.0.tgz#51dd326571544e36aa3f756430b313576dc8fc79" integrity sha512-zshzwQW7gG7hjpBlgeQP9RuyPGNxvJdzR8SUM3QhxCnLjWN2E7j3dOvpeDcQoETfHx0urRS7EtmVToql7YpU4A== dependencies: archiver-utils "^2.1.0"