From 899af2f76e4b4c4706323096ba2f71a66026693a Mon Sep 17 00:00:00 2001 From: Dane Pilcher Date: Mon, 16 Oct 2023 09:54:04 -0600 Subject: [PATCH 1/5] fix: skip bad statement source on type generation and exclude type file (#738) --- packages/amplify-codegen/src/commands/add.js | 2 +- .../amplify-codegen/src/commands/types.js | 35 +++++++++++------ .../src/walkthrough/configure.js | 6 ++- .../commands/__snapshots__/add.test.js.snap | 20 ++++++++-- .../tests/commands/add.test.js | 4 +- .../tests/commands/mock-fs-setup.js | 2 +- .../tests/commands/types-mock-fs.test.js | 22 +++++++++++ .../tests/commands/types.test.js | 5 ++- .../tests/walkthrough/configure.test.js | 38 +++++++++++++++++-- 9 files changed, 108 insertions(+), 26 deletions(-) diff --git a/packages/amplify-codegen/src/commands/add.js b/packages/amplify-codegen/src/commands/add.js index 6b3a609a9..7ee6d4bae 100644 --- a/packages/amplify-codegen/src/commands/add.js +++ b/packages/amplify-codegen/src/commands/add.js @@ -133,7 +133,7 @@ async function add(context, apiId = null, region = 'us-east-1') { const newProject = { projectName: withoutInit ? 'Codegen Project' : apiDetails.name, includes: answer.includePattern, - excludes: answer.excludePattern, + excludes: [...answer.excludePattern, answer.generatedFileName], schema, amplifyExtension: { codeGenTarget: answer.target || '', diff --git a/packages/amplify-codegen/src/commands/types.js b/packages/amplify-codegen/src/commands/types.js index c1bd220af..7cac9a288 100644 --- a/packages/amplify-codegen/src/commands/types.js +++ b/packages/amplify-codegen/src/commands/types.js @@ -62,18 +62,29 @@ async function generateTypes(context, forceDownloadSchema, withoutInit = false, cwd: projectPath, absolute: true, }); - const queries = queryFilePaths.map(queryFilePath => { - const fileContents = fs.readFileSync(queryFilePath, 'utf8'); - if ( - queryFilePath.endsWith('.jsx') || - queryFilePath.endsWith('.js') || - queryFilePath.endsWith('.tsx') || - queryFilePath.endsWith('.ts') - ) { - return extractDocumentFromJavascript(fileContents, ''); - } - return new Source(fileContents, queryFilePath); - }); + const queries = queryFilePaths + .map(queryFilePath => { + const fileContents = fs.readFileSync(queryFilePath, 'utf8'); + if ( + queryFilePath.endsWith('.jsx') || + queryFilePath.endsWith('.js') || + queryFilePath.endsWith('.tsx') || + queryFilePath.endsWith('.ts') + ) { + return [queryFilePath, extractDocumentFromJavascript(fileContents, '')]; + } + return [queryFilePath, new Source(fileContents, queryFilePath)]; + }) + .filter(([queryFilePath, source]) => { + if (!source) { + context.print.warning( + `Unable to extract GraphQL queries from ${queryFilePath}. Skipping source. This source matched the includes target in .grapqhlconfig.yml. Modify the includes or excludes target if this file should not be included.`, + ); + return false; + } + return true; + }) + .map(([, source]) => source); if (queries.length === 0) { throw new Error("No queries found to generate types for, you may need to run 'codegen statements' first"); } diff --git a/packages/amplify-codegen/src/walkthrough/configure.js b/packages/amplify-codegen/src/walkthrough/configure.js index 65c9fe63a..90a3fee90 100644 --- a/packages/amplify-codegen/src/walkthrough/configure.js +++ b/packages/amplify-codegen/src/walkthrough/configure.js @@ -50,12 +50,14 @@ async function configureProjectWalkThrough(context, amplifyConfig, withoutInit = selectedProjectConfig.includes = await askCodeGeneQueryFilePattern(includePattern); if (!(frontend === 'android' || targetLanguage === 'javascript')) { - amplifyExtension.generatedFileName = await askTargetFileName(amplifyExtension.generatedFileName || 'API', targetLanguage); + const generatedFileName = await askTargetFileName(amplifyExtension.generatedFileName || 'API', targetLanguage); + amplifyExtension.generatedFileName = generatedFileName; + selectedProjectConfig.excludes = Array.from(new Set(selectedProjectConfig.excludes || []).add(generatedFileName)); } else { amplifyExtension.generatedFileName = ''; } amplifyExtension.codeGenTarget = targetLanguage; - amplifyExtension.docsFilePath = getGraphQLDocPath(frontend, includePatternDefault.graphQLDirectory, selectedProjectConfig.includes) + amplifyExtension.docsFilePath = getGraphQLDocPath(frontend, includePatternDefault.graphQLDirectory, selectedProjectConfig.includes); amplifyExtension.maxDepth = await askMaxDepth(amplifyExtension.maxDepth); return selectedProjectConfig; diff --git a/packages/amplify-codegen/tests/commands/__snapshots__/add.test.js.snap b/packages/amplify-codegen/tests/commands/__snapshots__/add.test.js.snap index beb912eb0..de3e1a98a 100644 --- a/packages/amplify-codegen/tests/commands/__snapshots__/add.test.js.snap +++ b/packages/amplify-codegen/tests/commands/__snapshots__/add.test.js.snap @@ -11,7 +11,10 @@ Object { "generatedFileName": "API.TS", "region": "us-east-1", }, - "excludes": "MOCK_EXCLUDE", + "excludes": Array [ + "MOCK_EXCLUDE", + "API.TS", + ], "includes": "MOCK_INCLUDE", "projectName": "Codegen Project", "schema": "/user/foo/project/schema.json", @@ -29,7 +32,10 @@ Object { "generatedFileName": "API.TS", "region": "us-east-1", }, - "excludes": "MOCK_EXCLUDE", + "excludes": Array [ + "MOCK_EXCLUDE", + "API.TS", + ], "includes": "MOCK_INCLUDE", "projectName": "Codegen Project", "schema": "/user/foo/project/schema.json", @@ -47,7 +53,10 @@ Object { "generatedFileName": "API.TS", "region": "us-east-1", }, - "excludes": "MOCK_EXCLUDE", + "excludes": Array [ + "MOCK_EXCLUDE", + "API.TS", + ], "includes": "MOCK_INCLUDE", "projectName": "Codegen Project", "schema": "/user/foo/project/schema.graphql", @@ -65,7 +74,10 @@ Object { "generatedFileName": "API.TS", "region": "us-west-2", }, - "excludes": "MOCK_EXCLUDE", + "excludes": Array [ + "MOCK_EXCLUDE", + "API.TS", + ], "includes": "MOCK_INCLUDE", "projectName": "Codegen Project", "schema": "/user/foo/project/schema.json", diff --git a/packages/amplify-codegen/tests/commands/add.test.js b/packages/amplify-codegen/tests/commands/add.test.js index f353d6548..007c09ac8 100644 --- a/packages/amplify-codegen/tests/commands/add.test.js +++ b/packages/amplify-codegen/tests/commands/add.test.js @@ -45,7 +45,7 @@ jest.mock('process', () => ({ })); const MOCK_INCLUDE_PATTERN = 'MOCK_INCLUDE'; -const MOCK_EXCLUDE_PATTERN = 'MOCK_EXCLUDE'; +const MOCK_EXCLUDE_PATTERN = ['MOCK_EXCLUDE']; const MOCK_SCHEMA_LOCATION = 'INTROSPECTION_SCHEMA.JSON'; const MOCK_TARGET = 'TYPE_SCRIPT_OR_FLOW_OR_ANY_OTHER_LANGUAGE'; const MOCK_GENERATED_FILE_NAME = 'API.TS'; @@ -100,7 +100,7 @@ describe('command - add', () => { const newProjectConfig = LOAD_CONFIG_METHODS.addProject.mock.calls[0][0]; expect(newProjectConfig.projectName).toEqual(MOCK_API_NAME); expect(newProjectConfig.includes).toEqual(MOCK_INCLUDE_PATTERN); - expect(newProjectConfig.excludes).toEqual(MOCK_EXCLUDE_PATTERN); + expect(newProjectConfig.excludes).toEqual([...MOCK_EXCLUDE_PATTERN, MOCK_GENERATED_FILE_NAME]); expect(newProjectConfig.schema).toEqual(MOCK_SCHEMA_FILE_LOCATION); expect(newProjectConfig.amplifyExtension.codeGenTarget).toEqual(MOCK_TARGET); expect(newProjectConfig.amplifyExtension.generatedFileName).toEqual(MOCK_GENERATED_FILE_NAME); diff --git a/packages/amplify-codegen/tests/commands/mock-fs-setup.js b/packages/amplify-codegen/tests/commands/mock-fs-setup.js index 34dd71bc3..7ad30f5be 100644 --- a/packages/amplify-codegen/tests/commands/mock-fs-setup.js +++ b/packages/amplify-codegen/tests/commands/mock-fs-setup.js @@ -36,7 +36,7 @@ function setupMocks(mockFs, loadConfig, apiId, frontend, target, generatedFileNa { schema: schemaFilePath, includes: [path.join(docsFilePath[frontend], '*')], - excludes: ['./amplify/**'], + excludes: ['./amplify/**', './src/graphql/excluded.ts'], amplifyExtension: { codeGenTarget: target, generatedFileName, diff --git a/packages/amplify-codegen/tests/commands/types-mock-fs.test.js b/packages/amplify-codegen/tests/commands/types-mock-fs.test.js index 2a03488aa..288eaa969 100644 --- a/packages/amplify-codegen/tests/commands/types-mock-fs.test.js +++ b/packages/amplify-codegen/tests/commands/types-mock-fs.test.js @@ -34,6 +34,7 @@ const MOCK_APIS = [ const MOCK_CONTEXT = { print: { info: jest.fn(), + warning: jest.fn(), }, amplify: { getProjectMeta: jest.fn(() => ({ api: { id: MOCK_API_ID } })), @@ -121,4 +122,25 @@ describe('command - types (mock fs)', () => { await generateTypes(MOCK_CONTEXT, false); expect(fs.existsSync(generatedFileName)).toBeFalsy(); }); + + it('should skip invalid sources', async () => { + const { generatedFileName } = setupMocks(mockFs, loadConfig, MOCK_API_ID, 'javascript', 'typescript', 'src/graphql/API.ts', { + 'src/graphql/excluded.ts': '', + 'src/graphql/foo.ts': '', + }); + + await generateStatements(MOCK_CONTEXT, false); + await generateTypes(MOCK_CONTEXT, false); + expect(MOCK_CONTEXT.print.warning).toHaveBeenCalledWith( + expect.stringMatching( + 'Unable to extract GraphQL queries from .*/src/graphql/foo.ts. Skipping source. This source matched the includes target in .grapqhlconfig.yml. Modify the includes or excludes target if this file should not be included.', + ), + ); + expect(MOCK_CONTEXT.print.warning).not.toHaveBeenCalledWith( + expect.stringMatching( + 'Unable to extract GraphQL queries from .*/src/graphql/excluded.ts. Skipping source. This source matched the includes target in .grapqhlconfig.yml. Modify the includes or excludes target if this file should not be included.', + ), + ); + expect(fs.existsSync(generatedFileName)).toBeTruthy(); + }); }); diff --git a/packages/amplify-codegen/tests/commands/types.test.js b/packages/amplify-codegen/tests/commands/types.test.js index c885209c1..30bd0786c 100644 --- a/packages/amplify-codegen/tests/commands/types.test.js +++ b/packages/amplify-codegen/tests/commands/types.test.js @@ -80,7 +80,10 @@ describe('command - types', () => { await generateTypes(MOCK_CONTEXT, forceDownload); expect(getFrontEndHandler).toHaveBeenCalledWith(MOCK_CONTEXT); expect(loadConfig).toHaveBeenCalledWith(MOCK_CONTEXT, false); - expect(sync).toHaveBeenCalledWith([MOCK_INCLUDE_PATH, `!${MOCK_EXCLUDE_PATH}`], { cwd: MOCK_PROJECT_ROOT, absolute: true }); + expect(sync).toHaveBeenCalledWith([MOCK_INCLUDE_PATH, `!${MOCK_EXCLUDE_PATH}`], { + cwd: MOCK_PROJECT_ROOT, + absolute: true, + }); expect(generateTypesHelper).toHaveBeenCalledWith({ queries: [new Source('query 1', 'q1.gql'), new Source('query 2', 'q2.gql')], schema: 'schema', diff --git a/packages/amplify-codegen/tests/walkthrough/configure.test.js b/packages/amplify-codegen/tests/walkthrough/configure.test.js index 811048028..3d2b2f6ab 100644 --- a/packages/amplify-codegen/tests/walkthrough/configure.test.js +++ b/packages/amplify-codegen/tests/walkthrough/configure.test.js @@ -24,10 +24,14 @@ describe('configure walk-through', () => { const mockGraphQLExtension = 'MOCK_GQL_EXTENSION'; const MOCK_MAX_DEPTH = 'MOCK_MAX_DEPTH'; + const projectOneExcludes = ['one/excluded/*.gql', 'one/excluded/*.graphql']; + const projectTwoExcludes = ['two/excluded/*.gql', 'two/excluded/*.graphql']; + const mockConfigs = [ { projectName: 'One', - includes: ['one/**/*.gql', 'one/**/*.graohql'], + includes: ['one/**/*.gql', 'one/**/*.graphql'], + excludes: projectOneExcludes, amplifyExtension: { graphQLApiId: 'one', generatedFileName: 'one-1.ts', @@ -37,7 +41,8 @@ describe('configure walk-through', () => { }, { projectName: 'Two', - includes: ['two/**/*.gql', 'two/**/*.graohql'], + includes: ['two/**/*.gql', 'two/**/*.graphql'], + excludes: projectTwoExcludes, amplifyExtension: { graphQLApiId: 'two', maxDepth: 10, @@ -78,13 +83,40 @@ describe('configure walk-through', () => { mockConfigs[1].amplifyExtension.codeGenTarget, false, undefined, - undefined + undefined, ); expect(askCodegneQueryFilePattern).toHaveBeenCalledWith([join(mockGraphQLDirectory, '**', mockGraphQLExtension)]); expect(askGeneratedFileName).toHaveBeenCalledWith(mockConfigs[1].amplifyExtension.generatedFileName, mockTargetLanguage); expect(askMaxDepth).toHaveBeenCalledWith(10); expect(results).toEqual({ projectName: mockConfigs[1].projectName, + excludes: [...projectTwoExcludes, mockGeneratedFileName], + includes: mockIncludes, + amplifyExtension: { + graphQLApiId: mockConfigs[1].amplifyExtension.graphQLApiId, + generatedFileName: mockGeneratedFileName, + codeGenTarget: mockTargetLanguage, + maxDepth: MOCK_MAX_DEPTH, + }, + }); + }); + + it('should not add generated types file to excludes twice', async () => { + const result = await configure(mockContext, mockConfigs); + expect(result).toEqual({ + projectName: mockConfigs[1].projectName, + excludes: [...projectTwoExcludes, mockGeneratedFileName], + includes: mockIncludes, + amplifyExtension: { + graphQLApiId: mockConfigs[1].amplifyExtension.graphQLApiId, + generatedFileName: mockGeneratedFileName, + codeGenTarget: mockTargetLanguage, + maxDepth: MOCK_MAX_DEPTH, + }, + }); + expect(await configure(mockContext, [result])).toEqual({ + projectName: mockConfigs[1].projectName, + excludes: [...projectTwoExcludes, mockGeneratedFileName], includes: mockIncludes, amplifyExtension: { graphQLApiId: mockConfigs[1].amplifyExtension.graphQLApiId, From f74aaa7c183ca0efcfdff08efa2b5888489b7901 Mon Sep 17 00:00:00 2001 From: Dane Pilcher Date: Mon, 16 Oct 2023 09:54:25 -0600 Subject: [PATCH 2/5] fix: correctly remove file extension on types import path (#742) --- .../utils/GraphQLStatementsFormatter.test.ts | 15 ++++ .../GraphQLStatementsFormatter.test.ts.snap | 78 +++++++++++++++++++ .../src/utils/GraphQLStatementsFormatter.ts | 20 +++-- 3 files changed, 107 insertions(+), 6 deletions(-) diff --git a/packages/graphql-generator/src/__tests__/utils/GraphQLStatementsFormatter.test.ts b/packages/graphql-generator/src/__tests__/utils/GraphQLStatementsFormatter.test.ts index a9a049b7d..644e9a8eb 100644 --- a/packages/graphql-generator/src/__tests__/utils/GraphQLStatementsFormatter.test.ts +++ b/packages/graphql-generator/src/__tests__/utils/GraphQLStatementsFormatter.test.ts @@ -36,6 +36,21 @@ describe('GraphQL statements Formatter', () => { expect(formattedOutput).toMatchSnapshot(); }); + it('Generates formatted output for TS frontend with posix path in same dir', () => { + const formattedOutput = new GraphQLStatementsFormatter('typescript', 'queries', './API.ts').format(statements); + expect(formattedOutput).toMatchSnapshot(); + }); + + it('Generates formatted output for TS frontend with windows path in same dir', () => { + const formattedOutput = new GraphQLStatementsFormatter('typescript', 'queries', '.\\API.ts').format(statements); + expect(formattedOutput).toMatchSnapshot(); + }); + + it('Generates formatted output and only remove file extension', () => { + const formattedOutput = new GraphQLStatementsFormatter('typescript', 'queries', '../Components/Data/API.tsx').format(statements); + expect(formattedOutput).toMatchSnapshot(); + }); + it('Generates formatted output for Flow frontend', () => { const formattedOutput = new GraphQLStatementsFormatter('flow').format(statements); expect(formattedOutput).toMatchSnapshot(); diff --git a/packages/graphql-generator/src/__tests__/utils/__snapshots__/GraphQLStatementsFormatter.test.ts.snap b/packages/graphql-generator/src/__tests__/utils/__snapshots__/GraphQLStatementsFormatter.test.ts.snap index 72114f01c..871c73f3f 100644 --- a/packages/graphql-generator/src/__tests__/utils/__snapshots__/GraphQLStatementsFormatter.test.ts.snap +++ b/packages/graphql-generator/src/__tests__/utils/__snapshots__/GraphQLStatementsFormatter.test.ts.snap @@ -1,5 +1,31 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`GraphQL statements Formatter Generates formatted output and only remove file extension 1`] = ` +"/* tslint:disable */ +/* eslint-disable */ +// this is an auto generated file. This will be overwritten + +import * as APITypes from \\"../Components/Data/API\\"; +type GeneratedQuery = string & { + __generatedQueryInput: InputType; + __generatedQueryOutput: OutputType; +}; + +export const getProject = /* GraphQL */ \`query GetProject($id: ID!) { + getProject(id: $id) { + id + name + createdAt + updatedAt + } +} +\` as GeneratedQuery< + APITypes.GetProjectQueryVariables, + APITypes.GetProjectQuery +>; +" +`; + exports[`GraphQL statements Formatter Generates formatted output for Angular frontend 1`] = ` "# this is an auto generated file. This will be overwritten @@ -88,6 +114,32 @@ export const getProject = /* GraphQL */ \`query GetProject($id: ID!) { " `; +exports[`GraphQL statements Formatter Generates formatted output for TS frontend with posix path in same dir 1`] = ` +"/* tslint:disable */ +/* eslint-disable */ +// this is an auto generated file. This will be overwritten + +import * as APITypes from \\"./API\\"; +type GeneratedQuery = string & { + __generatedQueryInput: InputType; + __generatedQueryOutput: OutputType; +}; + +export const getProject = /* GraphQL */ \`query GetProject($id: ID!) { + getProject(id: $id) { + id + name + createdAt + updatedAt + } +} +\` as GeneratedQuery< + APITypes.GetProjectQueryVariables, + APITypes.GetProjectQuery +>; +" +`; + exports[`GraphQL statements Formatter Generates formatted output for TS frontend with windows path 1`] = ` "/* tslint:disable */ /* eslint-disable */ @@ -113,3 +165,29 @@ export const getProject = /* GraphQL */ \`query GetProject($id: ID!) { >; " `; + +exports[`GraphQL statements Formatter Generates formatted output for TS frontend with windows path in same dir 1`] = ` +"/* tslint:disable */ +/* eslint-disable */ +// this is an auto generated file. This will be overwritten + +import * as APITypes from \\"./API\\"; +type GeneratedQuery = string & { + __generatedQueryInput: InputType; + __generatedQueryOutput: OutputType; +}; + +export const getProject = /* GraphQL */ \`query GetProject($id: ID!) { + getProject(id: $id) { + id + name + createdAt + updatedAt + } +} +\` as GeneratedQuery< + APITypes.GetProjectQueryVariables, + APITypes.GetProjectQuery +>; +" +`; diff --git a/packages/graphql-generator/src/utils/GraphQLStatementsFormatter.ts b/packages/graphql-generator/src/utils/GraphQLStatementsFormatter.ts index 0958df584..2c894af0e 100644 --- a/packages/graphql-generator/src/utils/GraphQLStatementsFormatter.ts +++ b/packages/graphql-generator/src/utils/GraphQLStatementsFormatter.ts @@ -35,12 +35,20 @@ export class GraphQLStatementsFormatter { }[operation]; this.lintOverrides = []; this.headerComments = []; - this.typesPath = typesPath - ? typesPath.replace(/.ts/i, '') - // ensure posix path separators are used - .split(path.win32.sep) - .join(path.posix.sep) - : null; + if (typesPath) { + // ensure posix path separators are used + const typesPathWithPosixSep = typesPath.split(path.win32.sep).join(path.posix.sep) + const { dir, name } = path.parse(typesPathWithPosixSep); + const typesPathWithoutExtension = path.join(dir, name); + if (!typesPathWithoutExtension.startsWith('.')) { + // path.join will strip prefixed ./ + this.typesPath = `./${typesPathWithoutExtension}`; + } else { + this.typesPath = typesPathWithoutExtension; + } + } else { + this.typesPath = null; + } this.includeTypeScriptTypes = !!(this.language === 'typescript' && this.opTypeName && this.typesPath); } From adfff4468173070d77ea7938750cef96a7dbf36f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 20 Oct 2023 10:07:44 -0700 Subject: [PATCH 3/5] build(deps): bump @babel/traverse from 7.23.0 to 7.23.2 (#745) Bumps [@babel/traverse](https://github.com/babel/babel/tree/HEAD/packages/babel-traverse) from 7.23.0 to 7.23.2. - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v7.23.2/packages/babel-traverse) --- updated-dependencies: - dependency-name: "@babel/traverse" dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- yarn.lock | 30 +++--------------------------- 1 file changed, 3 insertions(+), 27 deletions(-) diff --git a/yarn.lock b/yarn.lock index 248b51210..c88449fe6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -91,14 +91,6 @@ winston "^3.3.3" winston-daily-rotate-file "^4.5.0" -"@aws-amplify/amplify-cli-logger@1.3.6": - version "1.3.6" - resolved "https://registry.npmjs.org/@aws-amplify/amplify-cli-logger/-/amplify-cli-logger-1.3.6.tgz#341a64921e3165e104ce6f0d717067b440402498" - integrity sha512-wjiSZbu/5sK7In08Q5se6LkUPR8waGn6V6mc2p5r7tBK9f3UxAaY5UjYPD5ulO6l3dOsLcWGWnClLTdImUmiZQ== - dependencies: - winston "^3.3.3" - winston-daily-rotate-file "^4.5.0" - "@aws-amplify/amplify-cli-shared-interfaces@1.2.3": version "1.2.3" resolved "https://registry.npmjs.org/@aws-amplify/amplify-cli-shared-interfaces/-/amplify-cli-shared-interfaces-1.2.3.tgz#01afc1508e11faadeb5d45298e8b5c486dc272b0" @@ -118,15 +110,6 @@ chalk "^4.1.1" enquirer "^2.3.6" -"@aws-amplify/amplify-prompts@2.8.4": - version "2.8.4" - resolved "https://registry.npmjs.org/@aws-amplify/amplify-prompts/-/amplify-prompts-2.8.4.tgz#cb2880312284d28b2fa1a3266942d73169cd3432" - integrity sha512-hR6oUzosH8DIb1aZXmPxdvMBsNRORsR8dy6/Wl8D4pGyPDxJPFZ2BqIS4DECX/gjDTiZx9ivso7ABCkF5w7pUg== - dependencies: - "@aws-amplify/amplify-cli-shared-interfaces" "1.2.3" - chalk "^4.1.1" - enquirer "^2.3.6" - "@aws-amplify/analytics@6.5.5": version "6.5.5" resolved "https://registry.npmjs.org/@aws-amplify/analytics/-/analytics-6.5.5.tgz#76959cbe539c43bb5d4673a17dd28570ca2d5a6f" @@ -252,13 +235,6 @@ dependencies: graphql "^15.5.0" -"@aws-amplify/graphql-transformer-interfaces@^3.1.2": - version "3.2.0" - resolved "https://registry.npmjs.org/@aws-amplify/graphql-transformer-interfaces/-/graphql-transformer-interfaces-3.2.0.tgz#29179690bbe5e9c2fd564d588ba00b12f62d5834" - integrity sha512-BDhRoGa8YjxglsYjqlJ/rog182lKzBO4FAq/3hRDA0Hij0Be2npCOPVP1HZ9OsAkRCdSrNE1IokwRQP8o512eg== - dependencies: - graphql "^15.5.0" - "@aws-amplify/interactions@5.2.11": version "5.2.11" resolved "https://registry.npmjs.org/@aws-amplify/interactions/-/interactions-5.2.11.tgz#bb1bf0ccdfa604e5fc3acee94a372944ccbdb5bd" @@ -3070,9 +3046,9 @@ "@babel/types" "^7.22.15" "@babel/traverse@^7.14.0", "@babel/traverse@^7.23.0", "@babel/traverse@^7.7.2": - version "7.23.0" - resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.0.tgz#18196ddfbcf4ccea324b7f6d3ada00d8c5a99c53" - integrity sha512-t/QaEvyIoIkwzpiZ7aoSKK8kObQYeF7T2v+dazAYCb8SXtp58zEVkWW7zAnju8FNKNdr4ScAOEDmMItbyOmEYw== + version "7.23.2" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.2.tgz#329c7a06735e144a506bdb2cad0268b7f46f4ad8" + integrity sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw== dependencies: "@babel/code-frame" "^7.22.13" "@babel/generator" "^7.23.0" From a033f3314a90095a92b58f870dffa10fcd1a8b25 Mon Sep 17 00:00:00 2001 From: Dane Pilcher Date: Fri, 20 Oct 2023 11:12:36 -0600 Subject: [PATCH 4/5] ci: run unit test on windows and fix windows bugs (#743) * fix: use correct path separators on windows environment (again) * fix: use posix path sep on graphql-generator output --- .codebuild/build_windows.yml | 4 +- .codebuild/e2e_workflow.yml | 8 ++ .codebuild/e2e_workflow_base.yml | 8 ++ .codebuild/pr_workflow.yml | 8 ++ .codebuild/release_workflow.yml | 8 ++ .codebuild/scripts/build_windows.sh | 6 ++ .codebuild/scripts/test_windows.sh | 6 ++ .codebuild/test_windows.yml | 11 +++ .../codegen-config/AmplifyCodeGenConfig.js | 14 ++-- packages/amplify-codegen/src/commands/add.js | 4 +- .../tests/commands/statements.test.js | 3 +- packages/graphql-generator/src/models.ts | 5 +- .../src/utils/GraphQLStatementsFormatter.ts | 5 +- .../src/utilities/getOutputFileName.ts | 3 +- .../test/utilities/getOutputFileName.test.ts | 3 +- shared-scripts.sh | 83 +++++++++++++++---- 16 files changed, 149 insertions(+), 30 deletions(-) create mode 100644 .codebuild/scripts/build_windows.sh create mode 100644 .codebuild/scripts/test_windows.sh create mode 100644 .codebuild/test_windows.yml diff --git a/.codebuild/build_windows.yml b/.codebuild/build_windows.yml index a79f4a825..9631f7dac 100644 --- a/.codebuild/build_windows.yml +++ b/.codebuild/build_windows.yml @@ -4,8 +4,8 @@ env: phases: build: commands: - - yarn run production-build - + # commands need to be run in stand-alone bash scripts so that bash can be used on windows + - bash ./.codebuild/scripts/build_windows.sh artifacts: files: - 'shared-scripts.sh' diff --git a/.codebuild/e2e_workflow.yml b/.codebuild/e2e_workflow.yml index e75a50bb1..1c420534c 100644 --- a/.codebuild/e2e_workflow.yml +++ b/.codebuild/e2e_workflow.yml @@ -16,6 +16,14 @@ batch: type: WINDOWS_SERVER_2019_CONTAINER compute-type: BUILD_GENERAL1_LARGE image: $WINDOWS_IMAGE_2019 + - identifier: test_windows + buildspec: .codebuild/test_windows.yml + env: + type: WINDOWS_SERVER_2019_CONTAINER + compute-type: BUILD_GENERAL1_LARGE + image: $WINDOWS_IMAGE_2019 + depend-on: + - build_windows - identifier: test buildspec: .codebuild/test.yml env: diff --git a/.codebuild/e2e_workflow_base.yml b/.codebuild/e2e_workflow_base.yml index 3e33fd18d..538530760 100644 --- a/.codebuild/e2e_workflow_base.yml +++ b/.codebuild/e2e_workflow_base.yml @@ -16,6 +16,14 @@ batch: type: WINDOWS_SERVER_2019_CONTAINER compute-type: BUILD_GENERAL1_LARGE image: $WINDOWS_IMAGE_2019 + - identifier: test_windows + buildspec: .codebuild/test_windows.yml + env: + type: WINDOWS_SERVER_2019_CONTAINER + compute-type: BUILD_GENERAL1_LARGE + image: $WINDOWS_IMAGE_2019 + depend-on: + - build_windows - identifier: test buildspec: .codebuild/test.yml env: diff --git a/.codebuild/pr_workflow.yml b/.codebuild/pr_workflow.yml index 56eb3ff7e..ebaa670fc 100644 --- a/.codebuild/pr_workflow.yml +++ b/.codebuild/pr_workflow.yml @@ -14,6 +14,14 @@ batch: type: WINDOWS_SERVER_2019_CONTAINER compute-type: BUILD_GENERAL1_LARGE image: $WINDOWS_IMAGE_2019 + - identifier: test_windows + buildspec: .codebuild/test_windows.yml + env: + type: WINDOWS_SERVER_2019_CONTAINER + compute-type: BUILD_GENERAL1_LARGE + image: $WINDOWS_IMAGE_2019 + depend-on: + - build_windows - identifier: test buildspec: .codebuild/test.yml depend-on: diff --git a/.codebuild/release_workflow.yml b/.codebuild/release_workflow.yml index e7d6b7857..50ce2d11e 100644 --- a/.codebuild/release_workflow.yml +++ b/.codebuild/release_workflow.yml @@ -14,6 +14,14 @@ batch: type: WINDOWS_SERVER_2019_CONTAINER compute-type: BUILD_GENERAL1_LARGE image: $WINDOWS_IMAGE_2019 + - identifier: test_windows + buildspec: .codebuild/test_windows.yml + env: + type: WINDOWS_SERVER_2019_CONTAINER + compute-type: BUILD_GENERAL1_LARGE + image: $WINDOWS_IMAGE_2019 + depend-on: + - build_windows - identifier: test buildspec: .codebuild/test.yml depend-on: diff --git a/.codebuild/scripts/build_windows.sh b/.codebuild/scripts/build_windows.sh new file mode 100644 index 000000000..f2787257b --- /dev/null +++ b/.codebuild/scripts/build_windows.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +# set exit on error to true +set -e + +source ./shared-scripts.sh && _buildWindows diff --git a/.codebuild/scripts/test_windows.sh b/.codebuild/scripts/test_windows.sh new file mode 100644 index 000000000..6ba7cdb0c --- /dev/null +++ b/.codebuild/scripts/test_windows.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +# set exit on error to true +set -e + +source ./shared-scripts.sh && _testWindows diff --git a/.codebuild/test_windows.yml b/.codebuild/test_windows.yml new file mode 100644 index 000000000..e86bbdcb0 --- /dev/null +++ b/.codebuild/test_windows.yml @@ -0,0 +1,11 @@ +version: 0.2 +env: + shell: powershell.exe +phases: + build: + commands: + # commands need to be run in stand-alone bash scripts so that bash can be used on windows + - bash ./.codebuild/scripts/test_windows.sh +artifacts: + files: + - 'shared-scripts.sh' diff --git a/packages/amplify-codegen/src/codegen-config/AmplifyCodeGenConfig.js b/packages/amplify-codegen/src/codegen-config/AmplifyCodeGenConfig.js index abb12c6a5..7b8886570 100644 --- a/packages/amplify-codegen/src/codegen-config/AmplifyCodeGenConfig.js +++ b/packages/amplify-codegen/src/codegen-config/AmplifyCodeGenConfig.js @@ -2,7 +2,8 @@ const graphQLConfig = require('graphql-config'); const { isAbsolute, relative, join } = require('path'); const slash = require('slash'); const { graphQlToAmplifyConfig } = require('./utils'); -const fs = require('fs-extra'); +const fs = require('fs-extra'); +const path = require('path'); class AmplifyCodeGenConfig { static configFileName = '.graphqlconfig.yml'; @@ -15,10 +16,9 @@ class AmplifyCodeGenConfig { if (e instanceof graphQLConfig.ConfigNotFoundError) { const projectRoot = projectPath || process.cwd(); const configPath = join(projectRoot, '.graphqlconfig.yml'); - if(fs.existsSync(configPath)) { + if (fs.existsSync(configPath)) { this.gqlConfig = graphQLConfig.getGraphQLConfig(projectRoot); - } - else { + } else { this.gqlConfig = new graphQLConfig.GraphQLConfig(null, configPath); this.gqlConfig.config = {}; } @@ -45,7 +45,11 @@ class AmplifyCodeGenConfig { if (!this.constructor.isValidAmplifyProject(project)) { return false; } - const schemaPath = isAbsolute(project.schema) ? relative(this.gqlConfig.configDir, project.schema) : project.schema; + // Set schemaPath to use posix separators. Node can handle windows and posix separators regradless of platform + // Ensures all paths in .graphlqconfig.yml use posix style + const schemaPath = (isAbsolute(project.schema) ? relative(this.gqlConfig.configDir, project.schema) : project.schema) + .split(path.win32.sep) + .join(path.posix.sep); const newProject = { schemaPath, includes: project.includes, diff --git a/packages/amplify-codegen/src/commands/add.js b/packages/amplify-codegen/src/commands/add.js index 7ee6d4bae..21572d310 100644 --- a/packages/amplify-codegen/src/commands/add.js +++ b/packages/amplify-codegen/src/commands/add.js @@ -134,7 +134,9 @@ async function add(context, apiId = null, region = 'us-east-1') { projectName: withoutInit ? 'Codegen Project' : apiDetails.name, includes: answer.includePattern, excludes: [...answer.excludePattern, answer.generatedFileName], - schema, + // Set schema path to use posix separators. Node can handle windows and posix separators regradless of platform + // Ensures all paths in .graphlqconfig.yml use posix style + schema: schema.split(path.win32.sep).join(path.posix.sep), amplifyExtension: { codeGenTarget: answer.target || '', generatedFileName: answer.generatedFileName || '', diff --git a/packages/amplify-codegen/tests/commands/statements.test.js b/packages/amplify-codegen/tests/commands/statements.test.js index 21440dc71..d9b9f221d 100644 --- a/packages/amplify-codegen/tests/commands/statements.test.js +++ b/packages/amplify-codegen/tests/commands/statements.test.js @@ -87,7 +87,8 @@ describe('command - statements', () => { await generateStatements(MOCK_CONTEXT, forceDownload); expect(getFrontEndHandler).toHaveBeenCalledWith(MOCK_CONTEXT); expect(loadConfig).toHaveBeenCalledWith(MOCK_CONTEXT, false); - expect(getRelativeTypesPath).toHaveBeenCalledWith('MOCK_PROJECT_ROOT/MOCK_STATEMENTS_PATH', 'API.TS'); + // ok for getRelativeTypePath to be called with posix or Windows path separators + expect(getRelativeTypesPath).toHaveBeenCalledWith(path.join(MOCK_PROJECT_ROOT, MOCK_STATEMENTS_PATH), 'API.TS'); expect(generateStatementsHelper).toHaveBeenCalledWith({ relativeTypesPath: relativePath, schema: MOCK_SCHEMA, diff --git a/packages/graphql-generator/src/models.ts b/packages/graphql-generator/src/models.ts index 1b744ac60..9695ae989 100644 --- a/packages/graphql-generator/src/models.ts +++ b/packages/graphql-generator/src/models.ts @@ -1,3 +1,4 @@ +import * as path from 'path'; import { parse } from 'graphql'; import * as appSyncDataStoreCodeGen from '@aws-amplify/appsync-modelgen-plugin'; import { codegen } from '@graphql-codegen/core'; @@ -61,7 +62,9 @@ export async function generateModels(options: GenerateModelsOptions): Promise { const content = await codegen(config); - return { [config.filename]: content }; + + // set the keys to always use posix path separators + return { [config.filename.split(path.win32.sep).join(path.posix.sep)]: content }; }), ).then((outputs: GeneratedOutput[]) => outputs.reduce((curr, next) => ({ ...curr, ...next }), {})); } diff --git a/packages/graphql-generator/src/utils/GraphQLStatementsFormatter.ts b/packages/graphql-generator/src/utils/GraphQLStatementsFormatter.ts index 2c894af0e..9293f226c 100644 --- a/packages/graphql-generator/src/utils/GraphQLStatementsFormatter.ts +++ b/packages/graphql-generator/src/utils/GraphQLStatementsFormatter.ts @@ -36,10 +36,9 @@ export class GraphQLStatementsFormatter { this.lintOverrides = []; this.headerComments = []; if (typesPath) { + const { dir, name } = path.parse(typesPath); // ensure posix path separators are used - const typesPathWithPosixSep = typesPath.split(path.win32.sep).join(path.posix.sep) - const { dir, name } = path.parse(typesPathWithPosixSep); - const typesPathWithoutExtension = path.join(dir, name); + const typesPathWithoutExtension = path.join(dir, name).split(path.win32.sep).join(path.posix.sep); if (!typesPathWithoutExtension.startsWith('.')) { // path.join will strip prefixed ./ this.typesPath = `./${typesPathWithoutExtension}`; diff --git a/packages/graphql-types-generator/src/utilities/getOutputFileName.ts b/packages/graphql-types-generator/src/utilities/getOutputFileName.ts index e043a0d01..517cfae00 100644 --- a/packages/graphql-types-generator/src/utilities/getOutputFileName.ts +++ b/packages/graphql-types-generator/src/utilities/getOutputFileName.ts @@ -9,7 +9,8 @@ export function getOutputFileName(inputFileName: string, target: Target): string const ext = path.extname(inputFileName); const baseName = inputFileName.substr(0, inputFileName.length - ext.length); const filename = inputFileName.includes(fileExtension) ? inputFileName : `${baseName}.${fileExtension}`; - return ['API', 'api'].includes(inputFileName) ? path.join(folderMap[target], filename) : filename; + // ensure the filepath for the types file uses posix separators + return ['API', 'api'].includes(inputFileName) ? path.join(folderMap[target], filename).split(path.win32.sep).join(path.posix.sep) : filename; } return inputFileName; } diff --git a/packages/graphql-types-generator/test/utilities/getOutputFileName.test.ts b/packages/graphql-types-generator/test/utilities/getOutputFileName.test.ts index da6af53cc..7429068dc 100644 --- a/packages/graphql-types-generator/test/utilities/getOutputFileName.test.ts +++ b/packages/graphql-types-generator/test/utilities/getOutputFileName.test.ts @@ -1,4 +1,3 @@ -const { join } = require('path'); import { getOutputFileName } from '../../src/utilities/getOutputFileName'; describe('getOutputFileName', () => { @@ -15,7 +14,7 @@ describe('getOutputFileName', () => { }); it('should return api.service.ts when input name is missing and target is angular', () => { - expect(getOutputFileName(null, 'angular')).toEqual(join('src', 'app', 'api.service.ts')); + expect(getOutputFileName(null, 'angular')).toEqual('src/app/api.service.ts'); }); it('should not add any extension if the code generation target is unknown', () => { diff --git a/shared-scripts.sh b/shared-scripts.sh index 647a1b1d2..78f7f9eec 100644 --- a/shared-scripts.sh +++ b/shared-scripts.sh @@ -3,15 +3,36 @@ # set exit on error to true set -e +# The flags address the issue here: https://github.com/boto/botocore/issues/1716 +export MSYS_NO_PATHCONV=1 +export MSYS2_ARG_CONV_EXCL="*" + # storeCache function storeCache { localPath="$1" alias="$2" + environment="$3" s3Path="s3://$CACHE_BUCKET_NAME/$CODEBUILD_SOURCE_VERSION/$alias" echo "Writing cache folder $alias to $s3Path" # zip contents and upload to s3 - if ! (cd $localPath && tar cz . | aws s3 cp - $s3Path); then - echo "Something went wrong storing the cache folder $alias." + errorMessage="Something went wrong storing the cache folder $alias. Continuing anyway." + # tar behaves differently on windows + # Windows tar does not allow stdin/stdout Windows equivalent. + # The archive needs to be written to a file first. + # We don't also do this for Linux because: + # 1. It is much slower. + # 2. The linux version fails with `file changed as we read it`. + # Branching the bash script is the easiest way around this + if [[ $environment == "windows" ]]; then + echo "Storing cache for Windows" + if ! (cd $localPath && tar -czf cache.tar . && ls && aws s3 cp cache.tar $s3Path); then + echo $errorMessage + fi + else + echo "Storing cache for Linux" + if ! (cd $localPath && tar cz . | aws s3 cp - $s3Path); then + echo $errorMessage + fi fi echo "Done writing cache folder $alias" cd $CODEBUILD_SRC_DIR @@ -21,6 +42,7 @@ function storeCache { function loadCache { alias="$1" localPath="$2" + environment="$3" s3Path="s3://$CACHE_BUCKET_NAME/$CODEBUILD_SOURCE_VERSION/$alias" echo "Loading cache folder from $s3Path" # create directory if it doesn't exist yet @@ -31,25 +53,46 @@ function loadCache { exit 0 fi # load cache and unzip it - if ! (cd $localPath && aws s3 cp $s3Path - | tar xz); then - echo "Something went wrong fetching the cache folder $alias. Continuing anyway." + errorMessage="Something went wrong fetching the cache folder $alias. Continuing anyway." + if [[ $environment == "windows" ]]; then # tar behaves differently on windows + echo "Loading cache for Windows" + if ! (cd $localPath && aws s3 cp $s3Path - | tar xzkf -); then + echo $errorMessage + fi + else + echo "Loading cache for Linux" + if ! (cd $localPath && aws s3 cp $s3Path - | tar xz); then + echo $errorMessage + fi fi echo "Done loading cache folder $alias" cd $CODEBUILD_SRC_DIR } -function storeCacheForBuildJob { +function storeCacheForLinuxBuildJob { # upload [repo, .cache] to s3 storeCache $CODEBUILD_SRC_DIR repo storeCache $HOME/.cache .cache } -function loadCacheFromBuildJob { +function storeCacheForWindowsBuildJob { + storeCache $CODEBUILD_SRC_DIR repo-windows windows + storeCache $HOME/AppData/Local/Yarn/Cache/v6 .cache-windows windows +} + +function loadCacheFromLinuxBuildJob { # download [repo, .cache] from s3 loadCache repo $CODEBUILD_SRC_DIR loadCache .cache $HOME/.cache } + +function loadCacheFromWindowsBuildJob { + # download [repo, .cache] from s3 + loadCache repo-windows $CODEBUILD_SRC_DIR windows + loadCache .cache-windows $HOME/AppData/Local/Yarn/Cache/v6 windows +} + function storeCacheFile { localFilePath="$1" alias="$2" @@ -90,30 +133,42 @@ function _buildLinux { _setShell echo "Linux Build" yarn run production-build - storeCacheForBuildJob + storeCacheForLinuxBuildJob +} + +function _buildWindows { + echo "Linux Build" + yarn run production-build + storeCacheForWindowsBuildJob } function _testLinux { - echo "Run Unit Test" - loadCacheFromBuildJob + echo "Run Unit Test Linux" + loadCacheFromLinuxBuildJob + yarn test-ci +} + +function _testWindows { + echo "Run Unit Test Windows" + loadCacheFromWindowsBuildJob yarn test-ci } function _verifyAPIExtract { echo "Verify API Extract" - loadCacheFromBuildJob + loadCacheFromLinuxBuildJob yarn verify-api-extract } function _lint { echo "Lint" - loadCacheFromBuildJob + loadCacheFromLinuxBuildJob chmod +x .codebuild/scripts/lint_pr.sh && ./.codebuild/scripts/lint_pr.sh } function _publishToLocalRegistry { echo "Publish To Local Registry" - loadCacheFromBuildJob + loadCacheFromLinuxBuildJob if [ -z "$BRANCH_NAME" ]; then if [ -z "$CODEBUILD_WEBHOOK_TRIGGER" ]; then export BRANCH_NAME="$(git symbolic-ref HEAD --short 2>/dev/null)" @@ -178,7 +233,7 @@ function _loadTestAccountCredentials { function _setupE2ETestsLinux { echo "Setup E2E Tests Linux" - loadCacheFromBuildJob + loadCacheFromLinuxBuildJob loadCache verdaccio-cache $CODEBUILD_SRC_DIR/../verdaccio-cache _installCLIFromLocalRegistry _loadTestAccountCredentials @@ -200,7 +255,7 @@ function _scanArtifacts { function _cleanupE2EResources { echo "Cleanup E2E resources" - loadCacheFromBuildJob + loadCacheFromLinuxBuildJob cd packages/amplify-codegen-e2e-tests echo "Running clean up script" build_batch_arn=$(aws codebuild batch-get-builds --ids $CODEBUILD_BUILD_ID | jq -r -c '.builds[0].buildBatchArn') From 211bb0da63b0f5a771d67460f1d5aefb792a2b53 Mon Sep 17 00:00:00 2001 From: Phani Srikar Edupuganti <55896475+phani-srikar@users.noreply.github.com> Date: Fri, 20 Oct 2023 13:12:28 -0700 Subject: [PATCH 5/5] fix: add codegen for non-ios frontends; updated e2e test for iOS frontend (#749) --- .../amplify-codegen-e2e-core/src/utils/graphql-config-helper.ts | 1 + packages/amplify-codegen/src/commands/add.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/amplify-codegen-e2e-core/src/utils/graphql-config-helper.ts b/packages/amplify-codegen-e2e-core/src/utils/graphql-config-helper.ts index 80b4d7c42..61aecd9bd 100644 --- a/packages/amplify-codegen-e2e-core/src/utils/graphql-config-helper.ts +++ b/packages/amplify-codegen-e2e-core/src/utils/graphql-config-helper.ts @@ -35,6 +35,7 @@ export function constructGraphQLConfig( extensions.amplify.codeGenTarget = 'swift'; extensions.amplify.docsFilePath = 'graphql'; extensions.amplify.generatedFileName = 'API.swift'; + excludes.push('API.swift'); break; default: schemaPath = `amplify/backend/api/${projectName}/build/schema.graphql`; diff --git a/packages/amplify-codegen/src/commands/add.js b/packages/amplify-codegen/src/commands/add.js index 21572d310..26ddb3f88 100644 --- a/packages/amplify-codegen/src/commands/add.js +++ b/packages/amplify-codegen/src/commands/add.js @@ -133,7 +133,7 @@ async function add(context, apiId = null, region = 'us-east-1') { const newProject = { projectName: withoutInit ? 'Codegen Project' : apiDetails.name, includes: answer.includePattern, - excludes: [...answer.excludePattern, answer.generatedFileName], + excludes: [...answer.excludePattern, answer.generatedFileName]?.filter(item => item), // Set schema path to use posix separators. Node can handle windows and posix separators regradless of platform // Ensures all paths in .graphlqconfig.yml use posix style schema: schema.split(path.win32.sep).join(path.posix.sep),