Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
58e77c8
chore: update dependencies
dgandhi62 Oct 8, 2025
5d41a41
fix: prevent infinite retry loops in deleteProject when CloudFormatio…
dgandhi62 Oct 8, 2025
37eff25
chore: update dependency
dgandhi62 Oct 8, 2025
51cba3f
fix: change err.code to err.name for NotFoundException handling
dgandhi62 Oct 8, 2025
9567edd
fix: increase macOS binary size threshold to 1100MB
dgandhi62 Oct 9, 2025
ae486c9
fix: resolve Jest worker SIGKILL and hanging process issues
dgandhi62 Oct 9, 2025
7fdd750
fix: add failing tests to RUN_SOLO to prevent Jest worker SIGKILL errors
dgandhi62 Oct 10, 2025
e40271e
fix: remove 'as any' assertions from notification tests and add SIGKI…
dgandhi62 Oct 10, 2025
7499c10
feat: migrate notifications category to AWS SDK v3
dgandhi62 Oct 13, 2025
e28a09a
fix: retry logic in deleteProject
dgandhi62 Oct 13, 2025
45ea649
Merge dev branch into notifications SDK v3 migration
dgandhi62 Oct 15, 2025
dd17aad
fix: update dependencies
dgandhi62 Oct 15, 2025
98aba33
chore: update dependencies
dgandhi62 Oct 17, 2025
cc4b6c4
chore: merge upstream/dev with notifications category SDK v3 migration
dgandhi62 Oct 17, 2025
322f32f
fix: add tests to run_duo in codebuild
dgandhi62 Oct 17, 2025
5e7f7b4
chore: update codebuild config files
dgandhi62 Oct 17, 2025
2d05aeb
chore: merge upstream/dev
dgandhi62 Oct 21, 2025
b0297d3
fix: correct AWS SDK versions to match other packages
dgandhi62 Oct 22, 2025
99c3341
fix: api extractor version change
dgandhi62 Oct 22, 2025
1fd6b45
chore: add api extractor updates
dgandhi62 Oct 22, 2025
b1b809f
fix: dedupe yarn.lock
dgandhi62 Oct 22, 2025
c836bee
chore: dependency updates
dgandhi62 Oct 22, 2025
9349fa7
chore: update dependency
dgandhi62 Oct 22, 2025
ce16d6c
Merge branch 'dev' into category-notifications/sdk-v3-migration
Oct 22, 2025
aa865a5
chore: update e2es
Oct 22, 2025
570d83d
fix: api and yarn
Oct 22, 2025
1249541
fix: extract-api and yarn lock
Oct 24, 2025
975cad0
Merge branch 'dev' into category-notifications/sdk-v3-migration
Oct 24, 2025
c221382
fix: dedupe
Oct 24, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .circleci/local_publish_helpers_codebuild.sh
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ function verifyPkgCli {

# TODO: After V3 migrations are done, decrease 1095 back to 930 and 875 back to 750
verifySinglePkg "amplify-pkg-linux-x64" "amplify-pkg-linux-x64.tgz" $((1095 * 1024 * 1024))
verifySinglePkg "amplify-pkg-macos-x64" "amplify-pkg-macos-x64.tgz" $((1095 * 1024 * 1024))
verifySinglePkg "amplify-pkg-macos-x64" "amplify-pkg-macos-x64.tgz" $((1105 * 1024 * 1024))
verifySinglePkg "amplify-pkg-win-x64.exe" "amplify-pkg-win-x64.tgz" $((1095 * 1024 * 1024))
verifySinglePkg "amplify-pkg-linux-arm64" "amplify-pkg-linux-arm64.tgz" $((875 * 1024 * 1024))
}
Expand Down
192 changes: 100 additions & 92 deletions codebuild_specs/e2e_workflow_generated.yml

Large diffs are not rendered by default.

93 changes: 47 additions & 46 deletions codebuild_specs/wait_for_ids.json
Original file line number Diff line number Diff line change
@@ -1,69 +1,64 @@
[
"l_S3server_smoketest_smoketest_ios",
"l_amplify_app",
"l_analytics_pinpoint_flutter_analytics_kinesis_notifications_analytics_compatibility_sms_2",
"l_android_analytics_pinpoint_config_opensearch_simulator_general_config_headless_init",
"l_api_10_api_key_migration5_schema_iterative_rollback_1",
"l_api_2a_amplify_remove_S3server",
"l_api_3_layer_1_api_1",
"l_api_5_api_key_migration2_api_lambda_auth_1",
"l_api_6a_http_migration_schema_function_2",
"l_api_6c_api_2b",
"l_api_key_migration3_api_connection_migration_init_special_case",
"l_api_key_migration4_schema_iterative_update_4",
"l_android_notifications_pinpoint_config_android_analytics_pinpoint_config_opensearch_simulator",
"l_api_10_api_key_migration5",
"l_api_1_api_key_migration4",
"l_api_2b_api_2a_amplify_remove",
"l_api_6b_api_3_layer_1",
"l_api_9a_api_6c",
"l_api_9b_function_7_function_2b",
"l_api_lambda_auth_1_schema_auth_14_api_key_migration1",
"l_apigw_api_5_api_key_migration2",
"l_auth_10_init_f_init_d",
"l_auth_12_api_9a",
"l_auth_1a_auth_trigger_schema_versioned",
"l_auth_1b_auth_11_predictions_migration",
"l_auth_2b_auth_2a_analytics_pinpoint_js",
"l_auth_2c",
"l_auth_2e",
"l_auth_2h_auth_2g_auth_12",
"l_auth_4a_auth_3b_auth_3a",
"l_auth_4c_auth_3c_schema_auth_8c",
"l_auth_5b_schema_auth_8a_schema_auth_7c",
"l_auth_5d_tags_schema_model_a",
"l_auth_5e_auth_1c_schema_predictions",
"l_auth_5f_model_migration_schema_auth_5c",
"l_auth_5g_auth_2h_auth_2g",
"l_auth_8a_auth_4b_auth_migration",
"l_auth_6_storage_1b_storage_1a",
"l_auth_7b_api_6a_http_migration",
"l_auth_migration_push_pull_2",
"l_build_function_build_function_yarn_modern_auth_5g",
"l_containers_api_1",
"l_containers_api_2",
"l_custom_policies_container_api_9b_function_7",
"l_custom_resource_with_storage_build_function_build_function_yarn_modern",
"l_containers_api_secrets_api_4_schema_auth_10",
"l_custom_resources_auth_9",
"l_datastore_modelgen",
"l_delete_auth_1b_auth_11",
"l_diagnose_mock_api_hooks_a",
"l_dynamodb_simulator_user_groups_user_groups_s3_access",
"l_env_1_auth_5c_auth_5a",
"l_env_2_amplify_configure_layer_4",
"l_env_3",
"l_export_pull_a_api_7",
"l_export_pull_c_custom_resource_with_storage",
"l_export_pull_d_auth_8a_auth_4b",
"l_feature_flags_auth_8c_auth_7a",
"l_flutter_notifications_pinpoint_config_flutter_analytics_pinpoint_config_android_notifications_pinpoint_config",
"l_function_10_function_permissions_env_5",
"l_function_12_export_pull_c",
"l_function_15_function_14_function_13",
"l_function_1_storage_5",
"l_function_2a_auth_6_storage_1b",
"l_function_2b_function_11_api_connection_migration2",
"l_function_3a_dotnet_export_pull_b_auth_7b",
"l_function_3a_python_function_3a_nodejs_function_3a_go",
"l_function_11_api_connection_migration2_storage_4",
"l_function_13_function_12",
"l_function_2d_function_15_function_14",
"l_function_3a_go_function_3a_dotnet_export_pull_b",
"l_function_4_function_3b_function_2c",
"l_function_5_schema_function_1_schema_connection_2",
"l_function_8_api_8_schema_auth_13",
"l_function_migration_storage_3_schema_auth_9_c",
"l_geo_add_d_geo_add_c_delete",
"l_general_config_headless_init_dynamodb_simulator_user_groups",
"l_geo_add_d_geo_add_c",
"l_geo_add_e",
"l_geo_add_f",
"l_geo_import_2_geo_import_1a_function_9c",
"l_geo_multi_env_searchable_datastore",
"l_geo_remove_1",
"l_geo_remove_2",
"l_geo_remove_3",
"l_geo_update_1",
"l_geo_update_2",
"l_global_sandbox_c_analytics_2_pull",
"l_hooks_c_help_function_2d",
"l_hosted_ui_admin_api_schema_iterative_update_locking",
"l_hostingPROD",
"l_hosting_geo_import_3",
"l_iam_permissions_boundary_export_node_function",
Expand All @@ -83,47 +78,53 @@
"l_import_s3_3",
"l_init_c_git_clone_attach_configure_project",
"l_init_e_global_sandbox_a_geo_import_1b",
"l_javascript_analytics_pinpoint_config_ios_notifications_pinpoint_config_ios_analytics_pinpoint_config",
"l_init_force_push_hooks_c_help",
"l_init_special_case_function_3a_python_function_3a_nodejs",
"l_ios_analytics_pinpoint_config_flutter_notifications_pinpoint_config_flutter_analytics_pinpoint_config",
"l_javascript_notifications_pinpoint_config_javascript_analytics_pinpoint_config_ios_notifications_pinpoint_config",
"l_js_frontend_config",
"l_layer_2_api_lambda_auth_2_schema_iterative_update_1",
"l_notifications_analytics_compatibility_in_app_1_studio_modelgen",
"l_notifications_apns_init_b_container_hosting",
"l_notifications_in_app_messaging",
"l_notifications_lifecycle_auth_2f_auth_2d",
"l_notifications_multi_env_minify_cloudformation_init_force_push",
"l_notifications_sms_pull_notifications_in_app_messaging_env_1_custom_transformers",
"l_parameter_store_2_parameter_store_1_notifications_sms_update",
"l_notifications_sms_update_notifications_multi_env_minify_cloudformation",
"l_plugin_notifications_analytics_compatibility_sms_1_hooks_b",
"l_predictions_layer_3",
"l_push_pull_2_pr_previews_multi_env_1",
"l_pr_previews_multi_env_1_parameter_store_2_parameter_store_1",
"l_predictions_migration_api_key_migration3_api_connection_migration",
"l_s3_sse_geo_add_b_auth_8b",
"l_schema_auth_10_schema_key_resolvers",
"l_schema_auth_11_a",
"l_schema_auth_11_b_predictions_layer_3",
"l_schema_auth_11_c_notifications_analytics_compatibility_in_app_2",
"l_schema_auth_14_api_key_migration1_api_6b",
"l_schema_auth_13_layer_2_api_lambda_auth_2",
"l_schema_auth_15",
"l_schema_auth_1a_geo_headless_function_9a",
"l_schema_auth_2a_schema_auth_1b_schema_auth_11_b",
"l_schema_auth_3_schema_auth_12_schema_iterative_update_3",
"l_schema_auth_4c_init_a_geo_add_a",
"l_schema_auth_4d_frontend_config_drift_env_4",
"l_schema_auth_6b_schema_auth_5d_global_sandbox_b",
"l_schema_auth_6d_schema_auth_6c_schema_auth_2b",
"l_schema_auth_7a_schema_auth_2a_schema_auth_1b",
"l_schema_auth_9_a_schema_auth_8b_schema_auth_5b",
"l_schema_auth_9_b_schema_auth_7b_schema_auth_7a",
"l_schema_connection_1",
"l_schema_iterative_rollback_2_schema_auth_5a_export_pull_d",
"l_schema_connection_2_function_2a",
"l_schema_function_2_schema_auth_3_schema_auth_12",
"l_schema_iterative_rollback_1_schema_auth_9_b_schema_auth_7b",
"l_schema_iterative_update_1_function_5_schema_function_1",
"l_schema_iterative_update_2_function_9b_custom_policies_container",
"l_schema_iterative_update_3_schema_iterative_rollback_2_schema_auth_5a",
"l_schema_iterative_update_4_function_1",
"l_schema_iterative_update_locking_function_8_api_8",
"l_schema_key_resolvers_geo_multi_env",
"l_schema_model_c_schema_data_access_patterns_schema_auth_6a",
"l_schema_model_d_schema_model_b_schema_auth_4a",
"l_schema_model_e_schema_auth_4b_notifications_sms",
"l_schema_searchable_apigw",
"l_searchable_datastore_schema_searchable",
"l_searchable_migration",
"l_smoketest_amplify_app",
"l_smoketest_smoketest_ios_javascript_notifications_pinpoint_config",
"l_storage_1a_schema_iterative_update_2_function_9b",
"l_storage_2_function_6_custom_policies_function",
"l_storage_4_containers_api_secrets_api_4",
"l_storage_5",
"l_uibuilder",
"l_user_groups_s3_access_hosted_ui_admin_api",
"l_with_babel_config_notifications_in_app_messaging_env_2_notifications_fcm",
"w_admin_api_schema_iterative_update_locking",
"w_amplify_configure_layer_4",
Expand Down
8 changes: 7 additions & 1 deletion packages/amplify-category-notifications/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,20 @@
"@aws-amplify/amplify-environment-parameters": "1.9.22",
"@aws-amplify/amplify-prompts": "2.8.7",
"@aws-amplify/amplify-provider-awscloudformation": "8.11.14",
"aws-sdk": "^2.1464.0",
"@aws-sdk/client-iam": "^3.624.0",
"@aws-sdk/client-pinpoint": "^3.624.0",
"@smithy/node-http-handler": "^4.1.0",
"chalk": "^4.1.1",
"fs-extra": "^8.1.0",
"lodash": "^4.17.21",
"ora": "^4.0.3",
"promise-sequential": "^1.1.1",
"proxy-agent": "^6.3.0"
},
"devDependencies": {
"aws-sdk-client-mock": "^4.1.0",
"aws-sdk-client-mock-jest": "^4.1.0"
},
"jest": {
"testEnvironmentOptions": {
"url": "http://localhost"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { $TSAny, $TSContext, AmplifyCategories, AmplifyFault, AmplifySupportedService, IContextPrint } from '@aws-amplify/amplify-cli-core';
import { prompter } from '@aws-amplify/amplify-prompts';
import { mockClient } from 'aws-sdk-client-mock';
import 'aws-sdk-client-mock-jest';
import { PinpointClient, UpdateApnsChannelCommand, UpdateApnsSandboxChannelCommand } from '@aws-sdk/client-pinpoint';
import * as configureKey from '../apns-key-config';
import * as configureCertificate from '../apns-cert-config';

Expand All @@ -14,6 +17,8 @@ jest.mock('../apns-cert-config');
jest.mock('@aws-amplify/amplify-prompts');
const prompterMock = prompter as jest.Mocked<typeof prompter>;

const mockPinpointClient = mockClient(PinpointClient);

class NoErrorThrownError extends Error {}
// wrapper to avoid conditional error checks
const getError = async <TError>(call: () => unknown): Promise<TError> => {
Expand Down Expand Up @@ -43,8 +48,20 @@ describe('channel-APNS', () => {
mockServiceOutput[channelName] = mockChannelOutput;

const mockPinpointResponseErr = new Error('channel-APNS.test.js error');
const mockPinpointResponseData = {
APNSChannelResponse: {},
const mockApnsChannelResponseData = {
APNSChannelResponse: {
Enabled: true,
ApplicationId: 'test-app-id',
Platform: 'APNS' as const,
},
};

const mockApnsSandboxChannelResponseData = {
APNSSandboxChannelResponse: {
Enabled: true,
ApplicationId: 'test-app-id',
Platform: 'APNS_SANDBOX' as const,
},
};

const mockAPNSChannelResponseData = (status: boolean, action: ChannelAction, output: $TSAny): IChannelAPIResponse => ({
Expand All @@ -64,49 +81,22 @@ describe('channel-APNS', () => {
const mockKeyConfig = {};
const mockCertificateConfig = {};

const mockPinpointClient = {
updateApnsChannel: jest.fn().mockReturnValue({
promise: jest.fn().mockResolvedValue(mockPinpointResponseData),
}),
updateApnsSandboxChannel: jest.fn().mockReturnValue({
promise: jest.fn().mockResolvedValue(mockPinpointResponseData),
}),
};

const mockPinpointClientReject = {
updateApnsChannel: jest.fn().mockReturnValue({
promise: jest.fn().mockRejectedValue(mockPinpointResponseErr),
}),
updateApnsSandboxChannel: jest.fn().mockReturnValue({
promise: jest.fn().mockRejectedValue(mockPinpointResponseErr),
}),
};

const mockContext: $TSContext = {
exeInfo: {
serviceMeta: {
output: mockServiceOutput,
},
pinpointClient: mockPinpointClient,
pinpointClient: mockPinpointClient as unknown as PinpointClient,
},
print: {
info: jest.fn(),
error: jest.fn(),
} as unknown as IContextPrint,
} as unknown as $TSContext;

const mockContextReject = {
exeInfo: {
serviceMeta: {
output: mockServiceOutput,
},
pinpointClient: mockPinpointClientReject,
},
print: {
info: jest.fn(),
error: jest.fn(),
},
};
beforeEach(() => {
mockPinpointClient.reset();
});

beforeAll(() => {
global.console = { ...global.console, log: jest.fn() };
Expand All @@ -118,69 +108,73 @@ describe('channel-APNS', () => {
});

test('configure', async () => {
mockPinpointClient.on(UpdateApnsChannelCommand).resolves(mockApnsChannelResponseData);
mockPinpointClient.on(UpdateApnsSandboxChannelCommand).resolves(mockApnsSandboxChannelResponseData);

mockChannelOutput.Enabled = true;
prompterMock.yesOrNo.mockResolvedValueOnce(true);
await channelAPNS.configure(mockContext).then(() => {
expect(mockPinpointClient.updateApnsChannel).toBeCalled();
});
await channelAPNS.configure(mockContext);
expect(mockPinpointClient).toHaveReceivedCommand(UpdateApnsChannelCommand);

mockChannelOutput.Enabled = true;
prompterMock.yesOrNo.mockResolvedValueOnce(false);
await channelAPNS.configure(mockContext).then(() => {
expect(mockPinpointClient.updateApnsChannel).toBeCalled();
});
prompterMock.pick.mockResolvedValueOnce('Certificate');
await channelAPNS.configure(mockContext);
expect(mockPinpointClient).toHaveReceivedCommand(UpdateApnsChannelCommand);

mockChannelOutput.Enabled = false;
prompterMock.yesOrNo.mockResolvedValueOnce(true);
prompterMock.pick.mockResolvedValueOnce('Certificate');
await channelAPNS.configure(mockContext).then(() => {
expect(mockPinpointClient.updateApnsChannel).toBeCalled();
});
await channelAPNS.configure(mockContext);
expect(mockPinpointClient).toHaveReceivedCommand(UpdateApnsChannelCommand);
});

test('enable', async () => {
prompterMock.pick.mockResolvedValueOnce('Certificate');
mockPinpointClient.on(UpdateApnsChannelCommand).resolves(mockApnsChannelResponseData);
mockPinpointClient.on(UpdateApnsSandboxChannelCommand).resolves(mockApnsSandboxChannelResponseData);

prompterMock.pick.mockResolvedValueOnce('Certificate');
const disableData = await channelAPNS.enable(mockContext, 'successMessage');
expect(mockPinpointClient.updateApnsChannel).toBeCalled();
expect(mockPinpointClient.updateApnsSandboxChannel).toBeCalled();
expect(disableData).toEqual(mockAPNSChannelResponseData(true, ChannelAction.ENABLE, mockPinpointResponseData.APNSChannelResponse));
expect(mockPinpointClient).toHaveReceivedCommand(UpdateApnsChannelCommand);
expect(mockPinpointClient).toHaveReceivedCommand(UpdateApnsSandboxChannelCommand);
expect(disableData).toEqual(mockAPNSChannelResponseData(true, ChannelAction.ENABLE, mockApnsChannelResponseData.APNSChannelResponse));

prompterMock.pick.mockResolvedValueOnce('Key');
const enableData = await channelAPNS.enable(mockContext, 'successMessage');
expect(mockPinpointClient.updateApnsChannel).toBeCalled();
expect(mockPinpointClient.updateApnsSandboxChannel).toBeCalled();
expect(enableData).toEqual(mockAPNSChannelResponseData(true, ChannelAction.ENABLE, mockPinpointResponseData.APNSChannelResponse));
expect(mockPinpointClient).toHaveReceivedCommand(UpdateApnsChannelCommand);
expect(mockPinpointClient).toHaveReceivedCommand(UpdateApnsSandboxChannelCommand);
expect(enableData).toEqual(mockAPNSChannelResponseData(true, ChannelAction.ENABLE, mockApnsChannelResponseData.APNSChannelResponse));
});

test('enable unsuccessful', async () => {
prompterMock.pick.mockResolvedValueOnce('Certificate');
mockPinpointClient.on(UpdateApnsChannelCommand).rejects(mockPinpointResponseErr);

const errCert: AmplifyFault = await getError(async () =>
channelAPNS.enable(mockContextReject as unknown as $TSContext, 'successMessage'),
);
expect(mockContextReject.exeInfo.pinpointClient.updateApnsChannel).toBeCalled();
prompterMock.pick.mockResolvedValueOnce('Certificate');
const errCert: AmplifyFault = await getError(async () => channelAPNS.enable(mockContext, 'successMessage'));
expect(mockPinpointClient).toHaveReceivedCommand(UpdateApnsChannelCommand);
expect(errCert?.downstreamException?.message).toContain(mockPinpointResponseErr.message);

prompterMock.pick.mockResolvedValueOnce('Key');
const errKey: AmplifyFault = await getError(async () =>
channelAPNS.enable(mockContextReject as unknown as $TSContext, 'successMessage'),
);
expect(mockPinpointClient.updateApnsChannel).toBeCalled();
const errKey: AmplifyFault = await getError(async () => channelAPNS.enable(mockContext, 'successMessage'));
expect(mockPinpointClient).toHaveReceivedCommand(UpdateApnsChannelCommand);
expect(errKey?.downstreamException?.message).toContain(mockPinpointResponseErr.message);
});

test('disable', async () => {
await channelAPNS.disable(mockContext).then((data) => {
expect(mockPinpointClient.updateApnsChannel).toBeCalled();
expect(mockPinpointClient.updateApnsSandboxChannel).toBeCalled();
expect(data).toEqual(mockAPNSChannelResponseData(true, ChannelAction.DISABLE, mockPinpointResponseData.APNSChannelResponse));
});
mockPinpointClient.on(UpdateApnsChannelCommand).resolves(mockApnsChannelResponseData);
mockPinpointClient.on(UpdateApnsSandboxChannelCommand).resolves(mockApnsSandboxChannelResponseData);

const data = await channelAPNS.disable(mockContext);
expect(mockPinpointClient).toHaveReceivedCommand(UpdateApnsChannelCommand);
expect(mockPinpointClient).toHaveReceivedCommand(UpdateApnsSandboxChannelCommand);
expect(data).toEqual(mockAPNSChannelResponseData(true, ChannelAction.DISABLE, mockApnsChannelResponseData.APNSChannelResponse));
});

test('disable unsuccessful', async () => {
const errKey: AmplifyFault = await getError(async () => channelAPNS.disable(mockContextReject as unknown as $TSContext));
expect(mockPinpointClient.updateApnsChannel).toBeCalled();
mockPinpointClient.on(UpdateApnsChannelCommand).rejects(mockPinpointResponseErr);

const errKey: AmplifyFault = await getError(async () => channelAPNS.disable(mockContext));
expect(mockPinpointClient).toHaveReceivedCommand(UpdateApnsChannelCommand);
expect(errKey?.downstreamException?.message).toContain(mockPinpointResponseErr.message);
});
});
Loading
Loading