@ui5/task-adaptation 1.6.5-rc.3 → 1.6.5
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/.env.test +1 -0
- package/CHANGELOG.md +10 -57
- package/README.md +4 -0
- package/dist/adapters/abapAdapter.d.ts +7 -5
- package/dist/adapters/abapAdapter.js +9 -11
- package/dist/adapters/adapter.d.ts +9 -5
- package/dist/adapters/adapter.js +20 -0
- package/dist/adapters/cfAdapter.d.ts +8 -5
- package/dist/adapters/cfAdapter.js +16 -10
- package/dist/adapters/commands/command.d.ts +26 -23
- package/dist/adapters/commands/command.js +73 -46
- package/dist/adapters/commands/fetchEndpointsCommand.d.ts +9 -0
- package/dist/adapters/commands/fetchEndpointsCommand.js +21 -0
- package/dist/adapters/commands/fetchPreviewResourcesCommand.d.ts +15 -0
- package/dist/adapters/commands/fetchPreviewResourcesCommand.js +102 -0
- package/dist/adapters/commands/filterFilesCommand.d.ts +4 -0
- package/dist/adapters/commands/filterFilesCommand.js +22 -0
- package/dist/adapters/commands/omitDeletedResourcesCommand.d.ts +10 -0
- package/dist/adapters/commands/omitDeletedResourcesCommand.js +31 -0
- package/dist/adapters/commands/processPreviewResourcesCommand.d.ts +9 -0
- package/dist/adapters/commands/processPreviewResourcesCommand.js +51 -0
- package/dist/adapters/commands/renameFilesCommand.d.ts +20 -0
- package/dist/{util/filesUtil.js → adapters/commands/renameFilesCommand.js} +34 -43
- package/dist/adapters/commands/writeResourcesCommand.d.ts +7 -0
- package/dist/adapters/commands/writeResourcesCommand.js +20 -0
- package/dist/adapters/commands/xsAppJsonEnhanceRoutesCommand.d.ts +3 -3
- package/dist/adapters/commands/xsAppJsonEnhanceRoutesCommand.js +4 -4
- package/dist/adapters/previewAdapter.d.ts +12 -6
- package/dist/adapters/previewAdapter.js +28 -7
- package/dist/{appVariantManager.d.ts → appVariant.d.ts} +2 -9
- package/dist/{appVariantManager.js → appVariant.js} +14 -26
- package/dist/{baseAppManager.js → baseApp.js} +6 -12
- package/dist/bundle.js +53 -12
- package/dist/cache/cacheHolder.d.ts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +34 -69
- package/dist/model/configuration.d.ts +1 -0
- package/dist/model/configuration.js +1 -0
- package/dist/model/types.d.ts +9 -2
- package/dist/repositories/localRepository.d.ts +2 -3
- package/dist/repositories/localRepository.js +54 -33
- package/dist/util/cf/xsAppJsonUtil.d.ts +16 -3
- package/dist/util/cf/xsAppJsonUtil.js +7 -18
- package/dist/util/commonUtil.d.ts +6 -0
- package/dist/util/commonUtil.js +17 -0
- package/dist/util/fsUtil.d.ts +1 -2
- package/dist/util/fsUtil.js +12 -33
- package/dist/util/renamingUtil.js +1 -1
- package/dist/util/resourceUtil.js +1 -1
- package/dist/util/validator/abapValidator.js +2 -2
- package/dist/util/validator/validator.d.ts +1 -0
- package/dist/util/validator/validator.js +11 -0
- package/package.json +11 -12
- package/.hyperspace/pull_request_bot.json +0 -19
- package/dist/previewManager.d.ts +0 -14
- package/dist/previewManager.js +0 -147
- package/dist/util/filesUtil.d.ts +0 -19
- package/scripts/metadataDownloadHelper.ts +0 -88
- package/scripts/publish.ts +0 -256
- package/scripts/test-integration-prep.sh +0 -4
- /package/dist/{baseAppManager.d.ts → baseApp.d.ts} +0 -0
|
@@ -14,7 +14,7 @@ export function renameMap(content, references, ignoreInStrings) {
|
|
|
14
14
|
if (ignoredReferenceKeys.length > 0) {
|
|
15
15
|
log.info(`Ignored renaming: ${ignoredReferenceKeys.join(", ")}`);
|
|
16
16
|
}
|
|
17
|
-
const searchTerms = [...references.keys()];
|
|
17
|
+
const searchTerms = [...references.keys()].filter(key => key.length > 0);
|
|
18
18
|
if (!content || !searchTerms || searchTerms.length === 0) {
|
|
19
19
|
return content;
|
|
20
20
|
}
|
|
@@ -78,7 +78,7 @@ export default class ResourceUtil {
|
|
|
78
78
|
].concat(excludes));
|
|
79
79
|
}
|
|
80
80
|
static getString(resource) {
|
|
81
|
-
return resource.getBuffer().then((buffer) => buffer.toString(UTF8));
|
|
81
|
+
return resource.getBuffer().then((buffer) => buffer.toString(UTF8).replaceAll("\r\n", "\n"));
|
|
82
82
|
}
|
|
83
83
|
static getJson(resource) {
|
|
84
84
|
return resource.getBuffer().then((buffer) => JSON.parse(buffer.toString(UTF8)));
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { validateObject } from "../commonUtil.js";
|
|
2
|
-
import
|
|
2
|
+
import { isAppStudio } from "@sap-ux/btp-utils";
|
|
3
3
|
import { getLogger } from "@ui5/logger";
|
|
4
4
|
const log = getLogger("@ui5/task-adaptation::AbapValidator");
|
|
5
5
|
export default class AbapValidator {
|
|
@@ -9,7 +9,7 @@ export default class AbapValidator {
|
|
|
9
9
|
// if target configuration appears, we validate that it should be
|
|
10
10
|
// either target/destination for BAS or target/url for IDE we're
|
|
11
11
|
// trying to detect is it destination for BAS or url for IDE
|
|
12
|
-
const abapTargetProperties =
|
|
12
|
+
const abapTargetProperties = isAppStudio() ? ["destination"] : ["url"];
|
|
13
13
|
validateObject(target, abapTargetProperties, "should be specified in ui5.yaml configuration/target");
|
|
14
14
|
return target;
|
|
15
15
|
}
|
|
@@ -1,4 +1,15 @@
|
|
|
1
1
|
export function isOneOf(values, value) {
|
|
2
2
|
return values.includes(value);
|
|
3
3
|
}
|
|
4
|
+
export function validateAppId(id) {
|
|
5
|
+
if (!id) {
|
|
6
|
+
throw new Error(`The application id must not be empty.`);
|
|
7
|
+
}
|
|
8
|
+
// https://help.sap.com/docs/bas/developing-sap-fiori-app-in-sap-business-application-studio/releasing-sap-fiori-application-to-be-extensible-in-adaptation-projects-on-sap-s-4hana-cloud
|
|
9
|
+
// In the manifest.json file, make sure that the attribute
|
|
10
|
+
// sap.app/id has at least 2 segments.
|
|
11
|
+
if (id.split(".").filter(Boolean).length < 2) {
|
|
12
|
+
throw new Error(`The application id '${id}' must have at least two parts, separated by a period.`);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
4
15
|
//# sourceMappingURL=validator.js.map
|
package/package.json
CHANGED
|
@@ -1,21 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ui5/task-adaptation",
|
|
3
|
-
"version": "1.6.5
|
|
3
|
+
"version": "1.6.5",
|
|
4
4
|
"description": "Custom task for ui5-builder which allows building UI5 Flexibility Adaptation Projects for SAP BTP, Cloud Foundry environment",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"test": "npm run lint && npm run build && npm run coverage",
|
|
8
8
|
"lint": "eslint ./src ./test/lib",
|
|
9
|
-
"dev": "
|
|
10
|
-
"perf": "
|
|
9
|
+
"dev": "mocha --no-timeouts --no-warnings --import=tsx \"test/lib/**/*.spec.ts\"",
|
|
10
|
+
"perf": "mocha --no-timeouts --no-warnings --import=tsx \"test/lib/**/*.perf.ts\"",
|
|
11
11
|
"coverage": "c8 npm run dev",
|
|
12
12
|
"preversion": "npm test",
|
|
13
13
|
"version": "git-chglog --next-tag v$npm_package_version -o CHANGELOG.md && git add CHANGELOG.md",
|
|
14
14
|
"prepublishOnly": "git push --follow-tags",
|
|
15
15
|
"release-note": "git-chglog -c .chglog/release-config.yml v$npm_package_version",
|
|
16
16
|
"rollup": "tsx rollup/rollup.ts",
|
|
17
|
-
"build": "npm run rollup && tsc -p ./"
|
|
18
|
-
"download-metadata": "tsx scripts/metadataDownloadHelper.ts"
|
|
17
|
+
"build": "npm run rollup && tsc -p ./"
|
|
19
18
|
},
|
|
20
19
|
"repository": {
|
|
21
20
|
"type": "git",
|
|
@@ -33,10 +32,10 @@
|
|
|
33
32
|
"author": "SAP SE",
|
|
34
33
|
"license": "Apache-2.0",
|
|
35
34
|
"dependencies": {
|
|
36
|
-
"@sap-ux/axios-extension": "^
|
|
37
|
-
"@sap-ux/btp-utils": "^
|
|
38
|
-
"@sap-ux/store": "^
|
|
39
|
-
"@sap-ux/system-access": "^0.
|
|
35
|
+
"@sap-ux/axios-extension": "^2.0.1",
|
|
36
|
+
"@sap-ux/btp-utils": "^2.0.1",
|
|
37
|
+
"@sap-ux/store": "^2.0.1",
|
|
38
|
+
"@sap-ux/system-access": "^1.0.1",
|
|
40
39
|
"@sap/cf-tools": "^3.2.2",
|
|
41
40
|
"@ui5/fs": "^4.0.1",
|
|
42
41
|
"@ui5/logger": "^4.0.1",
|
|
@@ -45,6 +44,7 @@
|
|
|
45
44
|
"crc": "^4.3.2",
|
|
46
45
|
"dotenv": "^16.0.3",
|
|
47
46
|
"filenamify": "^6.0.0",
|
|
47
|
+
"glob": "^13.0.0",
|
|
48
48
|
"jsdom": "^23.0.1",
|
|
49
49
|
"transliteration": "^2.3.5",
|
|
50
50
|
"xml-js": "^1.6.11"
|
|
@@ -73,17 +73,16 @@
|
|
|
73
73
|
"eslint": "^9.22.0",
|
|
74
74
|
"eslint-plugin-import": "^2.31.0",
|
|
75
75
|
"esmock": "^2.7.3",
|
|
76
|
-
"glob": "^13.0.0",
|
|
77
76
|
"js-yaml": "^4.1.0",
|
|
78
77
|
"meriyah": "^6.0.3",
|
|
79
78
|
"minimatch": "^9.0.3",
|
|
80
|
-
"mocha": "^11.7.
|
|
79
|
+
"mocha": "^11.7.6",
|
|
81
80
|
"mock-require": "^3.0.3",
|
|
82
81
|
"rollup": "^4.24.0",
|
|
83
82
|
"semver": "^7.3.5",
|
|
84
83
|
"sinon": "^18.0.1",
|
|
85
84
|
"source-map-support": "^0.5.19",
|
|
86
|
-
"tsx": "
|
|
85
|
+
"tsx": "4.21.0",
|
|
87
86
|
"typescript": "^6.0.2",
|
|
88
87
|
"typescript-eslint": "^8.58.0",
|
|
89
88
|
"yargs": "^17.7.2"
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "https://devops-insights-pr-bot.cfapps.eu10-004.hana.ondemand.com/schema/pull_request_bot.json",
|
|
3
|
-
"features": {
|
|
4
|
-
"control_panel": false,
|
|
5
|
-
"summarize": {
|
|
6
|
-
"auto_generate_summary": true,
|
|
7
|
-
"auto_insert_summary": true,
|
|
8
|
-
"auto_run_on_draft_pr": true,
|
|
9
|
-
"use_custom_summarize_prompt": false,
|
|
10
|
-
"use_custom_summarize_output_template": false,
|
|
11
|
-
"use_tabular_summarize_output_template": false
|
|
12
|
-
},
|
|
13
|
-
"review": {
|
|
14
|
-
"auto_generate_review": true,
|
|
15
|
-
"auto_run_on_draft_pr": true,
|
|
16
|
-
"use_custom_review_focus": false
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
}
|
package/dist/previewManager.d.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { IConfiguration } from "./model/types.js";
|
|
2
|
-
import IRepository from "./repositories/repository.js";
|
|
3
|
-
export default class PreviewManager {
|
|
4
|
-
private readonly fetchLibsPromises;
|
|
5
|
-
private readonly configuration;
|
|
6
|
-
static createFromRoot(appId: string, repository: IRepository, configuration: IConfiguration): Promise<PreviewManager>;
|
|
7
|
-
static isPreviewRequested(): boolean;
|
|
8
|
-
private constructor();
|
|
9
|
-
processPreviewResources(baseAppFiles: ReadonlyMap<string, string>): Promise<void>;
|
|
10
|
-
private preReadLibs;
|
|
11
|
-
private searchBaseAppXsAppJsonFile;
|
|
12
|
-
private static moveLibraryFiles;
|
|
13
|
-
private static modifyRoutes;
|
|
14
|
-
}
|
package/dist/previewManager.js
DELETED
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
import { getLogger } from "@ui5/logger";
|
|
2
|
-
import ResourceUtil from "./util/resourceUtil.js";
|
|
3
|
-
import path from "path";
|
|
4
|
-
import { fetchCredentialsAndEnhanceRoutes, merge } from "./util/cf/xsAppJsonUtil.js";
|
|
5
|
-
import FsUtil from "./util/fsUtil.js";
|
|
6
|
-
const log = getLogger("@ui5/task-adaptation::PreviewManager");
|
|
7
|
-
const REUSE_DIR = ".adp/reuse";
|
|
8
|
-
const APP_INFO_FILE = "ui5AppInfo.json";
|
|
9
|
-
const XS_APP_JSON_FILE = "xs-app.json";
|
|
10
|
-
export default class PreviewManager {
|
|
11
|
-
fetchLibsPromises = new Map();
|
|
12
|
-
configuration;
|
|
13
|
-
static async createFromRoot(appId, repository, configuration) {
|
|
14
|
-
let ui5AppInfo = "";
|
|
15
|
-
if (PreviewManager.isPreviewRequested()) {
|
|
16
|
-
try {
|
|
17
|
-
ui5AppInfo = await FsUtil.readInProject(APP_INFO_FILE);
|
|
18
|
-
}
|
|
19
|
-
catch (error) {
|
|
20
|
-
throw new Error(`ui5AppInfo.json is missing in project root, cannot process preview resources: ${error instanceof Error ? error.message : String(error)}`);
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
else {
|
|
24
|
-
log.verbose("Preview mode not requested (env variable ADP_BUILDER_MODE=preview is not set), skipping preview resources processing.");
|
|
25
|
-
}
|
|
26
|
-
return new PreviewManager(appId, ui5AppInfo, repository, configuration);
|
|
27
|
-
}
|
|
28
|
-
static isPreviewRequested() {
|
|
29
|
-
return process.env.ADP_BUILDER_MODE === "preview";
|
|
30
|
-
}
|
|
31
|
-
constructor(appId, ui5AppInfo, repository, configuration) {
|
|
32
|
-
this.configuration = configuration;
|
|
33
|
-
// If no ui5AppInfo is provided, no preview processing is needed
|
|
34
|
-
if (!ui5AppInfo) {
|
|
35
|
-
log.verbose("No ui5AppInfo provided, skipping preview resources processing.");
|
|
36
|
-
return;
|
|
37
|
-
}
|
|
38
|
-
const appInfo = JSON.parse(ui5AppInfo)[appId];
|
|
39
|
-
if (!appInfo) {
|
|
40
|
-
throw new Error(`No app info found for original app id '${appId}' in ui5AppInfo.json`);
|
|
41
|
-
}
|
|
42
|
-
const reuseLibs = appInfo.asyncHints.libs.filter(lib => lib.html5AppHostId && lib.html5AppName && lib.html5AppVersion);
|
|
43
|
-
if (reuseLibs.length > 0) {
|
|
44
|
-
this.fetchLibsPromises = this.preReadLibs(reuseLibs, repository);
|
|
45
|
-
}
|
|
46
|
-
const logMap = {
|
|
47
|
-
Error: log.error,
|
|
48
|
-
Warning: log.warning,
|
|
49
|
-
Info: log.info,
|
|
50
|
-
debug: log.verbose
|
|
51
|
-
};
|
|
52
|
-
appInfo.messages.forEach((message) => {
|
|
53
|
-
const logger = logMap[message.severity] || log.info;
|
|
54
|
-
logger(`ui5AppInfo.json: ${message.severity} Message: ${message.message} (Error Code: ${message.errorCode})`);
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
async processPreviewResources(baseAppFiles) {
|
|
58
|
-
if (!PreviewManager.isPreviewRequested()) {
|
|
59
|
-
log.verbose("Preview mode not requested, skipping downloading reuse libraries and xs-app.json processing.");
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
log.verbose(`Downloading reuse libraries to reuse folder`);
|
|
63
|
-
const xsAppFiles = new Array();
|
|
64
|
-
if (this.fetchLibsPromises.size === 0) {
|
|
65
|
-
log.verbose("No reuse libraries defined in ui5AppInfo.json for preview");
|
|
66
|
-
}
|
|
67
|
-
const mergedFiles = new Map();
|
|
68
|
-
for (const [libName, libFilesPromise] of this.fetchLibsPromises) {
|
|
69
|
-
const libFiles = await libFilesPromise;
|
|
70
|
-
if (!libFiles || libFiles.size === 0) {
|
|
71
|
-
log.warn(`No files found in reuse library ${libName} for preview`);
|
|
72
|
-
continue;
|
|
73
|
-
}
|
|
74
|
-
for (const [filename, content] of libFiles) {
|
|
75
|
-
mergedFiles.set(filename, content);
|
|
76
|
-
if (filename.includes(XS_APP_JSON_FILE)) {
|
|
77
|
-
xsAppFiles.push(content);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
this.searchBaseAppXsAppJsonFile(xsAppFiles, baseAppFiles);
|
|
82
|
-
let xsAppJson = merge(xsAppFiles);
|
|
83
|
-
if (xsAppJson) {
|
|
84
|
-
xsAppJson = await fetchCredentialsAndEnhanceRoutes(xsAppJson, this.configuration);
|
|
85
|
-
mergedFiles.set(XS_APP_JSON_FILE, xsAppJson);
|
|
86
|
-
}
|
|
87
|
-
if (mergedFiles.size === 0) {
|
|
88
|
-
return;
|
|
89
|
-
}
|
|
90
|
-
await ResourceUtil.writeInProject(REUSE_DIR, mergedFiles);
|
|
91
|
-
}
|
|
92
|
-
preReadLibs(reuseLibs, repository) {
|
|
93
|
-
const promises = new Map();
|
|
94
|
-
reuseLibs.forEach(lib => {
|
|
95
|
-
log.info(`Downloading reuse library '${lib.html5AppName}' version '${lib.html5AppVersion}'`);
|
|
96
|
-
const resource = {
|
|
97
|
-
appName: lib.html5AppName,
|
|
98
|
-
appVersion: lib.html5AppVersion,
|
|
99
|
-
appHostId: lib.html5AppHostId,
|
|
100
|
-
cacheBusterToken: Promise.resolve(lib.html5CacheBusterToken)
|
|
101
|
-
};
|
|
102
|
-
const promise = repository
|
|
103
|
-
.fetch(resource)
|
|
104
|
-
.then((libFiles) => PreviewManager.moveLibraryFiles(libFiles, lib.html5AppName, lib.name));
|
|
105
|
-
promises.set(lib.html5AppName, promise);
|
|
106
|
-
});
|
|
107
|
-
return promises;
|
|
108
|
-
}
|
|
109
|
-
searchBaseAppXsAppJsonFile(xsAppFiles, baseAppFiles) {
|
|
110
|
-
const xsAppJsonContent = baseAppFiles.get(XS_APP_JSON_FILE);
|
|
111
|
-
if (xsAppJsonContent) {
|
|
112
|
-
xsAppFiles.push(xsAppJsonContent);
|
|
113
|
-
}
|
|
114
|
-
else {
|
|
115
|
-
log.warn("xs-app.json is missing in the downloaded base app files for preview");
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
static moveLibraryFiles(inputFiles, libraryName, libId) {
|
|
119
|
-
const files = new Map();
|
|
120
|
-
inputFiles.forEach((content, filename) => {
|
|
121
|
-
const newFilename = path.join(libraryName, filename);
|
|
122
|
-
// Source path in xs-app.json needs to be adjusted to new location
|
|
123
|
-
if (filename.includes(XS_APP_JSON_FILE)) {
|
|
124
|
-
content = PreviewManager.modifyRoutes(content, libraryName, libId);
|
|
125
|
-
}
|
|
126
|
-
files.set(newFilename, content);
|
|
127
|
-
});
|
|
128
|
-
return files;
|
|
129
|
-
}
|
|
130
|
-
;
|
|
131
|
-
static modifyRoutes(xsAppJson, libName, libId) {
|
|
132
|
-
const xsApp = JSON.parse(xsAppJson);
|
|
133
|
-
xsApp.routes = xsApp.routes.map((route) => {
|
|
134
|
-
route.source = route.source.replace(new RegExp("^\\^\\/?(resources/)?"), `^/resources/${libId.replaceAll(".", "/")}/`);
|
|
135
|
-
if (route.service === "html5-apps-repo-rt") {
|
|
136
|
-
route = {
|
|
137
|
-
source: route.source,
|
|
138
|
-
target: route.target,
|
|
139
|
-
localDir: path.join(REUSE_DIR, libName)
|
|
140
|
-
};
|
|
141
|
-
}
|
|
142
|
-
return route;
|
|
143
|
-
});
|
|
144
|
-
return JSON.stringify(xsApp);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
//# sourceMappingURL=previewManager.js.map
|
package/dist/util/filesUtil.d.ts
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { IChange } from "../model/types.js";
|
|
2
|
-
export default class FilesUtil {
|
|
3
|
-
static filter(files: ReadonlyMap<string, string>): ReadonlyMap<string, string>;
|
|
4
|
-
static sortByTimeStamp(a: IChange, b: IChange): number;
|
|
5
|
-
/**
|
|
6
|
-
* 1p. i18n.properties are not renamed and property keys are ignored during
|
|
7
|
-
* the renaming across the files.
|
|
8
|
-
* @param files - all files both base and appVariants
|
|
9
|
-
* @param references - Reference maps of the app variant
|
|
10
|
-
* @returns A map of renamed files
|
|
11
|
-
*/
|
|
12
|
-
static rename(files: ReadonlyMap<string, string>, references: Map<string, string>): ReadonlyMap<string, string>;
|
|
13
|
-
private static getManifestSAPUI5DependencyIds;
|
|
14
|
-
private static getI18nPropertyKeys;
|
|
15
|
-
}
|
|
16
|
-
/**
|
|
17
|
-
* We might rename appVariantIdHierarchy and dependencies, so we restore them after the renaming.
|
|
18
|
-
*/
|
|
19
|
-
export declare function restoreWhatShouldntBeRenamed(): (_target: any, _propertyKey: string, descriptor: PropertyDescriptor) => void;
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
import * as dotenv from "dotenv";
|
|
2
|
-
import * as fs from "fs/promises";
|
|
3
|
-
|
|
4
|
-
import { Agent } from "https";
|
|
5
|
-
import RequestUtil from "../src/util/requestUtil.js";
|
|
6
|
-
|
|
7
|
-
dotenv.config();
|
|
8
|
-
const httpsAgent = new Agent({ rejectUnauthorized: false });
|
|
9
|
-
|
|
10
|
-
export default class MetadataDownloadHelper {
|
|
11
|
-
|
|
12
|
-
static async readAllUrls() {
|
|
13
|
-
await fs.readdir("./test/resources/annotations/inline", { encoding: "utf8" });
|
|
14
|
-
const resultsObject = JSON.parse(await fs.readFile("./test/resources/allReleasedODataServices.json", { encoding: "utf8" }));
|
|
15
|
-
return this.exractUrlsFromResponse(resultsObject);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
static async fetchAllUrls(host: string) {
|
|
19
|
-
const REQUEST_OPTIONS_JSON = {
|
|
20
|
-
headers: {
|
|
21
|
-
"Content-Type": "application/json; charset=utf-8",
|
|
22
|
-
'Cookie': process.env.cookie,
|
|
23
|
-
},
|
|
24
|
-
httpsAgent
|
|
25
|
-
};
|
|
26
|
-
const url = "/sap/bc/ui2/app_index?sap.fiori/cloudDevAdaptationStatus=released&fields=sap.app/id,sap.app/dataSources/OData/uri";
|
|
27
|
-
const response = await RequestUtil.get(host + url, REQUEST_OPTIONS_JSON);
|
|
28
|
-
const allUris = this.exractUrlsFromResponse(response);
|
|
29
|
-
for (const [index, url] of allUris.entries()) {
|
|
30
|
-
try {
|
|
31
|
-
const metadataFile = await this.fetchMetadataFileByUri(host, url);
|
|
32
|
-
if (typeof metadataFile === "object") {
|
|
33
|
-
console.error(`Received object instead of xml file with content: ${JSON.stringify(metadataFile)}`)
|
|
34
|
-
continue;
|
|
35
|
-
}
|
|
36
|
-
// @ts-ignore
|
|
37
|
-
await fs.writeFile(`test/resources/metadata/download/${index}__${url.replaceAll("/", "_")}.xml`, metadataFile, { encoding: "utf8" });
|
|
38
|
-
} catch (e: any) {
|
|
39
|
-
console.error(`Error fetching metadata file with url ${url} with error \n\n ${e}`);
|
|
40
|
-
continue;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
private static exractUrlsFromResponse(resultsObject: any) {
|
|
46
|
-
let allUrls: string[] = [];
|
|
47
|
-
resultsObject.results.map((value: any) => {
|
|
48
|
-
allUrls = allUrls.concat(value["sap.app/dataSources/OData/uri"]);
|
|
49
|
-
});
|
|
50
|
-
return allUrls;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
static readMetadataFileByFilePath(filePath: string) {
|
|
54
|
-
return fs.readFile(filePath, { encoding: "utf8" });
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
static fetchMetadataFileByUri(host: string, url: string) {
|
|
58
|
-
const REQUEST_OPTIONS_XML = {
|
|
59
|
-
headers: {
|
|
60
|
-
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
|
|
61
|
-
'Cookie': process.env.cookie,
|
|
62
|
-
},
|
|
63
|
-
httpsAgent,
|
|
64
|
-
timeout: 4000
|
|
65
|
-
};
|
|
66
|
-
url = url.endsWith("/") ? `${url}$metadata` : `${url}/$metadata`;
|
|
67
|
-
return RequestUtil.get(host + url, REQUEST_OPTIONS_XML);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// Get the command line arguments
|
|
72
|
-
const args = process.argv;
|
|
73
|
-
|
|
74
|
-
// Find the index of the `--host=` argument
|
|
75
|
-
const hostArgIndex = args.findIndex(arg => arg.startsWith('--host='));
|
|
76
|
-
|
|
77
|
-
// If the `--host=` argument is found
|
|
78
|
-
if (hostArgIndex !== -1) {
|
|
79
|
-
// Extract the value of the `--host=` argument
|
|
80
|
-
const hostArg = args[hostArgIndex];
|
|
81
|
-
let host = hostArg.split('=')[1];
|
|
82
|
-
host = host.endsWith("/") ? host.substring(0, host.lastIndexOf("/")) : host;
|
|
83
|
-
|
|
84
|
-
// Use the `host` variable as needed
|
|
85
|
-
MetadataDownloadHelper.fetchAllUrls(host);
|
|
86
|
-
} else {
|
|
87
|
-
console.info("Please provide missing host parameter");
|
|
88
|
-
}
|
package/scripts/publish.ts
DELETED
|
@@ -1,256 +0,0 @@
|
|
|
1
|
-
import { promises as fs } from "fs";
|
|
2
|
-
import path from "path";
|
|
3
|
-
import yargs from "yargs";
|
|
4
|
-
import { hideBin } from "yargs/helpers";
|
|
5
|
-
import { Octokit } from "@octokit/rest";
|
|
6
|
-
import { retry } from "@octokit/plugin-retry";
|
|
7
|
-
|
|
8
|
-
const OctokitClass = Octokit.plugin(retry);
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Recursively get all file paths in the workspace root, excluding:
|
|
13
|
-
* - test/lib/integration
|
|
14
|
-
* - test/fixtures
|
|
15
|
-
* - test/expected
|
|
16
|
-
* - test/lib/index.perf.ts
|
|
17
|
-
* Returns relative paths from the root.
|
|
18
|
-
*/
|
|
19
|
-
async function getAllRootFilesExceptTestExclusions(root: string): Promise<string[]> {
|
|
20
|
-
const excludeDirs = [
|
|
21
|
-
"test/lib/integration",
|
|
22
|
-
"test/fixtures",
|
|
23
|
-
"test/expected",
|
|
24
|
-
".git",
|
|
25
|
-
"coverage",
|
|
26
|
-
".DS_Store",
|
|
27
|
-
"node_modules",
|
|
28
|
-
".nyc_output",
|
|
29
|
-
"coverage",
|
|
30
|
-
"dist",
|
|
31
|
-
"dist-debug",
|
|
32
|
-
"dist.zip",
|
|
33
|
-
".env",
|
|
34
|
-
"test/resources/metadata/download"
|
|
35
|
-
];
|
|
36
|
-
const excludeFiles = [
|
|
37
|
-
"test/lib/index.perf.ts",
|
|
38
|
-
"scripts/test-integration-prep.sh",
|
|
39
|
-
"Jenkinsfile"
|
|
40
|
-
];
|
|
41
|
-
|
|
42
|
-
async function walk(dir: string): Promise<string[]> {
|
|
43
|
-
const dirents = await fs.readdir(dir, { withFileTypes: true });
|
|
44
|
-
const files: string[] = [];
|
|
45
|
-
for (const dirent of dirents) {
|
|
46
|
-
const relPath = path.relative(root, path.join(dir, dirent.name));
|
|
47
|
-
if (excludeDirs.some(ex => relPath === ex || relPath.startsWith(ex + path.sep))) {
|
|
48
|
-
continue;
|
|
49
|
-
}
|
|
50
|
-
if (excludeFiles.includes(relPath)) {
|
|
51
|
-
continue;
|
|
52
|
-
}
|
|
53
|
-
if (dirent.isDirectory()) {
|
|
54
|
-
files.push(...await walk(path.join(dir, dirent.name)));
|
|
55
|
-
} else {
|
|
56
|
-
files.push(relPath);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
return files;
|
|
60
|
-
}
|
|
61
|
-
return walk(root);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
const FILES = await getAllRootFilesExceptTestExclusions(process.cwd());
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
interface PublishArgs {
|
|
68
|
-
p?: string;
|
|
69
|
-
dryRun?: boolean;
|
|
70
|
-
tag?: string;
|
|
71
|
-
branch?: string;
|
|
72
|
-
[key: string]: unknown;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
async function publish() {
|
|
76
|
-
const argv = yargs(hideBin(process.argv))
|
|
77
|
-
.option("p", {
|
|
78
|
-
type: "string",
|
|
79
|
-
description: "GitHub token (-p)",
|
|
80
|
-
alias: "p"
|
|
81
|
-
})
|
|
82
|
-
.option("dryRun", {
|
|
83
|
-
type: "boolean",
|
|
84
|
-
description: "Run without publishing",
|
|
85
|
-
default: false
|
|
86
|
-
})
|
|
87
|
-
.option("tag", {
|
|
88
|
-
type: "string",
|
|
89
|
-
description: "Publish with a specific tag"
|
|
90
|
-
})
|
|
91
|
-
.option("branch", {
|
|
92
|
-
type: "string",
|
|
93
|
-
description: "Branch to update (default: main)",
|
|
94
|
-
default: "main",
|
|
95
|
-
alias: "b"
|
|
96
|
-
})
|
|
97
|
-
.help()
|
|
98
|
-
.alias("h", "help")
|
|
99
|
-
.parseSync() as PublishArgs;
|
|
100
|
-
|
|
101
|
-
if (argv.dryRun) {
|
|
102
|
-
console.log("Dry run: no publishing will be performed.");
|
|
103
|
-
return;
|
|
104
|
-
}
|
|
105
|
-
const auth = argv.p;
|
|
106
|
-
if (auth) {
|
|
107
|
-
const octokit = new OctokitClass({ auth });
|
|
108
|
-
const ORGANIZATION = "SAP";
|
|
109
|
-
const REPO = "ui5-task-adaptation";
|
|
110
|
-
await uploadToRepo(octokit, ORGANIZATION, REPO, argv.branch);
|
|
111
|
-
if (argv.tag) {
|
|
112
|
-
console.log(`Published with tag: ${argv.tag}`);
|
|
113
|
-
}
|
|
114
|
-
} else {
|
|
115
|
-
console.log("Github token is not provided.");
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
async function getLatestVersion(): Promise<string> {
|
|
121
|
-
const pkg = await fs.readFile(path.join(process.cwd(), "package.json"), { encoding: "utf-8" });
|
|
122
|
-
const pkgJson = JSON.parse(pkg);
|
|
123
|
-
return pkgJson.version;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
async function uploadToRepo(
|
|
128
|
-
octokit: InstanceType<typeof OctokitClass>,
|
|
129
|
-
org: string,
|
|
130
|
-
repo: string,
|
|
131
|
-
branch: string = "main"
|
|
132
|
-
): Promise<void> {
|
|
133
|
-
const fileBlobs = await Promise.all(Object.values(FILES).map(file => toBlob(octokit, org, repo, path.join(process.cwd(), file))));
|
|
134
|
-
const currentCommit = await getCurrentCommit(octokit, org, repo, branch);
|
|
135
|
-
const newTree = await createNewTree(
|
|
136
|
-
octokit,
|
|
137
|
-
org,
|
|
138
|
-
repo,
|
|
139
|
-
fileBlobs,
|
|
140
|
-
FILES,
|
|
141
|
-
currentCommit.treeSha
|
|
142
|
-
);
|
|
143
|
-
const currentVersion = await getLatestVersion();
|
|
144
|
-
const commitMessage = `Release ${currentVersion}`;
|
|
145
|
-
const newCommit = await createNewCommit(
|
|
146
|
-
octokit,
|
|
147
|
-
org,
|
|
148
|
-
repo,
|
|
149
|
-
commitMessage,
|
|
150
|
-
newTree.sha,
|
|
151
|
-
currentCommit.commitSha
|
|
152
|
-
);
|
|
153
|
-
await setBranchToCommit(octokit, org, repo, branch, newCommit.sha);
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
async function getCurrentCommit(
|
|
158
|
-
octokit: InstanceType<typeof OctokitClass>,
|
|
159
|
-
org: string,
|
|
160
|
-
repo: string,
|
|
161
|
-
branch: string = "main"
|
|
162
|
-
): Promise<{ commitSha: string; treeSha: string }> {
|
|
163
|
-
const { data: refData } = await octokit.git.getRef({
|
|
164
|
-
owner: org,
|
|
165
|
-
repo,
|
|
166
|
-
ref: `heads/${branch}`,
|
|
167
|
-
});
|
|
168
|
-
const commitSha = refData.object.sha
|
|
169
|
-
const { data: commitData } = await octokit.git.getCommit({
|
|
170
|
-
owner: org,
|
|
171
|
-
repo,
|
|
172
|
-
commit_sha: commitSha,
|
|
173
|
-
});
|
|
174
|
-
return {
|
|
175
|
-
commitSha,
|
|
176
|
-
treeSha: commitData.tree.sha,
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
async function toBlob(
|
|
182
|
-
octokit: InstanceType<typeof OctokitClass>,
|
|
183
|
-
org: string,
|
|
184
|
-
repo: string,
|
|
185
|
-
filePath: string
|
|
186
|
-
): Promise<{ sha: string }> {
|
|
187
|
-
const content = await fs.readFile(filePath, { encoding: "utf8" });
|
|
188
|
-
const blobData = await octokit.git.createBlob({
|
|
189
|
-
owner: org,
|
|
190
|
-
repo,
|
|
191
|
-
content,
|
|
192
|
-
encoding: "utf-8",
|
|
193
|
-
})
|
|
194
|
-
return blobData.data;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
async function createNewTree(
|
|
199
|
-
octokit: InstanceType<typeof OctokitClass>,
|
|
200
|
-
owner: string,
|
|
201
|
-
repo: string,
|
|
202
|
-
blobs: { sha: string }[],
|
|
203
|
-
paths: string[],
|
|
204
|
-
parentTreeSha: string
|
|
205
|
-
): Promise<any> {
|
|
206
|
-
const tree = blobs.map(({ sha }, i) => ({
|
|
207
|
-
path: paths[i],
|
|
208
|
-
mode: "100644" as const,
|
|
209
|
-
type: "blob" as const,
|
|
210
|
-
sha,
|
|
211
|
-
}));
|
|
212
|
-
const { data } = await octokit.git.createTree({
|
|
213
|
-
owner,
|
|
214
|
-
repo,
|
|
215
|
-
tree,
|
|
216
|
-
base_tree: parentTreeSha,
|
|
217
|
-
})
|
|
218
|
-
return data;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
async function createNewCommit(
|
|
223
|
-
octokit: InstanceType<typeof OctokitClass>,
|
|
224
|
-
org: string,
|
|
225
|
-
repo: string,
|
|
226
|
-
message: string,
|
|
227
|
-
currentTreeSha: string,
|
|
228
|
-
currentCommitSha: string
|
|
229
|
-
): Promise<any> {
|
|
230
|
-
const commit = await octokit.git.createCommit({
|
|
231
|
-
owner: org,
|
|
232
|
-
repo,
|
|
233
|
-
message,
|
|
234
|
-
tree: currentTreeSha,
|
|
235
|
-
parents: [currentCommitSha],
|
|
236
|
-
});
|
|
237
|
-
return commit.data;
|
|
238
|
-
};
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
async function setBranchToCommit(
|
|
242
|
-
octokit: InstanceType<typeof OctokitClass>,
|
|
243
|
-
org: string,
|
|
244
|
-
repo: string,
|
|
245
|
-
branch: string = "main",
|
|
246
|
-
commitSha: string
|
|
247
|
-
): Promise<any> {
|
|
248
|
-
return octokit.git.updateRef({
|
|
249
|
-
owner: org,
|
|
250
|
-
repo,
|
|
251
|
-
ref: `heads/${branch}`,
|
|
252
|
-
sha: commitSha,
|
|
253
|
-
});
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
publish();
|
|
File without changes
|