Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export const getFunctionDefinition = (
funcDef.runtime = configuration?.Runtime;
const functionName = configuration?.FunctionName;
assert(functionName);
const functionRecordInMeta = Object.entries(meta.function).find(([_, value]) => value.output.Name === functionName);
const functionRecordInMeta = Object.entries(meta.function).find(([, value]) => value.output.Name === functionName);
assert(functionRecordInMeta);
funcDef.category = functionCategoryMap.get(functionRecordInMeta[0]) ?? 'function';
funcDef.resourceName = functionRecordInMeta[0];
Expand Down
2 changes: 1 addition & 1 deletion packages/amplify-gen2-codegen/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export type AuthLambdaTriggers = Record<AuthTriggerEvents, Lambda>;
export type AuthTriggerEvents = 'createAuthChallenge' | 'customMessage' | 'defineAuthChallenge' | 'postAuthentication' | 'postConfirmation' | 'preAuthentication' | 'preSignUp' | 'preTokenGeneration' | 'userMigration' | 'verifyAuthChallengeResponse';

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

// @public (undocumented)
export type CustomAttribute = {
Expand Down
1 change: 0 additions & 1 deletion packages/amplify-gen2-codegen/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ const createFileWriter = (path: string) => async (content: string) => fs.writeFi

export const createGen2Renderer = ({
outputDir,
appId,
backendEnvironmentName,
auth,
storage,
Expand Down
98 changes: 98 additions & 0 deletions packages/amplify-migration/src/command-handler.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import fs from 'node:fs/promises';
import { AmplifyClient, GetAppCommand } from '@aws-sdk/client-amplify';
import { updateAmplifyYmlFile } from './command-handlers';
import { pathManager } from '@aws-amplify/amplify-cli-core';

jest.mock('node:fs/promises', () => ({
access: jest.fn(),
readFile: jest.fn(),
writeFile: jest.fn(),
}));

jest.mock('@aws-amplify/amplify-cli-core');

jest.mock('@aws-sdk/client-amplify');

const GEN1_COMMAND = 'amplifyPush --simple';
const GEN2_COMMAND = 'npx ampx pipeline-deploy --branch $AWS_BRANCH --app-id $AWS_APP_ID';

describe('updateAmplifyYmlFile', () => {
const amplifyClient = new AmplifyClient();
const mockAppId = 'testAppId';
const amplifyYmlPath = '/mockRootDir/amplify.yml';
const mockBuildSpec = `version: 1
backend:
phases:
build:
commands:
- '# Execute Amplify CLI with the helper script'
- amplifyPush --simple
frontend:
phases:
preBuild:
commands:
- npm ci --cache .npm --prefer-offline
build:
commands:
- npm run build
artifacts:
baseDirectory: build
files:
- '**/*'
cache:
paths:
- .npm/**/*`;

beforeEach(() => {
jest.clearAllMocks();
(pathManager.findProjectRoot as jest.Mock).mockReturnValue('/mockRootDir');
});

it('should update amplify.yml file if it exists', async () => {
(fs.readFile as jest.Mock).mockResolvedValue(mockBuildSpec);

await updateAmplifyYmlFile(amplifyClient, mockAppId);

expect(fs.readFile).toHaveBeenCalledWith(amplifyYmlPath, 'utf-8');
expect(fs.writeFile).toHaveBeenCalledWith(amplifyYmlPath, mockBuildSpec.replace(new RegExp(GEN1_COMMAND, 'g'), GEN2_COMMAND), {
encoding: 'utf-8',
});
});

it('should create amplify.yml file with updated buildSpec if it does not exist', async () => {
(fs.readFile as jest.Mock).mockRejectedValue({ code: 'ENOENT' });
(AmplifyClient.prototype.send as jest.Mock).mockResolvedValue({
app: { buildSpec: mockBuildSpec },
});

await updateAmplifyYmlFile(amplifyClient, mockAppId);

expect(AmplifyClient.prototype.send).toHaveBeenCalledWith(expect.any(GetAppCommand));
expect(fs.writeFile).toHaveBeenCalledWith(amplifyYmlPath, mockBuildSpec.replace(new RegExp(GEN1_COMMAND, 'g'), GEN2_COMMAND), {
encoding: 'utf-8',
});
});

it('should throw an error if buildSpec is not found in the app', async () => {
(fs.readFile as jest.Mock).mockRejectedValue({ code: 'ENOENT' });
(AmplifyClient.prototype.send as jest.Mock).mockResolvedValue({
app: {},
});

await expect(updateAmplifyYmlFile(amplifyClient, mockAppId)).rejects.toThrow('buildSpec not found in the app');
});

it('should throw an error if app is not found', async () => {
(fs.readFile as jest.Mock).mockRejectedValue({ code: 'ENOENT' });
(AmplifyClient.prototype.send as jest.Mock).mockResolvedValue({});

await expect(updateAmplifyYmlFile(amplifyClient, mockAppId)).rejects.toThrow('App not found');
});

it('should throw the original error if it is not related to file not found', async () => {
const error = new Error('Some other error');
(fs.readFile as jest.Mock).mockRejectedValue(error);

await expect(updateAmplifyYmlFile(amplifyClient, mockAppId)).rejects.toThrow(error);
});
});
47 changes: 40 additions & 7 deletions packages/amplify-migration/src/command-handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { v4 as uuid } from 'uuid';
import { createGen2Renderer } from '@aws-amplify/amplify-gen2-codegen';

import { UsageData } from '@aws-amplify/cli-internal';
import { AmplifyClient, UpdateAppCommand } from '@aws-sdk/client-amplify';
import { AmplifyClient, UpdateAppCommand, GetAppCommand } from '@aws-sdk/client-amplify';
import { CloudFormationClient } from '@aws-sdk/client-cloudformation';
import { CognitoIdentityProviderClient, LambdaConfigType } from '@aws-sdk/client-cognito-identity-provider';
import { CognitoIdentityClient } from '@aws-sdk/client-cognito-identity';
Expand All @@ -21,7 +21,7 @@ import { BackendEnvironmentResolver } from './backend_environment_selector';
import { Analytics, AppAnalytics } from './analytics';
import { AppAuthDefinitionFetcher } from './app_auth_definition_fetcher';
import { AppStorageDefinitionFetcher } from './app_storage_definition_fetcher';
import { AmplifyCategories, IUsageData, stateManager } from '@aws-amplify/amplify-cli-core';
import { AmplifyCategories, IUsageData, stateManager, pathManager } from '@aws-amplify/amplify-cli-core';
import { AuthTriggerConnection } from '@aws-amplify/amplify-gen1-codegen-auth-adapter';
import { DataDefinitionFetcher } from './data_definition_fetcher';
import { AmplifyStackParser } from './amplify_stack_parser';
Expand All @@ -36,7 +36,6 @@ interface CodegenCommandParameters {
logger: AppContextLogger;
outputDirectory: string;
backendEnvironmentName: string | undefined;
appId: string;
dataDefinitionFetcher: DataDefinitionFetcher;
authDefinitionFetcher: AppAuthDefinitionFetcher;
storageDefinitionFetcher: AppStorageDefinitionFetcher;
Expand All @@ -46,6 +45,8 @@ interface CodegenCommandParameters {
const TEMP_GEN_2_OUTPUT_DIR = 'amplify-gen2';
const AMPLIFY_DIR = 'amplify';
const MIGRATION_DIR = '.amplify/migration';
const GEN1_COMMAND = 'amplifyPush --simple';
const GEN2_COMMAND = 'npx ampx pipeline-deploy --branch $AWS_BRANCH --app-id $AWS_APP_ID';

enum GEN2_AMPLIFY_GITIGNORE_FILES_OR_DIRS {
DOT_AMPLIFY = '.amplify',
Expand All @@ -57,7 +58,6 @@ enum GEN2_AMPLIFY_GITIGNORE_FILES_OR_DIRS {
const generateGen2Code = async ({
outputDirectory,
backendEnvironmentName,
appId,
authDefinitionFetcher,
dataDefinitionFetcher,
storageDefinitionFetcher,
Expand All @@ -66,7 +66,6 @@ const generateGen2Code = async ({
const fetchingAWSResourceDetails = ora('Fetching resource details from AWS').start();
const gen2RenderOptions = {
outputDir: outputDirectory,
appId: appId,
backendEnvironmentName: backendEnvironmentName,
auth: await authDefinitionFetcher.getDefinition(),
storage: await storageDefinitionFetcher.getDefinition(),
Expand Down Expand Up @@ -214,6 +213,39 @@ const unsupportedCategories = (): Map<string, string> => {
return unsupportedCategoriesList;
};

export async function updateAmplifyYmlFile(amplifyClient: AmplifyClient, appId: string) {
const rootDir = pathManager.findProjectRoot();
assert(rootDir);
const amplifyYmlPath = path.join(rootDir, 'amplify.yml');

try {
// Read the content of amplify.yml file if it exists
const amplifyYmlContent = await fs.readFile(amplifyYmlPath, 'utf-8');
Comment thread Fixed

await writeToAmplifyYmlFile(amplifyYmlPath, amplifyYmlContent);
} catch (error) {
if (error.code === 'ENOENT') {
// If amplify.yml file doesn't exist, make a getApp call to get buildSpec
const getAppResponse = await amplifyClient.send(new GetAppCommand({ appId }));

assert(getAppResponse.app, 'App not found');
const buildSpec = getAppResponse.app.buildSpec;
assert(buildSpec, 'buildSpec not found in the app');

await writeToAmplifyYmlFile(amplifyYmlPath, buildSpec);
} else {
// Throw the original error if it's not related to file not found
throw error;
}
}
}

async function writeToAmplifyYmlFile(amplifyYmlPath: string, content: string) {
// Replace 'amplifyPush --simple' with 'npx ampx pipeline-deploy'
content = content.replace(new RegExp(GEN1_COMMAND, 'g'), GEN2_COMMAND);
await fs.writeFile(amplifyYmlPath, content, { encoding: 'utf-8' });
}

async function updateGitIgnoreForGen2() {
const cwd = process.cwd();
const updateGitIgnore = ora('Updating gitignore contents').start();
Expand Down Expand Up @@ -287,14 +319,15 @@ export async function execute() {
() => getAuthTriggersConnections(),
ccbFetcher,
),
dataDefinitionFetcher: new DataDefinitionFetcher(backendEnvironmentResolver, amplifyStackParser),
dataDefinitionFetcher: new DataDefinitionFetcher(backendEnvironmentResolver, new BackendDownloader(s3Client), amplifyStackParser),
functionsDefinitionFetcher: new AppFunctionsDefinitionFetcher(lambdaClient, backendEnvironmentResolver, stateManager),
analytics: new AppAnalytics(appId),
logger: new AppContextLogger(appId),
backendEnvironmentName: backendEnvironment?.environmentName,
appId: appId,
});

await updateAmplifyYmlFile(amplifyClient, appId);

await updateGitIgnoreForGen2();

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