1
1
/* eslint-disable spellcheck/spell-checker, camelcase, @typescript-eslint/no-explicit-any */
2
- import { CodeBuild } from 'aws-sdk' ;
2
+ import { CodeBuild , Account } from 'aws-sdk' ;
3
3
import { config } from 'dotenv' ;
4
4
import yargs from 'yargs' ;
5
5
import * as aws from 'aws-sdk' ;
@@ -8,29 +8,31 @@ import fs from 'fs-extra';
8
8
import path from 'path' ;
9
9
import { deleteS3Bucket , sleep } from '@aws-amplify/amplify-codegen-e2e-core' ;
10
10
11
- // Ensure to update scripts/split-e2e-tests.ts is also updated this gets updated
12
- const AWS_REGIONS_TO_RUN_TESTS = [
13
- 'ap-east-1' ,
14
- 'ap-northeast-1' ,
15
- 'ap-northeast-2' ,
16
- 'ap-northeast-3' ,
17
- 'ap-south-1' ,
18
- 'ap-southeast-1' ,
19
- 'ap-southeast-2' ,
20
- 'ca-central-1' ,
21
- 'eu-central-1' ,
22
- 'eu-north-1' ,
23
- 'eu-south-1' ,
24
- 'eu-west-1' ,
25
- 'eu-west-2' ,
26
- 'eu-west-3' ,
27
- 'me-south-1' ,
28
- 'sa-east-1' ,
29
- 'us-east-1' ,
30
- 'us-east-2' ,
31
- 'us-west-1' ,
32
- 'us-west-2' ,
33
- ] ;
11
+ /**
12
+ * Supported regions:
13
+ * - All Amplify regions, as reported https://docs.aws.amazon.com/general/latest/gr/amplify.html
14
+ *
15
+ * NOTE:
16
+ * - 'ap-east-1' is not included in the list due to known discrepancy in Amplify CLI 'configure' command dropdown and supported regions
17
+ * - Since 'ap-east-1' is not available via 'amplify configure', test $CLI_REGION with 'ap-east-1' will run in 'us-east-1'
18
+ * and fail Amplify profile assertion in test setup phase
19
+ *
20
+ * The list of supported regions must be kept in sync amongst all of:
21
+ * - Amplify CLI 'amplify configure' command regions dropdown
22
+ * - the internal pipeline that publishes new lambda layer versions
23
+ * - amplify-codegen/scripts/e2e-test-regions.json
24
+ * - amplify-codegen/scripts/split-canary-tests.ts
25
+ * - amplify-codegen/scripts/split-e2e-tests.ts
26
+ */
27
+ const REPO_ROOT = path . join ( __dirname , '..' , '..' , '..' ) ;
28
+ const SUPPORTED_REGIONS_PATH = path . join ( REPO_ROOT , 'scripts' , 'e2e-test-regions.json' ) ;
29
+ const AWS_REGIONS_TO_RUN_TESTS_METADATA : TestRegion [ ] = JSON . parse ( fs . readFileSync ( SUPPORTED_REGIONS_PATH , 'utf-8' ) ) ;
30
+ const AWS_REGIONS_TO_RUN_TESTS = AWS_REGIONS_TO_RUN_TESTS_METADATA . map ( region => region . name ) ;
31
+
32
+ type TestRegion = {
33
+ name : string ;
34
+ optIn : boolean ;
35
+ } ;
34
36
35
37
const reportPathDir = path . normalize ( path . join ( __dirname , '..' , 'amplify-e2e-reports' ) ) ;
36
38
@@ -97,7 +99,7 @@ type AWSAccountInfo = {
97
99
} ;
98
100
99
101
const BUCKET_TEST_REGEX = / t e s t / ;
100
- const IAM_TEST_REGEX = / ! R o t a t e E 2 e A w s T o k e n - e 2 e T e s t C o n t e x t R o l e | - i n t e g t e s t $ | ^ a m p l i f y - | ^ e u - | ^ u s - | ^ a p - / ;
102
+ const IAM_TEST_REGEX = / - R o t a t e E 2 e A w s T o k e n - e 2 e T e s t C o n t e x t R o l e | - i n t e g t e s t | ^ a m p l i f y - / ;
101
103
const STALE_DURATION_MS = 2 * 60 * 60 * 1000 ; // 2 hours in milliseconds
102
104
103
105
const isCI = ( ) : boolean => process . env . CI && process . env . CODEBUILD ? true : false ;
@@ -164,7 +166,23 @@ const getOrphanTestIamRoles = async (account: AWSAccountInfo): Promise<IamRoleIn
164
166
} ,
165
167
...( region ? { region } : { } ) ,
166
168
maxRetries : 10 ,
167
- } ) ;
169
+ } ) ;
170
+
171
+ /**
172
+ * Returns a list of regions enabled given the AWS account information
173
+ * @param accountInfo aws account to check region
174
+ * @returns Promise<string[]> a list of AWS regions enabled by the account
175
+ */
176
+ const getRegionsEnabled = async ( accountInfo : AWSAccountInfo ) : Promise < string [ ] > => {
177
+ // Specify service region to avoid possible endpoint unavailable error
178
+ const account = new Account ( { ...accountInfo , region : 'us-east-1' } ) ;
179
+ const response = await account . listRegions ( ) . promise ( ) ;
180
+ const enabledRegions = response . Regions . map ( r =>
181
+ r . RegionOptStatus === 'ENABLED' || r . RegionOptStatus === 'ENABLED_BY_DEFAULT' ? r . RegionName : null ,
182
+ ) . filter ( Boolean ) ;
183
+
184
+ return enabledRegions ;
185
+ } ;
168
186
169
187
/**
170
188
* Returns a list of Amplify Apps in the region. The apps includes information about the CI build that created the app
@@ -173,8 +191,14 @@ const getOrphanTestIamRoles = async (account: AWSAccountInfo): Promise<IamRoleIn
173
191
* @param region aws region to query for amplify Apps
174
192
* @returns Promise<AmplifyAppInfo[]> a list of Amplify Apps in the region with build info
175
193
*/
176
- const getAmplifyApps = async ( account : AWSAccountInfo , region : string ) : Promise < AmplifyAppInfo [ ] > => {
194
+ const getAmplifyApps = async ( account : AWSAccountInfo , region : string , regionsEnabled : string [ ] ) : Promise < AmplifyAppInfo [ ] > => {
177
195
const amplifyClient = new aws . Amplify ( getAWSConfig ( account , region ) ) ;
196
+
197
+ if ( ! regionsEnabled . includes ( region ) ) {
198
+ console . error ( `Listing apps for account ${ account . accountId } -${ region } failed since ${ region } is not enabled. Skipping.` ) ;
199
+ return [ ] ;
200
+ }
201
+
178
202
const amplifyApps = await amplifyClient . listApps ( { maxResults : 50 } ) . promise ( ) ; // keeping it to 50 as max supported is 50
179
203
const result : AmplifyAppInfo [ ] = [ ] ;
180
204
for ( const app of amplifyApps . apps ) {
@@ -244,8 +268,14 @@ const getStackDetails = async (stackName: string, account: AWSAccountInfo, regio
244
268
} ;
245
269
} ;
246
270
247
- const getStacks = async ( account : AWSAccountInfo , region : string ) : Promise < StackInfo [ ] > => {
271
+ const getStacks = async ( account : AWSAccountInfo , region : string , regionsEnabled : string [ ] ) : Promise < StackInfo [ ] > => {
248
272
const cfnClient = new aws . CloudFormation ( getAWSConfig ( account , region ) ) ;
273
+
274
+ if ( ! regionsEnabled . includes ( region ) ) {
275
+ console . error ( `Listing stacks for account ${ account . accountId } -${ region } failed since ${ region } is not enabled. Skipping.` ) ;
276
+ return [ ] ;
277
+ }
278
+
249
279
const stacks = await cfnClient
250
280
. listStacks ( {
251
281
StackStatusFilter : [
@@ -725,8 +755,10 @@ const getAccountsToCleanup = async (): Promise<AWSAccountInfo[]> => {
725
755
} ;
726
756
727
757
const cleanupAccount = async ( account : AWSAccountInfo , accountIndex : number , filterPredicate : JobFilterPredicate ) : Promise < void > => {
728
- const appPromises = AWS_REGIONS_TO_RUN_TESTS . map ( region => getAmplifyApps ( account , region ) ) ;
729
- const stackPromises = AWS_REGIONS_TO_RUN_TESTS . map ( region => getStacks ( account , region ) ) ;
758
+ const regionsEnabled = await getRegionsEnabled ( account ) ;
759
+
760
+ const appPromises = AWS_REGIONS_TO_RUN_TESTS . map ( region => getAmplifyApps ( account , region , regionsEnabled ) ) ;
761
+ const stackPromises = AWS_REGIONS_TO_RUN_TESTS . map ( region => getStacks ( account , region , regionsEnabled ) ) ;
730
762
const bucketPromise = getS3Buckets ( account ) ;
731
763
const orphanBucketPromise = getOrphanS3TestBuckets ( account ) ;
732
764
const orphanIamRolesPromise = getOrphanTestIamRoles ( account ) ;
0 commit comments