├── .eslintrc.js ├── .github ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE │ ├── Bug_report.md │ └── Feature_request.md └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── LICENSE ├── README.md ├── modules └── aws │ ├── acm │ ├── main.tf │ ├── output.tf │ ├── variable.tf │ └── versions.tf │ ├── api │ ├── alb.tf │ ├── codebuild.tf │ ├── codedeploy.tf │ ├── fargate.tf │ ├── iam.tf │ ├── local_ssm_parameter.tf │ ├── output.tf │ ├── route53.tf │ ├── secretsmanager.tf │ ├── ssm_parameter.tf │ ├── task │ │ └── fargate-api.json │ ├── variable.tf │ └── versions.tf │ ├── bastion │ ├── main.tf │ ├── output.tf │ ├── variable.tf │ └── versions.tf │ ├── ecr │ ├── main.tf │ ├── output.tf │ └── versions.tf │ ├── frontend │ ├── cloudfront.tf │ ├── codebuild.tf │ ├── local_ssm_parameter.tf │ ├── s3.tf │ ├── secretsmanager.tf │ ├── ssm_parameter.tf │ ├── variable.tf │ └── versions.tf │ ├── iam │ ├── main.tf │ ├── output.tf │ └── versions.tf │ ├── rds │ ├── iam.tf │ ├── main.tf │ ├── variable.tf │ └── versions.tf │ └── vpc │ ├── main.tf │ ├── nat-instance.tf │ ├── output.tf │ ├── variable.tf │ └── versions.tf ├── package.json ├── providers └── aws │ └── environments │ ├── 10-network │ ├── main.tf │ ├── output.tf │ ├── variable.tf │ └── versions.tf │ ├── 11-acm │ ├── main.tf │ ├── output.tf │ ├── variable.tf │ └── versions.tf │ ├── 12-ecr │ ├── main.tf │ ├── output.tf │ └── versions.tf │ ├── 13-iam │ ├── main.tf │ └── output.tf │ ├── 20-bastion │ ├── main.tf │ ├── output.tf │ ├── variable.tf │ └── versions.tf │ ├── 21-api │ ├── main.tf │ ├── output.tf │ ├── variable.tf │ └── versions.tf │ ├── 22-frontend │ ├── main.tf │ ├── variable.tf │ └── versions.tf │ └── 23-rds │ ├── main.tf │ ├── variable.tf │ └── versions.tf ├── scripts ├── createBackend.ts ├── createProvider.ts ├── createTerraformConfig.ts ├── createTfvars.ts └── terraformConfigUtil.ts ├── tsconfig.json ├── versions.tf └── yarn.lock /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | node: true, 4 | es6: true 5 | }, 6 | extends: [ 7 | 'eslint:recommended', 8 | 'plugin:prettier/recommended' 9 | ], 10 | plugins: [ 11 | '@typescript-eslint' 12 | ], 13 | parser: '@typescript-eslint/parser', 14 | parserOptions: { 15 | 'sourceType': 'module', 16 | 'project': './tsconfig.json', 17 | 'ecmaVersion': 2019 18 | }, 19 | rules: { 20 | 'no-console': 0, 21 | 'no-unused-vars': 0 22 | }, 23 | settings: { 24 | node: { 25 | tryExtensions: ['.ts', '.tsx', '.js', '.jsx', '.json', '.node'] 26 | } 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # PRを出す前に確認する事 2 | 3 | 以下の条件を満たしているか再度チェックしよう🐱! 4 | 5 | - PRのタイトルは分かりやすい事(理想は非エンジニアが見ても何となく分かるように、無理な場合も多いけど・・・) 6 | - READMEに書いてるセルフチェックが全て完了している事 7 | - e.g. Lintでのコード整形 8 | - e.g テストコードの実装 9 | - PRテンプレートに従って必要な情報が記載されている事 10 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/Bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: バグ報告 3 | about: バグの報告用テンプレート 4 | 5 | --- 6 | 7 | # 概要 8 | [required] 9 | 10 | # 再現手順 11 | [required] 12 | 13 | # 再現環境 14 | [required] 15 | 16 | # このバグによって引き起こされる問題 17 | [optional] 18 | 19 | # スクリーンショット 20 | [optional] 21 | 22 | # 補足情報 23 | [optional] 24 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/Feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: ストーリー 3 | about: スクラム開発でいうところのストーリーのテンプレート 4 | 5 | --- 6 | 7 | # Doneの定義 8 | [required] 9 | 10 | # 補足情報 11 | [optional] 12 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | # issueURL 2 | [required] 3 | 4 | # 関連URL 5 | [optional] 6 | 7 | # Doneの定義 8 | [required] 9 | 10 | # スクリーンショット 11 | [optional] ただしUI変更の時は [required] 12 | 13 | # 変更点概要 14 | 15 | ## 仕様的変更点概要 16 | [optional] 17 | 18 | ## 技術的変更点概要 19 | [required] 20 | 21 | # レビュアーに重点的にチェックして欲しい点 22 | [optional] 23 | 24 | # 補足情報 25 | [optional] 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Terraform template 3 | # Local .terraform directories 4 | **/.terraform/* 5 | 6 | # .tfstate files 7 | *.tfstate 8 | *.tfstate.* 9 | 10 | # Crash log files 11 | crash.log 12 | 13 | # Ignore any .tfvars files that are generated automatically for each Terraform run. Most 14 | # .tfvars files are managed as part of configuration and so should be included in 15 | # version control. 16 | # 17 | # example.tfvars 18 | 19 | # IDEA Setting File 20 | .idea 21 | qiita-stocker-terraform.iml 22 | dev-qiita-stocker-terraform.iml 23 | prod-qiita-stocker-terraform.iml 24 | 25 | providers/aws/environments/10-network/terraform.tfvars 26 | providers/aws/environments/11-acm/terraform.tfvars 27 | providers/aws/environments/20-bastion/terraform.tfvars 28 | providers/aws/environments/21-api/terraform.tfvars 29 | providers/aws/environments/22-frontend/terraform.tfvars 30 | providers/aws/environments/23-rds/terraform.tfvars 31 | providers/aws/environments/25-ecs/terraform.tfvars 32 | providers/aws/environments/26-fargate/terraform.tfvars 33 | 34 | # Node.js 35 | node_modules 36 | dist 37 | 38 | # backend.tf, provider.tf 39 | providers/aws/environments/**/backend.tf 40 | providers/aws/environments/**/provider.tf 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 nekochans 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # qiita-stocker-terraform 2 | 3 | # 事前準備 4 | 5 | ## AWSクレデンシャルの設定 6 | 7 | 自身の利用しているMacOS PC上で `brew install awscli` を実行します。 8 | 9 | `aws configure --profile qiita-stocker-dev` を実行します。 10 | 11 | 対話式のインターフェースに以下を入力します。 12 | 13 | ``` 14 | AWS Access Key ID [None]: `アクセスキーIDを入力` 15 | AWS Secret Access Key [None]: `シークレットアクセスキーを入力` 16 | Default region name [None]: ap-northeast-1 17 | Default output format [None]: json 18 | ``` 19 | 20 | 同じく `aws configure --profile qiita-stocker-dev` を実行します。 21 | 22 | 先程と同じように対話式のインターフェースに従い必要な情報を入力します。 23 | 24 | `~/.aws/credentials` に下記のように設定されていればOKです。 25 | 26 | ``` 27 | [qiita-stocker-dev] 28 | aws_access_key_id = 開発・ステージング用アクセスキーID 29 | aws_secret_access_key = 開発・ステージング用シークレットアクセスキー 30 | [qiita-stocker-prod] 31 | aws_access_key_id = 本番用アクセスキーID 32 | aws_secret_access_key = 本番用シークレットアクセスキー 33 | ``` 34 | 35 | `brew install awscli` を実行しない場合でもともかく `~/.aws/credentials` が上記の状態になっていればOKです。 36 | 37 | # terraformを実行に必要なconfigファイルを作成する 38 | 39 | 本プロジェクトは開発・ステージングと本番用のAWSアカウントを使い分けることを想定しています。 40 | 41 | その為以下のファイルはGitの管理対象外となっています。 42 | 43 | - `backend.tf` 44 | - `provider.tf` 45 | - `terraform.tfvars` 46 | 47 | 以下のコマンドを実行することで、それぞれの環境に応じた設定ファイルを作成出来ます。 48 | 49 | 仕組みとしてはAWS SecretsManagerにある機密情報にアクセスを行い、それを元に設定ファイルを作成しています。 50 | 51 | ## 開発・ステージング用のconfigファイルを作成 52 | `yarn run createConfig:dev` 53 | 54 | ## 本番用のconfigファイルを作成 55 | `yarn run createConfig:prod` 56 | 57 | ## 設定ファイルに関する注意点 58 | 59 | 設定ファイルの切り替えを行った後は `terraform init` の実行が必要になります。 60 | 61 | ステージングと本番両方で作業する際に混乱する可能性もあります。 62 | 63 | 以下のように本Gitリポジトリを開発・ステージング用、本番用と分けて作業すると良いかもしれません。 64 | 65 | ```bash 66 | $ git clone git@github.com:nekochans/qiita-stocker-terraform.git dev-qiita-stocker-terraform 67 | $ git clone git@github.com:nekochans/qiita-stocker-terraform.git prod-qiita-stocker-terraform 68 | ``` 69 | 70 | こうしておくと一度 `createConfig` を実行してしまえば、設定ファイルの内容に変更がない限りはそのまま各環境で作業が可能です。 71 | 72 | ## コーディング規約 73 | 74 | 以下の命名規則に従って命名します。 75 | 76 | | 項目名 | 命名規則 | 77 | |----------------|----------------| 78 | | ファイル名 | ケバブケース | 79 | | ディレクトリ名 | ケバブケース | 80 | | リソースID | スネークケース | 81 | | リソース名 | ケバブケース | 82 | | 変数名 | スネークケース | 83 | 84 | リソースIDというのは `resource` や `data` 等のTerraformの予約語に付けられる名前です。 85 | 86 | ```hcl 87 | resource "aws_security_group_rule" "ssh_from_all_to_bastion" { 88 | } 89 | ``` 90 | 91 | リソース名はそのリソースの中で一意になっている必要がある値です。 92 | 93 | 下記の例だと `key_name` がそれに該当します。 94 | 95 | ```hcl 96 | resource "aws_key_pair" "ssh_key_pair" { 97 | public_key = "${file(var.ssh_public_key_path)}" 98 | key_name = "${terraform.workspace}-ssh-key" 99 | } 100 | ``` 101 | 102 | 他にもタグ名を良く付ける事がありますが、それもこちらのルールの通りケバブケースで命名します。 103 | 104 | ``` 105 | tags { 106 | Name = "${lookup(var.bastion, "${terraform.env}.name", var.bastion["default.name"])}-1a" 107 | } 108 | ``` 109 | 110 | このようなややこしい規則になっている理由ですが、RDSCluster等、一部のリソース名で `_` が禁止文字に設定されている為です。 111 | 112 | 他にもインデント等細かいルールがありますが、こちらに関しては `terraform fmt` を実行すれば自動整形されるのでこれを利用すれば良いでしょう。 113 | 114 | `terraform fmt` は必ずプロジェクトルートで実行を行ってください。 115 | 116 | そうしないと全ての `.tf` ファイルに修正が適応されません。 117 | -------------------------------------------------------------------------------- /modules/aws/acm/main.tf: -------------------------------------------------------------------------------- 1 | data "aws_acm_certificate" "main" { 2 | domain = "*.${var.main_domain_name}" 3 | } 4 | -------------------------------------------------------------------------------- /modules/aws/acm/output.tf: -------------------------------------------------------------------------------- 1 | output "acm" { 2 | value = { 3 | "main_arn" = data.aws_acm_certificate.main.arn 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /modules/aws/acm/variable.tf: -------------------------------------------------------------------------------- 1 | variable "main_domain_name" { 2 | type = string 3 | 4 | default = "" 5 | } 6 | -------------------------------------------------------------------------------- /modules/aws/acm/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 0.12" 3 | } 4 | -------------------------------------------------------------------------------- /modules/aws/api/alb.tf: -------------------------------------------------------------------------------- 1 | // Fargate 2 | resource "aws_security_group" "fargate_api_alb" { 3 | name = "${lookup( 4 | var.fargate, 5 | "${terraform.workspace}.name", 6 | var.fargate["default.name"] 7 | )}-alb" 8 | description = "Security Group to ${lookup( 9 | var.fargate, 10 | "${terraform.workspace}.name", 11 | var.fargate["default.name"] 12 | )}-alb" 13 | vpc_id = var.vpc["vpc_id"] 14 | 15 | tags = { 16 | Name = "${lookup( 17 | var.fargate, 18 | "${terraform.workspace}.name", 19 | var.fargate["default.name"] 20 | )}-alb" 21 | } 22 | 23 | egress { 24 | from_port = 0 25 | to_port = 0 26 | protocol = "-1" 27 | cidr_blocks = ["0.0.0.0/0"] 28 | } 29 | } 30 | 31 | resource "aws_security_group_rule" "fargate_api_alb" { 32 | security_group_id = aws_security_group.fargate_api_alb.id 33 | type = "ingress" 34 | from_port = 443 35 | to_port = 443 36 | protocol = "tcp" 37 | cidr_blocks = ["0.0.0.0/0"] 38 | } 39 | 40 | resource "aws_s3_bucket" "fargate_api_alb_logs" { 41 | bucket = "${lookup( 42 | var.fargate, 43 | "${terraform.workspace}.name", 44 | var.fargate["default.name"] 45 | )}-alb-logs" 46 | force_destroy = true 47 | } 48 | 49 | data "aws_iam_policy_document" "put_fargate_api_alb_logs_policy" { 50 | statement { 51 | actions = ["s3:PutObject"] 52 | resources = ["${aws_s3_bucket.fargate_api_alb_logs.arn}/*"] 53 | 54 | principals { 55 | type = "AWS" 56 | identifiers = [data.aws_elb_service_account.aws_elb_service_account.id] 57 | } 58 | } 59 | } 60 | 61 | resource "aws_s3_bucket_policy" "fargate_api" { 62 | bucket = aws_s3_bucket.fargate_api_alb_logs.id 63 | policy = data.aws_iam_policy_document.put_fargate_api_alb_logs_policy.json 64 | } 65 | 66 | resource "aws_alb" "fargate_alb" { 67 | name = lookup( 68 | var.fargate, 69 | "${terraform.workspace}.name", 70 | var.fargate["default.name"] 71 | ) 72 | internal = false 73 | load_balancer_type = "application" 74 | security_groups = [aws_security_group.fargate_api_alb.id] 75 | subnets = [var.vpc["subnet_public_1a_id"], var.vpc["subnet_public_1c_id"], var.vpc["subnet_public_1d_id"]] 76 | enable_deletion_protection = false 77 | 78 | access_logs { 79 | enabled = true 80 | bucket = aws_s3_bucket.fargate_api_alb_logs.bucket 81 | } 82 | 83 | tags = { 84 | Name = "${lookup( 85 | var.fargate, 86 | "${terraform.workspace}.name", 87 | var.fargate["default.name"] 88 | )}-alb" 89 | } 90 | } 91 | 92 | resource "aws_alb_target_group" "fargate_api_blue" { 93 | name = "${lookup( 94 | var.fargate, 95 | "${terraform.workspace}.name", 96 | var.fargate["default.name"] 97 | )}-blue" 98 | port = 80 99 | protocol = "HTTP" 100 | vpc_id = var.vpc["vpc_id"] 101 | 102 | health_check { 103 | path = "/api/statuses" 104 | timeout = 5 105 | healthy_threshold = 5 106 | unhealthy_threshold = 2 107 | interval = 20 108 | matcher = 200 109 | } 110 | 111 | target_type = "ip" 112 | } 113 | 114 | resource "aws_alb_target_group" "fargate_api_green" { 115 | name = "${lookup( 116 | var.fargate, 117 | "${terraform.workspace}.name", 118 | var.fargate["default.name"] 119 | )}-green" 120 | port = 80 121 | protocol = "HTTP" 122 | vpc_id = var.vpc["vpc_id"] 123 | 124 | health_check { 125 | path = "/api/statuses" 126 | timeout = 5 127 | healthy_threshold = 5 128 | unhealthy_threshold = 2 129 | interval = 20 130 | matcher = 200 131 | } 132 | 133 | target_type = "ip" 134 | } 135 | 136 | resource "aws_alb_listener" "fargate_alb" { 137 | load_balancer_arn = aws_alb.fargate_alb.id 138 | port = 443 139 | protocol = "HTTPS" 140 | 141 | ssl_policy = "ELBSecurityPolicy-2016-08" 142 | certificate_arn = data.aws_acm_certificate.main.arn 143 | 144 | lifecycle { 145 | ignore_changes = [default_action] 146 | } 147 | 148 | default_action { 149 | target_group_arn = aws_alb_target_group.fargate_api_blue.id 150 | type = "forward" 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /modules/aws/api/codebuild.tf: -------------------------------------------------------------------------------- 1 | resource "aws_security_group" "api_codebuild" { 2 | name = "${terraform.workspace}-${lookup(var.api, "${terraform.workspace}.name", var.api["default.name"])}-codebuild" 3 | description = "Security Group to ${lookup(var.api, "${terraform.workspace}.name", var.api["default.name"])} codebuild" 4 | vpc_id = var.vpc["vpc_id"] 5 | 6 | tags = { 7 | Name = "${terraform.workspace}-${lookup(var.api, "${terraform.workspace}.name", var.api["default.name"])}" 8 | } 9 | 10 | egress { 11 | from_port = 0 12 | to_port = 0 13 | protocol = "-1" 14 | cidr_blocks = ["0.0.0.0/0"] 15 | } 16 | } 17 | 18 | resource "aws_codebuild_project" "api_rds_migration" { 19 | artifacts { 20 | type = "NO_ARTIFACTS" 21 | } 22 | 23 | environment { 24 | compute_type = "BUILD_GENERAL1_SMALL" 25 | image = "nekochans/laravel-build:0.2.0" 26 | type = "LINUX_CONTAINER" 27 | 28 | environment_variable { 29 | name = "CORS_ORIGIN" 30 | value = aws_ssm_parameter.api_cors_origin.name 31 | type = "PARAMETER_STORE" 32 | } 33 | 34 | environment_variable { 35 | name = "APP_URL" 36 | value = aws_ssm_parameter.api_app_url.name 37 | type = "PARAMETER_STORE" 38 | } 39 | 40 | environment_variable { 41 | name = "APP_KEY" 42 | value = aws_ssm_parameter.api_app_key.name 43 | type = "PARAMETER_STORE" 44 | } 45 | 46 | environment_variable { 47 | name = "DB_PASSWORD" 48 | value = aws_ssm_parameter.api_db_password.name 49 | type = "PARAMETER_STORE" 50 | } 51 | 52 | environment_variable { 53 | name = "NOTIFICATION_SLACK_TOKEN" 54 | value = aws_ssm_parameter.api_slack_token.name 55 | type = "PARAMETER_STORE" 56 | } 57 | 58 | environment_variable { 59 | name = "NOTIFICATION_SLACK_CHANNEL" 60 | value = aws_ssm_parameter.api_slack_channel.name 61 | type = "PARAMETER_STORE" 62 | } 63 | 64 | environment_variable { 65 | name = "APP_NAME" 66 | value = aws_ssm_parameter.api_app_name.name 67 | type = "PARAMETER_STORE" 68 | } 69 | 70 | environment_variable { 71 | name = "APP_ENV" 72 | value = aws_ssm_parameter.api_app_env.name 73 | type = "PARAMETER_STORE" 74 | } 75 | 76 | environment_variable { 77 | name = "APP_DEBUG" 78 | value = aws_ssm_parameter.api_app_debug.name 79 | type = "PARAMETER_STORE" 80 | } 81 | 82 | environment_variable { 83 | name = "LOG_CHANNEL" 84 | value = aws_ssm_parameter.api_log_channel.name 85 | type = "PARAMETER_STORE" 86 | } 87 | 88 | environment_variable { 89 | name = "DB_CONNECTION" 90 | value = aws_ssm_parameter.api_db_connection.name 91 | type = "PARAMETER_STORE" 92 | } 93 | 94 | environment_variable { 95 | name = "DB_HOST" 96 | value = aws_ssm_parameter.api_db_host.name 97 | type = "PARAMETER_STORE" 98 | } 99 | 100 | environment_variable { 101 | name = "DB_PORT" 102 | value = aws_ssm_parameter.api_db_port.name 103 | type = "PARAMETER_STORE" 104 | } 105 | 106 | environment_variable { 107 | name = "DB_DATABASE" 108 | value = aws_ssm_parameter.api_db_database.name 109 | type = "PARAMETER_STORE" 110 | } 111 | 112 | environment_variable { 113 | name = "DB_USERNAME" 114 | value = aws_ssm_parameter.api_db_username.name 115 | type = "PARAMETER_STORE" 116 | } 117 | 118 | environment_variable { 119 | name = "BROADCAST_DRIVER" 120 | value = aws_ssm_parameter.api_broadcast_driver.name 121 | type = "PARAMETER_STORE" 122 | } 123 | 124 | environment_variable { 125 | name = "MAINTENANCE_MODE" 126 | value = aws_ssm_parameter.api_maintenance_mode.name 127 | type = "PARAMETER_STORE" 128 | } 129 | } 130 | 131 | name = "${terraform.workspace}-${lookup(var.api, "${terraform.workspace}.name", var.api["default.name"])}-rds-migration" 132 | service_role = var.iam["codebuild_role_arn"] 133 | 134 | source { 135 | type = "GITHUB" 136 | location = "https://github.com/nekochans/qiita-stocker-backend.git" 137 | git_clone_depth = 1 138 | buildspec = "buildspec-migration.yml" 139 | } 140 | 141 | vpc_config { 142 | security_group_ids = [aws_security_group.api_codebuild.id] 143 | 144 | subnets = [ 145 | var.vpc["subnet_private_1a_id"], 146 | var.vpc["subnet_private_1c_id"], 147 | ] 148 | 149 | vpc_id = var.vpc["vpc_id"] 150 | } 151 | } 152 | 153 | data "aws_caller_identity" "current" { 154 | } 155 | 156 | resource "aws_codebuild_project" "push_to_ecr" { 157 | artifacts { 158 | type = "NO_ARTIFACTS" 159 | } 160 | 161 | environment { 162 | compute_type = "BUILD_GENERAL1_SMALL" 163 | image = "aws/codebuild/standard:2.0" 164 | type = "LINUX_CONTAINER" 165 | image_pull_credentials_type = "CODEBUILD" 166 | privileged_mode = true 167 | 168 | environment_variable { 169 | name = "DEPLOY_STAGE" 170 | value = terraform.workspace 171 | } 172 | 173 | environment_variable { 174 | name = "AWS_ACCOUNT_ID" 175 | value = data.aws_caller_identity.current.account_id 176 | } 177 | 178 | environment_variable { 179 | name = "IMAGE_TAG" 180 | value = "latest" 181 | } 182 | 183 | environment_variable { 184 | name = "REPOSITORY_NGINX" 185 | value = "${terraform.workspace}-api-nginx" 186 | } 187 | 188 | environment_variable { 189 | name = "REPOSITORY_PHP" 190 | value = "${terraform.workspace}-api-php" 191 | } 192 | } 193 | 194 | name = "${lookup( 195 | var.fargate, 196 | "${terraform.workspace}.name", 197 | var.fargate["default.name"] 198 | )}-push-ecr" 199 | service_role = var.iam["codebuild_role_arn"] 200 | 201 | source { 202 | type = "GITHUB" 203 | location = "https://github.com/nekochans/qiita-stocker-backend.git" 204 | git_clone_depth = 1 205 | buildspec = "buildspec-push-ecr.yml" 206 | report_build_status = true 207 | } 208 | 209 | badge_enabled = true 210 | } 211 | -------------------------------------------------------------------------------- /modules/aws/api/codedeploy.tf: -------------------------------------------------------------------------------- 1 | data "aws_iam_policy_document" "codedeploy_for_fargate_trust_relationship" { 2 | statement { 3 | effect = "Allow" 4 | 5 | actions = ["sts:AssumeRole"] 6 | 7 | principals { 8 | type = "Service" 9 | 10 | identifiers = [ 11 | "codedeploy.amazonaws.com", 12 | ] 13 | } 14 | } 15 | } 16 | 17 | data "aws_iam_policy_document" "codedeploy_for_fagate" { 18 | statement { 19 | effect = "Allow" 20 | 21 | actions = ["iam:PassRole"] 22 | 23 | resources = ["*"] 24 | } 25 | } 26 | 27 | resource "aws_iam_role" "codedeploy_for_fargate_role" { 28 | name = "${terraform.workspace}-fargate-codedeploy-role" 29 | assume_role_policy = data.aws_iam_policy_document.codedeploy_for_fargate_trust_relationship.json 30 | } 31 | 32 | resource "aws_iam_role_policy" "codedeploy_for_fargate" { 33 | name = "${terraform.workspace}-fargate-codedeploy" 34 | role = aws_iam_role.codedeploy_for_fargate_role.id 35 | policy = data.aws_iam_policy_document.codedeploy_for_fagate.json 36 | } 37 | 38 | resource "aws_iam_role_policy_attachment" "codedeploy_role_attach" { 39 | role = aws_iam_role.codedeploy_for_fargate_role.name 40 | policy_arn = "arn:aws:iam::aws:policy/service-role/AWSCodeDeployRole" 41 | } 42 | 43 | resource "aws_iam_role_policy_attachment" "codedeploy_role_ecs_attach" { 44 | role = aws_iam_role.codedeploy_for_fargate_role.name 45 | policy_arn = "arn:aws:iam::aws:policy/AWSCodeDeployRoleForECSLimited" 46 | } 47 | 48 | resource "aws_codedeploy_app" "fargate_api" { 49 | compute_platform = "ECS" 50 | name = lookup( 51 | var.fargate, 52 | "${terraform.workspace}.name", 53 | var.fargate["default.name"] 54 | ) 55 | } 56 | 57 | resource "aws_codedeploy_deployment_group" "fargate_api_blue_green_deploy" { 58 | app_name = aws_codedeploy_app.fargate_api.name 59 | deployment_group_name = "blue-green" 60 | service_role_arn = aws_iam_role.codedeploy_for_fargate_role.arn 61 | deployment_config_name = "CodeDeployDefault.ECSAllAtOnce" 62 | 63 | auto_rollback_configuration { 64 | enabled = true 65 | events = ["DEPLOYMENT_FAILURE"] 66 | } 67 | 68 | blue_green_deployment_config { 69 | deployment_ready_option { 70 | action_on_timeout = "CONTINUE_DEPLOYMENT" 71 | } 72 | 73 | terminate_blue_instances_on_deployment_success { 74 | action = "TERMINATE" 75 | termination_wait_time_in_minutes = "1" 76 | } 77 | } 78 | 79 | deployment_style { 80 | deployment_option = "WITH_TRAFFIC_CONTROL" 81 | deployment_type = "BLUE_GREEN" 82 | } 83 | 84 | ecs_service { 85 | cluster_name = aws_ecs_cluster.api_fargate_cluster.name 86 | service_name = aws_ecs_service.api_fargate_service.name 87 | } 88 | 89 | load_balancer_info { 90 | target_group_pair_info { 91 | prod_traffic_route { 92 | listener_arns = [aws_alb_listener.fargate_alb.arn] 93 | } 94 | 95 | target_group { 96 | name = aws_alb_target_group.fargate_api_blue.name 97 | } 98 | 99 | target_group { 100 | name = aws_alb_target_group.fargate_api_green.name 101 | } 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /modules/aws/api/fargate.tf: -------------------------------------------------------------------------------- 1 | resource "aws_security_group" "fargate_api" { 2 | name = lookup( 3 | var.fargate, 4 | "${terraform.workspace}.name", 5 | var.fargate["default.name"] 6 | ) 7 | description = "Security Group to ${lookup( 8 | var.fargate, 9 | "${terraform.workspace}.name", 10 | var.fargate["default.name"] 11 | )}" 12 | vpc_id = var.vpc["vpc_id"] 13 | 14 | tags = { 15 | Name = lookup( 16 | var.fargate, 17 | "${terraform.workspace}.name", 18 | var.fargate["default.name"] 19 | ) 20 | } 21 | 22 | egress { 23 | from_port = 0 24 | to_port = 0 25 | protocol = "-1" 26 | cidr_blocks = ["0.0.0.0/0"] 27 | } 28 | } 29 | 30 | resource "aws_security_group_rule" "fargate_api_from_alb" { 31 | security_group_id = aws_security_group.fargate_api.id 32 | type = "ingress" 33 | from_port = "80" 34 | to_port = "80" 35 | protocol = "tcp" 36 | source_security_group_id = aws_security_group.fargate_api_alb.id 37 | } 38 | 39 | resource "aws_cloudwatch_log_group" "fargate_api" { 40 | name = lookup( 41 | var.fargate, 42 | "${terraform.workspace}.name", 43 | var.fargate["default.name"] 44 | ) 45 | retention_in_days = 30 46 | } 47 | 48 | resource "aws_ecs_cluster" "api_fargate_cluster" { 49 | name = lookup( 50 | var.fargate, 51 | "${terraform.workspace}.name", 52 | var.fargate["default.name"] 53 | ) 54 | } 55 | 56 | data "template_file" "api_fargate_template_file" { 57 | template = file("../../../../modules/aws/api/task/fargate-api.json") 58 | 59 | vars = { 60 | aws_region = var.fargate["region"] 61 | php_image_url = var.ecr["php_image_url"] 62 | nginx_image_url = var.ecr["nginx_image_url"] 63 | aws_logs_group = aws_cloudwatch_log_group.fargate_api.name 64 | api_cors_origin_arn = aws_ssm_parameter.api_cors_origin.arn 65 | api_app_url_arn = aws_ssm_parameter.api_app_url.arn 66 | api_app_key_arn = aws_ssm_parameter.api_app_key.arn 67 | api_db_password_arn = aws_ssm_parameter.api_db_password.arn 68 | api_slack_token_arn = aws_ssm_parameter.api_slack_token.arn 69 | api_slack_channel_arn = aws_ssm_parameter.api_slack_channel.arn 70 | api_app_name_arn = aws_ssm_parameter.api_app_name.arn 71 | api_app_env_arn = aws_ssm_parameter.api_app_env.arn 72 | api_app_debug_arn = aws_ssm_parameter.api_app_debug.arn 73 | api_log_channel_arn = aws_ssm_parameter.api_log_channel.arn 74 | api_db_connection_arn = aws_ssm_parameter.api_db_connection.arn 75 | api_db_host_arn = aws_ssm_parameter.api_db_host.arn 76 | api_db_port_arn = aws_ssm_parameter.api_db_port.arn 77 | api_db_database_arn = aws_ssm_parameter.api_db_database.arn 78 | api_db_username_arn = aws_ssm_parameter.api_db_username.arn 79 | api_broadcast_driver_arn = aws_ssm_parameter.api_broadcast_driver.arn 80 | api_maintenance_mode_arn = aws_ssm_parameter.api_maintenance_mode.arn 81 | api_datadog_api_key_arn = aws_ssm_parameter.api_datadog_api_key.arn 82 | } 83 | } 84 | 85 | resource "aws_ecs_task_definition" "api_fargate" { 86 | family = lookup( 87 | var.fargate, 88 | "${terraform.workspace}.name", 89 | var.fargate["default.name"] 90 | ) 91 | network_mode = "awsvpc" 92 | container_definitions = data.template_file.api_fargate_template_file.rendered 93 | cpu = 256 94 | memory = 512 95 | requires_compatibilities = ["FARGATE"] 96 | execution_role_arn = aws_iam_role.task_execution_role.arn 97 | 98 | depends_on = [aws_cloudwatch_log_group.fargate_api] 99 | } 100 | 101 | resource "aws_ecs_service" "api_fargate_service" { 102 | name = lookup( 103 | var.fargate, 104 | "${terraform.workspace}.name", 105 | var.fargate["default.name"] 106 | ) 107 | cluster = aws_ecs_cluster.api_fargate_cluster.id 108 | task_definition = aws_ecs_task_definition.api_fargate.arn 109 | desired_count = 1 110 | launch_type = "FARGATE" 111 | 112 | load_balancer { 113 | target_group_arn = aws_alb_target_group.fargate_api_blue.id 114 | container_name = "nginx" 115 | container_port = 80 116 | } 117 | 118 | network_configuration { 119 | subnets = [var.vpc["subnet_private_1a_id"], var.vpc["subnet_private_1c_id"], var.vpc["subnet_private_1d_id"]] 120 | 121 | security_groups = [ 122 | aws_security_group.fargate_api.id, 123 | ] 124 | } 125 | 126 | deployment_controller { 127 | type = "CODE_DEPLOY" 128 | } 129 | 130 | lifecycle { 131 | ignore_changes = [ 132 | task_definition, 133 | load_balancer, 134 | desired_count, 135 | ] 136 | } 137 | 138 | depends_on = [aws_alb_listener.fargate_alb] 139 | } 140 | -------------------------------------------------------------------------------- /modules/aws/api/iam.tf: -------------------------------------------------------------------------------- 1 | data "aws_iam_policy_document" "ecs_service_trust_relationship" { 2 | statement { 3 | actions = ["sts:AssumeRole"] 4 | 5 | principals { 6 | type = "Service" 7 | identifiers = ["ecs.amazonaws.com"] 8 | } 9 | } 10 | } 11 | 12 | resource "aws_iam_role" "ecs_service_role" { 13 | count = terraform.workspace != "prod" ? 1 : 0 14 | name = "${terraform.workspace}-ecs-service-role" 15 | path = "/system/" 16 | assume_role_policy = data.aws_iam_policy_document.ecs_service_trust_relationship.json 17 | } 18 | 19 | resource "aws_iam_role_policy_attachment" "ecs_service_role_attach" { 20 | count = terraform.workspace != "prod" ? 1 : 0 21 | role = aws_iam_role.ecs_service_role[0].name 22 | policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceRole" 23 | } 24 | 25 | data "aws_iam_policy_document" "task_execution_trust_relationship" { 26 | statement { 27 | effect = "Allow" 28 | 29 | actions = ["sts:AssumeRole"] 30 | 31 | principals { 32 | type = "Service" 33 | identifiers = ["ecs-tasks.amazonaws.com"] 34 | } 35 | } 36 | } 37 | 38 | resource "aws_iam_role" "task_execution_role" { 39 | name = "${terraform.workspace}-task-execution-role" 40 | assume_role_policy = data.aws_iam_policy_document.task_execution_trust_relationship.json 41 | } 42 | 43 | resource "aws_iam_role_policy_attachment" "task_execution_role_attach" { 44 | role = aws_iam_role.task_execution_role.name 45 | policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy" 46 | } 47 | 48 | resource "aws_iam_role_policy_attachment" "ssm_read_only_access_role_attach" { 49 | role = aws_iam_role.task_execution_role.name 50 | policy_arn = "arn:aws:iam::aws:policy/AmazonSSMReadOnlyAccess" 51 | } 52 | 53 | data "aws_iam_policy_document" "datadog_agent_container_policy" { 54 | statement { 55 | effect = "Allow" 56 | 57 | actions = [ 58 | "ecs:ListClusters", 59 | "ecs:ListContainerInstances", 60 | "ecs:DescribeContainerInstances", 61 | ] 62 | 63 | resources = ["*"] 64 | } 65 | } 66 | 67 | resource "aws_iam_role_policy" "ecs_instance" { 68 | name = "${terraform.workspace}-datadog-agent-container-policy" 69 | role = aws_iam_role.task_execution_role.id 70 | policy = data.aws_iam_policy_document.datadog_agent_container_policy.json 71 | } 72 | -------------------------------------------------------------------------------- /modules/aws/api/local_ssm_parameter.tf: -------------------------------------------------------------------------------- 1 | resource "aws_ssm_parameter" "local_api_cors_origin" { 2 | count = terraform.workspace == "stg" ? 1 : 0 3 | name = "/local/qiita-stocker/api/CORS_ORIGIN" 4 | type = "SecureString" 5 | value = data.external.local_api.0.result["FRONTEND_URL"] 6 | overwrite = true 7 | } 8 | 9 | resource "aws_ssm_parameter" "local_api_app_url" { 10 | count = terraform.workspace == "stg" ? 1 : 0 11 | name = "/local/qiita-stocker/api/APP_URL" 12 | type = "SecureString" 13 | value = data.external.local_api.0.result["BACKEND_URL"] 14 | overwrite = true 15 | } 16 | 17 | resource "aws_ssm_parameter" "local_api_app_key" { 18 | count = terraform.workspace == "stg" ? 1 : 0 19 | name = "/local/qiita-stocker/api/APP_KEY" 20 | type = "SecureString" 21 | value = data.external.local_api.0.result["BACKEND_APP_KEY"] 22 | overwrite = true 23 | } 24 | 25 | resource "aws_ssm_parameter" "local_api_db_password" { 26 | count = terraform.workspace == "stg" ? 1 : 0 27 | name = "/local/qiita-stocker/api/DB_PASSWORD" 28 | type = "SecureString" 29 | value = data.external.local_api.0.result["DB_PASSWORD"] 30 | overwrite = true 31 | } 32 | 33 | resource "aws_ssm_parameter" "local_api_slack_token" { 34 | count = terraform.workspace == "stg" ? 1 : 0 35 | name = "/local/qiita-stocker/api/NOTIFICATION_SLACK_TOKEN" 36 | type = "SecureString" 37 | value = data.external.local_api.0.result["NOTIFICATION_SLACK_TOKEN"] 38 | overwrite = true 39 | } 40 | 41 | resource "aws_ssm_parameter" "local_api_slack_channel" { 42 | count = terraform.workspace == "stg" ? 1 : 0 43 | name = "/local/qiita-stocker/api/NOTIFICATION_SLACK_CHANNEL" 44 | type = "SecureString" 45 | value = data.external.local_api.0.result["NOTIFICATION_SLACK_CHANNEL"] 46 | overwrite = true 47 | } 48 | 49 | resource "aws_ssm_parameter" "local_api_app_name" { 50 | count = terraform.workspace == "stg" ? 1 : 0 51 | name = "/local/qiita-stocker/api/APP_NAME" 52 | type = "String" 53 | value = "qiita-stocker-backend" 54 | overwrite = true 55 | } 56 | 57 | resource "aws_ssm_parameter" "local_api_app_env" { 58 | count = terraform.workspace == "stg" ? 1 : 0 59 | name = "/local/qiita-stocker/api/APP_ENV" 60 | type = "String" 61 | value = "local" 62 | overwrite = true 63 | } 64 | 65 | resource "aws_ssm_parameter" "local_api_app_debug" { 66 | count = terraform.workspace == "stg" ? 1 : 0 67 | name = "/local/qiita-stocker/api/APP_DEBUG" 68 | type = "String" 69 | value = "true" 70 | overwrite = true 71 | } 72 | 73 | resource "aws_ssm_parameter" "local_api_log_channel" { 74 | count = terraform.workspace == "stg" ? 1 : 0 75 | name = "/local/qiita-stocker/api/LOG_CHANNEL" 76 | type = "String" 77 | value = "app" 78 | overwrite = true 79 | } 80 | 81 | resource "aws_ssm_parameter" "local_api_db_connection" { 82 | count = terraform.workspace == "stg" ? 1 : 0 83 | name = "/local/qiita-stocker/api/DB_CONNECTION" 84 | type = "String" 85 | value = "mysql" 86 | overwrite = true 87 | } 88 | 89 | resource "aws_ssm_parameter" "local_api_db_host" { 90 | count = terraform.workspace == "stg" ? 1 : 0 91 | name = "/local/qiita-stocker/api/DB_HOST" 92 | type = "String" 93 | value = "mysql" 94 | overwrite = true 95 | } 96 | 97 | resource "aws_ssm_parameter" "local_api_db_port" { 98 | count = terraform.workspace == "stg" ? 1 : 0 99 | name = "/local/qiita-stocker/api/DB_PORT" 100 | type = "String" 101 | value = "3306" 102 | overwrite = true 103 | } 104 | 105 | resource "aws_ssm_parameter" "local_api_db_database" { 106 | count = terraform.workspace == "stg" ? 1 : 0 107 | name = "/local/qiita-stocker/api/DB_DATABASE" 108 | type = "String" 109 | value = "qiita_stocker" 110 | overwrite = true 111 | } 112 | 113 | resource "aws_ssm_parameter" "local_api_db_username" { 114 | count = terraform.workspace == "stg" ? 1 : 0 115 | name = "/local/qiita-stocker/api/DB_USERNAME" 116 | type = "String" 117 | value = "qiita_stocker" 118 | overwrite = true 119 | } 120 | 121 | resource "aws_ssm_parameter" "local_api_broadcast_driver" { 122 | count = terraform.workspace == "stg" ? 1 : 0 123 | name = "/local/qiita-stocker/api/BROADCAST_DRIVER" 124 | type = "String" 125 | value = "log" 126 | overwrite = true 127 | } 128 | 129 | resource "aws_ssm_parameter" "local_api_maintenance_mode" { 130 | count = terraform.workspace == "stg" ? 1 : 0 131 | name = "/local/qiita-stocker/api/MAINTENANCE_MODE" 132 | type = "String" 133 | value = "false" 134 | overwrite = true 135 | } 136 | -------------------------------------------------------------------------------- /modules/aws/api/output.tf: -------------------------------------------------------------------------------- 1 | output "api" { 2 | value = { 3 | "api_security_id" = aws_security_group.fargate_api.id 4 | "api_codebuild_security_id" = aws_security_group.api_codebuild.id 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /modules/aws/api/route53.tf: -------------------------------------------------------------------------------- 1 | data "aws_route53_zone" "api" { 2 | name = var.main_domain_name 3 | } 4 | 5 | resource "aws_route53_record" "api" { 6 | zone_id = data.aws_route53_zone.api.zone_id 7 | name = lookup( 8 | var.sub_domain_name, 9 | "${terraform.workspace}.name", 10 | var.sub_domain_name["default.name"] 11 | ) 12 | type = "A" 13 | 14 | alias { 15 | name = aws_alb.fargate_alb.dns_name 16 | zone_id = aws_alb.fargate_alb.zone_id 17 | evaluate_target_health = false 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /modules/aws/api/secretsmanager.tf: -------------------------------------------------------------------------------- 1 | data "aws_secretsmanager_secret" "api" { 2 | name = "${terraform.workspace}/qiita-stocker" 3 | } 4 | 5 | data "aws_secretsmanager_secret_version" "api" { 6 | secret_id = data.aws_secretsmanager_secret.api.id 7 | } 8 | 9 | data "external" "api" { 10 | program = ["echo", data.aws_secretsmanager_secret_version.api.secret_string] 11 | } 12 | 13 | data "aws_secretsmanager_secret" "local_api" { 14 | count = terraform.workspace == "stg" ? 1 : 0 15 | name = "local/qiita-stocker" 16 | } 17 | 18 | data "aws_secretsmanager_secret_version" "local_api" { 19 | count = terraform.workspace == "stg" ? 1 : 0 20 | secret_id = data.aws_secretsmanager_secret.local_api[0].id 21 | } 22 | 23 | data "external" "local_api" { 24 | count = terraform.workspace == "stg" ? 1 : 0 25 | program = ["echo", data.aws_secretsmanager_secret_version.local_api[0].secret_string] 26 | } 27 | -------------------------------------------------------------------------------- /modules/aws/api/ssm_parameter.tf: -------------------------------------------------------------------------------- 1 | resource "aws_ssm_parameter" "api_cors_origin" { 2 | name = "/${terraform.workspace}/qiita-stocker/api/CORS_ORIGIN" 3 | type = "SecureString" 4 | value = data.external.api.result["FRONTEND_URL"] 5 | overwrite = true 6 | } 7 | 8 | resource "aws_ssm_parameter" "api_app_url" { 9 | name = "/${terraform.workspace}/qiita-stocker/api/APP_URL" 10 | type = "SecureString" 11 | value = data.external.api.result["BACKEND_URL"] 12 | overwrite = true 13 | } 14 | 15 | resource "aws_ssm_parameter" "api_app_key" { 16 | name = "/${terraform.workspace}/qiita-stocker/api/APP_KEY" 17 | type = "SecureString" 18 | value = data.external.api.result["BACKEND_APP_KEY"] 19 | overwrite = true 20 | } 21 | 22 | resource "aws_ssm_parameter" "api_db_password" { 23 | name = "/${terraform.workspace}/qiita-stocker/api/DB_PASSWORD" 24 | type = "SecureString" 25 | value = data.external.api.result["DB_PASSWORD"] 26 | overwrite = true 27 | } 28 | 29 | resource "aws_ssm_parameter" "api_slack_token" { 30 | name = "/${terraform.workspace}/qiita-stocker/api/NOTIFICATION_SLACK_TOKEN" 31 | type = "SecureString" 32 | value = data.external.api.result["NOTIFICATION_SLACK_TOKEN"] 33 | overwrite = true 34 | } 35 | 36 | resource "aws_ssm_parameter" "api_slack_channel" { 37 | name = "/${terraform.workspace}/qiita-stocker/api/NOTIFICATION_SLACK_CHANNEL" 38 | type = "SecureString" 39 | value = data.external.api.result["NOTIFICATION_SLACK_CHANNEL"] 40 | overwrite = true 41 | } 42 | 43 | resource "aws_ssm_parameter" "api_datadog_api_key" { 44 | name = "/${terraform.workspace}/qiita-stocker/api/DD_API_KEY" 45 | type = "SecureString" 46 | value = data.external.api.result["DATADOG_API_KEY"] 47 | overwrite = true 48 | } 49 | 50 | resource "aws_ssm_parameter" "api_app_name" { 51 | name = "/${terraform.workspace}/qiita-stocker/api/APP_NAME" 52 | type = "String" 53 | value = "qiita-stocker-backend" 54 | overwrite = true 55 | } 56 | 57 | resource "aws_ssm_parameter" "api_app_env" { 58 | name = "/${terraform.workspace}/qiita-stocker/api/APP_ENV" 59 | type = "String" 60 | value = terraform.workspace 61 | overwrite = true 62 | } 63 | 64 | resource "aws_ssm_parameter" "api_app_debug" { 65 | name = "/${terraform.workspace}/qiita-stocker/api/APP_DEBUG" 66 | type = "String" 67 | value = "true" 68 | overwrite = true 69 | } 70 | 71 | resource "aws_ssm_parameter" "api_log_channel" { 72 | name = "/${terraform.workspace}/qiita-stocker/api/LOG_CHANNEL" 73 | type = "String" 74 | value = "app" 75 | overwrite = true 76 | } 77 | 78 | resource "aws_ssm_parameter" "api_db_connection" { 79 | name = "/${terraform.workspace}/qiita-stocker/api/DB_CONNECTION" 80 | type = "String" 81 | value = "mysql" 82 | overwrite = true 83 | } 84 | 85 | resource "aws_ssm_parameter" "api_db_host" { 86 | name = "/${terraform.workspace}/qiita-stocker/api/DB_HOST" 87 | type = "String" 88 | value = "${var.rds_local_master_domain_name}.${terraform.workspace}" 89 | overwrite = true 90 | } 91 | 92 | resource "aws_ssm_parameter" "api_db_port" { 93 | name = "/${terraform.workspace}/qiita-stocker/api/DB_PORT" 94 | type = "String" 95 | value = "3306" 96 | overwrite = true 97 | } 98 | 99 | resource "aws_ssm_parameter" "api_db_database" { 100 | name = "/${terraform.workspace}/qiita-stocker/api/DB_DATABASE" 101 | type = "String" 102 | value = "qiita_stocker" 103 | overwrite = true 104 | } 105 | 106 | resource "aws_ssm_parameter" "api_db_username" { 107 | name = "/${terraform.workspace}/qiita-stocker/api/DB_USERNAME" 108 | type = "String" 109 | value = "qiita_stocker" 110 | overwrite = true 111 | } 112 | 113 | resource "aws_ssm_parameter" "api_broadcast_driver" { 114 | name = "/${terraform.workspace}/qiita-stocker/api/BROADCAST_DRIVER" 115 | type = "String" 116 | value = "log" 117 | overwrite = true 118 | } 119 | 120 | resource "aws_ssm_parameter" "api_maintenance_mode" { 121 | name = "/${terraform.workspace}/qiita-stocker/api/MAINTENANCE_MODE" 122 | type = "String" 123 | value = "false" 124 | overwrite = true 125 | } 126 | -------------------------------------------------------------------------------- /modules/aws/api/task/fargate-api.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "php", 4 | "image": "${php_image_url}", 5 | "memory": 300, 6 | "essential": true, 7 | "logConfiguration": { 8 | "logDriver": "awslogs", 9 | "options": { 10 | "awslogs-group": "${aws_logs_group}", 11 | "awslogs-region": "${aws_region}", 12 | "awslogs-stream-prefix": "ecs" 13 | } 14 | }, 15 | "secrets": [ 16 | { 17 | "name": "CORS_ORIGIN", 18 | "valueFrom": "${api_cors_origin_arn}" 19 | }, 20 | { 21 | "name": "APP_URL", 22 | "valueFrom": "${api_app_url_arn}" 23 | }, 24 | { 25 | "name": "APP_KEY", 26 | "valueFrom": "${api_app_key_arn}" 27 | }, 28 | { 29 | "name": "DB_PASSWORD", 30 | "valueFrom": "${api_db_password_arn}" 31 | }, 32 | { 33 | "name": "NOTIFICATION_SLACK_TOKEN", 34 | "valueFrom": "${api_slack_token_arn}" 35 | }, 36 | { 37 | "name": "NOTIFICATION_SLACK_CHANNEL", 38 | "valueFrom": "${api_slack_channel_arn}" 39 | }, 40 | { 41 | "name": "APP_NAME", 42 | "valueFrom": "${api_app_name_arn}" 43 | }, 44 | { 45 | "name": "APP_ENV", 46 | "valueFrom": "${api_app_env_arn}" 47 | }, 48 | { 49 | "name": "APP_DEBUG", 50 | "valueFrom": "${api_app_debug_arn}" 51 | }, 52 | { 53 | "name": "LOG_CHANNEL", 54 | "valueFrom": "${api_log_channel_arn}" 55 | }, 56 | { 57 | "name": "DB_CONNECTION", 58 | "valueFrom": "${api_db_connection_arn}" 59 | }, 60 | { 61 | "name": "DB_HOST", 62 | "valueFrom": "${api_db_host_arn}" 63 | }, 64 | { 65 | "name": "DB_PORT", 66 | "valueFrom": "${api_db_port_arn}" 67 | }, 68 | { 69 | "name": "DB_DATABASE", 70 | "valueFrom": "${api_db_database_arn}" 71 | }, 72 | { 73 | "name": "DB_USERNAME", 74 | "valueFrom": "${api_db_username_arn}" 75 | }, 76 | { 77 | "name": "BROADCAST_DRIVER", 78 | "valueFrom": "${api_broadcast_driver_arn}" 79 | }, 80 | { 81 | "name": "MAINTENANCE_MODE", 82 | "valueFrom": "${api_maintenance_mode_arn}" 83 | } 84 | ] 85 | }, 86 | { 87 | "name": "nginx", 88 | "image": "${nginx_image_url}", 89 | "memory": 300, 90 | "essential": true, 91 | "ulimits": [ 92 | { 93 | "name": "nofile", 94 | "softLimit": 65536, 95 | "hardLimit": 65536 96 | } 97 | ], 98 | "portMappings": [ 99 | { 100 | "containerPort": 80, 101 | "hostPort": 80, 102 | "protocol": "tcp" 103 | } 104 | ], 105 | "logConfiguration": { 106 | "logDriver": "awslogs", 107 | "options": { 108 | "awslogs-group": "${aws_logs_group}", 109 | "awslogs-region": "${aws_region}", 110 | "awslogs-stream-prefix": "ecs" 111 | } 112 | } 113 | }, 114 | { 115 | "name": "datadog-agent", 116 | "image": "datadog/agent:latest", 117 | "memoryReservation": 256, 118 | "essential": true, 119 | "cpu": 10, 120 | "secrets": [ 121 | { 122 | "name": "DD_API_KEY", 123 | "valueFrom": "${api_datadog_api_key_arn}" 124 | } 125 | ], 126 | "environment": [ 127 | { 128 | "name": "ECS_FARGATE", 129 | "value": "true" 130 | } 131 | ] 132 | } 133 | ] 134 | -------------------------------------------------------------------------------- /modules/aws/api/variable.tf: -------------------------------------------------------------------------------- 1 | variable "api" { 2 | type = map(string) 3 | 4 | default = { 5 | "default.project" = "qiita-stocker" 6 | "default.name" = "api" 7 | } 8 | } 9 | 10 | variable "fargate" { 11 | type = map(string) 12 | 13 | default = { 14 | "default.name" = "prod-fargate-api" 15 | "stg.name" = "stg-fargate-api" 16 | region = "ap-northeast-1" 17 | } 18 | } 19 | 20 | variable "vpc" { 21 | type = map(string) 22 | 23 | default = {} 24 | } 25 | 26 | variable "bastion" { 27 | type = map(string) 28 | 29 | default = {} 30 | } 31 | 32 | variable "main_domain_name" { 33 | type = string 34 | 35 | default = "" 36 | } 37 | 38 | variable "sub_domain_name" { 39 | type = map(string) 40 | 41 | default = { 42 | "stg.name" = "stg-api" 43 | "default.name" = "api" 44 | "stg.fargate_name" = "stg-fargate-api" 45 | "default.fargate_name" = "fargate-api" 46 | } 47 | } 48 | 49 | data "aws_elb_service_account" "aws_elb_service_account" { 50 | } 51 | 52 | data "aws_acm_certificate" "main" { 53 | domain = "*.${var.main_domain_name}" 54 | } 55 | 56 | variable "ecr" { 57 | type = map(string) 58 | 59 | default = {} 60 | } 61 | 62 | variable "rds_local_master_domain_name" { 63 | type = string 64 | 65 | default = "" 66 | } 67 | 68 | variable "iam" { 69 | type = map(string) 70 | 71 | default = {} 72 | } 73 | -------------------------------------------------------------------------------- /modules/aws/api/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 0.12" 3 | } 4 | -------------------------------------------------------------------------------- /modules/aws/bastion/main.tf: -------------------------------------------------------------------------------- 1 | resource "aws_security_group" "bastion" { 2 | name = "${terraform.workspace}-${lookup( 3 | var.bastion, 4 | "${terraform.workspace}.name", 5 | var.bastion["default.name"] 6 | )}" 7 | description = "Security Group to ${lookup( 8 | var.bastion, 9 | "${terraform.workspace}.name", 10 | var.bastion["default.name"] 11 | )}" 12 | vpc_id = var.vpc["vpc_id"] 13 | 14 | tags = { 15 | Name = "${terraform.workspace}-${lookup( 16 | var.bastion, 17 | "${terraform.workspace}.name", 18 | var.bastion["default.name"] 19 | )}" 20 | } 21 | 22 | egress { 23 | from_port = 0 24 | to_port = 0 25 | protocol = "-1" 26 | cidr_blocks = ["0.0.0.0/0"] 27 | } 28 | } 29 | 30 | resource "aws_key_pair" "ssh_key_pair" { 31 | public_key = file(var.ssh_public_key_path) 32 | key_name = "${terraform.workspace}-ssh-key" 33 | } 34 | 35 | resource "aws_security_group_rule" "ssh_from_workplace" { 36 | security_group_id = aws_security_group.bastion.id 37 | type = "ingress" 38 | from_port = "22" 39 | to_port = "22" 40 | protocol = "tcp" 41 | cidr_blocks = ["0.0.0.0/0"] 42 | } 43 | 44 | resource "aws_instance" "bastion_1a" { 45 | ami = lookup( 46 | var.bastion, 47 | "${terraform.workspace}.ami", 48 | var.bastion["default.ami"] 49 | ) 50 | associate_public_ip_address = true 51 | instance_type = lookup( 52 | var.bastion, 53 | "${terraform.workspace}.instance_type", 54 | var.bastion["default.instance_type"] 55 | ) 56 | 57 | ebs_block_device { 58 | device_name = "/dev/xvda" 59 | volume_type = lookup( 60 | var.bastion, 61 | "${terraform.workspace}.volume_type", 62 | var.bastion["default.volume_type"] 63 | ) 64 | volume_size = lookup( 65 | var.bastion, 66 | "${terraform.workspace}.volume_size", 67 | var.bastion["default.volume_size"] 68 | ) 69 | } 70 | 71 | key_name = aws_key_pair.ssh_key_pair.id 72 | subnet_id = var.vpc["subnet_public_1a_id"] 73 | vpc_security_group_ids = [aws_security_group.bastion.id] 74 | 75 | tags = { 76 | Name = "${terraform.workspace}-${lookup( 77 | var.bastion, 78 | "${terraform.workspace}.name", 79 | var.bastion["default.name"] 80 | )}-1a" 81 | } 82 | 83 | lifecycle { 84 | ignore_changes = all 85 | } 86 | } 87 | 88 | resource "aws_eip" "bastion_ip_1a" { 89 | instance = aws_instance.bastion_1a.id 90 | 91 | tags = { 92 | Name = "${terraform.workspace}-bastion-1a" 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /modules/aws/bastion/output.tf: -------------------------------------------------------------------------------- 1 | output "bastion" { 2 | value = { 3 | "bastion_security_id" = aws_security_group.bastion.id 4 | "key_pair_id" = aws_key_pair.ssh_key_pair.id 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /modules/aws/bastion/variable.tf: -------------------------------------------------------------------------------- 1 | variable "bastion" { 2 | type = map(string) 3 | 4 | default = { 5 | "default.name" = "bastion" 6 | "default.ami" = "ami-0d7ed3ddb85b521a6" 7 | "default.instance_type" = "t3.micro" 8 | "default.volume_type" = "gp2" 9 | "default.volume_size" = "8" 10 | } 11 | } 12 | 13 | variable "vpc" { 14 | type = map(string) 15 | 16 | default = {} 17 | } 18 | 19 | variable "ssh_public_key_path" { 20 | type = string 21 | 22 | default = "" 23 | } 24 | -------------------------------------------------------------------------------- /modules/aws/bastion/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 0.12" 3 | } 4 | -------------------------------------------------------------------------------- /modules/aws/ecr/main.tf: -------------------------------------------------------------------------------- 1 | resource "aws_ecr_repository" "php" { 2 | name = "${terraform.workspace}-api-php" 3 | } 4 | 5 | resource "aws_ecr_repository" "nginx" { 6 | name = "${terraform.workspace}-api-nginx" 7 | } 8 | 9 | locals { 10 | lifecycle_policy = < => { 20 | const params = { 21 | outputPath: networkOutputPath(), 22 | backendParams: { 23 | requiredVersion: terraformVersion(), 24 | backend: { 25 | bucket: tfstateBucketName(deployStage), 26 | key: "network/terraform.tfstate", 27 | region: tfstateBucketRegion(), 28 | profile: awsProfileName(deployStage) 29 | } 30 | } 31 | }; 32 | 33 | await createS3Backend(params); 34 | }; 35 | 36 | export const createAcmBackend = async (deployStage: string): Promise => { 37 | const params = { 38 | outputPath: acmOutputPath(), 39 | backendParams: { 40 | requiredVersion: terraformVersion(), 41 | backend: { 42 | bucket: tfstateBucketName(deployStage), 43 | key: "acm/terraform.tfstate", 44 | region: tfstateBucketRegion(), 45 | profile: awsProfileName(deployStage) 46 | } 47 | } 48 | }; 49 | 50 | await createS3Backend(params); 51 | }; 52 | 53 | export const createIamBackend = async (deployStage: string): Promise => { 54 | const params = { 55 | outputPath: iamOutputPath(), 56 | backendParams: { 57 | requiredVersion: terraformVersion(), 58 | backend: { 59 | bucket: tfstateBucketName(deployStage), 60 | key: "iam/terraform.tfstate", 61 | region: tfstateBucketRegion(), 62 | profile: awsProfileName(deployStage) 63 | } 64 | } 65 | }; 66 | 67 | await createS3Backend(params); 68 | }; 69 | 70 | export const createBastionBackend = async ( 71 | deployStage: string 72 | ): Promise => { 73 | const params = { 74 | outputPath: bastionOutputPath(), 75 | backendParams: { 76 | requiredVersion: terraformVersion(), 77 | backend: { 78 | bucket: tfstateBucketName(deployStage), 79 | key: "bastion/terraform.tfstate", 80 | region: tfstateBucketRegion(), 81 | profile: awsProfileName(deployStage) 82 | } 83 | }, 84 | remoteStateList: [networkRemoteState(deployStage)] 85 | }; 86 | 87 | await createS3Backend(params); 88 | }; 89 | 90 | export const createApiBackend = async (deployStage: string): Promise => { 91 | const params = { 92 | outputPath: apiOutputPath(), 93 | backendParams: { 94 | requiredVersion: terraformVersion(), 95 | backend: { 96 | bucket: tfstateBucketName(deployStage), 97 | key: "api/terraform.tfstate", 98 | region: tfstateBucketRegion(), 99 | profile: awsProfileName(deployStage) 100 | } 101 | }, 102 | remoteStateList: [ 103 | networkRemoteState(deployStage), 104 | { 105 | name: "bastion", 106 | bucket: tfstateBucketName(deployStage), 107 | key: "env:/${terraform.workspace}/bastion/terraform.tfstate", 108 | region: tfstateBucketRegion(), 109 | profile: awsProfileName(deployStage) 110 | }, 111 | { 112 | name: "ecr", 113 | bucket: tfstateBucketName(deployStage), 114 | key: "env:/${terraform.workspace}/ecr/terraform.tfstate", 115 | region: tfstateBucketRegion(), 116 | profile: awsProfileName(deployStage) 117 | }, 118 | { 119 | name: "iam", 120 | bucket: tfstateBucketName(deployStage), 121 | key: "env:/${terraform.workspace}/iam/terraform.tfstate", 122 | region: tfstateBucketRegion(), 123 | profile: awsProfileName(deployStage) 124 | } 125 | ] 126 | }; 127 | 128 | await createS3Backend(params); 129 | }; 130 | 131 | export const createFrontendBackend = async ( 132 | deployStage: string 133 | ): Promise => { 134 | const params = { 135 | outputPath: frontendOutputPath(), 136 | backendParams: { 137 | requiredVersion: terraformVersion(), 138 | backend: { 139 | bucket: tfstateBucketName(deployStage), 140 | key: "frontend/terraform.tfstate", 141 | region: tfstateBucketRegion(), 142 | profile: awsProfileName(deployStage) 143 | } 144 | }, 145 | remoteStateList: [ 146 | { 147 | name: "acm", 148 | bucket: tfstateBucketName(deployStage), 149 | key: "env:/${terraform.workspace}/acm/terraform.tfstate", 150 | region: tfstateBucketRegion(), 151 | profile: awsProfileName(deployStage) 152 | }, 153 | { 154 | name: "iam", 155 | bucket: tfstateBucketName(deployStage), 156 | key: "env:/${terraform.workspace}/iam/terraform.tfstate", 157 | region: tfstateBucketRegion(), 158 | profile: awsProfileName(deployStage) 159 | } 160 | ] 161 | }; 162 | 163 | await createS3Backend(params); 164 | }; 165 | 166 | export const createRdsBackend = async (deployStage: string): Promise => { 167 | const params = { 168 | outputPath: rdsOutputPath(), 169 | backendParams: { 170 | requiredVersion: terraformVersion(), 171 | backend: { 172 | bucket: tfstateBucketName(deployStage), 173 | key: "rds/terraform.tfstate", 174 | region: tfstateBucketRegion(), 175 | profile: awsProfileName(deployStage) 176 | } 177 | }, 178 | remoteStateList: [ 179 | networkRemoteState(deployStage), 180 | { 181 | name: "api", 182 | bucket: tfstateBucketName(deployStage), 183 | key: "env:/${terraform.workspace}/api/terraform.tfstate", 184 | region: tfstateBucketRegion(), 185 | profile: awsProfileName(deployStage) 186 | } 187 | ] 188 | }; 189 | 190 | await createS3Backend(params); 191 | }; 192 | 193 | export const createEcrBackend = async (deployStage: string): Promise => { 194 | const params = { 195 | outputPath: ecrOutputPath(), 196 | backendParams: { 197 | requiredVersion: terraformVersion(), 198 | backend: { 199 | bucket: tfstateBucketName(deployStage), 200 | key: "ecr/terraform.tfstate", 201 | region: tfstateBucketRegion(), 202 | profile: awsProfileName(deployStage) 203 | } 204 | } 205 | }; 206 | 207 | await createS3Backend(params); 208 | }; 209 | 210 | const networkRemoteState = (deployStage: string) => { 211 | return { 212 | name: "network", 213 | bucket: tfstateBucketName(deployStage), 214 | key: "env:/${terraform.workspace}/network/terraform.tfstate", 215 | region: tfstateBucketRegion(), 216 | profile: awsProfileName(deployStage) 217 | }; 218 | }; 219 | -------------------------------------------------------------------------------- /scripts/createProvider.ts: -------------------------------------------------------------------------------- 1 | import { createAwsProvider } from "@nekonomokochan/terraform-config-creator"; 2 | import { awsProfileName } from "./terraformConfigUtil"; 3 | 4 | const createProvider = async ( 5 | deployStage: string, 6 | outputPath: string 7 | ): Promise => { 8 | const region = 9 | outputPath === "./providers/aws/environments/11-acm/" 10 | ? "us-east-1" 11 | : "ap-northeast-1"; 12 | const params = { 13 | outputPath, 14 | awsProviderParams: [ 15 | { 16 | version: "=2.15.0", 17 | region, 18 | profile: awsProfileName(deployStage) 19 | } 20 | ] 21 | }; 22 | 23 | return await createAwsProvider(params); 24 | }; 25 | 26 | export default createProvider; 27 | -------------------------------------------------------------------------------- /scripts/createTerraformConfig.ts: -------------------------------------------------------------------------------- 1 | import { 2 | createNetworkBackend, 3 | createAcmBackend, 4 | createIamBackend, 5 | createBastionBackend, 6 | createApiBackend, 7 | createFrontendBackend, 8 | createRdsBackend, 9 | createEcrBackend 10 | } from "./createBackend"; 11 | import createProvider from "./createProvider"; 12 | import { 13 | createAcmTfvars, 14 | createBastionTfvars, 15 | createApiTfvars, 16 | createFrontendTfvars, 17 | createRdsTfvars, 18 | createNetworkTfvars 19 | } from "./createTfvars"; 20 | import { isAllowedDeployStage, outputPathList } from "./terraformConfigUtil"; 21 | 22 | (async () => { 23 | const deployStage: string = process.env.DEPLOY_STAGE; 24 | if (!isAllowedDeployStage(deployStage)) { 25 | return Promise.reject( 26 | new Error("有効なステージではありません。dev, prod が利用出来ます。") 27 | ); 28 | } 29 | 30 | await Promise.all([ 31 | createNetworkBackend(deployStage), 32 | createAcmBackend(deployStage), 33 | createIamBackend(deployStage), 34 | createBastionBackend(deployStage), 35 | createApiBackend(deployStage), 36 | createFrontendBackend(deployStage), 37 | createRdsBackend(deployStage), 38 | createEcrBackend(deployStage), 39 | createNetworkTfvars(deployStage), 40 | createAcmTfvars(deployStage), 41 | createBastionTfvars(deployStage), 42 | createApiTfvars(deployStage), 43 | createFrontendTfvars(deployStage), 44 | createRdsTfvars(deployStage) 45 | ]); 46 | 47 | const promises = outputPathList().map((dir: string) => { 48 | return createProvider(deployStage, dir); 49 | }); 50 | await Promise.all(promises); 51 | 52 | return Promise.resolve(); 53 | })().catch((error: Error) => { 54 | console.error(error); 55 | }); 56 | -------------------------------------------------------------------------------- /scripts/createTfvars.ts: -------------------------------------------------------------------------------- 1 | import { 2 | AwsRegion, 3 | createEnvFile, 4 | EnvFileType 5 | } from "@nekonomokochan/aws-env-creator"; 6 | import { awsProfileName } from "./terraformConfigUtil"; 7 | 8 | const secretIds = (deployStage: string) => { 9 | return [`${deployStage}/qiita-stocker-terraform`]; 10 | }; 11 | 12 | export const createNetworkTfvars = async ( 13 | deployStage: string 14 | ): Promise => { 15 | const params = { 16 | region: AwsRegion.ap_northeast_1, 17 | profile: awsProfileName(deployStage), 18 | type: EnvFileType.terraform, 19 | outputDir: "./providers/aws/environments/10-network/", 20 | secretIds: secretIds(deployStage), 21 | outputWhitelist: ["SSH_PUBLIC_KEY_PATH"], 22 | keyMapping: { 23 | SSH_PUBLIC_KEY_PATH: "ssh_public_key_path" 24 | } 25 | }; 26 | 27 | await createEnvFile(params); 28 | }; 29 | 30 | export const createAcmTfvars = async (deployStage: string): Promise => { 31 | const params = { 32 | region: AwsRegion.ap_northeast_1, 33 | profile: awsProfileName(deployStage), 34 | type: EnvFileType.terraform, 35 | outputDir: "./providers/aws/environments/11-acm/", 36 | secretIds: secretIds(deployStage), 37 | outputWhitelist: ["MAIN_DOMAIN_NAME"], 38 | keyMapping: { 39 | MAIN_DOMAIN_NAME: "main_domain_name" 40 | } 41 | }; 42 | 43 | await createEnvFile(params); 44 | }; 45 | 46 | export const createBastionTfvars = async ( 47 | deployStage: string 48 | ): Promise => { 49 | const params = { 50 | region: AwsRegion.ap_northeast_1, 51 | profile: awsProfileName(deployStage), 52 | type: EnvFileType.terraform, 53 | outputDir: "./providers/aws/environments/20-bastion/", 54 | secretIds: secretIds(deployStage), 55 | outputWhitelist: ["SSH_PUBLIC_KEY_PATH"], 56 | keyMapping: { 57 | SSH_PUBLIC_KEY_PATH: "ssh_public_key_path" 58 | } 59 | }; 60 | 61 | await createEnvFile(params); 62 | }; 63 | 64 | export const createApiTfvars = async (deployStage: string): Promise => { 65 | const params = { 66 | region: AwsRegion.ap_northeast_1, 67 | profile: awsProfileName(deployStage), 68 | type: EnvFileType.terraform, 69 | outputDir: "./providers/aws/environments/21-api/", 70 | secretIds: secretIds(deployStage), 71 | outputWhitelist: ["MAIN_DOMAIN_NAME"], 72 | addParams: { 73 | rds_local_master_domain_name: "qiita-stocker-db" 74 | }, 75 | keyMapping: { 76 | MAIN_DOMAIN_NAME: "main_domain_name" 77 | } 78 | }; 79 | 80 | await createEnvFile(params); 81 | }; 82 | 83 | export const createFrontendTfvars = async ( 84 | deployStage: string 85 | ): Promise => { 86 | const params = { 87 | region: AwsRegion.ap_northeast_1, 88 | profile: awsProfileName(deployStage), 89 | type: EnvFileType.terraform, 90 | outputDir: "./providers/aws/environments/22-frontend/", 91 | secretIds: secretIds(deployStage), 92 | outputWhitelist: ["MAIN_DOMAIN_NAME"], 93 | keyMapping: { 94 | MAIN_DOMAIN_NAME: "main_domain_name" 95 | } 96 | }; 97 | 98 | await createEnvFile(params); 99 | }; 100 | 101 | export const createRdsTfvars = async (deployStage: string): Promise => { 102 | const params = { 103 | region: AwsRegion.ap_northeast_1, 104 | profile: awsProfileName(deployStage), 105 | type: EnvFileType.terraform, 106 | outputDir: "./providers/aws/environments/23-rds/", 107 | secretIds: secretIds(deployStage), 108 | outputWhitelist: ["RDS_MASTER_USERNAME", "RDS_MASTER_PASSWORD"], 109 | addParams: { 110 | rds_local_master_domain_name: "qiita-stocker-db" 111 | }, 112 | keyMapping: { 113 | RDS_MASTER_USERNAME: "rds_master_username", 114 | RDS_MASTER_PASSWORD: "rds_master_password" 115 | } 116 | }; 117 | 118 | await createEnvFile(params); 119 | }; 120 | -------------------------------------------------------------------------------- /scripts/terraformConfigUtil.ts: -------------------------------------------------------------------------------- 1 | export const terraformVersion = (): string => { 2 | return "=0.12.2"; 3 | }; 4 | 5 | export const tfstateBucketName = (deployStage: string): string => { 6 | return `${deployStage}-qiita-stocker-tfstate`; 7 | }; 8 | 9 | export const tfstateBucketRegion = (): string => { 10 | return "ap-northeast-1"; 11 | }; 12 | 13 | export const awsProfileName = (deployStage: string) => { 14 | return `qiita-stocker-${deployStage}`; 15 | }; 16 | 17 | export const networkOutputPath = (): string => { 18 | return "./providers/aws/environments/10-network/"; 19 | }; 20 | 21 | export const acmOutputPath = (): string => { 22 | return "./providers/aws/environments/11-acm/"; 23 | }; 24 | 25 | export const iamOutputPath = (): string => { 26 | return "./providers/aws/environments/13-iam/"; 27 | }; 28 | 29 | export const bastionOutputPath = (): string => { 30 | return "./providers/aws/environments/20-bastion/"; 31 | }; 32 | 33 | export const apiOutputPath = (): string => { 34 | return "./providers/aws/environments/21-api/"; 35 | }; 36 | 37 | export const frontendOutputPath = (): string => { 38 | return "./providers/aws/environments/22-frontend/"; 39 | }; 40 | 41 | export const rdsOutputPath = (): string => { 42 | return "./providers/aws/environments/23-rds/"; 43 | }; 44 | 45 | export const ecrOutputPath = (): string => { 46 | return "./providers/aws/environments/12-ecr/"; 47 | }; 48 | 49 | export const outputPathList = (): string[] => { 50 | return [ 51 | networkOutputPath(), 52 | acmOutputPath(), 53 | iamOutputPath(), 54 | bastionOutputPath(), 55 | apiOutputPath(), 56 | frontendOutputPath(), 57 | rdsOutputPath(), 58 | ecrOutputPath() 59 | ]; 60 | }; 61 | 62 | export const isAllowedDeployStage = (deployStage: string) => { 63 | return deployStage === "dev" || deployStage === "prod"; 64 | }; 65 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "moduleResolution": "node", 5 | "target": "esnext", 6 | "sourceMap": true, 7 | "outDir": "dist", 8 | "removeComments": true, 9 | "strict": true, 10 | "noUnusedLocals": true, 11 | "noUnusedParameters": true, 12 | "noImplicitReturns": true, 13 | "noFallthroughCasesInSwitch": true, 14 | "forceConsistentCasingInFileNames": true, 15 | "allowSyntheticDefaultImports": true, 16 | "experimentalDecorators": true, 17 | "esModuleInterop": true, 18 | "newLine": "LF", 19 | "declaration": true, 20 | "declarationMap": true, 21 | "typeRoots": [ 22 | "node_modules/@types" 23 | ], 24 | "lib": [ 25 | "esnext" 26 | ] 27 | }, 28 | "exclude": [ 29 | "node_modules" 30 | ], 31 | "include": [ 32 | "scripts" 33 | ] 34 | } 35 | -------------------------------------------------------------------------------- /versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 0.12" 3 | } 4 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@babel/code-frame@^7.0.0": 6 | version "7.0.0" 7 | resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0.tgz#06e2ab19bdb535385559aabb5ba59729482800f8" 8 | integrity sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA== 9 | dependencies: 10 | "@babel/highlight" "^7.0.0" 11 | 12 | "@babel/highlight@^7.0.0": 13 | version "7.0.0" 14 | resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.0.0.tgz#f710c38c8d458e6dd9a201afb637fcb781ce99e4" 15 | integrity sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw== 16 | dependencies: 17 | chalk "^2.0.0" 18 | esutils "^2.0.2" 19 | js-tokens "^4.0.0" 20 | 21 | "@nekonomokochan/aws-env-creator@^1.3.0": 22 | version "1.3.0" 23 | resolved "https://registry.yarnpkg.com/@nekonomokochan/aws-env-creator/-/aws-env-creator-1.3.0.tgz#5ff0e2ac019f83134e343b22075694a658b7838c" 24 | integrity sha512-0S4X9Rt5L7RapLmpBm9S80JPXnEnwzWLOFPVS8xRctA7e3P26R2LYOnj0xkR4nL8FxL2O708Ro6UAAVRlgEIeQ== 25 | dependencies: 26 | aws-sdk "^2.391.0" 27 | 28 | "@nekonomokochan/terraform-config-creator@^2.0.0": 29 | version "2.0.0" 30 | resolved "https://registry.yarnpkg.com/@nekonomokochan/terraform-config-creator/-/terraform-config-creator-2.0.0.tgz#38aefaf2a3fd224ed573df6cd8feba9bc298b33f" 31 | integrity sha512-xcvvp1nTymniqFiOeO/5QYwP96Dj5lLP7dKqWhE7y6VVa4C+JGctFPRXyhI1DMj47JPIQ6Y2OvYuU0w/vwf4bQ== 32 | 33 | "@types/eslint-visitor-keys@^1.0.0": 34 | version "1.0.0" 35 | resolved "https://registry.yarnpkg.com/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#1ee30d79544ca84d68d4b3cdb0af4f205663dd2d" 36 | integrity sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag== 37 | 38 | "@types/node@^12.0.8": 39 | version "12.0.8" 40 | resolved "https://registry.yarnpkg.com/@types/node/-/node-12.0.8.tgz#551466be11b2adc3f3d47156758f610bd9f6b1d8" 41 | integrity sha512-b8bbUOTwzIY3V5vDTY1fIJ+ePKDUBqt2hC2woVGotdQQhG/2Sh62HOKHrT7ab+VerXAcPyAiTEipPu/FsreUtg== 42 | 43 | "@typescript-eslint/eslint-plugin@^1.10.2": 44 | version "1.10.2" 45 | resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-1.10.2.tgz#552fc64cfcb19c6162190360217c945e8faa330a" 46 | integrity sha512-7449RhjE1oLFIy5E/5rT4wG5+KsfPzakJuhvpzXJ3C46lq7xywY0/Rjo9ZBcwrfbk0nRZ5xmUHkk7DZ67tSBKw== 47 | dependencies: 48 | "@typescript-eslint/experimental-utils" "1.10.2" 49 | eslint-utils "^1.3.1" 50 | functional-red-black-tree "^1.0.1" 51 | regexpp "^2.0.1" 52 | tsutils "^3.7.0" 53 | 54 | "@typescript-eslint/experimental-utils@1.10.2": 55 | version "1.10.2" 56 | resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-1.10.2.tgz#cd548c03fc1a2b3ba5c136d1599001a1ede24215" 57 | integrity sha512-Hf5lYcrnTH5Oc67SRrQUA7KuHErMvCf5RlZsyxXPIT6AXa8fKTyfFO6vaEnUmlz48RpbxO4f0fY3QtWkuHZNjg== 58 | dependencies: 59 | "@typescript-eslint/typescript-estree" "1.10.2" 60 | eslint-scope "^4.0.0" 61 | 62 | "@typescript-eslint/parser@^1.10.2": 63 | version "1.10.2" 64 | resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-1.10.2.tgz#36cfe8c6bf1b6c1dd81da56f88c8588f4b1a852b" 65 | integrity sha512-xWDWPfZfV0ENU17ermIUVEVSseBBJxKfqBcRCMZ8nAjJbfA5R7NWMZmFFHYnars5MjK4fPjhu4gwQv526oZIPQ== 66 | dependencies: 67 | "@types/eslint-visitor-keys" "^1.0.0" 68 | "@typescript-eslint/experimental-utils" "1.10.2" 69 | "@typescript-eslint/typescript-estree" "1.10.2" 70 | eslint-visitor-keys "^1.0.0" 71 | 72 | "@typescript-eslint/typescript-estree@1.10.2": 73 | version "1.10.2" 74 | resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-1.10.2.tgz#8403585dd74b6cfb6f78aa98b6958de158b5897b" 75 | integrity sha512-Kutjz0i69qraOsWeI8ETqYJ07tRLvD9URmdrMoF10bG8y8ucLmPtSxROvVejWvlJUGl2et/plnMiKRDW+rhEhw== 76 | dependencies: 77 | lodash.unescape "4.0.1" 78 | semver "5.5.0" 79 | 80 | acorn-jsx@^5.0.0: 81 | version "5.0.1" 82 | resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.0.1.tgz#32a064fd925429216a09b141102bfdd185fae40e" 83 | integrity sha512-HJ7CfNHrfJLlNTzIEUTj43LNWGkqpRLxm3YjAlcD0ACydk9XynzYsCBHxut+iqt+1aBXkx9UP/w/ZqMr13XIzg== 84 | 85 | acorn@^6.0.7: 86 | version "6.4.1" 87 | resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.1.tgz#531e58ba3f51b9dacb9a6646ca4debf5b14ca474" 88 | integrity sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA== 89 | 90 | ajv@^6.9.1: 91 | version "6.10.0" 92 | resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.0.tgz#90d0d54439da587cd7e843bfb7045f50bd22bdf1" 93 | integrity sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg== 94 | dependencies: 95 | fast-deep-equal "^2.0.1" 96 | fast-json-stable-stringify "^2.0.0" 97 | json-schema-traverse "^0.4.1" 98 | uri-js "^4.2.2" 99 | 100 | ansi-escapes@^3.2.0: 101 | version "3.2.0" 102 | resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" 103 | integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ== 104 | 105 | ansi-regex@^3.0.0: 106 | version "3.0.0" 107 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" 108 | integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= 109 | 110 | ansi-regex@^4.1.0: 111 | version "4.1.0" 112 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" 113 | integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== 114 | 115 | ansi-styles@^3.2.0, ansi-styles@^3.2.1: 116 | version "3.2.1" 117 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" 118 | integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== 119 | dependencies: 120 | color-convert "^1.9.0" 121 | 122 | arg@^4.1.0: 123 | version "4.1.0" 124 | resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.0.tgz#583c518199419e0037abb74062c37f8519e575f0" 125 | integrity sha512-ZWc51jO3qegGkVh8Hwpv636EkbesNV5ZNQPCtRa+0qytRYPEs9IYT9qITY9buezqUH5uqyzlWLcufrzU2rffdg== 126 | 127 | argparse@^1.0.7: 128 | version "1.0.10" 129 | resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" 130 | integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== 131 | dependencies: 132 | sprintf-js "~1.0.2" 133 | 134 | astral-regex@^1.0.0: 135 | version "1.0.0" 136 | resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" 137 | integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== 138 | 139 | aws-sdk@^2.391.0: 140 | version "2.476.0" 141 | resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.476.0.tgz#e7d9cefaae33e14ba3d9203fa4b64647fc1b188b" 142 | integrity sha512-GBvp/VjKu5YAiwzLVyfUajq43BXBvxhNUz6D27mG/ttceeFdQxMkZbAHSk36vH7rtECGIgRTw5ok8BoHVCTGuw== 143 | dependencies: 144 | buffer "4.9.1" 145 | events "1.1.1" 146 | ieee754 "1.1.8" 147 | jmespath "0.15.0" 148 | querystring "0.2.0" 149 | sax "1.2.1" 150 | url "0.10.3" 151 | uuid "3.3.2" 152 | xml2js "0.4.19" 153 | 154 | balanced-match@^1.0.0: 155 | version "1.0.0" 156 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" 157 | integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= 158 | 159 | base64-js@^1.0.2: 160 | version "1.3.0" 161 | resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.0.tgz#cab1e6118f051095e58b5281aea8c1cd22bfc0e3" 162 | integrity sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw== 163 | 164 | brace-expansion@^1.1.7: 165 | version "1.1.11" 166 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" 167 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== 168 | dependencies: 169 | balanced-match "^1.0.0" 170 | concat-map "0.0.1" 171 | 172 | buffer-from@^1.0.0: 173 | version "1.1.1" 174 | resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" 175 | integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== 176 | 177 | buffer@4.9.1: 178 | version "4.9.1" 179 | resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" 180 | integrity sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg= 181 | dependencies: 182 | base64-js "^1.0.2" 183 | ieee754 "^1.1.4" 184 | isarray "^1.0.0" 185 | 186 | callsites@^3.0.0: 187 | version "3.1.0" 188 | resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" 189 | integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== 190 | 191 | chalk@^2.0.0, chalk@^2.1.0, chalk@^2.4.2: 192 | version "2.4.2" 193 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" 194 | integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== 195 | dependencies: 196 | ansi-styles "^3.2.1" 197 | escape-string-regexp "^1.0.5" 198 | supports-color "^5.3.0" 199 | 200 | chardet@^0.7.0: 201 | version "0.7.0" 202 | resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" 203 | integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== 204 | 205 | cli-cursor@^2.1.0: 206 | version "2.1.0" 207 | resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" 208 | integrity sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU= 209 | dependencies: 210 | restore-cursor "^2.0.0" 211 | 212 | cli-width@^2.0.0: 213 | version "2.2.0" 214 | resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" 215 | integrity sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk= 216 | 217 | color-convert@^1.9.0: 218 | version "1.9.3" 219 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" 220 | integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== 221 | dependencies: 222 | color-name "1.1.3" 223 | 224 | color-name@1.1.3: 225 | version "1.1.3" 226 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" 227 | integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= 228 | 229 | concat-map@0.0.1: 230 | version "0.0.1" 231 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 232 | integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= 233 | 234 | cross-spawn@^6.0.5: 235 | version "6.0.5" 236 | resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" 237 | integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== 238 | dependencies: 239 | nice-try "^1.0.4" 240 | path-key "^2.0.1" 241 | semver "^5.5.0" 242 | shebang-command "^1.2.0" 243 | which "^1.2.9" 244 | 245 | debug@^4.0.1: 246 | version "4.1.1" 247 | resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" 248 | integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== 249 | dependencies: 250 | ms "^2.1.1" 251 | 252 | deep-is@~0.1.3: 253 | version "0.1.3" 254 | resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" 255 | integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= 256 | 257 | diff@^4.0.1: 258 | version "4.0.1" 259 | resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.1.tgz#0c667cb467ebbb5cea7f14f135cc2dba7780a8ff" 260 | integrity sha512-s2+XdvhPCOF01LRQBC8hf4vhbVmI2CGS5aZnxLJlT5FtdhPCDFq80q++zK2KlrVorVDdL5BOGZ/VfLrVtYNF+Q== 261 | 262 | doctrine@^3.0.0: 263 | version "3.0.0" 264 | resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" 265 | integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== 266 | dependencies: 267 | esutils "^2.0.2" 268 | 269 | emoji-regex@^7.0.1: 270 | version "7.0.3" 271 | resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" 272 | integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== 273 | 274 | escape-string-regexp@^1.0.5: 275 | version "1.0.5" 276 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" 277 | integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= 278 | 279 | eslint-config-prettier@^5.0.0: 280 | version "5.0.0" 281 | resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-5.0.0.tgz#f7a94b2b8ae7cbf25842c36fa96c6d32cd0a697c" 282 | integrity sha512-c17Aqiz5e8LEqoc/QPmYnaxQFAHTx2KlCZBPxXXjEMmNchOLnV/7j0HoPZuC+rL/tDC9bazUYOKJW9bOhftI/w== 283 | dependencies: 284 | get-stdin "^6.0.0" 285 | 286 | eslint-plugin-prettier@^3.1.0: 287 | version "3.1.0" 288 | resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.1.0.tgz#8695188f95daa93b0dc54b249347ca3b79c4686d" 289 | integrity sha512-XWX2yVuwVNLOUhQijAkXz+rMPPoCr7WFiAl8ig6I7Xn+pPVhDhzg4DxHpmbeb0iqjO9UronEA3Tb09ChnFVHHA== 290 | dependencies: 291 | prettier-linter-helpers "^1.0.0" 292 | 293 | eslint-scope@^4.0.0, eslint-scope@^4.0.3: 294 | version "4.0.3" 295 | resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848" 296 | integrity sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg== 297 | dependencies: 298 | esrecurse "^4.1.0" 299 | estraverse "^4.1.1" 300 | 301 | eslint-utils@^1.3.1: 302 | version "1.4.3" 303 | resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.3.tgz#74fec7c54d0776b6f67e0251040b5806564e981f" 304 | integrity sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q== 305 | dependencies: 306 | eslint-visitor-keys "^1.1.0" 307 | 308 | eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0: 309 | version "1.1.0" 310 | resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz#e2a82cea84ff246ad6fb57f9bde5b46621459ec2" 311 | integrity sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A== 312 | 313 | eslint@^5.16.0: 314 | version "5.16.0" 315 | resolved "https://registry.yarnpkg.com/eslint/-/eslint-5.16.0.tgz#a1e3ac1aae4a3fbd8296fcf8f7ab7314cbb6abea" 316 | integrity sha512-S3Rz11i7c8AA5JPv7xAH+dOyq/Cu/VXHiHXBPOU1k/JAM5dXqQPt3qcrhpHSorXmrpu2g0gkIBVXAqCpzfoZIg== 317 | dependencies: 318 | "@babel/code-frame" "^7.0.0" 319 | ajv "^6.9.1" 320 | chalk "^2.1.0" 321 | cross-spawn "^6.0.5" 322 | debug "^4.0.1" 323 | doctrine "^3.0.0" 324 | eslint-scope "^4.0.3" 325 | eslint-utils "^1.3.1" 326 | eslint-visitor-keys "^1.0.0" 327 | espree "^5.0.1" 328 | esquery "^1.0.1" 329 | esutils "^2.0.2" 330 | file-entry-cache "^5.0.1" 331 | functional-red-black-tree "^1.0.1" 332 | glob "^7.1.2" 333 | globals "^11.7.0" 334 | ignore "^4.0.6" 335 | import-fresh "^3.0.0" 336 | imurmurhash "^0.1.4" 337 | inquirer "^6.2.2" 338 | js-yaml "^3.13.0" 339 | json-stable-stringify-without-jsonify "^1.0.1" 340 | levn "^0.3.0" 341 | lodash "^4.17.11" 342 | minimatch "^3.0.4" 343 | mkdirp "^0.5.1" 344 | natural-compare "^1.4.0" 345 | optionator "^0.8.2" 346 | path-is-inside "^1.0.2" 347 | progress "^2.0.0" 348 | regexpp "^2.0.1" 349 | semver "^5.5.1" 350 | strip-ansi "^4.0.0" 351 | strip-json-comments "^2.0.1" 352 | table "^5.2.3" 353 | text-table "^0.2.0" 354 | 355 | espree@^5.0.1: 356 | version "5.0.1" 357 | resolved "https://registry.yarnpkg.com/espree/-/espree-5.0.1.tgz#5d6526fa4fc7f0788a5cf75b15f30323e2f81f7a" 358 | integrity sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A== 359 | dependencies: 360 | acorn "^6.0.7" 361 | acorn-jsx "^5.0.0" 362 | eslint-visitor-keys "^1.0.0" 363 | 364 | esprima@^4.0.0: 365 | version "4.0.1" 366 | resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" 367 | integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== 368 | 369 | esquery@^1.0.1: 370 | version "1.0.1" 371 | resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.1.tgz#406c51658b1f5991a5f9b62b1dc25b00e3e5c708" 372 | integrity sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA== 373 | dependencies: 374 | estraverse "^4.0.0" 375 | 376 | esrecurse@^4.1.0: 377 | version "4.2.1" 378 | resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf" 379 | integrity sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ== 380 | dependencies: 381 | estraverse "^4.1.0" 382 | 383 | estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1: 384 | version "4.2.0" 385 | resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" 386 | integrity sha1-De4/7TH81GlhjOc0IJn8GvoL2xM= 387 | 388 | esutils@^2.0.2: 389 | version "2.0.2" 390 | resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" 391 | integrity sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs= 392 | 393 | events@1.1.1: 394 | version "1.1.1" 395 | resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" 396 | integrity sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ= 397 | 398 | external-editor@^3.0.3: 399 | version "3.0.3" 400 | resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.0.3.tgz#5866db29a97826dbe4bf3afd24070ead9ea43a27" 401 | integrity sha512-bn71H9+qWoOQKyZDo25mOMVpSmXROAsTJVVVYzrrtol3d4y+AsKjf4Iwl2Q+IuT0kFSQ1qo166UuIwqYq7mGnA== 402 | dependencies: 403 | chardet "^0.7.0" 404 | iconv-lite "^0.4.24" 405 | tmp "^0.0.33" 406 | 407 | fast-deep-equal@^2.0.1: 408 | version "2.0.1" 409 | resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" 410 | integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk= 411 | 412 | fast-diff@^1.1.2: 413 | version "1.2.0" 414 | resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" 415 | integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w== 416 | 417 | fast-json-stable-stringify@^2.0.0: 418 | version "2.0.0" 419 | resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" 420 | integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= 421 | 422 | fast-levenshtein@~2.0.4: 423 | version "2.0.6" 424 | resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" 425 | integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= 426 | 427 | figures@^2.0.0: 428 | version "2.0.0" 429 | resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" 430 | integrity sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI= 431 | dependencies: 432 | escape-string-regexp "^1.0.5" 433 | 434 | file-entry-cache@^5.0.1: 435 | version "5.0.1" 436 | resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c" 437 | integrity sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g== 438 | dependencies: 439 | flat-cache "^2.0.1" 440 | 441 | flat-cache@^2.0.1: 442 | version "2.0.1" 443 | resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0" 444 | integrity sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA== 445 | dependencies: 446 | flatted "^2.0.0" 447 | rimraf "2.6.3" 448 | write "1.0.3" 449 | 450 | flatted@^2.0.0: 451 | version "2.0.0" 452 | resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.0.tgz#55122b6536ea496b4b44893ee2608141d10d9916" 453 | integrity sha512-R+H8IZclI8AAkSBRQJLVOsxwAoHd6WC40b4QTNWIjzAa6BXOBfQcM587MXDTVPeYaopFNWHUFLx7eNmHDSxMWg== 454 | 455 | fs.realpath@^1.0.0: 456 | version "1.0.0" 457 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 458 | integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= 459 | 460 | functional-red-black-tree@^1.0.1: 461 | version "1.0.1" 462 | resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" 463 | integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= 464 | 465 | get-stdin@^6.0.0: 466 | version "6.0.0" 467 | resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b" 468 | integrity sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g== 469 | 470 | glob@^7.1.2, glob@^7.1.3: 471 | version "7.1.4" 472 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255" 473 | integrity sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A== 474 | dependencies: 475 | fs.realpath "^1.0.0" 476 | inflight "^1.0.4" 477 | inherits "2" 478 | minimatch "^3.0.4" 479 | once "^1.3.0" 480 | path-is-absolute "^1.0.0" 481 | 482 | globals@^11.7.0: 483 | version "11.12.0" 484 | resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" 485 | integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== 486 | 487 | has-flag@^3.0.0: 488 | version "3.0.0" 489 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" 490 | integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= 491 | 492 | iconv-lite@^0.4.24: 493 | version "0.4.24" 494 | resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" 495 | integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== 496 | dependencies: 497 | safer-buffer ">= 2.1.2 < 3" 498 | 499 | ieee754@1.1.8: 500 | version "1.1.8" 501 | resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4" 502 | integrity sha1-vjPUCsEO8ZJnAfbwii2G+/0a0+Q= 503 | 504 | ieee754@^1.1.4: 505 | version "1.1.13" 506 | resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84" 507 | integrity sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg== 508 | 509 | ignore@^4.0.6: 510 | version "4.0.6" 511 | resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" 512 | integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== 513 | 514 | import-fresh@^3.0.0: 515 | version "3.0.0" 516 | resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.0.0.tgz#a3d897f420cab0e671236897f75bc14b4885c390" 517 | integrity sha512-pOnA9tfM3Uwics+SaBLCNyZZZbK+4PTu0OPZtLlMIrv17EdBoC15S9Kn8ckJ9TZTyKb3ywNE5y1yeDxxGA7nTQ== 518 | dependencies: 519 | parent-module "^1.0.0" 520 | resolve-from "^4.0.0" 521 | 522 | imurmurhash@^0.1.4: 523 | version "0.1.4" 524 | resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" 525 | integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= 526 | 527 | inflight@^1.0.4: 528 | version "1.0.6" 529 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 530 | integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= 531 | dependencies: 532 | once "^1.3.0" 533 | wrappy "1" 534 | 535 | inherits@2: 536 | version "2.0.3" 537 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" 538 | integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= 539 | 540 | inquirer@^6.2.2: 541 | version "6.3.1" 542 | resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.3.1.tgz#7a413b5e7950811013a3db491c61d1f3b776e8e7" 543 | integrity sha512-MmL624rfkFt4TG9y/Jvmt8vdmOo836U7Y0Hxr2aFk3RelZEGX4Igk0KabWrcaaZaTv9uzglOqWh1Vly+FAWAXA== 544 | dependencies: 545 | ansi-escapes "^3.2.0" 546 | chalk "^2.4.2" 547 | cli-cursor "^2.1.0" 548 | cli-width "^2.0.0" 549 | external-editor "^3.0.3" 550 | figures "^2.0.0" 551 | lodash "^4.17.11" 552 | mute-stream "0.0.7" 553 | run-async "^2.2.0" 554 | rxjs "^6.4.0" 555 | string-width "^2.1.0" 556 | strip-ansi "^5.1.0" 557 | through "^2.3.6" 558 | 559 | is-fullwidth-code-point@^2.0.0: 560 | version "2.0.0" 561 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" 562 | integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= 563 | 564 | is-promise@^2.1.0: 565 | version "2.1.0" 566 | resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" 567 | integrity sha1-eaKp7OfwlugPNtKy87wWwf9L8/o= 568 | 569 | isarray@^1.0.0: 570 | version "1.0.0" 571 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" 572 | integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= 573 | 574 | isexe@^2.0.0: 575 | version "2.0.0" 576 | resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" 577 | integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= 578 | 579 | jmespath@0.15.0: 580 | version "0.15.0" 581 | resolved "https://registry.yarnpkg.com/jmespath/-/jmespath-0.15.0.tgz#a3f222a9aae9f966f5d27c796510e28091764217" 582 | integrity sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc= 583 | 584 | js-tokens@^4.0.0: 585 | version "4.0.0" 586 | resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" 587 | integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== 588 | 589 | js-yaml@^3.13.0: 590 | version "3.13.1" 591 | resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" 592 | integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== 593 | dependencies: 594 | argparse "^1.0.7" 595 | esprima "^4.0.0" 596 | 597 | json-schema-traverse@^0.4.1: 598 | version "0.4.1" 599 | resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" 600 | integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== 601 | 602 | json-stable-stringify-without-jsonify@^1.0.1: 603 | version "1.0.1" 604 | resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" 605 | integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= 606 | 607 | levn@^0.3.0, levn@~0.3.0: 608 | version "0.3.0" 609 | resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" 610 | integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= 611 | dependencies: 612 | prelude-ls "~1.1.2" 613 | type-check "~0.3.2" 614 | 615 | lodash.unescape@4.0.1: 616 | version "4.0.1" 617 | resolved "https://registry.yarnpkg.com/lodash.unescape/-/lodash.unescape-4.0.1.tgz#bf2249886ce514cda112fae9218cdc065211fc9c" 618 | integrity sha1-vyJJiGzlFM2hEvrpIYzcBlIR/Jw= 619 | 620 | lodash@^4.17.11: 621 | version "4.17.21" 622 | resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" 623 | integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== 624 | 625 | make-error@^1.1.1: 626 | version "1.3.5" 627 | resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.5.tgz#efe4e81f6db28cadd605c70f29c831b58ef776c8" 628 | integrity sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g== 629 | 630 | mimic-fn@^1.0.0: 631 | version "1.2.0" 632 | resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" 633 | integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== 634 | 635 | minimatch@^3.0.4: 636 | version "3.0.4" 637 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" 638 | integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== 639 | dependencies: 640 | brace-expansion "^1.1.7" 641 | 642 | minimist@0.0.8: 643 | version "0.0.8" 644 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" 645 | integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= 646 | 647 | mkdirp@^0.5.1: 648 | version "0.5.1" 649 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" 650 | integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= 651 | dependencies: 652 | minimist "0.0.8" 653 | 654 | ms@^2.1.1: 655 | version "2.1.2" 656 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" 657 | integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== 658 | 659 | mute-stream@0.0.7: 660 | version "0.0.7" 661 | resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" 662 | integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s= 663 | 664 | natural-compare@^1.4.0: 665 | version "1.4.0" 666 | resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" 667 | integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= 668 | 669 | nice-try@^1.0.4: 670 | version "1.0.5" 671 | resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" 672 | integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== 673 | 674 | once@^1.3.0: 675 | version "1.4.0" 676 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 677 | integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= 678 | dependencies: 679 | wrappy "1" 680 | 681 | onetime@^2.0.0: 682 | version "2.0.1" 683 | resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" 684 | integrity sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ= 685 | dependencies: 686 | mimic-fn "^1.0.0" 687 | 688 | optionator@^0.8.2: 689 | version "0.8.2" 690 | resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" 691 | integrity sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q= 692 | dependencies: 693 | deep-is "~0.1.3" 694 | fast-levenshtein "~2.0.4" 695 | levn "~0.3.0" 696 | prelude-ls "~1.1.2" 697 | type-check "~0.3.2" 698 | wordwrap "~1.0.0" 699 | 700 | os-tmpdir@~1.0.2: 701 | version "1.0.2" 702 | resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" 703 | integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= 704 | 705 | parent-module@^1.0.0: 706 | version "1.0.1" 707 | resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" 708 | integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== 709 | dependencies: 710 | callsites "^3.0.0" 711 | 712 | path-is-absolute@^1.0.0: 713 | version "1.0.1" 714 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 715 | integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= 716 | 717 | path-is-inside@^1.0.2: 718 | version "1.0.2" 719 | resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" 720 | integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= 721 | 722 | path-key@^2.0.1: 723 | version "2.0.1" 724 | resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" 725 | integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= 726 | 727 | prelude-ls@~1.1.2: 728 | version "1.1.2" 729 | resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" 730 | integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= 731 | 732 | prettier-linter-helpers@^1.0.0: 733 | version "1.0.0" 734 | resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" 735 | integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== 736 | dependencies: 737 | fast-diff "^1.1.2" 738 | 739 | prettier@^1.18.2: 740 | version "1.18.2" 741 | resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.18.2.tgz#6823e7c5900017b4bd3acf46fe9ac4b4d7bda9ea" 742 | integrity sha512-OeHeMc0JhFE9idD4ZdtNibzY0+TPHSpSSb9h8FqtP+YnoZZ1sl8Vc9b1sasjfymH3SonAF4QcA2+mzHPhMvIiw== 743 | 744 | progress@^2.0.0: 745 | version "2.0.3" 746 | resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" 747 | integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== 748 | 749 | punycode@1.3.2: 750 | version "1.3.2" 751 | resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" 752 | integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0= 753 | 754 | punycode@^2.1.0: 755 | version "2.1.1" 756 | resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" 757 | integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== 758 | 759 | querystring@0.2.0: 760 | version "0.2.0" 761 | resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" 762 | integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= 763 | 764 | regexpp@^2.0.1: 765 | version "2.0.1" 766 | resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" 767 | integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw== 768 | 769 | resolve-from@^4.0.0: 770 | version "4.0.0" 771 | resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" 772 | integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== 773 | 774 | restore-cursor@^2.0.0: 775 | version "2.0.0" 776 | resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" 777 | integrity sha1-n37ih/gv0ybU/RYpI9YhKe7g368= 778 | dependencies: 779 | onetime "^2.0.0" 780 | signal-exit "^3.0.2" 781 | 782 | rimraf@2.6.3: 783 | version "2.6.3" 784 | resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" 785 | integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== 786 | dependencies: 787 | glob "^7.1.3" 788 | 789 | run-async@^2.2.0: 790 | version "2.3.0" 791 | resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" 792 | integrity sha1-A3GrSuC91yDUFm19/aZP96RFpsA= 793 | dependencies: 794 | is-promise "^2.1.0" 795 | 796 | rxjs@^6.4.0: 797 | version "6.5.2" 798 | resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.2.tgz#2e35ce815cd46d84d02a209fb4e5921e051dbec7" 799 | integrity sha512-HUb7j3kvb7p7eCUHE3FqjoDsC1xfZQ4AHFWfTKSpZ+sAhhz5X1WX0ZuUqWbzB2QhSLp3DoLUG+hMdEDKqWo2Zg== 800 | dependencies: 801 | tslib "^1.9.0" 802 | 803 | "safer-buffer@>= 2.1.2 < 3": 804 | version "2.1.2" 805 | resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" 806 | integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== 807 | 808 | sax@1.2.1: 809 | version "1.2.1" 810 | resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.1.tgz#7b8e656190b228e81a66aea748480d828cd2d37a" 811 | integrity sha1-e45lYZCyKOgaZq6nSEgNgozS03o= 812 | 813 | sax@>=0.6.0: 814 | version "1.2.4" 815 | resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" 816 | integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== 817 | 818 | semver@5.5.0: 819 | version "5.5.0" 820 | resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" 821 | integrity sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA== 822 | 823 | semver@^5.5.0, semver@^5.5.1: 824 | version "5.7.0" 825 | resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b" 826 | integrity sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA== 827 | 828 | shebang-command@^1.2.0: 829 | version "1.2.0" 830 | resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" 831 | integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= 832 | dependencies: 833 | shebang-regex "^1.0.0" 834 | 835 | shebang-regex@^1.0.0: 836 | version "1.0.0" 837 | resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" 838 | integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= 839 | 840 | signal-exit@^3.0.2: 841 | version "3.0.2" 842 | resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" 843 | integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= 844 | 845 | slice-ansi@^2.1.0: 846 | version "2.1.0" 847 | resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" 848 | integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ== 849 | dependencies: 850 | ansi-styles "^3.2.0" 851 | astral-regex "^1.0.0" 852 | is-fullwidth-code-point "^2.0.0" 853 | 854 | source-map-support@^0.5.6: 855 | version "0.5.12" 856 | resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.12.tgz#b4f3b10d51857a5af0138d3ce8003b201613d599" 857 | integrity sha512-4h2Pbvyy15EE02G+JOZpUCmqWJuqrs+sEkzewTm++BPi7Hvn/HwcqLAcNxYAyI0x13CpPPn+kMjl+hplXMHITQ== 858 | dependencies: 859 | buffer-from "^1.0.0" 860 | source-map "^0.6.0" 861 | 862 | source-map@^0.6.0: 863 | version "0.6.1" 864 | resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" 865 | integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== 866 | 867 | sprintf-js@~1.0.2: 868 | version "1.0.3" 869 | resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" 870 | integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= 871 | 872 | string-width@^2.1.0: 873 | version "2.1.1" 874 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" 875 | integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== 876 | dependencies: 877 | is-fullwidth-code-point "^2.0.0" 878 | strip-ansi "^4.0.0" 879 | 880 | string-width@^3.0.0: 881 | version "3.1.0" 882 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" 883 | integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== 884 | dependencies: 885 | emoji-regex "^7.0.1" 886 | is-fullwidth-code-point "^2.0.0" 887 | strip-ansi "^5.1.0" 888 | 889 | strip-ansi@^4.0.0: 890 | version "4.0.0" 891 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" 892 | integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= 893 | dependencies: 894 | ansi-regex "^3.0.0" 895 | 896 | strip-ansi@^5.1.0: 897 | version "5.2.0" 898 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" 899 | integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== 900 | dependencies: 901 | ansi-regex "^4.1.0" 902 | 903 | strip-json-comments@^2.0.1: 904 | version "2.0.1" 905 | resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" 906 | integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= 907 | 908 | supports-color@^5.3.0: 909 | version "5.5.0" 910 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" 911 | integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== 912 | dependencies: 913 | has-flag "^3.0.0" 914 | 915 | table@^5.2.3: 916 | version "5.4.1" 917 | resolved "https://registry.yarnpkg.com/table/-/table-5.4.1.tgz#0691ae2ebe8259858efb63e550b6d5f9300171e8" 918 | integrity sha512-E6CK1/pZe2N75rGZQotFOdmzWQ1AILtgYbMAbAjvms0S1l5IDB47zG3nCnFGB/w+7nB3vKofbLXCH7HPBo864w== 919 | dependencies: 920 | ajv "^6.9.1" 921 | lodash "^4.17.11" 922 | slice-ansi "^2.1.0" 923 | string-width "^3.0.0" 924 | 925 | text-table@^0.2.0: 926 | version "0.2.0" 927 | resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" 928 | integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= 929 | 930 | through@^2.3.6: 931 | version "2.3.8" 932 | resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" 933 | integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= 934 | 935 | tmp@^0.0.33: 936 | version "0.0.33" 937 | resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" 938 | integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== 939 | dependencies: 940 | os-tmpdir "~1.0.2" 941 | 942 | ts-node@^8.3.0: 943 | version "8.3.0" 944 | resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-8.3.0.tgz#e4059618411371924a1fb5f3b125915f324efb57" 945 | integrity sha512-dyNS/RqyVTDcmNM4NIBAeDMpsAdaQ+ojdf0GOLqE6nwJOgzEkdRNzJywhDfwnuvB10oa6NLVG1rUJQCpRN7qoQ== 946 | dependencies: 947 | arg "^4.1.0" 948 | diff "^4.0.1" 949 | make-error "^1.1.1" 950 | source-map-support "^0.5.6" 951 | yn "^3.0.0" 952 | 953 | tslib@^1.8.1, tslib@^1.9.0: 954 | version "1.10.0" 955 | resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a" 956 | integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ== 957 | 958 | tsutils@^3.7.0: 959 | version "3.14.0" 960 | resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.14.0.tgz#bf8d5a7bae5369331fa0f2b0a5a10bd7f7396c77" 961 | integrity sha512-SmzGbB0l+8I0QwsPgjooFRaRvHLBLNYM8SeQ0k6rtNDru5sCGeLJcZdwilNndN+GysuFjF5EIYgN8GfFG6UeUw== 962 | dependencies: 963 | tslib "^1.8.1" 964 | 965 | type-check@~0.3.2: 966 | version "0.3.2" 967 | resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" 968 | integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= 969 | dependencies: 970 | prelude-ls "~1.1.2" 971 | 972 | typescript@^3.5.2: 973 | version "3.5.2" 974 | resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.5.2.tgz#a09e1dc69bc9551cadf17dba10ee42cf55e5d56c" 975 | integrity sha512-7KxJovlYhTX5RaRbUdkAXN1KUZ8PwWlTzQdHV6xNqvuFOs7+WBo10TQUqT19Q/Jz2hk5v9TQDIhyLhhJY4p5AA== 976 | 977 | uri-js@^4.2.2: 978 | version "4.2.2" 979 | resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" 980 | integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ== 981 | dependencies: 982 | punycode "^2.1.0" 983 | 984 | url@0.10.3: 985 | version "0.10.3" 986 | resolved "https://registry.yarnpkg.com/url/-/url-0.10.3.tgz#021e4d9c7705f21bbf37d03ceb58767402774c64" 987 | integrity sha1-Ah5NnHcF8hu/N9A861h2dAJ3TGQ= 988 | dependencies: 989 | punycode "1.3.2" 990 | querystring "0.2.0" 991 | 992 | uuid@3.3.2: 993 | version "3.3.2" 994 | resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" 995 | integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA== 996 | 997 | which@^1.2.9: 998 | version "1.3.1" 999 | resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" 1000 | integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== 1001 | dependencies: 1002 | isexe "^2.0.0" 1003 | 1004 | wordwrap@~1.0.0: 1005 | version "1.0.0" 1006 | resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" 1007 | integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= 1008 | 1009 | wrappy@1: 1010 | version "1.0.2" 1011 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 1012 | integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= 1013 | 1014 | write@1.0.3: 1015 | version "1.0.3" 1016 | resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3" 1017 | integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig== 1018 | dependencies: 1019 | mkdirp "^0.5.1" 1020 | 1021 | xml2js@0.4.19: 1022 | version "0.4.19" 1023 | resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.19.tgz#686c20f213209e94abf0d1bcf1efaa291c7827a7" 1024 | integrity sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q== 1025 | dependencies: 1026 | sax ">=0.6.0" 1027 | xmlbuilder "~9.0.1" 1028 | 1029 | xmlbuilder@~9.0.1: 1030 | version "9.0.7" 1031 | resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.7.tgz#132ee63d2ec5565c557e20f4c22df9aca686b10d" 1032 | integrity sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0= 1033 | 1034 | yn@^3.0.0: 1035 | version "3.1.0" 1036 | resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.0.tgz#fcbe2db63610361afcc5eb9e0ac91e976d046114" 1037 | integrity sha512-kKfnnYkbTfrAdd0xICNFw7Atm8nKpLcLv9AZGEt+kczL/WQVai4e2V6ZN8U/O+iI6WrNuJjNNOyu4zfhl9D3Hg== 1038 | --------------------------------------------------------------------------------