Skip to content

Commit

Permalink
Init configure dx changes (#6948)
Browse files Browse the repository at this point in the history
* Init configure dx changes (#6907)
  • Loading branch information
nikhname authored Mar 26, 2021
1 parent 27030ea commit eeb3102
Show file tree
Hide file tree
Showing 24 changed files with 364 additions and 55 deletions.
2 changes: 2 additions & 0 deletions .circleci/amplify_init.exp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ set repo [lindex $argv 0];
spawn ./.circleci/amplify_init.sh $repo
expect "Enter a name for the project"
send -- "unauth\r"
expect "Initialize the project with the above configuration?"
send -- "n\r"
expect "Enter a name for the environment"
send -- "integtest\r"
expect -exact "Choose your default editor:"
Expand Down
3 changes: 3 additions & 0 deletions packages/amplify-cli/src/__tests__/commands/init.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ describe('amplify init: ', () => {
},
parameters: {
options: {},
command: 'env', // to avoid default dx flow
},
usageData: {
emitError: jest.fn(),
Expand All @@ -55,6 +56,8 @@ describe('amplify init: ', () => {
print: {
warning: jest.fn(),
error: jest.fn(),
info: jest.fn(),
success: jest.fn(),
},
migrationInfo: jest.fn(),
projectHasMobileHubResources: jest.fn(),
Expand Down
71 changes: 70 additions & 1 deletion packages/amplify-cli/src/config-steps/c0-analyzeProject.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import * as path from 'path';
import inquirer, { InputQuestion } from 'inquirer';
import inquirer, { ListQuestion, InputQuestion } from 'inquirer';
import { normalizeEditor, editorSelection } from '../extensions/amplify-helpers/editor-selection';
import { isProjectNameValid, normalizeProjectName } from '../extensions/amplify-helpers/project-name-validation';
import { getEnvInfo } from '../extensions/amplify-helpers/get-env-info';
import { displayConfigurationDefaults } from '../init-steps/s0-analyzeProject';
import { getFrontendPlugins } from '../extensions/amplify-helpers/get-frontend-plugins';
import { isContainersEnabled } from '../execution-manager';
import { stateManager } from 'amplify-cli-core';

export async function analyzeProject(context) {
Expand All @@ -15,12 +18,78 @@ export async function analyzeProject(context) {
const projectPath = process.cwd();
Object.assign(context.exeInfo.localEnvInfo, { projectPath });

let { projectName } = context.exeInfo.projectConfig;
const { defaultEditor, envName } = context.exeInfo.localEnvInfo;

context.print.info('');
await displayConfigurationDefaults(context, projectName, envName, defaultEditor);

const frontendPlugins = getFrontendPlugins(context);
let frontend = context.exeInfo.projectConfig.frontend;
if (!frontend) {
frontend = 'javascript';
}
const frontendModule = require(frontendPlugins[frontend]);
await frontendModule.displayFrontendDefaults(context, projectPath);
context.print.info('');

const envAwsInfo = stateManager.getLocalAWSInfo();
if (typeof envAwsInfo?.[envName] === 'object') {
const awsInfo = envAwsInfo[envName];
if (awsInfo.useProfile && awsInfo.profileName) {
await displayProfileSetting(context, awsInfo['profileName']);
context.print.info('');
}
}

await displayContainersInfo(context);
context.print.info('');

const configurationSetting = await getConfigurationSetting();

if (configurationSetting === 'containers') {
context.exeInfo.inputParams.yes = true;
context.exeInfo.inputParams.containerSetting = true;
}
if (configurationSetting === 'profile') {
context.exeInfo.inputParams.yes = true;
context.exeInfo.inputParams.profileSetting = true;
}

await configureProjectName(context);
await configureEditor(context);

return context;
}

function displayProfileSetting(context, profileName) {
context.print.info('AWS Profile setting');
context.print.info(`| Selected profile: ${profileName}`);
}

function displayContainersInfo(context) {
context.print.info('Advanced: Container-based deployments');
const containerDeploymentStatus = isContainersEnabled(context) ? 'Yes' : 'No';
context.print.info(`| Leverage container-based deployments: ${containerDeploymentStatus}`);
}

async function getConfigurationSetting() {
const configureSettingQuestion: ListQuestion = {
type: 'list',
name: 'configurationSetting',
message: 'Which setting do you want to configure?',
choices: [
{ name: 'Project information', value: 'project' },
{ name: 'AWS Profile setting', value: 'profile' },
{ name: 'Advanced: Container-based deployments', value: 'containers' },
],
default: 'project',
};

const { configurationSetting } = await inquirer.prompt(configureSettingQuestion);
return configurationSetting;
}

async function configureProjectName(context) {
let { projectName } = context.exeInfo.projectConfig;
if (context.exeInfo.inputParams.amplify && context.exeInfo.inputParams.amplify.projectName) {
Expand Down
2 changes: 1 addition & 1 deletion packages/amplify-cli/src/execution-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export async function executeCommand(context: Context) {
}
}

function isContainersEnabled(context) {
export function isContainersEnabled(context) {
const projectConfig = context.amplify.getProjectConfig();
return projectConfig?.[projectConfig.frontend]?.config?.ServerlessContainers ?? false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as inquirer from 'inquirer';
import { JSONUtilities } from 'amplify-cli-core';
import { merge } from 'lodash';

const editors = [
export const editors = [
{
name: 'Visual Studio Code',
value: 'vscode',
Expand Down
80 changes: 72 additions & 8 deletions packages/amplify-cli/src/init-steps/s0-analyzeProject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ import * as path from 'path';
import * as fs from 'fs-extra';
import * as inquirer from 'inquirer';
import { InvalidEnvironmentNameError, stateManager, exitOnNextTick, $TSContext } from 'amplify-cli-core';
import { normalizeEditor, editorSelection } from '../extensions/amplify-helpers/editor-selection';
import { normalizeEditor, editorSelection, editors } from '../extensions/amplify-helpers/editor-selection';
import { getFrontendPlugins } from '../extensions/amplify-helpers/get-frontend-plugins';
import { getSuitableFrontend } from './s1-initFrontend';
import { isProjectNameValid, normalizeProjectName } from '../extensions/amplify-helpers/project-name-validation';
import { amplifyCLIConstants } from '../extensions/amplify-helpers/constants';

Expand All @@ -23,13 +25,64 @@ export async function analyzeProjectHeadless(context: $TSContext) {
}
}

export function displayConfigurationDefaults(context, defaultProjectName, defaultEnv, defaultEditorName) {
context.print.info('Project information');
context.print.info(`| Name: ${defaultProjectName}`);
context.print.info(`| Environment: ${defaultEnv}`);
context.print.info(`| Default editor: ${defaultEditorName}`);
}

function setConfigurationDefaults(context, projectPath, defaultProjectName, defaultEnv, defaultEditor) {
setExeInfo(context, projectPath, defaultEditor, defaultEnv);
setProjectConfig(context, defaultProjectName);
context.exeInfo.inputParams.amplify = context.exeInfo.inputParams.amplify || {};
context.exeInfo.inputParams.amplify.projectName = defaultProjectName;
context.exeInfo.inputParams.amplify.envName = defaultEnv;
context.exeInfo.inputParams.amplify.defaultEditor = defaultEditor;
}

async function displayAndSetDefaults(context, projectPath, projectName) {
const defaultProjectName = projectName;
const defaultEnv = getDefaultEnv(context);
let defaultEditor;
if (context?.exeInfo?.inputParams?.amplify?.defaultEditor) {
defaultEditor = normalizeEditor(context.exeInfo.inputParams.amplify.defaultEditor);
} else {
defaultEditor = editors.length > 0 ? editors[0].value : 'vscode';
}
const editorIndex = editors.findIndex(editorEntry => editorEntry.value === defaultEditor);
const defaultEditorName = editorIndex > -1 ? editors[editorIndex].name : 'Visual Studio Code';

context.print.success('The following configuration will be applied:');
context.print.info('');

await displayConfigurationDefaults(context, defaultProjectName, defaultEnv, defaultEditorName);

const frontendPlugins = getFrontendPlugins(context);
const defaultFrontend = getSuitableFrontend(frontendPlugins, projectPath);
const frontendModule = require(frontendPlugins[defaultFrontend]);

await frontendModule.displayFrontendDefaults(context, projectPath);
context.print.info('');

if (context.exeInfo.inputParams.yes || (await context.amplify.confirmPrompt('Initialize the project with the above configuration?'))) {
await setConfigurationDefaults(context, projectPath, defaultProjectName, defaultEnv, defaultEditorName);
await frontendModule.setFrontendDefaults(context, projectPath);
}
}

export async function analyzeProject(context): Promise<$TSContext> {
if (!context.parameters.options.app || !context.parameters.options.quickstart) {
context.print.warning('Note: It is recommended to run this command from the root of your app directory');
}
const projectPath = process.cwd();
context.exeInfo.isNewProject = isNewProject(context);
const projectName = await getProjectName(context);

if (context.exeInfo.isNewProject && context.parameters.command !== 'env') {
await displayAndSetDefaults(context, projectPath, projectName);
}

const envName = await getEnvName(context);

let defaultEditor = getDefaultEditor();
Expand Down Expand Up @@ -129,8 +182,25 @@ async function getEditor(context) {
}
/* End getEditor */

const isEnvNameValid = inputEnvName => {
return /^[a-z]{2,10}$/.test(inputEnvName);
};

const INVALID_ENV_NAME_MSG = 'Environment name must be between 2 and 10 characters, and lowercase only.';

function getDefaultEnv(context): string | undefined {
const defaultEnv = 'dev';
let defaultEnv = 'dev';

if (context?.exeInfo?.inputParams?.amplify?.envName) {
if (isEnvNameValid(context.exeInfo.inputParams.amplify.envName)) {
defaultEnv = context.exeInfo.inputParams.amplify.envName;
return defaultEnv;
}
context.print.error(INVALID_ENV_NAME_MSG);
context.usageData.emitError(new InvalidEnvironmentNameError(INVALID_ENV_NAME_MSG));
exitOnNextTick(1);
}

if (isNewProject(context) || !context.amplify.getAllEnvs().includes(defaultEnv)) {
return defaultEnv;
}
Expand All @@ -140,12 +210,6 @@ function getDefaultEnv(context): string | undefined {
async function getEnvName(context) {
let envName;

const isEnvNameValid = inputEnvName => {
return /^[a-z]{2,10}$/.test(inputEnvName);
};

const INVALID_ENV_NAME_MSG = 'Environment name must be between 2 and 10 characters, and lowercase only.';

if (context.exeInfo.inputParams.amplify && context.exeInfo.inputParams.amplify.envName) {
if (isEnvNameValid(context.exeInfo.inputParams.amplify.envName)) {
({ envName } = context.exeInfo.inputParams.amplify);
Expand Down
22 changes: 13 additions & 9 deletions packages/amplify-cli/src/init-steps/s1-initFrontend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,25 +11,29 @@ export async function initFrontend(context) {
}

const frontendPlugins = getFrontendPlugins(context);
const suitableFrontend = getSuitableFrontend(frontendPlugins, context.exeInfo.localEnvInfo.projectPath);
const frontend = await getFrontendHandler(context, frontendPlugins, suitableFrontend);

context.exeInfo.projectConfig.frontend = frontend;
const frontendModule = require(frontendPlugins[frontend]);
await frontendModule.init(context);

return context;
}

export function getSuitableFrontend(frontendPlugins, projectPath) {
let suitableFrontend;
let fitToHandleScore = -1;

Object.keys(frontendPlugins).forEach(key => {
const { scanProject } = require(frontendPlugins[key]);
const newScore = scanProject(context.exeInfo.localEnvInfo.projectPath);
const newScore = scanProject(projectPath);
if (newScore > fitToHandleScore) {
fitToHandleScore = newScore;
suitableFrontend = key;
}
});

const frontend = await getFrontendHandler(context, frontendPlugins, suitableFrontend);

context.exeInfo.projectConfig.frontend = frontend;
const frontendModule = require(frontendPlugins[frontend]);
await frontendModule.init(context);

return context;
return suitableFrontend;
}

async function getFrontendHandler(context, frontendPlugins, suitableFrontend) {
Expand Down
37 changes: 10 additions & 27 deletions packages/amplify-e2e-core/src/configure/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { nspawn as spawn, getCLIPath, singleSelect } from '..';
import { ExecutionContext } from '../utils';

type AmplifyConfiguration = {
accessKeyId: string;
Expand Down Expand Up @@ -28,6 +27,7 @@ const regionOptions = [
'ap-south-1',
];

const configurationOptions = ['project', 'profile', 'containers'];
const profileOptions = ['cancel', 'update', 'remove'];

const MANDATORY_PARAMS = ['accessKeyId', 'secretAccessKey', 'region'];
Expand Down Expand Up @@ -75,33 +75,16 @@ export function amplifyConfigure(settings: AmplifyConfiguration): Promise<void>
export function amplifyConfigureProject(settings: { cwd: string; enableContainers: boolean }): Promise<void> {
const { enableContainers = false, cwd } = settings;

const confirmContainers: keyof Pick<ExecutionContext, 'sendConfirmYes' | 'sendConfirmNo'> = enableContainers
? 'sendConfirmYes'
: 'sendConfirmNo';

return new Promise((resolve, reject) => {
const chain = spawn(getCLIPath(), ['configure', 'project'], { cwd, stripColors: true })
.wait('Enter a name for the project')
.sendCarriageReturn()
.wait('Choose your default editor:')
.sendCarriageReturn()
.wait("Choose the type of app that you're building")
.sendCarriageReturn()
.wait('What javascript framework are you using')
.sendCarriageReturn()
.wait('Source Directory Path:')
.sendCarriageReturn()
.wait('Distribution Directory Path:')
.sendCarriageReturn()
.wait('Build Command:')
.sendCarriageReturn()
.wait('Start Command:')
.sendCarriageReturn()
.wait('Do you want to enable container-based deployments?')
[confirmContainers]()
.wait('Do you want to update or remove the project level AWS profile?');

singleSelect(chain, profileOptions[0], profileOptions);
const chain = spawn(getCLIPath(), ['configure', 'project'], { cwd, stripColors: true }).wait('Which setting do you want to configure?');
if (enableContainers) {
singleSelect(chain, 'containers', configurationOptions);
chain.wait('Do you want to enable container-based deployments?').sendLine('y');
} else {
singleSelect(chain, 'profile', configurationOptions);
chain.wait('Do you want to update or remove the project level AWS profile?');
singleSelect(chain, profileOptions[0], profileOptions);
}

chain.wait('Successfully made configuration changes to your project.').run((err: Error) => {
if (!err) {
Expand Down
10 changes: 10 additions & 0 deletions packages/amplify-e2e-core/src/init/initProjectHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ export function initJSProjectWithProfile(cwd: string, settings: Object): Promise
spawn(getCLIPath(), ['init'], { cwd, stripColors: true, env, disableCIDetection: s.disableCIDetection })
.wait('Enter a name for the project')
.sendLine(s.name)
.wait('Initialize the project with the above configuration?')
.sendLine('n')
.wait('Enter a name for the environment')
.sendLine(s.envName)
.wait('Choose your default editor:')
Expand Down Expand Up @@ -97,6 +99,8 @@ export function initAndroidProjectWithProfile(cwd: string, settings: Object): Pr
})
.wait('Enter a name for the project')
.sendLine(s.name)
.wait('Initialize the project with the above configuration?')
.sendLine('n')
.wait('Enter a name for the environment')
.sendLine(s.envName)
.wait('Choose your default editor:')
Expand Down Expand Up @@ -138,6 +142,8 @@ export function initIosProjectWithProfile(cwd: string, settings: Object): Promis
})
.wait('Enter a name for the project')
.sendLine(s.name)
.wait('Initialize the project with the above configuration?')
.sendLine('n')
.wait('Enter a name for the environment')
.sendLine(s.envName)
.wait('Choose your default editor:')
Expand Down Expand Up @@ -171,6 +177,8 @@ export function initFlutterProjectWithProfile(cwd: string, settings: Object): Pr
let chain = spawn(getCLIPath(), ['init'], { cwd, stripColors: true })
.wait('Enter a name for the project')
.sendLine(s.name)
.wait('Initialize the project with the above configuration?')
.sendLine('n')
.wait('Enter a name for the environment')
.sendLine(s.envName)
.wait('Choose your default editor:')
Expand Down Expand Up @@ -216,6 +224,8 @@ export function initProjectWithAccessKey(
})
.wait('Enter a name for the project')
.sendLine(s.name)
.wait('Initialize the project with the above configuration?')
.sendLine('n')
.wait('Enter a name for the environment')
.sendLine(s.envName)
.wait('Choose your default editor:')
Expand Down
Loading

0 comments on commit eeb3102

Please sign in to comment.