Skip to content

Commit 45dcee0

Browse files
RandomBytematz3
andauthored
[FEATURE] Sapui5MavenSnapshotResolver: Use npm-dist.zip artifact for 1.116.0 and later (#622)
Use the SAP-internal npm-dist.zip instead of the default JAR when consuming SNAPSHOT versions. This artifact also contains selected test-resources and will eventually be published to the public npm registry. Since the extracted content is stored under the same directory path as the default JAR is stored in previous versions, we now only consider a package to be installed when it has a package.json. This causes old jar based packages that already exist to be removed and replaced by the new npm-dist.zip contents. JIRA: CPOUI5FOUNDATION-672 --------- Co-authored-by: Matthias Osswald <[email protected]>
1 parent 3de767f commit 45dcee0

File tree

4 files changed

+262
-18
lines changed

4 files changed

+262
-18
lines changed

lib/ui5Framework/Sapui5MavenSnapshotResolver.js

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import path from "node:path";
22
import os from "node:os";
3+
import semver from "semver";
34
import AbstractResolver from "./AbstractResolver.js";
45
import Installer from "./maven/Installer.js";
56
import {getLogger} from "@ui5/logger";
@@ -50,6 +51,11 @@ class Sapui5MavenSnapshotResolver extends AbstractResolver {
5051
cacheMode,
5152
});
5253
this._loadDistMetadata = null;
54+
55+
// TODO 4.0: Remove support for legacy snapshot versions
56+
this._isLegacySnapshotVersion = semver.lt(this._version, "1.116.0-SNAPSHOT", {
57+
includePrerelease: true
58+
});
5359
}
5460
loadDistMetadata() {
5561
if (!this._loadDistMetadata) {
@@ -95,8 +101,28 @@ class Sapui5MavenSnapshotResolver extends AbstractResolver {
95101
}
96102
const gav = metadata.gav.split(":");
97103
let pkgName = metadata.npmPackageName;
98-
if (!this._sources) {
104+
105+
// Use "npm-dist" artifact by default
106+
let classifier;
107+
let extension;
108+
if (this._sources) {
109+
// Use npm-sources artifact if sources are requested
110+
classifier = "npm-sources";
111+
extension = "zip";
112+
} else {
113+
// Add "prebuilt" suffix to package name
99114
pkgName += "-prebuilt";
115+
116+
if (this._isLegacySnapshotVersion) {
117+
// For legacy versions < 1.116.0-SNAPSHOT where npm-dist artifact is not
118+
// yet available, use "default" JAR
119+
classifier = null;
120+
extension = "jar";
121+
} else {
122+
// Use "npm-dist" artifact by default
123+
classifier = "npm-dist";
124+
extension = "zip";
125+
}
100126
}
101127

102128
return {
@@ -112,8 +138,8 @@ class Sapui5MavenSnapshotResolver extends AbstractResolver {
112138
groupId: gav[0],
113139
artifactId: gav[1],
114140
version: metadata.version,
115-
classifier: this._sources ? "npm-sources" : null,
116-
extension: this._sources ? "zip" : "jar",
141+
classifier,
142+
extension,
117143
}),
118144
};
119145
}

lib/ui5Framework/maven/Installer.js

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -443,11 +443,7 @@ class Installer extends AbstractInstaller {
443443
}
444444

445445
async _projectExists(targetDir) {
446-
const markers = await Promise.all([
447-
this._pathExists(path.join(targetDir, "package.json")),
448-
this._pathExists(path.join(targetDir, ".ui5", "build-manifest.json"))
449-
]);
450-
return markers.includes(true);
446+
return this._pathExists(path.join(targetDir, "package.json"));
451447
}
452448

453449
async _pathExists(targetPath) {

test/lib/ui5framework/Sapui5MavenSnapshotResolver.js

Lines changed: 166 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -132,15 +132,69 @@ test.serial("Sapui5MavenSnapshotResolver: handleLibrary", async (t) => {
132132

133133
const resolver = new Sapui5MavenSnapshotResolver({
134134
cwd: "/test-project/",
135-
version: "1.75.0"
135+
version: "1.116.0-SNAPSHOT"
136+
});
137+
138+
const loadDistMetadataStub = sinon.stub(resolver, "loadDistMetadata");
139+
loadDistMetadataStub.resolves({
140+
libraries: {
141+
"sap.ui.lib1": {
142+
"npmPackageName": "@openui5/sap.ui.lib1",
143+
"version": "1.116.0-SNAPSHOT",
144+
"dependencies": [],
145+
"optionalDependencies": [],
146+
"gav": "x:y:z"
147+
}
148+
}
149+
});
150+
151+
t.context.installPackageStub
152+
.callsFake(async ({pkgName, version}) => {
153+
throw new Error(`Unknown install call: ${pkgName}@${version}`);
154+
})
155+
.withArgs({
156+
pkgName: "@openui5/sap.ui.lib1-prebuilt",
157+
groupId: "x",
158+
artifactId: "y",
159+
version: "1.116.0-SNAPSHOT",
160+
classifier: "npm-dist",
161+
extension: "zip",
162+
})
163+
.resolves({pkgPath: "/foo/sap.ui.lib1"});
164+
165+
166+
const promises = await resolver.handleLibrary("sap.ui.lib1");
167+
168+
t.true(promises.metadata instanceof Promise, "Metadata promise should be returned");
169+
t.true(promises.install instanceof Promise, "Install promise should be returned");
170+
171+
const metadata = await promises.metadata;
172+
t.deepEqual(metadata, {
173+
"id": "@openui5/sap.ui.lib1-prebuilt",
174+
"version": "1.116.0-SNAPSHOT",
175+
"dependencies": [],
176+
"optionalDependencies": []
177+
}, "Expected library metadata should be returned");
178+
179+
t.deepEqual(await promises.install, {pkgPath: "/foo/sap.ui.lib1"}, "Install should resolve with expected object");
180+
t.is(loadDistMetadataStub.callCount, 1, "loadDistMetadata should be called once");
181+
});
182+
183+
184+
test.serial("Sapui5MavenSnapshotResolver: handleLibrary - legacy version", async (t) => {
185+
const {Sapui5MavenSnapshotResolver} = t.context;
186+
187+
const resolver = new Sapui5MavenSnapshotResolver({
188+
cwd: "/test-project/",
189+
version: "1.75.0-SNAPSHOT"
136190
});
137191

138192
const loadDistMetadataStub = sinon.stub(resolver, "loadDistMetadata");
139193
loadDistMetadataStub.resolves({
140194
libraries: {
141195
"sap.ui.lib1": {
142196
"npmPackageName": "@openui5/sap.ui.lib1",
143-
"version": "1.75.0",
197+
"version": "1.75.0-SNAPSHOT",
144198
"dependencies": [],
145199
"optionalDependencies": [],
146200
"gav": "x:y:z"
@@ -156,7 +210,7 @@ test.serial("Sapui5MavenSnapshotResolver: handleLibrary", async (t) => {
156210
pkgName: "@openui5/sap.ui.lib1-prebuilt",
157211
groupId: "x",
158212
artifactId: "y",
159-
version: "1.75.0",
213+
version: "1.75.0-SNAPSHOT",
160214
classifier: null,
161215
extension: "jar",
162216
})
@@ -171,7 +225,115 @@ test.serial("Sapui5MavenSnapshotResolver: handleLibrary", async (t) => {
171225
const metadata = await promises.metadata;
172226
t.deepEqual(metadata, {
173227
"id": "@openui5/sap.ui.lib1-prebuilt",
174-
"version": "1.75.0",
228+
"version": "1.75.0-SNAPSHOT",
229+
"dependencies": [],
230+
"optionalDependencies": []
231+
}, "Expected library metadata should be returned");
232+
233+
t.deepEqual(await promises.install, {pkgPath: "/foo/sap.ui.lib1"}, "Install should resolve with expected object");
234+
t.is(loadDistMetadataStub.callCount, 1, "loadDistMetadata should be called once");
235+
});
236+
237+
test.serial("Sapui5MavenSnapshotResolver: handleLibrary - sources requested", async (t) => {
238+
const {Sapui5MavenSnapshotResolver} = t.context;
239+
240+
const resolver = new Sapui5MavenSnapshotResolver({
241+
cwd: "/test-project/",
242+
version: "1.116.0-SNAPSHOT",
243+
sources: true
244+
});
245+
246+
const loadDistMetadataStub = sinon.stub(resolver, "loadDistMetadata");
247+
loadDistMetadataStub.resolves({
248+
libraries: {
249+
"sap.ui.lib1": {
250+
"npmPackageName": "@openui5/sap.ui.lib1",
251+
"version": "1.116.0-SNAPSHOT",
252+
"dependencies": [],
253+
"optionalDependencies": [],
254+
"gav": "x:y:z"
255+
}
256+
}
257+
});
258+
259+
t.context.installPackageStub
260+
.callsFake(async ({pkgName, version}) => {
261+
throw new Error(`Unknown install call: ${pkgName}@${version}`);
262+
})
263+
.withArgs({
264+
pkgName: "@openui5/sap.ui.lib1",
265+
groupId: "x",
266+
artifactId: "y",
267+
version: "1.116.0-SNAPSHOT",
268+
classifier: "npm-sources",
269+
extension: "zip",
270+
})
271+
.resolves({pkgPath: "/foo/sap.ui.lib1"});
272+
273+
274+
const promises = await resolver.handleLibrary("sap.ui.lib1");
275+
276+
t.true(promises.metadata instanceof Promise, "Metadata promise should be returned");
277+
t.true(promises.install instanceof Promise, "Install promise should be returned");
278+
279+
const metadata = await promises.metadata;
280+
t.deepEqual(metadata, {
281+
"id": "@openui5/sap.ui.lib1",
282+
"version": "1.116.0-SNAPSHOT",
283+
"dependencies": [],
284+
"optionalDependencies": []
285+
}, "Expected library metadata should be returned");
286+
287+
t.deepEqual(await promises.install, {pkgPath: "/foo/sap.ui.lib1"}, "Install should resolve with expected object");
288+
t.is(loadDistMetadataStub.callCount, 1, "loadDistMetadata should be called once");
289+
});
290+
291+
test.serial("Sapui5MavenSnapshotResolver: handleLibrary - sources requested with legacy version", async (t) => {
292+
const {Sapui5MavenSnapshotResolver} = t.context;
293+
294+
const resolver = new Sapui5MavenSnapshotResolver({
295+
cwd: "/test-project/",
296+
version: "1.75.0-SNAPSHOT",
297+
sources: true
298+
});
299+
300+
const loadDistMetadataStub = sinon.stub(resolver, "loadDistMetadata");
301+
loadDistMetadataStub.resolves({
302+
libraries: {
303+
"sap.ui.lib1": {
304+
"npmPackageName": "@openui5/sap.ui.lib1",
305+
"version": "1.75.0-SNAPSHOT",
306+
"dependencies": [],
307+
"optionalDependencies": [],
308+
"gav": "x:y:z"
309+
}
310+
}
311+
});
312+
313+
t.context.installPackageStub
314+
.callsFake(async ({pkgName, version}) => {
315+
throw new Error(`Unknown install call: ${pkgName}@${version}`);
316+
})
317+
.withArgs({
318+
pkgName: "@openui5/sap.ui.lib1",
319+
groupId: "x",
320+
artifactId: "y",
321+
version: "1.75.0-SNAPSHOT",
322+
classifier: "npm-sources",
323+
extension: "zip",
324+
})
325+
.resolves({pkgPath: "/foo/sap.ui.lib1"});
326+
327+
328+
const promises = await resolver.handleLibrary("sap.ui.lib1");
329+
330+
t.true(promises.metadata instanceof Promise, "Metadata promise should be returned");
331+
t.true(promises.install instanceof Promise, "Install promise should be returned");
332+
333+
const metadata = await promises.metadata;
334+
t.deepEqual(metadata, {
335+
"id": "@openui5/sap.ui.lib1",
336+
"version": "1.75.0-SNAPSHOT",
175337
"dependencies": [],
176338
"optionalDependencies": []
177339
}, "Expected library metadata should be returned");

test/lib/ui5framework/maven/Installer.js

Lines changed: 66 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -985,10 +985,12 @@ test.serial("_pathExists", async (t) => {
985985
snapshotEndpointUrlCb: () => {}
986986
});
987987

988-
statStub.resolves("/target/path/");
989-
const pathExists = await installer._pathExists();
988+
statStub.resolves();
989+
const pathExists = await installer._pathExists("/target/path/");
990990

991-
t.is(pathExists, true, "Resolves the target path");
991+
t.is(pathExists, true, "Target path exists");
992+
t.is(statStub.callCount, 1, "stat got called once");
993+
t.is(statStub.firstCall.firstArg, "/target/path/", "stat got called with expected argument");
992994
});
993995

994996
test.serial("_pathExists file not found", async (t) => {
@@ -1001,9 +1003,9 @@ test.serial("_pathExists file not found", async (t) => {
10011003
});
10021004

10031005
statStub.throws({code: "ENOENT"});
1004-
const pathExists = await installer._pathExists();
1006+
const pathExists = await installer._pathExists("/target/path/");
10051007

1006-
t.is(pathExists, false, "Target path is not resolved");
1008+
t.is(pathExists, false, "Target path does not exist");
10071009
});
10081010

10091011
test.serial("_pathExists throws", async (t) => {
@@ -1019,7 +1021,65 @@ test.serial("_pathExists throws", async (t) => {
10191021
throw new Error("Error message");
10201022
});
10211023

1022-
await t.throwsAsync(installer._pathExists(), {
1024+
await t.throwsAsync(installer._pathExists("/target/path/"), {
10231025
message: "Error message",
1026+
}, "Threw with expected error message");
1027+
});
1028+
1029+
test.serial("_projectExists", async (t) => {
1030+
const {Installer} = t.context;
1031+
1032+
const installer = new Installer({
1033+
cwd: "/cwd/",
1034+
ui5HomeDir: "/ui5Home/",
1035+
snapshotEndpointUrlCb: () => {}
1036+
});
1037+
1038+
const pathExistsStub = sinon.stub(installer, "_pathExists").resolves(true);
1039+
const projectExists = await installer._projectExists("/target/path/");
1040+
1041+
t.is(projectExists, true, "Resolves the target path");
1042+
t.is(pathExistsStub.callCount, 1, "_pathExists got called once");
1043+
t.is(pathExistsStub.firstCall.firstArg, path.join("/target/path/package.json"),
1044+
"_pathExists got called with expected argument");
1045+
});
1046+
1047+
test.serial("_projectExists: Does not exist", async (t) => {
1048+
const {Installer} = t.context;
1049+
1050+
const installer = new Installer({
1051+
cwd: "/cwd/",
1052+
ui5HomeDir: "/ui5Home/",
1053+
snapshotEndpointUrlCb: () => {}
1054+
});
1055+
1056+
const pathExistsStub = sinon.stub(installer, "_pathExists").resolves(false);
1057+
const projectExists = await installer._projectExists("/target/path/");
1058+
1059+
t.is(projectExists, false, "Resolves the target path");
1060+
t.is(pathExistsStub.callCount, 1, "_pathExists got called once");
1061+
t.is(pathExistsStub.firstCall.firstArg, path.join("/target/path/package.json"),
1062+
"_pathExists got called with expected argument");
1063+
});
1064+
1065+
test.serial("_projectExists: Throws", async (t) => {
1066+
const {Installer} = t.context;
1067+
1068+
const installer = new Installer({
1069+
cwd: "/cwd/",
1070+
ui5HomeDir: "/ui5Home/",
1071+
snapshotEndpointUrlCb: () => {}
10241072
});
1073+
1074+
const pathExistsStub = sinon.stub(installer, "_pathExists").throws(() => {
1075+
throw new Error("Error message");
1076+
});
1077+
1078+
await t.throwsAsync(installer._projectExists("/target/path/"), {
1079+
message: "Error message",
1080+
}, "Threw with expected error message");
1081+
1082+
t.is(pathExistsStub.callCount, 1, "_pathExists got called once");
1083+
t.is(pathExistsStub.firstCall.firstArg, path.join("/target/path/package.json"),
1084+
"_pathExists got called with expected argument");
10251085
});

0 commit comments

Comments
 (0)