From 4af1619646507a0253e66d8be0e2aa95a39ceca9 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Wed, 26 Jul 2023 14:19:40 +0300 Subject: [PATCH 01/11] Add env variable to the config --- lib/config/Configuration.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/config/Configuration.js b/lib/config/Configuration.js index 8bd14a538..b413a8799 100644 --- a/lib/config/Configuration.js +++ b/lib/config/Configuration.js @@ -41,6 +41,14 @@ class Configuration { }; } + static #resolvePath(filePath) { + const ui5DataDir = process.env.UI5_DATA_DIR; + + return filePath || + (ui5DataDir && path.resolve(path.join(ui5DataDir, ".ui5rc"))) || + path.resolve(path.join(os.homedir(), ".ui5rc")); + } + /** * Creates Configuration from a JSON file * @@ -50,7 +58,7 @@ class Configuration { * @returns {Promise<@ui5/project/config/Configuration>} Configuration instance */ static async fromFile(filePath) { - filePath = filePath || path.resolve(path.join(os.homedir(), ".ui5rc")); + filePath = Configuration.#resolvePath(filePath); const {default: fs} = await import("graceful-fs"); const {promisify} = await import("node:util"); @@ -87,7 +95,7 @@ class Configuration { * @returns {Promise} */ static async toFile(config, filePath) { - filePath = filePath || path.resolve(path.join(os.homedir(), ".ui5rc")); + filePath = Configuration.#resolvePath(filePath); const {default: fs} = await import("graceful-fs"); const {promisify} = await import("node:util"); From c6f070f3a8d495ac37b885a89be00ea7efbbd642 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Wed, 26 Jul 2023 14:19:46 +0300 Subject: [PATCH 02/11] Add tests --- test/lib/config/Configuration.js | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/test/lib/config/Configuration.js b/test/lib/config/Configuration.js index 083a2059a..d2aaffe2f 100644 --- a/test/lib/config/Configuration.js +++ b/test/lib/config/Configuration.js @@ -135,6 +135,26 @@ test.serial("toFile", async (t) => { ); }); +test.serial("toFile with custom .ui5rc destination via ENV var", async (t) => { + const {promisifyStub, sinon, Configuration} = t.context; + const toFile = Configuration.toFile; + + process.env.UI5_DATA_DIR = "/custom/ui5rc/destination"; + const writeStub = sinon.stub().resolves(); + promisifyStub.callsFake(() => writeStub); + + const config = new Configuration({mavenSnapshotEndpointUrl: "https://registry.corp/vendor/build-snapshots/"}); + await toFile(config); + + delete process.env.UI5_DATA_DIR; + + t.deepEqual( + writeStub.getCall(0).args, + ["/custom/ui5rc/destination/.ui5rc", JSON.stringify(config.toJson())], + "Write config to path" + ); +}); + test.serial("toFile: throws", async (t) => { const {promisifyStub, sinon, Configuration} = t.context; const toFile = Configuration.toFile; From 36b81abe6f32a111a81d43220c9f942477bfd9bd Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Thu, 27 Jul 2023 14:40:15 +0300 Subject: [PATCH 03/11] Add dataDir to the Config object + tests --- lib/config/Configuration.js | 36 ++++++++++++++------- test/lib/config/Configuration.js | 55 +++++++++++++++++--------------- 2 files changed, 55 insertions(+), 36 deletions(-) diff --git a/lib/config/Configuration.js b/lib/config/Configuration.js index b413a8799..4fdf8b0c2 100644 --- a/lib/config/Configuration.js +++ b/lib/config/Configuration.js @@ -11,13 +11,16 @@ import os from "node:os"; */ class Configuration { #mavenSnapshotEndpointUrl; + #ui5DataDir; /** * @param {object} configuration * @param {string} [configuration.mavenSnapshotEndpointUrl] + * @param {string} [configuration.ui5DataDir] */ - constructor({mavenSnapshotEndpointUrl}) { + constructor({mavenSnapshotEndpointUrl, ui5DataDir}) { this.#mavenSnapshotEndpointUrl = mavenSnapshotEndpointUrl; + this.#ui5DataDir = ui5DataDir; } /** @@ -31,6 +34,17 @@ class Configuration { return this.#mavenSnapshotEndpointUrl; } + /** + * Maven Repository Snapshot URL. + * Used to download artifacts and packages from Maven's build-snapshots URL. + * + * @public + * @returns {string} + */ + getUi5DataDir() { + return this.#ui5DataDir; + } + /** * @public * @returns {object} The configuration in a JSON format @@ -38,17 +52,10 @@ class Configuration { toJson() { return { mavenSnapshotEndpointUrl: this.#mavenSnapshotEndpointUrl, + ui5DataDir: this.#ui5DataDir, }; } - static #resolvePath(filePath) { - const ui5DataDir = process.env.UI5_DATA_DIR; - - return filePath || - (ui5DataDir && path.resolve(path.join(ui5DataDir, ".ui5rc"))) || - path.resolve(path.join(os.homedir(), ".ui5rc")); - } - /** * Creates Configuration from a JSON file * @@ -58,7 +65,7 @@ class Configuration { * @returns {Promise<@ui5/project/config/Configuration>} Configuration instance */ static async fromFile(filePath) { - filePath = Configuration.#resolvePath(filePath); + filePath = filePath || path.resolve(path.join(os.homedir(), ".ui5rc")); const {default: fs} = await import("graceful-fs"); const {promisify} = await import("node:util"); @@ -82,6 +89,13 @@ class Configuration { }); } } + + // ENV var should take precedence over the dataDir from the configuration. + const ui5DataDir = process.env.UI5_DATA_DIR; + if (ui5DataDir) { + config.ui5DataDir = path.resolve(path.join(ui5DataDir, ".ui5")); + } + return new Configuration(config); } @@ -95,7 +109,7 @@ class Configuration { * @returns {Promise} */ static async toFile(config, filePath) { - filePath = Configuration.#resolvePath(filePath); + filePath = filePath || path.resolve(path.join(os.homedir(), ".ui5rc")); const {default: fs} = await import("graceful-fs"); const {promisify} = await import("node:util"); diff --git a/test/lib/config/Configuration.js b/test/lib/config/Configuration.js index d2aaffe2f..aea19e3b8 100644 --- a/test/lib/config/Configuration.js +++ b/test/lib/config/Configuration.js @@ -28,13 +28,14 @@ test.afterEach.always((t) => { esmock.purge(t.context.Configuration); }); -test.serial("Build configuration with defaults", (t) => { +test("Build configuration with defaults", (t) => { const {Configuration} = t.context; const config = new Configuration({}); t.deepEqual(config.toJson(), { - mavenSnapshotEndpointUrl: undefined + mavenSnapshotEndpointUrl: undefined, + ui5DataDir: undefined, }); }); @@ -43,7 +44,8 @@ test.serial("Overwrite defaults defaults", (t) => { const {Configuration} = t.context; const params = { - mavenSnapshotEndpointUrl: "https://snapshot.url" + mavenSnapshotEndpointUrl: "https://snapshot.url", + ui5DataDir: "/custom/data/dir" }; const config = new Configuration(params); @@ -55,12 +57,14 @@ test.serial("Check getters", (t) => { const {Configuration} = t.context; const params = { - mavenSnapshotEndpointUrl: "https://snapshot.url" + mavenSnapshotEndpointUrl: "https://snapshot.url", + ui5DataDir: "/custom/data/dir" }; const config = new Configuration(params); t.is(config.getMavenSnapshotEndpointUrl(), params.mavenSnapshotEndpointUrl); + t.is(config.getUi5DataDir(), params.ui5DataDir); }); @@ -69,7 +73,8 @@ test.serial("fromFile", async (t) => { const {promisifyStub, sinon} = t.context; const ui5rcContents = { - mavenSnapshotEndpointUrl: "https://snapshot.url" + mavenSnapshotEndpointUrl: "https://snapshot.url", + ui5DataDir: "/custom/data/dir" }; const responseStub = sinon.stub().resolves(JSON.stringify(ui5rcContents)); promisifyStub.callsFake(() => responseStub); @@ -90,6 +95,7 @@ test.serial("fromFile: configuration file not found - fallback to default config t.is(config instanceof Configuration, true, "Created a default configuration"); t.is(config.getMavenSnapshotEndpointUrl(), undefined, "Default settings"); + t.is(config.getUi5DataDir(), undefined, "Default settings"); }); @@ -104,6 +110,25 @@ test.serial("fromFile: empty configuration file - fallback to default config", a t.is(config instanceof Configuration, true, "Created a default configuration"); t.is(config.getMavenSnapshotEndpointUrl(), undefined, "Default settings"); + t.is(config.getUi5DataDir(), undefined, "Default settings"); +}); + +test.serial("fromFile: ui5DataDir set via ENV variable", async (t) => { + const {promisifyStub, sinon, Configuration} = t.context; + const fromFile = Configuration.fromFile; + + process.env.UI5_DATA_DIR = "/custom/ui5rc/destination"; + + const responseStub = sinon.stub().resolves(""); + promisifyStub.callsFake(() => responseStub); + + const config = await fromFile("/non-existing/path/.ui5rc"); + + t.is(config instanceof Configuration, true, "Created a default configuration"); + t.is(config.getMavenSnapshotEndpointUrl(), undefined, "Default settings"); + t.is(config.getUi5DataDir(), "/custom/ui5rc/destination/.ui5", "ui5DataDir is resolved via the ENV Variable"); + + delete process.env.UI5_DATA_DIR; }); test.serial("fromFile: throws", async (t) => { @@ -135,26 +160,6 @@ test.serial("toFile", async (t) => { ); }); -test.serial("toFile with custom .ui5rc destination via ENV var", async (t) => { - const {promisifyStub, sinon, Configuration} = t.context; - const toFile = Configuration.toFile; - - process.env.UI5_DATA_DIR = "/custom/ui5rc/destination"; - const writeStub = sinon.stub().resolves(); - promisifyStub.callsFake(() => writeStub); - - const config = new Configuration({mavenSnapshotEndpointUrl: "https://registry.corp/vendor/build-snapshots/"}); - await toFile(config); - - delete process.env.UI5_DATA_DIR; - - t.deepEqual( - writeStub.getCall(0).args, - ["/custom/ui5rc/destination/.ui5rc", JSON.stringify(config.toJson())], - "Write config to path" - ); -}); - test.serial("toFile: throws", async (t) => { const {promisifyStub, sinon, Configuration} = t.context; const toFile = Configuration.toFile; From eff2a505d50bc83c9a0f9bf050a955bb1ed80ff8 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Thu, 27 Jul 2023 16:51:16 +0300 Subject: [PATCH 04/11] Read dataDir from the config/env var --- lib/graph/helpers/ui5Framework.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/graph/helpers/ui5Framework.js b/lib/graph/helpers/ui5Framework.js index 4dec54470..2f22e89a2 100644 --- a/lib/graph/helpers/ui5Framework.js +++ b/lib/graph/helpers/ui5Framework.js @@ -2,6 +2,7 @@ import Module from "../Module.js"; import ProjectGraph from "../ProjectGraph.js"; import {getLogger} from "@ui5/logger"; const log = getLogger("graph:helpers:ui5Framework"); +import Configuration from "../../config/Configuration.js"; class ProjectProcessor { constructor({libraryMetadata, graph, workspace}) { @@ -363,13 +364,16 @@ export default { }); } + const config = await Configuration.fromFile(); + // Note: version might be undefined here and the Resolver will throw an error when calling // #install and it can't be resolved via the provided library metadata const resolver = new Resolver({ cwd: rootProject.getRootPath(), version, providedLibraryMetadata, - cacheMode + cacheMode, + ui5HomeDir: config.getUi5DataDir() }); let startTime; From b3759ff7f0afa4260c4309cf72fcf2a7e863eafd Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Thu, 27 Jul 2023 16:51:24 +0300 Subject: [PATCH 05/11] Fix tests --- test/lib/graph/helpers/ui5Framework.js | 8 ++++++++ test/lib/ui5framework/Sapui5MavenSnapshotResolver.js | 3 ++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/test/lib/graph/helpers/ui5Framework.js b/test/lib/graph/helpers/ui5Framework.js index 458397f30..c7906da58 100644 --- a/test/lib/graph/helpers/ui5Framework.js +++ b/test/lib/graph/helpers/ui5Framework.js @@ -113,6 +113,7 @@ test.serial("enrichProjectGraph", async (t) => { cacheMode: undefined, cwd: dependencyTree.path, version: dependencyTree.configuration.framework.version, + ui5HomeDir: undefined, providedLibraryMetadata: undefined }], "Sapui5Resolver#constructor should be called with expected args"); @@ -319,6 +320,7 @@ test.serial("enrichProjectGraph: With versionOverride", async (t) => { cacheMode: undefined, cwd: dependencyTree.path, version: "1.99.9", + ui5HomeDir: undefined, providedLibraryMetadata: undefined }], "Sapui5Resolver#constructor should be called with expected args"); }); @@ -375,6 +377,7 @@ test.serial("enrichProjectGraph: With versionOverride containing snapshot versio cacheMode: undefined, cwd: dependencyTree.path, version: "1.99.9-SNAPSHOT", + ui5HomeDir: undefined, providedLibraryMetadata: undefined }], "Sapui5Resolver#constructor should be called with expected args"); }); @@ -431,6 +434,7 @@ test.serial("enrichProjectGraph: With versionOverride containing latest-snapshot cacheMode: undefined, cwd: dependencyTree.path, version: "1.99.9-SNAPSHOT", + ui5HomeDir: undefined, providedLibraryMetadata: undefined }], "Sapui5Resolver#constructor should be called with expected args"); }); @@ -587,6 +591,7 @@ test.serial("enrichProjectGraph should resolve framework project with version an cacheMode: undefined, cwd: dependencyTree.path, version: "1.2.3", + ui5HomeDir: undefined, providedLibraryMetadata: undefined }], "Sapui5Resolver#constructor should be called with expected args"); }); @@ -685,6 +690,7 @@ test.serial("enrichProjectGraph should resolve framework project " + cacheMode: undefined, cwd: dependencyTree.path, version: "1.99.9", + ui5HomeDir: undefined, providedLibraryMetadata: undefined }], "Sapui5Resolver#constructor should be called with expected args"); }); @@ -949,6 +955,7 @@ test.serial("enrichProjectGraph should use framework library metadata from works cacheMode: undefined, cwd: dependencyTree.path, version: "1.111.1", + ui5HomeDir: undefined, providedLibraryMetadata: workspaceFrameworkLibraryMetadata }], "Sapui5Resolver#constructor should be called with expected args"); t.is(Sapui5ResolverStub.getCall(0).args[0].providedLibraryMetadata, workspaceFrameworkLibraryMetadata); @@ -1006,6 +1013,7 @@ test.serial("enrichProjectGraph should allow omitting framework version in case t.deepEqual(Sapui5ResolverStub.getCall(0).args, [{ cacheMode: undefined, cwd: dependencyTree.path, + ui5HomeDir: undefined, version: undefined, providedLibraryMetadata: workspaceFrameworkLibraryMetadata }], "Sapui5Resolver#constructor should be called with expected args"); diff --git a/test/lib/ui5framework/Sapui5MavenSnapshotResolver.js b/test/lib/ui5framework/Sapui5MavenSnapshotResolver.js index 54fe3260a..0d7382d58 100644 --- a/test/lib/ui5framework/Sapui5MavenSnapshotResolver.js +++ b/test/lib/ui5framework/Sapui5MavenSnapshotResolver.js @@ -480,7 +480,8 @@ test.serial("_resolveSnapshotEndpointUrl: Maven fallback with config update", as t.is(configFromFile.callCount, 1, "Configuration has been read once"); t.is(configToFile.callCount, 1, "Configuration has been written once"); t.deepEqual(configToFile.firstCall.firstArg.toJson(), { - mavenSnapshotEndpointUrl: "maven-url" + mavenSnapshotEndpointUrl: "maven-url", + ui5DataDir: undefined }, "Correct configuration has been written"); }); From cdec60d51b9b7439151adaa7a439735360801a58 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Fri, 28 Jul 2023 10:06:30 +0300 Subject: [PATCH 06/11] Adjust jsdoc & tests --- lib/config/Configuration.js | 3 +-- test/lib/config/Configuration.js | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/config/Configuration.js b/lib/config/Configuration.js index 4fdf8b0c2..1e6caa5a3 100644 --- a/lib/config/Configuration.js +++ b/lib/config/Configuration.js @@ -35,8 +35,7 @@ class Configuration { } /** - * Maven Repository Snapshot URL. - * Used to download artifacts and packages from Maven's build-snapshots URL. + * Configurable directory where the artifacts would be stored. * * @public * @returns {string} diff --git a/test/lib/config/Configuration.js b/test/lib/config/Configuration.js index aea19e3b8..9acd7f060 100644 --- a/test/lib/config/Configuration.js +++ b/test/lib/config/Configuration.js @@ -28,7 +28,7 @@ test.afterEach.always((t) => { esmock.purge(t.context.Configuration); }); -test("Build configuration with defaults", (t) => { +test.serial("Build configuration with defaults", (t) => { const {Configuration} = t.context; const config = new Configuration({}); From 27945b814da47a81ab8f8defeb5ff9ece8fcf5f0 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Fri, 28 Jul 2023 12:58:04 +0300 Subject: [PATCH 07/11] Update jsdocs --- lib/config/Configuration.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/config/Configuration.js b/lib/config/Configuration.js index 1e6caa5a3..bb94b452f 100644 --- a/lib/config/Configuration.js +++ b/lib/config/Configuration.js @@ -35,7 +35,7 @@ class Configuration { } /** - * Configurable directory where the artifacts would be stored. + * Configurable directory where the framework artefacts would be stored. * * @public * @returns {string} From 29a3ae4cc22809a9fbbe971514ef4b1b0d7a72b0 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Fri, 28 Jul 2023 15:01:11 +0300 Subject: [PATCH 08/11] Move defaults out of Configuration --- lib/config/Configuration.js | 6 ------ lib/graph/helpers/ui5Framework.js | 7 ++++++- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/lib/config/Configuration.js b/lib/config/Configuration.js index bb94b452f..91a2a15a4 100644 --- a/lib/config/Configuration.js +++ b/lib/config/Configuration.js @@ -89,12 +89,6 @@ class Configuration { } } - // ENV var should take precedence over the dataDir from the configuration. - const ui5DataDir = process.env.UI5_DATA_DIR; - if (ui5DataDir) { - config.ui5DataDir = path.resolve(path.join(ui5DataDir, ".ui5")); - } - return new Configuration(config); } diff --git a/lib/graph/helpers/ui5Framework.js b/lib/graph/helpers/ui5Framework.js index 2f22e89a2..5d31cf8c7 100644 --- a/lib/graph/helpers/ui5Framework.js +++ b/lib/graph/helpers/ui5Framework.js @@ -3,6 +3,7 @@ import ProjectGraph from "../ProjectGraph.js"; import {getLogger} from "@ui5/logger"; const log = getLogger("graph:helpers:ui5Framework"); import Configuration from "../../config/Configuration.js"; +import path from "node:path"; class ProjectProcessor { constructor({libraryMetadata, graph, workspace}) { @@ -365,6 +366,10 @@ export default { } const config = await Configuration.fromFile(); + // ENV var should take precedence over the dataDir from the configuration. + const ui5HomeDir = process.env.UI5_DATA_DIR ? + path.resolve(path.join(process.env.UI5_DATA_DIR, ".ui5")) : + config.getUi5DataDir(); // Note: version might be undefined here and the Resolver will throw an error when calling // #install and it can't be resolved via the provided library metadata @@ -373,7 +378,7 @@ export default { version, providedLibraryMetadata, cacheMode, - ui5HomeDir: config.getUi5DataDir() + ui5HomeDir }); let startTime; From eff41e8de82df944115de3957add96309ba46de5 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Fri, 28 Jul 2023 15:02:06 +0300 Subject: [PATCH 09/11] Fix tests --- test/lib/config/Configuration.js | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/test/lib/config/Configuration.js b/test/lib/config/Configuration.js index 9acd7f060..1019fe526 100644 --- a/test/lib/config/Configuration.js +++ b/test/lib/config/Configuration.js @@ -113,24 +113,6 @@ test.serial("fromFile: empty configuration file - fallback to default config", a t.is(config.getUi5DataDir(), undefined, "Default settings"); }); -test.serial("fromFile: ui5DataDir set via ENV variable", async (t) => { - const {promisifyStub, sinon, Configuration} = t.context; - const fromFile = Configuration.fromFile; - - process.env.UI5_DATA_DIR = "/custom/ui5rc/destination"; - - const responseStub = sinon.stub().resolves(""); - promisifyStub.callsFake(() => responseStub); - - const config = await fromFile("/non-existing/path/.ui5rc"); - - t.is(config instanceof Configuration, true, "Created a default configuration"); - t.is(config.getMavenSnapshotEndpointUrl(), undefined, "Default settings"); - t.is(config.getUi5DataDir(), "/custom/ui5rc/destination/.ui5", "ui5DataDir is resolved via the ENV Variable"); - - delete process.env.UI5_DATA_DIR; -}); - test.serial("fromFile: throws", async (t) => { const fromFile = t.context.Configuration.fromFile; const {promisifyStub, sinon} = t.context; From 1e82a12a49ca2a32f0320549ec6c3f5171748549 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Tue, 1 Aug 2023 12:42:56 +0300 Subject: [PATCH 10/11] Update lib/config/Configuration.js Co-authored-by: Florian Vogt --- lib/config/Configuration.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/config/Configuration.js b/lib/config/Configuration.js index 91a2a15a4..7e04b0fb4 100644 --- a/lib/config/Configuration.js +++ b/lib/config/Configuration.js @@ -35,7 +35,7 @@ class Configuration { } /** - * Configurable directory where the framework artefacts would be stored. + * Configurable directory where the framework artefacts are stored. * * @public * @returns {string} From b19414024e6c323172d98eac613ac4844a330279 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Tue, 8 Aug 2023 09:05:25 +0300 Subject: [PATCH 11/11] Use dataDir as homeDir and do not suffix with .ui5 --- lib/graph/helpers/ui5Framework.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/graph/helpers/ui5Framework.js b/lib/graph/helpers/ui5Framework.js index 5d31cf8c7..1a02f4c52 100644 --- a/lib/graph/helpers/ui5Framework.js +++ b/lib/graph/helpers/ui5Framework.js @@ -368,7 +368,7 @@ export default { const config = await Configuration.fromFile(); // ENV var should take precedence over the dataDir from the configuration. const ui5HomeDir = process.env.UI5_DATA_DIR ? - path.resolve(path.join(process.env.UI5_DATA_DIR, ".ui5")) : + path.resolve(process.env.UI5_DATA_DIR) : config.getUi5DataDir(); // Note: version might be undefined here and the Resolver will throw an error when calling