Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
30ed97c
feat: Offer configPath property to workspace configs
maxreichmann Oct 2, 2026
d006aa8
feat(project): Add logic for configPath parameter
maxreichmann Oct 8, 2026
628498b
docs: Adjust Workspace.md page with configPath property
maxreichmann Oct 8, 2026
d7c329f
refactor: Improve error handling when `path` is absolute
maxreichmann Oct 9, 2026
553b6db
refactor: Adjust workspace config to fix tests
maxreichmann Oct 9, 2026
5c857ed
test(project): Adjust resolutions path to absolute
maxreichmann Oct 12, 2026
0dcf01a
refactor: Remove "else" block in schema
maxreichmann Oct 13, 2026
4ebdb73
refactor: Fix AJV strict mode warnings
maxreichmann Oct 13, 2026
a1e309b
docs: Remove "v5.0.0+" and only keep "v4.1.0+"
maxreichmann Oct 13, 2026
92b7388
docs: Apply @d3xter666 suggestion
maxreichmann Oct 14, 2026
64f03a2
refactor: Add temp test matrix (DELETE LATER)
maxreichmann Oct 15, 2026
c7f740b
test(project): Fix schema tests
maxreichmann Oct 16, 2026
09eb87e
test: Add scenario for configPath in collections
maxreichmann Oct 16, 2026
bbda671
test(project): Add first test case for collection scenarios
maxreichmann Oct 16, 2026
0a0d68d
test(project): Add test cases
maxreichmann Oct 19, 2026
2e937eb
test: Add important case isolating "last one wins" logic from current…
maxreichmann Oct 19, 2026
2a27fc6
test: Add test matrix for "specific one wins" logic
maxreichmann Oct 20, 2026
a549823
test: Add concept markdown for logic "specific one wins + error on du…
maxreichmann Oct 21, 2026
55b9780
refactor: Add error handling for duplicate assignments
maxreichmann Oct 21, 2026
0a19ab4
test(project): Fix stale tests
maxreichmann Oct 22, 2026
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
445 changes: 445 additions & 0 deletions configPath-test-matrix-lastOneWins.md

Large diffs are not rendered by default.

596 changes: 596 additions & 0 deletions configPath-test-matrix-specificOneWins+ErrorOnDuplicate.md

Large diffs are not rendered by default.

563 changes: 563 additions & 0 deletions configPath-test-matrix-specificOneWins.md

Large diffs are not rendered by default.

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`** | 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/UI5/cli) v4.1.0 and above.

### Specification Version `workspace/1.0`

Initial version.
Expand Down
5 changes: 3 additions & 2 deletions packages/project/lib/graph/Module.js
Original file line number Diff line number Diff line change
Expand Up @@ -308,8 +308,9 @@ class Module {
}
if (!configResource) {
if (configPath !== DEFAULT_CONFIG_PATH) {
throw new Error("Failed to read configuration for module " +
`${this.getId()}: Could not find configuration file in module at path '${configPath}'`);
throw new Error(`Failed to read configuration for module ` +
`${this.getId()}: Could not find configuration file in module at path `+
`'${this._configPath}'`);
}
return null;
}
Expand Down
35 changes: 31 additions & 4 deletions packages/project/lib/graph/Workspace.js
Original file line number Diff line number Diff line change
Expand Up @@ -138,13 +138,38 @@ class Workspace {
};
}

// Detect duplicate resolutions targeting the same library
const seenLibraryNames = [];
for (const {path: resolutionPath} of resolutions) {
if (!resolutionPath) {
continue;
}
const libraryName = path.basename(resolutionPath); // "../collection/library.a" -> "library.a"
if (seenLibraryNames.includes(libraryName)) {
throw new Error(
`Multiple resolutions for the same library '${libraryName}' ` +
`in workspace '${this.getName()}' exist.`);
}
seenLibraryNames.push(libraryName);
}

let resolvedModules = await Promise.all(resolutions.map(async (resolutionConfig) => {
if (!resolutionConfig.path) {
throw new Error(
`Missing property 'path' in dependency resolution configuration of workspace ${this.getName()}`);
}
if (path.isAbsolute(resolutionConfig.path)) {
throw new Error(
`Absolute paths are not allowed in workspace configurations of dependencies. ` +
`Found '${resolutionConfig.path}' in workspace '${this.getName()}'`);
}
if (resolutionConfig.configPath && path.isAbsolute(resolutionConfig.configPath)) {
throw new Error(
`Absolute config paths are not allowed in workspace configurations of dependencies. ` +
`Found '${resolutionConfig.configPath}' in workspace '${this.getName()}'`);
}
return await this._getModulesFromPath(
this.#cwd, resolutionConfig.path);
this.#cwd, resolutionConfig.path, resolutionConfig.configPath);
Comment on lines 171 to +172

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This modification leads to a bit strange behaviour that I'm not sure whtether is expected or not.
Here it is:

If you checkout the openui5-sample-app and use a ui5-worspaces.yaml in there to point to the openui5 monorepo locally and inside ui5-worspaces.yaml there is this configPath property with a custom ui5.yaml (it might have different name i.e. ui5-deployment.yaml) configuration, the solution will loop through all of the subpackages within openui5 monorepo and if such a custom file is missing somewhere, the build/serve will fail.

This means, that an external consumer will provide a path to a custom configuration in openui5 repo, expecting this custom configuration to be present everywhere.

A workaround I see is to point individually to every repo.

}));

// Flatten array since package-workspaces might have resolved to multiple modules for a single resolution
Expand Down Expand Up @@ -175,7 +200,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 +260,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 +274,8 @@ class Workspace {
return [new Module({
id: pkg.name,
version: pkg.version,
modulePath: nodePath
modulePath: nodePath,
configPath: configPath ? path.resolve(nodePath, configPath) : undefined,
})];
}
}
Expand Down
33 changes: 30 additions & 3 deletions packages/project/lib/validation/schema/ui5-workspace.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
"additionalProperties": false,
"properties": {
"specVersion": {
"enum": ["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"
"enum": ["workspace/1.1", "workspace/1.0"],
"errorMessage": "Unsupported \"specVersion\"\nYour UI5 CLI installation might be outdated.\nSupported specification versions: \"workspace/1.0\", \"workspace/1.1\".\nFor details, see: https://ui5.github.io/cli/stable/pages/Workspace/#workspace-specification-versions"
},
"metadata": {
"$ref": "#/definitions/metadata"
Expand All @@ -19,6 +19,31 @@
"$ref": "#/definitions/dependencyManagement"
}
},
"if": {
"properties": {"specVersion": {"const": "workspace/1.0"}}
},
"then": {
"properties": {
"dependencyManagement": {
"type": "object",
"properties": {
"resolutions": {
"type": "array",
"items": {
"if": {"type": "object"},
"then": {
"not": {
"type": "object",
"required": ["configPath"]
},
"errorMessage": "\"configPath\" is only supported for specVersion \"workspace/1.1\" and higher"
}
}
}
}
}
}
},
"definitions": {
"metadata": {
"type": "object",
Expand All @@ -42,13 +67,15 @@
"properties": {
"resolutions": {
"type": "array",

"items": {
"type": "object",
"additionalProperties": false,
"properties": {
"path": {
"type": "string"
},
"configPath": {
"type": "string"
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "library.c",
"version": "1.0.0",
"description": "Simple SAPUI5 based library"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8" ?>
<library xmlns="http://www.sap.com/sap.ui.library.xsd" >

<name>library.a</name>
<vendor>SAP SE</vendor>
<copyright>Some fancy copyright ${currentYear}</copyright>
<version>${version}</version>

<documentation>Library A</documentation>

<dependencies>
<dependency>
<libraryName>library.d</libraryName>
</dependency>
</dependencies>

</library>
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
specVersion: "2.3"
type: library
metadata:
name: library.c.another.custom
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
specVersion: "2.3"
type: library
metadata:
name: library.c.custom
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
specVersion: "2.3"
type: library
metadata:
name: library.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "library.d",
"version": "1.0.0",
"description": "Simple SAPUI5 based library"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8" ?>
<library xmlns="http://www.sap.com/sap.ui.library.xsd" >

<name>library.b</name>
<vendor>SAP SE</vendor>
<copyright>Some fancy copyright ${currentYear}</copyright>
<version>${version}</version>

<documentation>Library B</documentation>

<dependencies>
<dependency>
<libraryName>library.d</libraryName>
</dependency>
</dependencies>

</library>
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
specVersion: "2.3"
type: library
metadata:
name: library.d.another.custom
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
specVersion: "2.3"
type: library
metadata:
name: library.d.custom
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
specVersion: "2.3"
type: library
metadata:
name: library.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"name": "collection",
"version": "1.0.0",
"description": "Simple Collection",
"workspaces": [
"library.c",
"library.d"
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "library.a",
"version": "1.0.0",
"description": "Simple SAPUI5 based library"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8" ?>
<library xmlns="http://www.sap.com/sap.ui.library.xsd" >

<name>library.a</name>
<vendor>SAP SE</vendor>
<copyright>Some fancy copyright ${currentYear}</copyright>
<version>${version}</version>

<documentation>Library A</documentation>

<dependencies>
<dependency>
<libraryName>library.d</libraryName>
</dependency>
</dependencies>

</library>
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
specVersion: "2.3"
type: library
metadata:
name: library.a.another.custom
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
specVersion: "2.3"
type: library
metadata:
name: library.a
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "library.b",
"version": "1.0.0",
"description": "Simple SAPUI5 based library"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8" ?>
<library xmlns="http://www.sap.com/sap.ui.library.xsd" >

<name>library.b</name>
<vendor>SAP SE</vendor>
<copyright>Some fancy copyright ${currentYear}</copyright>
<version>${version}</version>

<documentation>Library B</documentation>

<dependencies>
<dependency>
<libraryName>library.d</libraryName>
</dependency>
</dependencies>

</library>
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
specVersion: "2.3"
type: library
metadata:
name: library.b.another.custom
Loading
Loading