Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEATURE] Introduce SpecificationVersion class #431

Merged
merged 10 commits into from
Nov 28, 2022
5 changes: 3 additions & 2 deletions lib/build/TaskRunner.js
Original file line number Diff line number Diff line change
Expand Up @@ -309,12 +309,13 @@ class TaskRunner {
params.dependencies = dependencies;
}

if (task.getSpecVersion() === "3.0") {
const specVersion = task.getSpecVersionComparator();
Copy link
Member

@matz3 matz3 Nov 28, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I struggle a bit with the naming of both the class and the getter. Here it's used with specVersion as local variable which reads fine (specVersion is greater then or equal to 3.0). But specVersionComparator.gte("3.0") would be strange.
But I also don't have a better idea, also as getSpecVersion() already returns the string. My only idea is to combine both to have getSpecVersion().toString() and getSpecVersion().gte("3.0")

Copy link
Member

@RandomByte RandomByte Nov 28, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not happy with the naming either.

I guess we could make this a SpecificationVersion class and have getSpecVersion() always return an instance of it. Indeed that might make things a bit simpler in the end.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that sounds good 👍🏻

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in latest commit. I think this is way better, since the main use of a project's spec version is to compare it anyways 👍

if (specVersion.gte("3.0")) {
params.options.taskName = newTaskName;
params.log = logger.getGroupLogger(`builder:custom-task:${newTaskName}`);
}

const taskUtilInterface = taskUtil.getInterface(task.getSpecVersion());
const taskUtilInterface = taskUtil.getInterface(specVersion);
// Interface is undefined if specVersion does not support taskUtil
if (taskUtilInterface) {
params.taskUtil = taskUtilInterface;
Expand Down
26 changes: 8 additions & 18 deletions lib/build/helpers/TaskUtil.js
Original file line number Diff line number Diff line change
Expand Up @@ -269,11 +269,13 @@ class TaskUtil {
* Get an interface to an instance of this class that only provides those functions
* that are supported by the given custom task extension specification version.
*
* @param {string} specVersion Specification version of custom task extension
* @param {@ui5/project/specifications/utils/SpecVersionComparator} specVersion
* SpecVersionComparator instance of the custom task
* @returns {object} An object with bound instance methods supported by the given specification version
*/
getInterface(specVersion) {
if (["0.1", "1.0", "1.1", "2.0", "2.1"].includes(specVersion)) {
if (specVersion.lte("2.1")) {
// Tasks defining specVersion <= 2.1 do not have access to any TaskUtil APIs
return undefined;
}

Expand All @@ -283,14 +285,8 @@ class TaskUtil {
bindFunctions(this, baseInterface, [
"setTag", "clearTag", "getTag", "isRootProject", "registerCleanupTask"
]);
switch (specVersion) {
case "2.2":
case "2.3":
case "2.4":
case "2.5":
case "2.6":
return baseInterface;
case "3.0":

if (specVersion.gte("3.0")) {
// getProject function, returning an interfaced project instance
baseInterface.getProject = (projectName) => {
const project = this.getProject(projectName);
Expand All @@ -299,10 +295,7 @@ class TaskUtil {
"getSpecVersion", "getType", "getName", "getVersion", "getNamespace",
"getRootReader", "getReader", "getCustomConfiguration", "isFrameworkProject"
]);
switch (specVersion) {
case "3.0":
return baseProjectInterface;
}
return baseProjectInterface;
};
// getDependencies function, returning an array of project names
baseInterface.getDependencies = (projectName) => {
Expand All @@ -318,11 +311,8 @@ class TaskUtil {
].forEach((factoryFunction) => {
baseInterface.resourceFactory[factoryFunction] = this.resourceFactory[factoryFunction];
});

return baseInterface;
default:
throw new Error(`TaskUtil: Unknown or unsupported Specification Version ${specVersion}`);
}
return baseInterface;
}
}

Expand Down
27 changes: 15 additions & 12 deletions lib/specifications/Specification.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import logger from "@ui5/logger";
import {createReader} from "@ui5/fs/resourceFactory";
import SpecVersionComparator from "./utils/SpecVersionComparator.js";

/**
* Abstract superclass for all projects and extensions
Expand Down Expand Up @@ -50,10 +51,9 @@ class Specification {
const config = JSON.parse(JSON.stringify(configuration));
const {validate} = await import("../validation/validator.js");

if (config.specVersion === "0.1" || config.specVersion === "1.0" ||
config.specVersion === "1.1") {
if (SpecVersionComparator.major(config.specVersion) <= 1) {
const originalSpecVersion = config.specVersion;
this._log.verbose(`Detected legacy specification version ${config.specVersion}, defined for ` +
this._log.verbose(`Detected legacy Specification Version ${config.specVersion}, defined for ` +
`${config.kind} ${config.metadata.name}. ` +
`Attempting to migrate the project to a supported specification version...`);
this._migrateLegacyProject(config);
Expand All @@ -69,20 +69,12 @@ class Specification {
`Validation error after migration of ${config.kind} ${config.metadata.name}:`);
this._log.verbose(err.message);
throw new Error(
`${config.kind} ${config.metadata.name} defines unsupported specification version ` +
`${config.kind} ${config.metadata.name} defines unsupported Specification Version ` +
`${originalSpecVersion}. Please manually upgrade to 2.0 or higher. ` +
`For details see https://sap.github.io/ui5-tooling/pages/Configuration/#specification-versions - ` +
`An attempted migration to a supported specification version failed, ` +
`likely due to unrecognized configuration. Check verbose log for details.`);
}
} else if (config.specVersion !== "2.0" &&
config.specVersion !== "2.1" && config.specVersion !== "2.2" &&
config.specVersion !== "2.3" && config.specVersion !== "2.4" &&
config.specVersion !== "2.5" && config.specVersion !== "2.6") {
throw new Error(
`Unsupported specification version ${config.specVersion} defined in ${config.kind} ` +
`${config.metadata.name}. Your UI5 CLI installation might be outdated. ` +
`For details see https://sap.github.io/ui5-tooling/pages/Configuration/#specification-versions`);
} else {
await validate({
config,
Expand Down Expand Up @@ -151,6 +143,17 @@ class Specification {
return this._specVersion;
}

/**
* Returns an instance of a helper class allowing for convenient comparison
* operations against this instance's Specification Version
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does everybody know what a Specification Version is? I'm wondering if this whole versioning business is explained somewhere in the documentation.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have a chapter in our documentation regarding that: https://sap.github.io/ui5-tooling/pages/Configuration/#specification-versions

*
* @public
* @returns {@ui5/project/specifications/utils/SpecVersionComparator}
*/
getSpecVersionComparator() {
return new SpecVersionComparator(this.getSpecVersion());
}

/**
* Get the specification's generic version, as typically defined in a <code>package.json</code>
*
Expand Down
Loading