@sap-ux/repo-app-import-sub-generator 1.0.20 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/generators/app/app-config-abap-repo.d.ts +42 -0
- package/generators/app/app-config-abap-repo.js +87 -0
- package/generators/app/{app-config.d.ts → app-config-quick-deploy.d.ts} +10 -18
- package/generators/app/{app-config.js → app-config-quick-deploy.js} +31 -64
- package/generators/app/index.d.ts +12 -1
- package/generators/app/index.js +59 -15
- package/generators/app/types.d.ts +32 -1
- package/generators/app/types.js +9 -0
- package/generators/prompts/prompt-helpers.d.ts +5 -2
- package/generators/prompts/prompt-helpers.js +20 -15
- package/generators/prompts/prompt-state.d.ts +7 -0
- package/generators/prompts/prompt-state.js +8 -0
- package/generators/prompts/prompts.d.ts +3 -1
- package/generators/prompts/prompts.js +8 -7
- package/generators/translations/repo-app-import-sub-generator.i18n.json +22 -8
- package/generators/utils/constants.d.ts +20 -6
- package/generators/utils/constants.js +41 -9
- package/generators/utils/download-utils.d.ts +14 -0
- package/generators/utils/download-utils.js +37 -0
- package/generators/utils/event-hook.d.ts +3 -2
- package/generators/utils/event-hook.js +5 -3
- package/generators/utils/file-helpers.d.ts +19 -2
- package/generators/utils/file-helpers.js +46 -8
- package/generators/utils/validators.d.ts +3 -1
- package/generators/utils/validators.js +12 -9
- package/package.json +3 -3
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { OdataVersion } from '@sap-ux/odata-service-inquirer';
|
|
2
|
+
import type { Editor } from 'mem-fs-editor';
|
|
3
|
+
import type { AppInfo, AbapRepositoryContext } from '../app/types.js';
|
|
4
|
+
import type { AbapDeployConfig } from '@sap-ux/ui5-config';
|
|
5
|
+
/**
|
|
6
|
+
* App configuration derived from the downloaded manifest for the ABAP repository flow.
|
|
7
|
+
* Used only for README generation, launch config creation, and adding a minimal package.json.
|
|
8
|
+
*/
|
|
9
|
+
export interface AbapRepoAppConfig {
|
|
10
|
+
app: {
|
|
11
|
+
id: string;
|
|
12
|
+
title: string;
|
|
13
|
+
flpAppId: string;
|
|
14
|
+
};
|
|
15
|
+
service: {
|
|
16
|
+
url: string | undefined;
|
|
17
|
+
version: OdataVersion;
|
|
18
|
+
};
|
|
19
|
+
ui5: {
|
|
20
|
+
version: string;
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Builds the app configuration for the ABAP repository download flow by reading
|
|
25
|
+
* the downloaded manifest. Returns a typed config object used for README generation, launch config, and deploy config.
|
|
26
|
+
*
|
|
27
|
+
* @param {string} webappPath - Path to the webapp folder.
|
|
28
|
+
* @param {AppInfo} appInfo - The selected app info from prompts.
|
|
29
|
+
* @param {Editor} fs - The file system editor.
|
|
30
|
+
* @returns {AbapRepoAppConfig} Derived app configuration.
|
|
31
|
+
*/
|
|
32
|
+
export declare function getAbapRepoAppConfig(webappPath: string, appInfo: AppInfo, fs: Editor): AbapRepoAppConfig;
|
|
33
|
+
/**
|
|
34
|
+
* Generates the deployment configuration for an ABAP repository application.
|
|
35
|
+
* Fetches package and description from the UI5 ABAP Repository service.
|
|
36
|
+
*
|
|
37
|
+
* @param {AppInfo} app - The application information collected from user prompts.
|
|
38
|
+
* @param {AppDownloadContext} context - The download context.
|
|
39
|
+
* @returns {Promise<AbapDeployConfig>} The deployment configuration.
|
|
40
|
+
*/
|
|
41
|
+
export declare function getAbapRepoDeployConfig(app: AppInfo, context: AbapRepositoryContext): Promise<AbapDeployConfig>;
|
|
42
|
+
//# sourceMappingURL=app-config-abap-repo.d.ts.map
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { OdataVersion } from '@sap-ux/odata-service-inquirer';
|
|
2
|
+
import { PromptState } from '../prompts/prompt-state.js';
|
|
3
|
+
import RepoAppDownloadLogger from '../utils/logger.js';
|
|
4
|
+
import { t } from '../utils/i18n.js';
|
|
5
|
+
import { getFlpId } from '@sap-ux/fiori-generator-shared';
|
|
6
|
+
import { FileName, getMainService } from '@sap-ux/project-access';
|
|
7
|
+
import { resolveTransportRequest } from '../utils/download-utils.js';
|
|
8
|
+
import { AuthenticationType } from '@sap-ux/store';
|
|
9
|
+
import { readManifest } from '../utils/file-helpers.js';
|
|
10
|
+
import { join } from 'node:path';
|
|
11
|
+
/**
|
|
12
|
+
* Builds the app configuration for the ABAP repository download flow by reading
|
|
13
|
+
* the downloaded manifest. Returns a typed config object used for README generation, launch config, and deploy config.
|
|
14
|
+
*
|
|
15
|
+
* @param {string} webappPath - Path to the webapp folder.
|
|
16
|
+
* @param {AppInfo} appInfo - The selected app info from prompts.
|
|
17
|
+
* @param {Editor} fs - The file system editor.
|
|
18
|
+
* @returns {AbapRepoAppConfig} Derived app configuration.
|
|
19
|
+
*/
|
|
20
|
+
export function getAbapRepoAppConfig(webappPath, appInfo, fs) {
|
|
21
|
+
const manifest = readManifest(join(webappPath, FileName.Manifest), fs);
|
|
22
|
+
const appId = manifest?.['sap.app']?.id ?? appInfo.appId;
|
|
23
|
+
const appTitle = manifest?.['sap.app']?.title ?? appInfo.title ?? '';
|
|
24
|
+
const minUI5Version = manifest?.['sap.ui5']?.dependencies?.minUI5Version ?? '';
|
|
25
|
+
const ui5Version = Array.isArray(minUI5Version) ? (minUI5Version[0] ?? '') : minUI5Version;
|
|
26
|
+
const mainServiceName = getMainService(manifest);
|
|
27
|
+
const odataVersionStr = mainServiceName
|
|
28
|
+
? manifest?.['sap.app']?.dataSources?.[mainServiceName]?.settings?.odataVersion
|
|
29
|
+
: undefined;
|
|
30
|
+
const odataVersion = odataVersionStr === '4.0' ? OdataVersion.v4 : OdataVersion.v2;
|
|
31
|
+
return {
|
|
32
|
+
app: {
|
|
33
|
+
id: appId,
|
|
34
|
+
title: appTitle,
|
|
35
|
+
flpAppId: `${getFlpId(appId)}-tile`
|
|
36
|
+
},
|
|
37
|
+
service: {
|
|
38
|
+
url: PromptState.baseURL,
|
|
39
|
+
version: odataVersion
|
|
40
|
+
},
|
|
41
|
+
ui5: {
|
|
42
|
+
version: ui5Version
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Generates the deployment configuration for an ABAP repository application.
|
|
48
|
+
* Fetches package and description from the UI5 ABAP Repository service.
|
|
49
|
+
*
|
|
50
|
+
* @param {AppInfo} app - The application information collected from user prompts.
|
|
51
|
+
* @param {AppDownloadContext} context - The download context.
|
|
52
|
+
* @returns {Promise<AbapDeployConfig>} The deployment configuration.
|
|
53
|
+
*/
|
|
54
|
+
export async function getAbapRepoDeployConfig(app, context) {
|
|
55
|
+
const { serviceProvider } = context;
|
|
56
|
+
let packageName = '';
|
|
57
|
+
let description = '';
|
|
58
|
+
try {
|
|
59
|
+
// get package and description from repository
|
|
60
|
+
const repoInfo = await serviceProvider
|
|
61
|
+
?.getUi5AbapRepository()
|
|
62
|
+
.getInfo(app?.repoName ?? '');
|
|
63
|
+
packageName = repoInfo?.Package ?? '';
|
|
64
|
+
description = repoInfo?.Description ?? '';
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
RepoAppDownloadLogger.logger?.warn(t('warn.repoInfoFetchFailed', { repoName: app?.repoName, error: error?.message }));
|
|
68
|
+
}
|
|
69
|
+
const transport = await resolveTransportRequest(serviceProvider, packageName, app?.repoName ?? '');
|
|
70
|
+
return {
|
|
71
|
+
target: {
|
|
72
|
+
url: PromptState.baseURL,
|
|
73
|
+
client: PromptState.sapClient,
|
|
74
|
+
destination: PromptState.destinationName,
|
|
75
|
+
...(PromptState.authenticationType === AuthenticationType.ReentranceTicket && {
|
|
76
|
+
authenticationType: PromptState.authenticationType
|
|
77
|
+
})
|
|
78
|
+
},
|
|
79
|
+
app: {
|
|
80
|
+
name: app?.repoName,
|
|
81
|
+
package: packageName,
|
|
82
|
+
description: description || app?.description,
|
|
83
|
+
transport
|
|
84
|
+
}
|
|
85
|
+
}; // NOSONAR
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=app-config-abap-repo.js.map
|
|
@@ -1,23 +1,8 @@
|
|
|
1
1
|
import { type FioriElementsApp, type LROPSettings } from '@sap-ux/fiori-elements-writer';
|
|
2
|
-
import type { AbapServiceProvider } from '@sap-ux/axios-extension';
|
|
3
2
|
import type { Editor } from 'mem-fs-editor';
|
|
4
|
-
import type { AppInfo,
|
|
3
|
+
import type { AppInfo, AdtQuickDeployContext } from '../app/types.js';
|
|
5
4
|
import type { AbapDeployConfig } from '@sap-ux/ui5-config';
|
|
6
5
|
import { type OdataServiceAnswers } from '@sap-ux/odata-service-inquirer';
|
|
7
|
-
/**
|
|
8
|
-
* Shared context for downloading and deploying ABAP applications.
|
|
9
|
-
*/
|
|
10
|
-
export interface AppDownloadContext {
|
|
11
|
-
serviceProvider?: AbapServiceProvider;
|
|
12
|
-
qfaJson: QfaJsonConfig;
|
|
13
|
-
}
|
|
14
|
-
/**
|
|
15
|
-
* Generates the deployment configuration for an ABAP application.
|
|
16
|
-
*
|
|
17
|
-
* @param {AppDownloadContext} context - The download context with service provider and qfa info.
|
|
18
|
-
* @returns {AbapDeployConfig} The deployment configuration containing `target` and `app` info.
|
|
19
|
-
*/
|
|
20
|
-
export declare const getAbapDeployConfig: (context: AppDownloadContext) => Promise<AbapDeployConfig>;
|
|
21
6
|
/**
|
|
22
7
|
* Gets the application configuration based on the provided user answers and manifest data.
|
|
23
8
|
* This configuration will be used to initialize a new Fiori application.
|
|
@@ -30,5 +15,12 @@ export declare const getAbapDeployConfig: (context: AppDownloadContext) => Promi
|
|
|
30
15
|
* @returns {Promise<FioriElementsApp<LROPSettings>>} - A promise resolving to the generated app configuration.
|
|
31
16
|
* @throws {Error} - Throws an error if there are issues generating the configuration.
|
|
32
17
|
*/
|
|
33
|
-
export declare function getAppConfig(app: AppInfo, extractedProjectPath: string, context:
|
|
34
|
-
|
|
18
|
+
export declare function getAppConfig(app: AppInfo, extractedProjectPath: string, context: AdtQuickDeployContext, systemSelection: OdataServiceAnswers, fs: Editor): Promise<FioriElementsApp<LROPSettings>>;
|
|
19
|
+
/**
|
|
20
|
+
* Generates the deployment configuration for an ADT Quick Deploy application.
|
|
21
|
+
*
|
|
22
|
+
* @param {AdtQuickDeployContext} context - The download context.
|
|
23
|
+
* @returns {Promise<AbapDeployConfig>} The deployment configuration.
|
|
24
|
+
*/
|
|
25
|
+
export declare function getAdtDeployConfig(context: AdtQuickDeployContext): Promise<AbapDeployConfig>;
|
|
26
|
+
//# sourceMappingURL=app-config-quick-deploy.d.ts.map
|
|
@@ -1,78 +1,20 @@
|
|
|
1
1
|
import { TemplateType } from '@sap-ux/fiori-elements-writer';
|
|
2
2
|
import { OdataVersion } from '@sap-ux/odata-service-inquirer';
|
|
3
|
-
import { TransportChecksService } from '@sap-ux/axios-extension';
|
|
4
3
|
import { t } from '../utils/i18n.js';
|
|
5
4
|
import { readManifest } from '../utils/file-helpers.js';
|
|
6
|
-
import { fioriAppSourcetemplateId } from '../utils/constants.js';
|
|
5
|
+
import { fioriAppSourcetemplateId, adtSourceTemplateId } from '../utils/constants.js';
|
|
7
6
|
import { PromptState } from '../prompts/prompt-state.js';
|
|
8
7
|
import RepoAppDownloadLogger from '../utils/logger.js';
|
|
9
8
|
import { FileName } from '@sap-ux/project-access';
|
|
10
9
|
import { join } from 'node:path';
|
|
11
10
|
import { getUI5Versions } from '@sap-ux/ui5-info';
|
|
12
|
-
|
|
13
|
-
* Resolve a transport request for the given app/package context.
|
|
14
|
-
* This function performs defensive checks and logs clear, actionable messages.
|
|
15
|
-
*
|
|
16
|
-
* @param context - AppDownloadContext containing qfaJson and serviceProvider
|
|
17
|
-
* @returns { Promise<string> } - Resolved transport request string
|
|
18
|
-
* - '' when package is local ('$TMP')
|
|
19
|
-
* - '<transport-request-id>' when transport request is found
|
|
20
|
-
* - 'REPLACE_WITH_TRANSPORT' when no transport request is found
|
|
21
|
-
* @throws Error when the transport check fails
|
|
22
|
-
*/
|
|
23
|
-
async function resolveTransportRequest(context) {
|
|
24
|
-
const { serviceProvider, qfaJson } = context;
|
|
25
|
-
const packageName = qfaJson.metadata.package;
|
|
26
|
-
const appName = qfaJson.deploymentDetails.repositoryName;
|
|
27
|
-
if (packageName === '$TMP') {
|
|
28
|
-
return '';
|
|
29
|
-
}
|
|
30
|
-
try {
|
|
31
|
-
const transportService = await serviceProvider?.getAdtService(TransportChecksService);
|
|
32
|
-
const transportRequests = await transportService?.getTransportRequests(packageName, appName);
|
|
33
|
-
if (transportRequests?.length === 1) {
|
|
34
|
-
return transportRequests[0].transportNumber;
|
|
35
|
-
}
|
|
36
|
-
return 'REPLACE_WITH_TRANSPORT';
|
|
37
|
-
}
|
|
38
|
-
catch (error) {
|
|
39
|
-
if (error.message === TransportChecksService.LocalPackageError) {
|
|
40
|
-
return '';
|
|
41
|
-
}
|
|
42
|
-
const msg = t('error.transportCheckFailed', { error: error?.message });
|
|
43
|
-
RepoAppDownloadLogger.logger?.error(msg);
|
|
44
|
-
throw new Error(msg);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
/**
|
|
48
|
-
* Generates the deployment configuration for an ABAP application.
|
|
49
|
-
*
|
|
50
|
-
* @param {AppDownloadContext} context - The download context with service provider and qfa info.
|
|
51
|
-
* @returns {AbapDeployConfig} The deployment configuration containing `target` and `app` info.
|
|
52
|
-
*/
|
|
53
|
-
export const getAbapDeployConfig = async (context) => {
|
|
54
|
-
const { qfaJson } = context;
|
|
55
|
-
const transportRequest = await resolveTransportRequest(context);
|
|
56
|
-
return {
|
|
57
|
-
target: {
|
|
58
|
-
url: PromptState.baseURL,
|
|
59
|
-
client: PromptState.sapClient,
|
|
60
|
-
destination: PromptState.destinationName
|
|
61
|
-
},
|
|
62
|
-
app: {
|
|
63
|
-
name: qfaJson.deploymentDetails.repositoryName,
|
|
64
|
-
package: qfaJson.metadata.package,
|
|
65
|
-
description: qfaJson.deploymentDetails.repositoryDescription,
|
|
66
|
-
transport: transportRequest
|
|
67
|
-
}
|
|
68
|
-
}; // NOSONAR
|
|
69
|
-
};
|
|
11
|
+
import { resolveTransportRequest } from '../utils/download-utils.js';
|
|
70
12
|
/**
|
|
71
13
|
* Fetches the metadata of a given service from the provided ABAP service provider.
|
|
72
14
|
*
|
|
73
15
|
* @param {AbapServiceProvider} provider - The ABAP service provider instance.
|
|
74
16
|
* @param {string} serviceUrl - The URL of the service to retrieve metadata for.
|
|
75
|
-
* @returns {Promise<
|
|
17
|
+
* @returns {Promise<string | undefined>} - A promise resolving to the service metadata.
|
|
76
18
|
*/
|
|
77
19
|
const fetchServiceMetadata = async (provider, serviceUrl) => {
|
|
78
20
|
try {
|
|
@@ -101,15 +43,16 @@ export async function getAppConfig(app, extractedProjectPath, context, systemSel
|
|
|
101
43
|
const manifest = readManifest(join(extractedProjectPath, FileName.Manifest), fs);
|
|
102
44
|
const serviceProvider = PromptState.systemSelection?.connectedSystem?.serviceProvider;
|
|
103
45
|
context.serviceProvider = serviceProvider;
|
|
46
|
+
if (manifest?.['sap.app']?.sourceTemplate?.id !== adtSourceTemplateId) {
|
|
47
|
+
RepoAppDownloadLogger.logger?.error(t('error.readManifestErrors.sourceTemplateNotSupported'));
|
|
48
|
+
}
|
|
104
49
|
if (!manifest?.['sap.app']?.dataSources) {
|
|
105
50
|
RepoAppDownloadLogger.logger?.error(t('error.dataSourcesNotFound'));
|
|
106
51
|
}
|
|
107
52
|
const odataVersion = manifest?.['sap.app']?.dataSources?.mainService?.settings?.odataVersion?.startsWith('4')
|
|
108
53
|
? OdataVersion.v4
|
|
109
54
|
: OdataVersion.v2;
|
|
110
|
-
// Fetch metadata for the service
|
|
111
55
|
const metadata = await fetchServiceMetadata(serviceProvider, manifest?.['sap.app']?.dataSources?.mainService.uri ?? '');
|
|
112
|
-
// Fetch latest UI5 versions from npm
|
|
113
56
|
const ui5Versions = await getUI5Versions({ onlyNpmVersion: true });
|
|
114
57
|
const localVersion = ui5Versions[0]?.version;
|
|
115
58
|
const appConfig = {
|
|
@@ -164,4 +107,28 @@ export async function getAppConfig(app, extractedProjectPath, context, systemSel
|
|
|
164
107
|
throw error;
|
|
165
108
|
}
|
|
166
109
|
}
|
|
167
|
-
|
|
110
|
+
/**
|
|
111
|
+
* Generates the deployment configuration for an ADT Quick Deploy application.
|
|
112
|
+
*
|
|
113
|
+
* @param {AdtQuickDeployContext} context - The download context.
|
|
114
|
+
* @returns {Promise<AbapDeployConfig>} The deployment configuration.
|
|
115
|
+
*/
|
|
116
|
+
export async function getAdtDeployConfig(context) {
|
|
117
|
+
const { qfaJson, serviceProvider } = context;
|
|
118
|
+
const packageName = qfaJson.metadata.package;
|
|
119
|
+
const transport = await resolveTransportRequest(serviceProvider, packageName, qfaJson.deploymentDetails.repositoryName);
|
|
120
|
+
return {
|
|
121
|
+
target: {
|
|
122
|
+
url: PromptState.baseURL,
|
|
123
|
+
client: PromptState.sapClient,
|
|
124
|
+
destination: PromptState.destinationName
|
|
125
|
+
},
|
|
126
|
+
app: {
|
|
127
|
+
name: qfaJson.deploymentDetails.repositoryName,
|
|
128
|
+
package: packageName,
|
|
129
|
+
description: qfaJson.deploymentDetails.repositoryDescription,
|
|
130
|
+
transport
|
|
131
|
+
}
|
|
132
|
+
}; // NOSONAR
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=app-config-quick-deploy.js.map
|
|
@@ -9,12 +9,14 @@ export default class extends Generator {
|
|
|
9
9
|
private readonly appWizard;
|
|
10
10
|
private readonly vscode?;
|
|
11
11
|
private readonly appRootPath;
|
|
12
|
-
private readonly prompts;
|
|
13
12
|
private readonly answers;
|
|
13
|
+
private readonly downloadType;
|
|
14
|
+
private readonly prompts;
|
|
14
15
|
options: RepoAppDownloadOptions;
|
|
15
16
|
private projectPath;
|
|
16
17
|
private extractedProjectPath;
|
|
17
18
|
private debugOptions;
|
|
19
|
+
private deployConfig;
|
|
18
20
|
setPromptsCallback: (fn: object) => void;
|
|
19
21
|
/**
|
|
20
22
|
* Constructor for Downloading App.
|
|
@@ -35,6 +37,15 @@ export default class extends Generator {
|
|
|
35
37
|
* Writes the configuration files for the project, including deployment config, and README.
|
|
36
38
|
*/
|
|
37
39
|
writing(): Promise<void>;
|
|
40
|
+
/**
|
|
41
|
+
* Writing phase for ABAP Repository downloads.
|
|
42
|
+
*/
|
|
43
|
+
private _generateAbapRepositoryApp;
|
|
44
|
+
/**
|
|
45
|
+
* Writing phase for ADT Quick Deploy downloads.
|
|
46
|
+
* Generates a full Fiori project from qfa.json metadata including deploy config.
|
|
47
|
+
*/
|
|
48
|
+
private _generateAdtQuickDeployApp;
|
|
38
49
|
/**
|
|
39
50
|
* Returns the configuration for the README file.
|
|
40
51
|
*
|
package/generators/app/index.js
CHANGED
|
@@ -2,11 +2,12 @@ import Generator from 'yeoman-generator';
|
|
|
2
2
|
import RepoAppDownloadLogger from '../utils/logger.js';
|
|
3
3
|
import { AppWizard, Prompts, MessageType } from '@sap-devx/yeoman-ui-types';
|
|
4
4
|
import { isInternalFeaturesSettingEnabled } from '@sap-ux/feature-toggle';
|
|
5
|
-
import {
|
|
5
|
+
import { extractedFilePath, generatorName, defaultAnswers, qfaJsonFileName, downloadTypeConfig } from '../utils/constants.js';
|
|
6
6
|
import { t } from '../utils/i18n.js';
|
|
7
7
|
import { extractZip } from '../utils/download-utils.js';
|
|
8
8
|
import { EventName } from '../telemetryEvents/index.js';
|
|
9
9
|
import { getDefaultTargetFolder, generateAppGenInfo, sendTelemetry, TelemetryHelper, isCli, setYeomanEnvConflicterForce } from '@sap-ux/fiori-generator-shared';
|
|
10
|
+
import { AppDownloadType, PromptNames } from './types.js';
|
|
10
11
|
import { getPrompts } from '../prompts/prompts.js';
|
|
11
12
|
import { generate, TemplateType } from '@sap-ux/fiori-elements-writer';
|
|
12
13
|
import { join, basename } from 'node:path';
|
|
@@ -19,9 +20,9 @@ import { OdataVersion } from '@sap-ux/odata-service-inquirer';
|
|
|
19
20
|
import { writeApplicationInfoSettings } from '@sap-ux/fiori-tools-settings';
|
|
20
21
|
import { generate as generateDeployConfig } from '@sap-ux/abap-deploy-config-writer';
|
|
21
22
|
import { PromptState } from '../prompts/prompt-state.js';
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
24
|
-
import { makeValidJson } from '../utils/file-helpers.js';
|
|
23
|
+
import { getAppConfig, getAdtDeployConfig } from './app-config-quick-deploy.js';
|
|
24
|
+
import { getAbapRepoAppConfig, getAbapRepoDeployConfig } from './app-config-abap-repo.js';
|
|
25
|
+
import { makeValidJson, processDebugArtifacts, addPackageJsonIfNotFound } from '../utils/file-helpers.js';
|
|
25
26
|
import { replaceWebappFiles, validateAndUpdateManifestUI5Version } from '../utils/updates.js';
|
|
26
27
|
import { getYUIDetails } from '../prompts/prompt-helpers.js';
|
|
27
28
|
import { isValidPromptState, validateQfaJsonFile } from '../utils/validators.js';
|
|
@@ -34,12 +35,14 @@ export default class extends Generator {
|
|
|
34
35
|
appWizard;
|
|
35
36
|
vscode;
|
|
36
37
|
appRootPath;
|
|
37
|
-
prompts;
|
|
38
38
|
answers = defaultAnswers;
|
|
39
|
+
downloadType;
|
|
40
|
+
prompts;
|
|
39
41
|
options;
|
|
40
42
|
projectPath;
|
|
41
43
|
extractedProjectPath;
|
|
42
44
|
debugOptions;
|
|
45
|
+
deployConfig;
|
|
43
46
|
setPromptsCallback;
|
|
44
47
|
/**
|
|
45
48
|
* Constructor for Downloading App.
|
|
@@ -54,11 +57,10 @@ export default class extends Generator {
|
|
|
54
57
|
this.vscode = opts.vscode;
|
|
55
58
|
this.appRootPath = opts?.appRootPath ?? getDefaultTargetFolder(this.vscode) ?? this.destinationRoot();
|
|
56
59
|
this.options = opts;
|
|
60
|
+
this.downloadType = opts.data?.appDownloadType ?? AppDownloadType.ADTQuickDeploy;
|
|
57
61
|
// Configure logging
|
|
58
62
|
RepoAppDownloadLogger.configureLogging(this.rootGeneratorName(), this.log, this.options.logWrapper, this.options.logLevel, this.options.logger, this.vscode);
|
|
59
|
-
|
|
60
|
-
this.appWizard.setHeaderTitle(generatorTitle);
|
|
61
|
-
this.prompts = new Prompts(getYUIDetails());
|
|
63
|
+
this.prompts = new Prompts(getYUIDetails(this.downloadType));
|
|
62
64
|
this.setPromptsCallback = (fn) => {
|
|
63
65
|
if (this.prompts) {
|
|
64
66
|
this.prompts.setCallback(fn);
|
|
@@ -85,7 +87,7 @@ export default class extends Generator {
|
|
|
85
87
|
*/
|
|
86
88
|
async prompting() {
|
|
87
89
|
const quickDeployedAppConfig = this.options?.data?.quickDeployedAppConfig;
|
|
88
|
-
const questions = await getPrompts(this.appRootPath, quickDeployedAppConfig, this.appWizard, isCli());
|
|
90
|
+
const questions = await getPrompts(this.appRootPath, quickDeployedAppConfig, this.appWizard, isCli(), this.downloadType);
|
|
89
91
|
const answers = await this.prompt(questions);
|
|
90
92
|
const { targetFolder } = answers;
|
|
91
93
|
if (quickDeployedAppConfig?.appId) {
|
|
@@ -108,6 +110,46 @@ export default class extends Generator {
|
|
|
108
110
|
* Writes the configuration files for the project, including deployment config, and README.
|
|
109
111
|
*/
|
|
110
112
|
async writing() {
|
|
113
|
+
if (this.downloadType === AppDownloadType.AbapRepository) {
|
|
114
|
+
await this._generateAbapRepositoryApp();
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
await this._generateAdtQuickDeployApp();
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Writing phase for ABAP Repository downloads.
|
|
122
|
+
*/
|
|
123
|
+
async _generateAbapRepositoryApp() {
|
|
124
|
+
const webappPath = join(this.projectPath, DirName.Webapp);
|
|
125
|
+
await extractZip(webappPath, this.fs);
|
|
126
|
+
processDebugArtifacts(webappPath, this.fs);
|
|
127
|
+
const appConfig = getAbapRepoAppConfig(webappPath, this.answers.selectedApp, this.fs);
|
|
128
|
+
// If package.json does not exist in the extracted app, add a minimal one with the appId as the package name.
|
|
129
|
+
addPackageJsonIfNotFound(this.projectPath, appConfig.app.id, this.fs);
|
|
130
|
+
// Generate deploy config
|
|
131
|
+
const serviceProvider = PromptState.systemSelection?.connectedSystem?.serviceProvider;
|
|
132
|
+
const context = {
|
|
133
|
+
serviceProvider,
|
|
134
|
+
appDownloadType: AppDownloadType.AbapRepository
|
|
135
|
+
};
|
|
136
|
+
this.deployConfig = await getAbapRepoDeployConfig(this.answers.selectedApp, context);
|
|
137
|
+
if (this.vscode) {
|
|
138
|
+
// Generate Fiori launch config
|
|
139
|
+
const fioriOptions = this._getLaunchConfig(appConfig);
|
|
140
|
+
// Create launch configuration
|
|
141
|
+
await createLaunchConfig(this.projectPath, fioriOptions, this.fs, RepoAppDownloadLogger.logger);
|
|
142
|
+
writeApplicationInfoSettings(this.projectPath);
|
|
143
|
+
}
|
|
144
|
+
// Generate README
|
|
145
|
+
const readMeConfig = this._getReadMeConfig(appConfig);
|
|
146
|
+
generateAppGenInfo(this.projectPath, readMeConfig, this.fs);
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Writing phase for ADT Quick Deploy downloads.
|
|
150
|
+
* Generates a full Fiori project from qfa.json metadata including deploy config.
|
|
151
|
+
*/
|
|
152
|
+
async _generateAdtQuickDeployApp() {
|
|
111
153
|
await extractZip(this.extractedProjectPath, this.fs);
|
|
112
154
|
// Check if the qfa.json file
|
|
113
155
|
const qfaJsonFilePath = join(this.extractedProjectPath, qfaJsonFileName);
|
|
@@ -115,14 +157,15 @@ export default class extends Generator {
|
|
|
115
157
|
// Generate project files
|
|
116
158
|
validateQfaJsonFile(qfaJson);
|
|
117
159
|
const context = {
|
|
118
|
-
qfaJson
|
|
160
|
+
qfaJson,
|
|
161
|
+
appDownloadType: AppDownloadType.ADTQuickDeploy
|
|
119
162
|
};
|
|
120
163
|
// Generate app config
|
|
121
164
|
const config = await getAppConfig(this.answers.selectedApp, this.extractedProjectPath, context, this.answers.systemSelection, this.fs);
|
|
122
165
|
await generate(this.projectPath, config, this.fs);
|
|
123
166
|
// Generate deploy config
|
|
124
|
-
|
|
125
|
-
await generateDeployConfig(this.projectPath, deployConfig, undefined, this.fs);
|
|
167
|
+
this.deployConfig = await getAdtDeployConfig(context);
|
|
168
|
+
await generateDeployConfig(this.projectPath, this.deployConfig, undefined, this.fs);
|
|
126
169
|
if (this.vscode) {
|
|
127
170
|
// Generate Fiori launch config
|
|
128
171
|
const fioriOptions = this._getLaunchConfig(config);
|
|
@@ -150,7 +193,7 @@ export default class extends Generator {
|
|
|
150
193
|
appName: config.app.id,
|
|
151
194
|
appTitle: config.app.title ?? '',
|
|
152
195
|
appNamespace: config.app.id.substring(0, config.app.id.lastIndexOf('.')),
|
|
153
|
-
appDescription:
|
|
196
|
+
appDescription: downloadTypeConfig[this.downloadType].readMeAppDescription,
|
|
154
197
|
ui5Theme: getDefaultUI5Theme(config.ui5?.version),
|
|
155
198
|
generatorName: generatorName,
|
|
156
199
|
generatorVersion: this.rootGeneratorVersion(),
|
|
@@ -260,7 +303,8 @@ export default class extends Generator {
|
|
|
260
303
|
await runPostAppGenHook({
|
|
261
304
|
path: this.projectPath,
|
|
262
305
|
vscodeInstance: this.vscode,
|
|
263
|
-
postGenCommand: this.options.data?.postGenCommand
|
|
306
|
+
postGenCommand: this.options.data?.postGenCommand,
|
|
307
|
+
deployConfig: this.deployConfig
|
|
264
308
|
});
|
|
265
309
|
}
|
|
266
310
|
}
|
|
@@ -269,7 +313,7 @@ export default class extends Generator {
|
|
|
269
313
|
*/
|
|
270
314
|
async end() {
|
|
271
315
|
try {
|
|
272
|
-
this.appWizard.showInformation(
|
|
316
|
+
this.appWizard.showInformation(downloadTypeConfig[this.downloadType].generatorSuccessMsg, MessageType.notification);
|
|
273
317
|
await this._handlePostAppGeneration();
|
|
274
318
|
await sendTelemetry(EventName.GENERATION_SUCCESS, TelemetryHelper.createTelemetryData({
|
|
275
319
|
appType: 'repo-app-import-sub-generator',
|
|
@@ -1,10 +1,39 @@
|
|
|
1
1
|
import type Generator from 'yeoman-generator';
|
|
2
2
|
import type { AppWizard } from '@sap-devx/yeoman-ui-types';
|
|
3
3
|
import type { VSCodeInstance, TelemetryData, LogWrapper } from '@sap-ux/fiori-generator-shared';
|
|
4
|
-
import type { AppIndex } from '@sap-ux/axios-extension';
|
|
4
|
+
import type { AppIndex, AbapServiceProvider } from '@sap-ux/axios-extension';
|
|
5
5
|
import type { OdataServiceAnswers } from '@sap-ux/odata-service-inquirer';
|
|
6
6
|
import type { YUIQuestion } from '@sap-ux/inquirer-common';
|
|
7
7
|
import type { AutocompleteQuestionOptions } from 'inquirer-autocomplete-prompt';
|
|
8
|
+
/**
|
|
9
|
+
* Identifies which download flow is active.
|
|
10
|
+
* ADTQuickDeploy: app was quick-deployed via ADT; uses qfa.json for config.
|
|
11
|
+
* AbapRepository: app lives in ABAP UI5 repository; config is read from manifest.
|
|
12
|
+
*/
|
|
13
|
+
export declare const AppDownloadType: {
|
|
14
|
+
ADTQuickDeploy: string;
|
|
15
|
+
AbapRepository: string;
|
|
16
|
+
};
|
|
17
|
+
export type AppDownloadType = (typeof AppDownloadType)[keyof typeof AppDownloadType];
|
|
18
|
+
/**
|
|
19
|
+
* Context for the ADT Quick Deploy download flow.
|
|
20
|
+
*/
|
|
21
|
+
export interface AdtQuickDeployContext {
|
|
22
|
+
appDownloadType: typeof AppDownloadType.ADTQuickDeploy;
|
|
23
|
+
qfaJson: QfaJsonConfig;
|
|
24
|
+
serviceProvider?: AbapServiceProvider;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Context for the ABAP Repository download flow.
|
|
28
|
+
*/
|
|
29
|
+
export interface AbapRepositoryContext {
|
|
30
|
+
appDownloadType: typeof AppDownloadType.AbapRepository;
|
|
31
|
+
serviceProvider?: AbapServiceProvider;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Union of download contexts.
|
|
35
|
+
*/
|
|
36
|
+
export type AppDownloadContext = AdtQuickDeployContext | AbapRepositoryContext;
|
|
8
37
|
/**
|
|
9
38
|
* Quick deploy app config are applicable only in scenarios where an application
|
|
10
39
|
* deployed via ADT Quick Deploy is being downloaded from a repository.
|
|
@@ -44,6 +73,8 @@ export interface RepoAppDownloadOptions extends Generator.GeneratorOptions {
|
|
|
44
73
|
telemetryData?: TelemetryData;
|
|
45
74
|
/** Logger instance for logging operations. */
|
|
46
75
|
logWrapper?: LogWrapper;
|
|
76
|
+
/** The type of app download. */
|
|
77
|
+
appDownloadType?: AppDownloadType;
|
|
47
78
|
}
|
|
48
79
|
/**
|
|
49
80
|
* Represents a question in the app download process.
|
package/generators/app/types.js
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Identifies which download flow is active.
|
|
3
|
+
* ADTQuickDeploy: app was quick-deployed via ADT; uses qfa.json for config.
|
|
4
|
+
* AbapRepository: app lives in ABAP UI5 repository; config is read from manifest.
|
|
5
|
+
*/
|
|
6
|
+
export const AppDownloadType = {
|
|
7
|
+
ADTQuickDeploy: 'adtQuickDeploy',
|
|
8
|
+
AbapRepository: 'abapRepository'
|
|
9
|
+
};
|
|
1
10
|
/**
|
|
2
11
|
* Enum representing the names of prompts used in the application download process.
|
|
3
12
|
*/
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import type { AppIndex } from '@sap-ux/axios-extension';
|
|
2
2
|
import type { AppInfo, AppItem } from '../app/types.js';
|
|
3
|
+
import { AppDownloadType } from '../app/types.js';
|
|
3
4
|
import { type ConnectedSystem } from '@sap-ux/odata-service-inquirer';
|
|
4
5
|
/**
|
|
5
6
|
* Returns the details for the YUI prompt.
|
|
6
7
|
*
|
|
8
|
+
* @param downloadType - The type of app download to determine which details to return.
|
|
7
9
|
* @returns step details
|
|
8
10
|
*/
|
|
9
|
-
export declare function getYUIDetails(): {
|
|
11
|
+
export declare function getYUIDetails(downloadType: AppDownloadType): {
|
|
10
12
|
name: string;
|
|
11
13
|
description: string;
|
|
12
14
|
}[];
|
|
@@ -35,7 +37,8 @@ export declare const formatAppChoices: (appList: AppIndex) => Array<{
|
|
|
35
37
|
*
|
|
36
38
|
* @param {ConnectedSystem} connectedSystem - The ABAP service provider.
|
|
37
39
|
* @param {string} appId - Application ID to be downloaded.
|
|
40
|
+
* @param {AppDownloadType} downloadType - The download type determining which search params to use.
|
|
38
41
|
* @returns {Promise<AppIndex>} A list of applications filtered by source template.
|
|
39
42
|
*/
|
|
40
|
-
export declare function fetchAppListForSelectedSystem(connectedSystem: ConnectedSystem, appId?: string): Promise<AppIndex>;
|
|
43
|
+
export declare function fetchAppListForSelectedSystem(connectedSystem: ConnectedSystem, appId?: string, downloadType?: AppDownloadType): Promise<AppIndex>;
|
|
41
44
|
//# sourceMappingURL=prompt-helpers.d.ts.map
|
|
@@ -1,19 +1,17 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { appListResultFields, downloadTypeConfig, generatorTitleConfig, adtSourceTemplateId } from '../utils/constants.js';
|
|
2
|
+
import { AppDownloadType } from '../app/types.js';
|
|
2
3
|
import { PromptState } from './prompt-state.js';
|
|
3
4
|
import { t } from '../utils/i18n.js';
|
|
4
5
|
import RepoAppDownloadLogger from '../utils/logger.js';
|
|
5
6
|
/**
|
|
6
7
|
* Returns the details for the YUI prompt.
|
|
7
8
|
*
|
|
9
|
+
* @param downloadType - The type of app download to determine which details to return.
|
|
8
10
|
* @returns step details
|
|
9
11
|
*/
|
|
10
|
-
export function getYUIDetails() {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
name: generatorTitle,
|
|
14
|
-
description: generatorDescription
|
|
15
|
-
}
|
|
16
|
-
];
|
|
12
|
+
export function getYUIDetails(downloadType) {
|
|
13
|
+
const { title, description } = generatorTitleConfig[downloadType];
|
|
14
|
+
return [{ name: title, description }];
|
|
17
15
|
}
|
|
18
16
|
/**
|
|
19
17
|
* Returns the prompt details for the selected application.
|
|
@@ -66,21 +64,27 @@ export const formatAppChoices = (appList) => {
|
|
|
66
64
|
*
|
|
67
65
|
* @param {AbapServiceProvider} provider - The ABAP service provider.
|
|
68
66
|
* @param {string} appId - Application ID to filter the list.
|
|
67
|
+
* @param {AppDownloadType} downloadType - The download type determining which search params to use.
|
|
69
68
|
* @returns {Promise<AppIndex>} A list of applications filtered by source template.
|
|
70
69
|
*/
|
|
71
|
-
async function getAppList(provider, appId) {
|
|
70
|
+
async function getAppList(provider, appId, downloadType = AppDownloadType.ADTQuickDeploy) {
|
|
72
71
|
try {
|
|
72
|
+
const baseSearchParams = downloadTypeConfig[downloadType].searchParams;
|
|
73
73
|
const searchParams = appId
|
|
74
74
|
? {
|
|
75
|
-
...
|
|
75
|
+
...baseSearchParams,
|
|
76
76
|
'sap.app/id': appId
|
|
77
77
|
}
|
|
78
|
-
:
|
|
79
|
-
|
|
78
|
+
: baseSearchParams;
|
|
79
|
+
const results = await provider.getAppIndex().search(searchParams, appListResultFields);
|
|
80
|
+
if (downloadType === AppDownloadType.AbapRepository) {
|
|
81
|
+
// For ABAP Repository downloads, filter out apps with the ADT source template as they follow the quick deploy app download flow.
|
|
82
|
+
return results.filter((app) => app['sap.app/sourceTemplate/id'] !== adtSourceTemplateId);
|
|
83
|
+
}
|
|
84
|
+
return results;
|
|
80
85
|
}
|
|
81
86
|
catch (error) {
|
|
82
87
|
RepoAppDownloadLogger.logger?.error(t('error.applicationListFetchError', { error: error.message }));
|
|
83
|
-
RepoAppDownloadLogger.logger?.debug(t('error.applicationListFetchError', { error: JSON.stringify(error) }));
|
|
84
88
|
return [];
|
|
85
89
|
}
|
|
86
90
|
}
|
|
@@ -89,14 +93,15 @@ async function getAppList(provider, appId) {
|
|
|
89
93
|
*
|
|
90
94
|
* @param {ConnectedSystem} connectedSystem - The ABAP service provider.
|
|
91
95
|
* @param {string} appId - Application ID to be downloaded.
|
|
96
|
+
* @param {AppDownloadType} downloadType - The download type determining which search params to use.
|
|
92
97
|
* @returns {Promise<AppIndex>} A list of applications filtered by source template.
|
|
93
98
|
*/
|
|
94
|
-
export async function fetchAppListForSelectedSystem(connectedSystem, appId) {
|
|
99
|
+
export async function fetchAppListForSelectedSystem(connectedSystem, appId, downloadType = AppDownloadType.ADTQuickDeploy) {
|
|
95
100
|
if (connectedSystem?.serviceProvider) {
|
|
96
101
|
PromptState.systemSelection = {
|
|
97
102
|
connectedSystem: connectedSystem
|
|
98
103
|
};
|
|
99
|
-
return await getAppList(connectedSystem.serviceProvider, appId);
|
|
104
|
+
return await getAppList(connectedSystem.serviceProvider, appId, downloadType);
|
|
100
105
|
}
|
|
101
106
|
return [];
|
|
102
107
|
}
|