diff --git a/.circleci/config.base.yml b/.circleci/config.base.yml index a9e95848236..ba8da8491b7 100644 --- a/.circleci/config.base.yml +++ b/.circleci/config.base.yml @@ -17,10 +17,7 @@ node12: &node12 defaults: &defaults working_directory: ~/repo docker: - - image: ${AWS_ECR_ACCOUNT_URL}/amplify-cli-e2e-base-image-repo:latest - aws_auth: - aws_access_key_id: $ECR_ACCESS_KEY - aws_secret_access_key: $ECR_SECRET_ACCESS_KEY + - image: ${AWS_ECR_ACCOUNT_URL}/amplify-cli-e2e-base-image-repo-public:latest resource_class: large clean_e2e_resources: &clean_e2e_resources @@ -526,7 +523,7 @@ jobs: path: /root/aws-amplify-cypress-api/cypress/screenshots deploy: - <<: *defaults + <<: *node12 steps: - attach_workspace: at: ./ @@ -539,13 +536,7 @@ jobs: - run: name: Publish Amplify CLI command: | - if [ -z "$CIRCLE_PULL_REQUEST" ]; then - git config --global user.email $GITHUB_EMAIL - git config --global user.name $GITHUB_USER - npm run publish:$CIRCLE_BRANCH - else - echo "Skipping deploy." - fi + bash ./.circleci/publish.sh - run: *scan_e2e_test_artifacts github_prerelease: <<: *node12 @@ -694,8 +685,8 @@ workflows: branches: only: - master - - func-env-vars-secrets - - iterative-update + - /tagged-release\/.*/ + - /run-e2e\/*./ requires: - build - mock_e2e_tests @@ -707,8 +698,9 @@ workflows: branches: only: - master - - func-env-vars-secrets - beta + - /tagged-release\/.*/ + - /run-e2e\/*./ requires: - build - mock_e2e_tests @@ -717,12 +709,10 @@ workflows: branches: only: - master - - func-env-vars-secrets - beta - - backendManager - - iterative-update - release - - compute-functions + - /tagged-release\/.*/ + - /run-e2e\/*./ requires: - build - build_pkg_binaries: @@ -736,6 +726,8 @@ workflows: branches: only: - master + - /tagged-release\/.*/ + - /run-e2e\/*./ - amplify_e2e_tests: context: - amplify-ecr-image-pull @@ -748,9 +740,8 @@ workflows: branches: only: - master - - func-env-vars-secrets - - compute-functions - - iterative-update + - /tagged-release\/.*/ + - /run-e2e\/*./ requires: - publish_to_local_registry - done_with_node_e2e_tests: @@ -768,6 +759,8 @@ workflows: branches: only: - master + - /tagged-release\/.*/ + - /run-e2e\/*./ requires: - done_with_node_e2e_tests - build_pkg_binaries @@ -784,6 +777,8 @@ workflows: branches: only: - master + - /tagged-release\/.*/ + - /run-e2e\/*./ requires: - build - amplify_migration_tests_v4: @@ -796,7 +791,8 @@ workflows: branches: only: - master - - func-env-vars-secrets + - /tagged-release\/.*/ + - /run-e2e\/*./ requires: - build - amplify_migration_tests_v4_30_0: @@ -809,10 +805,8 @@ workflows: branches: only: - master - - func-env-vars-secrets - - graphqlschemae2e - - feat-import - - test-fix-status + - /tagged-release\/.*/ + - /run-e2e\/*./ requires: - build - amplify_migration_tests_non_multi_env_layers: @@ -825,7 +819,8 @@ workflows: branches: only: - master - - func-env-vars-secrets + - /tagged-release\/.*/ + - /run-e2e\/*./ requires: - build - amplify_migration_tests_multi_env_layers: @@ -838,7 +833,8 @@ workflows: branches: only: - master - - func-env-vars-secrets + - /tagged-release\/.*/ + - /run-e2e\/*./ requires: - build - amplify_console_integration_tests: @@ -892,6 +888,11 @@ workflows: filters: branches: only: + - release + - master + - beta + - /tagged-release\/.*/ + - /tagged-release-without-e2e-tests\/.*/ - ext - github_release: context: github-publish @@ -901,3 +902,4 @@ workflows: branches: only: - release + diff --git a/.circleci/config.yml b/.circleci/config.yml index 4633f98010a..5a941ef201a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -16,10 +16,7 @@ node12: defaults: working_directory: ~/repo docker: &ref_1 - - image: ${AWS_ECR_ACCOUNT_URL}/amplify-cli-e2e-base-image-repo:latest - aws_auth: - aws_access_key_id: $ECR_ACCESS_KEY - aws_secret_access_key: $ECR_SECRET_ACCESS_KEY + - image: ${AWS_ECR_ACCOUNT_URL}/amplify-cli-e2e-base-image-repo-public:latest resource_class: large clean_e2e_resources: &ref_7 name: Cleanup resources @@ -549,7 +546,7 @@ jobs: path: /root/aws-amplify-cypress-api/cypress/screenshots deploy: working_directory: ~/repo - docker: *ref_1 + docker: *ref_0 resource_class: large steps: - attach_workspace: @@ -563,13 +560,7 @@ jobs: - run: name: Publish Amplify CLI command: | - if [ -z "$CIRCLE_PULL_REQUEST" ]; then - git config --global user.email $GITHUB_EMAIL - git config --global user.name $GITHUB_USER - npm run publish:$CIRCLE_BRANCH - else - echo "Skipping deploy." - fi + bash ./.circleci/publish.sh - run: *ref_4 github_prerelease: working_directory: ~/repo @@ -1188,6 +1179,14 @@ jobs: environment: TEST_SUITE: src/__tests__/s3-sse.test.ts CLI_REGION: us-west-2 + pull-amplify_e2e_tests: + working_directory: ~/repo + docker: *ref_1 + resource_class: large + steps: *ref_5 + environment: + TEST_SUITE: src/__tests__/pull.test.ts + CLI_REGION: eu-west-2 migration-node-function-amplify_e2e_tests: working_directory: ~/repo docker: *ref_1 @@ -1195,7 +1194,7 @@ jobs: steps: *ref_5 environment: TEST_SUITE: src/__tests__/migration/node.function.test.ts - CLI_REGION: eu-west-2 + CLI_REGION: eu-central-1 layer-2-amplify_e2e_tests: working_directory: ~/repo docker: *ref_1 @@ -1203,7 +1202,7 @@ jobs: steps: *ref_5 environment: TEST_SUITE: src/__tests__/layer-2.test.ts - CLI_REGION: eu-central-1 + CLI_REGION: ap-northeast-1 iam-permissions-boundary-amplify_e2e_tests: working_directory: ~/repo docker: *ref_1 @@ -1211,7 +1210,7 @@ jobs: steps: *ref_5 environment: TEST_SUITE: src/__tests__/iam-permissions-boundary.test.ts - CLI_REGION: ap-northeast-1 + CLI_REGION: ap-southeast-1 function_7-amplify_e2e_tests: working_directory: ~/repo docker: *ref_1 @@ -1219,7 +1218,7 @@ jobs: steps: *ref_5 environment: TEST_SUITE: src/__tests__/function_7.test.ts - CLI_REGION: ap-southeast-1 + CLI_REGION: ap-southeast-2 function_6-amplify_e2e_tests: working_directory: ~/repo docker: *ref_1 @@ -1227,7 +1226,7 @@ jobs: steps: *ref_5 environment: TEST_SUITE: src/__tests__/function_6.test.ts - CLI_REGION: ap-southeast-2 + CLI_REGION: us-east-2 function_5-amplify_e2e_tests: working_directory: ~/repo docker: *ref_1 @@ -1235,7 +1234,7 @@ jobs: steps: *ref_5 environment: TEST_SUITE: src/__tests__/function_5.test.ts - CLI_REGION: us-east-2 + CLI_REGION: us-west-2 frontend_config_drift-amplify_e2e_tests: working_directory: ~/repo docker: *ref_1 @@ -1243,7 +1242,15 @@ jobs: steps: *ref_5 environment: TEST_SUITE: src/__tests__/frontend_config_drift.test.ts - CLI_REGION: us-west-2 + CLI_REGION: eu-west-2 + container-hosting-amplify_e2e_tests: + working_directory: ~/repo + docker: *ref_1 + resource_class: large + steps: *ref_5 + environment: + TEST_SUITE: src/__tests__/container-hosting.test.ts + CLI_REGION: eu-central-1 configure-project-amplify_e2e_tests: working_directory: ~/repo docker: *ref_1 @@ -1251,7 +1258,15 @@ jobs: steps: *ref_5 environment: TEST_SUITE: src/__tests__/configure-project.test.ts - CLI_REGION: eu-west-2 + CLI_REGION: ap-northeast-1 + auth_6-amplify_e2e_tests: + working_directory: ~/repo + docker: *ref_1 + resource_class: large + steps: *ref_5 + environment: + TEST_SUITE: src/__tests__/auth_6.test.ts + CLI_REGION: ap-southeast-1 api_4-amplify_e2e_tests: working_directory: ~/repo docker: *ref_1 @@ -1259,7 +1274,7 @@ jobs: steps: *ref_5 environment: TEST_SUITE: src/__tests__/api_4.test.ts - CLI_REGION: eu-central-1 + CLI_REGION: ap-southeast-2 schema-iterative-update-4-amplify_e2e_tests_pkg_linux: working_directory: ~/repo docker: *ref_1 @@ -1910,6 +1925,16 @@ jobs: TEST_SUITE: src/__tests__/s3-sse.test.ts CLI_REGION: us-west-2 steps: *ref_6 + pull-amplify_e2e_tests_pkg_linux: + working_directory: ~/repo + docker: *ref_1 + resource_class: large + environment: + AMPLIFY_DIR: /home/circleci/repo/out + AMPLIFY_PATH: /home/circleci/repo/out/amplify-pkg-linux + TEST_SUITE: src/__tests__/pull.test.ts + CLI_REGION: eu-west-2 + steps: *ref_6 migration-node-function-amplify_e2e_tests_pkg_linux: working_directory: ~/repo docker: *ref_1 @@ -1918,7 +1943,7 @@ jobs: AMPLIFY_DIR: /home/circleci/repo/out AMPLIFY_PATH: /home/circleci/repo/out/amplify-pkg-linux TEST_SUITE: src/__tests__/migration/node.function.test.ts - CLI_REGION: eu-west-2 + CLI_REGION: eu-central-1 steps: *ref_6 layer-2-amplify_e2e_tests_pkg_linux: working_directory: ~/repo @@ -1928,7 +1953,7 @@ jobs: AMPLIFY_DIR: /home/circleci/repo/out AMPLIFY_PATH: /home/circleci/repo/out/amplify-pkg-linux TEST_SUITE: src/__tests__/layer-2.test.ts - CLI_REGION: eu-central-1 + CLI_REGION: ap-northeast-1 steps: *ref_6 iam-permissions-boundary-amplify_e2e_tests_pkg_linux: working_directory: ~/repo @@ -1938,7 +1963,7 @@ jobs: AMPLIFY_DIR: /home/circleci/repo/out AMPLIFY_PATH: /home/circleci/repo/out/amplify-pkg-linux TEST_SUITE: src/__tests__/iam-permissions-boundary.test.ts - CLI_REGION: ap-northeast-1 + CLI_REGION: ap-southeast-1 steps: *ref_6 function_7-amplify_e2e_tests_pkg_linux: working_directory: ~/repo @@ -1948,7 +1973,7 @@ jobs: AMPLIFY_DIR: /home/circleci/repo/out AMPLIFY_PATH: /home/circleci/repo/out/amplify-pkg-linux TEST_SUITE: src/__tests__/function_7.test.ts - CLI_REGION: ap-southeast-1 + CLI_REGION: ap-southeast-2 steps: *ref_6 function_6-amplify_e2e_tests_pkg_linux: working_directory: ~/repo @@ -1958,7 +1983,7 @@ jobs: AMPLIFY_DIR: /home/circleci/repo/out AMPLIFY_PATH: /home/circleci/repo/out/amplify-pkg-linux TEST_SUITE: src/__tests__/function_6.test.ts - CLI_REGION: ap-southeast-2 + CLI_REGION: us-east-2 steps: *ref_6 function_5-amplify_e2e_tests_pkg_linux: working_directory: ~/repo @@ -1968,7 +1993,7 @@ jobs: AMPLIFY_DIR: /home/circleci/repo/out AMPLIFY_PATH: /home/circleci/repo/out/amplify-pkg-linux TEST_SUITE: src/__tests__/function_5.test.ts - CLI_REGION: us-east-2 + CLI_REGION: us-west-2 steps: *ref_6 frontend_config_drift-amplify_e2e_tests_pkg_linux: working_directory: ~/repo @@ -1978,7 +2003,17 @@ jobs: AMPLIFY_DIR: /home/circleci/repo/out AMPLIFY_PATH: /home/circleci/repo/out/amplify-pkg-linux TEST_SUITE: src/__tests__/frontend_config_drift.test.ts - CLI_REGION: us-west-2 + CLI_REGION: eu-west-2 + steps: *ref_6 + container-hosting-amplify_e2e_tests_pkg_linux: + working_directory: ~/repo + docker: *ref_1 + resource_class: large + environment: + AMPLIFY_DIR: /home/circleci/repo/out + AMPLIFY_PATH: /home/circleci/repo/out/amplify-pkg-linux + TEST_SUITE: src/__tests__/container-hosting.test.ts + CLI_REGION: eu-central-1 steps: *ref_6 configure-project-amplify_e2e_tests_pkg_linux: working_directory: ~/repo @@ -1988,7 +2023,17 @@ jobs: AMPLIFY_DIR: /home/circleci/repo/out AMPLIFY_PATH: /home/circleci/repo/out/amplify-pkg-linux TEST_SUITE: src/__tests__/configure-project.test.ts - CLI_REGION: eu-west-2 + CLI_REGION: ap-northeast-1 + steps: *ref_6 + auth_6-amplify_e2e_tests_pkg_linux: + working_directory: ~/repo + docker: *ref_1 + resource_class: large + environment: + AMPLIFY_DIR: /home/circleci/repo/out + AMPLIFY_PATH: /home/circleci/repo/out/amplify-pkg-linux + TEST_SUITE: src/__tests__/auth_6.test.ts + CLI_REGION: ap-southeast-1 steps: *ref_6 api_4-amplify_e2e_tests_pkg_linux: working_directory: ~/repo @@ -1998,7 +2043,7 @@ jobs: AMPLIFY_DIR: /home/circleci/repo/out AMPLIFY_PATH: /home/circleci/repo/out/amplify-pkg-linux TEST_SUITE: src/__tests__/api_4.test.ts - CLI_REGION: eu-central-1 + CLI_REGION: ap-southeast-2 steps: *ref_6 workflows: version: 2 @@ -2057,8 +2102,8 @@ workflows: branches: only: - master - - func-env-vars-secrets - - iterative-update + - /tagged-release\/.*/ + - /run-e2e\/*./ requires: - build - mock_e2e_tests @@ -2070,8 +2115,9 @@ workflows: branches: only: - master - - func-env-vars-secrets - beta + - /tagged-release\/.*/ + - /run-e2e\/*./ requires: - build - mock_e2e_tests @@ -2080,12 +2126,10 @@ workflows: branches: only: - master - - func-env-vars-secrets - beta - - backendManager - - iterative-update - release - - compute-functions + - /tagged-release\/.*/ + - /run-e2e\/*./ requires: - build - build_pkg_binaries: @@ -2099,66 +2143,68 @@ workflows: branches: only: - master + - /tagged-release\/.*/ + - /run-e2e\/*./ - done_with_node_e2e_tests: requires: - analytics-amplify_e2e_tests - notifications-amplify_e2e_tests - schema-iterative-update-locking-amplify_e2e_tests - - function_5-amplify_e2e_tests + - function_6-amplify_e2e_tests - hosting-amplify_e2e_tests - tags-amplify_e2e_tests - s3-sse-amplify_e2e_tests - - frontend_config_drift-amplify_e2e_tests + - function_5-amplify_e2e_tests - amplify-app-amplify_e2e_tests - init-amplify_e2e_tests - - migration-node-function-amplify_e2e_tests - - configure-project-amplify_e2e_tests + - pull-amplify_e2e_tests + - frontend_config_drift-amplify_e2e_tests - schema-predictions-amplify_e2e_tests - amplify-configure-amplify_e2e_tests - - layer-2-amplify_e2e_tests - - api_4-amplify_e2e_tests - - containers-api-amplify_e2e_tests + - migration-node-function-amplify_e2e_tests + - container-hosting-amplify_e2e_tests - interactions-amplify_e2e_tests - datastore-modelgen-amplify_e2e_tests - - iam-permissions-boundary-amplify_e2e_tests - - schema-iterative-update-2-amplify_e2e_tests + - layer-2-amplify_e2e_tests + - configure-project-amplify_e2e_tests - schema-data-access-patterns-amplify_e2e_tests - init-special-case-amplify_e2e_tests - - function_7-amplify_e2e_tests - - feature-flags-amplify_e2e_tests + - iam-permissions-boundary-amplify_e2e_tests + - auth_6-amplify_e2e_tests - schema-versioned-amplify_e2e_tests - plugin-amplify_e2e_tests - - function_6-amplify_e2e_tests + - function_7-amplify_e2e_tests + - api_4-amplify_e2e_tests - done_with_pkg_linux_e2e_tests: requires: - analytics-amplify_e2e_tests_pkg_linux - notifications-amplify_e2e_tests_pkg_linux - schema-iterative-update-locking-amplify_e2e_tests_pkg_linux - - function_5-amplify_e2e_tests_pkg_linux + - function_6-amplify_e2e_tests_pkg_linux - hosting-amplify_e2e_tests_pkg_linux - tags-amplify_e2e_tests_pkg_linux - s3-sse-amplify_e2e_tests_pkg_linux - - frontend_config_drift-amplify_e2e_tests_pkg_linux + - function_5-amplify_e2e_tests_pkg_linux - amplify-app-amplify_e2e_tests_pkg_linux - init-amplify_e2e_tests_pkg_linux - - migration-node-function-amplify_e2e_tests_pkg_linux - - configure-project-amplify_e2e_tests_pkg_linux + - pull-amplify_e2e_tests_pkg_linux + - frontend_config_drift-amplify_e2e_tests_pkg_linux - schema-predictions-amplify_e2e_tests_pkg_linux - amplify-configure-amplify_e2e_tests_pkg_linux - - layer-2-amplify_e2e_tests_pkg_linux - - api_4-amplify_e2e_tests_pkg_linux - - containers-api-amplify_e2e_tests_pkg_linux + - migration-node-function-amplify_e2e_tests_pkg_linux + - container-hosting-amplify_e2e_tests_pkg_linux - interactions-amplify_e2e_tests_pkg_linux - datastore-modelgen-amplify_e2e_tests_pkg_linux - - iam-permissions-boundary-amplify_e2e_tests_pkg_linux - - schema-iterative-update-2-amplify_e2e_tests_pkg_linux + - layer-2-amplify_e2e_tests_pkg_linux + - configure-project-amplify_e2e_tests_pkg_linux - schema-data-access-patterns-amplify_e2e_tests_pkg_linux - init-special-case-amplify_e2e_tests_pkg_linux - - function_7-amplify_e2e_tests_pkg_linux - - feature-flags-amplify_e2e_tests_pkg_linux + - iam-permissions-boundary-amplify_e2e_tests_pkg_linux + - auth_6-amplify_e2e_tests_pkg_linux - schema-versioned-amplify_e2e_tests_pkg_linux - plugin-amplify_e2e_tests_pkg_linux - - function_6-amplify_e2e_tests_pkg_linux + - function_7-amplify_e2e_tests_pkg_linux + - api_4-amplify_e2e_tests_pkg_linux - amplify_migration_tests_latest: context: - amplify-ecr-image-pull @@ -2169,6 +2215,8 @@ workflows: branches: only: - master + - /tagged-release\/.*/ + - /run-e2e\/*./ requires: - build - amplify_migration_tests_v4: @@ -2181,7 +2229,8 @@ workflows: branches: only: - master - - func-env-vars-secrets + - /tagged-release\/.*/ + - /run-e2e\/*./ requires: - build - amplify_migration_tests_v4_30_0: @@ -2194,10 +2243,8 @@ workflows: branches: only: - master - - func-env-vars-secrets - - graphqlschemae2e - - feat-import - - test-fix-status + - /tagged-release\/.*/ + - /run-e2e\/*./ requires: - build - amplify_migration_tests_non_multi_env_layers: @@ -2210,7 +2257,8 @@ workflows: branches: only: - master - - func-env-vars-secrets + - /tagged-release\/.*/ + - /run-e2e\/*./ requires: - build - amplify_migration_tests_multi_env_layers: @@ -2223,7 +2271,8 @@ workflows: branches: only: - master - - func-env-vars-secrets + - /tagged-release\/.*/ + - /run-e2e\/*./ requires: - build - amplify_console_integration_tests: @@ -2276,6 +2325,11 @@ workflows: filters: branches: only: + - release + - master + - beta + - /tagged-release\/.*/ + - /tagged-release-without-e2e-tests\/.*/ - ext - github_release: context: github-publish @@ -2297,9 +2351,8 @@ workflows: branches: only: - master - - func-env-vars-secrets - - compute-functions - - iterative-update + - /tagged-release\/.*/ + - /run-e2e\/*./ requires: - publish_to_local_registry - schema-auth-6-amplify_e2e_tests: @@ -2356,7 +2409,7 @@ workflows: filters: *ref_10 requires: - function_2-amplify_e2e_tests - - function_5-amplify_e2e_tests: + - function_6-amplify_e2e_tests: context: *ref_8 post-steps: *ref_9 filters: *ref_10 @@ -2422,7 +2475,7 @@ workflows: filters: *ref_10 requires: - delete-amplify_e2e_tests - - frontend_config_drift-amplify_e2e_tests: + - function_5-amplify_e2e_tests: context: *ref_8 post-steps: *ref_9 filters: *ref_10 @@ -2482,13 +2535,13 @@ workflows: filters: *ref_10 requires: - schema-auth-7-amplify_e2e_tests - - migration-node-function-amplify_e2e_tests: + - pull-amplify_e2e_tests: context: *ref_8 post-steps: *ref_9 filters: *ref_10 requires: - schema-auth-3-amplify_e2e_tests - - configure-project-amplify_e2e_tests: + - frontend_config_drift-amplify_e2e_tests: context: *ref_8 post-steps: *ref_9 filters: *ref_10 @@ -2548,13 +2601,13 @@ workflows: filters: *ref_10 requires: - auth_4-amplify_e2e_tests - - layer-2-amplify_e2e_tests: + - migration-node-function-amplify_e2e_tests: context: *ref_8 post-steps: *ref_9 filters: *ref_10 requires: - schema-iterative-update-1-amplify_e2e_tests - - api_4-amplify_e2e_tests: + - container-hosting-amplify_e2e_tests: context: *ref_8 post-steps: *ref_9 filters: *ref_10 @@ -2614,12 +2667,18 @@ workflows: filters: *ref_10 requires: - migration-api-key-migration1-amplify_e2e_tests - - iam-permissions-boundary-amplify_e2e_tests: + - layer-2-amplify_e2e_tests: context: *ref_8 post-steps: *ref_9 filters: *ref_10 requires: - function_3-amplify_e2e_tests + - configure-project-amplify_e2e_tests: + context: *ref_8 + post-steps: *ref_9 + filters: *ref_10 + requires: + - containers-api-amplify_e2e_tests - schema-auth-2-amplify_e2e_tests: context: *ref_8 post-steps: *ref_9 @@ -2674,12 +2733,18 @@ workflows: filters: *ref_10 requires: - layer-amplify_e2e_tests - - function_7-amplify_e2e_tests: + - iam-permissions-boundary-amplify_e2e_tests: context: *ref_8 post-steps: *ref_9 filters: *ref_10 requires: - auth_5-amplify_e2e_tests + - auth_6-amplify_e2e_tests: + context: *ref_8 + post-steps: *ref_9 + filters: *ref_10 + requires: + - schema-iterative-update-2-amplify_e2e_tests - schema-iterative-update-3-amplify_e2e_tests: context: *ref_8 post-steps: *ref_9 @@ -2734,12 +2799,18 @@ workflows: filters: *ref_10 requires: - auth_3-amplify_e2e_tests - - function_6-amplify_e2e_tests: + - function_7-amplify_e2e_tests: context: *ref_8 post-steps: *ref_9 filters: *ref_10 requires: - auth_1-amplify_e2e_tests + - api_4-amplify_e2e_tests: + context: *ref_8 + post-steps: *ref_9 + filters: *ref_10 + requires: + - feature-flags-amplify_e2e_tests - schema-iterative-update-4-amplify_e2e_tests_pkg_linux: context: &ref_11 - amplify-ecr-image-pull @@ -2752,6 +2823,8 @@ workflows: branches: only: - master + - /tagged-release\/.*/ + - /run-e2e\/*./ requires: - done_with_node_e2e_tests - build_pkg_binaries @@ -2812,7 +2885,7 @@ workflows: filters: *ref_13 requires: - function_2-amplify_e2e_tests_pkg_linux - - function_5-amplify_e2e_tests_pkg_linux: + - function_6-amplify_e2e_tests_pkg_linux: context: *ref_11 post-steps: *ref_12 filters: *ref_13 @@ -2882,7 +2955,7 @@ workflows: filters: *ref_13 requires: - delete-amplify_e2e_tests_pkg_linux - - frontend_config_drift-amplify_e2e_tests_pkg_linux: + - function_5-amplify_e2e_tests_pkg_linux: context: *ref_11 post-steps: *ref_12 filters: *ref_13 @@ -2946,13 +3019,13 @@ workflows: filters: *ref_13 requires: - schema-auth-7-amplify_e2e_tests_pkg_linux - - migration-node-function-amplify_e2e_tests_pkg_linux: + - pull-amplify_e2e_tests_pkg_linux: context: *ref_11 post-steps: *ref_12 filters: *ref_13 requires: - schema-auth-3-amplify_e2e_tests_pkg_linux - - configure-project-amplify_e2e_tests_pkg_linux: + - frontend_config_drift-amplify_e2e_tests_pkg_linux: context: *ref_11 post-steps: *ref_12 filters: *ref_13 @@ -3016,13 +3089,13 @@ workflows: filters: *ref_13 requires: - auth_4-amplify_e2e_tests_pkg_linux - - layer-2-amplify_e2e_tests_pkg_linux: + - migration-node-function-amplify_e2e_tests_pkg_linux: context: *ref_11 post-steps: *ref_12 filters: *ref_13 requires: - schema-iterative-update-1-amplify_e2e_tests_pkg_linux - - api_4-amplify_e2e_tests_pkg_linux: + - container-hosting-amplify_e2e_tests_pkg_linux: context: *ref_11 post-steps: *ref_12 filters: *ref_13 @@ -3086,12 +3159,18 @@ workflows: filters: *ref_13 requires: - migration-api-key-migration1-amplify_e2e_tests_pkg_linux - - iam-permissions-boundary-amplify_e2e_tests_pkg_linux: + - layer-2-amplify_e2e_tests_pkg_linux: context: *ref_11 post-steps: *ref_12 filters: *ref_13 requires: - function_3-amplify_e2e_tests_pkg_linux + - configure-project-amplify_e2e_tests_pkg_linux: + context: *ref_11 + post-steps: *ref_12 + filters: *ref_13 + requires: + - containers-api-amplify_e2e_tests_pkg_linux - schema-auth-2-amplify_e2e_tests_pkg_linux: context: *ref_11 post-steps: *ref_12 @@ -3150,12 +3229,18 @@ workflows: filters: *ref_13 requires: - layer-amplify_e2e_tests_pkg_linux - - function_7-amplify_e2e_tests_pkg_linux: + - iam-permissions-boundary-amplify_e2e_tests_pkg_linux: context: *ref_11 post-steps: *ref_12 filters: *ref_13 requires: - auth_5-amplify_e2e_tests_pkg_linux + - auth_6-amplify_e2e_tests_pkg_linux: + context: *ref_11 + post-steps: *ref_12 + filters: *ref_13 + requires: + - schema-iterative-update-2-amplify_e2e_tests_pkg_linux - schema-iterative-update-3-amplify_e2e_tests_pkg_linux: context: *ref_11 post-steps: *ref_12 @@ -3214,9 +3299,15 @@ workflows: filters: *ref_13 requires: - auth_3-amplify_e2e_tests_pkg_linux - - function_6-amplify_e2e_tests_pkg_linux: + - function_7-amplify_e2e_tests_pkg_linux: context: *ref_11 post-steps: *ref_12 filters: *ref_13 requires: - auth_1-amplify_e2e_tests_pkg_linux + - api_4-amplify_e2e_tests_pkg_linux: + context: *ref_11 + post-steps: *ref_12 + filters: *ref_13 + requires: + - feature-flags-amplify_e2e_tests_pkg_linux diff --git a/.circleci/publish.sh b/.circleci/publish.sh new file mode 100755 index 00000000000..326034d76d8 --- /dev/null +++ b/.circleci/publish.sh @@ -0,0 +1,24 @@ +#!/bin/bash -e +if [ -z "$CIRCLE_PULL_REQUEST" ]; then + git config --global user.email $GITHUB_EMAIL + git config --global user.name $GITHUB_USER + if [[ "$CIRCLE_BRANCH" =~ ^tagged-release ]]; then + if [[ "$CIRCLE_BRANCH" =~ ^tagged-release-without-e2e-tests\/.* ]]; then + # Remove tagged-release-without-e2e-tests/ + export NPM_TAG="${CIRCLE_BRANCH/tagged-release-without-e2e-tests\//}" + elif [[ "$CIRCLE_BRANCH" =~ ^tagged-release\/.* ]]; then + # Remove tagged-release/ + export NPM_TAG="${CIRCLE_BRANCH/tagged-release\//}" + fi + if [ -z "$NPM_TAG" ]; then + echo "Tag name is missing. Name your branch with either tagged-release/ or tagged-release-without-e2e-tests/" + exit 1 + fi + echo "Publishing to NPM with tag $NPM_TAG" + yarn publish:tag + else + yarn publish:$CIRCLE_BRANCH + fi +else + echo "Skipping deploy." +fi \ No newline at end of file diff --git a/.eslintrc.js b/.eslintrc.js index 14884ff52b1..16063b8f8e8 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -308,6 +308,7 @@ module.exports = { '/packages/amplify-graphql-types-generator/lib', '/packages/amplify-headless-interface/lib', '/packages/amplify-migration-tests/lib', + '/packages/amplify-prompts/lib', '/packages/amplify-provider-awscloudformation/lib', '/packages/amplify-storage-simulator/lib', '/packages/amplify-ui-tests/lib', diff --git a/.github/stale.yml b/.github/stale.yml deleted file mode 100644 index 8ba17ec7d1b..00000000000 --- a/.github/stale.yml +++ /dev/null @@ -1,21 +0,0 @@ -only: issues -daysUntilStale: 30 -daysUntilClose: 7 -exemptLabels: - - bug - - critical-bug - - documentation - - enhancement - - feature-request - - pinned - - question - - RFC - - security -staleLabel: pending-close-response-required -markComment: > - This issue has been automatically marked as stale because it has not had - recent activity. It will be closed if no further activity occurs. Thank you - for your contributions. -closeComment: > - This issue has been automatically closed because of inactivity. - Please open a new issue if you are still encountering problems. diff --git a/.gitignore b/.gitignore index 4a58ea74193..ea1ba60ffb9 100644 --- a/.gitignore +++ b/.gitignore @@ -42,6 +42,7 @@ packages/amplify-migration-tests/amplify-migration-reports packages/amplify-migration-tests/lib packages/amplify-headless-interface/lib packages/amplify-provider-awscloudformation/lib +packages/amplify-prompts/lib packages/amplify-util-import/lib packages/amplify-util-headless-input/lib packages/*/node_modules diff --git a/Readme.md b/Readme.md index a0611ff40b9..32c5cae7523 100644 --- a/Readme.md +++ b/Readme.md @@ -64,7 +64,8 @@ The Amplify CLI supports the commands shown in the following table. | amplify push [--no-gql-override] | Provisions cloud resources with the latest local developments. The 'no-gql-override' flag does not automatically compile your annotated GraphQL schema and will override your local AppSync resolvers and templates. | | amplify pull | Fetch upstream backend environment definition changes from the cloud and updates the local environment to match that definition. | | amplify publish | Runs `amplify push`, publishes a static assets to Amazon S3 and Amazon CloudFront (\*hosting category is required). | -| amplify status | Displays the state of local resources that haven't been pushed to the cloud (Create/Update/Delete). | +| amplify status [ ``...] | Displays the state of local resources that haven't been pushed to the cloud (Create/Update/Delete). | +| amplify status -v [ ``...] | Verbose mode - Shows the detailed verbose diff between local and deployed resources, including cloudformation-diff | | amplify serve | Runs `amplify push`, and then executes the project's start command to test run the client-side application. | | amplify delete | Deletes resources tied to the project. | | amplify help \| amplify `` help | Displays help for the core CLI. | diff --git a/jest.config.js b/jest.config.js index 84a5267feba..e8b0bc6d65b 100644 --- a/jest.config.js +++ b/jest.config.js @@ -46,6 +46,8 @@ module.exports = { '/packages/amplify-graphql-docs-generator', '/packages/amplify-graphql-function-transformer', '/packages/amplify-graphql-http-transformer', + '/packages/amplify-graphql-index-transformer', + '/packages/amplify-graphql-model-transformer', '/packages/amplify-graphql-predictions-transformer', '/packages/amplify-graphql-searchable-transformer', '/packages/amplify-graphql-types-generator', diff --git a/package.json b/package.json index 20ca0e09814..3847d3de4ec 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "pkg-all-local": "yarn verdaccio-start && yarn verdaccio-connect && yarn publish-to-verdaccio && yarn pkg-all && yarn verdaccio-disconnect", "publish:master": "lerna publish --canary --force-publish --preid=alpha --exact --include-merged-tags --conventional-prerelease --no-verify-access --yes", "publish:beta": "lerna publish --exact --dist-tag=beta --preid=beta --conventional-commits --conventional-prerelease --message 'chore(release): Publish [ci skip]' --no-verify-access --yes", + "publish:tag": "lerna publish --exact --dist-tag=$NPM_TAG --preid=$NPM_TAG --conventional-commits --conventional-prerelease --message 'chore(release): Publish tagged release $NPM_TAG [ci skip]' --no-verify-access --yes", "publish:ext": "lerna publish --exact --dist-tag=ext --preid=ext --conventional-commits --conventional-prerelease --message 'chore(release): Publish [ci skip]' --no-verify-access --yes", "publish:release": "lerna publish --conventional-commits --exact --yes --message 'chore(release): Publish [ci skip]' --no-verify-access", "postpublish:release": "git fetch . release:master && git push origin master", @@ -66,7 +67,8 @@ "author": "Amazon Web Services", "license": "Apache-2.0", "dependencies": { - "lerna": "^3.16.4" + "strip-ansi": "^6.0.0", + "lerna": "^4.0.0" }, "workspaces": { "packages": [ @@ -120,7 +122,7 @@ "jest-junit": "^12.0.0", "js-yaml": "^4.0.0", "lnk": "1.1.0", - "pkg": "^4.4.9", + "pkg": "^5.3.1", "prettier": "^2.2.1", "prettier-eslint": "^12.0.0", "pretty-quick": "^3.1.0", diff --git a/packages/amplify-app/CHANGELOG.md b/packages/amplify-app/CHANGELOG.md index 6b84a7c092f..78e9e0c1f6e 100644 --- a/packages/amplify-app/CHANGELOG.md +++ b/packages/amplify-app/CHANGELOG.md @@ -3,7 +3,39 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. -## [3.0.3-ext.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-app@3.0.2...amplify-app@3.0.3-ext.0) (2021-07-14) +## [3.0.7](https://github.com/aws-amplify/amplify-cli/compare/amplify-app@3.0.6...amplify-app@3.0.7) (2021-08-06) + +**Note:** Version bump only for package amplify-app + + + + + +## [3.0.6](https://github.com/aws-amplify/amplify-cli/compare/amplify-app@3.0.5...amplify-app@3.0.6) (2021-07-30) + +**Note:** Version bump only for package amplify-app + + + + + +## [3.0.5](https://github.com/aws-amplify/amplify-cli/compare/amplify-app@3.0.4...amplify-app@3.0.5) (2021-07-27) + +**Note:** Version bump only for package amplify-app + + + + + +## [3.0.4](https://github.com/aws-amplify/amplify-cli/compare/amplify-app@3.0.3...amplify-app@3.0.4) (2021-07-16) + +**Note:** Version bump only for package amplify-app + + + + + +## [3.0.3](https://github.com/aws-amplify/amplify-cli/compare/amplify-app@3.0.2...amplify-app@3.0.3) (2021-07-12) **Note:** Version bump only for package amplify-app diff --git a/packages/amplify-app/package.json b/packages/amplify-app/package.json index a75ba19cbc1..cd1a3ce9f4d 100644 --- a/packages/amplify-app/package.json +++ b/packages/amplify-app/package.json @@ -1,6 +1,6 @@ { "name": "amplify-app", - "version": "3.0.3-ext.0", + "version": "3.0.7", "description": "Amplify CLI", "repository": { "type": "git", @@ -28,11 +28,11 @@ "@aws-amplify/cli": ">=5.0.0" }, "dependencies": { - "amplify-frontend-android": "2.15.3", - "amplify-frontend-flutter": "0.4.3", - "amplify-frontend-ios": "2.20.5", - "amplify-frontend-javascript": "2.23.0-ext.0", - "chalk": "^3.0.0", + "amplify-frontend-android": "2.15.4", + "amplify-frontend-flutter": "0.4.4", + "amplify-frontend-ios": "2.20.9", + "amplify-frontend-javascript": "2.23.4", + "chalk": "^4.1.1", "execa": "^4.1.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", diff --git a/packages/amplify-appsync-simulator/CHANGELOG.md b/packages/amplify-appsync-simulator/CHANGELOG.md index 8b015544bdc..7ee2590d832 100644 --- a/packages/amplify-appsync-simulator/CHANGELOG.md +++ b/packages/amplify-appsync-simulator/CHANGELOG.md @@ -3,7 +3,45 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. -## [1.27.2-ext.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-appsync-simulator@1.27.1...amplify-appsync-simulator@1.27.2-ext.0) (2021-07-14) +## [1.27.6](https://github.com/aws-amplify/amplify-cli/compare/amplify-appsync-simulator@1.27.5...amplify-appsync-simulator@1.27.6) (2021-08-06) + +**Note:** Version bump only for package amplify-appsync-simulator + + + + + +## [1.27.5](https://github.com/aws-amplify/amplify-cli/compare/amplify-appsync-simulator@1.27.4...amplify-appsync-simulator@1.27.5) (2021-07-30) + + +### Bug Fixes + +* lambda timeout should be an integer type ([#7699](https://github.com/aws-amplify/amplify-cli/issues/7699)) ([cbacf4d](https://github.com/aws-amplify/amplify-cli/commit/cbacf4d3e497421855c09825970e025550aacfd7)) + + + + + +## [1.27.4](https://github.com/aws-amplify/amplify-cli/compare/amplify-appsync-simulator@1.27.3...amplify-appsync-simulator@1.27.4) (2021-07-27) + +**Note:** Version bump only for package amplify-appsync-simulator + + + + + +## [1.27.3](https://github.com/aws-amplify/amplify-cli/compare/amplify-appsync-simulator@1.27.2...amplify-appsync-simulator@1.27.3) (2021-07-16) + + +### Bug Fixes + +* **amplify-appsync-simulator:** string functions not called on items … ([#7636](https://github.com/aws-amplify/amplify-cli/issues/7636)) ([0027abb](https://github.com/aws-amplify/amplify-cli/commit/0027abb1a8cc18c4ec0bac1ddf0191e37322bbff)) + + + + + +## [1.27.2](https://github.com/aws-amplify/amplify-cli/compare/amplify-appsync-simulator@1.27.1...amplify-appsync-simulator@1.27.2) (2021-07-12) ### Bug Fixes diff --git a/packages/amplify-appsync-simulator/package.json b/packages/amplify-appsync-simulator/package.json index 042fc7f94f9..d8de4ab5c44 100644 --- a/packages/amplify-appsync-simulator/package.json +++ b/packages/amplify-appsync-simulator/package.json @@ -1,6 +1,6 @@ { "name": "amplify-appsync-simulator", - "version": "1.27.2-ext.0", + "version": "1.27.6", "description": "An AppSync Simulator to test AppSync API.", "repository": { "type": "git", @@ -28,7 +28,7 @@ "dependencies": { "amplify-velocity-template": "1.4.5", "aws-sdk": "^2.919.0", - "chalk": "^3.0.0", + "chalk": "^4.1.1", "cors": "^2.8.5", "dataloader": "^2.0.0", "event-to-promise": "^0.8.0", diff --git a/packages/amplify-appsync-simulator/src/__tests__/velocity/util/mock-data.ts b/packages/amplify-appsync-simulator/src/__tests__/velocity/util/mock-data.ts new file mode 100644 index 00000000000..f0a98203d2f --- /dev/null +++ b/packages/amplify-appsync-simulator/src/__tests__/velocity/util/mock-data.ts @@ -0,0 +1,4 @@ +export const mockedInputToRdsJsonString = + '{"sqlStatementResults":[{"numberOfRecordsUpdated":1,"records":[],"columnMetadata":[],"generatedFields":[]},{"numberOfRecordsUpdated":1,"records":[[{"stringValue":80},{"stringValue":"Some note"},{"stringValue":"2021-01-01T00:00:00.000Z"},{"stringValue":1},{"stringValue":"2021-07-02T13:27:27.109Z"},{"stringValue":"2021-07-02T13:27:27.109Z"},{"stringValue":null},{"stringValue":0}]],"columnMetadata":[{"isAutoIncrement":false,"isSigned":true,"label":"id","name":"id","nullable":true,"autoIncrement":false,"tableName":"","arrayBaseColumnType":0,"isCaseSensitive":false,"isCurrency":false,"currency":false,"precision":10,"scale":0,"schemaName":""},{"isAutoIncrement":false,"isSigned":true,"label":"note","name":"note","nullable":true,"autoIncrement":false,"tableName":"","arrayBaseColumnType":0,"isCaseSensitive":false,"isCurrency":false,"currency":false,"precision":10,"scale":0,"schemaName":""},{"isAutoIncrement":false,"isSigned":true,"label":"deadline","name":"deadline","nullable":true,"autoIncrement":false,"tableName":"","arrayBaseColumnType":0,"isCaseSensitive":false,"isCurrency":false,"currency":false,"precision":10,"scale":0,"schemaName":""},{"isAutoIncrement":false,"isSigned":true,"label":"list_id","name":"list_id","nullable":true,"autoIncrement":false,"tableName":"","arrayBaseColumnType":0,"isCaseSensitive":false,"isCurrency":false,"currency":false,"precision":10,"scale":0,"schemaName":""},{"isAutoIncrement":false,"isSigned":true,"label":"created_at","name":"created_at","nullable":true,"autoIncrement":false,"tableName":"","arrayBaseColumnType":0,"isCaseSensitive":false,"isCurrency":false,"currency":false,"precision":10,"scale":0,"schemaName":""},{"isAutoIncrement":false,"isSigned":true,"label":"updated_at","name":"updated_at","nullable":true,"autoIncrement":false,"tableName":"","arrayBaseColumnType":0,"isCaseSensitive":false,"isCurrency":false,"currency":false,"precision":10,"scale":0,"schemaName":""},{"isAutoIncrement":false,"isSigned":true,"label":"deleted_at","name":"deleted_at","nullable":true,"autoIncrement":false,"tableName":"","arrayBaseColumnType":0,"isCaseSensitive":false,"isCurrency":false,"currency":false,"precision":10,"scale":0,"schemaName":""},{"isAutoIncrement":false,"isSigned":true,"label":"done","name":"done","nullable":true,"autoIncrement":false,"tableName":"","arrayBaseColumnType":0,"isCaseSensitive":false,"isCurrency":false,"currency":false,"precision":10,"scale":0,"schemaName":""}],"generatedFields":[]}]}'; +export const mockedOutputFromRdsJsonString = + '[[],[{"id":80,"note":"Some note","deadline":"2021-01-01T00:00:00.000Z","list_id":1,"created_at":"2021-07-02T13:27:27.109Z","updated_at":"2021-07-02T13:27:27.109Z","deleted_at":null,"done":0}]]'; diff --git a/packages/amplify-appsync-simulator/src/__tests__/velocity/util/rds.test.ts b/packages/amplify-appsync-simulator/src/__tests__/velocity/util/rds.test.ts new file mode 100644 index 00000000000..9a6155c20f8 --- /dev/null +++ b/packages/amplify-appsync-simulator/src/__tests__/velocity/util/rds.test.ts @@ -0,0 +1,23 @@ +import { create } from '../../../velocity/util/index'; +import { mockedInputToRdsJsonString, mockedOutputFromRdsJsonString } from './mock-data'; +import { GraphQLResolveInfo } from 'graphql'; + +const stubInfo = {} as unknown; +const mockInfo = stubInfo as GraphQLResolveInfo; +let util; + +beforeEach(() => { + util = create(undefined, undefined, mockInfo); +}); + +describe('$utils.rds.toJsonString', () => { + it('should convert rds object to stringified JSON', () => { + expect(util.rds.toJsonString(mockedInputToRdsJsonString)).toEqual(mockedOutputFromRdsJsonString); + }); + it('handle input without sqlStatementResults input', () => { + expect(util.rds.toJsonString('{}')).toEqual('[]'); + }); + it('handle invalid input', () => { + expect(util.rds.toJsonString('')).toEqual(''); + }); +}); diff --git a/packages/amplify-appsync-simulator/src/__tests__/velocity/value-mapper/map.test.ts b/packages/amplify-appsync-simulator/src/__tests__/velocity/value-mapper/map.test.ts index 2cfbbcb56e9..d71f135f8dd 100644 --- a/packages/amplify-appsync-simulator/src/__tests__/velocity/value-mapper/map.test.ts +++ b/packages/amplify-appsync-simulator/src/__tests__/velocity/value-mapper/map.test.ts @@ -1,4 +1,7 @@ +import { JavaArray } from './../../../velocity/value-mapper/array'; import { JavaMap } from '../../../velocity/value-mapper/map'; +import { JavaString } from '../../../velocity/value-mapper/string'; +import { map as mapper } from '../../../velocity/value-mapper/mapper'; describe('JavaMap', () => { let identityMapper = jest.fn().mockImplementation(val => val); @@ -36,7 +39,10 @@ describe('JavaMap', () => { it('entrySet', () => { const obj = { foo: 'Foo Value', bar: 'Bar Value' }; const map = new JavaMap(obj, identityMapper); - expect(map.entrySet().toJSON()).toEqual([{ key: 'foo', value: 'Foo Value' }, { key: 'bar', value: 'Bar Value' }]); + expect(map.entrySet().toJSON()).toEqual([ + { key: 'foo', value: 'Foo Value' }, + { key: 'bar', value: 'Bar Value' }, + ]); }); it('equal', () => { @@ -66,6 +72,12 @@ describe('JavaMap', () => { expect(map.keySet().toJSON()).toEqual(['foo', 'bar']); }); + it('keySet returns a JavaArray with each element of type JavaString', () => { + const obj = { foo: 'Foo Value', bar: 'Bar Value' }; + const map = new JavaMap(obj, mapper); + expect(map.keySet()).toEqual(new JavaArray([new JavaString('foo'), new JavaString('bar')], mapper)); + }); + it('put', () => { const map = new JavaMap({}, identityMapper); map.put('foo', 'Foo Value'); diff --git a/packages/amplify-appsync-simulator/src/velocity/util/index.ts b/packages/amplify-appsync-simulator/src/velocity/util/index.ts index 45afae09d58..4844ddc1eec 100644 --- a/packages/amplify-appsync-simulator/src/velocity/util/index.ts +++ b/packages/amplify-appsync-simulator/src/velocity/util/index.ts @@ -5,10 +5,10 @@ import { listUtils } from './list-utils'; import { mapUtils } from './map-utils'; import { transformUtils } from './transform'; import { time } from './time'; +import { rds } from './rds'; import { str } from './str'; import { math } from './math'; import { GraphQLResolveInfo } from 'graphql'; - export function create(errors = [], now: Date = new Date(), info: GraphQLResolveInfo) { return { ...generalUtils, @@ -22,5 +22,6 @@ export function create(errors = [], now: Date = new Date(), info: GraphQLResolve time: time(), str, math, + rds, }; } diff --git a/packages/amplify-appsync-simulator/src/velocity/util/rds.ts b/packages/amplify-appsync-simulator/src/velocity/util/rds.ts new file mode 100644 index 00000000000..7d96611dcaa --- /dev/null +++ b/packages/amplify-appsync-simulator/src/velocity/util/rds.ts @@ -0,0 +1,19 @@ +export const rds = { + toJsonString: rdsObject => { + try { + rdsObject = JSON.parse(rdsObject); + const rdsJson = (rdsObject?.sqlStatementResults ?? []).map(statement => + (statement?.records ?? []).map(record => { + const result = {}; + record.forEach((row, index) => { + result[statement?.columnMetadata?.[index]?.name] = Object.values(row)?.[0]; + }); + return result; + }), + ); + return JSON.stringify(rdsJson); + } catch { + return ''; + } + }, +}; diff --git a/packages/amplify-appsync-simulator/src/velocity/value-mapper/map.ts b/packages/amplify-appsync-simulator/src/velocity/value-mapper/map.ts index d075fa022b0..184f91f0d36 100644 --- a/packages/amplify-appsync-simulator/src/velocity/value-mapper/map.ts +++ b/packages/amplify-appsync-simulator/src/velocity/value-mapper/map.ts @@ -56,7 +56,7 @@ export class JavaMap { } keySet() { - return new JavaArray(Array.from(this.map.keys()), this.mapper); + return new JavaArray(Array.from(this.map.keys()).map(this.mapper as any), this.mapper); } put(key, value) { diff --git a/packages/amplify-category-analytics/CHANGELOG.md b/packages/amplify-category-analytics/CHANGELOG.md index c13b9ec0975..278c2ff6d8a 100644 --- a/packages/amplify-category-analytics/CHANGELOG.md +++ b/packages/amplify-category-analytics/CHANGELOG.md @@ -3,6 +3,49 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [2.21.16](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-analytics@2.21.15...amplify-category-analytics@2.21.16) (2021-08-06) + +**Note:** Version bump only for package amplify-category-analytics + + + + + +## [2.21.15](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-analytics@2.21.14...amplify-category-analytics@2.21.15) (2021-07-30) + + +### Bug Fixes + +* lambda timeout should be an integer type ([#7699](https://github.com/aws-amplify/amplify-cli/issues/7699)) ([cbacf4d](https://github.com/aws-amplify/amplify-cli/commit/cbacf4d3e497421855c09825970e025550aacfd7)) + + + + + +## [2.21.14](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-analytics@2.21.13...amplify-category-analytics@2.21.14) (2021-07-27) + + +### Bug Fixes + +* upgrade node default runtime to 14 ([#7700](https://github.com/aws-amplify/amplify-cli/issues/7700)) ([47968cc](https://github.com/aws-amplify/amplify-cli/commit/47968cc9c704ac1cffcbd0dbe40d164b1b1d48d6)) + + +### Reverts + +* Revert "fix: upgrade node default runtime to 14 (#7700)" (#7763) ([3ab8769](https://github.com/aws-amplify/amplify-cli/commit/3ab87694203584cdfa208bf75e648e0e944f5e18)), closes [#7700](https://github.com/aws-amplify/amplify-cli/issues/7700) [#7763](https://github.com/aws-amplify/amplify-cli/issues/7763) + + + + + +## [2.21.13](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-analytics@2.21.12...amplify-category-analytics@2.21.13) (2021-07-16) + +**Note:** Version bump only for package amplify-category-analytics + + + + + ## [2.21.12](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-analytics@2.21.11...amplify-category-analytics@2.21.12) (2021-06-30) **Note:** Version bump only for package amplify-category-analytics diff --git a/packages/amplify-category-analytics/package.json b/packages/amplify-category-analytics/package.json index e0749a09693..08b5fc87951 100644 --- a/packages/amplify-category-analytics/package.json +++ b/packages/amplify-category-analytics/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-analytics", - "version": "2.21.12", + "version": "2.21.16", "description": "amplify-cli analytics plugin", "repository": { "type": "git", @@ -15,7 +15,7 @@ "aws" ], "dependencies": { - "amplify-cli-core": "1.24.0", + "amplify-cli-core": "1.26.0", "fs-extra": "^8.1.0", "inquirer": "^7.3.3", "uuid": "^3.4.0" diff --git a/packages/amplify-category-analytics/provider-utils/awscloudformation/cloudformation-templates/pinpoint-cloudformation-template.json b/packages/amplify-category-analytics/provider-utils/awscloudformation/cloudformation-templates/pinpoint-cloudformation-template.json index 71dd61aefcd..3664cd96c45 100644 --- a/packages/amplify-category-analytics/provider-utils/awscloudformation/cloudformation-templates/pinpoint-cloudformation-template.json +++ b/packages/amplify-category-analytics/provider-utils/awscloudformation/cloudformation-templates/pinpoint-cloudformation-template.json @@ -230,7 +230,7 @@ }, "Handler": "index.handler", "Runtime": "nodejs12.x", - "Timeout": "300", + "Timeout": 300, "Role": { "Fn::GetAtt": ["LambdaExecutionRole", "Arn"] } diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 358c3ff01ad..133a4689cc7 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,7 +3,51 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. -## [2.31.14-ext.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.31.13...amplify-category-api@2.31.14-ext.0) (2021-07-14) +## [2.31.18](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.31.17...amplify-category-api@2.31.18) (2021-08-06) + + + +# 5.3.0 (2021-08-04) + + +### Bug Fixes + +* **container-hosting:** ignore test cases ([#7895](https://github.com/aws-amplify/amplify-cli/issues/7895)) ([f051445](https://github.com/aws-amplify/amplify-cli/commit/f05144510311fd38f188fd2d86a9fb0c74219269)) +* **graphql-model-transformer:** model input fields transform ([#7857](https://github.com/aws-amplify/amplify-cli/issues/7857)) ([12ff663](https://github.com/aws-amplify/amplify-cli/commit/12ff663a94a4896bd9eacef3847be15b7631d8df)) +* multi-env container hosting ([#7009](https://github.com/aws-amplify/amplify-cli/issues/7009)) ([#7346](https://github.com/aws-amplify/amplify-cli/issues/7346)) ([6c33215](https://github.com/aws-amplify/amplify-cli/commit/6c33215d064029add6b93bb10cad96bb63f40101)) + + + + + +## [2.31.17](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.31.16...amplify-category-api@2.31.17) (2021-07-30) + + +### Bug Fixes + +* lambda timeout should be an integer type ([#7699](https://github.com/aws-amplify/amplify-cli/issues/7699)) ([cbacf4d](https://github.com/aws-amplify/amplify-cli/commit/cbacf4d3e497421855c09825970e025550aacfd7)) + + + + + +## [2.31.16](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.31.15...amplify-category-api@2.31.16) (2021-07-27) + +**Note:** Version bump only for package amplify-category-api + + + + + +## [2.31.15](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.31.14...amplify-category-api@2.31.15) (2021-07-16) + +**Note:** Version bump only for package amplify-category-api + + + + + +## [2.31.14](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-api@2.31.13...amplify-category-api@2.31.14) (2021-07-12) **Note:** Version bump only for package amplify-category-api diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 92b29b405d1..8bd4c0679cb 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.31.14-ext.0", + "version": "2.31.18", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -25,11 +25,11 @@ "@aws-cdk/aws-autoscaling-common": "~1.72.0", "@aws-cdk/aws-autoscaling-hooktargets": "~1.72.0", "@aws-cdk/aws-certificatemanager": "~1.72.0", - "@aws-cdk/aws-cloudformation": "1.72.0", + "@aws-cdk/aws-cloudformation": "~1.72.0", "@aws-cdk/aws-cloudfront": "~1.72.0", "@aws-cdk/aws-cloudwatch": "~1.72.0", "@aws-cdk/aws-codebuild": "~1.72.0", - "@aws-cdk/aws-codeguruprofiler": "1.72.0", + "@aws-cdk/aws-codeguruprofiler": "~1.72.0", "@aws-cdk/aws-codepipeline": "~1.72.0", "@aws-cdk/aws-codepipeline-actions": "~1.72.0", "@aws-cdk/aws-cognito": "~1.72.0", @@ -37,7 +37,7 @@ "@aws-cdk/aws-ecr": "~1.72.0", "@aws-cdk/aws-ecr-assets": "~1.72.0", "@aws-cdk/aws-ecs": "~1.72.0", - "@aws-cdk/aws-efs": "1.72.0", + "@aws-cdk/aws-efs": "~1.72.0", "@aws-cdk/aws-elasticloadbalancing": "~1.72.0", "@aws-cdk/aws-elasticloadbalancingv2": "~1.72.0", "@aws-cdk/aws-events": "~1.72.0", @@ -49,7 +49,7 @@ "@aws-cdk/aws-route53-targets": "~1.72.0", "@aws-cdk/aws-s3": "~1.72.0", "@aws-cdk/aws-s3-assets": "~1.72.0", - "@aws-cdk/aws-sam": "1.72.0", + "@aws-cdk/aws-sam": "~1.72.0", "@aws-cdk/aws-secretsmanager": "~1.72.0", "@aws-cdk/aws-servicediscovery": "~1.72.0", "@aws-cdk/aws-sns": "~1.72.0", @@ -62,14 +62,14 @@ "@aws-cdk/cx-api": "~1.72.0", "@aws-cdk/region-info": "~1.72.0", "@graphql-tools/merge": "^6.0.18", - "amplify-cli-core": "1.24.0", - "amplify-util-headless-input": "1.5.1-ext.0", - "chalk": "^3.0.0", + "amplify-cli-core": "1.26.0", + "amplify-util-headless-input": "1.5.3", + "chalk": "^4.1.1", "constructs": "^3.2.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", - "graphql-relational-schema-transformer": "2.18.1", - "graphql-transformer-core": "6.28.12", + "graphql-relational-schema-transformer": "2.18.4", + "graphql-transformer-core": "6.29.2", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "ora": "^4.0.3", diff --git a/packages/amplify-category-api/resources/awscloudformation/sync-conflict-handler/sync-conflict-handler-template.json.ejs b/packages/amplify-category-api/resources/awscloudformation/sync-conflict-handler/sync-conflict-handler-template.json.ejs index 0cb2bca1ec0..f898077cbd3 100644 --- a/packages/amplify-category-api/resources/awscloudformation/sync-conflict-handler/sync-conflict-handler-template.json.ejs +++ b/packages/amplify-category-api/resources/awscloudformation/sync-conflict-handler/sync-conflict-handler-template.json.ejs @@ -67,7 +67,7 @@ }, "Role": { "Fn::GetAtt" : ["LambdaExecutionRole", "Arn"] }, "Runtime": "nodejs14.x", - "Timeout": "25" + "Timeout": 25 } }, "LambdaExecutionRole": { diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/base-api-stack.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/base-api-stack.ts index e197d4522e6..f495cbff5c3 100644 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/base-api-stack.ts +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/base-api-stack.ts @@ -10,490 +10,495 @@ import * as cdk from '@aws-cdk/core'; import { prepareApp } from '@aws-cdk/core/lib/private/prepare-app'; import { NETWORK_STACK_LOGICAL_ID } from '../../category-constants'; import Container from './docker-compose/ecs-objects/container'; -import { GitHubSourceActionInfo, PipelineWithAwaiter } from "./pipeline-with-awaiter"; +import { GitHubSourceActionInfo, PipelineWithAwaiter } from './pipeline-with-awaiter'; const PIPELINE_AWAITER_ZIP = 'custom-resource-pipeline-awaiter.zip'; export enum DEPLOYMENT_MECHANISM { - /** - * on every amplify push - */ - FULLY_MANAGED = 'FULLY_MANAGED', - /** - * on every github push - */ - INDENPENDENTLY_MANAGED = 'INDENPENDENTLY_MANAGED', - /** - * manually push by the customer to ECR - */ - SELF_MANAGED = 'SELF_MANAGED', -}; + /** + * on every amplify push + */ + FULLY_MANAGED = 'FULLY_MANAGED', + /** + * on every github push + */ + INDENPENDENTLY_MANAGED = 'INDENPENDENTLY_MANAGED', + /** + * manually push by the customer to ECR + */ + SELF_MANAGED = 'SELF_MANAGED', +} export type ContainersStackProps = Readonly<{ - skipWait?: boolean; - envName: string; - categoryName: string; - apiName: string; - deploymentBucketName: string, - dependsOn: ReadonlyArray<{ - category: string; - resourceName: string; - attributes: string[]; - }>; - taskEnvironmentVariables?: Record; - deploymentMechanism: DEPLOYMENT_MECHANISM; - restrictAccess: boolean; - policies?: ReadonlyArray>; - containers: ReadonlyArray; - secretsArns?: ReadonlyMap; - exposedContainer: { name: string; port: number }; - taskPorts: number[]; - isInitialDeploy: boolean; - desiredCount: number; - createCloudMapService?: boolean; - gitHubSourceActionInfo?: GitHubSourceActionInfo; - existingEcrRepositories: Set; + skipWait?: boolean; + envName: string; + categoryName: string; + apiName: string; + deploymentBucketName: string; + dependsOn: ReadonlyArray<{ + category: string; + resourceName: string; + attributes: string[]; + }>; + taskEnvironmentVariables?: Record; + deploymentMechanism: DEPLOYMENT_MECHANISM; + restrictAccess: boolean; + policies?: ReadonlyArray>; + containers: ReadonlyArray; + secretsArns?: ReadonlyMap; + exposedContainer: { name: string; port: number }; + taskPorts: number[]; + isInitialDeploy: boolean; + desiredCount: number; + createCloudMapService?: boolean; + gitHubSourceActionInfo?: GitHubSourceActionInfo; + existingEcrRepositories: Set; }>; export abstract class ContainersStack extends cdk.Stack { - protected readonly vpcId: string; - private readonly vpcCidrBlock: string; - protected readonly subnets: ReadonlyArray; - private readonly clusterName: string; - private readonly zipPath: string; - private readonly cloudMapNamespaceId: string; - protected readonly vpcLinkId: string; - private readonly pipelineWithAwaiter: PipelineWithAwaiter; - protected readonly cloudMapService: cloudmap.CfnService | undefined; - protected readonly ecsService: ecs.CfnService; - protected readonly isAuthCondition: cdk.CfnCondition; - protected readonly appClientId: string | undefined; - protected readonly userPoolId: string | undefined; - protected readonly ecsServiceSecurityGroup: ec2.CfnSecurityGroup; - protected readonly parameters: ReadonlyMap; - - constructor(scope: cdk.Construct, id: string, private readonly props: ContainersStackProps) { - super(scope, id); - - const { - parameters, - vpcId, - vpcCidrBlock, - subnets, - clusterName, - zipPath, - cloudMapNamespaceId, - vpcLinkId, - isAuthCondition, - appClientId, - userPoolId, - } = this.init(); - - this.parameters = parameters; - - this.vpcId = vpcId; - this.vpcCidrBlock = vpcCidrBlock; - this.subnets = subnets; - this.clusterName = clusterName; - this.zipPath = zipPath; - this.cloudMapNamespaceId = cloudMapNamespaceId; - this.vpcLinkId = vpcLinkId; - this.isAuthCondition = isAuthCondition; - this.appClientId = appClientId; - this.userPoolId = userPoolId; - - const { service, serviceSecurityGroup, containersInfo, cloudMapService } = this.ecs(); - - this.cloudMapService = cloudMapService; - this.ecsService = service; - this.ecsServiceSecurityGroup = serviceSecurityGroup; - - const { gitHubSourceActionInfo, skipWait } = this.props; - - const { pipelineWithAwaiter } = this.pipeline({ - skipWait, - service, - containersInfo, - gitHubSourceActionInfo, - }); - - this.pipelineWithAwaiter = pipelineWithAwaiter; + protected readonly vpcId: string; + private readonly vpcCidrBlock: string; + protected readonly subnets: ReadonlyArray; + private readonly clusterName: string; + private readonly zipPath: string; + private readonly cloudMapNamespaceId: string; + protected readonly vpcLinkId: string; + private readonly pipelineWithAwaiter: PipelineWithAwaiter; + protected readonly cloudMapService: cloudmap.CfnService | undefined; + protected readonly ecsService: ecs.CfnService; + protected readonly isAuthCondition: cdk.CfnCondition; + protected readonly appClientId: string | undefined; + protected readonly userPoolId: string | undefined; + protected readonly ecsServiceSecurityGroup: ec2.CfnSecurityGroup; + protected readonly parameters: ReadonlyMap; + + constructor(scope: cdk.Construct, id: string, private readonly props: ContainersStackProps) { + super(scope, id); + + const { + parameters, + vpcId, + vpcCidrBlock, + subnets, + clusterName, + zipPath, + cloudMapNamespaceId, + vpcLinkId, + isAuthCondition, + appClientId, + userPoolId, + } = this.init(); + + this.parameters = parameters; + + this.vpcId = vpcId; + this.vpcCidrBlock = vpcCidrBlock; + this.subnets = subnets; + this.clusterName = clusterName; + this.zipPath = zipPath; + this.cloudMapNamespaceId = cloudMapNamespaceId; + this.vpcLinkId = vpcLinkId; + this.isAuthCondition = isAuthCondition; + this.appClientId = appClientId; + this.userPoolId = userPoolId; + + const { service, serviceSecurityGroup, containersInfo, cloudMapService } = this.ecs(); + + this.cloudMapService = cloudMapService; + this.ecsService = service; + this.ecsServiceSecurityGroup = serviceSecurityGroup; + + const { gitHubSourceActionInfo, skipWait } = this.props; + + const { pipelineWithAwaiter } = this.pipeline({ + skipWait, + service, + containersInfo, + gitHubSourceActionInfo, + }); + + this.pipelineWithAwaiter = pipelineWithAwaiter; + + new cdk.CfnOutput(this, 'ContainerNames', { + value: cdk.Fn.join( + ',', + containersInfo.map(({ container: { containerName } }) => containerName), + ), + }); + } + + private init() { + const { restrictAccess, dependsOn, deploymentMechanism } = this.props; + + // Unused in this stack, but required by the root stack + new cdk.CfnParameter(this, 'env', { type: 'String' }); + + const paramDomain = new cdk.CfnParameter(this, 'domain', { type: 'String', default: '' }); + const paramRestrictAccess = new cdk.CfnParameter(this, 'restrictAccess', { + type: 'String', + allowedValues: ['true', 'false'], + default: 'false', + }); + + const paramZipPath = new cdk.CfnParameter(this, 'ParamZipPath', { + type: 'String', + // Required only for FULLY_MANAGED + default: deploymentMechanism === DEPLOYMENT_MECHANISM.FULLY_MANAGED ? undefined : '', + }); + + const parameters: Map = new Map(); + + parameters.set('ParamZipPath', paramZipPath); + parameters.set('domain', paramDomain); + parameters.set('restrictAccess', paramRestrictAccess); + + const authParams: { + UserPoolId?: cdk.CfnParameter; + AppClientIDWeb?: cdk.CfnParameter; + } = {}; + + const paramTypes: Record = { + NetworkStackSubnetIds: 'CommaDelimitedList', + }; + + dependsOn.forEach(({ category, resourceName, attributes }) => { + attributes.forEach(attrib => { + const paramName = [category, resourceName, attrib].join(''); + + const type = paramTypes[paramName] ?? 'String'; + const param = new cdk.CfnParameter(this, paramName, { type }); + + parameters.set(paramName, param); + + if (category === 'auth') { + authParams[attrib as keyof typeof authParams] = param; + } + }); + }); + + const paramVpcId = parameters.get(`${NETWORK_STACK_LOGICAL_ID}VpcId`); + const paramVpcCidrBlock = parameters.get(`${NETWORK_STACK_LOGICAL_ID}VpcCidrBlock`); + const paramSubnetIds = parameters.get(`${NETWORK_STACK_LOGICAL_ID}SubnetIds`); + const paramClusterName = parameters.get(`${NETWORK_STACK_LOGICAL_ID}ClusterName`); + const paramCloudMapNamespaceId = parameters.get(`${NETWORK_STACK_LOGICAL_ID}CloudMapNamespaceId`); + const paramVpcLinkId = parameters.get(`${NETWORK_STACK_LOGICAL_ID}VpcLinkId`); + + const { UserPoolId: paramUserPoolId, AppClientIDWeb: paramAppClientIdWeb } = authParams; + + const isAuthCondition = new cdk.CfnCondition(this, 'isAuthCondition', { + expression: cdk.Fn.conditionAnd( + cdk.Fn.conditionEquals(restrictAccess, true), + cdk.Fn.conditionNot(cdk.Fn.conditionEquals(paramUserPoolId ?? '', '')), + cdk.Fn.conditionNot(cdk.Fn.conditionEquals(paramAppClientIdWeb ?? '', '')), + ), + }); - new cdk.CfnOutput(this, 'ContainerNames', { - value: cdk.Fn.join(',', containersInfo.map(({ container: { containerName } }) => containerName)) - }); + return { + parameters, + vpcId: paramVpcId.valueAsString, + vpcCidrBlock: paramVpcCidrBlock.valueAsString, + subnets: paramSubnetIds.valueAsList, + clusterName: paramClusterName.valueAsString, + zipPath: paramZipPath.valueAsString, + cloudMapNamespaceId: paramCloudMapNamespaceId.valueAsString, + vpcLinkId: paramVpcLinkId.valueAsString, + isAuthCondition, + userPoolId: paramUserPoolId && paramUserPoolId.valueAsString, + appClientId: paramAppClientIdWeb && paramAppClientIdWeb.valueAsString, + }; + } + + private ecs() { + const { + envName, + categoryName, + apiName, + policies, + containers, + secretsArns, + taskEnvironmentVariables, + exposedContainer, + taskPorts, + isInitialDeploy, + desiredCount, + createCloudMapService, + } = this.props; + + let cloudMapService: cloudmap.CfnService = undefined; + + if (createCloudMapService) { + cloudMapService = new cloudmap.CfnService(this, 'CloudmapService', { + name: apiName, + dnsConfig: { + dnsRecords: [ + { + ttl: 60, + type: cloudmap.DnsRecordType.SRV, + }, + ], + namespaceId: this.cloudMapNamespaceId, + routingPolicy: cloudmap.RoutingPolicy.MULTIVALUE, + }, + }); } - private init() { - const { - restrictAccess, - dependsOn, - deploymentMechanism, - } = this.props; - - // Unused in this stack, but required by the root stack - new cdk.CfnParameter(this, 'env', { type: 'String' }); - - const paramZipPath = new cdk.CfnParameter(this, 'ParamZipPath', { - type: 'String', - // Required only for FULLY_MANAGED - default: deploymentMechanism === DEPLOYMENT_MECHANISM.FULLY_MANAGED ? undefined : '', + const task = new ecs.TaskDefinition(this, 'TaskDefinition', { + compatibility: ecs.Compatibility.FARGATE, + memoryMiB: '1024', + cpu: '512', + family: `${envName}-${apiName}`, + }); + (task.node.defaultChild as ecs.CfnTaskDefinition).overrideLogicalId('TaskDefinition'); + policies.forEach(policy => { + const statement = isPolicyStatement(policy) ? policy : wrapJsonPoliciesInCdkPolicies(policy); + + task.addToTaskRolePolicy(statement); + }); + + const containersInfo: { + container: ecs.ContainerDefinition; + repository: ecr.IRepository; + }[] = []; + + containers.forEach( + ({ + name, + image, + build, + portMappings, + logConfiguration, + environment, + entrypoint: entryPoint, + command, + working_dir: workingDirectory, + healthcheck: healthCheck, + secrets: containerSecrets, + }) => { + const logGroup = new logs.LogGroup(this, `${name}ContainerLogGroup`, { + logGroupName: `/ecs/${envName}-${apiName}-${name}`, + retention: logs.RetentionDays.ONE_MONTH, + removalPolicy: cdk.RemovalPolicy.DESTROY, }); - const parameters: Map = new Map(); - - parameters.set('ParamZipPath', paramZipPath); - - const authParams: { - UserPoolId?: cdk.CfnParameter; - AppClientIDWeb?: cdk.CfnParameter; - } = {}; - - const paramTypes: Record = { - NetworkStackSubnetIds: 'CommaDelimitedList', - }; - - dependsOn.forEach(({ category, resourceName, attributes }) => { - attributes.forEach(attrib => { - const paramName = [category, resourceName, attrib].join(''); - - const type = paramTypes[paramName] ?? 'String'; - const param = new cdk.CfnParameter(this, paramName, { type }); - - parameters.set(paramName, param); - - if (category === 'auth') { - authParams[attrib as keyof typeof authParams] = param; - } + const { logDriver, options: { 'awslogs-stream-prefix': streamPrefix } = {} } = logConfiguration; + + const logging: ecs.LogDriver = + logDriver === 'awslogs' + ? ecs.LogDriver.awsLogs({ + streamPrefix, + logGroup: logs.LogGroup.fromLogGroupName(this, `${name}logGroup`, logGroup.logGroupName), + }) + : undefined; + + let repository: ecr.IRepository; + if (build) { + const logicalId = `${name}Repository`; + + const repositoryName = `${envName}-${categoryName}-${apiName}-${name}`; + + if (this.props.existingEcrRepositories.has(repositoryName)) { + repository = ecr.Repository.fromRepositoryName(this, logicalId, repositoryName); + } else { + repository = new ecr.Repository(this, logicalId, { + repositoryName: `${envName}-${categoryName}-${apiName}-${name}`, + removalPolicy: cdk.RemovalPolicy.RETAIN, + lifecycleRules: [ + { + rulePriority: 10, + maxImageCount: 1, + tagPrefixList: ['latest'], + tagStatus: ecr.TagStatus.TAGGED, + }, + { + rulePriority: 100, + maxImageAge: cdk.Duration.days(7), + tagStatus: ecr.TagStatus.ANY, + }, + ], }); - }); + (repository.node.defaultChild as ecr.CfnRepository).overrideLogicalId(logicalId); + } - const paramVpcId = parameters.get(`${NETWORK_STACK_LOGICAL_ID}VpcId`); - const paramVpcCidrBlock = parameters.get(`${NETWORK_STACK_LOGICAL_ID}VpcCidrBlock`); - const paramSubnetIds = parameters.get(`${NETWORK_STACK_LOGICAL_ID}SubnetIds`); - const paramClusterName = parameters.get(`${NETWORK_STACK_LOGICAL_ID}ClusterName`); - const paramCloudMapNamespaceId = parameters.get(`${NETWORK_STACK_LOGICAL_ID}CloudMapNamespaceId`); - const paramVpcLinkId = parameters.get(`${NETWORK_STACK_LOGICAL_ID}VpcLinkId`); - - const { UserPoolId: paramUserPoolId, AppClientIDWeb: paramAppClientIdWeb } = authParams; - - const isAuthCondition = new cdk.CfnCondition(this, 'isAuthCondition', { - expression: cdk.Fn.conditionAnd( - cdk.Fn.conditionEquals(restrictAccess, true), - cdk.Fn.conditionNot(cdk.Fn.conditionEquals(paramUserPoolId ?? '', '')), - cdk.Fn.conditionNot(cdk.Fn.conditionEquals(paramAppClientIdWeb ?? '', '')), - ), - }); + // Needed because the image will be pulled from ecr repository later + repository.grantPull(task.obtainExecutionRole()); + } - return { - parameters, - vpcId: paramVpcId.valueAsString, - vpcCidrBlock: paramVpcCidrBlock.valueAsString, - subnets: paramSubnetIds.valueAsList, - clusterName: paramClusterName.valueAsString, - zipPath: paramZipPath.valueAsString, - cloudMapNamespaceId: paramCloudMapNamespaceId.valueAsString, - vpcLinkId: paramVpcLinkId.valueAsString, - isAuthCondition, - userPoolId: paramUserPoolId && paramUserPoolId.valueAsString, - appClientId: paramAppClientIdWeb && paramAppClientIdWeb.valueAsString, - }; - } + const secrets: ecs.ContainerDefinitionOptions['secrets'] = {}; + const environmentWithoutSecrets = environment || {}; - private ecs() { - const { - envName, - categoryName, - apiName, - policies, - containers, - secretsArns, - taskEnvironmentVariables, - exposedContainer, - taskPorts, - isInitialDeploy, - desiredCount, - createCloudMapService, - } = this.props; - - let cloudMapService: cloudmap.CfnService = undefined; - - if (createCloudMapService) { - cloudMapService = new cloudmap.CfnService(this, 'CloudmapService', { - name: apiName, - dnsConfig: { - dnsRecords: [ - { - ttl: 60, - type: cloudmap.DnsRecordType.SRV, - }, - ], - namespaceId: this.cloudMapNamespaceId, - routingPolicy: cloudmap.RoutingPolicy.MULTIVALUE, - }, - }); - } + containerSecrets.forEach((s, i) => { + if (secretsArns.has(s)) { + secrets[s] = ecs.Secret.fromSecretsManager(ssm.Secret.fromSecretCompleteArn(this, `${name}secret${i + 1}`, secretsArns.get(s))); + } - const task = new ecs.TaskDefinition(this, 'TaskDefinition', { - compatibility: ecs.Compatibility.FARGATE, - memoryMiB: '1024', - cpu: '512', - family: `${envName}-${apiName}`, + delete environmentWithoutSecrets[s]; }); - (task.node.defaultChild as ecs.CfnTaskDefinition).overrideLogicalId('TaskDefinition'); - policies.forEach(policy => { - const statement = isPolicyStatement(policy) ? policy : wrapJsonPoliciesInCdkPolicies(policy); - task.addToTaskRolePolicy(statement); + const container = task.addContainer(name, { + image: repository ? ecs.ContainerImage.fromEcrRepository(repository) : ecs.ContainerImage.fromRegistry(image), + logging, + environment: { + ...taskEnvironmentVariables, + ...environmentWithoutSecrets, + }, + entryPoint, + command, + workingDirectory, + healthCheck: healthCheck && { + command: healthCheck.command, + interval: cdk.Duration.seconds(healthCheck.interval ?? 30), + retries: healthCheck.retries, + timeout: cdk.Duration.seconds(healthCheck.timeout ?? 5), + startPeriod: cdk.Duration.seconds(healthCheck.start_period ?? 0), + }, + secrets, }); - const containersInfo: { - container: ecs.ContainerDefinition; - repository: ecr.IRepository; - }[] = []; - - containers.forEach( - ({ - name, - image, - build, - portMappings, - logConfiguration, - environment, - entrypoint: entryPoint, - command, - working_dir: workingDirectory, - healthcheck: healthCheck, - secrets: containerSecrets, - }) => { - const logGroup = new logs.LogGroup(this, `${name}ContainerLogGroup`, { - logGroupName: `/ecs/${envName}-${apiName}-${name}`, - retention: logs.RetentionDays.ONE_MONTH, - removalPolicy: cdk.RemovalPolicy.DESTROY, - }); - - const { logDriver, options: { 'awslogs-stream-prefix': streamPrefix } = {} } = logConfiguration; - - const logging: ecs.LogDriver = - logDriver === 'awslogs' - ? ecs.LogDriver.awsLogs({ - streamPrefix, - logGroup: logs.LogGroup.fromLogGroupName(this, `${name}logGroup`, logGroup.logGroupName), - }) - : undefined; - - let repository: ecr.IRepository; - if (build) { - const logicalId = `${name}Repository`; - - const repositoryName = `${envName}-${categoryName}-${apiName}-${name}`; - - if (this.props.existingEcrRepositories.has(repositoryName)) { - repository = ecr.Repository.fromRepositoryName(this, logicalId, repositoryName); - } else { - repository = new ecr.Repository(this, logicalId, { - repositoryName: `${envName}-${categoryName}-${apiName}-${name}`, - removalPolicy: cdk.RemovalPolicy.RETAIN, - lifecycleRules: [ - { - rulePriority: 10, - maxImageCount: 1, - tagPrefixList: ['latest'], - tagStatus: ecr.TagStatus.TAGGED, - }, - { - rulePriority: 100, - maxImageAge: cdk.Duration.days(7), - tagStatus: ecr.TagStatus.ANY, - }, - ], - }); - (repository.node.defaultChild as ecr.CfnRepository).overrideLogicalId(logicalId); - } - - // Needed because the image will be pulled from ecr repository later - repository.grantPull(task.obtainExecutionRole()); - } - - const secrets: ecs.ContainerDefinitionOptions['secrets'] = {}; - const environmentWithoutSecrets = environment || {}; - - containerSecrets.forEach((s, i) => { - if (secretsArns.has(s)) { - secrets[s] = ecs.Secret.fromSecretsManager(ssm.Secret.fromSecretCompleteArn(this, `${name}secret${i + 1}`, secretsArns.get(s))); - } - - delete environmentWithoutSecrets[s]; - }); - - const container = task.addContainer(name, { - image: repository ? ecs.ContainerImage.fromEcrRepository(repository) : ecs.ContainerImage.fromRegistry(image), - logging, - environment: { - ...taskEnvironmentVariables, - ...environmentWithoutSecrets, - }, - entryPoint, - command, - workingDirectory, - healthCheck: healthCheck && { - command: healthCheck.command, - interval: cdk.Duration.seconds(healthCheck.interval ?? 30), - retries: healthCheck.retries, - timeout: cdk.Duration.seconds(healthCheck.timeout ?? 5), - startPeriod: cdk.Duration.seconds(healthCheck.start_period ?? 0), - }, - secrets, - }); - - if (build) { - containersInfo.push({ - container, - repository, - }); - } - - // TODO: should we use hostPort too? check network mode - portMappings?.forEach(({ containerPort, protocol, hostPort }) => { - container.addPortMappings({ - containerPort, - protocol: ecs.Protocol.TCP, - }); - }); - }, - ); + if (build) { + containersInfo.push({ + container, + repository, + }); + } - const serviceSecurityGroup = new ec2.CfnSecurityGroup(this, 'ServiceSG', { - vpcId: this.vpcId, - groupDescription: 'Service SecurityGroup', - securityGroupEgress: [ - { - description: 'Allow all outbound traffic by default', - cidrIp: '0.0.0.0/0', - ipProtocol: '-1', - }, - ], - securityGroupIngress: taskPorts.map(servicePort => ({ - ipProtocol: 'tcp', - fromPort: servicePort, - toPort: servicePort, - cidrIp: this.vpcCidrBlock, - })), + // TODO: should we use hostPort too? check network mode + portMappings?.forEach(({ containerPort, protocol, hostPort }) => { + container.addPortMappings({ + containerPort, + protocol: ecs.Protocol.TCP, + }); }); + }, + ); + + const serviceSecurityGroup = new ec2.CfnSecurityGroup(this, 'ServiceSG', { + vpcId: this.vpcId, + groupDescription: 'Service SecurityGroup', + securityGroupEgress: [ + { + description: 'Allow all outbound traffic by default', + cidrIp: '0.0.0.0/0', + ipProtocol: '-1', + }, + ], + securityGroupIngress: taskPorts.map(servicePort => ({ + ipProtocol: 'tcp', + fromPort: servicePort, + toPort: servicePort, + cidrIp: this.vpcCidrBlock, + })), + }); + + let serviceRegistries: ecs.CfnService.ServiceRegistryProperty[] = undefined; + + if (cloudMapService) { + serviceRegistries = [ + { + containerName: exposedContainer.name, + containerPort: exposedContainer.port, + registryArn: cloudMapService.attrArn, + }, + ]; + } - let serviceRegistries: ecs.CfnService.ServiceRegistryProperty[] = undefined; + const service = new ecs.CfnService(this, 'Service', { + serviceName: `${apiName}-service-${exposedContainer.name}-${exposedContainer.port}`, + cluster: this.clusterName, + launchType: 'FARGATE', + desiredCount: isInitialDeploy ? 0 : desiredCount, // This is later adjusted by the Predeploy action in the codepipeline + networkConfiguration: { + awsvpcConfiguration: { + assignPublicIp: 'ENABLED', + securityGroups: [serviceSecurityGroup.attrGroupId], + subnets: this.subnets, + }, + }, + taskDefinition: task.taskDefinitionArn, + serviceRegistries, + }); - if (cloudMapService) { - serviceRegistries = [{ - containerName: exposedContainer.name, - containerPort: exposedContainer.port, - registryArn: cloudMapService.attrArn, - }]; - } + new cdk.CfnOutput(this, 'ServiceName', { + value: service.serviceName, + }); - const service = new ecs.CfnService(this, 'Service', { - serviceName: `${apiName}-service-${exposedContainer.name}-${exposedContainer.port}`, - cluster: this.clusterName, - launchType: 'FARGATE', - desiredCount: isInitialDeploy ? 0 : desiredCount, // This is later adjusted by the Predeploy action in the codepipeline - networkConfiguration: { - awsvpcConfiguration: { - assignPublicIp: 'ENABLED', - securityGroups: [serviceSecurityGroup.attrGroupId], - subnets: this.subnets, - }, - }, - taskDefinition: task.taskDefinitionArn, - serviceRegistries, - }); + new cdk.CfnOutput(this, 'ClusterName', { + value: this.clusterName, + }); - new cdk.CfnOutput(this, 'ServiceName', { - value: service.serviceName - }); + return { + service, + serviceSecurityGroup, + containersInfo, + cloudMapService, + }; + } + + private pipeline({ + skipWait = false, + service, + containersInfo, + gitHubSourceActionInfo, + }: { + skipWait?: boolean; + service: ecs.CfnService; + containersInfo: { + container: ecs.ContainerDefinition; + repository: ecr.IRepository; + }[]; + gitHubSourceActionInfo?: GitHubSourceActionInfo; + }) { + const { envName, deploymentBucketName, deploymentMechanism, desiredCount } = this.props; - new cdk.CfnOutput(this, 'ClusterName', { - value: this.clusterName - }); + const s3SourceActionKey = this.zipPath; - return { - service, - serviceSecurityGroup, - containersInfo, - cloudMapService, - }; - } + const bucket = s3.Bucket.fromBucketName(this, 'Bucket', deploymentBucketName); - private pipeline({ - skipWait = false, - service, - containersInfo, - gitHubSourceActionInfo, - }: { - skipWait?: boolean; - service: ecs.CfnService, - containersInfo: { - container: ecs.ContainerDefinition; - repository: ecr.IRepository; - }[], - gitHubSourceActionInfo?: GitHubSourceActionInfo - }) { - const { - envName, - deploymentBucketName, - deploymentMechanism, - desiredCount, - } = this.props; - - const s3SourceActionKey = this.zipPath; - - const bucket = s3.Bucket.fromBucketName(this, 'Bucket', deploymentBucketName); - - const pipelineWithAwaiter = new PipelineWithAwaiter(this, 'ApiPipeline', { - skipWait, - envName, - containersInfo, - service, - bucket, - s3SourceActionKey, - deploymentMechanism, - gitHubSourceActionInfo, - desiredCount, - }); + const pipelineWithAwaiter = new PipelineWithAwaiter(this, 'ApiPipeline', { + skipWait, + envName, + containersInfo, + service, + bucket, + s3SourceActionKey, + deploymentMechanism, + gitHubSourceActionInfo, + desiredCount, + }); - pipelineWithAwaiter.node.addDependency(service); + pipelineWithAwaiter.node.addDependency(service); - return { pipelineWithAwaiter }; - } + return { pipelineWithAwaiter }; + } - protected getPipelineName() { - return this.pipelineWithAwaiter.getPipelineName(); - } + protected getPipelineName() { + return this.pipelineWithAwaiter.getPipelineName(); + } - getPipelineConsoleUrl(region: string) { - const pipelineName = this.getPipelineName(); - return `https://${region}.console.aws.amazon.com/codesuite/codepipeline/pipelines/${pipelineName}/view`; - } + getPipelineConsoleUrl(region: string) { + const pipelineName = this.getPipelineName(); + return `https://${region}.console.aws.amazon.com/codesuite/codepipeline/pipelines/${pipelineName}/view`; + } - toCloudFormation() { - prepareApp(this); + toCloudFormation() { + prepareApp(this); - const cfn = this._toCloudFormation(); + const cfn = this._toCloudFormation(); - Object.keys(cfn.Parameters).forEach(k => { - if (k.startsWith('AssetParameters')) { - let value = ''; + Object.keys(cfn.Parameters).forEach(k => { + if (k.startsWith('AssetParameters')) { + let value = ''; - if (k.includes('Bucket')) { - value = this.props.deploymentBucketName; - } else if (k.includes('VersionKey')) { - value = `${PIPELINE_AWAITER_ZIP}||`; - } + if (k.includes('Bucket')) { + value = this.props.deploymentBucketName; + } else if (k.includes('VersionKey')) { + value = `${PIPELINE_AWAITER_ZIP}||`; + } - cfn.Parameters[k].Default = value; - } - }); + cfn.Parameters[k].Default = value; + } + }); - return cfn; - } + return cfn; + } } /** @@ -506,17 +511,17 @@ export abstract class ContainersStack extends cdk.Stack { * @returns {iam.PolicyStatement} CDK compatible policy statement */ function wrapJsonPoliciesInCdkPolicies(policy: Record): iam.PolicyStatement { - return { - toStatementJson() { - return policy; - }, - } as iam.PolicyStatement; + return { + toStatementJson() { + return policy; + }, + } as iam.PolicyStatement; } function isPolicyStatement(obj: any): obj is iam.PolicyStatement { - if (obj && typeof (obj).toStatementJson === 'function') { - return true; - } + if (obj && typeof (obj).toStatementJson === 'function') { + return true; + } - return false; -} \ No newline at end of file + return false; +} diff --git a/packages/amplify-category-auth/CHANGELOG.md b/packages/amplify-category-auth/CHANGELOG.md index 68d72508027..360b5741dec 100644 --- a/packages/amplify-category-auth/CHANGELOG.md +++ b/packages/amplify-category-auth/CHANGELOG.md @@ -3,7 +3,79 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. -# [2.35.0-ext.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-auth@2.34.1...amplify-category-auth@2.35.0-ext.0) (2021-07-14) +## [2.36.2](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-auth@2.36.1...amplify-category-auth@2.36.2) (2021-08-06) + + +### Bug Fixes + +* **amplify-category-auth:** add auth user selections to aws-exports/amplifyconfiguration files ([#7807](https://github.com/aws-amplify/amplify-cli/issues/7807)) ([3deae39](https://github.com/aws-amplify/amplify-cli/commit/3deae3969740562c8fe1a82d2659e0efffccb49d)) + + + + + +## [2.36.1](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-auth@2.36.0...amplify-category-auth@2.36.1) (2021-07-30) + + +### Bug Fixes + +* lambda timeout should be an integer type ([#7699](https://github.com/aws-amplify/amplify-cli/issues/7699)) ([cbacf4d](https://github.com/aws-amplify/amplify-cli/commit/cbacf4d3e497421855c09825970e025550aacfd7)) + + + + + +# [2.36.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-auth@2.35.1...amplify-category-auth@2.36.0) (2021-07-27) + + +### Bug Fixes + +* **amplify-category-auth:** add handling for undefined autoVerifiedAttributes ([#7780](https://github.com/aws-amplify/amplify-cli/issues/7780)) ([3aac45d](https://github.com/aws-amplify/amplify-cli/commit/3aac45d472903c2de2338409e71d6ba07248aa6b)) +* upgrade node default runtime to 14 ([#7700](https://github.com/aws-amplify/amplify-cli/issues/7700)) ([47968cc](https://github.com/aws-amplify/amplify-cli/commit/47968cc9c704ac1cffcbd0dbe40d164b1b1d48d6)) + + +### Features + +* **amplify-category-auth:** enable alternative signup/signin options ([#7461](https://github.com/aws-amplify/amplify-cli/issues/7461)) ([56a0c35](https://github.com/aws-amplify/amplify-cli/commit/56a0c35d2cef0fbff27c80f78dba57516ef18afb)), closes [#1546](https://github.com/aws-amplify/amplify-cli/issues/1546) +* **amplify-category-auth:** use EnabledMFAs to only configure TOTP ([#7779](https://github.com/aws-amplify/amplify-cli/issues/7779)) ([c2102c5](https://github.com/aws-amplify/amplify-cli/commit/c2102c53fd2ca974fb95c4468ad7a87fefe14ab0)) + + +### Reverts + +* Revert "feat(amplify-category-auth): use EnabledMFAs to only configure TOTP (#7779)" (#7790) ([fa172c4](https://github.com/aws-amplify/amplify-cli/commit/fa172c4caf6f15de56925bd1ff4f8ee743788b52)), closes [#7779](https://github.com/aws-amplify/amplify-cli/issues/7779) [#7790](https://github.com/aws-amplify/amplify-cli/issues/7790) +* Revert "fix: upgrade node default runtime to 14 (#7700)" (#7763) ([3ab8769](https://github.com/aws-amplify/amplify-cli/commit/3ab87694203584cdfa208bf75e648e0e944f5e18)), closes [#7700](https://github.com/aws-amplify/amplify-cli/issues/7700) [#7763](https://github.com/aws-amplify/amplify-cli/issues/7763) + + + + + +## [2.35.1](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-auth@2.35.0...amplify-category-auth@2.35.1) (2021-07-16) + + + +## 5.1.2 (2021-07-15) + + +### Bug Fixes + +* **amplify-category-auth:** \n made OS specific ([#7663](https://github.com/aws-amplify/amplify-cli/issues/7663)) ([3c0823e](https://github.com/aws-amplify/amplify-cli/commit/3c0823e8e004e00808351e958f5b587e8d77bd01)), closes [#7662](https://github.com/aws-amplify/amplify-cli/issues/7662) +* **amplify-category-auth:** added passrole policy to MFALambaRole ([#7729](https://github.com/aws-amplify/amplify-cli/issues/7729)) ([cd5d33a](https://github.com/aws-amplify/amplify-cli/commit/cd5d33aa822ceeb19a1af847d8c3eab0f1d10632)) +* **auth:** standardize CloudFormation trigger templates, prevent errors at runtime ([#7219](https://github.com/aws-amplify/amplify-cli/issues/7219)) ([f9796bd](https://github.com/aws-amplify/amplify-cli/commit/f9796bd3aca6606f155d37ac6a8931d6bdec25b9)) + + + + + +# [2.35.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-auth@2.34.1...amplify-category-auth@2.35.0) (2021-07-12) + + + +## 5.1.1 (2021-07-07) + + +### Bug Fixes + +* **amplify-category-auth:** check for siwa Cognito idp params ([#7678](https://github.com/aws-amplify/amplify-cli/issues/7678)) ([0c0adfb](https://github.com/aws-amplify/amplify-cli/commit/0c0adfb78350a192d4f44b722d6038b23c505527)) ### Features diff --git a/packages/amplify-category-auth/package.json b/packages/amplify-category-auth/package.json index 8688be30833..11a20c94b12 100644 --- a/packages/amplify-category-auth/package.json +++ b/packages/amplify-category-auth/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-auth", - "version": "2.35.0-ext.0", + "version": "2.36.2", "description": "amplify-cli authentication plugin", "repository": { "type": "git", @@ -23,14 +23,13 @@ "test-watch": "jest --watch" }, "dependencies": { - "amplify-cli-core": "1.24.0", - "amplify-headless-interface": "1.8.0-ext.0", - "amplify-util-headless-input": "1.5.1-ext.0", - "amplify-util-import": "1.5.3", + "amplify-cli-core": "1.26.0", + "amplify-headless-interface": "1.10.0", + "amplify-util-headless-input": "1.5.3", + "amplify-util-import": "1.5.7", "aws-cdk": "~1.72.0", "aws-sdk": "^2.919.0", - "chalk": "^3.0.0", - "chalk-pipe": "^3.0.0", + "chalk": "^4.1.1", "change-case": "^4.1.1", "enquirer": "^2.3.6", "fs-extra": "^8.1.0", diff --git a/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/CreateAuthChallenge/boilerplate-create-challenge.js b/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/CreateAuthChallenge/boilerplate-create-challenge.js index 42145a4faa6..2c48a0f6d41 100644 --- a/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/CreateAuthChallenge/boilerplate-create-challenge.js +++ b/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/CreateAuthChallenge/boilerplate-create-challenge.js @@ -1,12 +1,12 @@ /* tslint:disable */ /* eslint-disable */ -exports.handler = (event, context) => { +exports.handler = async event => { if (event.request.session.length === 2 && event.request.challengeName === 'CUSTOM_CHALLENGE') { event.response.publicChallengeParameters = { trigger: 'true' }; event.response.privateChallengeParameters = {}; event.response.privateChallengeParameters.answer = process.env.CHALLENGEANSWER; } - context.done(null, event); + return event; }; diff --git a/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/CreateAuthChallenge/captcha-create-challenge.js b/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/CreateAuthChallenge/captcha-create-challenge.js index 65c0ee3a404..98a5231b0bc 100644 --- a/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/CreateAuthChallenge/captcha-create-challenge.js +++ b/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/CreateAuthChallenge/captcha-create-challenge.js @@ -1,11 +1,11 @@ /* tslint:disable */ /* eslint-disable */ -exports.handler = (event, context) => { +exports.handler = async event => { if (event.request.session.length === 2 && event.request.challengeName === 'CUSTOM_CHALLENGE') { event.response.publicChallengeParameters = { trigger: 'true' }; event.response.privateChallengeParameters = { answer: '' }; event.response.challengeMetadata = 'CAPTCHA_CHALLENGE'; } - context.done(null, event); + return event; }; diff --git a/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/CreateAuthChallenge/cloudformation-templates/CreateAuthChallenge.json.ejs b/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/CreateAuthChallenge/cloudformation-templates/CreateAuthChallenge.json.ejs index d6f3b6f28f7..22ac7ebfeee 100644 --- a/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/CreateAuthChallenge/cloudformation-templates/CreateAuthChallenge.json.ejs +++ b/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/CreateAuthChallenge/cloudformation-templates/CreateAuthChallenge.json.ejs @@ -9,7 +9,7 @@ "modules": { "Type": "String", "Default": "", - "Description": "Comma-delimmited list of modules to be executed by a lambda trigger. Sent to resource as an env variable." + "Description": "Comma-delimited list of modules to be executed by a lambda trigger. Sent to resource as an env variable." }, "resourceName": { "Type": "String", @@ -105,7 +105,7 @@ }, "Role": { "Fn::GetAtt" : ["LambdaExecutionRole", "Arn"] }, "Runtime": "nodejs14.x", - "Timeout": "25" + "Timeout": 25 } }, "LambdaExecutionRole": { diff --git a/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/CreateAuthChallenge/function-template-dir/trigger-index.js b/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/CreateAuthChallenge/function-template-dir/trigger-index.js deleted file mode 100644 index 80c77ea4e38..00000000000 --- a/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/CreateAuthChallenge/function-template-dir/trigger-index.js +++ /dev/null @@ -1,14 +0,0 @@ -/* - this file will loop through all js modules which are uploaded to the lambda resource, - provided that the file names (without extension) are included in the "MODULES" env variable. - "MODULES" is a comma-delimmited string. -*/ -const moduleNames = process.env.MODULES.split(','); -const modules = moduleNames.map(name => require(`./${name}`)); - -exports.handler = (event, context, callback) => { - for (let i = 0; i < modules.length; i += 1) { - const { handler } = modules[i]; - handler(event, context, callback); - } -}; diff --git a/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/CustomMessage/cloudformation-templates/CustomMessage.json.ejs b/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/CustomMessage/cloudformation-templates/CustomMessage.json.ejs index f9ec35a28b7..89ea895bf60 100644 --- a/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/CustomMessage/cloudformation-templates/CustomMessage.json.ejs +++ b/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/CustomMessage/cloudformation-templates/CustomMessage.json.ejs @@ -17,7 +17,7 @@ "modules": { "Type": "String", "Default": "", - "Description": "Comma-delimmited list of modules to be executed by a lambda trigger. Sent to resource as an env variable." + "Description": "Comma-delimited list of modules to be executed by a lambda trigger. Sent to resource as an env variable." }, "resourceName": { "Type": "String", @@ -122,7 +122,7 @@ }, "Role": { "Fn::GetAtt" : ["LambdaExecutionRole", "Arn"] }, "Runtime": "nodejs14.x", - "Timeout": "25" + "Timeout": 25 } }, "LambdaExecutionRole": { diff --git a/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/CustomMessage/function-template-dir/trigger-index.js b/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/CustomMessage/function-template-dir/trigger-index.js deleted file mode 100644 index 80c77ea4e38..00000000000 --- a/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/CustomMessage/function-template-dir/trigger-index.js +++ /dev/null @@ -1,14 +0,0 @@ -/* - this file will loop through all js modules which are uploaded to the lambda resource, - provided that the file names (without extension) are included in the "MODULES" env variable. - "MODULES" is a comma-delimmited string. -*/ -const moduleNames = process.env.MODULES.split(','); -const modules = moduleNames.map(name => require(`./${name}`)); - -exports.handler = (event, context, callback) => { - for (let i = 0; i < modules.length; i += 1) { - const { handler } = modules[i]; - handler(event, context, callback); - } -}; diff --git a/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/CustomMessage/verification-link.js b/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/CustomMessage/verification-link.js index eb81ccc0e72..2a1b41765a8 100644 --- a/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/CustomMessage/verification-link.js +++ b/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/CustomMessage/verification-link.js @@ -1,4 +1,4 @@ -exports.handler = (event, context, callback) => { +exports.handler = async event => { // Define the URL that you want the user to be directed to after verification is complete if (event.triggerSource === 'CustomMessage_SignUp') { const { codeParameter } = event.request; @@ -26,7 +26,7 @@ exports.handler = (event, context, callback) => { redirectUrl, region, clientId, - }) + }), ).toString('base64'); const bucketUrl = `http://${resourcePrefix}verificationbucket-${process.env.ENV}.s3-website${seperator}${region}.amazonaws.com`; const url = `${bucketUrl}/?data=${payload}&code=${codeParameter}`; @@ -35,8 +35,7 @@ exports.handler = (event, context, callback) => { event.response.emailSubject = process.env.EMAILSUBJECT; event.response.emailMessage = message; console.log('event.response', event.response); - callback(null, event); - } else { - callback(null, event); } + + return event; }; diff --git a/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/DefineAuthChallenge/boilerplate-define-challenge.js b/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/DefineAuthChallenge/boilerplate-define-challenge.js index 9acf23986f8..77ed08c72c4 100644 --- a/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/DefineAuthChallenge/boilerplate-define-challenge.js +++ b/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/DefineAuthChallenge/boilerplate-define-challenge.js @@ -1,4 +1,4 @@ -exports.handler = (event, context) => { +exports.handler = async event => { if (event.request.session.length === 1 && event.request.session[0].challengeName === 'SRP_A') { event.response.issueTokens = false; event.response.failAuthentication = false; @@ -22,5 +22,6 @@ exports.handler = (event, context) => { event.response.issueTokens = false; event.response.failAuthentication = true; } - context.done(null, event); + + return event; }; diff --git a/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/DefineAuthChallenge/captcha-define-challenge.js b/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/DefineAuthChallenge/captcha-define-challenge.js index 9acf23986f8..77ed08c72c4 100644 --- a/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/DefineAuthChallenge/captcha-define-challenge.js +++ b/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/DefineAuthChallenge/captcha-define-challenge.js @@ -1,4 +1,4 @@ -exports.handler = (event, context) => { +exports.handler = async event => { if (event.request.session.length === 1 && event.request.session[0].challengeName === 'SRP_A') { event.response.issueTokens = false; event.response.failAuthentication = false; @@ -22,5 +22,6 @@ exports.handler = (event, context) => { event.response.issueTokens = false; event.response.failAuthentication = true; } - context.done(null, event); + + return event; }; diff --git a/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/DefineAuthChallenge/cloudformation-templates/DefineAuthChallenge.json.ejs b/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/DefineAuthChallenge/cloudformation-templates/DefineAuthChallenge.json.ejs index bf2d3a67518..991545d6c69 100644 --- a/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/DefineAuthChallenge/cloudformation-templates/DefineAuthChallenge.json.ejs +++ b/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/DefineAuthChallenge/cloudformation-templates/DefineAuthChallenge.json.ejs @@ -5,7 +5,7 @@ "modules": { "Type": "String", "Default": "", - "Description": "Comma-delimmited list of modules to be executed by a lambda trigger. Sent to resource as an env variable." + "Description": "Comma-delimited list of modules to be executed by a lambda trigger. Sent to resource as an env variable." }, "resourceName": { "Type": "String", @@ -98,7 +98,7 @@ }, "Role": { "Fn::GetAtt" : ["LambdaExecutionRole", "Arn"] }, "Runtime": "nodejs14.x", - "Timeout": "25" + "Timeout": 25 } }, "LambdaExecutionRole": { diff --git a/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/DefineAuthChallenge/function-template-dir/trigger-index.js b/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/DefineAuthChallenge/function-template-dir/trigger-index.js deleted file mode 100644 index 80c77ea4e38..00000000000 --- a/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/DefineAuthChallenge/function-template-dir/trigger-index.js +++ /dev/null @@ -1,14 +0,0 @@ -/* - this file will loop through all js modules which are uploaded to the lambda resource, - provided that the file names (without extension) are included in the "MODULES" env variable. - "MODULES" is a comma-delimmited string. -*/ -const moduleNames = process.env.MODULES.split(','); -const modules = moduleNames.map(name => require(`./${name}`)); - -exports.handler = (event, context, callback) => { - for (let i = 0; i < modules.length; i += 1) { - const { handler } = modules[i]; - handler(event, context, callback); - } -}; diff --git a/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/PostAuthentication/cloudformation-templates/PostAuthentication.json.ejs b/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/PostAuthentication/cloudformation-templates/PostAuthentication.json.ejs index bf2d3a67518..991545d6c69 100644 --- a/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/PostAuthentication/cloudformation-templates/PostAuthentication.json.ejs +++ b/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/PostAuthentication/cloudformation-templates/PostAuthentication.json.ejs @@ -5,7 +5,7 @@ "modules": { "Type": "String", "Default": "", - "Description": "Comma-delimmited list of modules to be executed by a lambda trigger. Sent to resource as an env variable." + "Description": "Comma-delimited list of modules to be executed by a lambda trigger. Sent to resource as an env variable." }, "resourceName": { "Type": "String", @@ -98,7 +98,7 @@ }, "Role": { "Fn::GetAtt" : ["LambdaExecutionRole", "Arn"] }, "Runtime": "nodejs14.x", - "Timeout": "25" + "Timeout": 25 } }, "LambdaExecutionRole": { diff --git a/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/PostAuthentication/function-template-dir/trigger-index.js b/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/PostAuthentication/function-template-dir/trigger-index.js deleted file mode 100644 index 80c77ea4e38..00000000000 --- a/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/PostAuthentication/function-template-dir/trigger-index.js +++ /dev/null @@ -1,14 +0,0 @@ -/* - this file will loop through all js modules which are uploaded to the lambda resource, - provided that the file names (without extension) are included in the "MODULES" env variable. - "MODULES" is a comma-delimmited string. -*/ -const moduleNames = process.env.MODULES.split(','); -const modules = moduleNames.map(name => require(`./${name}`)); - -exports.handler = (event, context, callback) => { - for (let i = 0; i < modules.length; i += 1) { - const { handler } = modules[i]; - handler(event, context, callback); - } -}; diff --git a/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/PostConfirmation/add-to-group.js b/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/PostConfirmation/add-to-group.js index c33dca12fc1..b3cd62cd3a8 100644 --- a/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/PostConfirmation/add-to-group.js +++ b/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/PostConfirmation/add-to-group.js @@ -1,34 +1,31 @@ /* eslint-disable-line */ const aws = require('aws-sdk'); -exports.handler = async (event, context) => { - const cognitoidentityserviceprovider = new aws.CognitoIdentityServiceProvider({ apiVersion: '2016-04-18' }); +const cognitoidentityserviceprovider = new aws.CognitoIdentityServiceProvider({ + apiVersion: '2016-04-18', +}); + +exports.handler = async event => { const groupParams = { GroupName: process.env.GROUP, UserPoolId: event.userPoolId, }; - const addUserParams = { GroupName: process.env.GROUP, UserPoolId: event.userPoolId, Username: event.userName, }; - + /** + * Check if the group exists; if it doesn't, create it. + */ try { await cognitoidentityserviceprovider.getGroup(groupParams).promise(); } catch (e) { await cognitoidentityserviceprovider.createGroup(groupParams).promise(); } + /** + * Then, add the user to the group. + */ + await cognitoidentityserviceprovider.adminAddUserToGroup(addUserParams).promise(); - try { - await cognitoidentityserviceprovider.adminAddUserToGroup(addUserParams).promise(); - return { - statusCode: 200, - body: JSON.stringify(event) - } - } catch (error) { - return { - statusCode: 500, - body: JSON.stringify(error) - } - } + return event; }; diff --git a/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/PostConfirmation/cloudformation-templates/PostConfirmation.json.ejs b/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/PostConfirmation/cloudformation-templates/PostConfirmation.json.ejs index f9a9b06daf9..fca77a152e7 100644 --- a/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/PostConfirmation/cloudformation-templates/PostConfirmation.json.ejs +++ b/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/PostConfirmation/cloudformation-templates/PostConfirmation.json.ejs @@ -9,7 +9,7 @@ "modules": { "Type": "String", "Default": "", - "Description": "Comma-delimmited list of modules to be executed by a lambda trigger. Sent to resource as an env variable." + "Description": "Comma-delimited list of modules to be executed by a lambda trigger. Sent to resource as an env variable." }, "resourceName": { "Type": "String", @@ -105,7 +105,7 @@ }, "Role": { "Fn::GetAtt" : ["LambdaExecutionRole", "Arn"] }, "Runtime": "nodejs14.x", - "Timeout": "25" + "Timeout": 25 } }, "LambdaExecutionRole": { diff --git a/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/PostConfirmation/function-template-dir/trigger-index.js b/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/PostConfirmation/function-template-dir/trigger-index.js deleted file mode 100644 index 80c77ea4e38..00000000000 --- a/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/PostConfirmation/function-template-dir/trigger-index.js +++ /dev/null @@ -1,14 +0,0 @@ -/* - this file will loop through all js modules which are uploaded to the lambda resource, - provided that the file names (without extension) are included in the "MODULES" env variable. - "MODULES" is a comma-delimmited string. -*/ -const moduleNames = process.env.MODULES.split(','); -const modules = moduleNames.map(name => require(`./${name}`)); - -exports.handler = (event, context, callback) => { - for (let i = 0; i < modules.length; i += 1) { - const { handler } = modules[i]; - handler(event, context, callback); - } -}; diff --git a/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/PreAuthentication/cloudformation-templates/PreAuthentication.json.ejs b/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/PreAuthentication/cloudformation-templates/PreAuthentication.json.ejs index ecd55ce47f3..aa2b6770e09 100644 --- a/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/PreAuthentication/cloudformation-templates/PreAuthentication.json.ejs +++ b/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/PreAuthentication/cloudformation-templates/PreAuthentication.json.ejs @@ -5,7 +5,7 @@ "modules": { "Type": "String", "Default": "", - "Description": "Comma-delimmited list of modules to be executed by a lambda trigger. Sent to resource as an env variable." + "Description": "Comma-delimited list of modules to be executed by a lambda trigger. Sent to resource as an env variable." }, "resourceName": { "Type": "String", @@ -98,7 +98,7 @@ }, "Role": { "Fn::GetAtt" : ["LambdaExecutionRole", "Arn"] }, "Runtime": "nodejs14.x", - "Timeout": "25" + "Timeout": 25 } }, "LambdaExecutionRole": { diff --git a/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/PreAuthentication/function-template-dir/trigger-index.js b/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/PreAuthentication/function-template-dir/trigger-index.js deleted file mode 100644 index 80c77ea4e38..00000000000 --- a/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/PreAuthentication/function-template-dir/trigger-index.js +++ /dev/null @@ -1,14 +0,0 @@ -/* - this file will loop through all js modules which are uploaded to the lambda resource, - provided that the file names (without extension) are included in the "MODULES" env variable. - "MODULES" is a comma-delimmited string. -*/ -const moduleNames = process.env.MODULES.split(','); -const modules = moduleNames.map(name => require(`./${name}`)); - -exports.handler = (event, context, callback) => { - for (let i = 0; i < modules.length; i += 1) { - const { handler } = modules[i]; - handler(event, context, callback); - } -}; diff --git a/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/PreSignup/cloudformation-templates/PreSignup.json.ejs b/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/PreSignup/cloudformation-templates/PreSignup.json.ejs index 958ceff1f78..a03baf5ae2f 100644 --- a/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/PreSignup/cloudformation-templates/PreSignup.json.ejs +++ b/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/PreSignup/cloudformation-templates/PreSignup.json.ejs @@ -13,7 +13,7 @@ "modules": { "Type": "String", "Default": "", - "Description": "Comma-delimmited list of modules to be executed by a lambda trigger. Sent to resource as an env variable." + "Description": "Comma-delimited list of modules to be executed by a lambda trigger. Sent to resource as an env variable." }, "resourceName": { "Type": "String", @@ -112,7 +112,7 @@ }, "Role": { "Fn::GetAtt" : ["LambdaExecutionRole", "Arn"] }, "Runtime": "nodejs14.x", - "Timeout": "25" + "Timeout": 25 } }, "LambdaExecutionRole": { diff --git a/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/PreSignup/email-filter-allowlist-legacy.js b/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/PreSignup/email-filter-allowlist-legacy.js index dc937d2d9c9..1e2873aeffa 100644 --- a/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/PreSignup/email-filter-allowlist-legacy.js +++ b/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/PreSignup/email-filter-allowlist-legacy.js @@ -1,4 +1,4 @@ -exports.handler = (event, context, callback) => { +exports.handler = async event => { // allowed domains const ald = process.env.DOMAINWHITELIST.split(',').map(d => d.trim()); @@ -6,8 +6,8 @@ exports.handler = (event, context, callback) => { const domain = email.substring(email.indexOf('@') + 1); if (!ald.includes(domain)) { - callback(new Error(`Invalid email domain: ${domain}`), event); - } else { - callback(null, event); + throw new Error(`Invalid email domain: ${domain}`); } + + return event; }; diff --git a/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/PreSignup/email-filter-allowlist.js b/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/PreSignup/email-filter-allowlist.js index 0f5eb4ad7a8..dc5b9e7b882 100644 --- a/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/PreSignup/email-filter-allowlist.js +++ b/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/PreSignup/email-filter-allowlist.js @@ -1,4 +1,4 @@ -exports.handler = (event, context, callback) => { +exports.handler = async event => { // allowed domains const ald = process.env.DOMAINALLOWLIST.split(',').map(d => d.trim()); @@ -6,8 +6,8 @@ exports.handler = (event, context, callback) => { const domain = email.substring(email.indexOf('@') + 1); if (!ald.includes(domain)) { - callback(new Error(`Invalid email domain: ${domain}`), event); - } else { - callback(null, event); + throw new Error(`Invalid email domain: ${domain}`); } + + return event; }; diff --git a/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/PreSignup/email-filter-denylist-legacy.js b/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/PreSignup/email-filter-denylist-legacy.js index ee976c5ebc5..fea04763e6b 100644 --- a/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/PreSignup/email-filter-denylist-legacy.js +++ b/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/PreSignup/email-filter-denylist-legacy.js @@ -1,4 +1,4 @@ -exports.handler = (event, context, callback) => { +exports.handler = async event => { // disallowed domains const dld = process.env.DOMAINBLACKLIST.split(',').map(d => d.trim()); @@ -6,8 +6,8 @@ exports.handler = (event, context, callback) => { const domain = email.substring(email.indexOf('@') + 1); if (dld.includes(domain)) { - callback(new Error(`Invalid email domain: ${domain}`), event); - } else { - callback(null, event); + throw new Error(`Invalid email domain: ${domain}`); } + + return event; }; diff --git a/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/PreSignup/email-filter-denylist.js b/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/PreSignup/email-filter-denylist.js index 034e2e74e3f..49fe4248f84 100644 --- a/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/PreSignup/email-filter-denylist.js +++ b/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/PreSignup/email-filter-denylist.js @@ -1,4 +1,4 @@ -exports.handler = (event, context, callback) => { +exports.handler = async event => { // disallowed domains const dld = process.env.DOMAINDENYLIST.split(',').map(d => d.trim()); @@ -6,8 +6,8 @@ exports.handler = (event, context, callback) => { const domain = email.substring(email.indexOf('@') + 1); if (dld.includes(domain)) { - callback(new Error(`Invalid email domain: ${domain}`), event); - } else { - callback(null, event); + throw new Error(`Invalid email domain: ${domain}`); } + + return event; }; diff --git a/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/PreSignup/function-template-dir/trigger-index.js b/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/PreSignup/function-template-dir/trigger-index.js deleted file mode 100644 index 80c77ea4e38..00000000000 --- a/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/PreSignup/function-template-dir/trigger-index.js +++ /dev/null @@ -1,14 +0,0 @@ -/* - this file will loop through all js modules which are uploaded to the lambda resource, - provided that the file names (without extension) are included in the "MODULES" env variable. - "MODULES" is a comma-delimmited string. -*/ -const moduleNames = process.env.MODULES.split(','); -const modules = moduleNames.map(name => require(`./${name}`)); - -exports.handler = (event, context, callback) => { - for (let i = 0; i < modules.length; i += 1) { - const { handler } = modules[i]; - handler(event, context, callback); - } -}; diff --git a/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/PreTokenGeneration/alter-claims.js b/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/PreTokenGeneration/alter-claims.js index 28427fd51b4..9f9d0f4ce4f 100644 --- a/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/PreTokenGeneration/alter-claims.js +++ b/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/PreTokenGeneration/alter-claims.js @@ -1,4 +1,4 @@ -exports.handler = async (event, context, callback) => { +exports.handler = async event => { event.response = { claimsOverrideDetails: { claimsToAddOrOverride: { @@ -9,5 +9,5 @@ exports.handler = async (event, context, callback) => { }, }; // Return to Amazon Cognito - callback(null, event); + return event; }; diff --git a/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/PreTokenGeneration/cloudformation-templates/PreTokenGeneration.json.ejs b/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/PreTokenGeneration/cloudformation-templates/PreTokenGeneration.json.ejs index ecd55ce47f3..aa2b6770e09 100644 --- a/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/PreTokenGeneration/cloudformation-templates/PreTokenGeneration.json.ejs +++ b/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/PreTokenGeneration/cloudformation-templates/PreTokenGeneration.json.ejs @@ -5,7 +5,7 @@ "modules": { "Type": "String", "Default": "", - "Description": "Comma-delimmited list of modules to be executed by a lambda trigger. Sent to resource as an env variable." + "Description": "Comma-delimited list of modules to be executed by a lambda trigger. Sent to resource as an env variable." }, "resourceName": { "Type": "String", @@ -98,7 +98,7 @@ }, "Role": { "Fn::GetAtt" : ["LambdaExecutionRole", "Arn"] }, "Runtime": "nodejs14.x", - "Timeout": "25" + "Timeout": 25 } }, "LambdaExecutionRole": { diff --git a/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/PreTokenGeneration/function-template-dir/trigger-index.js b/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/PreTokenGeneration/function-template-dir/trigger-index.js deleted file mode 100644 index 80c77ea4e38..00000000000 --- a/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/PreTokenGeneration/function-template-dir/trigger-index.js +++ /dev/null @@ -1,14 +0,0 @@ -/* - this file will loop through all js modules which are uploaded to the lambda resource, - provided that the file names (without extension) are included in the "MODULES" env variable. - "MODULES" is a comma-delimmited string. -*/ -const moduleNames = process.env.MODULES.split(','); -const modules = moduleNames.map(name => require(`./${name}`)); - -exports.handler = (event, context, callback) => { - for (let i = 0; i < modules.length; i += 1) { - const { handler } = modules[i]; - handler(event, context, callback); - } -}; diff --git a/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/VerifyAuthChallengeResponse/boilerplate-verify.js b/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/VerifyAuthChallengeResponse/boilerplate-verify.js index 000a95ad10c..3134d85336f 100644 --- a/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/VerifyAuthChallengeResponse/boilerplate-verify.js +++ b/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/VerifyAuthChallengeResponse/boilerplate-verify.js @@ -1,8 +1,9 @@ -exports.handler = (event, context) => { +exports.handler = async event => { if (event.request.privateChallengeParameters.answer === event.request.challengeAnswer) { event.response.answerCorrect = true; } else { event.response.answerCorrect = false; } - context.done(null, event); + + return event; }; diff --git a/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/VerifyAuthChallengeResponse/captcha-verify.js b/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/VerifyAuthChallengeResponse/captcha-verify.js index 06cb4601928..9ad349e0db7 100644 --- a/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/VerifyAuthChallengeResponse/captcha-verify.js +++ b/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/VerifyAuthChallengeResponse/captcha-verify.js @@ -2,23 +2,23 @@ const axios = require('axios'); /* eslint-enable */ -exports.handler = (event, context, callback) => { - axios - .post( - `https://www.google.com/recaptcha/api/siteverify?secret=${process.env.RECAPTCHASECRET}&response=${event.request.challengeAnswer}`, - {} - ) - .then(response => { - if (response && response.data && response.data.success) { - event.response.answerCorrect = true; - callback(null, event); - } else { - event.response.answerCorrect = false; - callback(new Error('captcha verification error'), event); - } - }) - .catch(() => { - event.response.answerCorrect = false; - callback(new Error('captcha verification error'), event); - }); +exports.handler = async event => { + const response = await axios.post( + `https://www.google.com/recaptcha/api/siteverify?secret=${process.env.RECAPTCHASECRET}&response=${event.request.challengeAnswer}`, + {}, + ); + /** + * Verify that the CAPTCHA challenge succeeded, and if it did, indicate so in + * the event response. + * + * If the challenge fails, throw an error. + */ + const challengeSucceeded = response && response.data && response.data.success; + event.response.answerCorrect = !!challengeSucceeded; + + if (!challengeSucceeded) { + throw new Error('CAPTCHA verification error'); + } + + return event; }; diff --git a/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/VerifyAuthChallengeResponse/cloudformation-templates/VerifyAuthChallengeResponse.json.ejs b/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/VerifyAuthChallengeResponse/cloudformation-templates/VerifyAuthChallengeResponse.json.ejs index 80d0203a9df..5fe23b58324 100644 --- a/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/VerifyAuthChallengeResponse/cloudformation-templates/VerifyAuthChallengeResponse.json.ejs +++ b/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/VerifyAuthChallengeResponse/cloudformation-templates/VerifyAuthChallengeResponse.json.ejs @@ -9,7 +9,7 @@ "modules": { "Type": "String", "Default": "", - "Description": "Comma-delimmited list of modules to be executed by a lambda trigger. Sent to resource as an env variable." + "Description": "Comma-delimited list of modules to be executed by a lambda trigger. Sent to resource as an env variable." }, "resourceName": { "Type": "String", @@ -106,7 +106,7 @@ }, "Role": { "Fn::GetAtt" : ["LambdaExecutionRole", "Arn"] }, "Runtime": "nodejs14.x", - "Timeout": "25" + "Timeout": 25 } }, "LambdaExecutionRole": { diff --git a/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/VerifyAuthChallengeResponse/function-template-dir/trigger-index.js b/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/VerifyAuthChallengeResponse/function-template-dir/trigger-index.js deleted file mode 100644 index 80c77ea4e38..00000000000 --- a/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/VerifyAuthChallengeResponse/function-template-dir/trigger-index.js +++ /dev/null @@ -1,14 +0,0 @@ -/* - this file will loop through all js modules which are uploaded to the lambda resource, - provided that the file names (without extension) are included in the "MODULES" env variable. - "MODULES" is a comma-delimmited string. -*/ -const moduleNames = process.env.MODULES.split(','); -const modules = moduleNames.map(name => require(`./${name}`)); - -exports.handler = (event, context, callback) => { - for (let i = 0; i < modules.length; i += 1) { - const { handler } = modules[i]; - handler(event, context, callback); - } -}; diff --git a/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/function-template-dir/trigger-index.js b/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/function-template-dir/trigger-index.js new file mode 100644 index 00000000000..f9854bb863a --- /dev/null +++ b/packages/amplify-category-auth/provider-utils/awscloudformation/triggers/function-template-dir/trigger-index.js @@ -0,0 +1,39 @@ +/** + * @fileoverview + * + * This CloudFormation Trigger creates a handler which awaits the other handlers + * specified in the `MODULES` env var, located at `./${MODULE}`. + */ + +/** + * The names of modules to load are stored as a comma-delimited string in the + * `MODULES` env var. + */ +const moduleNames = process.env.MODULES.split(','); +/** + * The array of imported modules. + */ +const modules = moduleNames.map(name => require(`./${name}`)); + +/** + * This async handler iterates over the given modules and awaits them. + * + * @see https://docs.aws.amazon.com/lambda/latest/dg/nodejs-handler.html#nodejs-handler-async + * + * @param {object} event + * + * The event that triggered this Lambda. + * + * @returns + * + * The handler response. + */ +exports.handler = async event => { + /** + * Instead of naively iterating over all handlers, run them concurrently with + * `await Promise.all(...)`. This would otherwise just be determined by the + * order of names in the `MODULES` var. + */ + await Promise.all(modules.map(module => module.handler(event))); + return event; +}; diff --git a/packages/amplify-category-auth/resources/adminAuth/admin-queries-function-template.json.ejs b/packages/amplify-category-auth/resources/adminAuth/admin-queries-function-template.json.ejs index 38d6af83ed1..484f96c06b9 100644 --- a/packages/amplify-category-auth/resources/adminAuth/admin-queries-function-template.json.ejs +++ b/packages/amplify-category-auth/resources/adminAuth/admin-queries-function-template.json.ejs @@ -66,7 +66,7 @@ }, "Role": { "Fn::GetAtt" : ["LambdaExecutionRole", "Arn"] }, "Runtime": "nodejs14.x", - "Timeout": "25" + "Timeout": 25 } }, "LambdaExecutionRole": { diff --git a/packages/amplify-category-auth/resources/cloudformation-templates/auth-template.yml.ejs b/packages/amplify-category-auth/resources/cloudformation-templates/auth-template.yml.ejs index a6b89c10c56..2b0e184271c 100644 --- a/packages/amplify-category-auth/resources/cloudformation-templates/auth-template.yml.ejs +++ b/packages/amplify-category-auth/resources/cloudformation-templates/auth-template.yml.ejs @@ -1,3 +1,4 @@ +<% var autoVerifiedAttributes = props.autoVerifiedAttributes ? props.autoVerifiedAttributes.concat(props.aliasAttributes).filter((attr, i, aliasAttributeArray) => ['email', 'phone_number'].includes(attr) && aliasAttributeArray.indexOf(attr) === i) : [] %> AWSTemplateFormatVersion: 2010-09-09 Parameters: @@ -157,10 +158,13 @@ Resources: VerifyAuthChallengeResponse: !Ref function<%=props.resourceName%>VerifyAuthChallengeResponseArn <% } %> <% } %> - <%if (props.autoVerifiedAttributes && props.autoVerifiedAttributes.length > 0) { %> - AutoVerifiedAttributes: !Ref autoVerifiedAttributes + <%if (autoVerifiedAttributes && autoVerifiedAttributes.length > 0) { %> + AutoVerifiedAttributes: + <% for(let x = 0; x < autoVerifiedAttributes.length; x++) { %> + - <%= autoVerifiedAttributes[x] %> <% } %> - <%if (props.autoVerifiedAttributes.includes('email')) { %> + <% } %> + <%if (autoVerifiedAttributes && autoVerifiedAttributes.includes('email')) { %> EmailVerificationMessage: !Ref emailVerificationMessage EmailVerificationSubject: !Ref emailVerificationSubject <% } %> @@ -174,6 +178,9 @@ Resources: <% if (props.usernameAttributes && props.usernameAttributes !== 'username') { %> UsernameAttributes: !Ref usernameAttributes <% } %> + <% if (props.aliasAttributes && props.aliasAttributes.length > 0) { %> + AliasAttributes: !Ref aliasAttributes + <% } %> MfaConfiguration: !Ref mfaConfiguration SmsVerificationMessage: !Ref smsVerificationMessage SmsAuthenticationMessage: !Ref smsAuthenticationMessage @@ -382,7 +389,7 @@ Resources: - '};' Handler: index.handler Runtime: nodejs12.x - Timeout: '300' + Timeout: 300 Role: !GetAtt - UserPoolClientRole - Arn @@ -508,7 +515,7 @@ Resources: Handler: index.handler Runtime: nodejs12.x - Timeout: '300' + Timeout: 300 Role: !GetAtt - UserPoolClientRole - Arn @@ -594,13 +601,17 @@ Resources: - ' AttributeMapping: providerMeta.AttributeMapping,' - ' };' - ' if (providerMeta.ProviderName === ''SignInWithApple'') {' - - ' requestParams.ProviderDetails = {' - - ' ''client_id'': providerCreds.client_id,' - - ' ''team_id'': providerCreds.team_id,' - - ' ''key_id'': providerCreds.key_id,' - - ' ''private_key'': providerCreds.private_key,' - - ' ''authorize_scopes'': providerMeta.authorize_scopes,' - - ' };' + - ' if (providerCreds.client_id && providerCreds.team_id && providerCreds.key_id && providerCreds.private_key) {' + - ' requestParams.ProviderDetails = {' + - ' ''client_id'': providerCreds.client_id,' + - ' ''team_id'': providerCreds.team_id,' + - ' ''key_id'': providerCreds.key_id,' + - ' ''private_key'': providerCreds.private_key,' + - ' ''authorize_scopes'': providerMeta.authorize_scopes,' + - ' };' + - ' } else {' + - ' requestParams = null;' + - ' }' - ' } else {' - ' requestParams.ProviderDetails = {' - ' ''client_id'': providerCreds.client_id,' @@ -612,11 +623,17 @@ Resources: - ' };' - ' let createIdentityProvider = (providerName) => {' - ' let requestParams = getRequestParams(providerName);' + - ' if (!requestParams) {' + - ' return Promise.resolve();' + - ' }' - ' requestParams.ProviderType = requestParams.ProviderName;' - ' return identity.createIdentityProvider(requestParams).promise();' - ' };' - ' let updateIdentityProvider = (providerName) => {' - ' let requestParams = getRequestParams(providerName);' + - ' if (!requestParams) {' + - ' return Promise.resolve();' + - ' }' - ' return identity.updateIdentityProvider(requestParams).promise();' - ' };' - ' let deleteIdentityProvider = (providerName) => {' @@ -650,7 +667,7 @@ Resources: Handler: index.handler Runtime: nodejs12.x - Timeout: '300' + Timeout: 300 Role: !GetAtt - UserPoolClientRole - Arn @@ -749,7 +766,7 @@ Resources: Handler: index.handler Runtime: nodejs12.x - Timeout: '300' + Timeout: 300 Role: !GetAtt - UserPoolClientRole - Arn @@ -826,6 +843,15 @@ Resources: Action: - 'iam:PassRole' Resource: !If [ShouldNotCreateEnvResources, '<%= `arn:aws:iam:::role/${props.resourceNameTruncated}_totp_lambda_role`%>', !Join ['',['<%= `arn:aws:iam:::role/${props.resourceNameTruncated}_totp_lambda_role` %>', '-', !Ref env]]] + - PolicyName: <%=`${props.resourceNameTruncated}_sns_pass_role_policy`%> + PolicyDocument: + Version: 2012-10-17 + Statement: + - Effect: Allow + Action: + - 'iam:PassRole' + Resource: !GetAtt SNSRole.Arn + DependsOn: SNSRole MFALambda: # Lambda which sets MFA config values # Depends on MFALambdaRole for role ARN @@ -870,7 +896,7 @@ Resources: - '};' Handler: index.handler Runtime: nodejs12.x - Timeout: '300' + Timeout: 300 Role: !GetAtt - MFALambdaRole - Arn @@ -1030,7 +1056,7 @@ Resources: - '};' Handler: index.handler Runtime: nodejs12.x - Timeout: '300' + Timeout: 300 Role: !GetAtt - OpenIdLambdaRole - Arn diff --git a/packages/amplify-category-auth/resources/cloudformation-templates/user-pool-group-template.json.ejs b/packages/amplify-category-auth/resources/cloudformation-templates/user-pool-group-template.json.ejs index 2a5e1d94023..0ce7619cb4e 100644 --- a/packages/amplify-category-auth/resources/cloudformation-templates/user-pool-group-template.json.ejs +++ b/packages/amplify-category-auth/resources/cloudformation-templates/user-pool-group-template.json.ejs @@ -249,7 +249,7 @@ }, "Handler": "index.handler", "Runtime": "nodejs12.x", - "Timeout": "300", + "Timeout": 300, "Role": { "Fn::GetAtt": [ "LambdaExecutionRole", diff --git a/packages/amplify-category-auth/src/__tests__/provider-utils/awscloudformation/utils/__snapshots__/auth-request-adaptor.test.ts.snap b/packages/amplify-category-auth/src/__tests__/provider-utils/awscloudformation/utils/__snapshots__/auth-request-adaptor.test.ts.snap index 051d1dcd94f..416409f0d9d 100644 --- a/packages/amplify-category-auth/src/__tests__/provider-utils/awscloudformation/utils/__snapshots__/auth-request-adaptor.test.ts.snap +++ b/packages/amplify-category-auth/src/__tests__/provider-utils/awscloudformation/utils/__snapshots__/auth-request-adaptor.test.ts.snap @@ -4,6 +4,42 @@ exports[`get add auth request adaptor valid translations translates request with Object { "adminQueries": false, "adminQueryGroup": undefined, + "aliasAttributes": Array [], + "authProviders": Array [], + "authSelections": "userPoolOnly", + "autoVerifiedAttributes": Array [], + "identityPoolName": undefined, + "mfaConfiguration": "OFF", + "requiredAttributes": Array [ + "email", + ], + "resourceName": "myTestAuth", + "serviceName": "Cognito", + "thirdPartyAuth": false, + "updateFlow": "manual", + "useDefault": "manual", + "userPoolGroupList": Array [], + "userPoolGroups": false, + "userPoolName": undefined, + "usernameAttributes": Array [ + "email", + ], + "userpoolClientReadAttributes": Array [], + "userpoolClientRefreshTokenValidity": undefined, + "userpoolClientWriteAttributes": Array [], +} +`; + + +exports[`get add auth request adaptor translates request with aliasAttributes 1`] = ` +Object { + "adminQueries": false, + "adminQueryGroup": undefined, + "aliasAttributes": Array [ + "email", + "phone_number", + "preferred_username", + ], "authProviders": Array [], "authSelections": "userPoolOnly", "autoVerifiedAttributes": Array [], diff --git a/packages/amplify-category-auth/src/__tests__/provider-utils/awscloudformation/utils/auth-request-adaptor.test.ts b/packages/amplify-category-auth/src/__tests__/provider-utils/awscloudformation/utils/auth-request-adaptor.test.ts index 45ae10ee531..a88463505c5 100644 --- a/packages/amplify-category-auth/src/__tests__/provider-utils/awscloudformation/utils/auth-request-adaptor.test.ts +++ b/packages/amplify-category-auth/src/__tests__/provider-utils/awscloudformation/utils/auth-request-adaptor.test.ts @@ -1,4 +1,10 @@ -import { AddAuthRequest, CognitoUserPoolSigninMethod, CognitoUserProperty, UpdateAuthRequest } from 'amplify-headless-interface'; +import { + AddAuthRequest, + CognitoUserAliasAttributes, + CognitoUserPoolSigninMethod, + CognitoUserProperty, + UpdateAuthRequest, +} from 'amplify-headless-interface'; import { getAddAuthRequestAdaptor, getUpdateAuthRequestAdaptor, @@ -23,6 +29,27 @@ describe('get add auth request adaptor', () => { expect(getAddAuthRequestAdaptor('javascript')(addAuthRequest)).toMatchSnapshot(); }); }); + it('translates request with aliasAttributes', () => { + const addAuthRequest: AddAuthRequest = { + version: 1, + resourceName: 'myTestAuth', + serviceConfiguration: { + serviceName: 'Cognito', + userPoolConfiguration: { + signinMethod: CognitoUserPoolSigninMethod.EMAIL, + requiredSignupAttributes: [CognitoUserProperty.EMAIL], + aliasAttributes: [ + CognitoUserAliasAttributes.EMAIL, + CognitoUserAliasAttributes.PHONE_NUMBER, + CognitoUserAliasAttributes.PREFERRED_USERNAME, + ], + }, + includeIdentityPool: false, + }, + }; + + expect(getAddAuthRequestAdaptor('javascript')(addAuthRequest)).toMatchSnapshot(); + }); }); describe('get update auth request adaptor', () => { diff --git a/packages/amplify-category-auth/src/__tests__/provider-utils/awscloudformation/utils/auth-sms-workflow-helper.test.ts b/packages/amplify-category-auth/src/__tests__/provider-utils/awscloudformation/utils/auth-sms-workflow-helper.test.ts index cff1740d672..45e9fb31ae6 100644 --- a/packages/amplify-category-auth/src/__tests__/provider-utils/awscloudformation/utils/auth-sms-workflow-helper.test.ts +++ b/packages/amplify-category-auth/src/__tests__/provider-utils/awscloudformation/utils/auth-sms-workflow-helper.test.ts @@ -1,4 +1,4 @@ -import { ServiceQuestionsResult } from '../../../../provider-utils/awscloudformation/service-walkthrough-types'; +import { ServiceQuestionsResult, AttributeType } from '../../../../provider-utils/awscloudformation/service-walkthrough-types'; import { doesConfigurationIncludeSMS } from '../../../../provider-utils/awscloudformation/utils/auth-sms-workflow-helper'; describe('doesConfigurationIncludeSMS', () => { @@ -47,17 +47,17 @@ describe('doesConfigurationIncludeSMS', () => { }); it('should return true when userNameAttribute contains phone number', () => { - request.usernameAttributes = ['phone_number']; + request.usernameAttributes = [AttributeType.PHONE_NUMBER]; expect(doesConfigurationIncludeSMS(request)).toBeTruthy(); }); it('should return true when userNameAttribute contains phone number', () => { - request.usernameAttributes = ['email, phone_number'] as any; + request.usernameAttributes = [AttributeType.EMAIL, AttributeType.PHONE_NUMBER] as any; expect(doesConfigurationIncludeSMS(request)).toBeTruthy(); }); it('should return false when username attribute does not contain phone number', () => { - request.usernameAttributes = ['email'] as any; + request.usernameAttributes = [AttributeType.EMAIL] as any; expect(doesConfigurationIncludeSMS(request)).toBeFalsy(); }); }); diff --git a/packages/amplify-category-auth/src/__tests__/provider-utils/awscloudformation/utils/message-printer.test.ts b/packages/amplify-category-auth/src/__tests__/provider-utils/awscloudformation/utils/message-printer.test.ts index 84a01121ca1..d6bbaee837c 100644 --- a/packages/amplify-category-auth/src/__tests__/provider-utils/awscloudformation/utils/message-printer.test.ts +++ b/packages/amplify-category-auth/src/__tests__/provider-utils/awscloudformation/utils/message-printer.test.ts @@ -1,5 +1,6 @@ import { printSMSSandboxWarning } from '../../../../provider-utils/awscloudformation/utils/message-printer'; import { BannerMessage } from 'amplify-cli-core'; +import os from 'os'; jest.mock('amplify-cli-core'); const printMock = { warning: jest.fn(), @@ -16,7 +17,7 @@ describe('printSMSSandboxWarning', () => { const message = 'BannerMessage'; mockedGetMessage.mockResolvedValueOnce(message); await printSMSSandboxWarning(printMock); - expect(printMock.warning).toHaveBeenCalledWith(`${message}\n`); + expect(printMock.warning).toHaveBeenCalledWith(`${message}${os.EOL}`); expect(mockedGetMessage).toHaveBeenCalledWith('COGNITO_SMS_SANDBOX_CATEGORY_AUTH_ADD_OR_UPDATE_INFO'); }); diff --git a/packages/amplify-category-auth/src/provider-utils/awscloudformation/assets/cognito-defaults.js b/packages/amplify-category-auth/src/provider-utils/awscloudformation/assets/cognito-defaults.js index c89da49dcc3..e94f9450270 100644 --- a/packages/amplify-category-auth/src/provider-utils/awscloudformation/assets/cognito-defaults.js +++ b/packages/amplify-category-auth/src/provider-utils/awscloudformation/assets/cognito-defaults.js @@ -36,6 +36,7 @@ const userPoolDefaults = projectName => { passwordPolicyMinLength: 8, passwordPolicyCharacters: [], requiredAttributes: ['email'], + aliasAttributes: [], userpoolClientGenerateSecret: false, userpoolClientRefreshTokenValidity: 30, userpoolClientWriteAttributes: ['email'], diff --git a/packages/amplify-category-auth/src/provider-utils/awscloudformation/assets/string-maps.js b/packages/amplify-category-auth/src/provider-utils/awscloudformation/assets/string-maps.js index eb752d7c8a7..87a4cde193a 100644 --- a/packages/amplify-category-auth/src/provider-utils/awscloudformation/assets/string-maps.js +++ b/packages/amplify-category-auth/src/provider-utils/awscloudformation/assets/string-maps.js @@ -391,6 +391,22 @@ const coreAttributes = [ }, ]; +const aliasAttributes = [ + { + name: 'Email', + value: 'email', + checked: true, + }, + { + name: 'Username', + value: 'preferred_username', + }, + { + name: 'Phone number', + value: 'phone_number', + }, +]; + const appClientReadAttributes = [ ...coreAttributes, { @@ -601,6 +617,7 @@ const getAllMaps = edit => { disableOptionsOnEdit(); } return { + aliasAttributes, coreAttributes, authSelectionMap, appClientReadAttributes, @@ -624,6 +641,7 @@ const getAllMaps = edit => { }; module.exports = { + aliasAttributes, coreAttributes, appClientReadAttributes, authSelectionMap, diff --git a/packages/amplify-category-auth/src/provider-utils/awscloudformation/import/types.ts b/packages/amplify-category-auth/src/provider-utils/awscloudformation/import/types.ts index a05f3ab1baa..84fea969dec 100644 --- a/packages/amplify-category-auth/src/provider-utils/awscloudformation/import/types.ts +++ b/packages/amplify-category-auth/src/provider-utils/awscloudformation/import/types.ts @@ -1,4 +1,4 @@ -import { $TSContext, $TSObject } from 'amplify-cli-core'; +import { $TSAny, $TSContext, $TSObject } from 'amplify-cli-core'; import { GetUserPoolMfaConfigResponse, IdentityProviderType, @@ -50,6 +50,19 @@ export type MetaOutput = { CreatedSNSRole?: string; }; +export type AuthParameters = { + dependsOn?: $TSAny[]; + triggers?: string; + identityPoolName?: string; + aliasAttributes?: string[]; + authProviders?: string[]; + requiredAttributes?: string[]; + passwordPolicyMinLength?: string; + passwordPolicyCharacters?: string[]; + mfaConfiguration?: string; + mfaTypes?: string[]; +}; + // Persisted into team-provider-info export type EnvSpecificResourceParameters = { userPoolId: string; diff --git a/packages/amplify-category-auth/src/provider-utils/awscloudformation/service-walkthrough-types.ts b/packages/amplify-category-auth/src/provider-utils/awscloudformation/service-walkthrough-types.ts index d27d006cf8c..617e47b9d8d 100644 --- a/packages/amplify-category-auth/src/provider-utils/awscloudformation/service-walkthrough-types.ts +++ b/packages/amplify-category-auth/src/provider-utils/awscloudformation/service-walkthrough-types.ts @@ -94,10 +94,17 @@ export interface PasswordPolicyResult { passwordPolicyMinLength?: number; } +export enum AttributeType { + EMAIL = 'email', + PHONE_NUMBER = 'phone_number', + PREFERRED_USERNAME = 'preferred_username', +} + export type PasswordPolicy = 'Requires Lowercase' | 'Requires Numbers' | 'Requires Symbols' | 'Requires Uppercase'; -export type UsernameAttributes = 'email' | 'phone_number'; +export type UsernameAttributes = AttributeType.EMAIL | AttributeType.PHONE_NUMBER; +export type AliasAttributes = AttributeType.EMAIL | AttributeType.PHONE_NUMBER | AttributeType.PREFERRED_USERNAME; export interface Triggers { triggers?: any; // TODO create a type for this } diff --git a/packages/amplify-category-auth/src/provider-utils/awscloudformation/service-walkthroughs/auth-questions.js b/packages/amplify-category-auth/src/provider-utils/awscloudformation/service-walkthroughs/auth-questions.js index 2ce2e57d05d..b71b3bebf3d 100644 --- a/packages/amplify-category-auth/src/provider-utils/awscloudformation/service-walkthroughs/auth-questions.js +++ b/packages/amplify-category-auth/src/provider-utils/awscloudformation/service-walkthroughs/auth-questions.js @@ -132,6 +132,10 @@ async function serviceWalkthrough(context, defaultValuesFilename, stringMapsFile if (answer.useDefault === 'defaultSocial') { coreAnswers.hostedUI = true; } + + if (answer.useDefault === 'default') { + coreAnswers.hostedUI = false; + } delete answer.updateFlow; } coreAnswers = { ...coreAnswers, ...answer }; diff --git a/packages/amplify-category-auth/src/provider-utils/awscloudformation/utils/amplify-meta-updaters.ts b/packages/amplify-category-auth/src/provider-utils/awscloudformation/utils/amplify-meta-updaters.ts index a60adde2c5c..8f0a2f0ad8a 100644 --- a/packages/amplify-category-auth/src/provider-utils/awscloudformation/utils/amplify-meta-updaters.ts +++ b/packages/amplify-category-auth/src/provider-utils/awscloudformation/utils/amplify-meta-updaters.ts @@ -1,6 +1,9 @@ import * as path from 'path'; -import { JSONUtilities, $TSAny, pathManager } from 'amplify-cli-core'; +import { JSONUtilities, pathManager } from 'amplify-cli-core'; import { transformUserPoolGroupSchema } from './transform-user-pool-group'; +import { authProviders as authProviderList } from '../assets/string-maps'; +import { AuthParameters } from '../import/types'; + /** * Factory function that returns a function that updates Amplify meta files after adding auth resource assets * @@ -16,7 +19,7 @@ export const getPostAddAuthMetaUpdater = (context: any, resultMetadata: { servic providerPlugin: resultMetadata.providerName, }; const parametersJSONPath = path.join(context.amplify.pathManager.getBackendDirPath(), 'auth', resourceName, 'parameters.json'); - const authParameters = JSONUtilities.readJson<{ dependsOn: any[]; triggers: string; identityPoolName: string }>(parametersJSONPath)!; + const authParameters = JSONUtilities.readJson(parametersJSONPath)!; if (authParameters.dependsOn) { options.dependsOn = authParameters.dependsOn; @@ -36,6 +39,7 @@ export const getPostAddAuthMetaUpdater = (context: any, resultMetadata: { servic } options.customAuth = customAuthConfigured; + options.frontendAuthConfig = getFrontendConfig(authParameters); context.amplify.updateamplifyMetaAfterResourceAdd('auth', resourceName, options); @@ -62,7 +66,7 @@ export const getPostAddAuthMetaUpdater = (context: any, resultMetadata: { servic */ export const getPostUpdateAuthMetaUpdater = (context: any) => async (resourceName: string) => { const resourceDirPath = path.join(pathManager.getBackendDirPath(), 'auth', resourceName, 'parameters.json'); - const authParameters = JSONUtilities.readJson<$TSAny>(resourceDirPath); + const authParameters = JSONUtilities.readJson(resourceDirPath)!; if (authParameters.dependsOn) { context.amplify.updateamplifyMetaAfterResourceUpdate('auth', resourceName, 'dependsOn', authParameters.dependsOn); } @@ -79,6 +83,7 @@ export const getPostUpdateAuthMetaUpdater = (context: any) => async (resourceNam triggers.VerifyAuthChallengeResponse.length > 0; } context.amplify.updateamplifyMetaAfterResourceUpdate('auth', resourceName, 'customAuth', customAuthConfigured); + context.amplify.updateamplifyMetaAfterResourceUpdate('auth', resourceName, 'frontendAuthConfig', getFrontendConfig(authParameters)); // Update Identity Pool dependency attributes on userpool groups const allResources = context.amplify.getProjectMeta(); @@ -100,3 +105,44 @@ export const getPostUpdateAuthMetaUpdater = (context: any) => async (resourceNam } return resourceName; }; + +function getFrontendConfig(authParameters: AuthParameters) { + const loginMechanisms: string[] = []; + loginMechanisms.push(...(authParameters?.aliasAttributes || []).map((att: string) => att.toUpperCase())); + + if (authParameters.authProviders) { + authParameters.authProviders.forEach((provider: string) => { + let name = authProviderList.find(it => it.value === provider)?.name; + + if (name) { + loginMechanisms.push(name.toUpperCase()); + } + }); + } + + const signupAttributes = (authParameters?.requiredAttributes || []).map((att: string) => att.toUpperCase()); + + const passwordProtectionSettings = { + passwordPolicyMinLength: authParameters?.passwordPolicyMinLength, + passwordPolicyCharacters: (authParameters?.passwordPolicyCharacters || []).map((i: string) => i.replace(/ /g, '_').toUpperCase()), + }; + + const mfaTypes: string[] = []; + if (authParameters.mfaTypes) { + if (authParameters.mfaTypes.includes('SMS Text Message')) { + mfaTypes.push('SMS'); + } + + if (authParameters.mfaTypes.includes('TOTP')) { + mfaTypes.push('TOTP'); + } + } + + return { + loginMechanisms: loginMechanisms, + signupAttributes: signupAttributes, + passwordProtectionSettings: passwordProtectionSettings, + mfaConfiguration: authParameters?.mfaConfiguration, + mfaTypes: mfaTypes, + }; +} diff --git a/packages/amplify-category-auth/src/provider-utils/awscloudformation/utils/auth-request-adaptors.ts b/packages/amplify-category-auth/src/provider-utils/awscloudformation/utils/auth-request-adaptors.ts index 7a48258e244..73f0562bac3 100644 --- a/packages/amplify-category-auth/src/provider-utils/awscloudformation/utils/auth-request-adaptors.ts +++ b/packages/amplify-category-auth/src/provider-utils/awscloudformation/utils/auth-request-adaptors.ts @@ -1,5 +1,6 @@ import { AddAuthRequest, + CognitoUserAliasAttributes, CognitoUserPoolSigninMethod, CognitoAdminQueries, CognitoMFAConfiguration, @@ -28,6 +29,8 @@ import { PasswordPolicy, PasswordRecoveryResult, UsernameAttributes, + AliasAttributes, + AttributeType, } from '../service-walkthrough-types'; import { pascalCase } from 'change-case'; @@ -75,6 +78,7 @@ const immutableAttributeAdaptor = (userPoolConfig: CognitoUserPoolConfiguration, return { userPoolName: userPoolConfig.userPoolName, usernameAttributes: signinAttributeMap[userPoolConfig.signinMethod], + aliasAttributes: userPoolConfig.aliasAttributes?.map(attr => aliasAttributeMap[attr]) ?? [], ...immutableIdentityPoolMap(identityPoolConfig), }; }; @@ -263,9 +267,15 @@ const mfaTypeMap: Record<'SMS' | 'TOTP', 'SMS Text Message' | 'TOTP'> = { const signinAttributeMap: Record = { [CognitoUserPoolSigninMethod.USERNAME]: undefined, - [CognitoUserPoolSigninMethod.EMAIL]: ['email'], - [CognitoUserPoolSigninMethod.PHONE_NUMBER]: ['phone_number'], - [CognitoUserPoolSigninMethod.EMAIL_AND_PHONE_NUMBER]: ['email', 'phone_number'], + [CognitoUserPoolSigninMethod.EMAIL]: [AttributeType.EMAIL], + [CognitoUserPoolSigninMethod.PHONE_NUMBER]: [AttributeType.PHONE_NUMBER], + [CognitoUserPoolSigninMethod.EMAIL_AND_PHONE_NUMBER]: [AttributeType.EMAIL, AttributeType.PHONE_NUMBER], +}; + +const aliasAttributeMap: Record = { + [CognitoUserAliasAttributes.PREFERRED_USERNAME]: AttributeType.PREFERRED_USERNAME, + [CognitoUserAliasAttributes.EMAIL]: AttributeType.EMAIL, + [CognitoUserAliasAttributes.PHONE_NUMBER]: AttributeType.PHONE_NUMBER, }; const socialFederationKeyMap = (provider: 'FACEBOOK' | 'AMAZON' | 'GOOGLE' | 'APPLE', projectType: string): string => { diff --git a/packages/amplify-category-auth/src/provider-utils/supported-services.ts b/packages/amplify-category-auth/src/provider-utils/supported-services.ts index d50fdf911ec..fbf817195a6 100644 --- a/packages/amplify-category-auth/src/provider-utils/supported-services.ts +++ b/packages/amplify-category-auth/src/provider-utils/supported-services.ts @@ -284,15 +284,13 @@ export const supportedServices = { ], }, { - key: 'usernameAttributes', + key: 'aliasAttributes', question: 'How do you want users to be able to sign in?', - type: 'list', - map: 'signInOptions', - prefix: 'Warning: you will not be able to edit these selections.', - prefixColor: 'red', - learnMore: - "Selecting 'Email' and/or 'Phone Number' will allow end users to sign-up using these values. Selecting 'Username' will require a unique username for users.", required: true, + type: 'multiselect', + map: 'aliasAttributes', + prefixColor: 'red', + prefix: 'Warning: you will not be able to edit these selections.', andConditions: [ { key: 'authSelections', diff --git a/packages/amplify-category-function/CHANGELOG.md b/packages/amplify-category-function/CHANGELOG.md index 53beded7b5b..bb885992a17 100644 --- a/packages/amplify-category-function/CHANGELOG.md +++ b/packages/amplify-category-function/CHANGELOG.md @@ -3,6 +3,66 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [2.34.2](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-function@2.34.1...amplify-category-function@2.34.2) (2021-08-06) + + +### Bug Fixes + +* **amplify-category-function:** Storage env vars not added to lambda function ([#7785](https://github.com/aws-amplify/amplify-cli/issues/7785)) ([cb4daaa](https://github.com/aws-amplify/amplify-cli/commit/cb4daaa6edfbf8dd2f7cab71abbda0ef450b16c3)) +* fiux e2e tests by passing categoryName for the resource ([#7886](https://github.com/aws-amplify/amplify-cli/issues/7886)) ([e420c6a](https://github.com/aws-amplify/amplify-cli/commit/e420c6ad11467dc8d1f52c8e65009794bf783944)) +* improve size checks before packaging Lambda resources ([#7756](https://github.com/aws-amplify/amplify-cli/issues/7756)) ([5952f6a](https://github.com/aws-amplify/amplify-cli/commit/5952f6aa6c1a6bbf3693a465ab61c46b7ab5c37b)) + + + + + +## [2.34.1](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-function@2.34.0...amplify-category-function@2.34.1) (2021-07-30) + + + +## 5.2.1 (2021-07-29) + + +### Bug Fixes + +* [#7696](https://github.com/aws-amplify/amplify-cli/issues/7696) - support production package install for function category ([#7812](https://github.com/aws-amplify/amplify-cli/issues/7812)) ([b39141e](https://github.com/aws-amplify/amplify-cli/commit/b39141e9d00bf0dc23318dcc476ed92ab031e88b)) +* correct behavior of --yes on push when missing env var ([#7826](https://github.com/aws-amplify/amplify-cli/issues/7826)) ([36b807b](https://github.com/aws-amplify/amplify-cli/commit/36b807bafa07c040eb66a1555bf95f17938aa93c)) +* lambda timeout should be an integer type ([#7699](https://github.com/aws-amplify/amplify-cli/issues/7699)) ([cbacf4d](https://github.com/aws-amplify/amplify-cli/commit/cbacf4d3e497421855c09825970e025550aacfd7)) + + + + + +# [2.34.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-function@2.33.1...amplify-category-function@2.34.0) (2021-07-27) + + +### Bug Fixes + +* disable layer version removal if fn depends on pinned version ([#7627](https://github.com/aws-amplify/amplify-cli/issues/7627)) ([a086789](https://github.com/aws-amplify/amplify-cli/commit/a086789661df95735679214a65a3808c8a5497e5)) + + +### Features + +* **amplify-category-function:** skip unnecessary prompt for 'amplify update function' ([12872a4](https://github.com/aws-amplify/amplify-cli/commit/12872a40d178f829cab3666037ebefde5eda02c2)) + + + + + +## [2.33.1](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-function@2.33.0...amplify-category-function@2.33.1) (2021-07-16) + + +### Bug Fixes + +* [#7441](https://github.com/aws-amplify/amplify-cli/issues/7441) - init from git prompts for credentials twice ([#7682](https://github.com/aws-amplify/amplify-cli/issues/7682)) ([7471c5f](https://github.com/aws-amplify/amplify-cli/commit/7471c5fcc86af0e17a967066a388f67891f93355)) +* add/update function when some LL are not yet migrated ([#7674](https://github.com/aws-amplify/amplify-cli/issues/7674)) ([9688681](https://github.com/aws-amplify/amplify-cli/commit/968868103744edcfbed6b082b3d9a92867180f73)) +* check for undefined permissions when removing dependent permissions ([#7594](https://github.com/aws-amplify/amplify-cli/issues/7594)) ([b1b6291](https://github.com/aws-amplify/amplify-cli/commit/b1b6291ac79b18b55723f9463aa93005ab75be88)) +* checkout into existing env with new LL ([#7687](https://github.com/aws-amplify/amplify-cli/issues/7687)) ([3e2e630](https://github.com/aws-amplify/amplify-cli/commit/3e2e6305b5a74db2a282dc33b0cc5d24f1c8eaaf)) + + + + + # [2.33.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-function@2.32.2...amplify-category-function@2.33.0) (2021-06-30) diff --git a/packages/amplify-category-function/package.json b/packages/amplify-category-function/package.json index 6ed5f9bce0a..19eda66cea3 100644 --- a/packages/amplify-category-function/package.json +++ b/packages/amplify-category-function/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-function", - "version": "2.33.0", + "version": "2.34.2", "description": "amplify-cli function plugin", "repository": { "type": "git", @@ -22,16 +22,16 @@ "aws" ], "dependencies": { - "amplify-cli-core": "1.24.0", - "amplify-function-plugin-interface": "1.9.0", + "amplify-cli-core": "1.26.0", + "amplify-function-plugin-interface": "1.9.1", "aws-sdk": "^2.930.0", - "chalk": "^3.0.0", + "chalk": "^4.1.1", "cloudform-types": "^4.2.0", "enquirer": "^2.3.6", "folder-hash": "^4.0.1", "fs-extra": "^8.1.0", "globby": "^11.0.3", - "graphql-transformer-core": "6.28.12", + "graphql-transformer-core": "6.29.2", "inquirer": "^7.3.3", "inquirer-datepicker": "^2.0.0", "jstreemap": "^1.28.2", diff --git a/packages/amplify-category-function/resources/awscloudformation/cloudformation-templates/lambda-function-cloudformation-template.json.ejs b/packages/amplify-category-function/resources/awscloudformation/cloudformation-templates/lambda-function-cloudformation-template.json.ejs index cd0273a8c4a..e898de8b668 100644 --- a/packages/amplify-category-function/resources/awscloudformation/cloudformation-templates/lambda-function-cloudformation-template.json.ejs +++ b/packages/amplify-category-function/resources/awscloudformation/cloudformation-templates/lambda-function-cloudformation-template.json.ejs @@ -93,7 +93,7 @@ "Role": { "Fn::GetAtt": ["LambdaExecutionRole", "Arn"] }, "Runtime": "<%= props.runtime.cloudTemplateValue %>", "Layers": <%- JSON.stringify(props.lambdaLayersCFNArray) %>, - "Timeout": "25" + "Timeout": 25 } }, "LambdaExecutionRole": { diff --git a/packages/amplify-category-function/src/__tests__/provider-utils/awscloudformation/service-walkthroughs/lambda-walkthrough.test.ts b/packages/amplify-category-function/src/__tests__/provider-utils/awscloudformation/service-walkthroughs/lambda-walkthrough.test.ts new file mode 100644 index 00000000000..07d5f8685f3 --- /dev/null +++ b/packages/amplify-category-function/src/__tests__/provider-utils/awscloudformation/service-walkthroughs/lambda-walkthrough.test.ts @@ -0,0 +1,46 @@ +import { topLevelCommentPrefix, topLevelCommentSuffix, envVarPrintoutPrefix } from '../../../../constants'; +import { buildTopLevelComment, buildShowEnvVars } from '../../../../provider-utils/awscloudformation/service-walkthroughs/lambda-walkthrough'; + + + +describe("Lambda Walkthrough : Advanced options and Environment Vars ", () => { + test("buildTopLevelComment should insert all environment variables in top-level-comment (example code header)", () => { + const inputEnvMap : Record = { + "ENV": { + "Ref": "env" + }, + "REGION": { + "Ref": "AWS::Region" + }, + "STORAGE_MOCK_BUCKETNAME": { + "Ref": "storageMockBucketName" + }, + "SES_EMAIL": { + "Ref": "sesEmail" + } + } + const outputString = `${topLevelCommentPrefix}ENV\n\tREGION\n\tSTORAGE_MOCK_BUCKETNAME\n\tSES_EMAIL${topLevelCommentSuffix}` + expect( buildTopLevelComment( inputEnvMap ) ).toEqual(outputString); + + }); + + test("buildShowEnvVars should insert all environment variables to be displayed", () => { + const inputEnvMap : Record = { + "ENV": { + "Ref": "env" + }, + "REGION": { + "Ref": "AWS::Region" + }, + "STORAGE_MOCK_BUCKETNAME": { + "Ref": "storageMockBucketName" + }, + "SES_EMAIL": { + "Ref": "sesEmail" + } + } + const outputString = `${envVarPrintoutPrefix}ENV\n\tREGION\n\tSTORAGE_MOCK_BUCKETNAME\n\tSES_EMAIL`; + expect( buildShowEnvVars( inputEnvMap ) ).toEqual(outputString); + }); + +}); \ No newline at end of file diff --git a/packages/amplify-category-function/src/__tests__/provider-utils/awscloudformation/service-walkthroughs/removeWalkthrough.test.ts b/packages/amplify-category-function/src/__tests__/provider-utils/awscloudformation/service-walkthroughs/removeWalkthrough.test.ts index aaed7b34ed0..9cd78c62957 100644 --- a/packages/amplify-category-function/src/__tests__/provider-utils/awscloudformation/service-walkthroughs/removeWalkthrough.test.ts +++ b/packages/amplify-category-function/src/__tests__/provider-utils/awscloudformation/service-walkthroughs/removeWalkthrough.test.ts @@ -9,6 +9,7 @@ describe('remove walkthough test', () => { const saveLayerVersionsToBeRemovedByCfn = jest.fn(); const selectPromptMock = jest.fn(); const updateLayerArtifacts = jest.fn(); + const getLambdaFunctionsDependentOnLayerFromMetaMock = jest.fn().mockReturnValue([]); beforeEach(() => { mockContext = { @@ -26,6 +27,19 @@ describe('remove walkthough test', () => { promptConfirmationRemove: jest.fn().mockReturnValue(true), stateManager: { getLocalEnvInfo: jest.fn().mockReturnValue({ envName }), + getMeta: jest.fn().mockReturnValue({ + function: { + mockFunction: { + service: 'Lambda', + dependsOn: [ + { + category: 'function', + resourceName: 'mockLayer', + }, + ], + }, + }, + }), }, })); @@ -43,6 +57,7 @@ describe('remove walkthough test', () => { getLayerName: jest.fn().mockReturnValue(layerName), loadLayerDataFromCloud: loadLayerDataFromCloudMock, loadStoredLayerParameters: loadStoredLayerParameters, + getLambdaFunctionsDependentOnLayerFromMeta: getLambdaFunctionsDependentOnLayerFromMetaMock, })); jest.mock('../../../../provider-utils/awscloudformation/utils/layerCloudState', () => ({ diff --git a/packages/amplify-category-function/src/__tests__/provider-utils/awscloudformation/utils/addLayerToFunctionUtil.test.ts b/packages/amplify-category-function/src/__tests__/provider-utils/awscloudformation/utils/addLayerToFunctionUtil.test.ts index c5b7a4697e9..d3a1955fd09 100644 --- a/packages/amplify-category-function/src/__tests__/provider-utils/awscloudformation/utils/addLayerToFunctionUtil.test.ts +++ b/packages/amplify-category-function/src/__tests__/provider-utils/awscloudformation/utils/addLayerToFunctionUtil.test.ts @@ -21,6 +21,7 @@ jest.mock('../../../../provider-utils/awscloudformation/utils/layerCloudState'); jest.mock('../../../../provider-utils/awscloudformation/utils/layerConfiguration', () => ({ getLayerRuntimes: jest.fn(), })); +jest.mock('../../../../provider-utils/awscloudformation/utils/layerMigrationUtils'); const getLayerRuntimes_mock = getLayerRuntimes as jest.MockedFunction; const inquirer_mock = inquirer as jest.Mocked; diff --git a/packages/amplify-category-function/src/__tests__/provider-utils/awscloudformation/utils/determineServiceSelection.ts b/packages/amplify-category-function/src/__tests__/provider-utils/awscloudformation/utils/determineServiceSelection.ts new file mode 100644 index 00000000000..b734100641f --- /dev/null +++ b/packages/amplify-category-function/src/__tests__/provider-utils/awscloudformation/utils/determineServiceSelection.ts @@ -0,0 +1,87 @@ +import { determineServiceSelection } from '../../../../provider-utils/awscloudformation/utils/determineServiceSelection'; +import { ServiceName } from '../../../../provider-utils/awscloudformation/utils/constants'; + +const serviceSelectionPromptMock = jest.fn(); +const mockChooseServiceMessage = 'mockChooseServiceMessage'; +const mockContext = { + amplify: { + getResourceStatus: async () => { + return { allResources: [] }; + }, + serviceSelectionPrompt: serviceSelectionPromptMock, + }, +}; + +describe('determineServiceSelection', () => { + it('returns LambdaFunction when no resources exists', async () => { + const response = await determineServiceSelection(mockContext, mockChooseServiceMessage); + expect(response.service === ServiceName.LambdaFunction); + expect(serviceSelectionPromptMock).toBeCalledTimes(0); + }); + + it('returns LambdaFunction when only LambdaFunction resources exists', async () => { + mockContext.amplify.getResourceStatus = async () => { + return { + allResources: [ + { + service: ServiceName.LambdaFunction, + }, + ], + }; + }; + const response = await determineServiceSelection(mockContext, mockChooseServiceMessage); + expect(response.service === ServiceName.LambdaFunction); + expect(serviceSelectionPromptMock).toBeCalledTimes(0); + }); + + it('returns LambdaLayer when only LambdaLayer resources exists', async () => { + mockContext.amplify.getResourceStatus = async () => { + return { + allResources: [ + { + service: ServiceName.LambdaLayer, + }, + ], + }; + }; + const response = await determineServiceSelection(mockContext, mockChooseServiceMessage); + expect(response.service === ServiceName.LambdaLayer); + expect(serviceSelectionPromptMock).toBeCalledTimes(0); + }); + + it('returns LambdaLayer when existing LambdaFunction resources have mobileHubMigrated', async () => { + mockContext.amplify.getResourceStatus = async () => { + return { + allResources: [ + { + service: ServiceName.LambdaLayer, + }, + { + service: ServiceName.LambdaFunction, + mobileHubMigrated: true, + }, + ], + }; + }; + const response = await determineServiceSelection(mockContext, mockChooseServiceMessage); + expect(response.service === ServiceName.LambdaLayer); + expect(serviceSelectionPromptMock).toBeCalledTimes(0); + }); + + it('prompts for user input when both LambdaFunction and LambdaLayer resources exist', async () => { + mockContext.amplify.getResourceStatus = async () => { + return { + allResources: [ + { + service: ServiceName.LambdaFunction, + }, + { + service: ServiceName.LambdaLayer, + }, + ], + }; + }; + await determineServiceSelection(mockContext, mockChooseServiceMessage); + expect(serviceSelectionPromptMock).toBeCalledTimes(1); + }); +}); diff --git a/packages/amplify-category-function/src/__tests__/provider-utils/awscloudformation/utils/getDependentFunction.test.ts b/packages/amplify-category-function/src/__tests__/provider-utils/awscloudformation/utils/getDependentFunction.test.ts index e93276afab1..df721f64d4c 100644 --- a/packages/amplify-category-function/src/__tests__/provider-utils/awscloudformation/utils/getDependentFunction.test.ts +++ b/packages/amplify-category-function/src/__tests__/provider-utils/awscloudformation/utils/getDependentFunction.test.ts @@ -68,7 +68,7 @@ const loadResourceParameters_mock = loadFunctionParameters as jest.MockedFunctio test('get dependent functions', async () => { jest.clearAllMocks(); - const modelsDeleted = ['model3']; + const modelsDeleted = ['model3', 'model2']; const FunctionMetaExpected = ['fn2', 'fn3']; loadResourceParameters_mock .mockReturnValueOnce({ @@ -91,9 +91,9 @@ test('get dependent functions', async () => { expect(fnMetaToBeUpdated.map(resource => resource.resourceName).toString()).toBe(FunctionMetaExpected.toString()); }); -test('get dependent functions', async () => { +test('get dependent functions with empty permissions', async () => { jest.clearAllMocks(); - const modelsDeleted = ['model1', 'model2']; + const modelsDeleted = ['model3']; const FunctionMetaExpected = ['fn2']; loadResourceParameters_mock .mockReturnValueOnce({ @@ -105,13 +105,7 @@ test('get dependent functions', async () => { }, }, }) - .mockReturnValueOnce({ - permissions: { - storage: { - model3: ['create'], - }, - }, - }); + .mockReturnValueOnce({}); const fnMetaToBeUpdated = await lambdasWithApiDependency((contextStub as unknown) as $TSContext, allResources, backendDir, modelsDeleted); expect(fnMetaToBeUpdated.map(resource => resource.resourceName).toString()).toBe(FunctionMetaExpected.toString()); }); diff --git a/packages/amplify-category-function/src/__tests__/provider-utils/awscloudformation/utils/packageFunction.test.ts b/packages/amplify-category-function/src/__tests__/provider-utils/awscloudformation/utils/packageFunction.test.ts index 9c23e31e373..1d3de474e15 100644 --- a/packages/amplify-category-function/src/__tests__/provider-utils/awscloudformation/utils/packageFunction.test.ts +++ b/packages/amplify-category-function/src/__tests__/provider-utils/awscloudformation/utils/packageFunction.test.ts @@ -1,11 +1,13 @@ import { getRuntimeManager } from '../../../../provider-utils/awscloudformation/utils/functionPluginLoader'; -import { $TSContext, pathManager } from 'amplify-cli-core'; +import { $TSContext, getFolderSize, pathManager } from 'amplify-cli-core'; import { packageFunction } from '../../../../provider-utils/awscloudformation/utils/packageFunction'; import { PackageRequestMeta } from '../../../../provider-utils/awscloudformation/types/packaging-types'; +import { zipPackage } from '../../../../provider-utils/awscloudformation/utils/zipResource'; jest.mock('fs-extra'); jest.mock('amplify-cli-core'); jest.mock('../../../../provider-utils/awscloudformation/utils/functionPluginLoader'); +jest.mock('../../../../provider-utils/awscloudformation/utils/zipResource'); const context_stub = { amplify: { @@ -16,15 +18,20 @@ const context_stub = { const pathManager_mock = pathManager as jest.Mocked; const getRuntimeManager_mock = getRuntimeManager as jest.MockedFunction; +const zipPackage_mock = zipPackage as jest.MockedFunction; +const getFolderSize_mock = getFolderSize as jest.MockedFunction; -pathManager_mock.getBackendDirPath.mockReturnValue('backend/dir/path'); +pathManager_mock.getResourceDirectoryPath.mockReturnValue('backend/dir/path/testcategory/testResourceName'); +getFolderSize_mock.mockResolvedValue(50 * 1024 ** 2); const runtimeManager_mock = { package: jest.fn().mockResolvedValue({ packageHash: 'testpackagehash', + zipEntries: ['mock/zip/entry'], }), }; getRuntimeManager_mock.mockResolvedValue(runtimeManager_mock as any); +zipPackage_mock.mockResolvedValue('mockedZipName.zip'); const resourceRequest: PackageRequestMeta = { category: 'testcategory', @@ -40,13 +47,16 @@ const resourceRequest: PackageRequestMeta = { describe('package function', () => { it('delegates packaging to the runtime manager', async () => { await packageFunction((context_stub as unknown) as $TSContext, resourceRequest); - expect(runtimeManager_mock.package.mock.calls[0][0].srcRoot).toEqual('backend/dir/path/testcategory/testResourceName'); }); it('updates amplify meta after packaging', async () => { await packageFunction((context_stub as unknown) as $TSContext, resourceRequest); - expect(context_stub.amplify.updateAmplifyMetaAfterPackage.mock.calls[0][0]).toEqual(resourceRequest); }); + + it('throws an error when the size of the function is too large', async () => { + getFolderSize_mock.mockResolvedValueOnce(251 * 1024 ** 2); + await expect(async () => await packageFunction((context_stub as unknown) as $TSContext, resourceRequest)).rejects.toThrow(); + }); }); diff --git a/packages/amplify-category-function/src/__tests__/provider-utils/awscloudformation/utils/packageLayer.test.ts b/packages/amplify-category-function/src/__tests__/provider-utils/awscloudformation/utils/packageLayer.test.ts index ade86531413..9e95eaa12d3 100644 --- a/packages/amplify-category-function/src/__tests__/provider-utils/awscloudformation/utils/packageLayer.test.ts +++ b/packages/amplify-category-function/src/__tests__/provider-utils/awscloudformation/utils/packageLayer.test.ts @@ -1,10 +1,9 @@ -import { $TSContext, pathManager } from 'amplify-cli-core'; +import { $TSContext, convertNumBytes, getFolderSize, pathManager } from 'amplify-cli-core'; import { FunctionRuntimeLifecycleManager } from 'amplify-function-plugin-interface'; import { packageLayer } from '../../../../provider-utils/awscloudformation/utils/packageLayer'; import { PackageRequestMeta } from '../../../../provider-utils/awscloudformation/types/packaging-types'; import { LayerCloudState } from '../../../../provider-utils/awscloudformation/utils/layerCloudState'; import { loadLayerConfigurationFile } from '../../../../provider-utils/awscloudformation/utils/layerConfiguration'; -import { validFilesize } from '../../../../provider-utils/awscloudformation/utils/layerHelpers'; jest.mock('fs-extra'); jest.mock('amplify-cli-core'); @@ -13,7 +12,6 @@ jest.mock('../../../../provider-utils/awscloudformation/utils/layerConfiguration jest.mock('../../../../provider-utils/awscloudformation/utils/layerCloudState'); jest.mock('../../../../provider-utils/awscloudformation/utils/layerHelpers', () => ({ loadPreviousLayerHash: jest.fn(), - validFilesize: jest.fn(), loadStoredLayerParameters: jest.fn(), getChangedResources: jest.fn(), ensureLayerVersion: jest.fn().mockReturnValue('newhash'), @@ -21,6 +19,8 @@ jest.mock('../../../../provider-utils/awscloudformation/utils/layerHelpers', () jest.mock('../../../../provider-utils/awscloudformation/utils/zipResource'); const pathManager_mock = pathManager as jest.Mocked; +const getFolderSize_mock = getFolderSize as jest.MockedFunction; +const convertNumBytes_mock = convertNumBytes as jest.MockedFunction; const loadLayerConfigurationFile_mock = loadLayerConfigurationFile as jest.MockedFunction; loadLayerConfigurationFile_mock.mockReturnValue({ @@ -39,9 +39,6 @@ loadLayerConfigurationFile_mock.mockReturnValue({ ], }); -const validFilesize_mock = validFilesize as jest.MockedFunction; -validFilesize_mock.mockReturnValue(true); - pathManager_mock.getResourceDirectoryPath.mockReturnValue('backend/dir/path/testcategory/testResourceName/'); const runtimePlugin_stub = ({ @@ -75,12 +72,22 @@ layerCloudState_mock.getInstance.mockReturnValue(({ describe('package function', () => { it('delegates packaging to the runtime manager', async () => { + getFolderSize_mock.mockResolvedValue(100 * 1024 ** 2); // 100MB await packageLayer((context_stub as unknown) as $TSContext, resourceRequest); expect(runtimePlugin_stub.package.mock.calls[0][0].srcRoot).toEqual('backend/dir/path/testcategory/testResourceName/lib/nodejs'); }); it('updates amplify meta after packaging', async () => { + getFolderSize_mock.mockResolvedValue(100 * 1024 ** 2); // 100MB await packageLayer((context_stub as unknown) as $TSContext, resourceRequest); expect((context_stub.amplify.updateAmplifyMetaAfterPackage as jest.Mock).mock.calls[0][0]).toEqual(resourceRequest); }); + + it('fails to pacakge layer that is greater than 250MB in size', async () => { + getFolderSize_mock.mockResolvedValue(260 * 1024 ** 2); // 260MB + convertNumBytes_mock.mockReturnValue({ toKB: jest.fn(), toMB: jest.fn().mockReturnValueOnce(260) }); + await expect(async () => await packageLayer((context_stub as unknown) as $TSContext, resourceRequest)).rejects.toEqual( + new Error(`Lambda layer ${resourceRequest.resourceName} is too large: 260/250 MB`), + ); + }); }); diff --git a/packages/amplify-category-function/src/commands/function/update.ts b/packages/amplify-category-function/src/commands/function/update.ts index c13ec660058..bef2a00a9db 100644 --- a/packages/amplify-category-function/src/commands/function/update.ts +++ b/packages/amplify-category-function/src/commands/function/update.ts @@ -1,6 +1,7 @@ import { supportedServices } from '../../provider-utils/supported-services'; import { chooseServiceMessageUpdate } from '../../provider-utils/awscloudformation/utils/constants'; import { categoryName } from '../../constants'; +import { determineServiceSelection } from '../../provider-utils/awscloudformation/utils/determineServiceSelection'; const subcommand = 'update'; @@ -8,10 +9,8 @@ module.exports = { name: subcommand, alias: ['configure'], run: async context => { - const { amplify } = context; const servicesMetadata = supportedServices; - return amplify - .serviceSelectionPrompt(context, categoryName, servicesMetadata, chooseServiceMessageUpdate) + return determineServiceSelection(context, chooseServiceMessageUpdate) .then(result => { const providerController = servicesMetadata[result.service].providerController; if (!providerController) { diff --git a/packages/amplify-category-function/src/index.ts b/packages/amplify-category-function/src/index.ts index ee4907ff5d1..0d6de3a6976 100644 --- a/packages/amplify-category-function/src/index.ts +++ b/packages/amplify-category-function/src/index.ts @@ -200,9 +200,12 @@ export async function getInvoker( } export function getBuilder(context: $TSContext, resourceName: string, buildType: BuildType): () => Promise { - const lastBuildTimestamp = _.get(stateManager.getMeta(), [categoryName, resourceName, buildTypeKeyMap[buildType]]); + const meta = stateManager.getMeta(); + const lastBuildTimestamp = _.get(meta, [categoryName, resourceName, buildTypeKeyMap[buildType]]); + const lastBuildType = _.get(meta, [categoryName, resourceName, 'lastBuildType']); + return async () => { - await buildFunction(context, { resourceName, buildType, lastBuildTimestamp }); + await buildFunction(context, { resourceName, buildType, lastBuildTimestamp, lastBuildType }); }; } diff --git a/packages/amplify-category-function/src/provider-utils/awscloudformation/index.ts b/packages/amplify-category-function/src/provider-utils/awscloudformation/index.ts index bfc45aab53f..796ee0fee5f 100644 --- a/packages/amplify-category-function/src/provider-utils/awscloudformation/index.ts +++ b/packages/amplify-category-function/src/provider-utils/awscloudformation/index.ts @@ -405,8 +405,10 @@ export async function updateConfigOnEnvInit(context: $TSContext, resourceName: s } const currentCfnTemplatePath = pathManager.getCurrentCfnTemplatePath(projectPath, categoryName, resourceName); - const { cfnTemplate: currentCfnTemplate } = await readCFNTemplate(currentCfnTemplatePath); - await writeCFNTemplate(currentCfnTemplate, pathManager.getResourceCfnTemplatePath(projectPath, categoryName, resourceName)); + const { cfnTemplate: currentCfnTemplate } = (await readCFNTemplate(currentCfnTemplatePath, { throwIfNotExist: false })) || {}; + if (currentCfnTemplate !== undefined) { + await writeCFNTemplate(currentCfnTemplate, pathManager.getResourceCfnTemplatePath(projectPath, categoryName, resourceName)); + } } } } diff --git a/packages/amplify-category-function/src/provider-utils/awscloudformation/secrets/ssmClientWrapper.ts b/packages/amplify-category-function/src/provider-utils/awscloudformation/secrets/ssmClientWrapper.ts index e5979795d0a..00a08df2b27 100644 --- a/packages/amplify-category-function/src/provider-utils/awscloudformation/secrets/ssmClientWrapper.ts +++ b/packages/amplify-category-function/src/provider-utils/awscloudformation/secrets/ssmClientWrapper.ts @@ -102,8 +102,15 @@ export class SSMClientWrapper { const getSSMClient = async (context: $TSContext) => { const spinner = ora('Initializing SSM Client'); - spinner.start(); - const { client } = await context.amplify.invokePluginMethod(context, 'awscloudformation', undefined, 'getConfiguredSSMClient', [context]); - spinner.stop(); - return client as aws.SSM; + try { + spinner.start(); + + const { client } = await context.amplify.invokePluginMethod(context, 'awscloudformation', undefined, 'getConfiguredSSMClient', [ + context, + ]); + + return client as aws.SSM; + } finally { + spinner.stop(); + } }; diff --git a/packages/amplify-category-function/src/provider-utils/awscloudformation/service-walkthroughs/lambda-walkthrough.ts b/packages/amplify-category-function/src/provider-utils/awscloudformation/service-walkthroughs/lambda-walkthrough.ts index f2576ad5a47..64935d66c6d 100644 --- a/packages/amplify-category-function/src/provider-utils/awscloudformation/service-walkthroughs/lambda-walkthrough.ts +++ b/packages/amplify-category-function/src/provider-utils/awscloudformation/service-walkthroughs/lambda-walkthrough.ts @@ -3,7 +3,7 @@ import { FunctionParameters, ProjectLayer } from 'amplify-function-plugin-interf import inquirer from 'inquirer'; import _ from 'lodash'; import path from 'path'; -import { categoryName } from '../../../constants'; +import { categoryName, envVarPrintoutPrefix, topLevelCommentPrefix, topLevelCommentSuffix } from '../../../constants'; import { getNewCFNEnvVariables, getNewCFNParameters } from '../utils/cloudformationHelpers'; import { advancedSettingsList, @@ -88,6 +88,11 @@ export async function createWalkthrough( // ask environment variable questions and merge in results if (await context.amplify.confirmPrompt('Do you want to configure environment variables for this function?', false)) { templateParameters = merge(templateParameters, await askEnvironmentVariableQuestions(templateParameters.functionName)); + //update top-level comment to be inserted into example + templateParameters.topLevelComment = buildTopLevelComment( templateParameters.environmentMap ); + //show updated environment variables + const envVarViewString = buildShowEnvVars(templateParameters.environmentMap); + context.print.info(envVarViewString); } // ask function secrets questions and merge in results @@ -103,6 +108,24 @@ export async function createWalkthrough( return templateParameters; } +//Function to build message to be displayed when +//Lambda environment variables are enabled. +export function buildShowEnvVars(envVariableMap){ + const envVarViewArr = Object.keys(envVariableMap); //sorted list of existing env variables + const envVarViewString= envVarViewArr.join("\n\t"); + const showEnvComment = `${envVarPrintoutPrefix}${envVarViewString}`; + return showEnvComment; +} + +//Insert 'Environment Map' keys - (env, region, resource-names, user supplied variables) +//into topLevelComment to be inserted into example files and displayed to the user +export function buildTopLevelComment( envVariableMap ){ + const envVarViewArr = Object.keys(envVariableMap); + const envVarViewString= envVarViewArr.join("\n\t"); + const topLevelComment = `${topLevelCommentPrefix}${envVarViewString}${topLevelCommentSuffix}`; + return topLevelComment; +} + function provideInformation(context, lambdaToUpdate, functionRuntime, currentParameters, scheduleParameters) { // Provide general information context.print.success('General information'); @@ -279,6 +302,8 @@ export async function updateWalkthrough(context: $TSContext, lambdaToUpdate?: st functionParameters, await askEnvironmentVariableQuestions(lambdaToUpdate, undefined, !selectedSettings.includes(environmentVariableSetting)), ); + //update top-level comment to be inserted into example + functionParameters.topLevelComment = buildTopLevelComment( functionParameters.environmentMap ); return functionParameters; } diff --git a/packages/amplify-category-function/src/provider-utils/awscloudformation/service-walkthroughs/removeFunctionWalkthrough.ts b/packages/amplify-category-function/src/provider-utils/awscloudformation/service-walkthroughs/removeFunctionWalkthrough.ts index 6879dd5b8a5..930744ce58c 100644 --- a/packages/amplify-category-function/src/provider-utils/awscloudformation/service-walkthroughs/removeFunctionWalkthrough.ts +++ b/packages/amplify-category-function/src/provider-utils/awscloudformation/service-walkthroughs/removeFunctionWalkthrough.ts @@ -7,6 +7,10 @@ import { ServiceName } from '../utils/constants'; export async function removeResource(resourceName?: string): Promise<$TSAny> { const enabledCategoryResources = getEnabledResources(); + if (enabledCategoryResources.length === 0) { + throw new Error('No Lambda function resource to remove. Use "amplify add function" to create a new function.'); + } + if (resourceName) { const resource = enabledCategoryResources.find(categoryResource => categoryResource.value.resourceName === resourceName); return resource.value; diff --git a/packages/amplify-category-function/src/provider-utils/awscloudformation/service-walkthroughs/removeLayerWalkthrough.ts b/packages/amplify-category-function/src/provider-utils/awscloudformation/service-walkthroughs/removeLayerWalkthrough.ts index 51f48bd642c..2ff2ab349d6 100644 --- a/packages/amplify-category-function/src/provider-utils/awscloudformation/service-walkthroughs/removeLayerWalkthrough.ts +++ b/packages/amplify-category-function/src/provider-utils/awscloudformation/service-walkthroughs/removeLayerWalkthrough.ts @@ -1,11 +1,13 @@ -import { $TSContext, stateManager } from 'amplify-cli-core'; +import { $TSContext, $TSObject, pathManager, stateManager } from 'amplify-cli-core'; import chalk from 'chalk'; import inquirer, { QuestionCollection } from 'inquirer'; import ora from 'ora'; +import { categoryName } from '../../../constants'; import { LayerCloudState } from '../utils/layerCloudState'; import { saveLayerVersionsToBeRemovedByCfn } from '../utils/layerConfiguration'; -import { loadStoredLayerParameters, getLayerName } from '../utils/layerHelpers'; +import { getLambdaFunctionsDependentOnLayerFromMeta, getLayerName, loadStoredLayerParameters } from '../utils/layerHelpers'; import { LayerVersionMetadata } from '../utils/layerParams'; +import { loadFunctionParameters } from '../utils/loadFunctionParameters'; import { updateLayerArtifacts } from '../utils/storeResources'; const removeLayerQuestion = 'Choose the Layer versions you want to remove.'; @@ -19,8 +21,12 @@ export async function removeWalkthrough(context: $TSContext, layerName: string): return layerName; } + // Disable any pinned versions in the version list + const lambdaFunctionsDependentOnLayer = getLambdaFunctionsDependentOnLayerFromMeta(layerName, stateManager.getMeta()); + disablePinnedVersions(lambdaFunctionsDependentOnLayer, layerName, layerVersionList); + const { versions } = await inquirer.prompt(question(layerVersionList)); - const selectedLayerVersion = versions as LayerVersionMetadata[]; + const selectedLayerVersion = versions as LayerVersionForPossibleRemoval[]; // if nothing is selected return; if (selectedLayerVersion.length === 0) { @@ -44,7 +50,7 @@ export async function removeWalkthrough(context: $TSContext, layerName: string): const totalSelectedVersionsToRemove = newLayerSelectedVersions.length + legacyLayerSelectedVersions.length; if (legacyLayerSelectedVersions.length > 0) { - await deleteLayer( + await deleteLayerVersionsWithSdk( context, getLayerName(context, layerName), legacyLayerSelectedVersions.map(r => r.Version), @@ -77,7 +83,11 @@ export async function removeWalkthrough(context: $TSContext, layerName: string): return layerName; } -function warnLegacyRemoval(context: $TSContext, legacyLayerVersions: LayerVersionMetadata[], newLayerVersions: LayerVersionMetadata[]) { +function warnLegacyRemoval( + context: $TSContext, + legacyLayerVersions: LayerVersionForPossibleRemoval[], + newLayerVersions: LayerVersionForPossibleRemoval[], +) { const amplifyPush = chalk.green('amplify push'); const legacyVersions: number[] = legacyLayerVersions.map(r => r.Version); @@ -97,7 +107,7 @@ function warnLegacyRemoval(context: $TSContext, legacyLayerVersions: LayerVersio context.print.info(''); } -async function deleteLayer(context: $TSContext, layerName: string, versions: number[]) { +async function deleteLayerVersionsWithSdk(context: $TSContext, layerName: string, versions: number[]) { const providerPlugin = await import(context.amplify.getProviderPlugins(context).awscloudformation); const lambdaClient = await providerPlugin.getLambdaSdk(context); const spinner = ora('Deleting layer version from the cloud...').start(); @@ -112,17 +122,51 @@ async function deleteLayer(context: $TSContext, layerName: string, versions: num } } -const question = (layerVersionMetadata: LayerVersionMetadata[]): QuestionCollection[] => [ +function disablePinnedVersions( + lambdaFunctionsDependentOnLayer: [string, $TSObject][], + layerName: string, + layerVersionList: LayerVersionForPossibleRemoval[], +) { + lambdaFunctionsDependentOnLayer.forEach(([lambdaFunctionName]: [string, $TSObject]) => { + const { lambdaLayers: lambdaLayerDependencies } = loadFunctionParameters( + pathManager.getResourceDirectoryPath(undefined, categoryName, lambdaFunctionName), + ); + + lambdaLayerDependencies.forEach(layerDependency => { + if (layerDependency.resourceName === layerName && layerDependency.isLatestVersionSelected === false) { + for (const layerVersion of layerVersionList) { + if (layerVersion.Version === layerDependency.version) { + layerVersion.pinnedByFunctions ||= []; + layerVersion.pinnedByFunctions.push(lambdaFunctionName); + break; + } + } + } + }); + }); +} + +const question = (layerVersionList: LayerVersionForPossibleRemoval[]): QuestionCollection[] => [ { name: 'versions', message: removeLayerQuestion, type: 'checkbox', - choices: layerVersionMetadata + choices: layerVersionList .sort((versiona, versionb) => versiona.Version - versionb.Version) .map(version => ({ + disabled: + Array.isArray(version.pinnedByFunctions) && version.pinnedByFunctions.length > 0 + ? `Can't be removed. ${version.pinnedByFunctions.join(', ')} depend${ + version.pinnedByFunctions.length > 1 ? '' : 's' + } on this version.` + : false, name: `${version.Version}: ${version.Description}`, short: version.Version.toString(), value: version, })), }, ]; + +interface LayerVersionForPossibleRemoval extends LayerVersionMetadata { + pinnedByFunctions?: string[]; +} diff --git a/packages/amplify-category-function/src/provider-utils/awscloudformation/utils/addLayerToFunctionUtils.ts b/packages/amplify-category-function/src/provider-utils/awscloudformation/utils/addLayerToFunctionUtils.ts index 4cca83a9113..f9642dd701f 100644 --- a/packages/amplify-category-function/src/provider-utils/awscloudformation/utils/addLayerToFunctionUtils.ts +++ b/packages/amplify-category-function/src/provider-utils/awscloudformation/utils/addLayerToFunctionUtils.ts @@ -8,6 +8,7 @@ import { ServiceName } from './constants'; import { LayerCloudState } from './layerCloudState'; import { getLayerRuntimes } from './layerConfiguration'; import { layerVersionQuestion, mapVersionNumberToChoice } from './layerHelpers'; +import { getLegacyLayerState, LegacyState } from './layerMigrationUtils'; export const provideExistingARNsPrompt = 'Provide existing Lambda layer ARNs'; const layerSelectionPrompt = 'Provide existing layers or select layers in this project to access from this function (pick up to 5):'; @@ -38,8 +39,10 @@ export const askLayerSelection = async ( const layerOptions = _.keys(functionMeta) .filter(key => functionMeta[key].service === ServiceName.LambdaLayer) .filter(key => { - // filter by compatible runtimes - return isRuntime(runtimeValue).inRuntimes(functionMeta[key].runtimes || getLayerRuntimes(key)); + // filter by compatible runtimes - unless no runtimes are present for the given Lambda layer + // since any Lambda function can depend on /opt folder content if there is no runtime. + const runtimes = functionMeta[key].runtimes || getLayerRuntimes(key); + return Array.isArray(runtimes) && (_.isEmpty(runtimes) || isRuntime(runtimeValue).inRuntimes(runtimes)); }); if (layerOptions.length === 0) { @@ -49,9 +52,19 @@ export const askLayerSelection = async ( askArnQuestion: true, }; } + + const disabledMessage = 'Layer requires migration. Run "amplify function update" and choose this layer to migrate.'; const currentResourceNames = filterProjectLayers(previousSelections).map(sel => (sel as ProjectLayer).resourceName); - const choices = layerOptions.map(op => ({ name: op, checked: currentResourceNames.includes(op) })); - choices.unshift({ name: provideExistingARNsPrompt, checked: previousSelections.map(sel => sel.type).includes('ExternalLayer') }); + const choices = layerOptions.map(op => ({ + name: op, + checked: currentResourceNames.includes(op), + disabled: getLegacyLayerState(op) !== LegacyState.NOT_LEGACY ? disabledMessage : false, + })); + choices.unshift({ + name: provideExistingARNsPrompt, + checked: previousSelections.map(sel => sel.type).includes('ExternalLayer'), + disabled: false, + }); const layerSelectionQuestion: CheckboxQuestion = { type: 'checkbox', diff --git a/packages/amplify-category-function/src/provider-utils/awscloudformation/utils/buildFunction.ts b/packages/amplify-category-function/src/provider-utils/awscloudformation/utils/buildFunction.ts index 65159e28605..3ad54fd7e0e 100644 --- a/packages/amplify-category-function/src/provider-utils/awscloudformation/utils/buildFunction.ts +++ b/packages/amplify-category-function/src/provider-utils/awscloudformation/utils/buildFunction.ts @@ -1,13 +1,11 @@ import { $TSContext, pathManager } from 'amplify-cli-core'; -import { FunctionRuntimeLifecycleManager, BuildRequest, BuildType } from 'amplify-function-plugin-interface'; -import * as path from 'path'; +import { BuildRequest, BuildType, FunctionRuntimeLifecycleManager } from 'amplify-function-plugin-interface'; import { categoryName } from '../../../constants'; export const buildFunction = async ( context: $TSContext, - { resourceName, lastBuildTimestamp, buildType = BuildType.PROD }: BuildRequestMeta, + { resourceName, lastBuildTimestamp, lastBuildType, buildType = BuildType.PROD }: BuildRequestMeta, ) => { - const resourcePath = path.join(pathManager.getBackendDirPath(), categoryName, resourceName); const breadcrumbs = context.amplify.readBreadcrumbs(categoryName, resourceName); const runtimePlugin: FunctionRuntimeLifecycleManager = (await context.amplify.loadRuntimePlugin( @@ -31,13 +29,14 @@ export const buildFunction = async ( } else { const buildRequest: BuildRequest = { buildType, - srcRoot: resourcePath, + srcRoot: pathManager.getResourceDirectoryPath(undefined, categoryName, resourceName), runtime: breadcrumbs.functionRuntime, legacyBuildHookParams: { projectRoot: pathManager.findProjectRoot(), - resourceName: resourceName, + resourceName, }, lastBuildTimeStamp: prevBuildTime, + lastBuildType, }; rebuilt = (await runtimePlugin.build(buildRequest)).rebuilt; } @@ -52,6 +51,7 @@ export const buildFunction = async ( export interface BuildRequestMeta { resourceName: string; lastBuildTimestamp?: string; + lastBuildType?: BuildType; buildType?: BuildType; } diff --git a/packages/amplify-category-function/src/provider-utils/awscloudformation/utils/constants.ts b/packages/amplify-category-function/src/provider-utils/awscloudformation/utils/constants.ts index 00980f60ecf..f3aba9cebc6 100644 --- a/packages/amplify-category-function/src/provider-utils/awscloudformation/utils/constants.ts +++ b/packages/amplify-category-function/src/provider-utils/awscloudformation/utils/constants.ts @@ -17,6 +17,8 @@ export const ephemeralField = 'ephemeral'; export const versionHash = 'latestPushedVersionHash'; export const cfnTemplateSuffix = '-awscloudformation-template.json'; +export const lambdaPackageLimitInMB = 250; + export const enum LayerCfnLogicalNamePrefix { LambdaLayerVersion = 'LambdaLayerVersion', LambdaLayerVersionPermission = 'LambdaLayerPermission', diff --git a/packages/amplify-category-function/src/provider-utils/awscloudformation/utils/determineServiceSelection.ts b/packages/amplify-category-function/src/provider-utils/awscloudformation/utils/determineServiceSelection.ts new file mode 100644 index 00000000000..cbcd0be9c54 --- /dev/null +++ b/packages/amplify-category-function/src/provider-utils/awscloudformation/utils/determineServiceSelection.ts @@ -0,0 +1,24 @@ +import { ServiceName } from './constants'; +import { categoryName } from '../../../constants'; +import { supportedServices } from '../../supported-services'; + +export const determineServiceSelection = async (context, chooseServiceMessage) => { + const { allResources } = await context.amplify.getResourceStatus(); + const lambdaLayerExists = allResources.filter(resource => resource.service === ServiceName.LambdaLayer).length > 0; + const lambdaFunctionExists = + allResources.filter(resource => resource.service === ServiceName.LambdaFunction && resource.mobileHubMigrated !== true).length > 0; + + if ((!lambdaFunctionExists && !lambdaLayerExists) || (lambdaFunctionExists && !lambdaLayerExists)) { + return { + service: ServiceName.LambdaFunction, + }; + } + + if (!lambdaFunctionExists && lambdaLayerExists) { + return { + service: ServiceName.LambdaLayer, + }; + } + + return await context.amplify.serviceSelectionPrompt(context, categoryName, supportedServices, chooseServiceMessage); +}; diff --git a/packages/amplify-category-function/src/provider-utils/awscloudformation/utils/environmentVariablesHelper.ts b/packages/amplify-category-function/src/provider-utils/awscloudformation/utils/environmentVariablesHelper.ts index 6bb5887503f..42c757db084 100644 --- a/packages/amplify-category-function/src/provider-utils/awscloudformation/utils/environmentVariablesHelper.ts +++ b/packages/amplify-category-function/src/provider-utils/awscloudformation/utils/environmentVariablesHelper.ts @@ -159,7 +159,7 @@ export const askEnvironmentVariableCarryOut = async ( }; export const ensureEnvironmentVariableValues = async (context: $TSContext) => { - const yesFlagSet = context?.exeInfo?.inputParams?.yes; + const yesFlagSet = context?.exeInfo?.inputParams?.yes || context?.input?.options?.yes; const currentEnvName = stateManager.getLocalEnvInfo()?.envName; const teamProviderInfo = stateManager.getTeamProviderInfo(undefined, { throwIfNotExist: false, @@ -248,7 +248,7 @@ const deleteEnvironmentVariable = (resourceName: string, targetedKey: string): v return item.cloudFormationParameterName !== cameledKey && item.environmentVariableName !== targetedKey; }); _.unset(newReferences, targetedKey); - _.unset(newParameters, targetedKey); + _.unset(newParameters, cameledKey); _.unset(newKeyValue, cameledKey); setStoredList(resourceName, newList); diff --git a/packages/amplify-category-function/src/provider-utils/awscloudformation/utils/getDependentFunction.ts b/packages/amplify-category-function/src/provider-utils/awscloudformation/utils/getDependentFunction.ts index 8b254f7a03f..8c8963b8b1a 100644 --- a/packages/amplify-category-function/src/provider-utils/awscloudformation/utils/getDependentFunction.ts +++ b/packages/amplify-category-function/src/provider-utils/awscloudformation/utils/getDependentFunction.ts @@ -27,10 +27,12 @@ export async function lambdasWithApiDependency( const selectedCategories = currentParameters.permissions; let deletedModelFound: boolean; - for (const selectedResources of Object.values(selectedCategories)) { - deletedModelFound = Object.keys(selectedResources).some(r => modelsDeleted.includes(r)); - if (deletedModelFound) { - dependentFunctions.push(lambda); + if (typeof selectedCategories === 'object' && selectedCategories !== null) { + for (const selectedResources of Object.values(selectedCategories)) { + deletedModelFound = Object.keys(selectedResources).some(r => modelsDeleted.includes(r)); + if (deletedModelFound) { + dependentFunctions.push(lambda); + } } } } diff --git a/packages/amplify-category-function/src/provider-utils/awscloudformation/utils/layerConfiguration.ts b/packages/amplify-category-function/src/provider-utils/awscloudformation/utils/layerConfiguration.ts index 81b6397d1bd..47414152306 100644 --- a/packages/amplify-category-function/src/provider-utils/awscloudformation/utils/layerConfiguration.ts +++ b/packages/amplify-category-function/src/provider-utils/awscloudformation/utils/layerConfiguration.ts @@ -1,8 +1,9 @@ import { $TSAny, $TSObject, JSONUtilities, pathManager, recursiveOmit, stateManager } from 'amplify-cli-core'; import _ from 'lodash'; import * as path from 'path'; -import { ephemeralField, deleteVersionsField, layerConfigurationFileName, updateVersionPermissionsField } from './constants'; +import { deleteVersionsField, ephemeralField, layerConfigurationFileName, updateVersionPermissionsField } from './constants'; import { categoryName } from '../../../constants'; +import { getLegacyLayerState, LegacyState, readLegacyRuntimes } from './layerMigrationUtils'; import { LayerParameters, LayerPermission, LayerRuntime, PermissionEnum } from './layerParams'; export type LayerConfiguration = Pick; @@ -24,7 +25,16 @@ export function getLayerConfiguration(layerName: string) { } export function getLayerRuntimes(layerName: string) { - return getLayerConfiguration(layerName).runtimes; + try { + return getLayerConfiguration(layerName).runtimes; + } catch (e) { + // File might not exist for layers that need to be migrated + const legacyState = getLegacyLayerState(layerName); + if (legacyState !== LegacyState.NOT_LEGACY) { + return readLegacyRuntimes(layerName, legacyState); + } + throw e; + } } export function saveLayerRuntimes(layerDirPath: string, runtimes: LayerRuntime[] = []) { diff --git a/packages/amplify-category-function/src/provider-utils/awscloudformation/utils/layerHelpers.ts b/packages/amplify-category-function/src/provider-utils/awscloudformation/utils/layerHelpers.ts index dbc0f4c6807..bd4b27f2259 100644 --- a/packages/amplify-category-function/src/provider-utils/awscloudformation/utils/layerHelpers.ts +++ b/packages/amplify-category-function/src/provider-utils/awscloudformation/utils/layerHelpers.ts @@ -1,4 +1,4 @@ -import { $TSAny, $TSContext, $TSMeta, getPackageManager, pathManager, stateManager } from 'amplify-cli-core'; +import { $TSAny, $TSContext, $TSMeta, $TSObject, getPackageManager, pathManager, stateManager } from 'amplify-cli-core'; import crypto from 'crypto'; import { hashElement, HashElementOptions } from 'folder-hash'; import * as fs from 'fs-extra'; @@ -241,6 +241,14 @@ export function getLayerName(context: $TSContext, layerName: string): string { return isMultiEnvLayer(layerName) ? `${layerName}-${envName}` : layerName; } +export function getLambdaFunctionsDependentOnLayerFromMeta(layerName: string, meta: $TSMeta) { + return Object.entries(meta[categoryName]).filter( + ([_, lambdaFunction]: [string, $TSObject]) => + lambdaFunction.service === ServiceName.LambdaFunction && + lambdaFunction?.dependsOn.filter(dependency => dependency.resourceName === layerName).length > 0, + ); +} + // Check hash results for content changes, bump version if so export async function ensureLayerVersion(context: $TSContext, layerName: string, previousHash?: string) { const currentHash = await hashLayerVersion(pathManager.getResourceDirectoryPath(undefined, categoryName, layerName), layerName); @@ -263,17 +271,6 @@ export function loadPreviousLayerHash(layerName: string): string | undefined { return previousHash; } -export function validFilesize(context: $TSContext, zipPath: string, maxSize = 250) { - try { - const { size } = fs.statSync(zipPath); - const fileSize = Math.round(size / 1024 ** 2); - return fileSize < maxSize; - } catch (error) { - context.print.error(error); - return new Error(`Calculating file size failed: ${zipPath}`); - } -} - // hashes all of the layer contents as well as the files in the layer path (CFN, parameters, etc) export const hashLayerResource = async (layerPath: string, resourceName: string): Promise => { return await hashLayerVersion(layerPath, resourceName, true); diff --git a/packages/amplify-category-function/src/provider-utils/awscloudformation/utils/layerMigrationUtils.ts b/packages/amplify-category-function/src/provider-utils/awscloudformation/utils/layerMigrationUtils.ts index 8776753922a..68acfbdcfd0 100644 --- a/packages/amplify-category-function/src/provider-utils/awscloudformation/utils/layerMigrationUtils.ts +++ b/packages/amplify-category-function/src/provider-utils/awscloudformation/utils/layerMigrationUtils.ts @@ -9,6 +9,12 @@ import { loadPluginFromFactory } from './functionPluginLoader'; import { writeLayerConfigurationFile } from './layerConfiguration'; import { defaultLayerPermission, LayerPermission, LayerRuntime, PermissionEnum } from './layerParams'; +export const enum LegacyState { + NOT_LEGACY, + MULTI_ENV_LEGACY, + SINGLE_ENV_LEGACY, +} + export const enum LegacyPermissionEnum { AwsAccounts = 'awsAccounts', AwsOrg = 'awsOrg', @@ -32,17 +38,16 @@ type LegacyVersionMap = { }; }; -const enum LegacyState { - NOT_LEGACY, - MULTI_ENV_LEGACY, - SINGLE_ENV_LEGACY, -} +type LegacyLayerParametersJson = { + [layerVersionMapKey]: LegacyVersionMap; + runtimes: LegacyRuntime[]; +}; const layerVersionMapKey = 'layerVersionMap'; export async function migrateLegacyLayer(context: $TSContext, layerName: string): Promise { const layerDirPath = pathManager.getResourceDirectoryPath(undefined, categoryName, layerName); - const legacyState = getLegacyLayerState(layerName, layerDirPath); + const legacyState = getLegacyLayerState(layerName); if (legacyState === LegacyState.NOT_LEGACY) { return false; @@ -69,13 +74,10 @@ This change requires a migration. Amplify will create a new Lambda layer version let layerVersionMap: LegacyVersionMap; if (legacyState === LegacyState.MULTI_ENV_LEGACY) { - legacyRuntimeArray = JSONUtilities.readJson(path.join(layerDirPath, LegacyFilename.layerRuntimes)); + legacyRuntimeArray = readLegacyRuntimes(layerName, legacyState); layerVersionMap = stateManager.getMeta()?.[categoryName]?.[layerName]?.[layerVersionMapKey] ?? {}; } else { - ({ layerVersionMap, runtimes: legacyRuntimeArray } = JSONUtilities.readJson<{ - [layerVersionMapKey]: LegacyVersionMap; - runtimes: LegacyRuntime[]; - }>(path.join(layerDirPath, LegacyFilename.layerParameters))); + ({ layerVersionMap, runtimes: legacyRuntimeArray } = readLegacyLayerParametersJson(layerDirPath)); layerConfiguration.nonMultiEnv = true; } @@ -140,7 +142,8 @@ This change requires a migration. Amplify will create a new Lambda layer version return true; } -function getLegacyLayerState(layerName: string, layerDirPath: string): LegacyState { +export function getLegacyLayerState(layerName: string): LegacyState { + const layerDirPath = pathManager.getResourceDirectoryPath(undefined, categoryName, layerName); if (fs.existsSync(path.join(layerDirPath, LegacyFilename.layerParameters))) { return LegacyState.SINGLE_ENV_LEGACY; } @@ -157,20 +160,17 @@ function getLegacyLayerState(layerName: string, layerDirPath: string): LegacySta ${chalk.red('Ensure your layer content is backed up!')}`); } -function migrateAmplifyProjectFiles(layerName: string, latestLegacyHash: string, envName?: string) { - const projectRoot = pathManager.findProjectRoot(); - removeLayerFromTeamProviderInfo(envName, layerName, projectRoot); - const meta = stateManager.getMeta(projectRoot); - - if (meta?.[categoryName]?.[layerName]?.[layerVersionMapKey]) { - meta[categoryName][layerName][layerVersionMapKey] = undefined; +export function readLegacyRuntimes(layerName: string, legacyState: LegacyState): LegacyRuntime[] { + const layerDirPath = pathManager.getResourceDirectoryPath(undefined, categoryName, layerName); + if (legacyState === LegacyState.SINGLE_ENV_LEGACY) { + return readLegacyLayerParametersJson(layerDirPath).runtimes; + } + if (legacyState === LegacyState.MULTI_ENV_LEGACY) { + return JSONUtilities.readJson(path.join(layerDirPath, LegacyFilename.layerRuntimes)); } - - _.set(meta, [categoryName, layerName, versionHash], latestLegacyHash); - stateManager.setMeta(projectRoot, meta); } -export function removeLayerFromTeamProviderInfo(envName: string, layerName: string, projectRoot?: string) { +export function removeLayerFromTeamProviderInfo(projectRoot: string | undefined, envName: string, layerName: string) { const nonCfnDataKey = 'nonCFNdata'; const teamProviderInfo = stateManager.getTeamProviderInfo(projectRoot); @@ -183,3 +183,20 @@ export function removeLayerFromTeamProviderInfo(envName: string, layerName: stri } stateManager.setTeamProviderInfo(projectRoot, teamProviderInfo); } + +function readLegacyLayerParametersJson(layerDirPath: string) { + return JSONUtilities.readJson(path.join(layerDirPath, LegacyFilename.layerParameters)); +} + +function migrateAmplifyProjectFiles(layerName: string, latestLegacyHash: string, envName?: string) { + const projectRoot = pathManager.findProjectRoot(); + removeLayerFromTeamProviderInfo(projectRoot, envName, layerName); + const meta = stateManager.getMeta(projectRoot); + + if (meta?.[categoryName]?.[layerName]?.[layerVersionMapKey]) { + meta[categoryName][layerName][layerVersionMapKey] = undefined; + } + + _.set(meta, [categoryName, layerName, versionHash], latestLegacyHash); + stateManager.setMeta(projectRoot, meta); +} diff --git a/packages/amplify-category-function/src/provider-utils/awscloudformation/utils/packageFunction.ts b/packages/amplify-category-function/src/provider-utils/awscloudformation/utils/packageFunction.ts index fd2fce1608b..5ceef39803a 100644 --- a/packages/amplify-category-function/src/provider-utils/awscloudformation/utils/packageFunction.ts +++ b/packages/amplify-category-function/src/provider-utils/awscloudformation/utils/packageFunction.ts @@ -1,19 +1,23 @@ -import { pathManager } from 'amplify-cli-core'; -import * as path from 'path'; +import { convertNumBytes, getFolderSize, pathManager } from 'amplify-cli-core'; +import { LambdaLayer } from 'amplify-function-plugin-interface'; import * as fs from 'fs-extra'; +import * as path from 'path'; +import { lambdaPackageLimitInMB } from './constants'; +import { categoryName } from '../../../constants'; import { Packager } from '../types/packaging-types'; import { getRuntimeManager } from './functionPluginLoader'; +import { loadFunctionParameters } from './loadFunctionParameters'; import { zipPackage } from './zipResource'; /** * Packages lambda source code and artifacts into a lambda-compatible .zip file */ export const packageFunction: Packager = async (context, resource) => { - const resourcePath = path.join(pathManager.getBackendDirPath(), resource.category, resource.resourceName); + const resourcePath = pathManager.getResourceDirectoryPath(undefined, resource.category, resource.resourceName); const runtimeManager = await getRuntimeManager(context, resource.resourceName); - const distDir = path.join(resourcePath, 'dist'); - fs.ensureDirSync(distDir); - const destination = path.join(distDir, 'latest-build.zip'); + const distDirPath = path.join(resourcePath, 'dist'); + fs.ensureDirSync(distDirPath); + const destination = path.join(distDirPath, 'latest-build.zip'); const packageRequest = { env: context.amplify.getEnvInfo().envName, srcRoot: resourcePath, @@ -28,6 +32,30 @@ export const packageFunction: Packager = async (context, resource) => { if (packageHash) { await zipPackage(packageResult.zipEntries, destination); } + + const functionSizeInBytes = await getFolderSize(path.join(resourcePath, 'src')); + let layersSizeInBytes = 0; + + const functionParameters: { lambdaLayers?: LambdaLayer[] } = loadFunctionParameters(resourcePath); + + for (const layer of functionParameters?.lambdaLayers || []) { + // Add up all the project lib/opt folders + if (layer.type === 'ProjectLayer') { + const layerDirPath = pathManager.getResourceDirectoryPath(undefined, categoryName, layer.resourceName); + layersSizeInBytes += await getFolderSize([path.join(layerDirPath, 'lib'), path.join(layerDirPath, 'opt')]); + } + } + + if (functionSizeInBytes + layersSizeInBytes > lambdaPackageLimitInMB * 1024 ** 2) { + throw new Error( + `Total size of Lambda function ${ + resource.resourceName + } plus it's dependent layers exceeds ${lambdaPackageLimitInMB}MB limit. Lambda function is ${convertNumBytes( + functionSizeInBytes, + ).toMB()}MB. Dependent Lambda layers are ${convertNumBytes(layersSizeInBytes).toMB()}MB.`, + ); + } + const zipFilename = packageHash ? `${resource.resourceName}-${packageHash}-build.zip` : resource.distZipFilename ?? `${resource.category}-${resource.resourceName}-build.zip`; diff --git a/packages/amplify-category-function/src/provider-utils/awscloudformation/utils/packageLayer.ts b/packages/amplify-category-function/src/provider-utils/awscloudformation/utils/packageLayer.ts index 301ffa8aa95..a26a62bfced 100644 --- a/packages/amplify-category-function/src/provider-utils/awscloudformation/utils/packageLayer.ts +++ b/packages/amplify-category-function/src/provider-utils/awscloudformation/utils/packageLayer.ts @@ -1,21 +1,19 @@ -import { $TSAny, $TSContext, pathManager } from 'amplify-cli-core'; -import { ZipEntry } from 'amplify-function-plugin-interface'; -import * as path from 'path'; +import { $TSAny, $TSContext, convertNumBytes, getFolderSize, pathManager } from 'amplify-cli-core'; +import { FunctionRuntimeLifecycleManager, ZipEntry } from 'amplify-function-plugin-interface'; +import chalk from 'chalk'; import * as fs from 'fs-extra'; import _ from 'lodash'; -import chalk from 'chalk'; import { EOL } from 'os'; +import * as path from 'path'; +import { lambdaLayerNewVersionWalkthrough } from '../service-walkthroughs/lambdaLayerWalkthrough'; import { Packager } from '../types/packaging-types'; -import { loadLayerConfigurationFile } from './layerConfiguration'; -import { FunctionRuntimeLifecycleManager } from 'amplify-function-plugin-interface'; -import { ServiceName, versionHash } from './constants'; +import { accessPermissions, description, lambdaPackageLimitInMB, ServiceName, versionHash } from './constants'; import { LayerCloudState } from './layerCloudState'; -import { loadPreviousLayerHash, ensureLayerVersion, validFilesize, loadStoredLayerParameters, getChangedResources } from './layerHelpers'; +import { loadLayerConfigurationFile } from './layerConfiguration'; +import { ensureLayerVersion, getChangedResources, loadPreviousLayerHash, loadStoredLayerParameters } from './layerHelpers'; import { defaultLayerPermission } from './layerParams'; -import { zipPackage } from './zipResource'; -import { accessPermissions, description } from './constants'; import { updateLayerArtifacts } from './storeResources'; -import { lambdaLayerNewVersionWalkthrough } from '../service-walkthroughs/lambdaLayerWalkthrough'; +import { zipPackage } from './zipResource'; /** * Packages lambda layer code and artifacts into a lambda-compatible .zip file @@ -35,6 +33,18 @@ export const packageLayer: Packager = async (context, resource) => { const distDir = path.join(resourcePath, 'dist'); fs.ensureDirSync(distDir); const destination = path.join(distDir, 'latest-build.zip'); + + // check total layer size is less than 250MB + let layerSizeInBytes = 0; + // Add up all the lib/opt folders + layerSizeInBytes += await getFolderSize([path.join(resourcePath, 'lib'), path.join(resourcePath, 'opt')]); + + if (layerSizeInBytes > lambdaPackageLimitInMB * 1024 ** 2) { + throw new Error( + `Lambda layer ${resource.resourceName} is too large: ${convertNumBytes(layerSizeInBytes).toMB()}/${lambdaPackageLimitInMB} MB`, + ); + } + let zipEntries: ZipEntry[] = [{ sourceFolder: path.join(resourcePath, 'opt') }]; for (const runtime of runtimes) { @@ -64,6 +74,7 @@ export const packageLayer: Packager = async (context, resource) => { zipEntries = [...zipEntries, ...packageResult.zipEntries]; } } + await zipPackage(zipEntries, destination); const layerCloudState = LayerCloudState.getInstance(resource.resourceName); @@ -73,12 +84,7 @@ export const packageLayer: Packager = async (context, resource) => { } const zipFilename = createLayerZipFilename(resource.resourceName, layerCloudState.latestVersionLogicalId); - // check zip size is less than 250MB - if (validFilesize(context, destination)) { - context.amplify.updateAmplifyMetaAfterPackage(resource, zipFilename, { resourceKey: versionHash, hashValue: currentHash }); - } else { - throw new Error('File size greater than 250MB'); - } + context.amplify.updateAmplifyMetaAfterPackage(resource, zipFilename, { resourceKey: versionHash, hashValue: currentHash }); return { newPackageCreated: true, zipFilename, zipFilePath: destination }; }; diff --git a/packages/amplify-category-function/src/provider-utils/awscloudformation/utils/storeResources.ts b/packages/amplify-category-function/src/provider-utils/awscloudformation/utils/storeResources.ts index 998952142f5..ddae3a95f74 100644 --- a/packages/amplify-category-function/src/provider-utils/awscloudformation/utils/storeResources.ts +++ b/packages/amplify-category-function/src/provider-utils/awscloudformation/utils/storeResources.ts @@ -86,7 +86,7 @@ export const updateLayerArtifacts = async ( export function removeLayerArtifacts(context: $TSContext, layerName: string) { if (isMultiEnvLayer(layerName)) { - removeLayerFromTeamProviderInfo(context.amplify.getEnvInfo().envName, layerName); + removeLayerFromTeamProviderInfo(undefined, context.amplify.getEnvInfo().envName, layerName); } } diff --git a/packages/amplify-category-hosting/CHANGELOG.md b/packages/amplify-category-hosting/CHANGELOG.md index 49fdb2eced2..c6765a822e5 100644 --- a/packages/amplify-category-hosting/CHANGELOG.md +++ b/packages/amplify-category-hosting/CHANGELOG.md @@ -3,6 +3,38 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [2.7.16](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-hosting@2.7.15...amplify-category-hosting@2.7.16) (2021-08-06) + +**Note:** Version bump only for package amplify-category-hosting + + + + + +## [2.7.15](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-hosting@2.7.14...amplify-category-hosting@2.7.15) (2021-07-30) + +**Note:** Version bump only for package amplify-category-hosting + + + + + +## [2.7.14](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-hosting@2.7.13...amplify-category-hosting@2.7.14) (2021-07-27) + +**Note:** Version bump only for package amplify-category-hosting + + + + + +## [2.7.13](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-hosting@2.7.12...amplify-category-hosting@2.7.13) (2021-07-16) + +**Note:** Version bump only for package amplify-category-hosting + + + + + ## [2.7.12](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-hosting@2.7.11...amplify-category-hosting@2.7.12) (2021-06-30) **Note:** Version bump only for package amplify-category-hosting diff --git a/packages/amplify-category-hosting/package.json b/packages/amplify-category-hosting/package.json index 7feede820cf..b55d6769032 100644 --- a/packages/amplify-category-hosting/package.json +++ b/packages/amplify-category-hosting/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-hosting", - "version": "2.7.12", + "version": "2.7.16", "description": "amplify-cli hosting plugin", "repository": { "type": "git", @@ -18,8 +18,8 @@ "test": "jest --coverage" }, "dependencies": { - "amplify-cli-core": "1.24.0", - "chalk": "^3.0.0", + "amplify-cli-core": "1.26.0", + "chalk": "^4.1.1", "fs-extra": "^8.1.0", "inquirer": "^7.3.3", "mime-types": "^2.1.26", diff --git a/packages/amplify-category-interactions/CHANGELOG.md b/packages/amplify-category-interactions/CHANGELOG.md index 8144143169b..71a694d2900 100644 --- a/packages/amplify-category-interactions/CHANGELOG.md +++ b/packages/amplify-category-interactions/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [2.6.3](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-interactions@2.6.2...amplify-category-interactions@2.6.3) (2021-07-30) + + +### Bug Fixes + +* lambda timeout should be an integer type ([#7699](https://github.com/aws-amplify/amplify-cli/issues/7699)) ([cbacf4d](https://github.com/aws-amplify/amplify-cli/commit/cbacf4d3e497421855c09825970e025550aacfd7)) + + + + + ## [2.6.2](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-interactions@2.6.1...amplify-category-interactions@2.6.2) (2021-03-05) diff --git a/packages/amplify-category-interactions/package.json b/packages/amplify-category-interactions/package.json index fd590a113ae..85e260a52db 100644 --- a/packages/amplify-category-interactions/package.json +++ b/packages/amplify-category-interactions/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-interactions", - "version": "2.6.2", + "version": "2.6.3", "description": "amplify-cli interactions plugin", "repository": { "type": "git", diff --git a/packages/amplify-category-interactions/provider-utils/awscloudformation/cloudformation-templates/lex-cloudformation-template.json.ejs b/packages/amplify-category-interactions/provider-utils/awscloudformation/cloudformation-templates/lex-cloudformation-template.json.ejs index 61085d08c21..7bb9a92ecf0 100644 --- a/packages/amplify-category-interactions/provider-utils/awscloudformation/cloudformation-templates/lex-cloudformation-template.json.ejs +++ b/packages/amplify-category-interactions/provider-utils/awscloudformation/cloudformation-templates/lex-cloudformation-template.json.ejs @@ -67,7 +67,7 @@ "Role": { "Fn::GetAtt" : ["LambdaExecutionRole", "Arn"] }, "Environment": {"Variables" : { "ENV": {"Ref": "env"}}}, "Runtime": "nodejs14.x", - "Timeout": "300" + "Timeout": 300 } }, diff --git a/packages/amplify-category-notifications/CHANGELOG.md b/packages/amplify-category-notifications/CHANGELOG.md index b0a9df2cc57..c5041b82dbd 100644 --- a/packages/amplify-category-notifications/CHANGELOG.md +++ b/packages/amplify-category-notifications/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [2.19.4](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-notifications@2.19.3...amplify-category-notifications@2.19.4) (2021-07-16) + + +### Bug Fixes + +* **amplify-category-notifications:** trim whitespace from fcm keys ([#7456](https://github.com/aws-amplify/amplify-cli/issues/7456)) ([155a071](https://github.com/aws-amplify/amplify-cli/commit/155a07156cb3467d9e6f6b9cb088bab21ab3bab9)), closes [#7440](https://github.com/aws-amplify/amplify-cli/issues/7440) + + + + + ## [2.19.3](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-notifications@2.19.2...amplify-category-notifications@2.19.3) (2021-06-24) diff --git a/packages/amplify-category-notifications/__tests__/lib/channel-FCM.test.js b/packages/amplify-category-notifications/__tests__/lib/channel-FCM.test.js new file mode 100644 index 00000000000..25e8f40bc7c --- /dev/null +++ b/packages/amplify-category-notifications/__tests__/lib/channel-FCM.test.js @@ -0,0 +1,133 @@ +const inquirer = require('inquirer'); +const channelName = 'FCM'; +const channelFCM = require('../../lib/channel-FCM'); + +const mockInquirer = answers => { + inquirer.prompt = async prompts => { + [].concat(prompts).forEach(function (prompt) { + if (!(prompt.name in answers) && typeof prompt.default !== 'undefined') { + answers[prompt.name] = prompt.default; + } + }); + + return answers; + }; +}; + +describe('channel-FCM', () => { + const mockServiceOutput = {}; + const mockChannelOutput = { Enabled: true }; + mockServiceOutput[channelName] = mockChannelOutput; + + const mockPinpointResponseErr = new Error('channel-FCM.test.js error'); + const mockPinpointResponseData = { + FCMChannelResponse: {}, + }; + + const mockPinpointClient = { + updateGcmChannel: jest.fn((_, cb) => { + return new Promise(() => { + cb(null, mockPinpointResponseData); + }); + }), + }; + + const mockPinpointClientReject = { + updateGcmChannel: jest.fn((_, cb) => { + return new Promise(() => { + cb(mockPinpointResponseErr); + }); + }), + }; + + let mockContext = { + exeInfo: { + serviceMeta: { + output: mockServiceOutput, + }, + pinpointClient: mockPinpointClient, + }, + print: { + info: jest.fn(), + error: jest.fn(), + }, + }; + + let mockContextReject = { + exeInfo: { + serviceMeta: { + output: mockServiceOutput, + }, + pinpointClient: mockPinpointClientReject, + }, + print: { + info: jest.fn(), + error: jest.fn(), + }, + }; + + test('configure', async () => { + mockChannelOutput.Enabled = true; + mockInquirer({ disableChannel: true }); + + await channelFCM.configure(mockContext).then(() => { + expect(mockPinpointClient.updateGcmChannel).toBeCalled(); + }); + + mockChannelOutput.Enabled = true; + mockInquirer({ disableChannel: false }); + await channelFCM.configure(mockContext).then(() => { + expect(mockPinpointClient.updateGcmChannel).toBeCalled(); + }); + + mockChannelOutput.Enabled = false; + mockInquirer({ enableChannel: true }); + await channelFCM.configure(mockContext).then(() => { + expect(mockPinpointClient.updateGcmChannel).toBeCalled(); + }); + }); + + test('enable', async () => { + mockInquirer({ ApiKey: 'ApiKey-abc123' }); + await channelFCM.enable(mockContext, 'successMessage').then(data => { + expect(mockPinpointClient.updateGcmChannel).toBeCalled(); + expect(data).toEqual(mockPinpointResponseData); + }); + }); + + test('enable with newline', async () => { + mockInquirer({ ApiKey: 'ApiKey-abc123\n' }); + await channelFCM.enable(mockContext, 'successMessage').then(data => { + expect(mockPinpointClient.updateGcmChannel).toBeCalledWith( + { + ApplicationId: undefined, + GCMChannelRequest: { + ApiKey: 'ApiKey-abc123', + Enabled: true, + }, + }, + expect.anything(), + ); + expect(data).toEqual(mockPinpointResponseData); + }); + }); + + test('enable unsuccessful', async () => { + mockInquirer({ ApiKey: 'ApiKey-abc123' }); + await channelFCM.enable(mockContextReject, 'successMessage').catch(err => { + expect(mockPinpointClient.updateGcmChannel).toBeCalled(); + expect(err).toEqual(mockPinpointResponseErr); + }); + }); + + test('disable', async () => { + await channelFCM.disable(mockContext).then(data => { + expect(mockPinpointClient.updateGcmChannel).toBeCalled(); + expect(data).toEqual(mockPinpointResponseData); + }); + }); + + test('disable unsuccessful', async () => { + await expect(channelFCM.disable(mockContextReject)).rejects.toThrow(mockPinpointResponseErr); + }); +}); diff --git a/packages/amplify-category-notifications/lib/channel-FCM.js b/packages/amplify-category-notifications/lib/channel-FCM.js index bbc283bb157..8852636899d 100644 --- a/packages/amplify-category-notifications/lib/channel-FCM.js +++ b/packages/amplify-category-notifications/lib/channel-FCM.js @@ -51,7 +51,7 @@ async function enable(context, successMessage) { default: channelOutput.ApiKey, }, ]; - answers = await inquirer.prompt(questions); + answers = trimAnswers(await inquirer.prompt(questions)); } const params = { @@ -104,7 +104,7 @@ async function disable(context) { default: channelOutput.ApiKey, }, ]; - answers = await inquirer.prompt(questions); + answers = trimAnswers(await inquirer.prompt(questions)); } const params = { @@ -154,6 +154,15 @@ function pull(context, pinpointApp) { }); } +function trimAnswers(answers) { + for (const [key, value] of Object.entries(answers)) { + if (typeof answers[key] === 'string') { + answers[key] = value.trim(); + } + } + return answers; +} + module.exports = { configure, enable, diff --git a/packages/amplify-category-notifications/package.json b/packages/amplify-category-notifications/package.json index cf551cef647..968ad08dffa 100644 --- a/packages/amplify-category-notifications/package.json +++ b/packages/amplify-category-notifications/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-notifications", - "version": "2.19.3", + "version": "2.19.4", "description": "amplify-cli notifications plugin", "repository": { "type": "git", diff --git a/packages/amplify-category-predictions/CHANGELOG.md b/packages/amplify-category-predictions/CHANGELOG.md index b9b30c8c8ca..90a7245e683 100644 --- a/packages/amplify-category-predictions/CHANGELOG.md +++ b/packages/amplify-category-predictions/CHANGELOG.md @@ -3,6 +3,49 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [2.9.7](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-predictions@2.9.6...amplify-category-predictions@2.9.7) (2021-08-06) + +**Note:** Version bump only for package amplify-category-predictions + + + + + +## [2.9.6](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-predictions@2.9.5...amplify-category-predictions@2.9.6) (2021-07-30) + + +### Bug Fixes + +* lambda timeout should be an integer type ([#7699](https://github.com/aws-amplify/amplify-cli/issues/7699)) ([cbacf4d](https://github.com/aws-amplify/amplify-cli/commit/cbacf4d3e497421855c09825970e025550aacfd7)) + + + + + +## [2.9.5](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-predictions@2.9.4...amplify-category-predictions@2.9.5) (2021-07-27) + + +### Bug Fixes + +* upgrade node default runtime to 14 ([#7700](https://github.com/aws-amplify/amplify-cli/issues/7700)) ([47968cc](https://github.com/aws-amplify/amplify-cli/commit/47968cc9c704ac1cffcbd0dbe40d164b1b1d48d6)) + + +### Reverts + +* Revert "fix: upgrade node default runtime to 14 (#7700)" (#7763) ([3ab8769](https://github.com/aws-amplify/amplify-cli/commit/3ab87694203584cdfa208bf75e648e0e944f5e18)), closes [#7700](https://github.com/aws-amplify/amplify-cli/issues/7700) [#7763](https://github.com/aws-amplify/amplify-cli/issues/7763) + + + + + +## [2.9.4](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-predictions@2.9.3...amplify-category-predictions@2.9.4) (2021-07-16) + +**Note:** Version bump only for package amplify-category-predictions + + + + + ## [2.9.3](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-predictions@2.9.2...amplify-category-predictions@2.9.3) (2021-06-30) **Note:** Version bump only for package amplify-category-predictions diff --git a/packages/amplify-category-predictions/package.json b/packages/amplify-category-predictions/package.json index 6ced8aace39..27c0fa1c47a 100644 --- a/packages/amplify-category-predictions/package.json +++ b/packages/amplify-category-predictions/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-predictions", - "version": "2.9.3", + "version": "2.9.7", "description": "amplify-cli predictions plugin", "repository": { "type": "git", @@ -15,9 +15,9 @@ "aws" ], "dependencies": { - "amplify-cli-core": "1.24.0", + "amplify-cli-core": "1.26.0", "aws-sdk": "^2.919.0", - "chalk": "^3.0.0", + "chalk": "^4.1.1", "fs-extra": "^8.1.0", "inquirer": "^7.3.3", "uuid": "^3.4.0" diff --git a/packages/amplify-category-predictions/provider-utils/awscloudformation/assets/identifyCFNGenerate.js b/packages/amplify-category-predictions/provider-utils/awscloudformation/assets/identifyCFNGenerate.js index 1b03a7197dd..01abc022f22 100644 --- a/packages/amplify-category-predictions/provider-utils/awscloudformation/assets/identifyCFNGenerate.js +++ b/packages/amplify-category-predictions/provider-utils/awscloudformation/assets/identifyCFNGenerate.js @@ -522,7 +522,7 @@ function generateLambdaAccessForRekognition(identifyCFNFile, functionName, s3Res }, Handler: 'index.handler', Runtime: 'nodejs12.x', - Timeout: '300', + Timeout: 300, Role: { 'Fn::GetAtt': ['CollectionsLambdaExecutionRole', 'Arn'], }, diff --git a/packages/amplify-category-predictions/provider-utils/awscloudformation/cloudformation-templates/identify-template.json.ejs b/packages/amplify-category-predictions/provider-utils/awscloudformation/cloudformation-templates/identify-template.json.ejs index 4e1663ca6e3..04996eed40b 100644 --- a/packages/amplify-category-predictions/provider-utils/awscloudformation/cloudformation-templates/identify-template.json.ejs +++ b/packages/amplify-category-predictions/provider-utils/awscloudformation/cloudformation-templates/identify-template.json.ejs @@ -354,7 +354,7 @@ }, "Handler": "index.handler", "Runtime": "nodejs12.x", - "Timeout": "300", + "Timeout": 300, "Role": { "Fn::GetAtt": [ "CollectionsLambdaExecutionRole", diff --git a/packages/amplify-category-predictions/provider-utils/awscloudformation/triggers/s3/lambda-cloudformation-template.json.ejs b/packages/amplify-category-predictions/provider-utils/awscloudformation/triggers/s3/lambda-cloudformation-template.json.ejs index 8aedb6505ac..d6faed091bd 100644 --- a/packages/amplify-category-predictions/provider-utils/awscloudformation/triggers/s3/lambda-cloudformation-template.json.ejs +++ b/packages/amplify-category-predictions/provider-utils/awscloudformation/triggers/s3/lambda-cloudformation-template.json.ejs @@ -70,7 +70,7 @@ }, "Role": { "Fn::GetAtt" : ["LambdaExecutionRole", "Arn"] }, "Runtime": "nodejs14.x", - "Timeout": "900" + "Timeout": 900 } }, "LambdaExecutionRole": { diff --git a/packages/amplify-category-storage/CHANGELOG.md b/packages/amplify-category-storage/CHANGELOG.md index 6abd40a34c5..908b8f7c7c0 100644 --- a/packages/amplify-category-storage/CHANGELOG.md +++ b/packages/amplify-category-storage/CHANGELOG.md @@ -3,6 +3,44 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [2.12.4](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-storage@2.12.3...amplify-category-storage@2.12.4) (2021-08-06) + +**Note:** Version bump only for package amplify-category-storage + + + + + +## [2.12.3](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-storage@2.12.2...amplify-category-storage@2.12.3) (2021-07-30) + + +### Bug Fixes + +* lambda timeout should be an integer type ([#7699](https://github.com/aws-amplify/amplify-cli/issues/7699)) ([cbacf4d](https://github.com/aws-amplify/amplify-cli/commit/cbacf4d3e497421855c09825970e025550aacfd7)) + + + + + +## [2.12.2](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-storage@2.12.1...amplify-category-storage@2.12.2) (2021-07-27) + +**Note:** Version bump only for package amplify-category-storage + + + + + +## [2.12.1](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-storage@2.12.0...amplify-category-storage@2.12.1) (2021-07-16) + + +### Bug Fixes + +* checkout into existing env with new LL ([#7687](https://github.com/aws-amplify/amplify-cli/issues/7687)) ([3e2e630](https://github.com/aws-amplify/amplify-cli/commit/3e2e6305b5a74db2a282dc33b0cc5d24f1c8eaaf)) + + + + + # [2.12.0](https://github.com/aws-amplify/amplify-cli/compare/amplify-category-storage@2.11.12...amplify-category-storage@2.12.0) (2021-06-30) diff --git a/packages/amplify-category-storage/package.json b/packages/amplify-category-storage/package.json index d295e970a09..636b28466b9 100644 --- a/packages/amplify-category-storage/package.json +++ b/packages/amplify-category-storage/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-storage", - "version": "2.12.0", + "version": "2.12.4", "description": "amplify-cli storage plugin", "repository": { "type": "git", @@ -22,8 +22,8 @@ "aws" ], "dependencies": { - "amplify-cli-core": "1.24.0", - "amplify-util-import": "1.5.3", + "amplify-cli-core": "1.26.0", + "amplify-util-import": "1.5.7", "cloudform-types": "^4.2.0", "enquirer": "^2.3.6", "fs-extra": "^8.1.0", diff --git a/packages/amplify-category-storage/resources/triggers/dynamoDB/lambda-cloudformation-template.json.ejs b/packages/amplify-category-storage/resources/triggers/dynamoDB/lambda-cloudformation-template.json.ejs index f89ce5f723c..4a6f2c8d091 100644 --- a/packages/amplify-category-storage/resources/triggers/dynamoDB/lambda-cloudformation-template.json.ejs +++ b/packages/amplify-category-storage/resources/triggers/dynamoDB/lambda-cloudformation-template.json.ejs @@ -53,7 +53,7 @@ }, "Role": { "Fn::GetAtt" : ["LambdaExecutionRole", "Arn"] }, "Runtime": "nodejs14.x", - "Timeout": "25" + "Timeout": 25 } }, "LambdaExecutionRole": { diff --git a/packages/amplify-category-storage/resources/triggers/s3/lambda-cloudformation-template.json.ejs b/packages/amplify-category-storage/resources/triggers/s3/lambda-cloudformation-template.json.ejs index f89ce5f723c..4a6f2c8d091 100644 --- a/packages/amplify-category-storage/resources/triggers/s3/lambda-cloudformation-template.json.ejs +++ b/packages/amplify-category-storage/resources/triggers/s3/lambda-cloudformation-template.json.ejs @@ -53,7 +53,7 @@ }, "Role": { "Fn::GetAtt" : ["LambdaExecutionRole", "Arn"] }, "Runtime": "nodejs14.x", - "Timeout": "25" + "Timeout": 25 } }, "LambdaExecutionRole": { diff --git a/packages/amplify-category-storage/src/__tests__/provider-utils/awscloudformation/cfn-template-utils.test.ts b/packages/amplify-category-storage/src/__tests__/provider-utils/awscloudformation/cfn-template-utils.test.ts index 6c39960a109..60403b92a05 100644 --- a/packages/amplify-category-storage/src/__tests__/provider-utils/awscloudformation/cfn-template-utils.test.ts +++ b/packages/amplify-category-storage/src/__tests__/provider-utils/awscloudformation/cfn-template-utils.test.ts @@ -10,7 +10,7 @@ pathManager_mock.getBackendDirPath.mockReturnValue('/test/path'); describe('get existing table column names', () => { it('returns empty array when no template exists', async () => { - readCFNTemplate_mock.mockRejectedValueOnce('the template does not exist'); + readCFNTemplate_mock.mockResolvedValueOnce(undefined); const result = await getExistingTableColumnNames('testResource'); expect(result).toEqual([]); }); diff --git a/packages/amplify-category-storage/src/provider-utils/awscloudformation/cfn-template-utils.ts b/packages/amplify-category-storage/src/provider-utils/awscloudformation/cfn-template-utils.ts index 897baa68fce..0ba81f3368f 100644 --- a/packages/amplify-category-storage/src/provider-utils/awscloudformation/cfn-template-utils.ts +++ b/packages/amplify-category-storage/src/provider-utils/awscloudformation/cfn-template-utils.ts @@ -30,12 +30,8 @@ const loadCfnTemplateSafe = async (resourceName?: string): Promise