@ui5/task-adaptation 1.5.3 → 1.6.0-rc.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/.hyperspace/pull_request_bot.json +19 -0
- package/CHANGELOG.md +18 -9
- package/dist/adapters/abapAdapter.d.ts +3 -0
- package/dist/adapters/abapAdapter.js +4 -0
- package/dist/adapters/adapter.d.ts +10 -0
- package/dist/adapters/adapter.js +11 -0
- package/dist/adapters/cfAdapter.d.ts +8 -0
- package/dist/adapters/cfAdapter.js +20 -0
- package/dist/appVariantManager.js +1 -1
- package/dist/baseAppManager.js +3 -3
- package/dist/buildStrategy.d.ts +0 -3
- package/dist/buildStrategy.js +0 -7
- package/dist/bundle.d.ts +4 -3
- package/dist/bundle.js +3663 -3606
- package/dist/cache/cacheHolder.d.ts +1 -1
- package/dist/cache/cacheHolder.js +8 -6
- package/dist/index.js +8 -2
- package/dist/model/authenticationError.d.ts +3 -0
- package/dist/model/authenticationError.js +8 -0
- package/dist/model/types.d.ts +12 -0
- package/dist/previewManager.d.ts +13 -0
- package/dist/previewManager.js +131 -0
- package/dist/processors/abapProcessor.d.ts +3 -0
- package/dist/processors/abapProcessor.js +7 -0
- package/dist/processors/cfProcessor.d.ts +4 -1
- package/dist/processors/cfProcessor.js +15 -1
- package/dist/processors/processor.d.ts +4 -1
- package/dist/repositories/html5RepoManager.d.ts +3 -2
- package/dist/repositories/html5RepoManager.js +18 -5
- package/dist/util/cf/xsAppJsonUtil.d.ts +23 -0
- package/dist/util/cf/xsAppJsonUtil.js +36 -0
- package/dist/util/cfUtil.d.ts +8 -1
- package/dist/util/cfUtil.js +16 -8
- package/dist/util/movingHandler/changeFileMoveHandler.d.ts +8 -0
- package/dist/util/movingHandler/changeFileMoveHandler.js +77 -0
- package/dist/util/resourceUtil.d.ts +11 -3
- package/dist/util/resourceUtil.js +83 -18
- package/eslint.config.js +4 -3
- package/package.json +15 -16
- package/rollup/amdToEsm.ts +22 -0
- package/rollup/bundle.d.ts +25 -0
- package/rollup/bundleDefinition.js +19 -0
- package/rollup/bundler.ts +35 -0
- package/rollup/overrides/sap/base/config.js +59 -0
- package/rollup/overrides/sap/ui/fl/apply/_internal/flexObjects/AppDescriptorChange.js +68 -0
- package/rollup/overrides/sap/ui/performance/Measurement.js +4 -0
- package/rollup/project/package.json +4 -0
- package/rollup/project/ui5.yaml +13 -0
- package/rollup/project/webapp/manifest.json +5 -0
- package/rollup/rollup.ts +133 -0
- package/rollup/ui5Resolve.ts +145 -0
- package/scripts/publish.ts +256 -0
- package/scripts/test-integration-prep.sh +4 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export default class CacheHolder {
|
|
2
2
|
private static TEMP_TASK_DIR;
|
|
3
3
|
private static getTempDir;
|
|
4
|
-
static read(repoName: string, token: string): Map<string, string
|
|
4
|
+
static read(repoName: string, token: string): Promise<Map<string, string>>;
|
|
5
5
|
static write(repoName: string, token: string, files: Map<string, string>): Promise<void>;
|
|
6
6
|
private static isValid;
|
|
7
7
|
/**
|
|
@@ -1,21 +1,22 @@
|
|
|
1
1
|
import * as fs from "fs";
|
|
2
2
|
import * as fsPromises from "fs/promises";
|
|
3
3
|
import * as path from "path";
|
|
4
|
+
import * as os from "node:os";
|
|
4
5
|
import ResourceUtil from "../util/resourceUtil.js";
|
|
5
6
|
import encodeFilename from "filenamify";
|
|
6
7
|
import { getLogger } from "@ui5/logger";
|
|
7
|
-
import tempDir from "temp-dir";
|
|
8
8
|
const log = getLogger("@ui5/task-adaptation::CacheHolder");
|
|
9
9
|
export default class CacheHolder {
|
|
10
10
|
static TEMP_TASK_DIR = "ui5-task-adaptation";
|
|
11
11
|
static getTempDir(...paths) {
|
|
12
|
-
return path.join(
|
|
12
|
+
return path.join(os.tmpdir(), this.TEMP_TASK_DIR, ...paths.map(part => encodeFilename(part, { replacement: "_" })));
|
|
13
13
|
}
|
|
14
14
|
static read(repoName, token) {
|
|
15
15
|
const directory = this.getTempDir(repoName, token);
|
|
16
16
|
if (this.isValid(repoName, "repoName") && this.isValid(token, "token") && fs.existsSync(directory)) {
|
|
17
|
-
return ResourceUtil.
|
|
17
|
+
return ResourceUtil.byGlob(directory, "**/*");
|
|
18
18
|
}
|
|
19
|
+
return Promise.resolve(new Map());
|
|
19
20
|
}
|
|
20
21
|
static async write(repoName, token, files) {
|
|
21
22
|
this.delete(repoName);
|
|
@@ -40,7 +41,7 @@ export default class CacheHolder {
|
|
|
40
41
|
* Clears all cached files
|
|
41
42
|
*/
|
|
42
43
|
static clear() {
|
|
43
|
-
this.deleteDir(path.join(
|
|
44
|
+
this.deleteDir(path.join(os.tmpdir(), this.TEMP_TASK_DIR));
|
|
44
45
|
}
|
|
45
46
|
static deleteDir(directory) {
|
|
46
47
|
if (fs.existsSync(directory)) {
|
|
@@ -67,9 +68,10 @@ export function cached() {
|
|
|
67
68
|
return function (_target, _propertyKey, descriptor) {
|
|
68
69
|
const originalValue = descriptor.value;
|
|
69
70
|
descriptor.value = async function (...args) {
|
|
70
|
-
let files = CacheHolder.read(args[0], args[1]);
|
|
71
|
+
let files = await CacheHolder.read(args[0], args[1]);
|
|
71
72
|
CacheHolder.clearOutdatedExcept(args[0]);
|
|
72
|
-
if (files
|
|
73
|
+
if (files.size === 0) {
|
|
74
|
+
log.verbose(`Cache repo '${args[0]}' with token '${args[1]}' does not contain files. Fetching...`);
|
|
73
75
|
files = await originalValue.apply(this, args);
|
|
74
76
|
await CacheHolder.write(args[0], args[1], files);
|
|
75
77
|
}
|
package/dist/index.js
CHANGED
|
@@ -6,6 +6,7 @@ import I18nMerger from "./util/i18nMerger.js";
|
|
|
6
6
|
import ResourceUtil from "./util/resourceUtil.js";
|
|
7
7
|
import { determineProcessor } from "./processors/processor.js";
|
|
8
8
|
import FilesUtil from "./util/filesUtil.js";
|
|
9
|
+
import PreviewManager from "./previewManager.js";
|
|
9
10
|
/**
|
|
10
11
|
* Creates an appVariant bundle from the provided resources.
|
|
11
12
|
*/
|
|
@@ -14,7 +15,9 @@ export default ({ workspace, options, taskUtil }) => {
|
|
|
14
15
|
async function process(workspace, taskUtil) {
|
|
15
16
|
logBuilderVersion();
|
|
16
17
|
const processor = determineProcessor(options.configuration);
|
|
18
|
+
const adapter = processor.getAdapter();
|
|
17
19
|
const adaptationProject = await AppVariant.fromWorkspace(workspace, options.projectNamespace);
|
|
20
|
+
const previewManagerPromise = PreviewManager.createFromRoot(adaptationProject.reference, processor);
|
|
18
21
|
const appVariantIdHierarchy = await processor.getAppVariantIdHierarchy(adaptationProject.reference);
|
|
19
22
|
if (appVariantIdHierarchy.length === 0) {
|
|
20
23
|
throw new Error(`No app variant found for reference ${adaptationProject.reference}`);
|
|
@@ -35,7 +38,8 @@ export default ({ workspace, options, taskUtil }) => {
|
|
|
35
38
|
appVariant = adaptationProject;
|
|
36
39
|
}
|
|
37
40
|
appVariants.push(appVariant);
|
|
38
|
-
|
|
41
|
+
let adaptedFiles = await baseApp.adapt(appVariant, processor);
|
|
42
|
+
adaptedFiles = await adapter.adapt(adaptedFiles, appVariantFiles);
|
|
39
43
|
return I18nMerger.merge(adaptedFiles, baseApp.i18nPath, appVariant);
|
|
40
44
|
};
|
|
41
45
|
let files = await fetchFilesPromises.reduce(async (previousFiles, currentFiles) => adapt(await previousFiles, await currentFiles), fetchFilesPromises.shift());
|
|
@@ -43,7 +47,9 @@ export default ({ workspace, options, taskUtil }) => {
|
|
|
43
47
|
files = FilesUtil.filter(files);
|
|
44
48
|
files = FilesUtil.rename(files, references);
|
|
45
49
|
adaptationProject.omitDeletedResources(files, options.projectNamespace, taskUtil);
|
|
46
|
-
|
|
50
|
+
// Read libs for preview
|
|
51
|
+
const previewManager = await previewManagerPromise;
|
|
52
|
+
const writePromises = new Array(previewManager.processPreviewResources(files));
|
|
47
53
|
files.forEach((content, filename) => {
|
|
48
54
|
const resource = ResourceUtil.createResource(filename, options.projectNamespace, content);
|
|
49
55
|
writePromises.push(workspace.write(resource));
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export default class AuthenticationError extends Error {
|
|
2
|
+
constructor(details) {
|
|
3
|
+
super(details);
|
|
4
|
+
this.name = "AuthenticationError";
|
|
5
|
+
this.message = "Authentication error. Use 'cf login' to authenticate in Cloud Foundry" + (details ? `: ${details}` : ".");
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=authenticationError.js.map
|
package/dist/model/types.d.ts
CHANGED
|
@@ -85,6 +85,18 @@ export interface IHTML5RepoInfo {
|
|
|
85
85
|
token: string;
|
|
86
86
|
baseUri: string;
|
|
87
87
|
}
|
|
88
|
+
export interface IReuseLibInfo {
|
|
89
|
+
name: string;
|
|
90
|
+
lazy: boolean;
|
|
91
|
+
html5AppHostId: string;
|
|
92
|
+
html5AppName: string;
|
|
93
|
+
html5AppVersion: string;
|
|
94
|
+
html5CacheBusterToken: string;
|
|
95
|
+
url: {
|
|
96
|
+
uri: string;
|
|
97
|
+
final: boolean;
|
|
98
|
+
};
|
|
99
|
+
}
|
|
88
100
|
export interface IAuth {
|
|
89
101
|
username: string;
|
|
90
102
|
password: string;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import IProcessor from "./processors/processor.js";
|
|
2
|
+
export default class PreviewManager {
|
|
3
|
+
private readonly fetchLibsPromises;
|
|
4
|
+
static createFromRoot(appId: string, processor: IProcessor): Promise<PreviewManager>;
|
|
5
|
+
static isPreviewRequested(): boolean;
|
|
6
|
+
private constructor();
|
|
7
|
+
processPreviewResources(baseAppFiles: ReadonlyMap<string, string>): Promise<void>;
|
|
8
|
+
private preReadLibs;
|
|
9
|
+
private searchBaseAppXsAppJsonFile;
|
|
10
|
+
private mergeXsAppJsonFiles;
|
|
11
|
+
private static moveLibraryFiles;
|
|
12
|
+
private static modifyRoutes;
|
|
13
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { getLogger } from "@ui5/logger";
|
|
2
|
+
import ResourceUtil from "./util/resourceUtil.js";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import { merge } from "./util/cf/xsAppJsonUtil.js";
|
|
5
|
+
const log = getLogger("@ui5/task-adaptation::PreviewManager");
|
|
6
|
+
const REUSE_DIR = ".adp/reuse";
|
|
7
|
+
const APP_INFO_FILE = "ui5AppInfo.json";
|
|
8
|
+
const XS_APP_JSON_FILE = "xs-app.json";
|
|
9
|
+
export default class PreviewManager {
|
|
10
|
+
fetchLibsPromises = new Map();
|
|
11
|
+
static async createFromRoot(appId, processor) {
|
|
12
|
+
let ui5AppInfo = "";
|
|
13
|
+
if (PreviewManager.isPreviewRequested()) {
|
|
14
|
+
try {
|
|
15
|
+
ui5AppInfo = await ResourceUtil.readInProject(APP_INFO_FILE);
|
|
16
|
+
}
|
|
17
|
+
catch (_err) {
|
|
18
|
+
log.verbose("Preview mode not requested (env variable ADP_BUILDER_MODE=preview is not set), skipping preview resources processing.");
|
|
19
|
+
throw new Error(`ui5AppInfo.json is missing in project root, cannot process preview resources.`);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return new PreviewManager(appId, ui5AppInfo, processor);
|
|
23
|
+
}
|
|
24
|
+
static isPreviewRequested() {
|
|
25
|
+
return process.env.ADP_BUILDER_MODE === "preview";
|
|
26
|
+
}
|
|
27
|
+
constructor(appId, ui5AppInfo, processor) {
|
|
28
|
+
// If no ui5AppInfo is provided, no preview processing is needed
|
|
29
|
+
if (!ui5AppInfo) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
const appInfo = JSON.parse(ui5AppInfo)[appId];
|
|
33
|
+
if (!appInfo) {
|
|
34
|
+
throw new Error(`No app info found for original app id '${appId}' in ui5AppInfo.json`);
|
|
35
|
+
}
|
|
36
|
+
const reuseLibs = appInfo.asyncHints.libs.filter(lib => lib.html5AppHostId && lib.html5AppName && lib.html5AppVersion);
|
|
37
|
+
if (reuseLibs.length > 0) {
|
|
38
|
+
this.fetchLibsPromises = this.preReadLibs(reuseLibs, processor);
|
|
39
|
+
}
|
|
40
|
+
const logMap = {
|
|
41
|
+
Error: log.error,
|
|
42
|
+
Warning: log.warning,
|
|
43
|
+
Info: log.info,
|
|
44
|
+
debug: log.verbose
|
|
45
|
+
};
|
|
46
|
+
appInfo.messages.forEach((message) => {
|
|
47
|
+
const logger = logMap[message.severity] || log.info;
|
|
48
|
+
logger(`ui5AppInfo.json: ${message.severity} Message: ${message.message} (Error Code: ${message.errorCode})`);
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
async processPreviewResources(baseAppFiles) {
|
|
52
|
+
log.verbose(`Downloading reuse libraries to reuse folder`);
|
|
53
|
+
const xsAppFiles = new Map();
|
|
54
|
+
if (this.fetchLibsPromises.size === 0) {
|
|
55
|
+
log.verbose("No reuse libraries defined in ui5AppInfo.json for preview");
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
const mergedFiles = new Map();
|
|
59
|
+
for (const [libName, libFilesPromise] of this.fetchLibsPromises) {
|
|
60
|
+
const libFiles = await libFilesPromise;
|
|
61
|
+
if (!libFiles || libFiles.size === 0) {
|
|
62
|
+
log.warn(`No files found in reuse library ${libName} for preview`);
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
for (const [filename, content] of libFiles) {
|
|
66
|
+
mergedFiles.set(filename, content);
|
|
67
|
+
if (filename.includes(XS_APP_JSON_FILE)) {
|
|
68
|
+
xsAppFiles.set(filename, content);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
this.searchBaseAppXsAppJsonFile(xsAppFiles, baseAppFiles);
|
|
73
|
+
this.mergeXsAppJsonFiles(xsAppFiles, mergedFiles);
|
|
74
|
+
await ResourceUtil.writeInProject(REUSE_DIR, mergedFiles);
|
|
75
|
+
}
|
|
76
|
+
preReadLibs(reuseLibs, processor) {
|
|
77
|
+
const promises = new Map();
|
|
78
|
+
reuseLibs.forEach(lib => {
|
|
79
|
+
log.info(`Downloading reuse library '${lib.html5AppName}' version '${lib.html5AppVersion}'`);
|
|
80
|
+
const promise = processor
|
|
81
|
+
.fetchReuseLib(lib.html5AppName, lib.html5CacheBusterToken, lib)
|
|
82
|
+
.then(libFiles => PreviewManager.moveLibraryFiles(libFiles, lib.html5AppName, lib.name));
|
|
83
|
+
promises.set(lib.html5AppName, promise);
|
|
84
|
+
});
|
|
85
|
+
return promises;
|
|
86
|
+
}
|
|
87
|
+
searchBaseAppXsAppJsonFile(xsAppFiles, baseAppFiles) {
|
|
88
|
+
const xsAppJsonContent = baseAppFiles.get(XS_APP_JSON_FILE);
|
|
89
|
+
if (xsAppJsonContent) {
|
|
90
|
+
xsAppFiles.set(XS_APP_JSON_FILE, xsAppJsonContent);
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
log.warn("xs-app.json is missing in the downloaded base app files for preview");
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
mergeXsAppJsonFiles(xsAppFiles, files) {
|
|
97
|
+
const mergedXsAppJson = merge([...xsAppFiles.values()]);
|
|
98
|
+
if (mergedXsAppJson) {
|
|
99
|
+
files.set(XS_APP_JSON_FILE, mergedXsAppJson);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
static moveLibraryFiles(inputFiles, libraryName, libId) {
|
|
103
|
+
const files = new Map();
|
|
104
|
+
inputFiles.forEach((content, filename) => {
|
|
105
|
+
const newFilename = path.join(libraryName, filename);
|
|
106
|
+
// Source path in xs-app.json needs to be adjusted to new location
|
|
107
|
+
if (filename.includes(XS_APP_JSON_FILE)) {
|
|
108
|
+
content = PreviewManager.modifyRoutes(content, libraryName, libId);
|
|
109
|
+
}
|
|
110
|
+
files.set(newFilename, content);
|
|
111
|
+
});
|
|
112
|
+
return files;
|
|
113
|
+
}
|
|
114
|
+
;
|
|
115
|
+
static modifyRoutes(xsAppJson, libName, libId) {
|
|
116
|
+
const xsApp = JSON.parse(xsAppJson);
|
|
117
|
+
xsApp.routes = xsApp.routes.map((route) => {
|
|
118
|
+
route.source = route.source.replace(new RegExp("^\\^\\/?(resources/)?"), `^/resources/${libId.replaceAll(".", "/")}/`);
|
|
119
|
+
if (route.service === "html5-apps-repo-rt") {
|
|
120
|
+
route = {
|
|
121
|
+
source: route.source,
|
|
122
|
+
target: route.target,
|
|
123
|
+
localDir: path.join(REUSE_DIR, libName)
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
return route;
|
|
127
|
+
});
|
|
128
|
+
return JSON.stringify(xsApp);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
//# sourceMappingURL=previewManager.js.map
|
|
@@ -3,13 +3,16 @@ import AnnotationManager from "../annotationManager.js";
|
|
|
3
3
|
import IAppVariantIdHierarchyItem from "../model/appVariantIdHierarchyItem.js";
|
|
4
4
|
import { IConfiguration } from "../model/types.js";
|
|
5
5
|
import IProcessor from "./processor.js";
|
|
6
|
+
import { Adapter } from "../adapters/adapter.js";
|
|
6
7
|
export default class AbapProcessor implements IProcessor {
|
|
7
8
|
private abapRepoManager;
|
|
8
9
|
private configuration;
|
|
9
10
|
private annotationManager;
|
|
10
11
|
constructor(configuration: IConfiguration, abapRepoManager: AbapRepoManager, annotationManager: AnnotationManager);
|
|
11
12
|
getAppVariantIdHierarchy(appId: string): Promise<IAppVariantIdHierarchyItem[]>;
|
|
13
|
+
getAdapter(): Adapter;
|
|
12
14
|
fetch(repoName: string, _cachebusterToken: string): Promise<Map<string, string>>;
|
|
15
|
+
fetchReuseLib(): Promise<Map<string, string>>;
|
|
13
16
|
validateConfiguration(): void;
|
|
14
17
|
updateLandscapeSpecificContent(baseAppManifest: any, baseAppFiles: Map<string, string>, appVariantId: string, prefix: string): Promise<void>;
|
|
15
18
|
getConfigurationType(): string;
|
|
@@ -7,6 +7,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
7
7
|
import Language from "../model/language.js";
|
|
8
8
|
import { cached } from "../cache/cacheHolder.js";
|
|
9
9
|
import { validateObject } from "../util/commonUtil.js";
|
|
10
|
+
import AbapAdapter from "../adapters/abapAdapter.js";
|
|
10
11
|
export default class AbapProcessor {
|
|
11
12
|
abapRepoManager;
|
|
12
13
|
configuration;
|
|
@@ -19,9 +20,15 @@ export default class AbapProcessor {
|
|
|
19
20
|
getAppVariantIdHierarchy(appId) {
|
|
20
21
|
return this.abapRepoManager.getAppVariantIdHierarchy(appId);
|
|
21
22
|
}
|
|
23
|
+
getAdapter() {
|
|
24
|
+
return new AbapAdapter();
|
|
25
|
+
}
|
|
22
26
|
fetch(repoName, _cachebusterToken) {
|
|
23
27
|
return this.abapRepoManager.fetch(repoName);
|
|
24
28
|
}
|
|
29
|
+
fetchReuseLib() {
|
|
30
|
+
throw new Error("Preview is not available on SAP S/4HANA On-Premise or Cloud Systems. Please create a ticket on CA-UI5-FL-ADP-BAS component.");
|
|
31
|
+
}
|
|
25
32
|
validateConfiguration() {
|
|
26
33
|
// validate general app config
|
|
27
34
|
const properties = ["appName"];
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import IAppInfo from "../model/appVariantIdHierarchyItem.js";
|
|
2
|
-
import { IConfiguration } from "../model/types.js";
|
|
2
|
+
import { IConfiguration, IReuseLibInfo } from "../model/types.js";
|
|
3
3
|
import IProcessor from "./processor.js";
|
|
4
|
+
import { Adapter } from "../adapters/adapter.js";
|
|
4
5
|
export default class CFProcessor implements IProcessor {
|
|
5
6
|
private configuration;
|
|
6
7
|
constructor(configuration: IConfiguration);
|
|
8
|
+
getAdapter(): Adapter;
|
|
7
9
|
getAppVariantIdHierarchy(appId: string): Promise<IAppInfo[]>;
|
|
8
10
|
fetch(_repoName: string, _cachebusterToken: string): Promise<Map<string, string>>;
|
|
11
|
+
fetchReuseLib(_libName: string, _cachebusterToken: string, lib: IReuseLibInfo): Promise<Map<string, string>>;
|
|
9
12
|
validateConfiguration(): void;
|
|
10
13
|
updateLandscapeSpecificContent(baseAppManifest: any, baseAppFiles: Map<string, string>): Promise<void>;
|
|
11
14
|
private updateXsAppJson;
|
|
@@ -9,12 +9,17 @@ import { cached } from "../cache/cacheHolder.js";
|
|
|
9
9
|
import { validateObject } from "../util/commonUtil.js";
|
|
10
10
|
import CFUtil from "../util/cfUtil.js";
|
|
11
11
|
import { getLogger } from "@ui5/logger";
|
|
12
|
+
import PreviewManager from "../previewManager.js";
|
|
13
|
+
import CFAdapter from "../adapters/cfAdapter.js";
|
|
12
14
|
const log = getLogger("@ui5/task-adaptation::CFProcessor");
|
|
13
15
|
export default class CFProcessor {
|
|
14
16
|
configuration;
|
|
15
17
|
constructor(configuration) {
|
|
16
18
|
this.configuration = configuration;
|
|
17
19
|
}
|
|
20
|
+
getAdapter() {
|
|
21
|
+
return new CFAdapter();
|
|
22
|
+
}
|
|
18
23
|
async getAppVariantIdHierarchy(appId) {
|
|
19
24
|
const metadata = await HTML5RepoManager.getMetadata(this.configuration);
|
|
20
25
|
return [{
|
|
@@ -26,12 +31,18 @@ export default class CFProcessor {
|
|
|
26
31
|
fetch(_repoName, _cachebusterToken) {
|
|
27
32
|
return HTML5RepoManager.getBaseAppFiles(this.configuration);
|
|
28
33
|
}
|
|
34
|
+
fetchReuseLib(_libName, _cachebusterToken, lib) {
|
|
35
|
+
return HTML5RepoManager.getReuseLibFiles(this.configuration, lib);
|
|
36
|
+
}
|
|
29
37
|
validateConfiguration() {
|
|
30
38
|
validateObject(this.configuration, ["appHostId", "appName", "appVersion"], "should be specified in ui5.yaml configuration");
|
|
31
39
|
}
|
|
32
40
|
async updateLandscapeSpecificContent(baseAppManifest, baseAppFiles) {
|
|
33
41
|
this.updateCloudPlatform(baseAppManifest);
|
|
34
|
-
|
|
42
|
+
// Preview uses destinations and does not require xs-app.json updates
|
|
43
|
+
if (!PreviewManager.isPreviewRequested()) {
|
|
44
|
+
await this.updateXsAppJson(baseAppFiles);
|
|
45
|
+
}
|
|
35
46
|
}
|
|
36
47
|
async updateXsAppJson(baseAppFiles) {
|
|
37
48
|
const xsAppJsonContent = baseAppFiles.get("xs-app.json");
|
|
@@ -119,4 +130,7 @@ export default class CFProcessor {
|
|
|
119
130
|
__decorate([
|
|
120
131
|
cached()
|
|
121
132
|
], CFProcessor.prototype, "fetch", null);
|
|
133
|
+
__decorate([
|
|
134
|
+
cached()
|
|
135
|
+
], CFProcessor.prototype, "fetchReuseLib", null);
|
|
122
136
|
//# sourceMappingURL=cfProcessor.js.map
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import IAppVariantIdHierarchyItem from "../model/appVariantIdHierarchyItem.js";
|
|
2
|
-
import { IConfiguration } from "../model/types.js";
|
|
2
|
+
import { IConfiguration, IReuseLibInfo } from "../model/types.js";
|
|
3
|
+
import { Adapter } from "../adapters/adapter.js";
|
|
3
4
|
export default interface IProcessor {
|
|
4
5
|
getAppVariantIdHierarchy(appId: string): Promise<IAppVariantIdHierarchyItem[]>;
|
|
5
6
|
fetch(repoName: string, cachebusterToken: string): Promise<Map<string, string>>;
|
|
7
|
+
fetchReuseLib(repoName: string, cachebusterToken: string, lib: IReuseLibInfo): Promise<Map<string, string>>;
|
|
8
|
+
getAdapter(): Adapter;
|
|
6
9
|
createAppVariantHierarchyItem(appVariantId: string, version: string): void;
|
|
7
10
|
updateLandscapeSpecificContent(baseAppManifest: any, baseAppFiles: Map<string, string>, appVariantId: string, prefix: string): Promise<void>;
|
|
8
11
|
}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import { IConfiguration } from "./../model/types.js";
|
|
1
|
+
import { IConfiguration, IReuseLibInfo } from "./../model/types.js";
|
|
2
2
|
export default class HTML5RepoManager {
|
|
3
3
|
static getBaseAppFiles(configuration: IConfiguration): Promise<Map<string, string>>;
|
|
4
4
|
static getMetadata(configuration: IConfiguration): Promise<any>;
|
|
5
|
+
static getReuseLibFiles(configuration: IConfiguration, lib: IReuseLibInfo): Promise<Map<string, string>>;
|
|
5
6
|
private static getHtml5RepoInfo;
|
|
6
7
|
private static getHTML5Credentials;
|
|
7
8
|
private static getToken;
|
|
8
9
|
private static requestMetadata;
|
|
9
|
-
private static
|
|
10
|
+
private static getAppZipEntries;
|
|
10
11
|
private static download;
|
|
11
12
|
}
|
|
@@ -6,12 +6,26 @@ const log = getLogger("@ui5/task-adaptation::HTML5RepoManager");
|
|
|
6
6
|
export default class HTML5RepoManager {
|
|
7
7
|
static async getBaseAppFiles(configuration) {
|
|
8
8
|
const { token, baseUri } = await this.getHtml5RepoInfo(configuration);
|
|
9
|
-
|
|
9
|
+
const app = {
|
|
10
|
+
appName: configuration.appName,
|
|
11
|
+
appVersion: configuration.appVersion,
|
|
12
|
+
appHostId: configuration.appHostId
|
|
13
|
+
};
|
|
14
|
+
return this.getAppZipEntries(app, baseUri, token);
|
|
10
15
|
}
|
|
11
16
|
static async getMetadata(configuration) {
|
|
12
17
|
const { token, baseUri } = await this.getHtml5RepoInfo(configuration);
|
|
13
18
|
return this.requestMetadata(configuration, baseUri, token);
|
|
14
19
|
}
|
|
20
|
+
static async getReuseLibFiles(configuration, lib) {
|
|
21
|
+
const { token, baseUri } = await this.getHtml5RepoInfo(configuration);
|
|
22
|
+
const libAppData = {
|
|
23
|
+
appName: lib.html5AppName,
|
|
24
|
+
appVersion: lib.html5AppVersion,
|
|
25
|
+
appHostId: lib.html5AppHostId
|
|
26
|
+
};
|
|
27
|
+
return this.getAppZipEntries(libAppData, baseUri, token);
|
|
28
|
+
}
|
|
15
29
|
static async getHtml5RepoInfo(configuration) {
|
|
16
30
|
const spaceGuid = await CFUtil.getSpaceGuid(configuration?.space);
|
|
17
31
|
const credentials = await this.getHTML5Credentials(spaceGuid);
|
|
@@ -65,10 +79,9 @@ export default class HTML5RepoManager {
|
|
|
65
79
|
const metadata = await RequestUtil.get(uri, requestOptions);
|
|
66
80
|
return metadata.find((item) => item.appHostId === appHostId && item.applicationName === appName && item.applicationVersion === appVersion);
|
|
67
81
|
}
|
|
68
|
-
static async
|
|
69
|
-
const
|
|
70
|
-
const
|
|
71
|
-
const zip = await this.download(token, appHostId, uri);
|
|
82
|
+
static async getAppZipEntries(app, html5RepoBaseUri, token) {
|
|
83
|
+
const uri = `${html5RepoBaseUri}/applications/content/${app.appName}-${app.appVersion}/`;
|
|
84
|
+
const zip = await this.download(token, app.appHostId, uri);
|
|
72
85
|
return unzipZipEntries(zip);
|
|
73
86
|
}
|
|
74
87
|
static async download(token, appHostId, uri) {
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export type XsApp = {
|
|
2
|
+
welcomeFile?: string;
|
|
3
|
+
authenticationMethod: "none" | "route";
|
|
4
|
+
routes: Route[];
|
|
5
|
+
};
|
|
6
|
+
export type Route = {
|
|
7
|
+
source: string;
|
|
8
|
+
target: string;
|
|
9
|
+
service?: string;
|
|
10
|
+
destination?: string;
|
|
11
|
+
authenticationType?: string;
|
|
12
|
+
localDir?: string;
|
|
13
|
+
};
|
|
14
|
+
export declare const XSAPP_JSON_FILENAME = "xs-app.json";
|
|
15
|
+
/**
|
|
16
|
+
* Merges multiple xs-app.json contents into one. AppVariant and Reuse Library
|
|
17
|
+
* xs-app.json files come first, base app xs-app.json last. Routes from all
|
|
18
|
+
* files are concatenated.
|
|
19
|
+
* @param xsAppFiles Array of xs-app.json file contents as strings
|
|
20
|
+
* @returns Merged xs-app.json content as a string, or undefined if no files
|
|
21
|
+
* were provided
|
|
22
|
+
*/
|
|
23
|
+
export declare function merge(xsAppFiles: string[]): string | undefined;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export const XSAPP_JSON_FILENAME = "xs-app.json";
|
|
2
|
+
/**
|
|
3
|
+
* Merges multiple xs-app.json contents into one. AppVariant and Reuse Library
|
|
4
|
+
* xs-app.json files come first, base app xs-app.json last. Routes from all
|
|
5
|
+
* files are concatenated.
|
|
6
|
+
* @param xsAppFiles Array of xs-app.json file contents as strings
|
|
7
|
+
* @returns Merged xs-app.json content as a string, or undefined if no files
|
|
8
|
+
* were provided
|
|
9
|
+
*/
|
|
10
|
+
export function merge(xsAppFiles) {
|
|
11
|
+
if (xsAppFiles.length === 0) {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
if (xsAppFiles.length === 1) {
|
|
15
|
+
return xsAppFiles[0];
|
|
16
|
+
}
|
|
17
|
+
// Start with empty xs-app.json
|
|
18
|
+
const merged = {
|
|
19
|
+
authenticationMethod: "none",
|
|
20
|
+
routes: []
|
|
21
|
+
};
|
|
22
|
+
for (const xsAppInfoContent of xsAppFiles) {
|
|
23
|
+
const { authenticationMethod, routes, welcomeFile } = JSON.parse(xsAppInfoContent);
|
|
24
|
+
if (merged.welcomeFile === undefined && welcomeFile) {
|
|
25
|
+
merged.welcomeFile = welcomeFile;
|
|
26
|
+
}
|
|
27
|
+
if (merged.authenticationMethod === "none" && authenticationMethod) {
|
|
28
|
+
merged.authenticationMethod = authenticationMethod;
|
|
29
|
+
}
|
|
30
|
+
if (Array.isArray(routes)) {
|
|
31
|
+
merged.routes = merged.routes.concat(routes);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return JSON.stringify(merged, null, 4);
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=xsAppJsonUtil.js.map
|
package/dist/util/cfUtil.d.ts
CHANGED
|
@@ -15,7 +15,7 @@ export default class CFUtil {
|
|
|
15
15
|
private static createServiceKey;
|
|
16
16
|
private static deleteServiceKeyUnsafe;
|
|
17
17
|
private static getServiceInstance;
|
|
18
|
-
static
|
|
18
|
+
static processCfErrors(errors?: ICfError[]): void;
|
|
19
19
|
static requestCfApi(url: string): Promise<IResource[]>;
|
|
20
20
|
static getOAuthToken(): Promise<string>;
|
|
21
21
|
private static cfExecute;
|
|
@@ -76,3 +76,10 @@ export default class CFUtil {
|
|
|
76
76
|
*/
|
|
77
77
|
static getSpaceGuid(spaceGuid?: string): Promise<string>;
|
|
78
78
|
}
|
|
79
|
+
interface ICfError {
|
|
80
|
+
code: number;
|
|
81
|
+
title: string;
|
|
82
|
+
detail: string;
|
|
83
|
+
[key: string]: any;
|
|
84
|
+
}
|
|
85
|
+
export {};
|
package/dist/util/cfUtil.js
CHANGED
|
@@ -3,6 +3,7 @@ import { getSpaceGuidThrowIfUndefined } from "@sap/cf-tools/out/src/utils.js";
|
|
|
3
3
|
import { Cli } from "@sap/cf-tools/out/src/cli.js";
|
|
4
4
|
import { eFilters } from "@sap/cf-tools/out/src/types.js";
|
|
5
5
|
import { getLogger } from "@ui5/logger";
|
|
6
|
+
import AuthenticationError from "../model/authenticationError.js";
|
|
6
7
|
const log = getLogger("@ui5/task-adaptation::CFUtil");
|
|
7
8
|
export default class CFUtil {
|
|
8
9
|
/**
|
|
@@ -103,19 +104,20 @@ export default class CFUtil {
|
|
|
103
104
|
guid: service.guid
|
|
104
105
|
}));
|
|
105
106
|
}
|
|
106
|
-
static
|
|
107
|
-
if (
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
throw new
|
|
107
|
+
static processCfErrors(errors) {
|
|
108
|
+
if (!errors || errors.length === 0) {
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
const authError = errors.find(e => e.title === "CF-NotAuthenticated" || e.code === 10002);
|
|
112
|
+
if (authError) {
|
|
113
|
+
throw new AuthenticationError(authError.detail);
|
|
113
114
|
}
|
|
115
|
+
throw new Error(`Failed sending request to Cloud Foundry: ${JSON.stringify(errors)}`);
|
|
114
116
|
}
|
|
115
117
|
static async requestCfApi(url) {
|
|
116
118
|
const response = await this.cfExecute(["curl", url]);
|
|
117
119
|
const json = this.parseJson(response);
|
|
118
|
-
this.
|
|
120
|
+
this.processCfErrors(json?.errors);
|
|
119
121
|
const resources = json?.resources;
|
|
120
122
|
const totalPages = json?.pagination?.total_pages;
|
|
121
123
|
if (totalPages > 1) {
|
|
@@ -142,11 +144,17 @@ export default class CFUtil {
|
|
|
142
144
|
if (errorValues?.length > 0) {
|
|
143
145
|
log.verbose(this.errorsToString(errorValues));
|
|
144
146
|
}
|
|
147
|
+
if (response.stdout === "\n") {
|
|
148
|
+
throw new AuthenticationError();
|
|
149
|
+
}
|
|
145
150
|
return response.stdout;
|
|
146
151
|
}
|
|
147
152
|
errors.add(response.error || response.stderr);
|
|
148
153
|
}
|
|
149
154
|
catch (error) {
|
|
155
|
+
if (error instanceof AuthenticationError) {
|
|
156
|
+
throw error;
|
|
157
|
+
}
|
|
150
158
|
errors.add(error.message);
|
|
151
159
|
}
|
|
152
160
|
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare const moveFiles: (inputFiles: ReadonlyMap<string, string>, prefix: string, id: string) => {
|
|
2
|
+
files: Map<string, string>;
|
|
3
|
+
renamingPaths: Map<string, string>;
|
|
4
|
+
};
|
|
5
|
+
export declare const moveFile: (filename: string, content: string, prefix: string, id: string) => {
|
|
6
|
+
newFilename: string;
|
|
7
|
+
renamingPath: Map<string, string>;
|
|
8
|
+
};
|