@sap-ux/repo-app-import-sub-generator 1.2.73 → 1.2.75

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.
@@ -2,7 +2,7 @@ import { TemplateType } from '@sap-ux/fiori-elements-writer';
2
2
  import { OdataVersion } from '@sap-ux/odata-service-inquirer';
3
3
  import { t } from '../utils/i18n.js';
4
4
  import { readManifest } from '../utils/file-helpers.js';
5
- import { fioriAppSourcetemplateId, adtSourceTemplateId } from '../utils/constants.js';
5
+ import { fioriAppSourcetemplateId, adtSourceTemplateIds } from '../utils/constants.js';
6
6
  import { PromptState } from '../prompts/prompt-state.js';
7
7
  import RepoAppDownloadLogger from '../utils/logger.js';
8
8
  import { FileName } from '@sap-ux/project-access';
@@ -26,11 +26,11 @@ export async function getAppConfig(app, extractedProjectPath, context, systemSel
26
26
  const manifest = readManifest(join(extractedProjectPath, FileName.Manifest), fs);
27
27
  const serviceProvider = PromptState.systemSelection?.connectedSystem?.serviceProvider;
28
28
  context.serviceProvider = serviceProvider;
29
- if (manifest?.['sap.app']?.sourceTemplate?.id !== adtSourceTemplateId) {
30
- RepoAppDownloadLogger.logger?.error(t('error.readManifestErrors.sourceTemplateNotSupported'));
29
+ if (!adtSourceTemplateIds.includes(manifest?.['sap.app']?.sourceTemplate?.id ?? '')) {
30
+ RepoAppDownloadLogger.logger?.warn(t('error.readManifestErrors.sourceTemplateNotSupported'));
31
31
  }
32
32
  if (!manifest?.['sap.app']?.dataSources) {
33
- RepoAppDownloadLogger.logger?.error(t('error.dataSourcesNotFound'));
33
+ RepoAppDownloadLogger.logger?.warn(t('error.dataSourcesNotFound'));
34
34
  }
35
35
  const odataVersion = manifest?.['sap.app']?.dataSources?.mainService?.settings?.odataVersion?.startsWith('4')
36
36
  ? OdataVersion.v4
@@ -1,4 +1,4 @@
1
- import { appListResultFields, downloadTypeConfig, generatorTitleConfig, adtSourceTemplateId, appListFieldsWithoutSourceTemplate, sourceTemplateIdField } from '../utils/constants.js';
1
+ import { appListResultFields, downloadTypeConfig, generatorTitleConfig, adtSourceTemplateIds, adtSourceTemplateId, adtSourceTemplateIdCorrected, appListFieldsWithoutSourceTemplate, sourceTemplateIdField } from '../utils/constants.js';
2
2
  import { AppDownloadType } from '../app/types.js';
3
3
  import { PromptState } from './prompt-state.js';
4
4
  import { t } from '../utils/i18n.js';
@@ -67,38 +67,78 @@ export const formatAppChoices = (appList) => {
67
67
  * @param {AppDownloadType} downloadType - The download type determining which search parameters to use.
68
68
  * @returns {Promise<AppIndex>} A list of deployed applications. For the ADTQuickDeploy flow, only ADT-deployed apps are returned. For the AbapRepository flow on systems that support it, ADT-deployed apps are excluded.
69
69
  */
70
+ /**
71
+ * Fallback for older ABAP systems that reject sourceTemplate/type search params with HTTP 400.
72
+ * Returns all apps unfiltered — old systems won't have ADT-deployed apps anyway.
73
+ *
74
+ * @param appIndex - The app index instance to search against.
75
+ * @returns All apps without filtering, or an empty array if the retry also fails.
76
+ */
77
+ async function retryAbapAppListFetch(appIndex) {
78
+ try {
79
+ // sap.app/type=application is also dropped — older systems may reject it too.
80
+ // Non-application entries in the list are acceptable; they will fail at the download step.
81
+ const results = await appIndex.search({}, appListFieldsWithoutSourceTemplate);
82
+ RepoAppDownloadLogger.logger?.debug(`Retry succeeded: ${results.length} results`);
83
+ return results;
84
+ }
85
+ catch (retryError) {
86
+ const message = retryError instanceof Error ? retryError.message : String(retryError);
87
+ RepoAppDownloadLogger.logger?.error(t('error.applicationListFetchError', { error: message }));
88
+ return [];
89
+ }
90
+ }
91
+ /**
92
+ * Searches the app index for AbapRepository apps, filtering out ADT-deployed entries.
93
+ *
94
+ * @param appIndex - The app index instance to search against.
95
+ * @param appId - Optional app ID to narrow the search.
96
+ * @returns Filtered app list excluding any ADT source template IDs.
97
+ */
98
+ async function searchAbapRepositoryApps(appIndex, appId) {
99
+ const base = downloadTypeConfig[AppDownloadType.AbapRepository].searchParams;
100
+ const searchParams = appId ? { ...base, 'sap.app/id': appId } : base;
101
+ const results = await appIndex.search(searchParams, appListResultFields);
102
+ const filtered = results.filter((app) => !adtSourceTemplateIds.includes(app[sourceTemplateIdField]));
103
+ RepoAppDownloadLogger.logger?.debug(`App list fetched: ${results.length} total, ${filtered.length} after filtering out ADT-deployed apps`);
104
+ return filtered;
105
+ }
106
+ /**
107
+ * Searches the app index for ADTQuickDeploy apps using both legacy and corrected template IDs concurrently.
108
+ * The app index API does not support OR filters, so two parallel searches are required.
109
+ *
110
+ * @param appIndex - The app index instance to search against.
111
+ * @param appId - Optional app ID to narrow the search.
112
+ * @returns Deduplicated app list from both template ID searches.
113
+ */
114
+ async function searchAdtQuickDeployApps(appIndex, appId) {
115
+ const buildSearchParams = (templateId) => ({
116
+ [sourceTemplateIdField]: templateId,
117
+ ...(appId ? { 'sap.app/id': appId } : {})
118
+ });
119
+ const [legacyResults, correctedResults] = await Promise.all([
120
+ appIndex.search(buildSearchParams(adtSourceTemplateId), appListResultFields),
121
+ appIndex.search(buildSearchParams(adtSourceTemplateIdCorrected), appListResultFields)
122
+ ]);
123
+ // An app can only carry one template ID at a time, so duplicates should not occur in practice.
124
+ // Dedup by sap.app/id as a safeguard against unexpected backend behaviour.
125
+ const legacyAppIds = new Set(legacyResults.map((app) => app['sap.app/id']));
126
+ return [...legacyResults, ...correctedResults.filter((app) => !legacyAppIds.has(app['sap.app/id']))];
127
+ }
70
128
  async function getAppList(provider, appId, downloadType = AppDownloadType.ADTQuickDeploy) {
71
- const baseSearchParams = downloadTypeConfig[downloadType].searchParams;
72
- const searchParams = appId ? { ...baseSearchParams, 'sap.app/id': appId } : baseSearchParams;
129
+ const appIndex = provider.getAppIndex();
73
130
  try {
74
- const results = await provider.getAppIndex().search(searchParams, appListResultFields);
75
131
  if (downloadType === AppDownloadType.AbapRepository) {
76
- // For ABAP Repository downloads, filter out apps with the ADT source template as they follow the quick deploy app download flow.
77
- const filtered = results.filter((app) => app[sourceTemplateIdField] !== adtSourceTemplateId);
78
- RepoAppDownloadLogger.logger?.debug(`App list fetched: ${results.length} total, ${filtered.length} after filtering out ADT-deployed apps`);
79
- return filtered;
132
+ return await searchAbapRepositoryApps(appIndex, appId);
80
133
  }
81
- return results;
134
+ return await searchAdtQuickDeployApps(appIndex, appId);
82
135
  }
83
136
  catch (error) {
84
137
  if (downloadType === AppDownloadType.AbapRepository &&
85
138
  error?.response?.status === 400) {
86
139
  // Older systems may not support sourceTemplateIdField or the sap.app/type search param.
87
- // Retry with no search params and without sourceTemplateIdField — return all results as-is
88
- // since old systems won't have ADT-deployed apps to filter out anyway.
89
140
  RepoAppDownloadLogger.logger?.debug(`Retrying without ${sourceTemplateIdField} and search params`);
90
- try {
91
- // sap.app/type=application is also dropped — older systems may reject it too.
92
- // Non-application entries in the list are acceptable; they will fail at the download step.
93
- const retryResults = await provider.getAppIndex().search({}, appListFieldsWithoutSourceTemplate);
94
- RepoAppDownloadLogger.logger?.debug(`Retry succeeded: ${retryResults.length} results`);
95
- return retryResults;
96
- }
97
- catch (retryError) {
98
- const retryMessage = retryError instanceof Error ? retryError.message : String(retryError);
99
- RepoAppDownloadLogger.logger?.error(t('error.applicationListFetchError', { error: retryMessage }));
100
- return [];
101
- }
141
+ return retryAbapAppListFetch(appIndex);
102
142
  }
103
143
  const message = error instanceof Error ? error.message : String(error);
104
144
  RepoAppDownloadLogger.logger?.error(t('error.applicationListFetchError', { error: message }));
@@ -7,6 +7,8 @@ export interface DownloadTypeConfig {
7
7
  searchParams: Record<string, string>;
8
8
  }
9
9
  export declare const adtSourceTemplateId = "@sap.adt.sevicebinding.deploy:lrop";
10
+ export declare const adtSourceTemplateIdCorrected = "@sap.adt.servicebinding.deploy:lrop";
11
+ export declare const adtSourceTemplateIds: readonly string[];
10
12
  export declare const sourceTemplateIdField = "sap.app/sourceTemplate/id";
11
13
  /**
12
14
  * Title and configuration of the description per download flow, used in the constructor
@@ -4,6 +4,10 @@ import { AppDownloadType } from '../app/types.js';
4
4
  import { t } from './i18n.js';
5
5
  // The source template ID used for filtering the apps in the repository
6
6
  export const adtSourceTemplateId = '@sap.adt.sevicebinding.deploy:lrop';
7
+ // Corrected spelling introduced; both IDs must be recognised during the transition period.
8
+ export const adtSourceTemplateIdCorrected = '@sap.adt.servicebinding.deploy:lrop';
9
+ // Both ADT source template IDs (typo and corrected) for backward-compatible matching.
10
+ export const adtSourceTemplateIds = [adtSourceTemplateId, adtSourceTemplateIdCorrected];
7
11
  // The app index field name for the source template ID
8
12
  export const sourceTemplateIdField = 'sap.app/sourceTemplate/id';
9
13
  /**
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.73",
4
+ "version": "1.2.75",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "https://github.com/SAP/open-ux-tools.git",
@@ -25,11 +25,13 @@
25
25
  "i18next": "26.3.6",
26
26
  "inquirer": "8.2.7",
27
27
  "yeoman-generator": "5.10.0",
28
+ "@sap-ux/feature-toggle": "1.0.5",
28
29
  "@sap-ux/fiori-generator-shared": "1.2.19",
29
30
  "@sap-ux/inquirer-common": "1.0.45",
30
31
  "@sap-ux/project-access": "2.2.2",
31
32
  "@sap-ux/odata-service-inquirer": "3.2.23",
32
- "@sap-ux/feature-toggle": "1.0.5",
33
+ "@sap-ux/fiori-elements-writer": "3.1.71",
34
+ "@sap-ux/fiori-freestyle-writer": "3.0.116",
33
35
  "@sap-ux/logger": "1.0.3",
34
36
  "@sap-ux/project-input-validator": "1.0.22",
35
37
  "@sap-ux/launch-config": "1.0.23",
@@ -40,9 +42,7 @@
40
42
  "@sap-ux/axios-extension": "2.1.0",
41
43
  "@sap-ux/store": "2.0.7",
42
44
  "@sap-ux/system-access": "1.0.14",
43
- "@sap-ux/guided-answers-helper": "1.0.2",
44
- "@sap-ux/fiori-elements-writer": "3.1.70",
45
- "@sap-ux/fiori-freestyle-writer": "3.0.115"
45
+ "@sap-ux/guided-answers-helper": "1.0.2"
46
46
  },
47
47
  "devDependencies": {
48
48
  "@jest/globals": "30.4.1",