diff --git a/lib/graph/graph.js b/lib/graph/graph.js index f0e10c613..61a1c9dc3 100644 --- a/lib/graph/graph.js +++ b/lib/graph/graph.js @@ -5,25 +5,6 @@ import createWorkspace from "./helpers/createWorkspace.js"; import {getLogger} from "@ui5/logger"; const log = getLogger("generateProjectGraph"); -function resolveProjectPaths(cwd, project) { - if (!project.path) { - throw new Error(`Missing or empty attribute 'path' for project ${project.id}`); - } - project.path = path.resolve(cwd, project.path); - - if (!project.id) { - throw new Error(`Missing or empty attribute 'id' for project with path ${project.path}`); - } - if (!project.version) { - throw new Error(`Missing or empty attribute 'version' for project ${project.id}`); - } - - if (project.dependencies) { - project.dependencies.forEach((project) => resolveProjectPaths(cwd, project)); - } - return project; -} - /** * Helper module to create a [@ui5/project/graph/ProjectGraph]{@link @ui5/project/graph/ProjectGraph} * from a directory @@ -43,7 +24,8 @@ function resolveProjectPaths(cwd, project) { * @param {object} [options.rootConfiguration] * Configuration object to use for the root module instead of reading from a configuration file * @param {string} [options.rootConfigPath] - * Configuration file to use for the root module instead the default ui5.yaml + * Configuration file to use for the root module instead the default ui5.yaml. Either a path relative to + * cwd or an absolute path. In both case, platform-specific path segment separators must be used. * @param {string} [options.versionOverride] Framework version to use instead of the one defined in the root project * @param {string} [options.resolveFrameworkDependencies=true] * Whether framework dependencies should be added to the graph @@ -67,6 +49,7 @@ export async function graphFromPackageDependencies({ } = await import("./providers/NodePackageDependencies.js"); cwd = cwd ? path.resolve(cwd) : process.cwd(); + rootConfigPath = utils.resolveConfigPath(cwd, rootConfigPath); let workspace; if (workspaceName || workspaceConfiguration) { @@ -106,24 +89,28 @@ export async function graphFromPackageDependencies({ * @param {object} [options.rootConfiguration] * Configuration object to use for the root module instead of reading from a configuration file * @param {string} [options.rootConfigPath] - * Configuration file to use for the root module instead the default ui5.yaml + * Configuration file to use for the root module instead the default ui5.yaml. Either a path relative to + * cwd or an absolute path. In both case, platform-specific path segment separators must be used. * @param {string} [options.versionOverride] Framework version to use instead of the one defined in the root project * @param {string} [options.resolveFrameworkDependencies=true] * Whether framework dependencies should be added to the graph * @returns {Promise<@ui5/project/graph/ProjectGraph>} Promise resolving to a Project Graph instance */ export async function graphFromStaticFile({ - cwd, filePath = "projectDependencies.yaml", + filePath = "projectDependencies.yaml", cwd, rootConfiguration, rootConfigPath, versionOverride, resolveFrameworkDependencies = true }) { log.verbose(`Creating project graph using static file...`); - - const dependencyTree = await utils.readDependencyConfigFile(cwd ? path.resolve(cwd) : process.cwd(), filePath); - const { default: DependencyTreeProvider } = await import("./providers/DependencyTree.js"); + + cwd = cwd ? path.resolve(cwd) : process.cwd(); + rootConfigPath = utils.resolveConfigPath(cwd, rootConfigPath); + + const dependencyTree = await utils.readDependencyConfigFile(cwd, filePath); + const provider = new DependencyTreeProvider({ dependencyTree, rootConfiguration, @@ -148,25 +135,30 @@ export async function graphFromStaticFile({ * @static * @param {object} options * @param {@ui5/project/graph/providers/DependencyTree~TreeNode} options.dependencyTree + * @param {string} [options.cwd=process.cwd()] Directory to resolve relative paths to * @param {object} [options.rootConfiguration] * Configuration object to use for the root module instead of reading from a configuration file * @param {string} [options.rootConfigPath] - * Configuration file to use for the root module instead the default ui5.yaml + * Configuration file to use for the root module instead the default ui5.yaml. Either a path relative to + * cwd or an absolute path. In both case, platform-specific path segment separators must be used. * @param {string} [options.versionOverride] Framework version to use instead of the one defined in the root project * @param {string} [options.resolveFrameworkDependencies=true] * Whether framework dependencies should be added to the graph * @returns {Promise<@ui5/project/graph/ProjectGraph>} Promise resolving to a Project Graph instance */ export async function graphFromObject({ - dependencyTree, + dependencyTree, cwd, rootConfiguration, rootConfigPath, versionOverride, resolveFrameworkDependencies = true }) { log.verbose(`Creating project graph using object...`); - const { default: DependencyTreeProvider } = await import("./providers/DependencyTree.js"); + + cwd = cwd ? path.resolve(cwd) : process.cwd(); + rootConfigPath = utils.resolveConfigPath(cwd, rootConfigPath); + const dependencyTreeProvider = new DependencyTreeProvider({ dependencyTree, rootConfiguration, @@ -183,6 +175,12 @@ export async function graphFromObject({ } const utils = { + resolveConfigPath: function(cwd, configPath) { + if (configPath && !path.isAbsolute(configPath)) { + configPath = path.join(cwd, configPath); + } + return configPath; + }, readDependencyConfigFile: async function(cwd, filePath) { const { default: fs @@ -191,9 +189,7 @@ const utils = { const readFile = promisify(fs.readFile); const parseYaml =(await import("js-yaml")).load; - if (!path.isAbsolute(filePath)) { - filePath = path.join(cwd, filePath); - } + filePath = utils.resolveConfigPath(cwd, filePath); let dependencyTree; try { @@ -201,12 +197,31 @@ const utils = { dependencyTree = parseYaml(contents, { filename: filePath }); - resolveProjectPaths(cwd, dependencyTree); + utils.resolveProjectPaths(cwd, dependencyTree); } catch (err) { throw new Error( `Failed to load dependency tree configuration from path ${filePath}: ${err.message}`); } return dependencyTree; + }, + + resolveProjectPaths: function(cwd, project) { + if (!project.path) { + throw new Error(`Missing or empty attribute 'path' for project ${project.id}`); + } + project.path = path.resolve(cwd, project.path); + + if (!project.id) { + throw new Error(`Missing or empty attribute 'id' for project with path ${project.path}`); + } + if (!project.version) { + throw new Error(`Missing or empty attribute 'version' for project ${project.id}`); + } + + if (project.dependencies) { + project.dependencies.forEach((project) => utils.resolveProjectPaths(cwd, project)); + } + return project; } }; diff --git a/test/lib/graph/graph.integration.js b/test/lib/graph/graph.integration.js index 4f27781e9..8aa4d2a20 100644 --- a/test/lib/graph/graph.integration.js +++ b/test/lib/graph/graph.integration.js @@ -47,7 +47,7 @@ test.serial("graphFromPackageDependencies with workspace object", async (t) => { const res = await graphFromPackageDependencies({ cwd: "cwd", rootConfiguration: "rootConfiguration", - rootConfigPath: "rootConfigPath", + rootConfigPath: "/rootConfigPath", versionOverride: "versionOverride", workspaceConfiguration: { specVersion: "workspace/1.0", @@ -68,7 +68,7 @@ test.serial("graphFromPackageDependencies with workspace object", async (t) => { t.deepEqual(npmProviderConstructorStub.getCall(0).args[0], { cwd: path.join(__dirname, "..", "..", "..", "cwd"), rootConfiguration: "rootConfiguration", - rootConfigPath: "rootConfigPath", + rootConfigPath: "/rootConfigPath", }, "Created NodePackageDependencies provider instance with correct parameters"); t.is(projectGraphBuilderStub.callCount, 1, "projectGraphBuilder got called once"); @@ -96,7 +96,7 @@ test.serial("graphFromPackageDependencies with workspace object and workspace na const res = await graphFromPackageDependencies({ cwd: "cwd", rootConfiguration: "rootConfiguration", - rootConfigPath: "rootConfigPath", + rootConfigPath: "/rootConfigPath", versionOverride: "versionOverride", workspaceName: "dolphin", workspaceConfiguration: { @@ -118,7 +118,7 @@ test.serial("graphFromPackageDependencies with workspace object and workspace na t.deepEqual(npmProviderConstructorStub.getCall(0).args[0], { cwd: path.join(__dirname, "..", "..", "..", "cwd"), rootConfiguration: "rootConfiguration", - rootConfigPath: "rootConfigPath", + rootConfigPath: "/rootConfigPath", }, "Created NodePackageDependencies provider instance with correct parameters"); t.is(projectGraphBuilderStub.callCount, 1, "projectGraphBuilder got called once"); @@ -142,7 +142,7 @@ test.serial("graphFromPackageDependencies with workspace object not matching wor await t.throwsAsync(graphFromPackageDependencies({ cwd: "cwd", rootConfiguration: "rootConfiguration", - rootConfigPath: "rootConfigPath", + rootConfigPath: "/rootConfigPath", versionOverride: "versionOverride", workspaceName: "other", workspaceConfiguration: { @@ -171,7 +171,7 @@ test.serial("graphFromPackageDependencies with workspace file", async (t) => { const res = await graphFromPackageDependencies({ cwd: libraryHPath, rootConfiguration: "rootConfiguration", - rootConfigPath: "rootConfigPath", + rootConfigPath: "/rootConfigPath", versionOverride: "versionOverride", workspaceName: "default", }); @@ -182,7 +182,7 @@ test.serial("graphFromPackageDependencies with workspace file", async (t) => { t.deepEqual(npmProviderConstructorStub.getCall(0).args[0], { cwd: libraryHPath, rootConfiguration: "rootConfiguration", - rootConfigPath: "rootConfigPath" + rootConfigPath: "/rootConfigPath" }, "Created NodePackageDependencies provider instance with correct parameters"); t.is(projectGraphBuilderStub.callCount, 1, "projectGraphBuilder got called once"); @@ -210,7 +210,7 @@ test.serial("graphFromPackageDependencies with workspace file at custom path", a const res = await graphFromPackageDependencies({ cwd: "cwd", rootConfiguration: "rootConfiguration", - rootConfigPath: "rootConfigPath", + rootConfigPath: "/rootConfigPath", versionOverride: "versionOverride", workspaceName: "default", workspaceConfigPath: path.join(libraryHPath, "ui5-workspace.yaml") @@ -222,7 +222,7 @@ test.serial("graphFromPackageDependencies with workspace file at custom path", a t.deepEqual(npmProviderConstructorStub.getCall(0).args[0], { cwd: path.join(__dirname, "..", "..", "..", "cwd"), rootConfiguration: "rootConfiguration", - rootConfigPath: "rootConfigPath" + rootConfigPath: "/rootConfigPath" }, "Created NodePackageDependencies provider instance with correct parameters"); t.is(projectGraphBuilderStub.callCount, 1, "projectGraphBuilder got called once"); @@ -250,7 +250,7 @@ test.serial("graphFromPackageDependencies with inactive workspace file at custom const res = await graphFromPackageDependencies({ cwd: "cwd", rootConfiguration: "rootConfiguration", - rootConfigPath: "rootConfigPath", + rootConfigPath: "/rootConfigPath", versionOverride: "versionOverride", workspaceName: "default", workspaceConfigPath: path.join(libraryHPath, "custom-ui5-workspace.yaml") @@ -262,7 +262,7 @@ test.serial("graphFromPackageDependencies with inactive workspace file at custom t.deepEqual(npmProviderConstructorStub.getCall(0).args[0], { cwd: path.join(__dirname, "..", "..", "..", "cwd"), rootConfiguration: "rootConfiguration", - rootConfigPath: "rootConfigPath" + rootConfigPath: "/rootConfigPath" }, "Created NodePackageDependencies provider instance with correct parameters"); t.is(projectGraphBuilderStub.callCount, 1, "projectGraphBuilder got called once"); diff --git a/test/lib/graph/graph.js b/test/lib/graph/graph.js index e5bf55fad..2ed052c29 100644 --- a/test/lib/graph/graph.js +++ b/test/lib/graph/graph.js @@ -56,7 +56,7 @@ test.serial("graphFromPackageDependencies", async (t) => { const res = await graphFromPackageDependencies({ cwd: "cwd", rootConfiguration: "rootConfiguration", - rootConfigPath: "rootConfigPath", + rootConfigPath: "/rootConfigPath", versionOverride: "versionOverride" }); @@ -67,7 +67,7 @@ test.serial("graphFromPackageDependencies", async (t) => { t.deepEqual(npmProviderConstructorStub.getCall(0).args[0], { cwd: path.join(__dirname, "..", "..", "..", "cwd"), rootConfiguration: "rootConfiguration", - rootConfigPath: "rootConfigPath" + rootConfigPath: "/rootConfigPath" }, "Created NodePackageDependencies provider instance with correct parameters"); t.is(projectGraphBuilderStub.callCount, 1, "projectGraphBuilder got called once"); @@ -95,7 +95,7 @@ test.serial("graphFromPackageDependencies with workspace name", async (t) => { const res = await graphFromPackageDependencies({ cwd: "cwd", rootConfiguration: "rootConfiguration", - rootConfigPath: "rootConfigPath", + rootConfigPath: "/rootConfigPath", versionOverride: "versionOverride", workspaceName: "dolphin", }); @@ -114,7 +114,7 @@ test.serial("graphFromPackageDependencies with workspace name", async (t) => { t.deepEqual(npmProviderConstructorStub.getCall(0).args[0], { cwd: path.join(__dirname, "..", "..", "..", "cwd"), rootConfiguration: "rootConfiguration", - rootConfigPath: "rootConfigPath", + rootConfigPath: "/rootConfigPath", }, "Created NodePackageDependencies provider instance with correct parameters"); t.is(projectGraphBuilderStub.callCount, 1, "projectGraphBuilder got called once"); @@ -141,7 +141,7 @@ test.serial("graphFromPackageDependencies with workspace object", async (t) => { const res = await graphFromPackageDependencies({ cwd: "cwd", rootConfiguration: "rootConfiguration", - rootConfigPath: "rootConfigPath", + rootConfigPath: "/rootConfigPath", versionOverride: "versionOverride", workspaceConfiguration: "workspaceConfiguration" }); @@ -166,7 +166,7 @@ test.serial("graphFromPackageDependencies with workspace object and workspace na const res = await graphFromPackageDependencies({ cwd: "cwd", rootConfiguration: "rootConfiguration", - rootConfigPath: "rootConfigPath", + rootConfigPath: "/rootConfigPath", versionOverride: "versionOverride", workspaceName: "dolphin", workspaceConfiguration: "workspaceConfiguration" @@ -192,7 +192,7 @@ test.serial("graphFromPackageDependencies with workspace path and workspace name const res = await graphFromPackageDependencies({ cwd: "cwd", rootConfiguration: "rootConfiguration", - rootConfigPath: "rootConfigPath", + rootConfigPath: "/rootConfigPath", versionOverride: "versionOverride", workspaceName: "dolphin", workspaceConfigPath: "workspaceConfigurationPath" @@ -222,7 +222,7 @@ test.serial("graphFromPackageDependencies with empty workspace", async (t) => { const res = await graphFromPackageDependencies({ cwd: "cwd", rootConfiguration: "rootConfiguration", - rootConfigPath: "rootConfigPath", + rootConfigPath: "/rootConfigPath", versionOverride: "versionOverride", workspaceName: "dolphin", }); @@ -241,7 +241,7 @@ test.serial("graphFromPackageDependencies with empty workspace", async (t) => { t.deepEqual(npmProviderConstructorStub.getCall(0).args[0], { cwd: path.join(__dirname, "..", "..", "..", "cwd"), rootConfiguration: "rootConfiguration", - rootConfigPath: "rootConfigPath", + rootConfigPath: "/rootConfigPath", }, "Created NodePackageDependencies provider instance with correct parameters"); t.is(projectGraphBuilderStub.callCount, 1, "projectGraphBuilder got called once"); @@ -266,7 +266,7 @@ test.serial("graphFromPackageDependencies: Do not resolve framework dependencies const res = await graphFromPackageDependencies({ cwd: "cwd", rootConfiguration: "rootConfiguration", - rootConfigPath: "rootConfigPath", + rootConfigPath: "/rootConfigPath", versionOverride: "versionOverride", resolveFrameworkDependencies: false }); @@ -289,7 +289,7 @@ test.serial("graphFromStaticFile", async (t) => { cwd: "cwd", filePath: "file/path", rootConfiguration: "rootConfiguration", - rootConfigPath: "rootConfigPath", + rootConfigPath: "/rootConfigPath", versionOverride: "versionOverride" }); @@ -305,7 +305,7 @@ test.serial("graphFromStaticFile", async (t) => { t.deepEqual(dependencyTreeProviderStub.getCall(0).args[0], { dependencyTree: "dependencyTree", rootConfiguration: "rootConfiguration", - rootConfigPath: "rootConfigPath", + rootConfigPath: "/rootConfigPath", }, "Created NodePackageDependencies provider instance with correct parameters"); t.is(projectGraphBuilderStub.callCount, 1, "projectGraphBuilder got called once"); @@ -331,7 +331,7 @@ test.serial("graphFromStaticFile: Do not resolve framework dependencies", async cwd: "cwd", filePath: "filePath", rootConfiguration: "rootConfiguration", - rootConfigPath: "rootConfigPath", + rootConfigPath: "/rootConfigPath", versionOverride: "versionOverride", resolveFrameworkDependencies: false }); @@ -350,7 +350,7 @@ test.serial("usingObject", async (t) => { const res = await graphFromObject({ dependencyTree: "dependencyTree", rootConfiguration: "rootConfiguration", - rootConfigPath: "rootConfigPath", + rootConfigPath: "/rootConfigPath", versionOverride: "versionOverride" }); @@ -360,7 +360,7 @@ test.serial("usingObject", async (t) => { t.deepEqual(dependencyTreeProviderStub.getCall(0).args[0], { dependencyTree: "dependencyTree", rootConfiguration: "rootConfiguration", - rootConfigPath: "rootConfigPath", + rootConfigPath: "/rootConfigPath", }, "Created NodePackageDependencies provider instance with correct parameters"); t.is(projectGraphBuilderStub.callCount, 1, "projectGraphBuilder got called once"); @@ -382,7 +382,7 @@ test.serial("usingObject: Do not resolve framework dependencies", async (t) => { cwd: "cwd", filePath: "filePath", rootConfiguration: "rootConfiguration", - rootConfigPath: "rootConfigPath", + rootConfigPath: "/rootConfigPath", versionOverride: "versionOverride", resolveFrameworkDependencies: false }); diff --git a/test/lib/graph/graphFromObject.js b/test/lib/graph/graphFromObject.js index 51979d53b..866fd5859 100644 --- a/test/lib/graph/graphFromObject.js +++ b/test/lib/graph/graphFromObject.js @@ -1655,7 +1655,8 @@ test("rootConfig", async (t) => { const {graphFromObject} = t.context; const projectGraph = await graphFromObject({ dependencyTree: getApplicationATree(), - rootConfigPath: "ui5-test-configPath.yaml" + cwd: applicationAPath, + rootConfigPath: "ui5-test-configPath.yaml", }); t.deepEqual(projectGraph.getRoot().getCustomConfiguration(), { configPathTest: true diff --git a/test/lib/graph/graphFromStaticFile.js b/test/lib/graph/graphFromStaticFile.js index a16e560e9..67951b257 100644 --- a/test/lib/graph/graphFromStaticFile.js +++ b/test/lib/graph/graphFromStaticFile.js @@ -105,7 +105,7 @@ test("rootConfiguration", async (t) => { test("rootConfig", async (t) => { const projectGraph = await graphFromStaticFile({ cwd: applicationHPath, - rootConfigPath: "ui5-test-configPath.yaml" + rootConfigPath: "../application.a/ui5-test-configPath.yaml" }); t.deepEqual(projectGraph.getRoot().getCustomConfiguration(), { configPathTest: true