diff --git a/configPath-test-matrix-lastOneWins.md b/configPath-test-matrix-lastOneWins.md new file mode 100644 index 00000000000..07504004bf1 --- /dev/null +++ b/configPath-test-matrix-lastOneWins.md @@ -0,0 +1,445 @@ +TODO: Delete this file before merging + +# `configPath` Test Matrix + +## Scenario 1 + +### GIVEN for all cases: + +``` +root.collection/ +├── library.a/ +│ ├── ui5.yaml +│ ├── ui5-custom.yaml +│ └── ui5-another-custom.yaml +├── library.b/ +│ ├── ui5.yaml +│ ├── ui5-custom.yaml +│ └── ui5-another-custom.yaml +└── collection.a/ + ├── library.c/ + │ ├── ui5.yaml + │ ├── ui5-custom.yaml + │ └── ui5-another-custom.yaml + └── library.d/ + ├── ui5.yaml + ├── ui5-custom.yaml + └── ui5-another-custom.yaml +``` + +--- + +### ✅ Case 1.1: [workspace/1.1] No configPath + +**WHEN** + +```yaml +specVersion: "workspace/1.1" +metadata: + name: default +dependencyManagement: + resolutions: + - path: ../root.collection +``` + +**THEN** + +| Resolved library | Config file used | +|------------------|------------------| +| `library.a` | `ui5.yaml` +| `library.b` | `ui5.yaml` +| `collection.a/library.c` | `ui5.yaml` +| `collection.a/library.d` | `ui5.yaml` + + +### ✅ Case 1.2: [workspace/1.1] Custom configPath for all libs + +**WHEN** + +```yaml +specVersion: "workspace/1.1" +metadata: + name: default +dependencyManagement: + resolutions: + - path: ../root.collection + configPath: ui5-custom.yaml +``` + +**THEN** + +| Resolved library | Config file used | +|------------------|------------------| +| `library.a` | `ui5-custom.yaml` +| `library.b` | `ui5-custom.yaml` +| `collection.a/library.c` | `ui5-custom.yaml` +| `collection.a/library.d` | `ui5-custom.yaml` + + +### ✅ Case 1.3: [workspace/1.1] No configPath + Custom configPath for single lib + +**WHEN** + +```yaml +specVersion: "workspace/1.1" +metadata: + name: default +dependencyManagement: + resolutions: + - path: ../root.collection + - path: ../root.collection/library.a + configPath: ui5-custom.yaml +``` + +**THEN** + +| Resolved library | Config file used | +|------------------|------------------| +| `library.a` | `ui5-custom.yaml` +| `library.b` | `ui5.yaml` +| `collection.a/library.c` | `ui5.yaml` +| `collection.a/library.d` | `ui5.yaml` + +### ✅ Case 1.4: [workspace/1.1] Custom configPath for single lib + No configPath for all libs + +**WHEN** + +```yaml +specVersion: "workspace/1.1" +metadata: + name: default +dependencyManagement: + resolutions: + - path: ../root.collection/library.a + configPath: ui5-custom.yaml + - path: ../root.collection # overwrites the prev. config entirely +``` + +**THEN** + +| Resolved library | Config file used | +|------------------|------------------| +| `library.a` | `ui5.yaml` +| `library.b` | `ui5.yaml` +| `collection.a/library.c` | `ui5.yaml` +| `collection.a/library.d` | `ui5.yaml` + +### ✅ Case 1.5: [workspace/1.1] Custom configPath for all libs + No configPath for single lib + +**WHEN** + +```yaml +specVersion: "workspace/1.1" +metadata: + name: default +dependencyManagement: + resolutions: + - path: ../root.collection + configPath: ui5-custom.yaml + - path: ../root.collection/library.a +``` + +**THEN** + +| Resolved library | Config file used | +|------------------|------------------| +| `library.a` | `ui5.yaml` +| `library.b` | `ui5-custom.yaml` +| `collection.a/library.c` | `ui5-custom.yaml` +| `collection.a/library.d` | `ui5-custom.yaml` + +### ✅ Case 1.6: [workspace/1.1] No configPath for all libs + Custom configPaths for two libs + +**WHEN** + +```yaml +specVersion: "workspace/1.1" +metadata: + name: default +dependencyManagement: + resolutions: + - path: ../root.collection + - path: ../root.collection/library.a + configPath: ui5-custom.yaml + - path: ../root.collection/library.b + configPath: ui5-another-custom.yaml +``` + +**THEN** + +| Resolved library | Config file used | +|------------------|------------------| +| `library.a` | `ui5-custom.yaml` +| `library.b` | `ui5-another-custom.yaml` +| `collection.a/library.c` | `ui5.yaml` +| `collection.a/library.d` | `ui5.yaml` + +### ✅ Case 1.7: [workspace/1.1] No configPath for all libs + Two custom configPaths for single lib + +**WHEN** + +```yaml +specVersion: "workspace/1.1" +metadata: + name: default +dependencyManagement: + resolutions: + - path: ../root.collection + - path: ../root.collection/library.a + configPath: ui5-custom.yaml + - path: ../root.collection/library.a + configPath: ui5-another-custom.yaml +``` + +**THEN** + +| Resolved library | Config file used | +|------------------|------------------| +| `library.a` | `ui5-another-custom.yaml` +| `library.b` | `ui5.yaml` +| `collection.a/library.c` | `ui5.yaml` +| `collection.a/library.d` | `ui5.yaml` + +**Remark:** For the validation, maybe log a warning (because multiple resolutions for the same library exist). + +### ✅ Case 1.8: [workspace/1.1] No configPath for all libs + Custom configPath for sub collection + +**WHEN** + +```yaml +specVersion: "workspace/1.1" +metadata: + name: default +dependencyManagement: + resolutions: + - path: ../root.collection + - path: ../root.collection/collection.a + configPath: ui5-custom.yaml +``` + +**THEN** + +| Resolved library | Config file used | +|------------------|------------------| +| `library.a` | `ui5.yaml` +| `library.b` | `ui5.yaml` +| `collection.a/library.c` | `ui5-custom.yaml` +| `collection.a/library.d` | `ui5-custom.yaml` + +### ✅ Case 1.9: [workspace/1.1] No configPath for all libs + Custom configPaths for sub collection & single lib + +**WHEN** + +```yaml +specVersion: "workspace/1.1" +metadata: + name: default +dependencyManagement: + resolutions: + - path: ../root.collection + - path: ../root.collection/collection.a + configPath: ui5-custom.yaml + - path: ../root.collection/collection.a/library.c + configPath: ui5-another-custom.yaml +``` + +**THEN** + +| Resolved library | Config file used | +|------------------|------------------| +| `library.a` | `ui5.yaml` +| `library.b` | `ui5.yaml` +| `collection.a/library.c` | `ui5-another-custom.yaml` +| `collection.a/library.d` | `ui5-custom.yaml` + +### ✅ Case 1.10: [workspace/1.1] Two custom configPaths for the same single lib (ordering isolation) + +**WHEN** + +```yaml +specVersion: "workspace/1.1" +metadata: + name: default +dependencyManagement: + resolutions: + - path: ../root.collection/library.a + configPath: ui5-custom.yaml + - path: ../root.collection/library.a # same lib, later resolution + configPath: ui5-another-custom.yaml +``` + +**THEN** + +| Resolved library | Config file used | +|------------------|------------------| +| `library.a` | `ui5-another-custom.yaml` + +Only `library.a` is resolved (the two resolutions collapse into a single module). +This case isolates the concept **the last resolution wins** from the original logic("specificity wins"). + +--- +--- + +## Scenario 2 + +### GIVEN for all cases: + +``` +root.collection/ +├── library.a/ +│ ├── ui5.yaml +│ │ # missing ui5-custom.yaml +│ └── ui5-another-custom.yaml +├── library.b/ +│ ├── ui5.yaml +│ ├── ui5-custom.yaml +│ └── ui5-another-custom.yaml +└── collection.a/ + ├── library.c/ + │ ├── ui5.yaml + │ ├── ui5-custom.yaml + │ └── ui5-another-custom.yaml + └── library.d/ + ├── ui5.yaml + ├── ui5-custom.yaml + └── ui5-another-custom.yaml +``` + +--- + +### Case 2.1: [workspace/1.1] No configPath -- **⚠️ NO AUTOMATED TEST** + +**WHEN** + +```yaml +specVersion: "workspace/1.1" +metadata: + name: default +dependencyManagement: + resolutions: + - path: ../root.collection +``` + +**THEN** + +| Resolved library | Config file used | +|------------------|------------------| +| `library.a` | `ui5.yaml` +| `library.b` | `ui5.yaml` +| `collection.a/library.c` | `ui5.yaml` +| `collection.a/library.d` | `ui5.yaml` + + +### ✅ Case 2.2: [workspace/1.1] Custom configPath for all libs -> File not existing for single lib + +**WHEN** + +```yaml +specVersion: "workspace/1.1" +metadata: + name: default +dependencyManagement: + resolutions: + - path: ../root.collection + configPath: ui5-custom.yaml +``` + +**THEN** + +Error: `Cannot find config file 'ui5-custom.yaml' for path '../root.collection/library.a'` + + +### ✅ Case 2.3: [workspace/1.1] Custom configPath for single lib -> File not existing for single lib + +**WHEN** + +```yaml +specVersion: "workspace/1.1" +metadata: + name: default +dependencyManagement: + resolutions: + - path: ../root.collection + - path: ../root.collection/library.a + configPath: ui5-custom.yaml +``` + +**THEN** + +Error: `Cannot find config file 'ui5-custom.yaml' for path '../root.collection/library.a'` + +### ✅ Case 2.4: [workspace/1.1] Not existing configPath for single lib overwritten by No configPath for all libs + +**WHEN** + +```yaml +specVersion: "workspace/1.1" +metadata: + name: default +dependencyManagement: + resolutions: + - path: ../root.collection/library.a + configPath: ui5-custom.yaml + - path: ../root.collection # overwrites the prev. config entirely +``` + +**THEN** + +| Resolved library | Config file used | +|------------------|------------------| +| `library.a` | `ui5.yaml` +| `library.b` | `ui5.yaml` +| `collection.a/library.c` | `ui5.yaml` +| `collection.a/library.d` | `ui5.yaml` + +### ✅ Case 2.5: [workspace/1.1] Not existing configPath for single lib overwritten by No configPath for the same lib + +**WHEN** + +```yaml +specVersion: "workspace/1.1" +metadata: + name: default +dependencyManagement: + resolutions: + - path: ../root.collection + configPath: ui5-custom.yaml + - path: ../root.collection/library.a +``` + +**THEN** + +| Resolved library | Config file used | +|------------------|------------------| +| `library.a` | `ui5.yaml` +| `library.b` | `ui5-custom.yaml` +| `collection.a/library.c` | `ui5-custom.yaml` +| `collection.a/library.d` | `ui5-custom.yaml` + +### ✅ Case 2.6: [workspace/1.1] Not existing configPath for single lib overwritten by Custom configPath for the same lib + +**WHEN** + +```yaml +specVersion: "workspace/1.1" +metadata: + name: default +dependencyManagement: + resolutions: + - path: ../root.collection + - path: ../root.collection/library.a + configPath: ui5-custom.yaml + - path: ../root.collection/library.a + configPath: ui5-another-custom.yaml +``` + +**THEN** + +| Resolved library | Config file used | +|------------------|------------------| +| `library.a` | `ui5-another-custom.yaml` +| `library.b` | `ui5.yaml` +| `collection.a/library.c` | `ui5.yaml` +| `collection.a/library.d` | `ui5.yaml` + +**Remark:** For the validation, maybe log a warning (because multiple resolutions for the same library exist). diff --git a/configPath-test-matrix-specificOneWins+ErrorOnDuplicate.md b/configPath-test-matrix-specificOneWins+ErrorOnDuplicate.md new file mode 100644 index 00000000000..6f3f8b1f732 --- /dev/null +++ b/configPath-test-matrix-specificOneWins+ErrorOnDuplicate.md @@ -0,0 +1,600 @@ +TODO: Delete this file before merging + +# `configPath` Test Matrix + +## Scenario 1 + +### GIVEN for all cases: + +``` +root.collection/ +├── library.a/ +│ ├── ui5.yaml +│ ├── ui5-custom.yaml +│ └── ui5-another-custom.yaml +├── library.b/ +│ ├── ui5.yaml +│ ├── ui5-custom.yaml +│ └── ui5-another-custom.yaml +└── collection.a/ + ├── library.c/ + │ ├── ui5.yaml + │ ├── ui5-custom.yaml + │ └── ui5-another-custom.yaml + └── library.d/ + ├── ui5.yaml + ├── ui5-custom.yaml + └── ui5-another-custom.yaml +``` + +--- + +### Case 1.1: [workspace/1.1] No configPath + +**WHEN** + +```yaml +specVersion: "workspace/1.1" +metadata: + name: default +dependencyManagement: + resolutions: + - path: ../root.collection +``` + +**THEN** + +| Resolved library | Config file used | +|------------------|------------------| +| `library.a` | `ui5.yaml` +| `library.b` | `ui5.yaml` +| `collection.a/library.c` | `ui5.yaml` +| `collection.a/library.d` | `ui5.yaml` + + +### Case 1.2: [workspace/1.1] Custom configPath for all libs + +**WHEN** + +```yaml +specVersion: "workspace/1.1" +metadata: + name: default +dependencyManagement: + resolutions: + - path: ../root.collection + configPath: ui5-custom.yaml +``` + +**THEN** + +| Resolved library | Config file used | +|------------------|------------------| +| `library.a` | `ui5-custom.yaml` +| `library.b` | `ui5-custom.yaml` +| `collection.a/library.c` | `ui5-custom.yaml` +| `collection.a/library.d` | `ui5-custom.yaml` + + +### Case 1.3: [workspace/1.1] No configPath + Custom configPath for single lib + +**WHEN** + +```yaml +specVersion: "workspace/1.1" +metadata: + name: default +dependencyManagement: + resolutions: + - path: ../root.collection + - path: ../root.collection/library.a + configPath: ui5-custom.yaml +``` + +**THEN** + +| Resolved library | Config file used | +|------------------|------------------| +| `library.a` | `ui5-custom.yaml` +| `library.b` | `ui5.yaml` +| `collection.a/library.c` | `ui5.yaml` +| `collection.a/library.d` | `ui5.yaml` + +### Case 1.4: [workspace/1.1] Custom configPath for single lib + No configPath for all libs + +**WHEN** + +```yaml +specVersion: "workspace/1.1" +metadata: + name: default +dependencyManagement: + resolutions: + - path: ../root.collection/library.a + configPath: ui5-custom.yaml + - path: ../root.collection +``` + +**THEN** + +| Resolved library | Config file used | +|------------------|------------------| +| `library.a` | `ui5-custom.yaml` +| `library.b` | `ui5.yaml` +| `collection.a/library.c` | `ui5.yaml` +| `collection.a/library.d` | `ui5.yaml` + +### Case 1.5: [workspace/1.1] Custom configPath for all libs + No configPath for single lib + +**WHEN** + +```yaml +specVersion: "workspace/1.1" +metadata: + name: default +dependencyManagement: + resolutions: + - path: ../root.collection + configPath: ui5-custom.yaml + - path: ../root.collection/library.a +``` + +**THEN** + +| Resolved library | Config file used | +|------------------|------------------| +| `library.a` | `ui5.yaml` +| `library.b` | `ui5-custom.yaml` +| `collection.a/library.c` | `ui5-custom.yaml` +| `collection.a/library.d` | `ui5-custom.yaml` + +### Case 1.5.1: [workspace/1.1] Custom configPath for all libs + No configPath for single lib (order changed) + +**WHEN** + +```yaml +specVersion: "workspace/1.1" +metadata: + name: default +dependencyManagement: + resolutions: + - path: ../root.collection/library.a + - path: ../root.collection + configPath: ui5-custom.yaml +``` + +**THEN** + +| Resolved library | Config file used | +|------------------|------------------| +| `library.a` | `ui5.yaml` +| `library.b` | `ui5-custom.yaml` +| `collection.a/library.c` | `ui5-custom.yaml` +| `collection.a/library.d` | `ui5-custom.yaml` + +### Case 1.6: [workspace/1.1] No configPath for all libs + Custom configPaths for two libs + +**WHEN** + +```yaml +specVersion: "workspace/1.1" +metadata: + name: default +dependencyManagement: + resolutions: + - path: ../root.collection + - path: ../root.collection/library.a + configPath: ui5-custom.yaml + - path: ../root.collection/library.b + configPath: ui5-another-custom.yaml +``` + +**THEN** + +| Resolved library | Config file used | +|------------------|------------------| +| `library.a` | `ui5-custom.yaml` +| `library.b` | `ui5-another-custom.yaml` +| `collection.a/library.c` | `ui5.yaml` +| `collection.a/library.d` | `ui5.yaml` + +### ⚠️ Case 1.7: [workspace/1.1] No configPath for all libs + Two custom configPaths for single lib + +**WHEN** + +```yaml +specVersion: "workspace/1.1" +metadata: + name: default +dependencyManagement: + resolutions: + - path: ../root.collection + - path: ../root.collection/library.a + configPath: ui5-custom.yaml + - path: ../root.collection/library.a + configPath: ui5-another-custom.yaml +``` + +**THEN** + +⚠️ Error: `Multiple resolutions for the same library 'library.a' in workspace config '' exist.` + +### ⚠️ Case 1.7.1: [workspace/1.1] No configPath for all libs + Two custom configPaths for single lib (order changed) + +**WHEN** + +```yaml +specVersion: "workspace/1.1" +metadata: + name: default +dependencyManagement: + resolutions: + - path: ../root.collection/library.a + configPath: ui5-custom.yaml + - path: ../root.collection + - path: ../root.collection/library.a + configPath: ui5-another-custom.yaml +``` + +**THEN** + +⚠️ Error: `Multiple resolutions for the same library 'library.a' in workspace config '' exist.` + +### Case 1.8: [workspace/1.1] No configPath for all libs + Custom configPath for sub collection + +**WHEN** + +```yaml +specVersion: "workspace/1.1" +metadata: + name: default +dependencyManagement: + resolutions: + - path: ../root.collection + - path: ../root.collection/collection.a + configPath: ui5-custom.yaml +``` + +**THEN** + +| Resolved library | Config file used | +|------------------|------------------| +| `library.a` | `ui5.yaml` +| `library.b` | `ui5.yaml` +| `collection.a/library.c` | `ui5-custom.yaml` +| `collection.a/library.d` | `ui5-custom.yaml` + +### Case 1.8.1: [workspace/1.1] Custom configPath for sub collection + No configPath for all libs + +**WHEN** + +```yaml +specVersion: "workspace/1.1" +metadata: + name: default +dependencyManagement: + resolutions: + - path: ../root.collection/collection.a + configPath: ui5-custom.yaml + - path: ../root.collection +``` + +**THEN** + +| Resolved library | Config file used | +|------------------|------------------| +| `library.a` | `ui5.yaml` +| `library.b` | `ui5.yaml` +| `collection.a/library.c` | `ui5-custom.yaml` +| `collection.a/library.d` | `ui5-custom.yaml` + +### Case 1.9: [workspace/1.1] No configPath for all libs + Custom configPaths for sub collection & single lib + +**WHEN** + +```yaml +specVersion: "workspace/1.1" +metadata: + name: default +dependencyManagement: + resolutions: + - path: ../root.collection + - path: ../root.collection/collection.a + configPath: ui5-custom.yaml + - path: ../root.collection/collection.a/library.c + configPath: ui5-another-custom.yaml +``` + +**THEN** + +| Resolved library | Config file used | +|------------------|------------------| +| `library.a` | `ui5.yaml` +| `library.b` | `ui5.yaml` +| `collection.a/library.c` | `ui5-another-custom.yaml` +| `collection.a/library.d` | `ui5-custom.yaml` + +### Case 1.9.1: [workspace/1.1] No configPath for all libs + Custom configPaths for sub collection & single lib (order changed) + +**WHEN** + +```yaml +specVersion: "workspace/1.1" +metadata: + name: default +dependencyManagement: + resolutions: + - path: ../root.collection/collection.a/library.c + configPath: ui5-another-custom.yaml + - path: ../root.collection + - path: ../root.collection/collection.a + configPath: ui5-custom.yaml +``` + +**THEN** + +| Resolved library | Config file used | +|------------------|------------------| +| `library.a` | `ui5.yaml` +| `library.b` | `ui5.yaml` +| `collection.a/library.c` | `ui5-another-custom.yaml` +| `collection.a/library.d` | `ui5-custom.yaml` + +### ⚠️ Case 1.10: [workspace/1.1] Two custom configPaths for the same single lib (ordering isolation) + +**WHEN** + +```yaml +specVersion: "workspace/1.1" +metadata: + name: default +dependencyManagement: + resolutions: + - path: ../root.collection/library.a + configPath: ui5-custom.yaml + - path: ../root.collection/library.a # same lib, later resolution + configPath: ui5-another-custom.yaml +``` + +**THEN** + +⚠️ Error: `Multiple resolutions for the same library 'library.a' in workspace config '' exist.` + +### ⚠️ Case 1.11: [workspace/1.1] Duplicate library via different path strings (no configPath) + +**WHEN** + +```yaml +specVersion: "workspace/1.1" +metadata: + name: default +dependencyManagement: + resolutions: + - path: ../root.collection/library.a + - path: ../root.collection/../root.collection/library.a +``` + +**THEN** + +⚠️ Error: `Multiple resolutions for the same library 'library.a' in workspace config '' exist.` + +### ⚠️ Case 1.11.1: [workspace/1.1] Duplicate library via different path strings (with configPath) + +**WHEN** + +```yaml +specVersion: "workspace/1.1" +metadata: + name: default +dependencyManagement: + resolutions: + - path: ../root.collection/library.a + configPath: ui5-custom.yaml + - path: ../root.collection/../root.collection/library.a + configPath: ui5-another-custom.yaml +``` + +**THEN** + +⚠️ Error: `Multiple resolutions for the same library 'library.a' in workspace config '' exist.` + +### 🔎 Case 1.11.2: [workspace/1.1] Duplicate library name via different directories + +**WHEN** + +```yaml +specVersion: "workspace/1.1" +metadata: + name: default +dependencyManagement: + resolutions: + - path: ../root.collection/library.a + configPath: ui5-custom.yaml + - path: ../another.root.collection/library.a + configPath: ui5-another-custom.yaml +``` + +**THEN** + +| Resolved library | Config file used | +|------------------|------------------| +| `root.collection/library.a` | `ui5-custom.yaml` +| `another.root.collection/library.a` | `ui5-another-custom.yaml` + + +--- +--- + +## Scenario 2 + +### GIVEN for all cases: + +``` +root.collection/ +├── library.a/ +│ ├── ui5.yaml +│ │ # missing ui5-custom.yaml +│ └── ui5-another-custom.yaml +├── library.b/ +│ ├── ui5.yaml +│ ├── ui5-custom.yaml +│ └── ui5-another-custom.yaml +└── collection.a/ + ├── library.c/ + │ ├── ui5.yaml + │ ├── ui5-custom.yaml + │ └── ui5-another-custom.yaml + └── library.d/ + ├── ui5.yaml + ├── ui5-custom.yaml + └── ui5-another-custom.yaml +``` + +--- + +### Case 2.1: [workspace/1.1] No configPath -- **⚠️ NO AUTOMATED TEST** + +**WHEN** + +```yaml +specVersion: "workspace/1.1" +metadata: + name: default +dependencyManagement: + resolutions: + - path: ../root.collection +``` + +**THEN** + +| Resolved library | Config file used | +|------------------|------------------| +| `library.a` | `ui5.yaml` +| `library.b` | `ui5.yaml` +| `collection.a/library.c` | `ui5.yaml` +| `collection.a/library.d` | `ui5.yaml` + + +### Case 2.2: [workspace/1.1] Custom configPath for all libs -> File not existing for single lib + +**WHEN** + +```yaml +specVersion: "workspace/1.1" +metadata: + name: default +dependencyManagement: + resolutions: + - path: ../root.collection + configPath: ui5-custom.yaml +``` + +**THEN** + +Error: `Cannot find config file 'ui5-custom.yaml' for path '../root.collection/library.a'` + + +### Case 2.3: [workspace/1.1] Custom configPath for single lib -> File not existing for single lib + +**WHEN** + +```yaml +specVersion: "workspace/1.1" +metadata: + name: default +dependencyManagement: + resolutions: + - path: ../root.collection + - path: ../root.collection/library.a + configPath: ui5-custom.yaml +``` + +**THEN** + +Error: `Cannot find config file 'ui5-custom.yaml' for path '../root.collection/library.a'` + +### Case 2.4: [workspace/1.1] Not existing configPath for single lib overwritten by No configPath for all libs + +**WHEN** + +```yaml +specVersion: "workspace/1.1" +metadata: + name: default +dependencyManagement: + resolutions: + - path: ../root.collection/library.a + configPath: ui5-custom.yaml + - path: ../root.collection +``` + +**THEN** + +Error: `Cannot find config file 'ui5-custom.yaml' for path '../root.collection/library.a'` + +### Case 2.5: [workspace/1.1] Not existing configPath for single lib overwritten by No configPath for the same lib + +**WHEN** + +```yaml +specVersion: "workspace/1.1" +metadata: + name: default +dependencyManagement: + resolutions: + - path: ../root.collection + configPath: ui5-custom.yaml + - path: ../root.collection/library.a +``` + +**THEN** + +| Resolved library | Config file used | +|------------------|------------------| +| `library.a` | `ui5.yaml` +| `library.b` | `ui5-custom.yaml` +| `collection.a/library.c` | `ui5-custom.yaml` +| `collection.a/library.d` | `ui5-custom.yaml` + +### ⚠️ Case 2.6: [workspace/1.1] Not existing configPath for single lib overwritten by Custom configPath for the same lib + +**WHEN** + +```yaml +specVersion: "workspace/1.1" +metadata: + name: default +dependencyManagement: + resolutions: + - path: ../root.collection + - path: ../root.collection/library.a + configPath: ui5-custom.yaml + - path: ../root.collection/library.a + configPath: ui5-another-custom.yaml +``` + +**THEN** + +⚠️ Error: `Multiple resolutions for the same library 'library.a' in workspace config '' exist.` + + +### ⚠️ Case 2.6.1: [workspace/1.1] Not existing configPath for single lib overwritten by Custom configPath for the same lib (order changed) + +**WHEN** + +```yaml +specVersion: "workspace/1.1" +metadata: + name: default +dependencyManagement: + resolutions: + - path: ../root.collection + - path: ../root.collection/library.a + configPath: ui5-another-custom.yaml + - path: ../root.collection/library.a + configPath: ui5-custom.yaml +``` + +**THEN** + +⚠️ Error: `Multiple resolutions for the same library 'library.a' in workspace config '' exist.` diff --git a/configPath-test-matrix-specificOneWins.md b/configPath-test-matrix-specificOneWins.md new file mode 100644 index 00000000000..584ccaf70bf --- /dev/null +++ b/configPath-test-matrix-specificOneWins.md @@ -0,0 +1,563 @@ +TODO: Delete this file before merging + +# `configPath` Test Matrix + +## Scenario 1 + +### GIVEN for all cases: + +``` +root.collection/ +├── library.a/ +│ ├── ui5.yaml +│ ├── ui5-custom.yaml +│ └── ui5-another-custom.yaml +├── library.b/ +│ ├── ui5.yaml +│ ├── ui5-custom.yaml +│ └── ui5-another-custom.yaml +└── collection.a/ + ├── library.c/ + │ ├── ui5.yaml + │ ├── ui5-custom.yaml + │ └── ui5-another-custom.yaml + └── library.d/ + ├── ui5.yaml + ├── ui5-custom.yaml + └── ui5-another-custom.yaml +``` + +--- + +### Case 1.1: [workspace/1.1] No configPath + +**WHEN** + +```yaml +specVersion: "workspace/1.1" +metadata: + name: default +dependencyManagement: + resolutions: + - path: ../root.collection +``` + +**THEN** + +| Resolved library | Config file used | +|------------------|------------------| +| `library.a` | `ui5.yaml` +| `library.b` | `ui5.yaml` +| `collection.a/library.c` | `ui5.yaml` +| `collection.a/library.d` | `ui5.yaml` + + +### Case 1.2: [workspace/1.1] Custom configPath for all libs + +**WHEN** + +```yaml +specVersion: "workspace/1.1" +metadata: + name: default +dependencyManagement: + resolutions: + - path: ../root.collection + configPath: ui5-custom.yaml +``` + +**THEN** + +| Resolved library | Config file used | +|------------------|------------------| +| `library.a` | `ui5-custom.yaml` +| `library.b` | `ui5-custom.yaml` +| `collection.a/library.c` | `ui5-custom.yaml` +| `collection.a/library.d` | `ui5-custom.yaml` + + +### Case 1.3: [workspace/1.1] No configPath + Custom configPath for single lib + +**WHEN** + +```yaml +specVersion: "workspace/1.1" +metadata: + name: default +dependencyManagement: + resolutions: + - path: ../root.collection + - path: ../root.collection/library.a + configPath: ui5-custom.yaml +``` + +**THEN** + +| Resolved library | Config file used | +|------------------|------------------| +| `library.a` | `ui5-custom.yaml` +| `library.b` | `ui5.yaml` +| `collection.a/library.c` | `ui5.yaml` +| `collection.a/library.d` | `ui5.yaml` + +### ⚠️ Case 1.4: [workspace/1.1] Custom configPath for single lib + No configPath for all libs + +**WHEN** + +```yaml +specVersion: "workspace/1.1" +metadata: + name: default +dependencyManagement: + resolutions: + - path: ../root.collection/library.a + configPath: ui5-custom.yaml + - path: ../root.collection +``` + +**THEN** + +| Resolved library | Config file used | +|------------------|------------------| +| `library.a` | ⚠️ `ui5-custom.yaml` +| `library.b` | `ui5.yaml` +| `collection.a/library.c` | `ui5.yaml` +| `collection.a/library.d` | `ui5.yaml` + +### Case 1.5: [workspace/1.1] Custom configPath for all libs + No configPath for single lib + +**WHEN** + +```yaml +specVersion: "workspace/1.1" +metadata: + name: default +dependencyManagement: + resolutions: + - path: ../root.collection + configPath: ui5-custom.yaml + - path: ../root.collection/library.a +``` + +**THEN** + +| Resolved library | Config file used | +|------------------|------------------| +| `library.a` | `ui5.yaml` +| `library.b` | `ui5-custom.yaml` +| `collection.a/library.c` | `ui5-custom.yaml` +| `collection.a/library.d` | `ui5-custom.yaml` + +### Case 1.5.1: [workspace/1.1] Custom configPath for all libs + No configPath for single lib (order changed) + +**WHEN** + +```yaml +specVersion: "workspace/1.1" +metadata: + name: default +dependencyManagement: + resolutions: + - path: ../root.collection/library.a + - path: ../root.collection + configPath: ui5-custom.yaml +``` + +**THEN** + +| Resolved library | Config file used | +|------------------|------------------| +| `library.a` | `ui5.yaml` +| `library.b` | `ui5-custom.yaml` +| `collection.a/library.c` | `ui5-custom.yaml` +| `collection.a/library.d` | `ui5-custom.yaml` + +### Case 1.6: [workspace/1.1] No configPath for all libs + Custom configPaths for two libs + +**WHEN** + +```yaml +specVersion: "workspace/1.1" +metadata: + name: default +dependencyManagement: + resolutions: + - path: ../root.collection + - path: ../root.collection/library.a + configPath: ui5-custom.yaml + - path: ../root.collection/library.b + configPath: ui5-another-custom.yaml +``` + +**THEN** + +| Resolved library | Config file used | +|------------------|------------------| +| `library.a` | `ui5-custom.yaml` +| `library.b` | `ui5-another-custom.yaml` +| `collection.a/library.c` | `ui5.yaml` +| `collection.a/library.d` | `ui5.yaml` + +### Case 1.7: [workspace/1.1] No configPath for all libs + Two custom configPaths for single lib + +**WHEN** + +```yaml +specVersion: "workspace/1.1" +metadata: + name: default +dependencyManagement: + resolutions: + - path: ../root.collection + - path: ../root.collection/library.a + configPath: ui5-custom.yaml + - path: ../root.collection/library.a + configPath: ui5-another-custom.yaml +``` + +**THEN** + +| Resolved library | Config file used | +|------------------|------------------| +| `library.a` | `ui5-another-custom.yaml` +| `library.b` | `ui5.yaml` +| `collection.a/library.c` | `ui5.yaml` +| `collection.a/library.d` | `ui5.yaml` + +### Case 1.7.1: [workspace/1.1] No configPath for all libs + Two custom configPaths for single lib (order changed) + +**WHEN** + +```yaml +specVersion: "workspace/1.1" +metadata: + name: default +dependencyManagement: + resolutions: + - path: ../root.collection/library.a + configPath: ui5-custom.yaml + - path: ../root.collection + - path: ../root.collection/library.a + configPath: ui5-another-custom.yaml +``` + +**THEN** + +| Resolved library | Config file used | +|------------------|------------------| +| `library.a` | `ui5-another-custom.yaml` +| `library.b` | `ui5.yaml` +| `collection.a/library.c` | `ui5.yaml` +| `collection.a/library.d` | `ui5.yaml` + +**Remark:** For the validation, maybe log a warning (because multiple resolutions for the same library exist). + +### Case 1.8: [workspace/1.1] No configPath for all libs + Custom configPath for sub collection + +**WHEN** + +```yaml +specVersion: "workspace/1.1" +metadata: + name: default +dependencyManagement: + resolutions: + - path: ../root.collection + - path: ../root.collection/collection.a + configPath: ui5-custom.yaml +``` + +**THEN** + +| Resolved library | Config file used | +|------------------|------------------| +| `library.a` | `ui5.yaml` +| `library.b` | `ui5.yaml` +| `collection.a/library.c` | `ui5-custom.yaml` +| `collection.a/library.d` | `ui5-custom.yaml` + +### Case 1.8.1: [workspace/1.1] Custom configPath for sub collection + No configPath for all libs + +**WHEN** + +```yaml +specVersion: "workspace/1.1" +metadata: + name: default +dependencyManagement: + resolutions: + - path: ../root.collection/collection.a + configPath: ui5-custom.yaml + - path: ../root.collection +``` + +**THEN** + +| Resolved library | Config file used | +|------------------|------------------| +| `library.a` | `ui5.yaml` +| `library.b` | `ui5.yaml` +| `collection.a/library.c` | `ui5-custom.yaml` +| `collection.a/library.d` | `ui5-custom.yaml` + +### Case 1.9: [workspace/1.1] No configPath for all libs + Custom configPaths for sub collection & single lib + +**WHEN** + +```yaml +specVersion: "workspace/1.1" +metadata: + name: default +dependencyManagement: + resolutions: + - path: ../root.collection + - path: ../root.collection/collection.a + configPath: ui5-custom.yaml + - path: ../root.collection/collection.a/library.c + configPath: ui5-another-custom.yaml +``` + +**THEN** + +| Resolved library | Config file used | +|------------------|------------------| +| `library.a` | `ui5.yaml` +| `library.b` | `ui5.yaml` +| `collection.a/library.c` | `ui5-another-custom.yaml` +| `collection.a/library.d` | `ui5-custom.yaml` + +### Case 1.9.1: [workspace/1.1] No configPath for all libs + Custom configPaths for sub collection & single lib (order changed) + +**WHEN** + +```yaml +specVersion: "workspace/1.1" +metadata: + name: default +dependencyManagement: + resolutions: + - path: ../root.collection/collection.a/library.c + configPath: ui5-another-custom.yaml + - path: ../root.collection + - path: ../root.collection/collection.a + configPath: ui5-custom.yaml +``` + +**THEN** + +| Resolved library | Config file used | +|------------------|------------------| +| `library.a` | `ui5.yaml` +| `library.b` | `ui5.yaml` +| `collection.a/library.c` | `ui5-another-custom.yaml` +| `collection.a/library.d` | `ui5-custom.yaml` + +### Case 1.10: [workspace/1.1] Two custom configPaths for the same single lib (ordering isolation) + +**WHEN** + +```yaml +specVersion: "workspace/1.1" +metadata: + name: default +dependencyManagement: + resolutions: + - path: ../root.collection/library.a + configPath: ui5-custom.yaml + - path: ../root.collection/library.a # same lib, later resolution + configPath: ui5-another-custom.yaml +``` + +**THEN** + +| Resolved library | Config file used | +|------------------|------------------| +| `library.a` | `ui5-another-custom.yaml` + +Only `library.a` is resolved (the two resolutions collapse into a single module). +This case isolates the concept **the last resolution wins** from the original logic ("specificity wins"). + +--- +--- + +## Scenario 2 + +### GIVEN for all cases: + +``` +root.collection/ +├── library.a/ +│ ├── ui5.yaml +│ │ # missing ui5-custom.yaml +│ └── ui5-another-custom.yaml +├── library.b/ +│ ├── ui5.yaml +│ ├── ui5-custom.yaml +│ └── ui5-another-custom.yaml +└── collection.a/ + ├── library.c/ + │ ├── ui5.yaml + │ ├── ui5-custom.yaml + │ └── ui5-another-custom.yaml + └── library.d/ + ├── ui5.yaml + ├── ui5-custom.yaml + └── ui5-another-custom.yaml +``` + +--- + +### Case 2.1: [workspace/1.1] No configPath -- **⚠️ NO AUTOMATED TEST** + +**WHEN** + +```yaml +specVersion: "workspace/1.1" +metadata: + name: default +dependencyManagement: + resolutions: + - path: ../root.collection +``` + +**THEN** + +| Resolved library | Config file used | +|------------------|------------------| +| `library.a` | `ui5.yaml` +| `library.b` | `ui5.yaml` +| `collection.a/library.c` | `ui5.yaml` +| `collection.a/library.d` | `ui5.yaml` + + +### Case 2.2: [workspace/1.1] Custom configPath for all libs -> File not existing for single lib + +**WHEN** + +```yaml +specVersion: "workspace/1.1" +metadata: + name: default +dependencyManagement: + resolutions: + - path: ../root.collection + configPath: ui5-custom.yaml +``` + +**THEN** + +Error: `Cannot find config file 'ui5-custom.yaml' for path '../root.collection/library.a'` + + +### Case 2.3: [workspace/1.1] Custom configPath for single lib -> File not existing for single lib + +**WHEN** + +```yaml +specVersion: "workspace/1.1" +metadata: + name: default +dependencyManagement: + resolutions: + - path: ../root.collection + - path: ../root.collection/library.a + configPath: ui5-custom.yaml +``` + +**THEN** + +Error: `Cannot find config file 'ui5-custom.yaml' for path '../root.collection/library.a'` + +### ⚠️ Case 2.4: [workspace/1.1] Not existing configPath for single lib overwritten by No configPath for all libs + +**WHEN** + +```yaml +specVersion: "workspace/1.1" +metadata: + name: default +dependencyManagement: + resolutions: + - path: ../root.collection/library.a + configPath: ui5-custom.yaml + - path: ../root.collection +``` + +**THEN** + +Error: `Cannot find config file 'ui5-custom.yaml' for path '../root.collection/library.a'` + +### Case 2.5: [workspace/1.1] Not existing configPath for single lib overwritten by No configPath for the same lib + +**WHEN** + +```yaml +specVersion: "workspace/1.1" +metadata: + name: default +dependencyManagement: + resolutions: + - path: ../root.collection + configPath: ui5-custom.yaml + - path: ../root.collection/library.a +``` + +**THEN** + +| Resolved library | Config file used | +|------------------|------------------| +| `library.a` | `ui5.yaml` +| `library.b` | `ui5-custom.yaml` +| `collection.a/library.c` | `ui5-custom.yaml` +| `collection.a/library.d` | `ui5-custom.yaml` + +### Case 2.6: [workspace/1.1] Not existing configPath for single lib overwritten by Custom configPath for the same lib + +**WHEN** + +```yaml +specVersion: "workspace/1.1" +metadata: + name: default +dependencyManagement: + resolutions: + - path: ../root.collection + - path: ../root.collection/library.a + configPath: ui5-custom.yaml + - path: ../root.collection/library.a + configPath: ui5-another-custom.yaml +``` + +**THEN** + +| Resolved library | Config file used | +|------------------|------------------| +| `library.a` | `ui5-another-custom.yaml` +| `library.b` | `ui5.yaml` +| `collection.a/library.c` | `ui5.yaml` +| `collection.a/library.d` | `ui5.yaml` + +**Remark:** For the validation, maybe log a warning (because multiple resolutions for the same library exist). + +### Case 2.6.1: [workspace/1.1] Not existing configPath for single lib overwritten by Custom configPath for the same lib (order changed) + +**WHEN** + +```yaml +specVersion: "workspace/1.1" +metadata: + name: default +dependencyManagement: + resolutions: + - path: ../root.collection + - path: ../root.collection/library.a + configPath: ui5-another-custom.yaml + - path: ../root.collection/library.a + configPath: ui5-custom.yaml +``` + +**THEN** + +Error: `Cannot find config file 'ui5-custom.yaml' for path '../root.collection/library.a'` + +**Remark:** For the validation, maybe log a warning (because multiple resolutions for the same library exist). diff --git a/internal/documentation/docs/pages/Workspace.md b/internal/documentation/docs/pages/Workspace.md index 730e9420284..441ea33e611 100644 --- a/internal/documentation/docs/pages/Workspace.md +++ b/internal/documentation/docs/pages/Workspace.md @@ -5,7 +5,7 @@ ::: details ```yaml title="ui5-workspace.yaml" -specVersion: workspace/1.0 +specVersion: workspace/1.1 metadata: name: default dependencyManagement: @@ -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: @@ -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 ``` @@ -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: @@ -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" [...] ``` @@ -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. diff --git a/packages/project/lib/graph/Module.js b/packages/project/lib/graph/Module.js index 5130ef2acf0..5bf5223a827 100644 --- a/packages/project/lib/graph/Module.js +++ b/packages/project/lib/graph/Module.js @@ -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; } diff --git a/packages/project/lib/graph/Workspace.js b/packages/project/lib/graph/Workspace.js index d39629a1491..71a830e1c34 100644 --- a/packages/project/lib/graph/Workspace.js +++ b/packages/project/lib/graph/Workspace.js @@ -138,13 +138,39 @@ class Workspace { }; } + // Detect duplicate resolutions targeting the same library + // (same exact absolute paths should throw): + const seenAbsolutePaths = []; + for (const {path: resolutionPath} of resolutions) { + if (!resolutionPath) { + continue; + } + const absolutePath = path.resolve(resolutionPath); + if (seenAbsolutePaths.includes(absolutePath)) { + throw new Error( + `Multiple resolutions for the same library '${path.basename(absolutePath)}' ` + + `(resolved to '${absolutePath}') in workspace '${this.getName()}' exist.`); + } + seenAbsolutePaths.push(absolutePath); + } + 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); })); // Flatten array since package-workspaces might have resolved to multiple modules for a single resolution @@ -175,7 +201,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`); @@ -235,7 +261,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)) { @@ -248,7 +275,8 @@ class Workspace { return [new Module({ id: pkg.name, version: pkg.version, - modulePath: nodePath + modulePath: nodePath, + configPath: configPath ? path.resolve(nodePath, configPath) : undefined, })]; } } diff --git a/packages/project/lib/validation/schema/ui5-workspace.json b/packages/project/lib/validation/schema/ui5-workspace.json index d4cd46c1946..ab2b5d5abea 100644 --- a/packages/project/lib/validation/schema/ui5-workspace.json +++ b/packages/project/lib/validation/schema/ui5-workspace.json @@ -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" @@ -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", @@ -42,13 +67,15 @@ "properties": { "resolutions": { "type": "array", - "items": { "type": "object", "additionalProperties": false, "properties": { "path": { "type": "string" + }, + "configPath": { + "type": "string" } } } diff --git a/packages/project/test/fixtures/collection.c.noCustomConfigForLibA/collection.a/library.c/package.json b/packages/project/test/fixtures/collection.c.noCustomConfigForLibA/collection.a/library.c/package.json new file mode 100644 index 00000000000..efbb5e86409 --- /dev/null +++ b/packages/project/test/fixtures/collection.c.noCustomConfigForLibA/collection.a/library.c/package.json @@ -0,0 +1,5 @@ +{ + "name": "library.c", + "version": "1.0.0", + "description": "Simple SAPUI5 based library" +} diff --git a/packages/project/test/fixtures/collection.c.noCustomConfigForLibA/collection.a/library.c/src/library/a/.library b/packages/project/test/fixtures/collection.c.noCustomConfigForLibA/collection.a/library.c/src/library/a/.library new file mode 100644 index 00000000000..ef0ea1065bc --- /dev/null +++ b/packages/project/test/fixtures/collection.c.noCustomConfigForLibA/collection.a/library.c/src/library/a/.library @@ -0,0 +1,17 @@ + + + + library.a + SAP SE + Some fancy copyright ${currentYear} + ${version} + + Library A + + + + library.d + + + + diff --git a/packages/project/test/fixtures/collection.c.noCustomConfigForLibA/collection.a/library.c/ui5-another-custom.yaml b/packages/project/test/fixtures/collection.c.noCustomConfigForLibA/collection.a/library.c/ui5-another-custom.yaml new file mode 100644 index 00000000000..90edaf85c9f --- /dev/null +++ b/packages/project/test/fixtures/collection.c.noCustomConfigForLibA/collection.a/library.c/ui5-another-custom.yaml @@ -0,0 +1,5 @@ +--- +specVersion: "2.3" +type: library +metadata: + name: library.c.another.custom diff --git a/packages/project/test/fixtures/collection.c.noCustomConfigForLibA/collection.a/library.c/ui5-custom.yaml b/packages/project/test/fixtures/collection.c.noCustomConfigForLibA/collection.a/library.c/ui5-custom.yaml new file mode 100644 index 00000000000..c84f8a4e014 --- /dev/null +++ b/packages/project/test/fixtures/collection.c.noCustomConfigForLibA/collection.a/library.c/ui5-custom.yaml @@ -0,0 +1,5 @@ +--- +specVersion: "2.3" +type: library +metadata: + name: library.c.custom diff --git a/packages/project/test/fixtures/collection.c.noCustomConfigForLibA/collection.a/library.c/ui5.yaml b/packages/project/test/fixtures/collection.c.noCustomConfigForLibA/collection.a/library.c/ui5.yaml new file mode 100644 index 00000000000..7c5e38a7fc1 --- /dev/null +++ b/packages/project/test/fixtures/collection.c.noCustomConfigForLibA/collection.a/library.c/ui5.yaml @@ -0,0 +1,5 @@ +--- +specVersion: "2.3" +type: library +metadata: + name: library.c diff --git a/packages/project/test/fixtures/collection.c.noCustomConfigForLibA/collection.a/library.d/package.json b/packages/project/test/fixtures/collection.c.noCustomConfigForLibA/collection.a/library.d/package.json new file mode 100644 index 00000000000..fd53171e802 --- /dev/null +++ b/packages/project/test/fixtures/collection.c.noCustomConfigForLibA/collection.a/library.d/package.json @@ -0,0 +1,5 @@ +{ + "name": "library.d", + "version": "1.0.0", + "description": "Simple SAPUI5 based library" +} diff --git a/packages/project/test/fixtures/collection.c.noCustomConfigForLibA/collection.a/library.d/src/library/b/.library b/packages/project/test/fixtures/collection.c.noCustomConfigForLibA/collection.a/library.d/src/library/b/.library new file mode 100644 index 00000000000..7128151f3f4 --- /dev/null +++ b/packages/project/test/fixtures/collection.c.noCustomConfigForLibA/collection.a/library.d/src/library/b/.library @@ -0,0 +1,17 @@ + + + + library.b + SAP SE + Some fancy copyright ${currentYear} + ${version} + + Library B + + + + library.d + + + + diff --git a/packages/project/test/fixtures/collection.c.noCustomConfigForLibA/collection.a/library.d/ui5-another-custom.yaml b/packages/project/test/fixtures/collection.c.noCustomConfigForLibA/collection.a/library.d/ui5-another-custom.yaml new file mode 100644 index 00000000000..82c1f167712 --- /dev/null +++ b/packages/project/test/fixtures/collection.c.noCustomConfigForLibA/collection.a/library.d/ui5-another-custom.yaml @@ -0,0 +1,5 @@ +--- +specVersion: "2.3" +type: library +metadata: + name: library.d.another.custom diff --git a/packages/project/test/fixtures/collection.c.noCustomConfigForLibA/collection.a/library.d/ui5-custom.yaml b/packages/project/test/fixtures/collection.c.noCustomConfigForLibA/collection.a/library.d/ui5-custom.yaml new file mode 100644 index 00000000000..47d355df4f9 --- /dev/null +++ b/packages/project/test/fixtures/collection.c.noCustomConfigForLibA/collection.a/library.d/ui5-custom.yaml @@ -0,0 +1,5 @@ +--- +specVersion: "2.3" +type: library +metadata: + name: library.d.custom diff --git a/packages/project/test/fixtures/collection.c.noCustomConfigForLibA/collection.a/library.d/ui5.yaml b/packages/project/test/fixtures/collection.c.noCustomConfigForLibA/collection.a/library.d/ui5.yaml new file mode 100644 index 00000000000..e05b61880d8 --- /dev/null +++ b/packages/project/test/fixtures/collection.c.noCustomConfigForLibA/collection.a/library.d/ui5.yaml @@ -0,0 +1,5 @@ +--- +specVersion: "2.3" +type: library +metadata: + name: library.d diff --git a/packages/project/test/fixtures/collection.c.noCustomConfigForLibA/collection.a/package.json b/packages/project/test/fixtures/collection.c.noCustomConfigForLibA/collection.a/package.json new file mode 100644 index 00000000000..b4e3eb86aea --- /dev/null +++ b/packages/project/test/fixtures/collection.c.noCustomConfigForLibA/collection.a/package.json @@ -0,0 +1,9 @@ +{ + "name": "collection", + "version": "1.0.0", + "description": "Simple Collection", + "workspaces": [ + "library.c", + "library.d" + ] +} diff --git a/packages/project/test/fixtures/collection.c.noCustomConfigForLibA/library.a/package.json b/packages/project/test/fixtures/collection.c.noCustomConfigForLibA/library.a/package.json new file mode 100644 index 00000000000..3529634765e --- /dev/null +++ b/packages/project/test/fixtures/collection.c.noCustomConfigForLibA/library.a/package.json @@ -0,0 +1,5 @@ +{ + "name": "library.a", + "version": "1.0.0", + "description": "Simple SAPUI5 based library" +} diff --git a/packages/project/test/fixtures/collection.c.noCustomConfigForLibA/library.a/src/library/a/.library b/packages/project/test/fixtures/collection.c.noCustomConfigForLibA/library.a/src/library/a/.library new file mode 100644 index 00000000000..ef0ea1065bc --- /dev/null +++ b/packages/project/test/fixtures/collection.c.noCustomConfigForLibA/library.a/src/library/a/.library @@ -0,0 +1,17 @@ + + + + library.a + SAP SE + Some fancy copyright ${currentYear} + ${version} + + Library A + + + + library.d + + + + diff --git a/packages/project/test/fixtures/collection.c.noCustomConfigForLibA/library.a/ui5-another-custom.yaml b/packages/project/test/fixtures/collection.c.noCustomConfigForLibA/library.a/ui5-another-custom.yaml new file mode 100644 index 00000000000..a1fa609975f --- /dev/null +++ b/packages/project/test/fixtures/collection.c.noCustomConfigForLibA/library.a/ui5-another-custom.yaml @@ -0,0 +1,5 @@ +--- +specVersion: "2.3" +type: library +metadata: + name: library.a.another.custom diff --git a/packages/project/test/fixtures/collection.c.noCustomConfigForLibA/library.a/ui5.yaml b/packages/project/test/fixtures/collection.c.noCustomConfigForLibA/library.a/ui5.yaml new file mode 100644 index 00000000000..8d4784313c3 --- /dev/null +++ b/packages/project/test/fixtures/collection.c.noCustomConfigForLibA/library.a/ui5.yaml @@ -0,0 +1,5 @@ +--- +specVersion: "2.3" +type: library +metadata: + name: library.a diff --git a/packages/project/test/fixtures/collection.c.noCustomConfigForLibA/library.b/package.json b/packages/project/test/fixtures/collection.c.noCustomConfigForLibA/library.b/package.json new file mode 100644 index 00000000000..a1f0a5e1650 --- /dev/null +++ b/packages/project/test/fixtures/collection.c.noCustomConfigForLibA/library.b/package.json @@ -0,0 +1,5 @@ +{ + "name": "library.b", + "version": "1.0.0", + "description": "Simple SAPUI5 based library" +} diff --git a/packages/project/test/fixtures/collection.c.noCustomConfigForLibA/library.b/src/library/b/.library b/packages/project/test/fixtures/collection.c.noCustomConfigForLibA/library.b/src/library/b/.library new file mode 100644 index 00000000000..7128151f3f4 --- /dev/null +++ b/packages/project/test/fixtures/collection.c.noCustomConfigForLibA/library.b/src/library/b/.library @@ -0,0 +1,17 @@ + + + + library.b + SAP SE + Some fancy copyright ${currentYear} + ${version} + + Library B + + + + library.d + + + + diff --git a/packages/project/test/fixtures/collection.c.noCustomConfigForLibA/library.b/ui5-another-custom.yaml b/packages/project/test/fixtures/collection.c.noCustomConfigForLibA/library.b/ui5-another-custom.yaml new file mode 100644 index 00000000000..4c7d3de243b --- /dev/null +++ b/packages/project/test/fixtures/collection.c.noCustomConfigForLibA/library.b/ui5-another-custom.yaml @@ -0,0 +1,5 @@ +--- +specVersion: "2.3" +type: library +metadata: + name: library.b.another.custom diff --git a/packages/project/test/fixtures/collection.c.noCustomConfigForLibA/library.b/ui5-custom.yaml b/packages/project/test/fixtures/collection.c.noCustomConfigForLibA/library.b/ui5-custom.yaml new file mode 100644 index 00000000000..52a13d705f2 --- /dev/null +++ b/packages/project/test/fixtures/collection.c.noCustomConfigForLibA/library.b/ui5-custom.yaml @@ -0,0 +1,5 @@ +--- +specVersion: "2.3" +type: library +metadata: + name: library.b.custom diff --git a/packages/project/test/fixtures/collection.c.noCustomConfigForLibA/library.b/ui5.yaml b/packages/project/test/fixtures/collection.c.noCustomConfigForLibA/library.b/ui5.yaml new file mode 100644 index 00000000000..b2fe5be59ee --- /dev/null +++ b/packages/project/test/fixtures/collection.c.noCustomConfigForLibA/library.b/ui5.yaml @@ -0,0 +1,5 @@ +--- +specVersion: "2.3" +type: library +metadata: + name: library.b diff --git a/packages/project/test/fixtures/collection.c.noCustomConfigForLibA/package.json b/packages/project/test/fixtures/collection.c.noCustomConfigForLibA/package.json new file mode 100644 index 00000000000..edb7e2145da --- /dev/null +++ b/packages/project/test/fixtures/collection.c.noCustomConfigForLibA/package.json @@ -0,0 +1,10 @@ +{ + "name": "collection", + "version": "1.0.0", + "description": "Simple Collection", + "workspaces": [ + "library.a", + "library.b", + "collection.a" + ] +} diff --git a/packages/project/test/fixtures/collection.c/collection.a/library.c/package.json b/packages/project/test/fixtures/collection.c/collection.a/library.c/package.json new file mode 100644 index 00000000000..efbb5e86409 --- /dev/null +++ b/packages/project/test/fixtures/collection.c/collection.a/library.c/package.json @@ -0,0 +1,5 @@ +{ + "name": "library.c", + "version": "1.0.0", + "description": "Simple SAPUI5 based library" +} diff --git a/packages/project/test/fixtures/collection.c/collection.a/library.c/src/library/a/.library b/packages/project/test/fixtures/collection.c/collection.a/library.c/src/library/a/.library new file mode 100644 index 00000000000..ef0ea1065bc --- /dev/null +++ b/packages/project/test/fixtures/collection.c/collection.a/library.c/src/library/a/.library @@ -0,0 +1,17 @@ + + + + library.a + SAP SE + Some fancy copyright ${currentYear} + ${version} + + Library A + + + + library.d + + + + diff --git a/packages/project/test/fixtures/collection.c/collection.a/library.c/ui5-another-custom.yaml b/packages/project/test/fixtures/collection.c/collection.a/library.c/ui5-another-custom.yaml new file mode 100644 index 00000000000..90edaf85c9f --- /dev/null +++ b/packages/project/test/fixtures/collection.c/collection.a/library.c/ui5-another-custom.yaml @@ -0,0 +1,5 @@ +--- +specVersion: "2.3" +type: library +metadata: + name: library.c.another.custom diff --git a/packages/project/test/fixtures/collection.c/collection.a/library.c/ui5-custom.yaml b/packages/project/test/fixtures/collection.c/collection.a/library.c/ui5-custom.yaml new file mode 100644 index 00000000000..c84f8a4e014 --- /dev/null +++ b/packages/project/test/fixtures/collection.c/collection.a/library.c/ui5-custom.yaml @@ -0,0 +1,5 @@ +--- +specVersion: "2.3" +type: library +metadata: + name: library.c.custom diff --git a/packages/project/test/fixtures/collection.c/collection.a/library.c/ui5.yaml b/packages/project/test/fixtures/collection.c/collection.a/library.c/ui5.yaml new file mode 100644 index 00000000000..7c5e38a7fc1 --- /dev/null +++ b/packages/project/test/fixtures/collection.c/collection.a/library.c/ui5.yaml @@ -0,0 +1,5 @@ +--- +specVersion: "2.3" +type: library +metadata: + name: library.c diff --git a/packages/project/test/fixtures/collection.c/collection.a/library.d/package.json b/packages/project/test/fixtures/collection.c/collection.a/library.d/package.json new file mode 100644 index 00000000000..fd53171e802 --- /dev/null +++ b/packages/project/test/fixtures/collection.c/collection.a/library.d/package.json @@ -0,0 +1,5 @@ +{ + "name": "library.d", + "version": "1.0.0", + "description": "Simple SAPUI5 based library" +} diff --git a/packages/project/test/fixtures/collection.c/collection.a/library.d/src/library/b/.library b/packages/project/test/fixtures/collection.c/collection.a/library.d/src/library/b/.library new file mode 100644 index 00000000000..7128151f3f4 --- /dev/null +++ b/packages/project/test/fixtures/collection.c/collection.a/library.d/src/library/b/.library @@ -0,0 +1,17 @@ + + + + library.b + SAP SE + Some fancy copyright ${currentYear} + ${version} + + Library B + + + + library.d + + + + diff --git a/packages/project/test/fixtures/collection.c/collection.a/library.d/ui5-another-custom.yaml b/packages/project/test/fixtures/collection.c/collection.a/library.d/ui5-another-custom.yaml new file mode 100644 index 00000000000..82c1f167712 --- /dev/null +++ b/packages/project/test/fixtures/collection.c/collection.a/library.d/ui5-another-custom.yaml @@ -0,0 +1,5 @@ +--- +specVersion: "2.3" +type: library +metadata: + name: library.d.another.custom diff --git a/packages/project/test/fixtures/collection.c/collection.a/library.d/ui5-custom.yaml b/packages/project/test/fixtures/collection.c/collection.a/library.d/ui5-custom.yaml new file mode 100644 index 00000000000..47d355df4f9 --- /dev/null +++ b/packages/project/test/fixtures/collection.c/collection.a/library.d/ui5-custom.yaml @@ -0,0 +1,5 @@ +--- +specVersion: "2.3" +type: library +metadata: + name: library.d.custom diff --git a/packages/project/test/fixtures/collection.c/collection.a/library.d/ui5.yaml b/packages/project/test/fixtures/collection.c/collection.a/library.d/ui5.yaml new file mode 100644 index 00000000000..e05b61880d8 --- /dev/null +++ b/packages/project/test/fixtures/collection.c/collection.a/library.d/ui5.yaml @@ -0,0 +1,5 @@ +--- +specVersion: "2.3" +type: library +metadata: + name: library.d diff --git a/packages/project/test/fixtures/collection.c/collection.a/package.json b/packages/project/test/fixtures/collection.c/collection.a/package.json new file mode 100644 index 00000000000..b4e3eb86aea --- /dev/null +++ b/packages/project/test/fixtures/collection.c/collection.a/package.json @@ -0,0 +1,9 @@ +{ + "name": "collection", + "version": "1.0.0", + "description": "Simple Collection", + "workspaces": [ + "library.c", + "library.d" + ] +} diff --git a/packages/project/test/fixtures/collection.c/library.a/package.json b/packages/project/test/fixtures/collection.c/library.a/package.json new file mode 100644 index 00000000000..3529634765e --- /dev/null +++ b/packages/project/test/fixtures/collection.c/library.a/package.json @@ -0,0 +1,5 @@ +{ + "name": "library.a", + "version": "1.0.0", + "description": "Simple SAPUI5 based library" +} diff --git a/packages/project/test/fixtures/collection.c/library.a/src/library/a/.library b/packages/project/test/fixtures/collection.c/library.a/src/library/a/.library new file mode 100644 index 00000000000..ef0ea1065bc --- /dev/null +++ b/packages/project/test/fixtures/collection.c/library.a/src/library/a/.library @@ -0,0 +1,17 @@ + + + + library.a + SAP SE + Some fancy copyright ${currentYear} + ${version} + + Library A + + + + library.d + + + + diff --git a/packages/project/test/fixtures/collection.c/library.a/ui5-another-custom.yaml b/packages/project/test/fixtures/collection.c/library.a/ui5-another-custom.yaml new file mode 100644 index 00000000000..a1fa609975f --- /dev/null +++ b/packages/project/test/fixtures/collection.c/library.a/ui5-another-custom.yaml @@ -0,0 +1,5 @@ +--- +specVersion: "2.3" +type: library +metadata: + name: library.a.another.custom diff --git a/packages/project/test/fixtures/collection.c/library.a/ui5-custom.yaml b/packages/project/test/fixtures/collection.c/library.a/ui5-custom.yaml new file mode 100644 index 00000000000..62e46e14554 --- /dev/null +++ b/packages/project/test/fixtures/collection.c/library.a/ui5-custom.yaml @@ -0,0 +1,5 @@ +--- +specVersion: "2.3" +type: library +metadata: + name: library.a.custom diff --git a/packages/project/test/fixtures/collection.c/library.a/ui5.yaml b/packages/project/test/fixtures/collection.c/library.a/ui5.yaml new file mode 100644 index 00000000000..8d4784313c3 --- /dev/null +++ b/packages/project/test/fixtures/collection.c/library.a/ui5.yaml @@ -0,0 +1,5 @@ +--- +specVersion: "2.3" +type: library +metadata: + name: library.a diff --git a/packages/project/test/fixtures/collection.c/library.b/package.json b/packages/project/test/fixtures/collection.c/library.b/package.json new file mode 100644 index 00000000000..a1f0a5e1650 --- /dev/null +++ b/packages/project/test/fixtures/collection.c/library.b/package.json @@ -0,0 +1,5 @@ +{ + "name": "library.b", + "version": "1.0.0", + "description": "Simple SAPUI5 based library" +} diff --git a/packages/project/test/fixtures/collection.c/library.b/src/library/b/.library b/packages/project/test/fixtures/collection.c/library.b/src/library/b/.library new file mode 100644 index 00000000000..7128151f3f4 --- /dev/null +++ b/packages/project/test/fixtures/collection.c/library.b/src/library/b/.library @@ -0,0 +1,17 @@ + + + + library.b + SAP SE + Some fancy copyright ${currentYear} + ${version} + + Library B + + + + library.d + + + + diff --git a/packages/project/test/fixtures/collection.c/library.b/ui5-another-custom.yaml b/packages/project/test/fixtures/collection.c/library.b/ui5-another-custom.yaml new file mode 100644 index 00000000000..4c7d3de243b --- /dev/null +++ b/packages/project/test/fixtures/collection.c/library.b/ui5-another-custom.yaml @@ -0,0 +1,5 @@ +--- +specVersion: "2.3" +type: library +metadata: + name: library.b.another.custom diff --git a/packages/project/test/fixtures/collection.c/library.b/ui5-custom.yaml b/packages/project/test/fixtures/collection.c/library.b/ui5-custom.yaml new file mode 100644 index 00000000000..52a13d705f2 --- /dev/null +++ b/packages/project/test/fixtures/collection.c/library.b/ui5-custom.yaml @@ -0,0 +1,5 @@ +--- +specVersion: "2.3" +type: library +metadata: + name: library.b.custom diff --git a/packages/project/test/fixtures/collection.c/library.b/ui5.yaml b/packages/project/test/fixtures/collection.c/library.b/ui5.yaml new file mode 100644 index 00000000000..b2fe5be59ee --- /dev/null +++ b/packages/project/test/fixtures/collection.c/library.b/ui5.yaml @@ -0,0 +1,5 @@ +--- +specVersion: "2.3" +type: library +metadata: + name: library.b diff --git a/packages/project/test/fixtures/collection.c/package.json b/packages/project/test/fixtures/collection.c/package.json new file mode 100644 index 00000000000..edb7e2145da --- /dev/null +++ b/packages/project/test/fixtures/collection.c/package.json @@ -0,0 +1,10 @@ +{ + "name": "collection", + "version": "1.0.0", + "description": "Simple Collection", + "workspaces": [ + "library.a", + "library.b", + "collection.a" + ] +} diff --git a/packages/project/test/fixtures/library.d/custom-config-path.yaml b/packages/project/test/fixtures/library.d/custom-config-path.yaml new file mode 100644 index 00000000000..ca7c0921253 --- /dev/null +++ b/packages/project/test/fixtures/library.d/custom-config-path.yaml @@ -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 diff --git a/packages/project/test/fixtures/library.e/ui5-library.d-config.yaml b/packages/project/test/fixtures/library.e/ui5-library.d-config.yaml new file mode 100644 index 00000000000..a9f1cdca018 --- /dev/null +++ b/packages/project/test/fixtures/library.e/ui5-library.d-config.yaml @@ -0,0 +1,11 @@ +--- +specVersion: "2.3" +type: library +metadata: + name: library.d + copyright: This is a config for another library (outside of this dir) +resources: + configuration: + paths: + src: main/src + test: main/test diff --git a/packages/project/test/lib/graph/Module.js b/packages/project/test/lib/graph/Module.js index abd57d90860..6460bbc2c9d 100644 --- a/packages/project/test/lib/graph/Module.js +++ b/packages/project/test/lib/graph/Module.js @@ -433,9 +433,10 @@ test("Corrupt configuration in file", async (t) => { }); const err = await t.throwsAsync(ui5Module.getSpecifications()); - t.regex(err.message, - new RegExp("^Failed to parse configuration for project application.a.id at 'ui5-test-corrupt.yaml'.*"), - "Threw with parsing error"); + t.true(err.message.startsWith( + `Failed to parse configuration for project application.a.id at ` + + `'ui5-test-corrupt.yaml'`), + `Should throw with parsing error.`); }); test("Merge keys (<<:) in ui5.yaml are resolved and not left as literal keys", async (t) => { @@ -511,9 +512,9 @@ test("Incorrect config path", async (t) => { const err = await t.throwsAsync(ui5Module.getSpecifications()); t.is(err.message, - "Failed to read configuration for module application.a.id: " + - "Could not find configuration file in module at path 'ui5-does-not-exist.yaml'", - "Threw with expected error message"); + `Failed to read configuration for module application.a.id: ` + + `Could not find configuration file in module at path 'ui5-does-not-exist.yaml'`, + "Should throw with parsing error."); }); test("Incorrect absolute config path", async (t) => { @@ -528,7 +529,7 @@ test("Incorrect absolute config path", async (t) => { t.true(err.message.startsWith( `Failed to read configuration for module application.a.id at '${configPath}'. Error:`), - "Threw with expected error message"); + "Should throw with parsing error."); }); test("Module without ui5.yaml is ignored", async (t) => { diff --git a/packages/project/test/lib/graph/Workspace.js b/packages/project/test/lib/graph/Workspace.js index 6e5b586e138..46c5ec13bdd 100644 --- a/packages/project/test/lib/graph/Workspace.js +++ b/packages/project/test/lib/graph/Workspace.js @@ -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" }, @@ -473,3 +473,819 @@ test("Missing parameters", (t) => { message: "Could not create Workspace: Missing or empty parameter 'configuration'" }, "Threw with expected error message"); }); + +test("Absolute resolution path", async (t) => { + const workspace = new t.context.Workspace({ + cwd: __dirname, + configuration: createWorkspaceConfig({ + dependencyManagement: { + resolutions: [{ + path: path.resolve(__dirname, "../../fixtures/library.d") + }] + } + }) + }); + + const err = await t.throwsAsync(async () => await workspace._getResolvedModules()); + t.true(err.message.startsWith(`Absolute paths are not allowed in workspace configurations of dependencies. `+ + `Found '${path.resolve(__dirname, "../../fixtures/library.d")}' in workspace '${workspace.getName()}'`), + "Starts 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"); + // Custom config: + t.is(projectNameMap.get("library.d")._configPath, + path.resolve(__dirname, "../../fixtures/library.d/custom-config-path.yaml")); + // Default config: + 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.true(err.message.includes("\"configPath\" is only supported for specVersion \"workspace/1.1\" and higher"), + "Starts with expected error message"); +}); + +test("[workspace/1.1] Absolute custom configPath", async (t) => { + const workspace = new t.context.Workspace({ + cwd: __dirname, + configuration: createWorkspaceConfig({ + specVersion: "workspace/1.1", + dependencyManagement: { + resolutions: [{ + path: "../../fixtures/library.d", + configPath: path.resolve(__dirname, "../../fixtures/library.d/ui5.yaml") // Absolute configPath + }] + } + }) + }); + + const err = await t.throwsAsync(async () => await workspace._getResolvedModules()); + t.true(err.message.startsWith(`Absolute config paths ` + + `are not allowed in workspace configurations of dependencies. ` + + `Found '${path.resolve(__dirname, "../../fixtures/library.d/ui5.yaml")}' `+ + `in workspace 'workspace-name'`), + "Starts with expected error message"); +}); + +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 not-existing configPath + }] + } + }) + }); + + const err = await t.throwsAsync(async () => await workspace._getResolvedModules()); + t.true(err.message.startsWith(`Failed to read configuration for module library.d at `+ + `'${path.resolve(__dirname, "../../fixtures/library.d/not-existing-config-path.yaml")}'. ` + + `Error: ENOENT: no such file or directory, `+ + `open '${path.resolve(__dirname, "../../fixtures/library.d/not-existing-config-path.yaml")}'`), + "Starts with expected error message"); +}); + +test("[workspace/1.1] Custom relative configPath which is outside of the module dir", async (t) => { + // This test covers a scenario where the custom relative configPath + // points to a location outside of the module directory. + // Config for library.d is located in library.e: + + const workspace = new t.context.Workspace({ + cwd: __dirname, + configuration: createWorkspaceConfig({ + specVersion: "workspace/1.1", + dependencyManagement: { + resolutions: [{ + path: "../../fixtures/library.d", + configPath: "../library.e/ui5-library.d-config.yaml" // Out-of-root path + }] + } + }) + }); + + const {projectNameMap} = await workspace._getResolvedModules(); + t.deepEqual(Array.from(projectNameMap.keys()).sort(), ["library.d"], "Correct project name key"); + // Returns absolute path of other library config: + t.is(projectNameMap.get("library.d")._configPath, + path.resolve(__dirname, "../../fixtures/library.e/ui5-library.d-config.yaml")); +}); + +// DEBUG: Case 1.1 +test("[workspace/1.1] No configPath", async (t) => { + const workspace = new t.context.Workspace({ + cwd: __dirname, + configuration: createWorkspaceConfig({ + specVersion: "workspace/1.1", + dependencyManagement: { + resolutions: [{ + path: "../../fixtures/collection.c", + }] + } + }) + }); + + const {projectNameMap} = await workspace._getResolvedModules(); + t.is(projectNameMap.get("library.a")._configPath, "ui5.yaml"); + t.is(projectNameMap.get("library.b")._configPath, "ui5.yaml"); + t.is(projectNameMap.get("library.c")._configPath, "ui5.yaml"); + t.is(projectNameMap.get("library.d")._configPath, "ui5.yaml"); +}); + +// DEBUG: Case 1.2 +test("[workspace/1.1] Custom configPath for all libs", async (t) => { + const workspace = new t.context.Workspace({ + cwd: __dirname, + configuration: createWorkspaceConfig({ + specVersion: "workspace/1.1", + dependencyManagement: { + resolutions: [{ + path: "../../fixtures/collection.c", + configPath: "ui5-custom.yaml" + }] + } + }) + }); + + const {projectNameMap} = await workspace._getResolvedModules(); + t.is(projectNameMap.get("library.a.custom")._configPath, + path.resolve(__dirname, `../../fixtures/collection.c/library.a/ui5-custom.yaml`)); + t.is(projectNameMap.get("library.b.custom")._configPath, + path.resolve(__dirname, `../../fixtures/collection.c/library.b/ui5-custom.yaml`)); + t.is(projectNameMap.get("library.c.custom")._configPath, + path.resolve(__dirname, `../../fixtures/collection.c/collection.a/library.c/ui5-custom.yaml`)); + t.is(projectNameMap.get("library.d.custom")._configPath, + path.resolve(__dirname, `../../fixtures/collection.c/collection.a/library.d/ui5-custom.yaml`)); +}); + +// DEBUG: Case 1.3 +test("[workspace/1.1] No configPath + Custom configPath for single lib", async (t) => { + const workspace = new t.context.Workspace({ + cwd: __dirname, + configuration: createWorkspaceConfig({ + specVersion: "workspace/1.1", + dependencyManagement: { + resolutions: [{ + path: "../../fixtures/collection.c", + }, + { + path: "../../fixtures/collection.c/library.a", + configPath: "ui5-custom.yaml" + }] + } + }) + }); + + const {projectNameMap} = await workspace._getResolvedModules(); + t.is(projectNameMap.get("library.a.custom")._configPath, + path.resolve(__dirname, `../../fixtures/collection.c/library.a/ui5-custom.yaml`)); + t.is(projectNameMap.get("library.b")._configPath, "ui5.yaml"); + t.is(projectNameMap.get("library.c")._configPath, "ui5.yaml"); + t.is(projectNameMap.get("library.d")._configPath, "ui5.yaml"); +}); + +// DEBUG: Case 1.4 +test("[workspace/1.1] Custom configPath for single lib + No configPath for all libs", async (t) => { + const workspace = new t.context.Workspace({ + cwd: __dirname, + configuration: createWorkspaceConfig({ + specVersion: "workspace/1.1", + dependencyManagement: { + resolutions: [{ + path: "../../fixtures/collection.c/library.a", + configPath: "ui5-custom.yaml" + }, + { + path: "../../fixtures/collection.c", + }] + } + }) + }); + + const {projectNameMap} = await workspace._getResolvedModules(); + // "Specific one wins": the specific library.a resolution beats the broader + // collection resolution regardless of order. + t.is(projectNameMap.get("library.a.custom")._configPath, + path.resolve(__dirname, "../../fixtures/collection.c/library.a/ui5-custom.yaml")); + t.is(projectNameMap.get("library.b")._configPath, "ui5.yaml"); + t.is(projectNameMap.get("library.c")._configPath, "ui5.yaml"); + t.is(projectNameMap.get("library.d")._configPath, "ui5.yaml"); +}); + +// DEBUG: Case 1.5 +test("[workspace/1.1] Custom configPath for all libs + No configPath for single lib", async (t) => { + const workspace = new t.context.Workspace({ + cwd: __dirname, + configuration: createWorkspaceConfig({ + specVersion: "workspace/1.1", + dependencyManagement: { + resolutions: [{ + path: "../../fixtures/collection.c", + configPath: "ui5-custom.yaml" + }, + { + path: "../../fixtures/collection.c/library.a", + }] + } + }) + }); + + const collectionPath = path.resolve(__dirname, "../../fixtures/collection.c"); + + const {projectNameMap} = await workspace._getResolvedModules(); + t.is(projectNameMap.get("library.a")._configPath, "ui5.yaml"); + t.is(projectNameMap.get("library.b.custom")._configPath, + path.join(collectionPath, "library.b", "ui5-custom.yaml")); + t.is(projectNameMap.get("library.c.custom")._configPath, + path.join(collectionPath, "collection.a", "library.c", "ui5-custom.yaml")); + t.is(projectNameMap.get("library.d.custom")._configPath, + path.join(collectionPath, "collection.a", "library.d", "ui5-custom.yaml")); +}); + +// DEBUG: Case 1.5.1 +test("[workspace/1.1] No configPath for single lib + Custom configPath for all libs", async (t) => { + const workspace = new t.context.Workspace({ + cwd: __dirname, + configuration: createWorkspaceConfig({ + specVersion: "workspace/1.1", + dependencyManagement: { + resolutions: [{ + path: "../../fixtures/collection.c/library.a", + }, + { + path: "../../fixtures/collection.c", + configPath: "ui5-custom.yaml" + }] + } + }) + }); + + const collectionPath = path.resolve(__dirname, "../../fixtures/collection.c"); + + const {projectNameMap} = await workspace._getResolvedModules(); + t.is(projectNameMap.get("library.a")._configPath, "ui5.yaml"); + t.is(projectNameMap.get("library.b.custom")._configPath, + path.join(collectionPath, "library.b", "ui5-custom.yaml")); + t.is(projectNameMap.get("library.c.custom")._configPath, + path.join(collectionPath, "collection.a", "library.c", "ui5-custom.yaml")); + t.is(projectNameMap.get("library.d.custom")._configPath, + path.join(collectionPath, "collection.a", "library.d", "ui5-custom.yaml")); +}); + +// DEBUG: Case 1.6 +test("No configPath for all libs + Custom configPaths for two libs", async (t) => { + const workspace = new t.context.Workspace({ + cwd: __dirname, + configuration: createWorkspaceConfig({ + specVersion: "workspace/1.1", + dependencyManagement: { + resolutions: [{ + path: "../../fixtures/collection.c", + }, + { + path: "../../fixtures/collection.c/library.a", + configPath: "ui5-custom.yaml" + }, + { + path: "../../fixtures/collection.c/library.b", + configPath: "ui5-another-custom.yaml" + }] + } + }) + }); + + const collectionPath = path.resolve(__dirname, "../../fixtures/collection.c"); + + const {projectNameMap} = await workspace._getResolvedModules(); + t.is(projectNameMap.get("library.a.custom")._configPath, + path.join(collectionPath, "library.a", "ui5-custom.yaml")); + t.is(projectNameMap.get("library.b.another.custom")._configPath, + path.join(collectionPath, "library.b", "ui5-another-custom.yaml")); + t.is(projectNameMap.get("library.c")._configPath, + "ui5.yaml"); + t.is(projectNameMap.get("library.d")._configPath, + "ui5.yaml"); +}); + +// DEBUG: Case 1.7 +test("[workspace/1.1] No configPath for all libs + Two custom configPaths for single lib", async (t) => { + const workspace = new t.context.Workspace({ + cwd: __dirname, + configuration: createWorkspaceConfig({ + specVersion: "workspace/1.1", + dependencyManagement: { + resolutions: [{ + path: "../../fixtures/collection.c", + }, + { + path: "../../fixtures/collection.c/library.a", + configPath: "ui5-custom.yaml" + }, + { + path: "../../fixtures/collection.c/library.a", // duplicate resolution + configPath: "ui5-another-custom.yaml" + }] + } + }) + }); + + const err = await t.throwsAsync(async () => await workspace._getResolvedModules()); + t.is(err.message, + `Multiple resolutions for the same library 'library.a' ` + + `(resolved to '${path.resolve("../../fixtures/collection.c/library.a")}') ` + + `in workspace '${workspace.getName()}' exist.`); +}); + +// DEBUG: Case 1.7.1 +test("[workspace/1.1] Two custom configPaths for single lib + No configPath for all libs (interleaved)", + async (t) => { + const workspace = new t.context.Workspace({ + cwd: __dirname, + configuration: createWorkspaceConfig({ + specVersion: "workspace/1.1", + dependencyManagement: { + resolutions: [{ + path: "../../fixtures/collection.c/library.a", + configPath: "ui5-custom.yaml" + }, + { + path: "../../fixtures/collection.c", + }, + { + path: "../../fixtures/collection.c/library.a", // duplicate resolution + configPath: "ui5-another-custom.yaml" + }] + } + }) + }); + + const err = await t.throwsAsync(async () => await workspace._getResolvedModules()); + t.is(err.message, + `Multiple resolutions for the same library 'library.a' ` + + `(resolved to '${path.resolve("../../fixtures/collection.c/library.a")}') ` + + `in workspace '${workspace.getName()}' exist.`); + } +); + +// DEBUG: Case 1.8 +test("[workspace/1.1] No configPath for all libs + Custom configPath for sub collection", async (t) => { + const workspace = new t.context.Workspace({ + cwd: __dirname, + configuration: createWorkspaceConfig({ + specVersion: "workspace/1.1", + dependencyManagement: { + resolutions: [{ + path: "../../fixtures/collection.c", + }, + { + path: "../../fixtures/collection.c/collection.a", // sub collection + configPath: "ui5-custom.yaml" + }] + } + }) + }); + + const collectionPath = path.resolve(__dirname, "../../fixtures/collection.c"); + + const {projectNameMap} = await workspace._getResolvedModules(); + t.is(projectNameMap.get("library.a")._configPath, + "ui5.yaml"); + t.is(projectNameMap.get("library.b")._configPath, + "ui5.yaml"); + t.is(projectNameMap.get("library.c.custom")._configPath, + path.resolve(collectionPath, "collection.a/library.c/ui5-custom.yaml")); + t.is(projectNameMap.get("library.d.custom")._configPath, + path.resolve(collectionPath, "collection.a/library.d/ui5-custom.yaml")); +}); + +// DEBUG: Case 1.8.1 +test("[workspace/1.1] Custom configPath for sub collection + No configPath for all libs", async (t) => { + const workspace = new t.context.Workspace({ + cwd: __dirname, + configuration: createWorkspaceConfig({ + specVersion: "workspace/1.1", + dependencyManagement: { + resolutions: [{ + path: "../../fixtures/collection.c/collection.a", // sub collection + configPath: "ui5-custom.yaml" + }, + { + path: "../../fixtures/collection.c", + }] + } + }) + }); + + const collectionPath = path.resolve(__dirname, "../../fixtures/collection.c"); + + // "Specific one wins": the sub collection resolution beats the broader collection + // resolution regardless of order (mirror of Case 1.8 with reversed order). + const {projectNameMap} = await workspace._getResolvedModules(); + t.is(projectNameMap.get("library.a")._configPath, + "ui5.yaml"); + t.is(projectNameMap.get("library.b")._configPath, + "ui5.yaml"); + t.is(projectNameMap.get("library.c.custom")._configPath, + path.resolve(collectionPath, "collection.a/library.c/ui5-custom.yaml")); + t.is(projectNameMap.get("library.d.custom")._configPath, + path.resolve(collectionPath, "collection.a/library.d/ui5-custom.yaml")); +}); + +// DEBUG: Case 1.9 +test("[workspace/1.1] No configPath for all libs + Custom configPaths for sub collection & single lib", async (t) => { + const workspace = new t.context.Workspace({ + cwd: __dirname, + configuration: createWorkspaceConfig({ + specVersion: "workspace/1.1", + dependencyManagement: { + resolutions: [{ + path: "../../fixtures/collection.c", + }, + { + path: "../../fixtures/collection.c/collection.a", // sub collection + configPath: "ui5-custom.yaml" + }, + { + path: "../../fixtures/collection.c/collection.a/library.c", // lib in sub collection + configPath: "ui5-another-custom.yaml" + }] + } + }) + }); + + const collectionPath = path.resolve(__dirname, "../../fixtures/collection.c"); + + const {projectNameMap} = await workspace._getResolvedModules(); + t.is(projectNameMap.get("library.a")._configPath, + "ui5.yaml"); + t.is(projectNameMap.get("library.b")._configPath, + "ui5.yaml"); + t.is(projectNameMap.get("library.c.another.custom")._configPath, + path.resolve(collectionPath, "collection.a/library.c/ui5-another-custom.yaml")); + t.is(projectNameMap.get("library.d.custom")._configPath, + path.resolve(collectionPath, "collection.a/library.d/ui5-custom.yaml")); +}); + +// DEBUG: Case 1.9.1 +test("[workspace/1.1] Custom configPaths for sub collection & single lib + No configPath for all libs " + + "(interleaved)", async (t) => { + const workspace = new t.context.Workspace({ + cwd: __dirname, + configuration: createWorkspaceConfig({ + specVersion: "workspace/1.1", + dependencyManagement: { + resolutions: [{ + path: "../../fixtures/collection.c/collection.a/library.c", // lib in sub collection + configPath: "ui5-another-custom.yaml" + }, + { + path: "../../fixtures/collection.c", + }, + { + path: "../../fixtures/collection.c/collection.a", // sub collection + configPath: "ui5-custom.yaml" + }] + } + }) + }); + + const collectionPath = path.resolve(__dirname, "../../fixtures/collection.c"); + + const {projectNameMap} = await workspace._getResolvedModules(); + t.is(projectNameMap.get("library.a")._configPath, + "ui5.yaml"); + t.is(projectNameMap.get("library.b")._configPath, + "ui5.yaml"); + t.is(projectNameMap.get("library.c.another.custom")._configPath, + path.resolve(collectionPath, "collection.a/library.c/ui5-another-custom.yaml")); + t.is(projectNameMap.get("library.d.custom")._configPath, + path.resolve(collectionPath, "collection.a/library.d/ui5-custom.yaml")); +}); + +// DEBUG: Case 1.10 (ordering isolation: two direct resolutions, same lib) +test("[workspace/1.1] Two custom configPaths for the same single lib -> error on duplicate", async (t) => { + const workspace = new t.context.Workspace({ + cwd: __dirname, + configuration: createWorkspaceConfig({ + specVersion: "workspace/1.1", + dependencyManagement: { + resolutions: [{ + path: "../../fixtures/collection.c/library.a", + configPath: "ui5-custom.yaml" + }, + { + path: "../../fixtures/collection.c/library.a", // duplicate resolution + configPath: "ui5-another-custom.yaml" + }] + } + }) + }); + + const err = await t.throwsAsync(async () => await workspace._getResolvedModules()); + t.is(err.message, + `Multiple resolutions for the same library 'library.a' ` + + `(resolved to '${path.resolve("../../fixtures/collection.c/library.a")}') ` + + `in workspace '${workspace.getName()}' exist.`); +}); + +// DEBUG: Case 1.11 +test("[workspace/1.1] Duplicate library via different path strings (no configPath)", async (t) => { + const workspace = new t.context.Workspace({ + cwd: __dirname, + configuration: createWorkspaceConfig({ + specVersion: "workspace/1.1", + dependencyManagement: { + resolutions: [{ + path: "../../fixtures/collection.c/library.a" + }, + { + // Different path string, same resolved directory + path: "../../fixtures/collection.c/../collection.c/library.a" + }] + } + }) + }); + + const err = await t.throwsAsync(async () => await workspace._getResolvedModules()); + t.is(err.message, + `Multiple resolutions for the same library 'library.a' ` + + `(resolved to '${path.resolve("../../fixtures/collection.c/library.a")}') ` + + `in workspace '${workspace.getName()}' exist.`); +}); + +// DEBUG: Case 1.11.1 +test("[workspace/1.1] Duplicate library via different path strings (with configPath)", async (t) => { + const workspace = new t.context.Workspace({ + cwd: __dirname, + configuration: createWorkspaceConfig({ + specVersion: "workspace/1.1", + dependencyManagement: { + resolutions: [{ + path: "../../fixtures/collection.c/library.a", + configPath: "ui5-custom.yaml" + }, + { + // Different path string, same resolved directory + path: "../../fixtures/collection.c/../collection.c/library.a", + configPath: "ui5-another-custom.yaml" + }] + } + }) + }); + + const err = await t.throwsAsync(async () => await workspace._getResolvedModules()); + t.is(err.message, + `Multiple resolutions for the same library 'library.a' ` + + `(resolved to '${path.resolve("../../fixtures/collection.c/library.a")}') ` + + `in workspace '${workspace.getName()}' exist.`); +}); + +// DEBUG: Case 1.11.2 +test("[workspace/1.1] Duplicate library name via different directories", async (t) => { + const workspace = new t.context.Workspace({ + cwd: __dirname, + configuration: createWorkspaceConfig({ + specVersion: "workspace/1.1", + dependencyManagement: { + resolutions: [{ + path: "../../fixtures/collection.c/library.a", + configPath: "ui5-custom.yaml" + }, + { + // Different directory, but same library (directory) name 'library.a' + path: "../../fixtures/collection/library.a" + }] + } + }) + }); + + const {projectNameMap} = await workspace._getResolvedModules(); + t.is(projectNameMap.get("library.a.custom")._configPath, + path.resolve(__dirname, "../../fixtures/collection.c/library.a/ui5-custom.yaml")); + t.is(projectNameMap.get("library.a")._configPath, "ui5.yaml"); +}); + +// DEBUG: Case 2.2 +test("[workspace/1.1] Custom configPath for all libs -> File not existing for single lib", async (t) => { + const workspace = new t.context.Workspace({ + cwd: __dirname, + configuration: createWorkspaceConfig({ + specVersion: "workspace/1.1", + dependencyManagement: { + resolutions: [{ + path: "../../fixtures/collection.c.noCustomConfigForLibA", + configPath: "ui5-custom.yaml" // not existing + }] + } + }) + }); + + const collectionPath = path.resolve(__dirname, "../../fixtures/collection.c.noCustomConfigForLibA"); + const configPath = path.join(collectionPath, "library.a", "ui5-custom.yaml"); + const err = await t.throwsAsync(async () => await workspace._getResolvedModules()); + t.true(err.message.startsWith(`Failed to read configuration for module library.a at `+ + `'${configPath}'. ` + + `Error: ENOENT: no such file or directory, `+ + `open '${configPath}'`), + "Starts with expected error message"); +}); + +// DEBUG: Case 2.3 +test("[workspace/1.1] Custom configPath for single lib -> File not existing for single lib", async (t) => { + const workspace = new t.context.Workspace({ + cwd: __dirname, + configuration: createWorkspaceConfig({ + specVersion: "workspace/1.1", + dependencyManagement: { + resolutions: [{ + path: "../../fixtures/collection.c.noCustomConfigForLibA", + }, + { + path: "../../fixtures/collection.c.noCustomConfigForLibA/library.a", + configPath: "ui5-custom.yaml" // not existing + } + ] + } + }) + }); + + const collectionPath = path.resolve(__dirname, "../../fixtures/collection.c.noCustomConfigForLibA"); + const configPath = path.join(collectionPath, "library.a", "ui5-custom.yaml"); + const err = await t.throwsAsync(async () => await workspace._getResolvedModules()); + t.true(err.message.startsWith(`Failed to read configuration for module library.a at `+ + `'${configPath}'. ` + + `Error: ENOENT: no such file or directory, `+ + `open '${configPath}'`), + "Starts with expected error message"); +}); + +// DEBUG: Case 2.4 +test("[workspace/1.1] Not existing configPath for single lib overwritten by No configPath for all libs", + async (t) => { + const workspace = new t.context.Workspace({ + cwd: __dirname, + configuration: createWorkspaceConfig({ + specVersion: "workspace/1.1", + dependencyManagement: { + resolutions: [ + { + path: "../../fixtures/collection.c.noCustomConfigForLibA/library.a", + configPath: "ui5-custom.yaml" // not existing + }, + { + path: "../../fixtures/collection.c.noCustomConfigForLibA", + }, + ] + } + }) + }); + + const collectionPath = path.resolve(__dirname, "../../fixtures/collection.c.noCustomConfigForLibA"); + const configPath = path.join(collectionPath, "library.a", "ui5-custom.yaml"); + // "Specific one wins": the specific library.a + ui5-custom.yaml resolution beats the + // broader collection resolution regardless of order, so the missing file throws. + const err = await t.throwsAsync(async () => await workspace._getResolvedModules()); + t.true(err.message.startsWith(`Failed to read configuration for module library.a at `+ + `'${configPath}'. ` + + `Error: ENOENT: no such file or directory, `+ + `open '${configPath}'`), + "Starts with expected error message"); + } +); + +// DEBUG: Case 2.5 +test("[workspace/1.1] Not existing configPath for single lib overwritten by No configPath for the same lib", + async (t) => { + const workspace = new t.context.Workspace({ + cwd: __dirname, + configuration: createWorkspaceConfig({ + specVersion: "workspace/1.1", + dependencyManagement: { + resolutions: [{ + path: "../../fixtures/collection.c.noCustomConfigForLibA", + configPath: "ui5-custom.yaml" // not existing for library.a + }, + { + path: "../../fixtures/collection.c.noCustomConfigForLibA/library.a", + }] + } + }) + }); + + const collectionPath = path.resolve(__dirname, "../../fixtures/collection.c.noCustomConfigForLibA"); + + const {projectNameMap} = await workspace._getResolvedModules(); + t.is(projectNameMap.get("library.a")._configPath, "ui5.yaml"); + t.is(projectNameMap.get("library.b.custom")._configPath, + path.join(collectionPath, "library.b", "ui5-custom.yaml")); + t.is(projectNameMap.get("library.c.custom")._configPath, + path.join(collectionPath, "collection.a", "library.c", "ui5-custom.yaml")); + t.is(projectNameMap.get("library.d.custom")._configPath, + path.join(collectionPath, "collection.a", "library.d", "ui5-custom.yaml")); + } +); + +// DEBUG: Case 2.6 +test("[workspace/1.1] Duplicate resolutions for single lib (with missing config) -> error on duplicate", + async (t) => { + const workspace = new t.context.Workspace({ + cwd: __dirname, + configuration: createWorkspaceConfig({ + specVersion: "workspace/1.1", + dependencyManagement: { + resolutions: [{ + path: "../../fixtures/collection.c.noCustomConfigForLibA", + }, + { + path: "../../fixtures/collection.c.noCustomConfigForLibA/library.a", + configPath: "ui5-custom.yaml" // not existing + }, + { + path: "../../fixtures/collection.c.noCustomConfigForLibA/library.a", // duplicate resolution + configPath: "ui5-another-custom.yaml" + }] + } + }) + }); + + // The duplicate is detected before any config file is read, so the missing + // 'ui5-custom.yaml' never causes an ENOENT; the duplicate error wins. + const err = await t.throwsAsync(async () => await workspace._getResolvedModules()); + t.is(err.message, + `Multiple resolutions for the same library 'library.a' ` + + `(resolved to '${path.resolve("../../fixtures/collection.c.noCustomConfigForLibA/library.a")}') ` + + `in workspace '${workspace.getName()}' exist.`); + } +); + +// DEBUG: Case 2.6.1 +test("[workspace/1.1] Duplicate resolutions for single lib (missing config last) -> error on duplicate", + async (t) => { + const workspace = new t.context.Workspace({ + cwd: __dirname, + configuration: createWorkspaceConfig({ + specVersion: "workspace/1.1", + dependencyManagement: { + resolutions: [{ + path: "../../fixtures/collection.c.noCustomConfigForLibA", + }, + { + path: "../../fixtures/collection.c.noCustomConfigForLibA/library.a", + configPath: "ui5-another-custom.yaml" + }, + { + path: "../../fixtures/collection.c.noCustomConfigForLibA/library.a", // duplicate resolution + configPath: "ui5-custom.yaml" // not existing + }] + } + }) + }); + + // The duplicate is detected before any config file is read, so the missing + // 'ui5-custom.yaml' never causes an ENOENT; the duplicate error wins. + const err = await t.throwsAsync(async () => await workspace._getResolvedModules()); + t.is(err.message, + `Multiple resolutions for the same library 'library.a' ` + + `(resolved to '${path.resolve("../../fixtures/collection.c.noCustomConfigForLibA/library.a")}') ` + + `in workspace '${workspace.getName()}' exist.`); + } +); + + diff --git a/packages/project/test/lib/validation/schema/ui5-workspace.js b/packages/project/test/lib/validation/schema/ui5-workspace.js index 232f5965991..60cd0a80343 100644 --- a/packages/project/test/lib/validation/schema/ui5-workspace.js +++ b/packages/project/test/lib/validation/schema/ui5-workspace.js @@ -79,7 +79,7 @@ test("Empty config", async (t) => { keyword: "errorMessage", message: `Unsupported "specVersion" Your UI5 CLI installation might be outdated. -Supported specification versions: "workspace/1.0" +Supported specification versions: "workspace/1.0", "workspace/1.1". For details, see: https://ui5.github.io/cli/stable/pages/Workspace/#workspace-specification-versions`, params: { errors: [ @@ -89,7 +89,7 @@ For details, see: https://ui5.github.io/cli/stable/pages/Workspace/#workspace-sp message: "must be equal to one of the allowed values", params: { - allowedValues: ["workspace/1.0"], + allowedValues: ["workspace/1.1", "workspace/1.0"], }, }, ], @@ -280,7 +280,7 @@ test("Invalid fields", async (t) => { keyword: "errorMessage", message: `Unsupported "specVersion" Your UI5 CLI installation might be outdated. -Supported specification versions: "workspace/1.0" +Supported specification versions: "workspace/1.0", "workspace/1.1". For details, see: https://ui5.github.io/cli/stable/pages/Workspace/#workspace-specification-versions`, params: { errors: [ @@ -290,7 +290,7 @@ For details, see: https://ui5.github.io/cli/stable/pages/Workspace/#workspace-sp message: "must be equal to one of the allowed values", params: { - allowedValues: ["workspace/1.0"], + allowedValues: ["workspace/1.1", "workspace/1.0"], }, }, ], @@ -341,7 +341,7 @@ test("Invalid types", async (t) => { keyword: "errorMessage", message: `Unsupported "specVersion" Your UI5 CLI installation might be outdated. -Supported specification versions: "workspace/1.0" +Supported specification versions: "workspace/1.0", "workspace/1.1". For details, see: https://ui5.github.io/cli/stable/pages/Workspace/#workspace-specification-versions`, params: { errors: [ @@ -351,7 +351,7 @@ For details, see: https://ui5.github.io/cli/stable/pages/Workspace/#workspace-sp message: "must be equal to one of the allowed values", params: { - allowedValues: ["workspace/1.0"], + allowedValues: ["workspace/1.1", "workspace/1.0"], }, }, ], @@ -456,3 +456,54 @@ test("Invalid dependencyManagement", async (t) => { ] ); }); + +test("Invalid dependencyManagement: configPath not allowed for workspace/1.0", async (t) => { + await assertValidation( + t, + { + specVersion: "workspace/1.0", + metadata: { + name: "test-spec-name", + }, + dependencyManagement: { + resolutions: [ + { + path: "../my.library", + configPath: "config/ui5.yaml" + }], + }, + }, + [ + { + instancePath: "/dependencyManagement/resolutions/0", + keyword: "errorMessage", + message: "\"configPath\" is only supported for specVersion \"workspace/1.1\" and higher", + params: { + errors: [ + { + instancePath: "/dependencyManagement/resolutions/0", + keyword: "not", + message: "must NOT be valid", + params: {}, + }, + ], + }, + }, + ] + ); +}); + +test("Valid dependencyManagement: configPath allowed for workspace/1.1", async (t) => { + await assertValidation( + t, + { + specVersion: "workspace/1.1", + metadata: { + name: "test-spec-name", + }, + dependencyManagement: { + resolutions: [{path: "../my.library", configPath: "config/ui5.yaml"}], + }, + } + ); +});