diff --git a/.eslint-dictionary.json b/.eslint-dictionary.json index 7772f38ab74..dee59decbab 100644 --- a/.eslint-dictionary.json +++ b/.eslint-dictionary.json @@ -6,6 +6,7 @@ "admingroup", "adminui", "aggs", + "al2023", "allowlist", "alphanumerics", "amazonaws", @@ -198,6 +199,7 @@ "igrantable", "indexable", "indicies", + "Infos", "integ", "integtest", "integtestfn", diff --git a/codebuild_specs/e2e_workflow_generated.yml b/codebuild_specs/e2e_workflow_generated.yml index abd7e7ab42a..858f7df6824 100644 --- a/codebuild_specs/e2e_workflow_generated.yml +++ b/codebuild_specs/e2e_workflow_generated.yml @@ -474,11 +474,18 @@ batch: TEST_SUITE: src/__tests__/api_6a.test.ts|src/__tests__/auth_7b.test.ts|src/__tests__/export-pull-b.test.ts depend-on: - upb - - identifier: l_function_3a_init_special_case_http_migration + - identifier: l_function_3a_dotnet_function_3a_go_function_3a_nodejs buildspec: codebuild_specs/run_e2e_tests_linux.yml env: variables: - TEST_SUITE: src/__tests__/function_3a.test.ts|src/__tests__/init-special-case.test.ts|src/__tests__/transformer-migrations/http-migration.test.ts + TEST_SUITE: src/__tests__/function_3a_dotnet.test.ts|src/__tests__/function_3a_go.test.ts|src/__tests__/function_3a_nodejs.test.ts + depend-on: + - upb + - identifier: l_function_3a_python_init_special_case_http_migration + buildspec: codebuild_specs/run_e2e_tests_linux.yml + env: + variables: + TEST_SUITE: src/__tests__/function_3a_python.test.ts|src/__tests__/init-special-case.test.ts|src/__tests__/transformer-migrations/http-migration.test.ts depend-on: - upb - identifier: l_schema_auth_12_schema_auth_3_schema_function_2 diff --git a/codebuild_specs/wait_for_ids.json b/codebuild_specs/wait_for_ids.json index e1bc0af16f0..d1de355194f 100644 --- a/codebuild_specs/wait_for_ids.json +++ b/codebuild_specs/wait_for_ids.json @@ -50,7 +50,8 @@ "l_function_1_storage_5", "l_function_2b_function_7_api_connection_migration2", "l_function_2c_function_3b_function_4", - "l_function_3a_init_special_case_http_migration", + "l_function_3a_dotnet_function_3a_go_function_3a_nodejs", + "l_function_3a_python_init_special_case_http_migration", "l_function_6_storage_2_export", "l_function_8_schema_iterative_update_locking_api_lambda_auth_2", "l_general_config_headless_init_help_hooks_c", diff --git a/package.json b/package.json index 593bee830ae..e0e8898138f 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "link-dev": "mkdir -p .bin/ && cd packages/amplify-cli && ln -s \"$(pwd)/bin/amplify\" ../../.bin/amplify-dev && cd ../../", "link-win": "node ./scripts/link-bin.js packages/amplify-cli/bin/amplify amplify-dev", "lint-check-package-json": "yarn eslint --no-eslintrc --config .eslint.package.json.js '**/package.json'", - "lint-check": "yarn eslint . --ext .js,.jsx,.ts,.tsx --max-warnings=773", + "lint-check": "yarn eslint . --ext .js,.jsx,.ts,.tsx --max-warnings=755", "lint-fix-package-json": "yarn lint-check-package-json --fix", "lint-fix": "git diff --name-only --cached --diff-filter d | grep -E '\\.(js|jsx|ts|tsx)$' | xargs eslint --fix --quiet", "mergewords": "yarn ts-node ./scripts/handle-dict-conflicts.ts", diff --git a/packages/amplify-category-auth/src/provider-utils/awscloudformation/auth-stack-builder/auth-stack-transform.ts b/packages/amplify-category-auth/src/provider-utils/awscloudformation/auth-stack-builder/auth-stack-transform.ts index 40c4a34d081..99c3a45ffd7 100644 --- a/packages/amplify-category-auth/src/provider-utils/awscloudformation/auth-stack-builder/auth-stack-transform.ts +++ b/packages/amplify-category-auth/src/provider-utils/awscloudformation/auth-stack-builder/auth-stack-transform.ts @@ -4,7 +4,6 @@ import { AmplifyCategories, AmplifyCategoryTransform, AmplifyError, - AmplifyStackTemplate, AmplifySupportedService, buildOverrideDir, CFNTemplateFormat, @@ -16,7 +15,6 @@ import { Template, writeCFNTemplate, } from '@aws-amplify/amplify-cli-core'; -import { formatter } from '@aws-amplify/amplify-prompts'; import * as cdk from 'aws-cdk-lib'; import * as fs from 'fs-extra'; import _ from 'lodash'; @@ -95,7 +93,7 @@ export class AmplifyAuthTransform extends AmplifyCategoryTransform { this.addCfnParameters(props); // add CFN condition - this.addCfnConditions(props); + this.addCfnConditions(); // generate Resources await this._authTemplateObj.generateCognitoStackResources(props); @@ -544,7 +542,7 @@ export class AmplifyAuthTransform extends AmplifyCategoryTransform { /** * adds cfn conditions */ - private addCfnConditions = (props: CognitoStackOptions): void => { + private addCfnConditions = (): void => { this._authTemplateObj.addCfnCondition( { expression: cdk.Fn.conditionEquals(cdk.Fn.ref('env'), 'NONE'), diff --git a/packages/amplify-category-auth/src/provider-utils/awscloudformation/auth-stack-builder/user-pool-group-stack-transform.ts b/packages/amplify-category-auth/src/provider-utils/awscloudformation/auth-stack-builder/user-pool-group-stack-transform.ts index 82b78e4e4aa..21b93a91fc6 100644 --- a/packages/amplify-category-auth/src/provider-utils/awscloudformation/auth-stack-builder/user-pool-group-stack-transform.ts +++ b/packages/amplify-category-auth/src/provider-utils/awscloudformation/auth-stack-builder/user-pool-group-stack-transform.ts @@ -4,7 +4,6 @@ import { AmplifyCategories, AmplifyCategoryTransform, AmplifyError, - AmplifyStackTemplate, AmplifySupportedService, buildOverrideDir, CFNTemplateFormat, @@ -14,9 +13,7 @@ import { Template, writeCFNTemplate, } from '@aws-amplify/amplify-cli-core'; -import { formatter } from '@aws-amplify/amplify-prompts'; import * as cdk from 'aws-cdk-lib'; -import * as fs from 'fs-extra'; import * as path from 'path'; import { AuthInputState } from '../auth-inputs-manager/auth-input-state'; import { CognitoCLIInputs } from '../service-walkthrough-types/awsCognito-user-input-types'; diff --git a/packages/amplify-category-auth/src/provider-utils/awscloudformation/import/index.ts b/packages/amplify-category-auth/src/provider-utils/awscloudformation/import/index.ts index 25d272f7e57..e5808e479dc 100644 --- a/packages/amplify-category-auth/src/provider-utils/awscloudformation/import/index.ts +++ b/packages/amplify-category-auth/src/provider-utils/awscloudformation/import/index.ts @@ -1130,7 +1130,7 @@ export const importedAuthEnvInit = async ( answers.appClientWeb = questionParameters.webClients!.find((c) => c.ClientId! === currentEnvSpecificParameters.webClientId); if (!answers.appClientWeb) { - printer.error(importMessages.AppClientNotFound('Web', currentEnvSpecificParameters.webClientId)); + printer.error(importMessages.AppClientNotFound('Web')); return { succeeded: false, @@ -1140,7 +1140,7 @@ export const importedAuthEnvInit = async ( answers.appClientNative = questionParameters.nativeClients!.find((c) => c.ClientId! === currentEnvSpecificParameters.nativeClientId); if (!answers.appClientNative) { - printer.error(importMessages.AppClientNotFound('Native', currentEnvSpecificParameters.nativeClientId)); + printer.error(importMessages.AppClientNotFound('Native')); return { succeeded: false, @@ -1292,7 +1292,7 @@ export const headlessImport = async ( if (!answers.appClientWeb) { throw new AmplifyError('AuthImportError', { - message: importMessages.AppClientNotFound('Web', resolvedEnvParams.webClientId), + message: importMessages.AppClientNotFound('Web'), }); } @@ -1300,7 +1300,7 @@ export const headlessImport = async ( if (!answers.appClientNative) { throw new AmplifyError('AuthImportError', { - message: importMessages.AppClientNotFound('Native', resolvedEnvParams.nativeClientId), + message: importMessages.AppClientNotFound('Native'), }); } diff --git a/packages/amplify-category-auth/src/provider-utils/awscloudformation/import/messages.ts b/packages/amplify-category-auth/src/provider-utils/awscloudformation/import/messages.ts index b4baf0cec6c..d400e6a9166 100644 --- a/packages/amplify-category-auth/src/provider-utils/awscloudformation/import/messages.ts +++ b/packages/amplify-category-auth/src/provider-utils/awscloudformation/import/messages.ts @@ -20,7 +20,7 @@ export const importMessages = { `The previously configured Cognito User Pool: '${userPoolName}' (${userPoolId}) cannot be found.`, IdentityPoolNotFound: (identityPoolName: string, identityPoolId: string) => `The previously configured Identity Pool: '${identityPoolName}' (${identityPoolId}) cannot be found.`, - AppClientNotFound: (type: 'Web' | 'Native', clientId: string) => `The previously configured ${type} app client cannot be found.`, + AppClientNotFound: (type: 'Web' | 'Native') => `The previously configured ${type} app client cannot be found.`, NoAtLeastOneAppClient: (type: 'Web' | 'Native') => `The selected Cognito User Pool does not have at least 1 ${type} app client configured. ${type} app clients are app clients ${ type === 'Web' ? 'without' : 'with' diff --git a/packages/amplify-category-function/src/provider-utils/awscloudformation/secrets/secretDeltaUtilities.ts b/packages/amplify-category-function/src/provider-utils/awscloudformation/secrets/secretDeltaUtilities.ts index 1334c538a95..54479ad37c5 100644 --- a/packages/amplify-category-function/src/provider-utils/awscloudformation/secrets/secretDeltaUtilities.ts +++ b/packages/amplify-category-function/src/provider-utils/awscloudformation/secrets/secretDeltaUtilities.ts @@ -15,7 +15,7 @@ export const hasExistingSecrets = (secretDeltas: SecretDeltas) => */ export const getExistingSecrets = (secretDeltas: SecretDeltas) => Object.entries(secretDeltas) - .filter(([_, delta]) => existingSecretDeltaPredicate(delta)) + .filter(([, delta]) => existingSecretDeltaPredicate(delta)) .reduce((acc, [secretName, secretDelta]) => ({ ...acc, [secretName]: secretDelta }), {} as SecretDeltas); /** 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 f79b33602fa..5b1eab1d2f4 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 @@ -243,7 +243,7 @@ export function getLayerName(context: $TSContext, layerName: string): string { export function getLambdaFunctionsDependentOnLayerFromMeta(layerName: string, meta: $TSMeta) { return Object.entries(meta[categoryName]).filter( - ([_, lambdaFunction]: [string, $TSObject]) => + ([, lambdaFunction]: [string, $TSObject]) => lambdaFunction.service === ServiceName.LambdaFunction && lambdaFunction?.dependsOn?.filter((dependency) => dependency.resourceName === layerName).length > 0, ); diff --git a/packages/amplify-category-storage/src/provider-utils/awscloudformation/cdk-stack-builder/ddb-stack-transform.ts b/packages/amplify-category-storage/src/provider-utils/awscloudformation/cdk-stack-builder/ddb-stack-transform.ts index d9f25e286f9..18b9e58f2c8 100644 --- a/packages/amplify-category-storage/src/provider-utils/awscloudformation/cdk-stack-builder/ddb-stack-transform.ts +++ b/packages/amplify-category-storage/src/provider-utils/awscloudformation/cdk-stack-builder/ddb-stack-transform.ts @@ -1,6 +1,5 @@ -import { AmplifyDDBResourceTemplate, getProjectInfo } from '@aws-amplify/cli-extensibility-helper'; +import { getProjectInfo } from '@aws-amplify/cli-extensibility-helper'; import { $TSContext, AmplifyError, buildOverrideDir, JSONUtilities, pathManager, runOverride } from '@aws-amplify/amplify-cli-core'; -import { formatter } from '@aws-amplify/amplify-prompts'; import * as cdk from 'aws-cdk-lib'; import * as fs from 'fs-extra'; import * as path from 'path'; diff --git a/packages/amplify-category-storage/src/provider-utils/awscloudformation/cdk-stack-builder/s3-stack-transform.ts b/packages/amplify-category-storage/src/provider-utils/awscloudformation/cdk-stack-builder/s3-stack-transform.ts index febe14b93be..36d666baf35 100644 --- a/packages/amplify-category-storage/src/provider-utils/awscloudformation/cdk-stack-builder/s3-stack-transform.ts +++ b/packages/amplify-category-storage/src/provider-utils/awscloudformation/cdk-stack-builder/s3-stack-transform.ts @@ -1,5 +1,5 @@ import * as cdk from 'aws-cdk-lib'; -import { AmplifyS3ResourceTemplate, getProjectInfo } from '@aws-amplify/cli-extensibility-helper'; +import { getProjectInfo } from '@aws-amplify/cli-extensibility-helper'; import { $TSAny, $TSContext, @@ -12,7 +12,6 @@ import { pathManager, runOverride, } from '@aws-amplify/amplify-cli-core'; -import { formatter } from '@aws-amplify/amplify-prompts'; import * as fs from 'fs-extra'; import * as path from 'path'; import { S3PermissionType, S3UserInputs } from '../service-walkthrough-types/s3-user-input-types'; diff --git a/packages/amplify-cli/src/extensions/amplify-helpers/docs-manager.ts b/packages/amplify-cli/src/extensions/amplify-helpers/docs-manager.ts index fb1b7e142b5..d118d8b2765 100644 --- a/packages/amplify-cli/src/extensions/amplify-helpers/docs-manager.ts +++ b/packages/amplify-cli/src/extensions/amplify-helpers/docs-manager.ts @@ -3,10 +3,10 @@ const ReadMeContent = `# Getting Started with Amplify CLI This directory was generated by [Amplify CLI](https://docs.amplify.aws/cli). Helpful resources: -- Amplify documentation: https://docs.amplify.aws -- Amplify CLI documentation: https://docs.amplify.aws/cli -- More details on this folder & generated files: https://docs.amplify.aws/cli/reference/files -- Join Amplify's community: https://amplify.aws/community/ +- Amplify documentation: https://docs.amplify.aws. +- Amplify CLI documentation: https://docs.amplify.aws/cli. +- More details on this folder & generated files: https://docs.amplify.aws/cli/reference/files. +- Join Amplify's community: https://amplify.aws/community/. `; export function writeReadMeFile(readMeFilePath: string): void { diff --git a/packages/amplify-cli/src/extensions/amplify-helpers/read-json-file.ts b/packages/amplify-cli/src/extensions/amplify-helpers/read-json-file.ts index c8b590623b1..9fdc6db413b 100644 --- a/packages/amplify-cli/src/extensions/amplify-helpers/read-json-file.ts +++ b/packages/amplify-cli/src/extensions/amplify-helpers/read-json-file.ts @@ -1,6 +1,7 @@ //TODO Remove this whole function once read-json removed from everywhere import { JSONUtilities, $TSAny } from '@aws-amplify/amplify-cli-core'; +// eslint-disable-next-line @typescript-eslint/no-unused-vars export function readJsonFile(jsonFilePath, encoding = 'utf8', throwOnError = true): $TSAny { return JSONUtilities.readJson(jsonFilePath, { throwIfNotExist: throwOnError, diff --git a/packages/amplify-cli/src/init-steps/s9-onSuccess.ts b/packages/amplify-cli/src/init-steps/s9-onSuccess.ts index f5a7d550993..4a88d76d67c 100644 --- a/packages/amplify-cli/src/init-steps/s9-onSuccess.ts +++ b/packages/amplify-cli/src/init-steps/s9-onSuccess.ts @@ -93,7 +93,7 @@ export const onSuccess = async (context: $TSContext): Promise => { await initializeEnv(context, currentAmplifyMeta); if (!context.parameters.options?.app) { - printWelcomeMessage(context); + printWelcomeMessage(); } }; @@ -217,7 +217,7 @@ const generateHooksSampleDirectory = (context: $TSContext): void => { stateManager.setSampleHooksDir(projectPath, sampleHookScriptsDirPath); }; -const printWelcomeMessage = (context: $TSContext): void => { +const printWelcomeMessage = (): void => { printer.success('Your project has been successfully initialized and connected to the cloud!'); printer.info('Some next steps:', 'green'); printer.info(` diff --git a/packages/amplify-e2e-tests/src/__tests__/function_3a.test.ts b/packages/amplify-e2e-tests/src/__tests__/function_3a.test.ts deleted file mode 100644 index 80126884a59..00000000000 --- a/packages/amplify-e2e-tests/src/__tests__/function_3a.test.ts +++ /dev/null @@ -1,237 +0,0 @@ -import { - initJSProjectWithProfile, - deleteProject, - amplifyPushAuth, - getBackendAmplifyMeta, - addFunction, - functionMockAssert, - functionCloudInvoke, - createNewProjectDir, - deleteProjectDir, - generateRandomShortId, -} from '@aws-amplify/amplify-e2e-core'; -import _ from 'lodash'; - -describe('go function tests', () => { - const helloWorldSuccessOutput = 'Hello Amplify!'; - let projRoot: string; - let funcName: string; - - beforeEach(async () => { - projRoot = await createNewProjectDir('go-functions'); - await initJSProjectWithProfile(projRoot, {}); - - funcName = `gotestfn${generateRandomShortId()}`; - - await addFunction( - projRoot, - { - name: funcName, - functionTemplate: 'Hello World', - }, - 'go', - ); - }); - - afterEach(async () => { - await deleteProject(projRoot); - deleteProjectDir(projRoot); - }); - - it('add go hello world function and mock locally', async () => { - await functionMockAssert(projRoot, { - funcName, - successString: helloWorldSuccessOutput, - eventFile: 'src/event.json', - }); // will throw if successString is not in output - }); - - it('add go hello world function and invoke in the cloud', async () => { - const payload = '{"name":"Amplify"}'; - await amplifyPushAuth(projRoot); - const response = await functionCloudInvoke(projRoot, { funcName, payload }); - expect(JSON.parse(response.Payload.toString())).toEqual(helloWorldSuccessOutput); - }); -}); - -describe('python function tests', () => { - const statusCode = 200; - const headers = { - 'Access-Control-Allow-Headers': '*', - 'Access-Control-Allow-Origin': '*', - 'Access-Control-Allow-Methods': 'OPTIONS,POST,GET', - }; - const message = 'Hello from your new Amplify Python lambda!'; - const helloWorldSuccessOutput = { - statusCode, - headers, - body: message, - }; - - let projRoot: string; - let funcName: string; - - beforeEach(async () => { - projRoot = await createNewProjectDir('py-functions'); - await initJSProjectWithProfile(projRoot, {}); - - funcName = `pytestfn${generateRandomShortId()}`; - - await addFunction( - projRoot, - { - name: funcName, - functionTemplate: 'Hello World', - }, - 'python', - ); - }); - - afterEach(async () => { - await deleteProject(projRoot); - deleteProjectDir(projRoot); - }); - - it('add python hello world and mock locally', async () => { - await functionMockAssert(projRoot, { - funcName, - successString: helloWorldSuccessOutput.body, - eventFile: 'src/event.json', - timeout: 120, - }); // will throw if successString is not in output - }); - - it('add python hello world and invoke in the cloud', async () => { - const payload = '{"test":"event"}'; - await amplifyPushAuth(projRoot); - const response = await functionCloudInvoke(projRoot, { funcName, payload }); - const helloWorldSuccessOutputCloud = { - ...helloWorldSuccessOutput, - body: JSON.stringify(helloWorldSuccessOutput.body), - }; - expect(JSON.parse(response.Payload.toString())).toEqual(JSON.parse(JSON.stringify(helloWorldSuccessOutputCloud))); - }); -}); - -describe('dotnet function tests', () => { - const helloWorldSuccessObj = { - key1: 'VALUE1', - key2: 'VALUE2', - key3: 'VALUE3', - }; - const helloWorldSuccessString = ' "key3": "VALUE3"'; - let projRoot: string; - let funcName: string; - - beforeEach(async () => { - projRoot = await createNewProjectDir('dotnet-functions'); - await initJSProjectWithProfile(projRoot, {}); - - funcName = `dotnettestfn${generateRandomShortId()}`; - - await addFunction( - projRoot, - { - name: funcName, - functionTemplate: 'Hello World', - }, - 'dotnet6', - ); - }); - - afterEach(async () => { - await deleteProject(projRoot); - deleteProjectDir(projRoot); - }); - - it('add dotnet hello world function and mock locally', async () => { - await functionMockAssert(projRoot, { - funcName, - successString: helloWorldSuccessString, - eventFile: 'src/event.json', - }); // will throw if successString is not in output - }); - - it('add dotnet hello world function and invoke in the cloud', async () => { - const payload = '{"key1":"value1","key2":"value2","key3":"value3"}'; - await amplifyPushAuth(projRoot); - const response = await functionCloudInvoke(projRoot, { funcName, payload }); - expect(JSON.parse(response.Payload.toString())).toEqual(helloWorldSuccessObj); - }); -}); - -describe('nodejs function tests', () => { - const helloWorldSuccessString = 'Hello from Lambda!'; - const helloWorldSuccessObj = { - statusCode: 200, - body: '"Hello from Lambda!"', - }; - - let projRoot: string; - let funcName: string; - - beforeEach(async () => { - projRoot = await createNewProjectDir('nodejs-functions'); - await initJSProjectWithProfile(projRoot, {}); - - funcName = `nodejstestfn${generateRandomShortId()}`; - - await addFunction( - projRoot, - { - name: funcName, - functionTemplate: 'Hello World', - }, - 'nodejs', - ); - }); - - afterEach(async () => { - await deleteProject(projRoot); - deleteProjectDir(projRoot); - }); - - it('add nodejs hello world function and mock locally', async () => { - await functionMockAssert(projRoot, { - funcName, - successString: helloWorldSuccessString, - eventFile: 'src/event.json', - }); // will throw if successString is not in output - }); - - it('add nodejs hello world function and invoke in the cloud', async () => { - const payload = '{"key1":"value1","key2":"value2","key3":"value3"}'; - - await amplifyPushAuth(projRoot); - - const response = await functionCloudInvoke(projRoot, { funcName, payload }); - - expect(JSON.parse(response.Payload.toString())).toEqual(helloWorldSuccessObj); - }); - - it('add nodejs hello world function and mock locally, check buildType, push, check buildType', async () => { - await functionMockAssert(projRoot, { - funcName, - successString: helloWorldSuccessString, - eventFile: 'src/event.json', - }); // will throw if successString is not in output - - let meta = getBackendAmplifyMeta(projRoot); - let functionResource = _.get(meta, ['function', funcName]); - - const lastDevBuildTimeStampBeforePush = functionResource.lastDevBuildTimeStamp; - - // Mock should trigger a DEV build of the function - expect(functionResource).toBeDefined(); - expect(functionResource.lastBuildType).toEqual('DEV'); - - await amplifyPushAuth(projRoot); - - meta = getBackendAmplifyMeta(projRoot); - functionResource = _.get(meta, ['function', funcName]); - - // Push should trigger a PROD build of the function - expect(functionResource.lastBuildType).toEqual('PROD'); - expect(functionResource.lastDevBuildTimeStamp).toEqual(lastDevBuildTimeStampBeforePush); - }); -}); diff --git a/packages/amplify-e2e-tests/src/__tests__/function_3a_dotnet.test.ts b/packages/amplify-e2e-tests/src/__tests__/function_3a_dotnet.test.ts new file mode 100644 index 00000000000..20a95a1144d --- /dev/null +++ b/packages/amplify-e2e-tests/src/__tests__/function_3a_dotnet.test.ts @@ -0,0 +1,58 @@ +import { + initJSProjectWithProfile, + deleteProject, + amplifyPushAuth, + addFunction, + functionMockAssert, + functionCloudInvoke, + createNewProjectDir, + deleteProjectDir, + generateRandomShortId, +} from '@aws-amplify/amplify-e2e-core'; + +describe('dotnet function tests', () => { + const helloWorldSuccessObj = { + key1: 'VALUE1', + key2: 'VALUE2', + key3: 'VALUE3', + }; + const helloWorldSuccessString = ' "key3": "VALUE3"'; + let projRoot: string; + let funcName: string; + + beforeEach(async () => { + projRoot = await createNewProjectDir('dotnet-functions'); + await initJSProjectWithProfile(projRoot, {}); + + funcName = `dotnettestfn${generateRandomShortId()}`; + + await addFunction( + projRoot, + { + name: funcName, + functionTemplate: 'Hello World', + }, + 'dotnet6', + ); + }); + + afterEach(async () => { + await deleteProject(projRoot); + deleteProjectDir(projRoot); + }); + + it('add dotnet hello world function and mock locally', async () => { + await functionMockAssert(projRoot, { + funcName, + successString: helloWorldSuccessString, + eventFile: 'src/event.json', + }); // will throw if successString is not in output + }); + + it('add dotnet hello world function and invoke in the cloud', async () => { + const payload = '{"key1":"value1","key2":"value2","key3":"value3"}'; + await amplifyPushAuth(projRoot); + const response = await functionCloudInvoke(projRoot, { funcName, payload }); + expect(JSON.parse(response.Payload.toString())).toEqual(helloWorldSuccessObj); + }); +}); diff --git a/packages/amplify-e2e-tests/src/__tests__/function_3a_go.test.ts b/packages/amplify-e2e-tests/src/__tests__/function_3a_go.test.ts new file mode 100644 index 00000000000..db523a78abe --- /dev/null +++ b/packages/amplify-e2e-tests/src/__tests__/function_3a_go.test.ts @@ -0,0 +1,44 @@ +import { + initJSProjectWithProfile, + deleteProject, + amplifyPushAuth, + addFunction, + functionCloudInvoke, + createNewProjectDir, + deleteProjectDir, + generateRandomShortId, +} from '@aws-amplify/amplify-e2e-core'; + +describe('go function tests', () => { + const helloWorldSuccessOutput = 'Hello Amplify!'; + let projRoot: string; + let funcName: string; + + beforeEach(async () => { + projRoot = await createNewProjectDir('go-functions'); + await initJSProjectWithProfile(projRoot, {}); + + funcName = `gotestfn${generateRandomShortId()}`; + + await addFunction( + projRoot, + { + name: funcName, + functionTemplate: 'Hello World', + }, + 'go', + ); + }); + + afterEach(async () => { + await deleteProject(projRoot); + deleteProjectDir(projRoot); + }); + + it('add go hello world function and invoke in the cloud', async () => { + const payload = '{"name":"Amplify"}'; + await amplifyPushAuth(projRoot); + const response = await functionCloudInvoke(projRoot, { funcName, payload }); + expect(JSON.parse(response.Payload.toString())).toEqual(helloWorldSuccessOutput); + }); +}); diff --git a/packages/amplify-e2e-tests/src/__tests__/function_3a_nodejs.test.ts b/packages/amplify-e2e-tests/src/__tests__/function_3a_nodejs.test.ts new file mode 100644 index 00000000000..39764fc6b29 --- /dev/null +++ b/packages/amplify-e2e-tests/src/__tests__/function_3a_nodejs.test.ts @@ -0,0 +1,89 @@ +import { + initJSProjectWithProfile, + deleteProject, + amplifyPushAuth, + getBackendAmplifyMeta, + addFunction, + functionMockAssert, + functionCloudInvoke, + createNewProjectDir, + deleteProjectDir, + generateRandomShortId, +} from '@aws-amplify/amplify-e2e-core'; +import _ from 'lodash'; + +describe('nodejs function tests', () => { + const helloWorldSuccessString = 'Hello from Lambda!'; + const helloWorldSuccessObj = { + statusCode: 200, + body: '"Hello from Lambda!"', + }; + + let projRoot: string; + let funcName: string; + + beforeEach(async () => { + projRoot = await createNewProjectDir('nodejs-functions'); + await initJSProjectWithProfile(projRoot, {}); + + funcName = `nodejstestfn${generateRandomShortId()}`; + + await addFunction( + projRoot, + { + name: funcName, + functionTemplate: 'Hello World', + }, + 'nodejs', + ); + }); + + afterEach(async () => { + await deleteProject(projRoot); + deleteProjectDir(projRoot); + }); + + it('add nodejs hello world function and mock locally', async () => { + await functionMockAssert(projRoot, { + funcName, + successString: helloWorldSuccessString, + eventFile: 'src/event.json', + }); // will throw if successString is not in output + }); + + it('add nodejs hello world function and invoke in the cloud', async () => { + const payload = '{"key1":"value1","key2":"value2","key3":"value3"}'; + + await amplifyPushAuth(projRoot); + + const response = await functionCloudInvoke(projRoot, { funcName, payload }); + + expect(JSON.parse(response.Payload.toString())).toEqual(helloWorldSuccessObj); + }); + + it('add nodejs hello world function and mock locally, check buildType, push, check buildType', async () => { + await functionMockAssert(projRoot, { + funcName, + successString: helloWorldSuccessString, + eventFile: 'src/event.json', + }); // will throw if successString is not in output + + let meta = getBackendAmplifyMeta(projRoot); + let functionResource = _.get(meta, ['function', funcName]); + + const lastDevBuildTimeStampBeforePush = functionResource.lastDevBuildTimeStamp; + + // Mock should trigger a DEV build of the function + expect(functionResource).toBeDefined(); + expect(functionResource.lastBuildType).toEqual('DEV'); + + await amplifyPushAuth(projRoot); + + meta = getBackendAmplifyMeta(projRoot); + functionResource = _.get(meta, ['function', funcName]); + + // Push should trigger a PROD build of the function + expect(functionResource.lastBuildType).toEqual('PROD'); + expect(functionResource.lastDevBuildTimeStamp).toEqual(lastDevBuildTimeStampBeforePush); + }); +}); diff --git a/packages/amplify-e2e-tests/src/__tests__/function_3a_python.test.ts b/packages/amplify-e2e-tests/src/__tests__/function_3a_python.test.ts new file mode 100644 index 00000000000..4f622dd0483 --- /dev/null +++ b/packages/amplify-e2e-tests/src/__tests__/function_3a_python.test.ts @@ -0,0 +1,70 @@ +import { + initJSProjectWithProfile, + deleteProject, + amplifyPushAuth, + addFunction, + functionMockAssert, + functionCloudInvoke, + createNewProjectDir, + deleteProjectDir, + generateRandomShortId, +} from '@aws-amplify/amplify-e2e-core'; + +describe('python function tests', () => { + const statusCode = 200; + const headers = { + 'Access-Control-Allow-Headers': '*', + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Methods': 'OPTIONS,POST,GET', + }; + const message = 'Hello from your new Amplify Python lambda!'; + const helloWorldSuccessOutput = { + statusCode, + headers, + body: message, + }; + + let projRoot: string; + let funcName: string; + + beforeEach(async () => { + projRoot = await createNewProjectDir('py-functions'); + await initJSProjectWithProfile(projRoot, {}); + + funcName = `pytestfn${generateRandomShortId()}`; + + await addFunction( + projRoot, + { + name: funcName, + functionTemplate: 'Hello World', + }, + 'python', + ); + }); + + afterEach(async () => { + await deleteProject(projRoot); + deleteProjectDir(projRoot); + }); + + it('add python hello world and mock locally', async () => { + await functionMockAssert(projRoot, { + funcName, + successString: helloWorldSuccessOutput.body, + eventFile: 'src/event.json', + timeout: 120, + }); // will throw if successString is not in output + }); + + it('add python hello world and invoke in the cloud', async () => { + const payload = '{"test":"event"}'; + await amplifyPushAuth(projRoot); + const response = await functionCloudInvoke(projRoot, { funcName, payload }); + const helloWorldSuccessOutputCloud = { + ...helloWorldSuccessOutput, + body: JSON.stringify(helloWorldSuccessOutput.body), + }; + expect(JSON.parse(response.Payload.toString())).toEqual(JSON.parse(JSON.stringify(helloWorldSuccessOutputCloud))); + }); +}); diff --git a/packages/amplify-go-function-runtime-provider/src/constants.ts b/packages/amplify-go-function-runtime-provider/src/constants.ts index 49c97e57af0..d53eead0060 100644 --- a/packages/amplify-go-function-runtime-provider/src/constants.ts +++ b/packages/amplify-go-function-runtime-provider/src/constants.ts @@ -6,8 +6,8 @@ export const BIN = 'bin'; export const SRC = 'src'; export const DIST = 'dist'; export const MAIN_SOURCE = 'main.go'; -export const MAIN_BINARY = 'main'; -export const MAIN_BINARY_WIN = 'main.exe'; +export const MAIN_BINARY = 'bootstrap'; +export const MAIN_BINARY_WIN = 'bootstrap.exe'; export const BASE_PORT = 8900; export const MAX_PORT = 9999; diff --git a/packages/amplify-go-function-runtime-provider/src/index.ts b/packages/amplify-go-function-runtime-provider/src/index.ts index af1f3fa44fb..9af4fdc96c8 100644 --- a/packages/amplify-go-function-runtime-provider/src/index.ts +++ b/packages/amplify-go-function-runtime-provider/src/index.ts @@ -12,11 +12,11 @@ export const functionRuntimeContributorFactory: FunctionRuntimeContributorFactor } return Promise.resolve({ runtime: { - name: 'Go 1.x', - value: 'go1.x', - cloudTemplateValue: 'go1.x', - defaultHandler: 'main', - layerExecutablePath: 'go1.x', + name: 'provided.al2023', + value: 'provided.al2023', + cloudTemplateValue: 'provided.al2023', + defaultHandler: 'bootstrap', + layerExecutablePath: 'provided.al2023', }, }); }, diff --git a/packages/amplify-go-function-runtime-provider/src/localinvoke.ts b/packages/amplify-go-function-runtime-provider/src/localinvoke.ts index 62cddff48aa..bd9a063c823 100644 --- a/packages/amplify-go-function-runtime-provider/src/localinvoke.ts +++ b/packages/amplify-go-function-runtime-provider/src/localinvoke.ts @@ -26,7 +26,7 @@ const buildLocalInvoker = async (context: any) => { // Build localInvoker context.print.info('Local invoker binary was not found, building it...'); executeCommand(['mod', 'tidy'], true, undefined, localInvokerDir); - executeCommand(['build', MAIN_SOURCE], true, undefined, localInvokerDir); + executeCommand(['build', '-o', 'bootstrap', MAIN_SOURCE], true, undefined, localInvokerDir); } return { diff --git a/packages/amplify-go-function-runtime-provider/src/runtime.ts b/packages/amplify-go-function-runtime-provider/src/runtime.ts index 2867a5e9be3..d22443a4288 100644 --- a/packages/amplify-go-function-runtime-provider/src/runtime.ts +++ b/packages/amplify-go-function-runtime-provider/src/runtime.ts @@ -86,7 +86,7 @@ export const buildResource = async ({ buildType, srcRoot, lastBuildTimeStamp }: fs.mkdirSync(outDir); } - const envVars: any = {}; + const envVars: any = { GOPROXY: 'direct' }; if (buildType === BuildType.PROD) { envVars.GOOS = 'linux'; @@ -95,12 +95,14 @@ export const buildResource = async ({ buildType, srcRoot, lastBuildTimeStamp }: if (isWindows) { envVars.CGO_ENABLED = 0; + executeCommand(['go.exe', 'install', 'github.com/aws/aws-lambda-go/cmd/build-lambda-zip@latest'], true, envVars, srcDir); } // for go@1.16, dependencies must be manually installed executeCommand(['mod', 'tidy', '-v'], true, envVars, srcDir); // Execute the build command, cwd must be the source file directory (Windows requires it) - executeCommand(['build', '-o', executablePath, '.'], true, envVars, srcDir); + // Details: https://github.com/aws/aws-lambda-go + executeCommand(['build', '-o', '../bin/bootstrap', 'main.go'], true, envVars, srcDir); rebuilt = true; } diff --git a/packages/amplify-go-function-template-provider/amplify-plugin.json b/packages/amplify-go-function-template-provider/amplify-plugin.json index 3a06c1c4895..2415925746b 100644 --- a/packages/amplify-go-function-template-provider/amplify-plugin.json +++ b/packages/amplify-go-function-template-provider/amplify-plugin.json @@ -7,7 +7,7 @@ "conditions": { "provider": "awscloudformation", "services": ["Lambda"], - "runtime": "go1.x" + "runtime": "provided.al2023" }, "templates": [ { diff --git a/packages/amplify-go-function-template-provider/package.json b/packages/amplify-go-function-template-provider/package.json index 07c79392aa6..da667e46091 100644 --- a/packages/amplify-go-function-template-provider/package.json +++ b/packages/amplify-go-function-template-provider/package.json @@ -1,7 +1,7 @@ { "name": "@aws-amplify/amplify-go-function-template-provider", "version": "1.4.7", - "description": "Go 1.x templates supplied by the Amplify Team", + "description": "Go templates supplied by the Amplify Team", "repository": { "type": "git", "url": "https://github.com/aws-amplify/amplify-cli.git", diff --git a/packages/amplify-provider-awscloudformation/src/root-stack-builder/root-stack-transform.ts b/packages/amplify-provider-awscloudformation/src/root-stack-builder/root-stack-transform.ts index cf5ef09e70c..dbec71bde8d 100644 --- a/packages/amplify-provider-awscloudformation/src/root-stack-builder/root-stack-transform.ts +++ b/packages/amplify-provider-awscloudformation/src/root-stack-builder/root-stack-transform.ts @@ -11,8 +11,6 @@ import { Template, writeCFNTemplate, } from '@aws-amplify/amplify-cli-core'; -import { formatter } from '@aws-amplify/amplify-prompts'; -import * as fs from 'fs-extra'; import * as path from 'path'; import { AmplifyRootStack, AmplifyRootStackOutputs } from './root-stack-builder'; import { RootStackSynthesizer } from './stack-synthesizer'; diff --git a/scripts/cci-test-timings.data.json b/scripts/cci-test-timings.data.json index cec3567e650..d39bfe816b5 100644 --- a/scripts/cci-test-timings.data.json +++ b/scripts/cci-test-timings.data.json @@ -743,7 +743,19 @@ "medianRuntime": 27 }, { - "test": "src/__tests__/function_3a.test.ts", + "test": "src/__tests__/function_3a_go.test.ts", + "medianRuntime": 27 + }, + { + "test": "src/__tests__/function_3a_python.test.ts", + "medianRuntime": 27 + }, + { + "test": "src/__tests__/function_3a_dotnet.test.ts", + "medianRuntime": 27 + }, + { + "test": "src/__tests__/function_3a_nodejs.test.ts", "medianRuntime": 27 }, { diff --git a/scripts/split-e2e-tests-codebuild.ts b/scripts/split-e2e-tests-codebuild.ts index bc892cdb8b7..163c9cc76d7 100644 --- a/scripts/split-e2e-tests-codebuild.ts +++ b/scripts/split-e2e-tests-codebuild.ts @@ -68,7 +68,10 @@ const TEST_EXCLUSIONS: { l: string[]; w: string[] } = { 'src/__tests__/env-2.test.ts', 'src/__tests__/pr-previews-multi-env-1.test.ts', 'src/__tests__/export.test.ts', - 'src/__tests__/function_3a.test.ts', + 'src/__tests__/function_3a_dotnet.test.ts', + 'src/__tests__/function_3a_python.test.ts', + 'src/__tests__/function_3a_go.test.ts', + 'src/__tests__/function_3a_nodejs.test.ts', 'src/__tests__/function_3b.test.ts', 'src/__tests__/function_4.test.ts', 'src/__tests__/function_6.test.ts',