Skip to content

Commit 1711c21

Browse files
iankhouiliapolo
andauthored
chore: pass cloud-e2e CodeBuild jobs (#14829)
* fix: error contains circular reference and crashes e2e reporting mechanism * add gen2-migration e2es to cloud-e2e * prettier * various changes to pass cloud-e2e * fix: amplify --version warnings are not handled in uploadPkgCodeBuild * name fix for gen2 e2e migration system * feat: bump version * add profile to existing config and credentials files, if they exist * chore: skip deleting the gen1 placeholder app * chore: lint * chore: more cleanup filters * chore: update credentials writer * chore: update amplify path * chore: debug logs * chore: add gen2-migration apps as a dependency of cleanup_resources * chore: more debug logs --------- Co-authored-by: Eli Polonsky <epolon@amazon.com>
1 parent 412db64 commit 1711c21

14 files changed

Lines changed: 620 additions & 33 deletions

File tree

.circleci/local_publish_helpers_codebuild.sh

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ function uploadPkgCliCodeBuild {
2828
set -e
2929

3030
cd out/
31-
export version=$(./amplify-pkg-linux-x64 --version)
31+
# --version can emit warnings before the version line; keep only the last line
32+
export version=$(./amplify-pkg-linux-x64 --version | tail -n 1)
3233

3334
# validate that version is uploaded in right build
3435
if [[ "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
@@ -140,7 +141,7 @@ function verifyPkgCli {
140141
}
141142

142143
# TODO: After V3 migrations are done, decrease 1095 back to 930 and 875 back to 750
143-
verifySinglePkg "amplify-pkg-linux-x64" "amplify-pkg-linux-x64.tgz" $((1095 * 1024 * 1024))
144+
verifySinglePkg "amplify-pkg-linux-x64" "amplify-pkg-linux-x64.tgz" $((1130 * 1024 * 1024))
144145
verifySinglePkg "amplify-pkg-macos-x64" "amplify-pkg-macos-x64.tgz" $((1105 * 1024 * 1024))
145146
verifySinglePkg "amplify-pkg-win-x64.exe" "amplify-pkg-win-x64.tgz" $((1095 * 1024 * 1024))
146147
verifySinglePkg "amplify-pkg-linux-arm64" "amplify-pkg-linux-arm64.tgz" $((875 * 1024 * 1024))

codebuild_specs/e2e_workflow_base.yml

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,3 +140,75 @@ batch:
140140
buildspec: codebuild_specs/cleanup_resources.yml
141141
depend-on:
142142
- aggregate_e2e_reports
143+
- migrate_backend_only
144+
- migrate_discussions
145+
- migrate_fitness_tracker
146+
- migrate_media_vault
147+
- migrate_mood_board
148+
- migrate_product_catalog
149+
- migrate_project_boards
150+
- migrate_store_locator
151+
- identifier: migrate_backend_only
152+
buildspec: codebuild_specs/run_gen2_migration_e2e.yml
153+
depend-on:
154+
- upb
155+
env:
156+
compute-type: BUILD_GENERAL1_LARGE
157+
variables:
158+
MIGRATION_APP: backend-only
159+
- identifier: migrate_discussions
160+
buildspec: codebuild_specs/run_gen2_migration_e2e.yml
161+
depend-on:
162+
- upb
163+
env:
164+
compute-type: BUILD_GENERAL1_LARGE
165+
variables:
166+
MIGRATION_APP: discussions
167+
- identifier: migrate_fitness_tracker
168+
buildspec: codebuild_specs/run_gen2_migration_e2e.yml
169+
depend-on:
170+
- upb
171+
env:
172+
compute-type: BUILD_GENERAL1_LARGE
173+
variables:
174+
MIGRATION_APP: fitness-tracker
175+
- identifier: migrate_media_vault
176+
buildspec: codebuild_specs/run_gen2_migration_e2e.yml
177+
depend-on:
178+
- upb
179+
env:
180+
compute-type: BUILD_GENERAL1_LARGE
181+
variables:
182+
MIGRATION_APP: media-vault
183+
- identifier: migrate_mood_board
184+
buildspec: codebuild_specs/run_gen2_migration_e2e.yml
185+
depend-on:
186+
- upb
187+
env:
188+
compute-type: BUILD_GENERAL1_LARGE
189+
variables:
190+
MIGRATION_APP: mood-board
191+
- identifier: migrate_product_catalog
192+
buildspec: codebuild_specs/run_gen2_migration_e2e.yml
193+
depend-on:
194+
- upb
195+
env:
196+
compute-type: BUILD_GENERAL1_LARGE
197+
variables:
198+
MIGRATION_APP: product-catalog
199+
- identifier: migrate_project_boards
200+
buildspec: codebuild_specs/run_gen2_migration_e2e.yml
201+
depend-on:
202+
- upb
203+
env:
204+
compute-type: BUILD_GENERAL1_LARGE
205+
variables:
206+
MIGRATION_APP: project-boards
207+
- identifier: migrate_store_locator
208+
buildspec: codebuild_specs/run_gen2_migration_e2e.yml
209+
depend-on:
210+
- upb
211+
env:
212+
compute-type: BUILD_GENERAL1_LARGE
213+
variables:
214+
MIGRATION_APP: store-locator

codebuild_specs/e2e_workflow_generated.yml

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,78 @@ batch:
140140
buildspec: codebuild_specs/cleanup_resources.yml
141141
depend-on:
142142
- aggregate_e2e_reports
143+
- migrate_backend_only
144+
- migrate_discussions
145+
- migrate_fitness_tracker
146+
- migrate_media_vault
147+
- migrate_mood_board
148+
- migrate_product_catalog
149+
- migrate_project_boards
150+
- migrate_store_locator
151+
- identifier: migrate_backend_only
152+
buildspec: codebuild_specs/run_gen2_migration_e2e.yml
153+
depend-on:
154+
- upb
155+
env:
156+
compute-type: BUILD_GENERAL1_LARGE
157+
variables:
158+
MIGRATION_APP: backend-only
159+
- identifier: migrate_discussions
160+
buildspec: codebuild_specs/run_gen2_migration_e2e.yml
161+
depend-on:
162+
- upb
163+
env:
164+
compute-type: BUILD_GENERAL1_LARGE
165+
variables:
166+
MIGRATION_APP: discussions
167+
- identifier: migrate_fitness_tracker
168+
buildspec: codebuild_specs/run_gen2_migration_e2e.yml
169+
depend-on:
170+
- upb
171+
env:
172+
compute-type: BUILD_GENERAL1_LARGE
173+
variables:
174+
MIGRATION_APP: fitness-tracker
175+
- identifier: migrate_media_vault
176+
buildspec: codebuild_specs/run_gen2_migration_e2e.yml
177+
depend-on:
178+
- upb
179+
env:
180+
compute-type: BUILD_GENERAL1_LARGE
181+
variables:
182+
MIGRATION_APP: media-vault
183+
- identifier: migrate_mood_board
184+
buildspec: codebuild_specs/run_gen2_migration_e2e.yml
185+
depend-on:
186+
- upb
187+
env:
188+
compute-type: BUILD_GENERAL1_LARGE
189+
variables:
190+
MIGRATION_APP: mood-board
191+
- identifier: migrate_product_catalog
192+
buildspec: codebuild_specs/run_gen2_migration_e2e.yml
193+
depend-on:
194+
- upb
195+
env:
196+
compute-type: BUILD_GENERAL1_LARGE
197+
variables:
198+
MIGRATION_APP: product-catalog
199+
- identifier: migrate_project_boards
200+
buildspec: codebuild_specs/run_gen2_migration_e2e.yml
201+
depend-on:
202+
- upb
203+
env:
204+
compute-type: BUILD_GENERAL1_LARGE
205+
variables:
206+
MIGRATION_APP: project-boards
207+
- identifier: migrate_store_locator
208+
buildspec: codebuild_specs/run_gen2_migration_e2e.yml
209+
depend-on:
210+
- upb
211+
env:
212+
compute-type: BUILD_GENERAL1_LARGE
213+
variables:
214+
MIGRATION_APP: store-locator
143215
- identifier: l_diagnose_mock_api_hooks_a
144216
buildspec: codebuild_specs/run_e2e_tests_linux.yml
145217
env:
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
version: 0.2
2+
env:
3+
shell: bash
4+
variables:
5+
CI: true
6+
IS_AMPLIFY_CI: true
7+
TEARDOWN: '1'
8+
9+
phases:
10+
build:
11+
commands:
12+
- export NODE_OPTIONS=--max-old-space-size=4096
13+
- export AMPLIFY_DIR=$CODEBUILD_SRC_DIR/out
14+
- export AMPLIFY_PATH=$CODEBUILD_SRC_DIR/out/amplify
15+
- echo "AMPLIFY_DIR=$AMPLIFY_DIR"
16+
- echo "AMPLIFY_PATH=$AMPLIFY_PATH"
17+
- echo "MIGRATION_APP=$MIGRATION_APP"
18+
- source ./shared-scripts.sh && _runGen2MigrationE2E
19+
20+
post_build:
21+
commands:
22+
- echo "Migration E2E test completed for $MIGRATION_APP"

packages/amplify-cli-npm/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,4 @@ export const install = async (): Promise<void> => {
1616
return binary.install();
1717
};
1818

19-
// force version bump to 14.3.0
19+
// force version bump to 14.4.0

packages/amplify-cli/src/__tests__/commands/diagnose.test.ts

Lines changed: 78 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as fs from 'fs-extra';
22
import archiver from 'archiver';
3-
import { pathManager, stateManager } from '@aws-amplify/amplify-cli-core';
3+
import { AmplifyFault, pathManager, stateManager } from '@aws-amplify/amplify-cli-core';
44
import { Redactor } from '@aws-amplify/amplify-cli-logger';
55
import { WriteStream } from 'fs-extra';
66
import fetch from 'node-fetch';
@@ -10,7 +10,20 @@ import { run } from '../../commands/diagnose';
1010
import { Context } from '../../domain/context';
1111

1212
jest.mock('uuid');
13-
jest.mock('@aws-amplify/amplify-cli-core');
13+
jest.mock('@aws-amplify/amplify-cli-core', () => {
14+
const actual = jest.requireActual('@aws-amplify/amplify-cli-core');
15+
return {
16+
...actual,
17+
pathManager: { findProjectRoot: jest.fn() },
18+
stateManager: {
19+
getBackendConfig: jest.fn(),
20+
getProjectConfig: jest.fn(),
21+
getMeta: jest.fn().mockReturnValue({}),
22+
getCurrentEnvName: jest.fn().mockReturnValue('dev'),
23+
},
24+
spinner: { start: jest.fn(), stop: jest.fn(), succeed: jest.fn(), fail: jest.fn() },
25+
};
26+
});
1427
jest.mock('../../commands/helpers/collect-files');
1528
jest.mock('../../commands/helpers/encryption-helpers', () => ({
1629
createHashedIdentifier: jest.fn().mockReturnValue({
@@ -163,4 +176,67 @@ describe('run report command', () => {
163176
expect(fetch).toBeCalled();
164177
expect(zipperMock.append).toBeCalledTimes(3);
165178
});
179+
180+
it('serializes errors with circular downstream references without throwing', async () => {
181+
const contextMock = {
182+
usageData: {
183+
getUsageDataPayload: jest.fn().mockReturnValue({
184+
sessionUuid: 'sessionId',
185+
installationUuid: '',
186+
}),
187+
},
188+
exeInfo: {},
189+
input: {
190+
options: {
191+
'send-report': true,
192+
},
193+
},
194+
};
195+
196+
const pathManagerMock = pathManager as jest.Mocked<typeof pathManager>;
197+
pathManagerMock.findProjectRoot = jest.fn().mockReturnValue('user/source/myProject');
198+
const stateManagerMock = stateManager as jest.Mocked<typeof stateManager>;
199+
stateManagerMock.getBackendConfig = jest.fn().mockReturnValue(mockMeta);
200+
stateManagerMock.getProjectConfig = jest.fn().mockReturnValue({ projectName: 'myProject' });
201+
202+
const collectFilesMock = collectFiles as jest.MockedFunction<typeof collectFiles>;
203+
collectFilesMock.mockReturnValue([]);
204+
205+
const mockArchiver = archiver as jest.Mocked<typeof archiver>;
206+
const zipperMock = {
207+
append: jest.fn(),
208+
pipe: jest.fn(),
209+
finalize: jest.fn(),
210+
};
211+
mockArchiver.create = jest.fn().mockReturnValue(zipperMock);
212+
213+
const fsMock = fs as jest.Mocked<typeof fs>;
214+
fsMock.createWriteStream.mockReturnValue({
215+
on: jest.fn().mockImplementation((event, resolveFunction) => {
216+
if (event === 'close') {
217+
resolveFunction();
218+
}
219+
}),
220+
error: jest.fn(),
221+
} as unknown as WriteStream);
222+
223+
// Construct a downstream error with a self-referential property, mirroring the
224+
// `$response.req <-> $response.res` cycle that AWS SDK v3 ServiceException carries.
225+
const downstream = new Error('underlying AWS error') as Error & { $response?: unknown };
226+
const response: { req: unknown } = { req: {} };
227+
const request: { res: unknown } = { res: response };
228+
response.req = request;
229+
downstream.$response = response;
230+
231+
const fault = new AmplifyFault('NotificationsChannelSmsFault', { message: 'Failed to enable the SMS channel.' }, downstream);
232+
233+
const contextMockTyped = contextMock as unknown as Context;
234+
await expect(run(contextMockTyped, fault)).resolves.not.toThrow();
235+
236+
const errorJsonCall = zipperMock.append.mock.calls.find(([, meta]: [unknown, { name: string }]) => meta?.name === 'error.json');
237+
expect(errorJsonCall).toBeDefined();
238+
const payload = JSON.parse(errorJsonCall![0] as string);
239+
expect(payload.error.name).toBe('NotificationsChannelSmsFault');
240+
expect(payload.downstreamException.message).toBe('underlying AWS error');
241+
});
166242
});

packages/amplify-cli/src/commands/diagnose.ts

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
1-
import { stateManager, pathManager, spinner, DiagnoseReportUploadError, projectNotInitializedError } from '@aws-amplify/amplify-cli-core';
1+
import {
2+
stateManager,
3+
pathManager,
4+
spinner,
5+
DiagnoseReportUploadError,
6+
projectNotInitializedError,
7+
AmplifyException,
8+
} from '@aws-amplify/amplify-cli-core';
29
import archiver from 'archiver';
310
import * as fs from 'fs-extra';
411
import * as path from 'path';
@@ -12,6 +19,7 @@ import { prompter, printer } from '@aws-amplify/amplify-prompts';
1219
import { collectFiles } from './helpers/collect-files';
1320
import { encryptBuffer, encryptKey, createHashedIdentifier } from './helpers/encryption-helpers';
1421
import { UsageDataPayload } from '../domain/amplify-usageData/UsageDataPayload';
22+
import { SerializableError } from '../domain/amplify-usageData/SerializableError';
1523
import { DebugConfig } from '../app-config/debug-config';
1624
import { isHeadlessCommand } from '../utils/headless-input-utils';
1725
import { Context } from '../domain/context';
@@ -163,7 +171,7 @@ const createZip = async (context: Context, error: Error | undefined): Promise<st
163171
}
164172

165173
if (error) {
166-
zipper.append(JSON.stringify(error, null, 4), {
174+
zipper.append(JSON.stringify(serializeErrorForReport(error), null, 4), {
167175
name: 'error.json',
168176
});
169177
}
@@ -241,3 +249,23 @@ const getAppId = (): string => {
241249
const meta = stateManager.getMeta();
242250
return _.get(meta, ['providers', 'awscloudformation', 'AmplifyAppId']);
243251
};
252+
253+
/**
254+
* Convert an error into a JSON-safe shape for inclusion in the diagnose report.
255+
*
256+
* Caught AWS SDK errors attach the raw `IncomingMessage`/`ClientRequest` via `$response`,
257+
* which contains a circular `req <-> res` reference. A naive `JSON.stringify(error)` throws
258+
* `TypeError: Converting circular structure to JSON` and aborts report creation. Routing
259+
* through `SerializableError` guarantees a cycle-free payload and redacts ARNs and
260+
* home-directory paths as a side benefit.
261+
*/
262+
const serializeErrorForReport = (error: Error): object => {
263+
const serializedError = new SerializableError(error);
264+
if (error instanceof AmplifyException && error.downstreamException) {
265+
return {
266+
error: serializedError,
267+
downstreamException: new SerializableError(error.downstreamException),
268+
};
269+
}
270+
return { error: serializedError };
271+
};

0 commit comments

Comments
 (0)