diff --git a/packages/amplify-provider-awscloudformation/src/__tests__/initializer.test.ts b/packages/amplify-provider-awscloudformation/src/__tests__/initializer.test.ts index 563b23501b8..e15cfb09226 100644 --- a/packages/amplify-provider-awscloudformation/src/__tests__/initializer.test.ts +++ b/packages/amplify-provider-awscloudformation/src/__tests__/initializer.test.ts @@ -21,6 +21,11 @@ describe('run', () => { it('transforms the root stack using the pre-push modifier', async () => { // setup const context_stub = { + pluginPlatform: { + plugins: { + core: [{ packageVersion: '5.2' }], + }, + }, exeInfo: { isNewEnv: true, projectConfig: { diff --git a/packages/amplify-provider-awscloudformation/src/initializer.ts b/packages/amplify-provider-awscloudformation/src/initializer.ts index 5c55d14104b..dcc02e4822a 100644 --- a/packages/amplify-provider-awscloudformation/src/initializer.ts +++ b/packages/amplify-provider-awscloudformation/src/initializer.ts @@ -2,6 +2,7 @@ import { $TSContext, FeatureFlags, Template, pathManager, PathConstants, stateMa import _ from 'lodash'; import { transformRootStack } from './override-manager'; import { rootStackFileName } from './push-resources'; +import { getDefaultTemplateDescription } from './template-description-utils'; const moment = require('moment'); const path = require('path'); @@ -56,10 +57,7 @@ export async function run(context) { await prePushCfnTemplateModifier(rootStack); - // Track Amplify Console generated stacks - if (!!process.env.CLI_DEV_INTERNAL_DISABLE_AMPLIFY_APP_DELETION) { - rootStack.Description = 'Root Stack for AWS Amplify Console'; - } + rootStack.Description = getDefaultTemplateDescription(context, 'root'); // deploy steps const params = { diff --git a/packages/amplify-provider-awscloudformation/src/push-resources.ts b/packages/amplify-provider-awscloudformation/src/push-resources.ts index 9323891fd6d..5090fd4f9c5 100644 --- a/packages/amplify-provider-awscloudformation/src/push-resources.ts +++ b/packages/amplify-provider-awscloudformation/src/push-resources.ts @@ -54,6 +54,7 @@ import { } from './disconnect-dependent-resources'; import { storeRootStackTemplate } from './initializer'; import { transformRootStack } from './override-manager'; +import { prePushTemplateDescriptionHandler } from './template-description-utils'; const logger = fileLogger('push-resources'); @@ -218,6 +219,7 @@ export async function run(context: $TSContext, resourceDefinition: $TSObject, re await prePushAuthTransform(context, resources); await prePushGraphQLCodegen(context, resourcesToBeCreated, resourcesToBeUpdated); const projectDetails = context.amplify.getProjectDetails(); + await prePushTemplateDescriptionHandler(context, resourcesToBeCreated); await updateS3Templates(context, resources, projectDetails.amplifyMeta); // We do not need CloudFormation update if only syncable resources are the changes. @@ -408,9 +410,7 @@ export async function run(context: $TSContext, resourceDefinition: $TSObject, re //check for auth resources and remove deployment secret for push resources - .filter( - resource => resource.category === 'auth' && resource.service === 'Cognito' && resource.providerPlugin === 'awscloudformation', - ) + .filter(resource => resource.category === 'auth' && resource.service === 'Cognito' && resource.providerPlugin === 'awscloudformation') .map(({ category, resourceName }) => context.amplify.removeDeploymentSecrets(context, category, resourceName)); await adminModelgen(context, resources); @@ -806,6 +806,7 @@ async function updateS3Templates(context: $TSContext, resourcesToBeUpdated: $TSA for (const cfnFile of cfnFiles) { await writeCustomPoliciesToCFNTemplate(resourceName, service, cfnFile, category); const transformedCFNPath = await preProcessCFNTemplate(path.join(resourceDir, cfnFile)); + promises.push(uploadTemplateToS3(context, transformedCFNPath, category, resourceName, amplifyMeta)); } } @@ -1211,4 +1212,3 @@ function rollbackLambdaLayers(layerResources: $TSAny[]) { stateManager.setMeta(projectRoot, meta); } } - diff --git a/packages/amplify-provider-awscloudformation/src/template-description-utils.ts b/packages/amplify-provider-awscloudformation/src/template-description-utils.ts new file mode 100644 index 00000000000..881897c1507 --- /dev/null +++ b/packages/amplify-provider-awscloudformation/src/template-description-utils.ts @@ -0,0 +1,98 @@ +import { $TSAny, $TSContext, readCFNTemplate, writeCFNTemplate } from 'amplify-cli-core'; +import * as os from 'os'; +import * as path from 'path'; +import { getCfnFiles } from './push-resources'; + +enum DeploymentTypes { + AMPLIFY_CLI = 'Amplify', + AMPLIFY_ADMIN = 'AmplifyAdmin', +} + +enum SupportedPlatforms { + WINDOWS = 'Windows', + MAC = 'Mac', + LINUX = 'Linux', + OTHER = 'Other', +} + +type TemplateDescription = { + createdOn: SupportedPlatforms; + createdBy: DeploymentTypes; + createdWith: string; + stackType: string; + metadata: object; +}; + +export async function prePushTemplateDescriptionHandler(context: $TSContext, resourcesToBeCreated: $TSAny) { + let promises = []; + + for (const { category, resourceName, service } of resourcesToBeCreated) { + const { resourceDir, cfnFiles } = getCfnFiles(category, resourceName); + for (const cfnFile of cfnFiles) { + const cfnFilePath = path.resolve(path.join(resourceDir, cfnFile)); + promises.push(await setDefaultTemplateDescription(context, category, resourceName, service, cfnFilePath)); + } + } + + await Promise.all(promises); +} + +export async function setDefaultTemplateDescription( + context: $TSContext, + category: string, + resourceName: string, + service: string, + cfnFilePath: string, +) { + const { templateFormat, cfnTemplate } = readCFNTemplate(cfnFilePath); + + cfnTemplate.Description = getDefaultTemplateDescription(context, category, service); + + await writeCFNTemplate(cfnTemplate, cfnFilePath, { templateFormat }); +} + +export function getDefaultTemplateDescription(context: $TSContext, category: string, service?: string): string { + let descriptionJson: TemplateDescription; + + // get platform "createdOn" + + let platformDescription: SupportedPlatforms; + let deploymentTypeDescription: DeploymentTypes; + let stackTypeDescription: string; + + const platform = os.platform(); + + if (platform == 'darwin') { + platformDescription = SupportedPlatforms.MAC; + } else if (platform == 'win32') { + platformDescription = SupportedPlatforms.WINDOWS; + } else if (platform == 'linux') { + platformDescription = SupportedPlatforms.LINUX; + } else { + platformDescription = SupportedPlatforms.OTHER; + } + + // get deployment mchanism "createdBy" + + if (!!process.env.CLI_DEV_INTERNAL_DISABLE_AMPLIFY_APP_DELETION) { + deploymentTypeDescription = DeploymentTypes.AMPLIFY_ADMIN; + } else { + deploymentTypeDescription = DeploymentTypes.AMPLIFY_CLI; + } + + // get CLI version number "createdWith" + const cliVersion = context.pluginPlatform.plugins.core[0].packageVersion; + + // get stack type "stackType" + stackTypeDescription = service ? `${category}-${service}` : category; + + descriptionJson = { + createdOn: platformDescription, + createdBy: deploymentTypeDescription, + createdWith: cliVersion, + stackType: stackTypeDescription, + metadata: {}, + }; + + return JSON.stringify(descriptionJson); +}