Skip to content

Commit

Permalink
[FEATURE] Sapui5MavenSnapshotResolver: Use npm-dist.zip artifact for …
Browse files Browse the repository at this point in the history
…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 <mat.osswald@sap.com>
  • Loading branch information
RandomByte and matz3 authored Jun 20, 2023
1 parent 3de767f commit 45dcee0
Show file tree
Hide file tree
Showing 4 changed files with 262 additions and 18 deletions.
32 changes: 29 additions & 3 deletions lib/ui5Framework/Sapui5MavenSnapshotResolver.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import path from "node:path";
import os from "node:os";
import semver from "semver";
import AbstractResolver from "./AbstractResolver.js";
import Installer from "./maven/Installer.js";
import {getLogger} from "@ui5/logger";
Expand Down Expand Up @@ -50,6 +51,11 @@ class Sapui5MavenSnapshotResolver extends AbstractResolver {
cacheMode,
});
this._loadDistMetadata = null;

// TODO 4.0: Remove support for legacy snapshot versions
this._isLegacySnapshotVersion = semver.lt(this._version, "1.116.0-SNAPSHOT", {
includePrerelease: true
});
}
loadDistMetadata() {
if (!this._loadDistMetadata) {
Expand Down Expand Up @@ -95,8 +101,28 @@ class Sapui5MavenSnapshotResolver extends AbstractResolver {
}
const gav = metadata.gav.split(":");
let pkgName = metadata.npmPackageName;
if (!this._sources) {

// Use "npm-dist" artifact by default
let classifier;
let extension;
if (this._sources) {
// Use npm-sources artifact if sources are requested
classifier = "npm-sources";
extension = "zip";
} else {
// Add "prebuilt" suffix to package name
pkgName += "-prebuilt";

if (this._isLegacySnapshotVersion) {
// For legacy versions < 1.116.0-SNAPSHOT where npm-dist artifact is not
// yet available, use "default" JAR
classifier = null;
extension = "jar";
} else {
// Use "npm-dist" artifact by default
classifier = "npm-dist";
extension = "zip";
}
}

return {
Expand All @@ -112,8 +138,8 @@ class Sapui5MavenSnapshotResolver extends AbstractResolver {
groupId: gav[0],
artifactId: gav[1],
version: metadata.version,
classifier: this._sources ? "npm-sources" : null,
extension: this._sources ? "zip" : "jar",
classifier,
extension,
}),
};
}
Expand Down
6 changes: 1 addition & 5 deletions lib/ui5Framework/maven/Installer.js
Original file line number Diff line number Diff line change
Expand Up @@ -443,11 +443,7 @@ class Installer extends AbstractInstaller {
}

async _projectExists(targetDir) {
const markers = await Promise.all([
this._pathExists(path.join(targetDir, "package.json")),
this._pathExists(path.join(targetDir, ".ui5", "build-manifest.json"))
]);
return markers.includes(true);
return this._pathExists(path.join(targetDir, "package.json"));
}

async _pathExists(targetPath) {
Expand Down
170 changes: 166 additions & 4 deletions test/lib/ui5framework/Sapui5MavenSnapshotResolver.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,15 +132,69 @@ test.serial("Sapui5MavenSnapshotResolver: handleLibrary", async (t) => {

const resolver = new Sapui5MavenSnapshotResolver({
cwd: "/test-project/",
version: "1.75.0"
version: "1.116.0-SNAPSHOT"
});

const loadDistMetadataStub = sinon.stub(resolver, "loadDistMetadata");
loadDistMetadataStub.resolves({
libraries: {
"sap.ui.lib1": {
"npmPackageName": "@openui5/sap.ui.lib1",
"version": "1.116.0-SNAPSHOT",
"dependencies": [],
"optionalDependencies": [],
"gav": "x:y:z"
}
}
});

t.context.installPackageStub
.callsFake(async ({pkgName, version}) => {
throw new Error(`Unknown install call: ${pkgName}@${version}`);
})
.withArgs({
pkgName: "@openui5/sap.ui.lib1-prebuilt",
groupId: "x",
artifactId: "y",
version: "1.116.0-SNAPSHOT",
classifier: "npm-dist",
extension: "zip",
})
.resolves({pkgPath: "/foo/sap.ui.lib1"});


const promises = await resolver.handleLibrary("sap.ui.lib1");

t.true(promises.metadata instanceof Promise, "Metadata promise should be returned");
t.true(promises.install instanceof Promise, "Install promise should be returned");

const metadata = await promises.metadata;
t.deepEqual(metadata, {
"id": "@openui5/sap.ui.lib1-prebuilt",
"version": "1.116.0-SNAPSHOT",
"dependencies": [],
"optionalDependencies": []
}, "Expected library metadata should be returned");

t.deepEqual(await promises.install, {pkgPath: "/foo/sap.ui.lib1"}, "Install should resolve with expected object");
t.is(loadDistMetadataStub.callCount, 1, "loadDistMetadata should be called once");
});


test.serial("Sapui5MavenSnapshotResolver: handleLibrary - legacy version", async (t) => {
const {Sapui5MavenSnapshotResolver} = t.context;

const resolver = new Sapui5MavenSnapshotResolver({
cwd: "/test-project/",
version: "1.75.0-SNAPSHOT"
});

const loadDistMetadataStub = sinon.stub(resolver, "loadDistMetadata");
loadDistMetadataStub.resolves({
libraries: {
"sap.ui.lib1": {
"npmPackageName": "@openui5/sap.ui.lib1",
"version": "1.75.0",
"version": "1.75.0-SNAPSHOT",
"dependencies": [],
"optionalDependencies": [],
"gav": "x:y:z"
Expand All @@ -156,7 +210,7 @@ test.serial("Sapui5MavenSnapshotResolver: handleLibrary", async (t) => {
pkgName: "@openui5/sap.ui.lib1-prebuilt",
groupId: "x",
artifactId: "y",
version: "1.75.0",
version: "1.75.0-SNAPSHOT",
classifier: null,
extension: "jar",
})
Expand All @@ -171,7 +225,115 @@ test.serial("Sapui5MavenSnapshotResolver: handleLibrary", async (t) => {
const metadata = await promises.metadata;
t.deepEqual(metadata, {
"id": "@openui5/sap.ui.lib1-prebuilt",
"version": "1.75.0",
"version": "1.75.0-SNAPSHOT",
"dependencies": [],
"optionalDependencies": []
}, "Expected library metadata should be returned");

t.deepEqual(await promises.install, {pkgPath: "/foo/sap.ui.lib1"}, "Install should resolve with expected object");
t.is(loadDistMetadataStub.callCount, 1, "loadDistMetadata should be called once");
});

test.serial("Sapui5MavenSnapshotResolver: handleLibrary - sources requested", async (t) => {
const {Sapui5MavenSnapshotResolver} = t.context;

const resolver = new Sapui5MavenSnapshotResolver({
cwd: "/test-project/",
version: "1.116.0-SNAPSHOT",
sources: true
});

const loadDistMetadataStub = sinon.stub(resolver, "loadDistMetadata");
loadDistMetadataStub.resolves({
libraries: {
"sap.ui.lib1": {
"npmPackageName": "@openui5/sap.ui.lib1",
"version": "1.116.0-SNAPSHOT",
"dependencies": [],
"optionalDependencies": [],
"gav": "x:y:z"
}
}
});

t.context.installPackageStub
.callsFake(async ({pkgName, version}) => {
throw new Error(`Unknown install call: ${pkgName}@${version}`);
})
.withArgs({
pkgName: "@openui5/sap.ui.lib1",
groupId: "x",
artifactId: "y",
version: "1.116.0-SNAPSHOT",
classifier: "npm-sources",
extension: "zip",
})
.resolves({pkgPath: "/foo/sap.ui.lib1"});


const promises = await resolver.handleLibrary("sap.ui.lib1");

t.true(promises.metadata instanceof Promise, "Metadata promise should be returned");
t.true(promises.install instanceof Promise, "Install promise should be returned");

const metadata = await promises.metadata;
t.deepEqual(metadata, {
"id": "@openui5/sap.ui.lib1",
"version": "1.116.0-SNAPSHOT",
"dependencies": [],
"optionalDependencies": []
}, "Expected library metadata should be returned");

t.deepEqual(await promises.install, {pkgPath: "/foo/sap.ui.lib1"}, "Install should resolve with expected object");
t.is(loadDistMetadataStub.callCount, 1, "loadDistMetadata should be called once");
});

test.serial("Sapui5MavenSnapshotResolver: handleLibrary - sources requested with legacy version", async (t) => {
const {Sapui5MavenSnapshotResolver} = t.context;

const resolver = new Sapui5MavenSnapshotResolver({
cwd: "/test-project/",
version: "1.75.0-SNAPSHOT",
sources: true
});

const loadDistMetadataStub = sinon.stub(resolver, "loadDistMetadata");
loadDistMetadataStub.resolves({
libraries: {
"sap.ui.lib1": {
"npmPackageName": "@openui5/sap.ui.lib1",
"version": "1.75.0-SNAPSHOT",
"dependencies": [],
"optionalDependencies": [],
"gav": "x:y:z"
}
}
});

t.context.installPackageStub
.callsFake(async ({pkgName, version}) => {
throw new Error(`Unknown install call: ${pkgName}@${version}`);
})
.withArgs({
pkgName: "@openui5/sap.ui.lib1",
groupId: "x",
artifactId: "y",
version: "1.75.0-SNAPSHOT",
classifier: "npm-sources",
extension: "zip",
})
.resolves({pkgPath: "/foo/sap.ui.lib1"});


const promises = await resolver.handleLibrary("sap.ui.lib1");

t.true(promises.metadata instanceof Promise, "Metadata promise should be returned");
t.true(promises.install instanceof Promise, "Install promise should be returned");

const metadata = await promises.metadata;
t.deepEqual(metadata, {
"id": "@openui5/sap.ui.lib1",
"version": "1.75.0-SNAPSHOT",
"dependencies": [],
"optionalDependencies": []
}, "Expected library metadata should be returned");
Expand Down
72 changes: 66 additions & 6 deletions test/lib/ui5framework/maven/Installer.js
Original file line number Diff line number Diff line change
Expand Up @@ -985,10 +985,12 @@ test.serial("_pathExists", async (t) => {
snapshotEndpointUrlCb: () => {}
});

statStub.resolves("/target/path/");
const pathExists = await installer._pathExists();
statStub.resolves();
const pathExists = await installer._pathExists("/target/path/");

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

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

statStub.throws({code: "ENOENT"});
const pathExists = await installer._pathExists();
const pathExists = await installer._pathExists("/target/path/");

t.is(pathExists, false, "Target path is not resolved");
t.is(pathExists, false, "Target path does not exist");
});

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

await t.throwsAsync(installer._pathExists(), {
await t.throwsAsync(installer._pathExists("/target/path/"), {
message: "Error message",
}, "Threw with expected error message");
});

test.serial("_projectExists", async (t) => {
const {Installer} = t.context;

const installer = new Installer({
cwd: "/cwd/",
ui5HomeDir: "/ui5Home/",
snapshotEndpointUrlCb: () => {}
});

const pathExistsStub = sinon.stub(installer, "_pathExists").resolves(true);
const projectExists = await installer._projectExists("/target/path/");

t.is(projectExists, true, "Resolves the target path");
t.is(pathExistsStub.callCount, 1, "_pathExists got called once");
t.is(pathExistsStub.firstCall.firstArg, path.join("/target/path/package.json"),
"_pathExists got called with expected argument");
});

test.serial("_projectExists: Does not exist", async (t) => {
const {Installer} = t.context;

const installer = new Installer({
cwd: "/cwd/",
ui5HomeDir: "/ui5Home/",
snapshotEndpointUrlCb: () => {}
});

const pathExistsStub = sinon.stub(installer, "_pathExists").resolves(false);
const projectExists = await installer._projectExists("/target/path/");

t.is(projectExists, false, "Resolves the target path");
t.is(pathExistsStub.callCount, 1, "_pathExists got called once");
t.is(pathExistsStub.firstCall.firstArg, path.join("/target/path/package.json"),
"_pathExists got called with expected argument");
});

test.serial("_projectExists: Throws", async (t) => {
const {Installer} = t.context;

const installer = new Installer({
cwd: "/cwd/",
ui5HomeDir: "/ui5Home/",
snapshotEndpointUrlCb: () => {}
});

const pathExistsStub = sinon.stub(installer, "_pathExists").throws(() => {
throw new Error("Error message");
});

await t.throwsAsync(installer._projectExists("/target/path/"), {
message: "Error message",
}, "Threw with expected error message");

t.is(pathExistsStub.callCount, 1, "_pathExists got called once");
t.is(pathExistsStub.firstCall.firstArg, path.join("/target/path/package.json"),
"_pathExists got called with expected argument");
});

0 comments on commit 45dcee0

Please sign in to comment.