UNPKG

@aws-amplify/cli-internal

Version:
177 lines • 7.56 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.createUnifiedCategoryView = exports.cfnChangesetConsoleUrl = void 0; const client_cloudformation_1 = require("@aws-sdk/client-cloudformation"); const chalk_1 = __importDefault(require("chalk")); const amplify_cli_core_1 = require("@aws-amplify/amplify-cli-core"); const categories_1 = require("../../gen2-migration/_common/categories"); function colorResourceLine(symbol, line) { if (symbol === '+') return chalk_1.default.green(line); if (symbol === '-') return chalk_1.default.red(line); if (symbol === '~') return chalk_1.default.yellow(line); return line; } function getActionSymbol(action) { if (action === client_cloudformation_1.ChangeAction.Add) return '+'; if (action === client_cloudformation_1.ChangeAction.Remove) return '-'; return '~'; } function getCFDriftSymbol(status) { if (status === client_cloudformation_1.StackResourceDriftStatus.MODIFIED) return '~'; if (status === client_cloudformation_1.StackResourceDriftStatus.DELETED) return '-'; return '?'; } function regionFromArn(arn) { try { return (0, amplify_cli_core_1.parseArn)(arn).region || undefined; } catch (_a) { return undefined; } } function cfnDriftConsoleUrl(stackArn) { const region = regionFromArn(stackArn); if (!region) return undefined; return `https://${region}.console.aws.amazon.com/cloudformation/home?region=${region}#/stacks/drifts?stackId=${encodeURIComponent(stackArn)}`; } function cfnChangesetConsoleUrl(changeSetArn, stackArn) { const region = regionFromArn(changeSetArn); if (!region) return undefined; const encodedStackId = encodeURIComponent(stackArn || ''); const encodedChangeSetId = encodeURIComponent(changeSetArn); return `https://${region}.console.aws.amazon.com/cloudformation/home?region=${region}#/stacks/changesets/changes?stackId=${encodedStackId}&changeSetId=${encodedChangeSetId}`; } exports.cfnChangesetConsoleUrl = cfnChangesetConsoleUrl; function flattenTree(node, result = []) { result.push(node); for (const child of node.children) flattenTree(child, result); return result; } function collectDriftBlocks(phase1, phase2, phase3) { const blocks = []; for (const node of flattenTree(phase1.root)) { for (const drift of node.drifts) { blocks.push({ categoryName: node.category, logicalId: drift.LogicalResourceId || 'Unknown', type: 'cf', cfDrift: drift, driftDetectionId: node.driftDetectionId, }); } } if (!phase2.skipped && phase2.changes.length > 0) { const flattenChanges = (changes, fallbackCategory, fallbackChangeSetId, parentStackArn) => { for (const change of changes) { if (change.ResourceType === 'AWS::CloudFormation::Stack' && change.nestedChanges && change.nestedChanges.length > 0) { flattenChanges(change.nestedChanges, (0, categories_1.extractCategory)(change.LogicalResourceId), change.ChangeSetId || fallbackChangeSetId, change.PhysicalResourceId || parentStackArn); } else { const resourceCategory = (0, categories_1.extractCategory)(change.LogicalResourceId); blocks.push({ categoryName: resourceCategory !== 'Other' ? resourceCategory : fallbackCategory, logicalId: change.LogicalResourceId || 'Unknown', type: 'template', templateChange: change, changeSetId: change.ChangeSetId || fallbackChangeSetId, stackArn: parentStackArn, }); } } }; flattenChanges(phase2.changes, 'Other', phase2.changeSetId); } const localResources = [ ...(phase3.resourcesToBeCreated || []), ...(phase3.resourcesToBeUpdated || []), ...(phase3.resourcesToBeDeleted || []), ]; if (!phase3.skipped && localResources.length > 0) { const seenCategories = new Set(); for (const resource of localResources) { const categoryName = (0, categories_1.extractCategory)(resource.category || resource.service || 'Other'); if (!seenCategories.has(categoryName)) { seenCategories.add(categoryName); blocks.push({ categoryName, type: 'local' }); } } } return blocks; } function formatPropertyDiffs(differences) { let output = ''; for (const propDiff of differences) { output += ` Property: ${propDiff.PropertyPath}\n`; if (propDiff.ActualValue != null) { output += ` ${chalk_1.default.green(`Deployed: "${propDiff.ActualValue}"`)}\n`; } if (propDiff.ExpectedValue != null) { output += ` ${chalk_1.default.red(`Expected: "${propDiff.ExpectedValue}"`)}\n`; } } return output; } function formatBlock(block) { const header = block.logicalId ? `${block.categoryName.toUpperCase()} ${block.logicalId}` : block.categoryName.toUpperCase(); let output = chalk_1.default.bold(header) + '\n'; if (block.type === 'cf') { const drift = block.cfDrift; const symbol = getCFDriftSymbol(drift.StackResourceDriftStatus); const arn = drift.PhysicalResourceId || ''; output += ` CloudFormation Drift: Deployed resources do not match templates\n`; if (block.driftDetectionId) { const stackArn = drift.StackId || ''; const driftUrl = cfnDriftConsoleUrl(stackArn); output += ` Drift Id: ${driftUrl || block.driftDetectionId}\n`; } if (arn) { output += `\n ${arn}\n`; } output += ` ${colorResourceLine(symbol, `${symbol} ${drift.ResourceType || 'Unknown'}`)}\n`; if (drift.StackResourceDriftStatus === client_cloudformation_1.StackResourceDriftStatus.MODIFIED && drift.PropertyDifferences && drift.PropertyDifferences.length > 0) { output += formatPropertyDiffs(drift.PropertyDifferences); } } else if (block.type === 'template') { const change = block.templateChange; const symbol = getActionSymbol(change.Action); output += ` Template Drift: S3 and deployed templates differ\n`; if (block.changeSetId) { const changesetUrl = cfnChangesetConsoleUrl(block.changeSetId, block.stackArn); output += ` Changeset Id: ${changesetUrl || block.changeSetId}\n`; } output += ` ${colorResourceLine(symbol, `${symbol} ${change.ResourceType || 'Unknown'}`)}\n`; } else { output += ` Local Drift: Undeployed changes in this category\n`; } return output; } function createUnifiedCategoryView(phase1, phase2, phase3) { const blocks = collectDriftBlocks(phase1, phase2, phase3); if (blocks.length === 0) { return undefined; } let output = '\n'; for (const block of blocks) { output += formatBlock(block) + '\n'; } return output; } exports.createUnifiedCategoryView = createUnifiedCategoryView; //# sourceMappingURL=drift-formatter.js.map