@sap-ux/repo-app-import-sub-generator 1.2.90 → 1.2.92
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/index.d.ts +2 -1
- package/generators/app/index.js +10 -2
- package/generators/prompts/prompt-helpers.js +17 -11
- package/generators/translations/repo-app-import-sub-generator.i18n.json +3 -1
- package/generators/utils/constants.js +3 -2
- package/generators/utils/download-utils.d.ts +2 -0
- package/generators/utils/download-utils.js +25 -4
- package/package.json +15 -15
|
@@ -10,7 +10,8 @@ export default class extends Generator {
|
|
|
10
10
|
private readonly vscode?;
|
|
11
11
|
private readonly appRootPath;
|
|
12
12
|
private readonly answers;
|
|
13
|
-
private
|
|
13
|
+
private downloadType;
|
|
14
|
+
private readonly downloadTypeExplicit;
|
|
14
15
|
private readonly prompts;
|
|
15
16
|
options: RepoAppDownloadOptions;
|
|
16
17
|
private projectPath;
|
package/generators/app/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import { AppWizard, Prompts, MessageType } from '@sap-devx/yeoman-ui-types';
|
|
|
4
4
|
import { isInternalFeaturesSettingEnabled } from '@sap-ux/feature-toggle';
|
|
5
5
|
import { extractedFilePath, generatorName, defaultAnswers, qfaJsonFileName, downloadTypeConfig } from '../utils/constants.js';
|
|
6
6
|
import { t } from '../utils/i18n.js';
|
|
7
|
-
import { extractZip } from '../utils/download-utils.js';
|
|
7
|
+
import { extractZip, hasQfaJson } from '../utils/download-utils.js';
|
|
8
8
|
import { EventName } from '../telemetryEvents/index.js';
|
|
9
9
|
import { getDefaultTargetFolder, generateAppGenInfo, sendTelemetry, TelemetryHelper, isCli, setYeomanEnvConflicterForce, getFloorplanLabel } from '@sap-ux/fiori-generator-shared';
|
|
10
10
|
import { AppDownloadType, PromptNames } from './types.js';
|
|
@@ -37,6 +37,7 @@ export default class extends Generator {
|
|
|
37
37
|
appRootPath;
|
|
38
38
|
answers = defaultAnswers;
|
|
39
39
|
downloadType;
|
|
40
|
+
downloadTypeExplicit;
|
|
40
41
|
prompts;
|
|
41
42
|
options;
|
|
42
43
|
projectPath;
|
|
@@ -58,6 +59,7 @@ export default class extends Generator {
|
|
|
58
59
|
this.appRootPath = opts?.appRootPath ?? getDefaultTargetFolder(this.vscode) ?? this.destinationRoot();
|
|
59
60
|
this.options = opts;
|
|
60
61
|
this.downloadType = opts.data?.appDownloadType ?? AppDownloadType.ADTQuickDeploy;
|
|
62
|
+
this.downloadTypeExplicit = opts.data?.appDownloadType !== undefined;
|
|
61
63
|
// Configure logging
|
|
62
64
|
RepoAppDownloadLogger.configureLogging(this.rootGeneratorName(), this.log, this.options.logWrapper, this.options.logLevel, this.options.logger, this.vscode);
|
|
63
65
|
this.prompts = new Prompts(getYUIDetails(this.downloadType));
|
|
@@ -110,8 +112,14 @@ export default class extends Generator {
|
|
|
110
112
|
* Writes the configuration files for the project, including deployment config, and README.
|
|
111
113
|
*/
|
|
112
114
|
async writing() {
|
|
115
|
+
// hasQfaJson() is the authoritative signal: qfa.json is only present in ADT Quick Deploy apps.
|
|
116
|
+
// When downloadType was not explicitly set (CLI invocation defaults to ADTQuickDeploy),
|
|
117
|
+
// use qfa.json presence to decide which flow to run.
|
|
118
|
+
const isAdtQuickDeploy = this.downloadType === AppDownloadType.ADTQuickDeploy && (this.downloadTypeExplicit || hasQfaJson());
|
|
119
|
+
// Resolve the effective type so all post-writing phases (README, telemetry, success msg) are consistent.
|
|
120
|
+
this.downloadType = isAdtQuickDeploy ? AppDownloadType.ADTQuickDeploy : AppDownloadType.AbapRepository;
|
|
113
121
|
try {
|
|
114
|
-
if (
|
|
122
|
+
if (!isAdtQuickDeploy) {
|
|
115
123
|
await this._generateAbapRepositoryApp();
|
|
116
124
|
}
|
|
117
125
|
else {
|
|
@@ -69,18 +69,21 @@ export const formatAppChoices = (appList) => {
|
|
|
69
69
|
*/
|
|
70
70
|
/**
|
|
71
71
|
* Fallback for older ABAP systems that reject sourceTemplate/type search params with HTTP 400.
|
|
72
|
-
*
|
|
72
|
+
* Fetches the full unfiltered list and then applies client-side appId filtering if provided,
|
|
73
|
+
* since older systems cannot handle server-side field filtering.
|
|
73
74
|
*
|
|
74
75
|
* @param appIndex - The app index instance to search against.
|
|
75
|
-
* @
|
|
76
|
+
* @param appId - Optional app ID to filter results client-side.
|
|
77
|
+
* @returns Matching apps (or all apps when appId is omitted), or an empty array if the retry also fails.
|
|
76
78
|
*/
|
|
77
|
-
async function
|
|
79
|
+
async function retryAppListFetchForOlderSystems(appIndex, appId) {
|
|
78
80
|
try {
|
|
79
81
|
// sap.app/type=application is also dropped — older systems may reject it too.
|
|
80
82
|
// Non-application entries in the list are acceptable; they will fail at the download step.
|
|
81
83
|
const results = await appIndex.search({}, appListFieldsWithoutSourceTemplate);
|
|
82
|
-
|
|
83
|
-
|
|
84
|
+
const filtered = appId ? results.filter((app) => app['sap.app/id'] === appId) : results;
|
|
85
|
+
RepoAppDownloadLogger.logger?.debug(`Retry succeeded: ${filtered.length} results`);
|
|
86
|
+
return filtered;
|
|
84
87
|
}
|
|
85
88
|
catch (retryError) {
|
|
86
89
|
const message = retryError instanceof Error ? retryError.message : String(retryError);
|
|
@@ -134,13 +137,16 @@ async function getAppList(provider, appId, downloadType = AppDownloadType.ADTQui
|
|
|
134
137
|
return await searchAdtQuickDeployApps(appIndex, appId);
|
|
135
138
|
}
|
|
136
139
|
catch (error) {
|
|
137
|
-
|
|
138
|
-
error?.response?.status === 400) {
|
|
139
|
-
// Older systems may not support sourceTemplateIdField or the sap.app/type search param.
|
|
140
|
-
RepoAppDownloadLogger.logger?.debug(`Retrying without ${sourceTemplateIdField} and search params`);
|
|
141
|
-
return retryAbapAppListFetch(appIndex);
|
|
142
|
-
}
|
|
140
|
+
const status = error?.response?.status;
|
|
143
141
|
const message = error instanceof Error ? error.message : String(error);
|
|
142
|
+
// Older systems rejects unknown fields either as HTTP 400 or with an "unknown column" error message
|
|
143
|
+
const isOlderSystemError = status === 400 || /column.*unknown|unknown.*column/i.test(message);
|
|
144
|
+
if (isOlderSystemError) {
|
|
145
|
+
// Older systems reject sap.app/sourceTemplate/id as an unknown column.
|
|
146
|
+
// Both flows send it — ADTQuickDeploy as a search param, AbapRepository as a result field.
|
|
147
|
+
RepoAppDownloadLogger.logger?.debug(`Retrying without ${sourceTemplateIdField} and search params (original error: ${message})`);
|
|
148
|
+
return retryAppListFetchForOlderSystems(appIndex, appId);
|
|
149
|
+
}
|
|
144
150
|
RepoAppDownloadLogger.logger?.error(t('error.applicationListFetchError', { error: message }));
|
|
145
151
|
return [];
|
|
146
152
|
}
|
|
@@ -10,7 +10,9 @@
|
|
|
10
10
|
"writingPhase": "An error occurred in the writing phase: {{- error}}. For more information, view the logs.",
|
|
11
11
|
"errorProcessingJsonFile": "An error occurred when processing the JSON file: {{- error}}. Ensure that the file is valid.",
|
|
12
12
|
"noAppsDeployed": "No applications deployed to this system can be downloaded.",
|
|
13
|
-
"appDownloadFailed": "The application
|
|
13
|
+
"appDownloadFailed": "The application could not be downloaded. The ABAP system does not support any available download method.",
|
|
14
|
+
"adtFallbackDownload": "ZIP download is not supported on this system. Falling back to downloading from the ADT file store.",
|
|
15
|
+
"adtFallbackDownloadFailed": "Downloading from the ADT file store failed: {{- error}}",
|
|
14
16
|
"validationErrors": {
|
|
15
17
|
"invalidMetadataPackage": "Invalid or missing package in the metadata. Check the metadata.",
|
|
16
18
|
"invalidServiceName": "Invalid or missing `serviceName` in `serviceBindingDetails`. Check the `serviceName`.",
|
|
@@ -78,6 +78,7 @@ export const appListResultFields = [
|
|
|
78
78
|
'fileType',
|
|
79
79
|
'url'
|
|
80
80
|
];
|
|
81
|
-
// Fallback for older systems that reject
|
|
82
|
-
|
|
81
|
+
// Fallback for older systems (e.g. ABAP 731) that reject unknown columns with HTTP 400.
|
|
82
|
+
// Drops sourceTemplateIdField and fileType, which older app index versions do not support.
|
|
83
|
+
export const appListFieldsWithoutSourceTemplate = appListResultFields.filter((field) => field !== sourceTemplateIdField && field !== 'fileType');
|
|
83
84
|
//# sourceMappingURL=constants.js.map
|
|
@@ -24,6 +24,8 @@ export declare function hasQfaJson(): boolean;
|
|
|
24
24
|
export declare function extractZip(extractedProjectPath: string, fs: Editor): Promise<void>;
|
|
25
25
|
/**
|
|
26
26
|
* Downloads application files from the ABAP repository.
|
|
27
|
+
* First attempts download via ABAP_REPOSITORY_SRV (requires SAP_UI 754+).
|
|
28
|
+
* Falls back to ADT FileStoreService on older systems.
|
|
27
29
|
*
|
|
28
30
|
* @param {string} repoName - The repository name of the application.
|
|
29
31
|
* @returns `{ success: true }` on success, or `{ success: false, errorMessage }` if the server
|
|
@@ -3,7 +3,7 @@ import { PromptState } from '../prompts/prompt-state.js';
|
|
|
3
3
|
import { t } from './i18n.js';
|
|
4
4
|
import RepoAppDownloadLogger from '../utils/logger.js';
|
|
5
5
|
import { qfaJsonFileName } from './constants.js';
|
|
6
|
-
import { TransportChecksService } from '@sap-ux/axios-extension';
|
|
6
|
+
import { TransportChecksService, FileStoreService } from '@sap-ux/axios-extension';
|
|
7
7
|
import { restoreServiceProviderLoggers } from '@sap-ux/fiori-generator-shared';
|
|
8
8
|
/**
|
|
9
9
|
* Fetches the metadata of a given service from the provided ABAP service provider.
|
|
@@ -57,6 +57,8 @@ export async function extractZip(extractedProjectPath, fs) {
|
|
|
57
57
|
}
|
|
58
58
|
/**
|
|
59
59
|
* Downloads application files from the ABAP repository.
|
|
60
|
+
* First attempts download via ABAP_REPOSITORY_SRV (requires SAP_UI 754+).
|
|
61
|
+
* Falls back to ADT FileStoreService on older systems.
|
|
60
62
|
*
|
|
61
63
|
* @param {string} repoName - The repository name of the application.
|
|
62
64
|
* @returns `{ success: true }` on success, or `{ success: false, errorMessage }` if the server
|
|
@@ -64,10 +66,30 @@ export async function extractZip(extractedProjectPath, fs) {
|
|
|
64
66
|
*/
|
|
65
67
|
export async function downloadApp(repoName) {
|
|
66
68
|
const serviceProvider = PromptState.systemSelection?.connectedSystem?.serviceProvider;
|
|
67
|
-
const ui5AbapRepository =
|
|
69
|
+
const ui5AbapRepository = serviceProvider.getUi5AbapRepository();
|
|
68
70
|
ui5AbapRepository.log = RepoAppDownloadLogger.logger;
|
|
69
71
|
RepoAppDownloadLogger.logger?.debug(`App download started: ${repoName}`);
|
|
70
|
-
|
|
72
|
+
let downloadedAppPackage;
|
|
73
|
+
try {
|
|
74
|
+
downloadedAppPackage = await ui5AbapRepository.downloadFiles(repoName);
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
// ABAP_REPOSITORY_SRV may not be available on older systems (e.g. ABAP 731 / SAP_UI < 754).
|
|
78
|
+
// Fall through to the ADT FileStoreService fallback below.
|
|
79
|
+
RepoAppDownloadLogger.logger?.debug(`ABAP_REPOSITORY_SRV unavailable, falling back to ADT: ${error.message}`);
|
|
80
|
+
}
|
|
81
|
+
if (!downloadedAppPackage || downloadedAppPackage.length === 0) {
|
|
82
|
+
RepoAppDownloadLogger.logger?.debug(t('error.adtFallbackDownload'));
|
|
83
|
+
try {
|
|
84
|
+
const fileStoreService = await serviceProvider.getAdtService(FileStoreService);
|
|
85
|
+
if (fileStoreService) {
|
|
86
|
+
downloadedAppPackage = await ui5AbapRepository.downloadFilesViaAdt(repoName, fileStoreService);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
RepoAppDownloadLogger.logger?.error(t('error.adtFallbackDownloadFailed', { error: error.message }));
|
|
91
|
+
}
|
|
92
|
+
}
|
|
71
93
|
if (!downloadedAppPackage || downloadedAppPackage.length === 0) {
|
|
72
94
|
// Legacy ABAP systems may return empty content rather than an error response.
|
|
73
95
|
const errorMessage = t('error.appDownloadFailed');
|
|
@@ -75,7 +97,6 @@ export async function downloadApp(repoName) {
|
|
|
75
97
|
return { success: false, errorMessage };
|
|
76
98
|
}
|
|
77
99
|
RepoAppDownloadLogger.logger?.debug(`App download completed: ${repoName}`);
|
|
78
|
-
// store downloaded package in prompt state
|
|
79
100
|
PromptState.admZip = downloadedAppPackage;
|
|
80
101
|
return { success: true };
|
|
81
102
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sap-ux/repo-app-import-sub-generator",
|
|
3
3
|
"description": "Generator to download LROP Fiori applications deployed from an ABAP repository.",
|
|
4
|
-
"version": "1.2.
|
|
4
|
+
"version": "1.2.92",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "https://github.com/SAP/open-ux-tools.git",
|
|
@@ -25,24 +25,24 @@
|
|
|
25
25
|
"i18next": "26.3.6",
|
|
26
26
|
"inquirer": "8.2.7",
|
|
27
27
|
"yeoman-generator": "5.10.0",
|
|
28
|
-
"@sap-ux/
|
|
29
|
-
"@sap-ux/
|
|
30
|
-
"@sap-ux/inquirer
|
|
31
|
-
"@sap-ux/project-access": "2.3.
|
|
32
|
-
"@sap-ux/
|
|
33
|
-
"@sap-ux/fiori-
|
|
34
|
-
"@sap-ux/fiori-freestyle-writer": "3.0.128",
|
|
28
|
+
"@sap-ux/fiori-generator-shared": "1.2.24",
|
|
29
|
+
"@sap-ux/inquirer-common": "1.0.50",
|
|
30
|
+
"@sap-ux/odata-service-inquirer": "3.2.28",
|
|
31
|
+
"@sap-ux/project-access": "2.3.2",
|
|
32
|
+
"@sap-ux/fiori-elements-writer": "3.1.87",
|
|
33
|
+
"@sap-ux/fiori-freestyle-writer": "3.0.130",
|
|
35
34
|
"@sap-ux/logger": "1.0.3",
|
|
36
|
-
"@sap-ux/project-input-validator": "1.0.
|
|
37
|
-
"@sap-ux/launch-config": "1.0.
|
|
35
|
+
"@sap-ux/project-input-validator": "1.0.25",
|
|
36
|
+
"@sap-ux/launch-config": "1.0.26",
|
|
38
37
|
"@sap-ux/fiori-tools-settings": "1.1.1",
|
|
39
|
-
"@sap-ux/abap-deploy-config-writer": "1.0.
|
|
38
|
+
"@sap-ux/abap-deploy-config-writer": "1.0.34",
|
|
40
39
|
"@sap-ux/btp-utils": "2.0.8",
|
|
41
40
|
"@sap-ux/ui5-info": "1.0.7",
|
|
42
|
-
"@sap-ux/axios-extension": "2.1.
|
|
41
|
+
"@sap-ux/axios-extension": "2.1.4",
|
|
42
|
+
"@sap-ux/system-access": "1.0.18",
|
|
43
43
|
"@sap-ux/store": "2.0.7",
|
|
44
|
-
"@sap-ux/
|
|
45
|
-
"@sap-ux/
|
|
44
|
+
"@sap-ux/guided-answers-helper": "1.0.2",
|
|
45
|
+
"@sap-ux/feature-toggle": "1.0.5"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
48
|
"@jest/globals": "30.4.1",
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
"unionfs": "4.6.0",
|
|
68
68
|
"yeoman-environment": "3.19.3",
|
|
69
69
|
"yeoman-test": "6.3.0",
|
|
70
|
-
"@sap-ux/nodejs-utils": "1.0.
|
|
70
|
+
"@sap-ux/nodejs-utils": "1.0.13",
|
|
71
71
|
"@sap-ux/store": "2.0.7",
|
|
72
72
|
"@sap-ux/ui5-config": "1.0.10"
|
|
73
73
|
},
|