Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 27 additions & 7 deletions internal/documentation/docs/pages/Workspace.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

::: details
```yaml title="ui5-workspace.yaml"
specVersion: workspace/1.0
specVersion: workspace/1.1
metadata:
name: default
dependencyManagement:
Expand All @@ -23,14 +23,14 @@ Workspaces are typically configured in a `ui5-workspace.yaml` file, located next

::: details Example
```yaml title="ui5-workspace.yaml"
specVersion: workspace/1.0
specVersion: workspace/1.1
metadata:
name: default
dependencyManagement:
resolutions:
- path: ../heavy.library
---
specVersion: workspace/1.0
specVersion: workspace/1.1
metadata:
name: extended
dependencyManagement:
Expand All @@ -52,14 +52,14 @@ This concept has been discussed in an RFC: [RFC 0006 Local Dependency Resolution
A UI5 Workspace configuration must define a specification version (`specVersion`) compatible with its configuration. For more information, see [Workspace Specification Versions](#workspace-specification-versions).

```yaml
specVersion: "workspace/1.0"
specVersion: "workspace/1.1"
```

### Metadata

::: details Example
```yaml
specVersion: workspace/1.0
specVersion: workspace/1.1
metadata:
name: dolphin
```
Expand Down Expand Up @@ -91,7 +91,7 @@ UI5 Workspace configurations allow to influence the dependency resolution when w

::: details
```yaml
specVersion: workspace/1.0
specVersion: workspace/1.1
metadata:
name: dolphin
dependencyManagement:
Expand Down Expand Up @@ -119,11 +119,24 @@ Paths must be written in POSIX (i.e. using only forward slashes `/` as path segm

Note that this configuration only affects the resolution of dependencies which have already been found during the regular dependency resolution process of a project. For example, if a workspace resolution path resolves to a project that would otherwise not be part of the dependency tree of the current root project, it will not be added to the dependency tree. Also, transitive dependencies of resolved projects are not being followed.

#### configPath

*Available since `workspace/1.1`*

```yaml
dependencyManagement:
resolutions:
- path: ../test.library
configPath: custom-config.yaml
```

By default, UI5 CLI looks for a `ui5.yaml` at the root of the resolved module. The optional `configPath` property allows pointing to a different configuration file within the module directory. The path must be written in POSIX notation and must be **relative to the resolution `path`**.

## Workspace Specification Versions
A workspace configuration must define a Specification Version by setting the `specVersion` property. UI5 CLI uses this information to detect whether the currently installed version is compatible with a workspace's configuration.

```yaml
specVersion: "workspace/1.0"
specVersion: "workspace/1.1"
[...]
```

Expand All @@ -142,8 +155,15 @@ Unless otherwise noted in the table below, UI5 CLI modules are backward-compatib

Version | UI5 CLI Release
--- | ---
**`workspace/1.1`** | v5.0.0+ and v4.1.0+
**`workspace/1.0`** | v3.0.0+

### Specification Version `workspace/1.1`

Added [`configPath`](#configpath) property to resolution entries.

Specification Version `workspace/1.1` configurations are compatible with [UI5 CLI](https://github.com/SAP/ui5-cli) v5.0.0 and above, as well as v4.1.0 and above.

### Specification Version `workspace/1.0`

Initial version.
Expand Down
10 changes: 6 additions & 4 deletions packages/project/lib/graph/Workspace.js
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ class Workspace {
`Missing property 'path' in dependency resolution configuration of workspace ${this.getName()}`);
}
return await this._getModulesFromPath(
this.#cwd, resolutionConfig.path);
this.#cwd, resolutionConfig.path, resolutionConfig.configPath);
}));

// Flatten array since package-workspaces might have resolved to multiple modules for a single resolution
Expand Down Expand Up @@ -175,7 +175,7 @@ class Workspace {
};
}

async _getModulesFromPath(cwd, relPath, failOnMissingFiles = true) {
async _getModulesFromPath(cwd, relPath, configPath, failOnMissingFiles = true) {
const nodePath = path.join(cwd, relPath);
if (this.#visitedNodePaths.has(nodePath)) {
log.verbose(`Module located at ${nodePath} has already been visited`);
Expand Down Expand Up @@ -235,7 +235,8 @@ class Workspace {

const resolvedModules = new Map();
await Promise.all(searchPaths.map(async (pkgPath) => {
const modules = await this._getModulesFromPath(nodePath, pkgPath, staticPatterns.includes(pkgPath));
const modules =
await this._getModulesFromPath(nodePath, pkgPath, configPath, staticPatterns.includes(pkgPath));
modules.forEach((module) => {
const id = module.getId();
if (!resolvedModules.get(id)) {
Expand All @@ -248,7 +249,8 @@ class Workspace {
return [new Module({
id: pkg.name,
version: pkg.version,
modulePath: nodePath
modulePath: nodePath,
configPath: configPath,
})];
}
}
Expand Down
23 changes: 21 additions & 2 deletions packages/project/lib/validation/schema/ui5-workspace.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"additionalProperties": false,
"properties": {
"specVersion": {
"enum": ["workspace/1.0"],
"enum": ["workspace/1.1", "workspace/1.0"],
"errorMessage": "Unsupported \"specVersion\"\nYour UI5 CLI installation might be outdated.\nSupported specification versions: \"workspace/1.0\"\nFor details, see: https://ui5.github.io/cli/stable/pages/Workspace/#workspace-specification-versions"
},
"metadata": {
Expand All @@ -19,6 +19,23 @@
"$ref": "#/definitions/dependencyManagement"
}
},
"if": {
"properties": {"specVersion": {"const": "workspace/1.0"}}
},
"then": {
"properties": {
"dependencyManagement": {
"properties": {
"resolutions": {
"items": {
"not": {"required": ["configPath"]},
"errorMessage": "\"configPath\" is only supported for specVersion \"workspace/1.1\" and higher"
}
}
}
}
}
},
"definitions": {
"metadata": {
"type": "object",
Expand All @@ -42,13 +59,15 @@
"properties": {
"resolutions": {
"type": "array",

"items": {
"type": "object",
"additionalProperties": false,
"properties": {
"path": {
"type": "string"
},
"configPath": {
"type": "string"
}
}
}
Expand Down
10 changes: 10 additions & 0 deletions packages/project/test/fixtures/library.d/custom-config-path.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
specVersion: "2.3"
type: library
metadata:
name: library.d
copyright: A custom config (called by configPath paramater)
resources:
configuration:
paths:
src: main/src
test: main/test
69 changes: 67 additions & 2 deletions packages/project/test/lib/graph/Workspace.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ const collectionBLibraryA = path.join(__dirname, "..", "..", "fixtures", "collec
const collectionBLibraryB = path.join(__dirname, "..", "..", "fixtures", "collection.b", "library.b");
const collectionBLibraryC = path.join(__dirname, "..", "..", "fixtures", "collection.b", "library.c");

function createWorkspaceConfig({dependencyManagement}) {
function createWorkspaceConfig({dependencyManagement, specVersion = "workspace/1.0"}) {
return {
specVersion: "workspace/1.0",
specVersion,
metadata: {
name: "workspace-name"
},
Expand Down Expand Up @@ -473,3 +473,68 @@ test("Missing parameters", (t) => {
message: "Could not create Workspace: Missing or empty parameter 'configuration'"
}, "Threw with expected error message");
});

test("workspace/1.1: Basic validation with specified configPath for dependency", async (t) => {
const workspace = new t.context.Workspace({
cwd: __dirname,
configuration: createWorkspaceConfig({
specVersion: "workspace/1.1",
dependencyManagement: {
resolutions: [{
path: "../../fixtures/library.d",
configPath: "custom-config-path.yaml" // Custom configPath
}, {
path: "../../fixtures/library.e",
// no custom yaml -> resorts to default: ui5.yaml
}]
}
})
});

const {projectNameMap} = await workspace._getResolvedModules();
t.deepEqual(Array.from(projectNameMap.keys()).sort(), ["library.d", "library.e"], "Correct project name keys");
t.is(projectNameMap.get("library.d")._configPath, "custom-config-path.yaml");
t.is(projectNameMap.get("library.e")._configPath, "ui5.yaml");
});

test("workspace/1.1: Custom configPath for dependency but specVersion is workspace/1.0", async (t) => {
const workspace = new t.context.Workspace({
cwd: __dirname,
configuration: createWorkspaceConfig({
specVersion: "workspace/1.0",
dependencyManagement: {
resolutions: [{
path: "../../fixtures/library.d",
configPath: "custom-config-path.yaml" // Custom configPath
}, {
path: "../../fixtures/library.e",
}]
}
})
});

const err = await t.throwsAsync(async () => await workspace._getResolvedModules());
t.is(err.message.includes("\"configPath\" is only supported for specVersion \"workspace/1.1\" and higher"), true);
});

test("workspace/1.1: Custom configPath for dependency does not exist", async (t) => {
const workspace = new t.context.Workspace({
cwd: __dirname,
configuration: createWorkspaceConfig({
specVersion: "workspace/1.1",
dependencyManagement: {
resolutions: [{
path: "../../fixtures/library.d",
configPath: "not-existing-config-path.yaml" // Custom configPath
}, {
path: "../../fixtures/library.e",
// no custom yaml -> resorts to default: ui5.yaml
}]
}
})
});

const err = await t.throwsAsync(async () => await workspace._getResolvedModules());
t.is(err.message.includes("Failed to read configuration for module library.d: " +
"Could not find configuration file in module at path 'not-existing-config-path.yaml'"), true);
});
Loading