feat(gen2-migration): geo category for gen2-migration.#14712
Merged
iliapolo merged 76 commits intogen2-migrationfrom Mar 28, 2026
Merged
feat(gen2-migration): geo category for gen2-migration.#14712iliapolo merged 76 commits intogen2-migrationfrom
iliapolo merged 76 commits intogen2-migrationfrom
Conversation
Squash of all work on the migration-plan branch since diverging from gen2-migration. Includes the assess subcommand for migration readiness, the refactor command rebuild with category-specific forward/rollback refactorers, the generate-new infrastructure with Generator+Renderer pattern, unified validation model, SpinningLogger UX, and comprehensive unit tests. --- Prompt: squash all commits after the merge base with gen2-migration into one and commit
Add a noOpLogger() test helper that creates a real SpinningLogger in debug mode, then replace all `null as any` logger arguments across 8 refactor test files with it. This improves type safety without changing test behavior since the logger methods are never exercised in these tests. All 30 tests pass. --- Prompt: In the refactor test directory there are lot of null as any being used to pass a spinning logger instance - change it to actually create a proper logger instance.
Plan.validate() now captures the report field from ValidationResult and renders a "Failed Validations Report" section before the summary table. Each failed validation shows its description in red followed by the report text. Also trims the drift report in _validations.ts. --- Prompt: The report property in ValidationResult is currently not used at all. We should use to print the validation report in case the validation failed.
Replace description-JSON-based auth stack classification with resource-type detection. The new approach checks for the presence of an AWS::Cognito::UserPool resource instead of parsing the stack Description field, which is more reliable. Also rename fetchStackDescription to fetchStack and descriptionCache to stackCache for accuracy since the method returns the full Stack object. --- Prompt: commit what I did
…apping Split monolithic auth-forward/rollback/utils into separate files for Cognito and UserPoolGroups, enabling independent forward and rollback refactoring per auth sub-resource. Replace gen1LogicalIds map with abstract targetLogicalId() method on RollbackCategoryRefactorer, giving each subclass explicit control over logical ID resolution. Extract match() hook on ForwardCategoryRefactorer for type-matching customization. Thread DiscoveredResource through CategoryRefactorer base class so refactorers can use resource metadata (e.g. resourceName) for stack discovery instead of relying on shared utility functions. Minor fixes to migration app docs and sanitize script (trailing newline normalization). --- Prompt: commit what I have
…tize --- Prompt: I reset the changes. just commit.
Thread DiscoveredResource through all resource-backed planners so each operation carries the resource it belongs to. Plan.describe() now groups operations under resource headers using the format "<resourceName> (<category>/<service>)", matching the assessment display style. Ungrouped operations (scaffolding, validations) render as a flat list. Changes: - Add optional `resource` field to AmplifyMigrationOperation - Update Plan.describe() to group by resource label - Thread DiscoveredResource into all generate-side planners (Auth, ReferenceAuth, Data, S3, DynamoDB, RestApi, Function, AnalyticsKinesis) replacing separate resourceName params - Tag refactor-side operations via CategoryRefactorer and its forward/rollback subclasses (already had this.resource) - Update all affected test files with DiscoveredResource objects --- Prompt: in the gen2-migration, i want to make the plan describe itself by listing the description of each operation per resource.
Change label format to "category/resourceName (service)", add cyan color to group headers, remove indentation on grouped items, and add blank lines between groups for readability. --- Prompt: i've made changes
…ollback Group all operations under labeled sections — resource-backed ops use "Resource: category/name (service)", ungrouped ops fall under "Project". Descriptions rendered in gray for visual hierarchy. Add auth:Cognito-UserPool-Groups support in refactor assess and rollback using AuthUserPoolGroupsRollbackRefactorer. --- Prompt: I've made more changes. commit
Add NODE_OPTIONS="--max-old-space-size=8192" to the commit command example and instructions to delete the scratch commit message file after a successful commit. --- Prompt: add an instruction in AGENTS.md to delete the commit file after committing and always increase memory size to prevent lint failures
…plan Enrich the refactor plan output with changeset reports and formatted move tables so operators can review exactly what each operation will change before executing. Key changes: - Auth cognito: explicit client matching (GEN1_WEB_CLIENT ↔ GEN2_WEB_CLIENT, GEN1_NATIVE_APP_CLIENT ↔ GEN2_NATIVE_APP_CLIENT) replacing negation-based logic. Exported shared constants. - Auth user pool groups: extracted RESOURCE_TYPES constant, use USER_POOL_GROUP_TYPE consistently. - category-refactorer: added changeset preview via CreateChangeSetCommand/DescribeChangeSetCommand, made updateSource/updateTarget/buildMoveOperations/beforeMovePlan async, enriched plan descriptions with changeset reports and move tables. - forward/rollback-category-refactorer: updated to async signatures, added move table formatting to descriptions. - Removed validateSingleResourcePerCategory from refactor.ts. - Plan output now uses numbered steps and bold labels. - New files: changeset-report.ts, template-diff.ts, move-table.ts (formatting utilities). - Test stubs updated for new CFN commands. --- Prompt: I've made changes - commit what i've done. dont run tests or anything, just commit.
Use full JSON path (Target.Path) instead of just the top-level property name so duplicate property names like RoleMappings are distinguishable. Show before/after values on separate lines for readability. Use bgGray chalk headers for operation descriptions. Minor spacing tweaks in plan output and move table. --- Prompt: I've made more changes. Commit them. not tests.
…et no-changes detection Replace hand-rolled box-drawing move table with cli-table3 (CLITable) to match existing patterns. Fix changeset no-changes detection: a CREATE_COMPLETE changeset with an empty Changes list is the actual no-changes case, not a waiter failure. formatChangeSetReport now returns undefined when there are no changes. Remove debug 'bubu' suffix from cfn-output-resolver. --- Prompt: commit
…tor plan Move changeset creation into the validation lifecycle of updateSource/updateTarget operations. formatChangeSetReport returns undefined when no changes are detected. The validation checks report === undefined (valid) and surfaces the changeset report on failure. The describe output shows the report regardless. Removed unused chalk and formatTemplateDiff imports. --- Prompt: Commit. Don't run tests yet.
Add CreateChangeSetCommand/DescribeChangeSetCommand mocks to the CloudFormationMock framework and individual test files that call plan(). Update tests for API changes: renamed module paths (auth-forward → auth-cognito-forward), new abstract targetLogicalId method on RollbackCategoryRefactorer, async beforeMovePlan, updated error message format, and Cognito-UserPool-Groups now being supported. Remove dead auth-utils.test.ts for deleted module. All 376 gen2-migr
Improve category refactorer resilience for partial failure recovery and multi-stack auth scenarios: - Handle empty change-sets gracefully when source/target templates match deployed state (partial failure recovery) - Support reusing existing holding stacks in forward path for auth's two-gen1-stack-to-one-gen2-stack mapping - Consolidate rollback restore-from-holding into a single operation instead of three separate ops - Add logging before stack update/move/refactor operations - Improve plan step formatting (remove extra blank lines, add trailing newline to move table) - Use clearer descriptions for empty change-set validation --- Prompt: commit my changes
Move physicalResourceId onto MoveMapping so it is populated once during buildResourceMappings and carried through the entire refactor pipeline. This eliminates redundant fetchStackResources calls in buildMoveOperations and the separate physicalIds/types maps that were threaded to formatMoveTable. - buildResourceMappings is now async; forward fetches from gen1Env, rollback from gen2Branch. - buildBlueprint is now async to await buildResourceMappings. - Deleted move-table.ts; renderMappingTable is now a protected method on CategoryRefactorer accepting MoveMapping[]. --- Prompt: in category-refactorer - I want to add the physical resource id to MoveMapping. Also make formatMoveTable accept MoveMapping[] and remove the unnecessary maps being passed to it. Remove move-table.ts and put formatMoveTable into a protected method inside CategoryRefactorer. Rename formatMoveTable to renderMappingTable.
…fy error handling Move all non-mutating work out of execute/describe/validate callbacks so errors surface during planning before any mutations run. tryRefactorStack and tryUpdateStack now throw on failure instead of returning result objects, eliminating boilerplate checks at every call site. createChangeSetReport now cleans up its changeset via try/finally. Deleted unused legacy-custom-resource.ts and template-diff.ts. --- Prompt: hoist computation out of execute callbacks, make tryRefactorStack and tryUpdateStack throw on failure, createChangeSetReport should delete its changeset, remove legacy-custom-resource.ts and template-diff.ts.
Introduce a Cfn class that centralizes all CloudFormation operations (update, refactor, createChangeSet, findStack, deleteStack, renderChangeSet) behind a single client instance. Replace custom polling with SDK waiters (waitUntilStackUpdateComplete, waitUntilStackRefactorCreate/ ExecuteComplete, waitUntilStackDeleteComplete). Delete refactorer.ts (re-export of Planner), holding-stack.ts, cfn-stack-updater.ts, cfn-stack-refactor-updater.ts, changeset-report.ts, and snap.ts. Move getHoldingStackName and HOLDING_STACK_SUFFIX into CategoryRefactorer. Inline snapshot writing into cfn.ts. --- Prompt: consolidate 3 CFN operations into a Cfn class, replace custom polling with SDK waiters, remove refactorer.ts, holding-stack.ts, snap.ts, changeset-report.ts, inline snap into cfn.ts, remove resolveStackName, move ensureOutputDirectory to constructor.
Cfn now accepts a SpinningLogger and logs info messages before every wait operation (stack update, refactor create/execute, source/destination verification, stack deletion). --- Prompt: the cfn class should accept the spinning logger and log info whenever it is waiting on something.
Split rollback holding stack update into its own operation with a validation that the changeset only adds the placeholder. Split forward holding stack deletion into a separate operation. Remove redundant fetchStackResources calls by deriving physical IDs from blueprint mappings. Move description/header construction into describe callbacks and ResourceMapping construction into execute callbacks. Add Cfn.fetchTemplate method. Remove unused imports. --- Prompt: split holding stack operations, add validation, remove redundant fetches, move descriptions into describe callbacks, add Cfn.fetchTemplate.
Add stack-level deduplication to prevent duplicate updates when multiple refactorers target the same stack. Thread targetStackId through buildResourceMappings for better error messages. Rework forward beforeMove to incrementally build holding stack templates by fetching existing state. In rollback, defer template computation into the execute closure and add duplicate-resource detection. Remove non-null assertions on StackResource fields. --- Prompt: commit everything I did. don't run tests.
… noop handling Add resource-scoped log prefixes to Cfn operations so each category/resource pair is identifiable in output. Remove StackFacade caching layer so every call fetches fresh state from CloudFormation. Introduce buildNoopOperation and suppress the Implications section when all operations are no-ops. In rollback, skip resources that already exist in the target stack instead of throwing. Reduce max wait time from 3600s to 900s and pre-check destination stack existence to select the correct waiter. --- Prompt: commit everything I did. Don't run tests. just commit.
…actor workflow RefactorBlueprint now carries only mappings and stack IDs. Templates are fetched and resolved fresh inside each operation's execute() closure, so sequential refactorers targeting the same stack always see current state. This fixes the stale template bug where the second auth refactorer (user-pool-groups) would operate on a Gen2 template that the first refactorer (cognito) had already mutated. updateSource/updateTarget use plan-time resolved stacks directly (still fresh since they run before any moves). updateSource now accepts mappings to determine if a placeholder is needed. move(), beforeMove() (forward), and afterMove() (rollback) all re-fetch and re-resolve templates at execution time. --- Prompt: defer template resolution to execution time in refactor workflow to fix stale template bug when two Gen1 stacks map to the same Gen2 stack.
…and use SDK ResourceMapping Cfn.refactor() now accepts ResourceMapping[] directly, fetches both stack templates, moves resources between them, and handles the full refactor lifecycle internally. This eliminates template manipulation from callers entirely. Replace custom MoveMapping with the SDK's ResourceMapping type throughout the workflow. Simplify move(), beforeMove() (forward), and afterMove() (rollback) to just pass resource mappings. Remove fetchHoldingStackTemplate, isPlaceholderOnlyChangeSet, and the holding stack changeset validation. Move placeholder logic into addPlaceHolderIfNeeded() at the top of plan(). Fix symmetricDifference check to compare .size === 0. --- Prompt: Read what i've done and commit it.
Update flowcharts and plan() lifecycle to reflect that beforeMove and afterMove now independently discover resources from stack templates rather than using blueprint mappings. --- Prompt: run the PR stage from AGENTS.md.
Add tests for multiple matching targets, empty source, resource already in target (rollback skip), and empty rollback source. Remove unused CFNResource import from category-refactorer test. --- Prompt: add missing buildResourceMappings tests.
…torers Add targetLogicalId tests for auth-cognito-rollback, auth-user-pool-groups-rollback, storage-rollback, storage-dynamo-rollback, and analytics-rollback. Add GroupName-based match tests for auth-user-pool-groups-forward. Add forward edge case tests for duplicate targets and ambiguous same-type matching. Fix bare throw in auth-cognito-rollback to use AmplifyError. Remove unused AmplifyError import from storage-dynamo-rollback. --- Prompt: add targetLogicalId and match tests for all refactorers, fix bare throw.
Add Resource Mapping section to refactor.md explaining forward type-based matching with usedTargetIds dedup, rollback targetLogicalId-based mapping, and all error conditions. --- Prompt: explain happy and unhappy paths of building resource mappings in refactor.md.
…foreMove beforeMove now checks the holding stack template before building resource mappings. Resources that already exist in the holding stack are skipped to handle re-execution of forward after a partial failure. Fix test mock to return empty template for REVIEW_IN_PROGRESS holding stacks. --- Prompt: fix REVIEW_IN_PROGRESS holding stack test failure.
…holder remains After moving resources out of the holding stack during rollback, check if only the migration placeholder resource remains. If so, delete the holding stack. This cleanup happens at execution time since each refactorer moves its own resources independently. --- Prompt: commit what I did.
…uth' into sai/geo-category-gen2-migration
Three test files were broken after merging the gen2-migration branch: - category-refactorer.test.ts: fetchSourceStackId now uses 'storage' + resourceName as the prefix. Changed resourceName from 'test' to 'avatars' to match the mock's 'storageavatars' logical ID. - backend.generator.test.ts: Removed ensureStorageStack tests since that method was replaced by createDynamoDBStack (which already has its own tests). - dynamodb.generator.test.ts: Constructor now takes a DiscoveredResource instead of a string. Updated two call sites to pass full DiscoveredResource objects. All 125 test suites (716 tests) pass. --- Prompt: I merged code from the gen2-migration branch and now some cli package tests are failing. run and fix.
…uth' into sai/geo-category-gen2-migration
Update pre-generate input and regenerate post-generate snapshots to match current codegen output. Changes include environment variable ordering in auth resource, geo resource import ordering, amplify.yml build commands, and package.json metadata. --- Prompt: commit this
GeofenceCollection resources use Custom::LambdaCallout which cannot be moved via CloudFormation StackRefactor. Mark them as unsupported in assess and throw in forward/rollback. --- Prompt: mark geofence collection as unsupported for refactor and throw error
Regenerate lockfile after store-locator pre-generate package.json dependency changes. --- Prompt: fix yarn.lock CI failure
iliapolo
approved these changes
Mar 28, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description of changes
Adds geo category support to the gen2-migration tooling: gen2 code generation, sample app, frontend simulation test scripts, and snapshot tests.
Generate step (codegen)
amplify/geo/directory with per-resource CDK constructs for Map, PlaceIndex, and GeofenceCollectiongeoprefix (e.g.,geostoreLocatorGeofence) matching Gen1 Amplify Console naminggeo/resource.tsaggregator wires all geo resources intobackend.addOutput()with maps, search indices, and geofence collections configRefactor step
Custom::LambdaCalloutwhich CloudFormation StackRefactor does not support. Marked as unsupported inassess()and throws a clear error inforward()/rollback()Frontend simulation test scripts
gen1-test-script.ts,gen2-test-script.ts, andtest-utils.tsfor the store-locator app@aws-amplify/geoAPIsstoreLocatorAdmingroup viaAdminAddUserToGroupCommandafter provisioning sinceAdminCreateUserdoes not trigger the PostConfirmation Lambdaamplify_outputs.jsonschema to the Gen1AmplifyConfiginterface forprovisionTestUsercompatibility"type": "module"to_test-common/package.jsonto fix ESM re-export resolution across all migration appsAdminAddUserToGroupCommanddirectly to grant group permissions instead. Testing the Lambda would require switching fromAdminCreateUserto theSignUp/ConfirmSignUpflow, which diverges from the sharedprovisionTestUserpattern used by all other apps. For comparison, media-vault's Lambda functions (addUserToGroup,removeUserFromGroup) are exposed as GraphQL resolvers callable from the frontend, so its test script can invoke them directly. Store-locator's Lambda is only invoked internally by Cognito during the self-signup confirmation flow.createMap()from maplibre-gl-js-amplify) is not tested because it requires a DOM container and WebGL context which are unavailable in Node. The map resource is implicitly validated by the search and geofence tests succeeding, since they all share the same auth/identity pool configuration.Migration app
Snapshot tests
Issue #, if available
Builds on #14596 (geo codegen) and #14637 (store-locator app).
Resolves #14539
Description of how you validated changes
npx jest --testPathPattern='generate.test.ts' --testNamePattern='store-locator'passesamplify gen2-migration refactor --to <gen2-stack>against deployed store-locator app — confirmed GeofenceCollection throws the expected unsupported error, blocking the refactor.npx tsx gen1-test-script.tsinamplify-migration-apps/store-locator/— all 6 tests pass (searchByText, searchByCoordinates, saveGeofences, getGeofence, listGeofences, deleteGeofences)npx tsx gen2-test-script.tsinamplify-migration-apps/store-locator/— all 6 tests pass against Gen2 backendChecklist
yarn testpassesBy submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.