Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

2821/add cap mta prompting #2889

Open
wants to merge 23 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
c20a205
fix(cf-deploy-config-writer): support new prompt to support user addi…
longieirl Feb 7, 2025
f697d27
fix(cf-deploy-config-writer): fix linting
longieirl Feb 7, 2025
bbf0d8a
fix(cf-deploy-config-writer): fix sonar issues
longieirl Feb 7, 2025
7e46fef
Merge branch 'main' into 2821/add-cap-mta-prompting
longieirl Feb 7, 2025
accee52
fix(cf-deploy-config-writer): support new CAP MTA continue option
longieirl Feb 12, 2025
908cf07
Merge branch 'main' into 2821/add-cap-mta-prompting
longieirl Feb 12, 2025
8c9c8f8
fix(cf-deploy-config-writer): add changeset
longieirl Feb 12, 2025
e22b43f
fix(cf-deploy-config-writer): remove duplicate changeset
longieirl Feb 12, 2025
252c9f6
fix(cf-deploy-config-writer): fix spelling mistake
longieirl Feb 12, 2025
b437142
Merge branch 'main' into 2821/add-cap-mta-prompting
longieirl Feb 12, 2025
3e51b93
fix(cf-deploy-config-writer): remove spelling fix
longieirl Feb 12, 2025
d35f8e1
fix(flp): fix spelling
longieirl Feb 12, 2025
7fa1c24
fix(cf-deploy-config-writer): merge master
longieirl Feb 13, 2025
c1592b2
fix(cf-deploy-config-writer): merge master
longieirl Feb 13, 2025
b7152e4
fix(cf-deploy-config-writer): fix merge conflict
longieirl Feb 13, 2025
1a16f5b
Merge branch 'main' into 2821/add-cap-mta-prompting
longieirl Feb 14, 2025
0df5c2d
fix(cf-deploy-config-writer): cleanup code
longieirl Feb 14, 2025
b8de706
fix(cf-deploy-config-writer): remove unused code and error handling
longieirl Feb 14, 2025
bcb7c7d
fix(cf-deploy-config-writer): fix text formatting
longieirl Feb 17, 2025
22493af
Merge branch 'main' into 2821/add-cap-mta-prompting
longieirl Feb 19, 2025
06c82fd
Merge branch 'main' into 2821/add-cap-mta-prompting
longieirl Feb 20, 2025
6bce186
Merge branch 'main' into 2821/add-cap-mta-prompting
longieirl Feb 21, 2025
77fffb4
Merge branch 'main' into 2821/add-cap-mta-prompting
longieirl Feb 21, 2025
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
8 changes: 8 additions & 0 deletions .changeset/tasty-cats-search.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
'@sap-ux/cf-deploy-config-sub-generator': patch
'@sap-ux/deploy-config-generator-shared': patch
'@sap-ux/cf-deploy-config-inquirer': patch
'@sap-ux/cf-deploy-config-writer': patch
---

Changes to support adding CAP MTA prompt to allow user generate MTA
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ When analyzing a problem, it is helpful to be able to debug the modules. How to

Each of the packages has an extensive set of unit tests covering as many as possible different scenarios, therefore, as a starting point for debugging, it is a good idea to use the tests. The easiest (but not the only) way to debug a specific test in VSCode is to open a `JavaScript Debug Terminal` and then go to the package that needs to be debugged. Using the debug terminal, execute all tests with `pnpm test` or a specific one, e.g. execute `pnpm test -- test/basic.test.ts` in the `fiori-freestyle-writer` directory (`./packages/fiori-freestyle-writer`). When running either of the commands in the debug terminal, breakpoints set in VSCode will be active.

Additionally for the `*-writer` modules it is sometimes helpful to manually inspect the generated output of the unit tests on the filesystem. This can be achieved by setting the variable `UX_DEBUG` before running the tests e.g. in `fiori-freestyle-writer` run `UX_DEBUG=true pnpm test` and after the tests finish, the generated files can be found at `./test/test-output`.
Additionally, for the `*-writer` modules it is sometimes helpful to manually inspect the generated output of the unit tests on the filesystem. This can be achieved by setting the variable `UX_DEBUG` before running the tests e.g. in `fiori-freestyle-writer` run `UX_DEBUG=true pnpm test` and after the tests finish, the generated files can be found at `./test/test-output`.
Additional checks can be performed on the generated projects by also setting `UX_DEBUG_FULL` e.g. `UX_DEBUG=true UX_DEBUG_FULL=true pnpm test`.
This includes checks such as `npm install`, `npm run ts-typecheck`, `npm run lint` as appropriate to the project.

Expand Down
3 changes: 2 additions & 1 deletion packages/cf-deploy-config-inquirer/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,5 +88,6 @@ export {
RouterModuleType,
type CfDeployConfigQuestions,
type CfDeployConfigAnswers,
type CfAppRouterDeployConfigAnswers
type CfAppRouterDeployConfigAnswers,
type CfAppRouterDeployConfigQuestions
};
82 changes: 60 additions & 22 deletions packages/cf-deploy-config-sub-generator/src/app/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,13 @@ import {
} from '@sap-ux/fiori-generator-shared';
import { isInternalFeaturesSettingEnabled } from '@sap-ux/feature-toggle';
import { isFullUrlDestination } from '@sap-ux/btp-utils';
import { generateAppConfig, ApiHubType, useAbapDirectServiceBinding } from '@sap-ux/cf-deploy-config-writer';
import {
generateAppConfig,
generateCAPConfig,
ApiHubType,
useAbapDirectServiceBinding,
DefaultMTADestination
} from '@sap-ux/cf-deploy-config-writer';
import {
DeploymentGenerator,
showOverwriteQuestion,
Expand All @@ -22,18 +28,25 @@ import {
mtaExecutable,
cdsExecutable,
generateDestinationName,
getDestination
getDestination,
getConfirmMtaContinuePrompt
} from '@sap-ux/deploy-config-generator-shared';
import { t, initI18n, DESTINATION_AUTHTYPE_NOTFOUND, API_BUSINESS_HUB_ENTERPRISE_PREFIX } from '../utils';
import { loadManifest } from './utils';
import { getMtaPath, findCapProjectRoot, FileName } from '@sap-ux/project-access';
import { EventName } from '../telemetryEvents';
import { getCFQuestions } from './questions';
import type { ApiHubConfig, CFAppConfig } from '@sap-ux/cf-deploy-config-writer';
import { getCFApprouterQuestionsForCap, getCFQuestions } from './questions';
import type { ApiHubConfig, CFAppConfig, CAPConfig } from '@sap-ux/cf-deploy-config-writer';
import type { Logger } from '@sap-ux/logger';
import type { CfDeployConfigOptions } from './types';
import type { CfDeployConfigAnswers, CfDeployConfigQuestions } from '@sap-ux/cf-deploy-config-inquirer';
import { CfDeployConfigOptions } from './types';
import {
type CfAppRouterDeployConfigAnswers,
type CfDeployConfigQuestions,
CfDeployConfigAnswers
} from '@sap-ux/cf-deploy-config-inquirer';
import type { YeomanEnvironment } from '@sap-ux/fiori-generator-shared';
import { withCondition } from '@sap-ux/inquirer-common';
import type { Answers, Question } from 'inquirer';

/**
* Cloud Foundry deployment configuration generator.
Expand All @@ -49,6 +62,7 @@ export default class extends DeploymentGenerator {
private readonly cloudServiceName?: string;
private readonly serviceBase?: string;
private answers: CfDeployConfigAnswers & Partial<CFAppConfig> = {};
private appRouterAnswers: CfAppRouterDeployConfigAnswers;
private projectRoot: string;
private mtaPath?: string;
private isCap = false;
Expand All @@ -75,7 +89,7 @@ export default class extends DeploymentGenerator {
this.options = opts;

this.destinationName = opts.destinationName ?? '';
this.addMtaDestination = opts.addMTADestination ?? false; // by default it's false unless passed in i.e. headless flow
this.addMtaDestination = opts.addMTADestination ?? false; // by default, it's false unless passed in i.e. headless flow
this.lcapModeOnly = opts.lcapModeOnly ?? false;
this.cloudServiceName = opts.cloudServiceName || undefined;
this.apiHubConfig = opts.apiHubConfig;
Expand Down Expand Up @@ -106,6 +120,8 @@ export default class extends DeploymentGenerator {

if (!this.launchDeployConfigAsSubGenerator) {
await this._init();
} else {
await this._processProjectConfigs();
}
}

Expand All @@ -115,12 +131,10 @@ export default class extends DeploymentGenerator {
this.abort = true;
handleErrorMessage(this.appWizard, { errorType: ERROR_TYPE.NO_MTA_BIN });
}

await this._processProjectPaths();
await this._processProjectConfigs();

this.isAbapDirectServiceBinding = await useAbapDirectServiceBinding(this.appPath, false, this.mtaPath);

// restricting local changes is only applicable for CAP flows
if (!this.isCap) {
this.lcapModeOnly = false;
Expand All @@ -134,7 +148,7 @@ export default class extends DeploymentGenerator {
private async _processProjectPaths(): Promise<void> {
const mtaPathResult = await getMtaPath(this.appPath);
this.mtaPath = mtaPathResult?.mtaPath;
const capRoot = await findCapProjectRoot(this.appPath);
const capRoot = await findCapProjectRoot(this.appPath, true, this.fs);
if (capRoot) {
if (!hasbin.sync(cdsExecutable)) {
bail(ErrorHandler.getErrorMsgFromType(ERROR_TYPE.NO_CDS_BIN));
Expand All @@ -156,29 +170,45 @@ export default class extends DeploymentGenerator {
if (!baseConfigExists) {
bail(ErrorHandler.noBaseConfig(baseConfigFile));
}

this.deployConfigExists = this.fs.exists(join(this.appPath, this.options.config ?? FileName.Ui5Yaml));
}

public async prompting(): Promise<void> {
if (this.abort) {
return;
}

if (this.isCap && this.projectRoot && !this.mtaPath) {
// if the user is adding deploy config to a CAP project and there is no mta.yaml in the root, then log error and exit
this.abort = true;
handleErrorMessage(this.appWizard, { errorType: ERROR_TYPE.CAP_DEPLOYMENT_NO_MTA });
return;
if (!this.launchDeployConfigAsSubGenerator) {
await this._prompting();
}
await this._reconcileAnswersWithOptions();
}

if (!this.launchDeployConfigAsSubGenerator) {
private async _prompting(): Promise<void> {
const isCAPMissingMTA = this.isCap && this.projectRoot && !this.mtaPath;
if (isCAPMissingMTA) {
DeploymentGenerator.logger?.debug(t('cfGen.debug.capMissingMTA'));
// If launched as root generator, add a prompt to allow user decide if they want to add an MTA config
let questions = (await getCFApprouterQuestionsForCap({
projectRoot: this.projectRoot ?? process.cwd()
})) as Question[];
questions = withCondition(questions, (answers: Answers) => answers.addCapMtaContinue === true);
questions.unshift(...getConfirmMtaContinuePrompt());
this.appRouterAnswers = (await this.prompt(questions)) as CfAppRouterDeployConfigAnswers;
if ((this.appRouterAnswers as Answers).addCapMtaContinue !== true) {
this.abort = true;
return;
}
// Configure defaults
this.destinationName = DefaultMTADestination;
this.options.overwrite = true; // Don't prompt the user to overwrite files we've just written!
this.answers = {};
this.answers.destinationName = this.destinationName;
this.answers.addManagedAppRouter = false;
} else {
Comment on lines +188 to +207
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe put all the mta related code in this condition into a new function? But its just a suggestion.

await this._handleApiHubConfig();
const questions = await this._getCFQuestions();
this.answers = await this.prompt(questions);
}

await this._reconcileAnswersWithOptions();
}

/**
Expand Down Expand Up @@ -251,8 +281,16 @@ export default class extends DeploymentGenerator {

private async _writing(): Promise<void> {
try {
const appConfig = this._getAppConfig();
await generateAppConfig(appConfig, this.fs, DeploymentGenerator.logger as unknown as Logger);
// Step1. (Optional) Generate CAP MTA with specific approuter type managed | standalone
if (this.appRouterAnswers) {
await generateCAPConfig(
this.appRouterAnswers as CAPConfig,
this.fs,
DeploymentGenerator.logger as unknown as Logger
);
}
// Step2. Append HTML5 app to MTA
await generateAppConfig(this._getAppConfig(), this.fs, DeploymentGenerator.logger as unknown as Logger);
} catch (error) {
this.abort = true;
handleErrorMessage(this.appWizard, { errorMsg: t('cfGen.error.writing', { error }) });
Expand Down
38 changes: 36 additions & 2 deletions packages/cf-deploy-config-sub-generator/src/app/questions.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
import { isAppStudio } from '@sap-ux/btp-utils';
import { DeploymentGenerator } from '@sap-ux/deploy-config-generator-shared';
import { getMtaPath } from '@sap-ux/project-access';
import { getPrompts, promptNames } from '@sap-ux/cf-deploy-config-inquirer';
import {
appRouterPromptNames,
type CfAppRouterDeployConfigPromptOptions,
type CfAppRouterDeployConfigQuestions,
type CfDeployConfigPromptOptions,
type CfDeployConfigQuestions,
getAppRouterPrompts,
getPrompts,
promptNames
} from '@sap-ux/cf-deploy-config-inquirer';
import { getHostEnvironment, hostEnvironment } from '@sap-ux/fiori-generator-shared';
import { destinationQuestionDefaultOption, getCFChoices } from './utils';
import { t } from '../utils';
import type { ApiHubConfig } from '@sap-ux/cf-deploy-config-writer';
import type { CfDeployConfigPromptOptions, CfDeployConfigQuestions } from '@sap-ux/cf-deploy-config-inquirer';

/**
* Fetches the Cloud Foundry deployment configuration questions.
Expand Down Expand Up @@ -60,3 +68,29 @@ export async function getCFQuestions({
DeploymentGenerator.logger?.debug(t('cfGen.debug.promptOptions', { options: JSON.stringify(options) }));
return getPrompts(options);
}

/**
* Retrieve the CF Approuter questions, certain prompts are restricted to support CAP project.
*
* @param options - the options required for retrieving the prompts.
* @param options.projectRoot - the root path of the project.
* @returns the cf approuter config questions.
*/
export async function getCFApprouterQuestionsForCap({
projectRoot
}: {
projectRoot: string;
}): Promise<CfAppRouterDeployConfigQuestions[]> {
// Disable some prompts, not required for CAP flow
const appRouterPromptOptions: CfAppRouterDeployConfigPromptOptions = {
[appRouterPromptNames.mtaPath]: projectRoot,
[appRouterPromptNames.mtaId]: true,
[appRouterPromptNames.mtaDescription]: false,
[appRouterPromptNames.mtaVersion]: false,
[appRouterPromptNames.routerType]: true,
[appRouterPromptNames.addConnectivityService]: true,
[appRouterPromptNames.addABAPServiceBinding]: false
};

return getAppRouterPrompts(appRouterPromptOptions);
}
6 changes: 5 additions & 1 deletion packages/cf-deploy-config-sub-generator/src/app/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { AppWizard } from '@sap-devx/yeoman-ui-types';
import type { CfDeployConfigAnswers } from '@sap-ux/cf-deploy-config-inquirer';
import { type CfDeployConfigAnswers } from '@sap-ux/cf-deploy-config-inquirer';
import type { ApiHubConfig } from '@sap-ux/cf-deploy-config-writer';
import type { TelemetryData } from '@sap-ux/fiori-generator-shared';

Expand Down Expand Up @@ -84,4 +84,8 @@ export interface CfDeployConfigOptions extends CfDeployConfigAnswers {
* Telemetry data to be send after deployment configuration has been added
*/
telemetryData?: TelemetryData;
/**
* Option to invoke the getConfirmMtaContinue prompt
*/
addCapMtaContinue?: boolean;
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@
},
"debug": {
"promptOptions": "Retrieving CF prompts using: \n {{- options}}",
"initTelemetry": "Initializing telemetry in CF deployment configuration generator"
"initTelemetry": "Initializing telemetry in CF deployment configuration generator",
"capMissingMTA": "CAP project detected with no MTA configuration"
}
},
"appRouterGen": {
Expand Down
Loading