|
| 1 | +import { |
| 2 | + AmplifyClient, |
| 3 | + ListAppsCommand, |
| 4 | + CreateAppCommand, |
| 5 | + ListBackendEnvironmentsCommand, |
| 6 | + CreateBackendEnvironmentCommand, |
| 7 | +} from '@aws-sdk/client-amplify'; |
| 8 | + |
| 9 | +/** |
| 10 | + * Name of the placeholder Amplify Gen1 app that, when present in an account + |
| 11 | + * region, bypasses the Gen1 end-of-life gate during `amplify init`. |
| 12 | + */ |
| 13 | +export const GEN1_PLACEHOLDER_APP_NAME = 'DoNotDeleteAppToBypassGen1Deprecation'; |
| 14 | + |
| 15 | +/** |
| 16 | + * Backend environment name required on the placeholder app for the bypass to |
| 17 | + * take effect. |
| 18 | + */ |
| 19 | +export const GEN1_PLACEHOLDER_BACKEND_ENV_NAME = 'test'; |
| 20 | + |
| 21 | +const LIST_APPS_PAGE_SIZE = 100; |
| 22 | + |
| 23 | +/** |
| 24 | + * Ensures the Gen1 deprecation-bypass placeholder app (and its `test` backend |
| 25 | + * environment) exists in the given region so the Gen1 EOL gate never blocks |
| 26 | + * `amplify init` during e2e runs, self-healing any prior cleanup deletion. |
| 27 | + * |
| 28 | + * Idempotent: the app and backend environment are created only when missing. |
| 29 | + * Never throws — all failures are logged and swallowed so an already-healthy |
| 30 | + * run is never broken by this best-effort setup step. Relies on the ambient |
| 31 | + * e2e credentials picked up by the AWS SDK default provider chain. |
| 32 | + * |
| 33 | + * @param region target AWS region; defaults to `process.env.CLI_REGION`. |
| 34 | + */ |
| 35 | +export async function ensureGen1PlaceholderApp(region: string = process.env.CLI_REGION): Promise<void> { |
| 36 | + if (!region) { |
| 37 | + console.log('⚠️ ensureGen1PlaceholderApp: no region provided (CLI_REGION unset); skipping'); |
| 38 | + return; |
| 39 | + } |
| 40 | + |
| 41 | + try { |
| 42 | + const client = new AmplifyClient({ region }); |
| 43 | + |
| 44 | + let appId: string | undefined; |
| 45 | + let nextToken: string | undefined; |
| 46 | + do { |
| 47 | + const { apps, nextToken: token } = await client.send(new ListAppsCommand({ maxResults: LIST_APPS_PAGE_SIZE, nextToken })); |
| 48 | + const existing = (apps ?? []).find((app) => app.name === GEN1_PLACEHOLDER_APP_NAME); |
| 49 | + if (existing) { |
| 50 | + appId = existing.appId; |
| 51 | + break; |
| 52 | + } |
| 53 | + nextToken = token; |
| 54 | + } while (nextToken); |
| 55 | + |
| 56 | + if (!appId) { |
| 57 | + const { app } = await client.send(new CreateAppCommand({ name: GEN1_PLACEHOLDER_APP_NAME })); |
| 58 | + appId = app?.appId; |
| 59 | + console.log(`✅ ensureGen1PlaceholderApp: created placeholder app '${GEN1_PLACEHOLDER_APP_NAME}' (${appId}) in ${region}`); |
| 60 | + } |
| 61 | + |
| 62 | + if (!appId) { |
| 63 | + console.log(`⚠️ ensureGen1PlaceholderApp: could not resolve placeholder appId in ${region}; skipping backend env`); |
| 64 | + return; |
| 65 | + } |
| 66 | + |
| 67 | + const { backendEnvironments } = await client.send(new ListBackendEnvironmentsCommand({ appId })); |
| 68 | + const hasEnv = (backendEnvironments ?? []).some((env) => env.environmentName === GEN1_PLACEHOLDER_BACKEND_ENV_NAME); |
| 69 | + if (!hasEnv) { |
| 70 | + await client.send(new CreateBackendEnvironmentCommand({ appId, environmentName: GEN1_PLACEHOLDER_BACKEND_ENV_NAME })); |
| 71 | + console.log( |
| 72 | + `✅ ensureGen1PlaceholderApp: created backend env '${GEN1_PLACEHOLDER_BACKEND_ENV_NAME}' for placeholder app in ${region}`, |
| 73 | + ); |
| 74 | + } |
| 75 | + } catch (err) { |
| 76 | + console.log(`⚠️ ensureGen1PlaceholderApp: best-effort setup failed in ${region} (continuing): ${err?.message ?? err}`); |
| 77 | + } |
| 78 | +} |
0 commit comments