Skip to content

Commit d4ba56a

Browse files
authored
Merge pull request #14136 from bzsurbhi/migrations
fix: update amplify.yml file with the gen2 command
2 parents 416d561 + 419d7ca commit d4ba56a

7 files changed

Lines changed: 344 additions & 194 deletions

File tree

packages/amplify-gen1-codegen-function-adapter/src/function_render_adapter.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export const getFunctionDefinition = (
2929
funcDef.runtime = configuration?.Runtime;
3030
const functionName = configuration?.FunctionName;
3131
assert(functionName);
32-
const functionRecordInMeta = Object.entries(meta.function).find(([_, value]) => value.output.Name === functionName);
32+
const functionRecordInMeta = Object.entries(meta.function).find(([, value]) => value.output.Name === functionName);
3333
assert(functionRecordInMeta);
3434
funcDef.category = functionCategoryMap.get(functionRecordInMeta[0]) ?? 'function';
3535
funcDef.resourceName = functionRecordInMeta[0];

packages/amplify-gen2-codegen/API.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ export type AuthLambdaTriggers = Record<AuthTriggerEvents, Lambda>;
6464
export type AuthTriggerEvents = 'createAuthChallenge' | 'customMessage' | 'defineAuthChallenge' | 'postAuthentication' | 'postConfirmation' | 'preAuthentication' | 'preSignUp' | 'preTokenGeneration' | 'userMigration' | 'verifyAuthChallengeResponse';
6565

6666
// @public (undocumented)
67-
export const createGen2Renderer: ({ outputDir, appId, backendEnvironmentName, auth, storage, data, functions, unsupportedCategories, fileWriter, }: Readonly<Gen2RenderingOptions>) => Renderer;
67+
export const createGen2Renderer: ({ outputDir, backendEnvironmentName, auth, storage, data, functions, unsupportedCategories, fileWriter, }: Readonly<Gen2RenderingOptions>) => Renderer;
6868

6969
// @public (undocumented)
7070
export type CustomAttribute = {

packages/amplify-gen2-codegen/src/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@ const createFileWriter = (path: string) => async (content: string) => fs.writeFi
6363

6464
export const createGen2Renderer = ({
6565
outputDir,
66-
appId,
6766
backendEnvironmentName,
6867
auth,
6968
storage,
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
import fs from 'node:fs/promises';
2+
import { AmplifyClient, GetAppCommand } from '@aws-sdk/client-amplify';
3+
import { updateAmplifyYmlFile } from './command-handlers';
4+
import { pathManager } from '@aws-amplify/amplify-cli-core';
5+
6+
jest.mock('node:fs/promises', () => ({
7+
access: jest.fn(),
8+
readFile: jest.fn(),
9+
writeFile: jest.fn(),
10+
}));
11+
12+
jest.mock('@aws-amplify/amplify-cli-core');
13+
14+
jest.mock('@aws-sdk/client-amplify');
15+
16+
const GEN1_COMMAND = 'amplifyPush --simple';
17+
const GEN2_COMMAND = 'npx ampx pipeline-deploy --branch $AWS_BRANCH --app-id $AWS_APP_ID';
18+
19+
describe('updateAmplifyYmlFile', () => {
20+
const amplifyClient = new AmplifyClient();
21+
const mockAppId = 'testAppId';
22+
const amplifyYmlPath = '/mockRootDir/amplify.yml';
23+
const mockBuildSpec = `version: 1
24+
backend:
25+
phases:
26+
build:
27+
commands:
28+
- '# Execute Amplify CLI with the helper script'
29+
- amplifyPush --simple
30+
frontend:
31+
phases:
32+
preBuild:
33+
commands:
34+
- npm ci --cache .npm --prefer-offline
35+
build:
36+
commands:
37+
- npm run build
38+
artifacts:
39+
baseDirectory: build
40+
files:
41+
- '**/*'
42+
cache:
43+
paths:
44+
- .npm/**/*`;
45+
46+
beforeEach(() => {
47+
jest.clearAllMocks();
48+
(pathManager.findProjectRoot as jest.Mock).mockReturnValue('/mockRootDir');
49+
});
50+
51+
it('should update amplify.yml file if it exists', async () => {
52+
(fs.readFile as jest.Mock).mockResolvedValue(mockBuildSpec);
53+
54+
await updateAmplifyYmlFile(amplifyClient, mockAppId);
55+
56+
expect(fs.readFile).toHaveBeenCalledWith(amplifyYmlPath, 'utf-8');
57+
expect(fs.writeFile).toHaveBeenCalledWith(amplifyYmlPath, mockBuildSpec.replace(new RegExp(GEN1_COMMAND, 'g'), GEN2_COMMAND), {
58+
encoding: 'utf-8',
59+
});
60+
});
61+
62+
it('should create amplify.yml file with updated buildSpec if it does not exist', async () => {
63+
(fs.readFile as jest.Mock).mockRejectedValue({ code: 'ENOENT' });
64+
(AmplifyClient.prototype.send as jest.Mock).mockResolvedValue({
65+
app: { buildSpec: mockBuildSpec },
66+
});
67+
68+
await updateAmplifyYmlFile(amplifyClient, mockAppId);
69+
70+
expect(AmplifyClient.prototype.send).toHaveBeenCalledWith(expect.any(GetAppCommand));
71+
expect(fs.writeFile).toHaveBeenCalledWith(amplifyYmlPath, mockBuildSpec.replace(new RegExp(GEN1_COMMAND, 'g'), GEN2_COMMAND), {
72+
encoding: 'utf-8',
73+
});
74+
});
75+
76+
it('should throw an error if buildSpec is not found in the app', async () => {
77+
(fs.readFile as jest.Mock).mockRejectedValue({ code: 'ENOENT' });
78+
(AmplifyClient.prototype.send as jest.Mock).mockResolvedValue({
79+
app: {},
80+
});
81+
82+
await expect(updateAmplifyYmlFile(amplifyClient, mockAppId)).rejects.toThrow('buildSpec not found in the app');
83+
});
84+
85+
it('should throw an error if app is not found', async () => {
86+
(fs.readFile as jest.Mock).mockRejectedValue({ code: 'ENOENT' });
87+
(AmplifyClient.prototype.send as jest.Mock).mockResolvedValue({});
88+
89+
await expect(updateAmplifyYmlFile(amplifyClient, mockAppId)).rejects.toThrow('App not found');
90+
});
91+
92+
it('should throw the original error if it is not related to file not found', async () => {
93+
const error = new Error('Some other error');
94+
(fs.readFile as jest.Mock).mockRejectedValue(error);
95+
96+
await expect(updateAmplifyYmlFile(amplifyClient, mockAppId)).rejects.toThrow(error);
97+
});
98+
});

packages/amplify-migration/src/command-handlers.ts

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { v4 as uuid } from 'uuid';
77
import { createGen2Renderer } from '@aws-amplify/amplify-gen2-codegen';
88

99
import { UsageData } from '@aws-amplify/cli-internal';
10-
import { AmplifyClient, UpdateAppCommand } from '@aws-sdk/client-amplify';
10+
import { AmplifyClient, UpdateAppCommand, GetAppCommand } from '@aws-sdk/client-amplify';
1111
import { CloudFormationClient } from '@aws-sdk/client-cloudformation';
1212
import { CognitoIdentityProviderClient, LambdaConfigType } from '@aws-sdk/client-cognito-identity-provider';
1313
import { CognitoIdentityClient } from '@aws-sdk/client-cognito-identity';
@@ -21,7 +21,7 @@ import { BackendEnvironmentResolver } from './backend_environment_selector';
2121
import { Analytics, AppAnalytics } from './analytics';
2222
import { AppAuthDefinitionFetcher } from './app_auth_definition_fetcher';
2323
import { AppStorageDefinitionFetcher } from './app_storage_definition_fetcher';
24-
import { AmplifyCategories, IUsageData, stateManager } from '@aws-amplify/amplify-cli-core';
24+
import { AmplifyCategories, IUsageData, stateManager, pathManager } from '@aws-amplify/amplify-cli-core';
2525
import { AuthTriggerConnection } from '@aws-amplify/amplify-gen1-codegen-auth-adapter';
2626
import { DataDefinitionFetcher } from './data_definition_fetcher';
2727
import { AmplifyStackParser } from './amplify_stack_parser';
@@ -36,7 +36,6 @@ interface CodegenCommandParameters {
3636
logger: AppContextLogger;
3737
outputDirectory: string;
3838
backendEnvironmentName: string | undefined;
39-
appId: string;
4039
dataDefinitionFetcher: DataDefinitionFetcher;
4140
authDefinitionFetcher: AppAuthDefinitionFetcher;
4241
storageDefinitionFetcher: AppStorageDefinitionFetcher;
@@ -46,6 +45,8 @@ interface CodegenCommandParameters {
4645
const TEMP_GEN_2_OUTPUT_DIR = 'amplify-gen2';
4746
const AMPLIFY_DIR = 'amplify';
4847
const MIGRATION_DIR = '.amplify/migration';
48+
const GEN1_COMMAND = 'amplifyPush --simple';
49+
const GEN2_COMMAND = 'npx ampx pipeline-deploy --branch $AWS_BRANCH --app-id $AWS_APP_ID';
4950

5051
enum GEN2_AMPLIFY_GITIGNORE_FILES_OR_DIRS {
5152
DOT_AMPLIFY = '.amplify',
@@ -57,7 +58,6 @@ enum GEN2_AMPLIFY_GITIGNORE_FILES_OR_DIRS {
5758
const generateGen2Code = async ({
5859
outputDirectory,
5960
backendEnvironmentName,
60-
appId,
6161
authDefinitionFetcher,
6262
dataDefinitionFetcher,
6363
storageDefinitionFetcher,
@@ -66,7 +66,6 @@ const generateGen2Code = async ({
6666
const fetchingAWSResourceDetails = ora('Fetching resource details from AWS').start();
6767
const gen2RenderOptions = {
6868
outputDir: outputDirectory,
69-
appId: appId,
7069
backendEnvironmentName: backendEnvironmentName,
7170
auth: await authDefinitionFetcher.getDefinition(),
7271
storage: await storageDefinitionFetcher.getDefinition(),
@@ -214,6 +213,39 @@ const unsupportedCategories = (): Map<string, string> => {
214213
return unsupportedCategoriesList;
215214
};
216215

216+
export async function updateAmplifyYmlFile(amplifyClient: AmplifyClient, appId: string) {
217+
const rootDir = pathManager.findProjectRoot();
218+
assert(rootDir);
219+
const amplifyYmlPath = path.join(rootDir, 'amplify.yml');
220+
221+
try {
222+
// Read the content of amplify.yml file if it exists
223+
const amplifyYmlContent = await fs.readFile(amplifyYmlPath, 'utf-8');
224+
225+
await writeToAmplifyYmlFile(amplifyYmlPath, amplifyYmlContent);
226+
} catch (error) {
227+
if (error.code === 'ENOENT') {
228+
// If amplify.yml file doesn't exist, make a getApp call to get buildSpec
229+
const getAppResponse = await amplifyClient.send(new GetAppCommand({ appId }));
230+
231+
assert(getAppResponse.app, 'App not found');
232+
const buildSpec = getAppResponse.app.buildSpec;
233+
assert(buildSpec, 'buildSpec not found in the app');
234+
235+
await writeToAmplifyYmlFile(amplifyYmlPath, buildSpec);
236+
} else {
237+
// Throw the original error if it's not related to file not found
238+
throw error;
239+
}
240+
}
241+
}
242+
243+
async function writeToAmplifyYmlFile(amplifyYmlPath: string, content: string) {
244+
// Replace 'amplifyPush --simple' with 'npx ampx pipeline-deploy'
245+
content = content.replace(new RegExp(GEN1_COMMAND, 'g'), GEN2_COMMAND);
246+
await fs.writeFile(amplifyYmlPath, content, { encoding: 'utf-8' });
247+
}
248+
217249
async function updateGitIgnoreForGen2() {
218250
const cwd = process.cwd();
219251
const updateGitIgnore = ora('Updating gitignore contents').start();
@@ -287,14 +319,15 @@ export async function execute() {
287319
() => getAuthTriggersConnections(),
288320
ccbFetcher,
289321
),
290-
dataDefinitionFetcher: new DataDefinitionFetcher(backendEnvironmentResolver, amplifyStackParser),
322+
dataDefinitionFetcher: new DataDefinitionFetcher(backendEnvironmentResolver, new BackendDownloader(s3Client), amplifyStackParser),
291323
functionsDefinitionFetcher: new AppFunctionsDefinitionFetcher(lambdaClient, backendEnvironmentResolver, stateManager),
292324
analytics: new AppAnalytics(appId),
293325
logger: new AppContextLogger(appId),
294326
backendEnvironmentName: backendEnvironment?.environmentName,
295-
appId: appId,
296327
});
297328

329+
await updateAmplifyYmlFile(amplifyClient, appId);
330+
298331
await updateGitIgnoreForGen2();
299332

300333
const movingGen1BackendFiles = ora(`Moving your Gen1 backend files to ${format.highlight(MIGRATION_DIR)}`).start();

0 commit comments

Comments
 (0)