Commit 6b7ca4d
Fix modifiedApps incremental builds for projects with external appFolders (#2194)
## Summary
When `incrementalBuilds.mode` is set to `modifiedApps` and a project
references app folders **outside** its own directory via `../` paths,
unmodified apps are never downloaded from the baseline workflow run.
Instead, every app is recompiled on every PR — even when only a single
file changed.
## The bug
`Get-UnmodifiedAppsFromBaselineWorkflowRun` needs to match entries from
`$settings.appFolders` (project-relative paths) against `$skipFolders`
(repo-relative paths). The old code assumed all resolved folder paths
start with `.\` and used `SubString(2)` to strip that prefix:
```powershell
# Old code
$downloadAppFolders = @($settings.appFolders | Where-Object {
$skipFolders -contains "$projectWithSeperator$($_.SubString(2))"
})
```
This works when apps live **inside** the project folder (paths like
`.\app`), but breaks when apps live **outside** (paths like
`..\..\..\src\Apps\SomeApp\App`).
### Toy example to illustrate
Consider a repo layout where a project at `build/projects/MyProject`
references apps at `src/`:
```
repo/
src/
Apps/
Invoicing/App/app.json ← modified
Reporting/App/app.json ← unmodified
build/
projects/
MyProject/
.AL-Go/settings.json ← appFolders: ["../../../src/Apps/*/App"]
```
After `ResolveProjectFolders` resolves the glob from the project
directory, `$settings.appFolders` contains:
```
..\..\..\src\Apps\Invoicing\App
..\..\..\src\Apps\Reporting\App
```
Meanwhile, `$skipFolders` (from `GetFoldersFromAllProjects`, resolved
from the repo root) contains:
```
src\Apps\Reporting\App
```
The old matching logic did:
| Step | Value |
|---|---|
| `$_.SubString(2)` on `..\..\..\src\Apps\Reporting\App` |
`\..\..\src\Apps\Reporting\App` |
| Prepend project separator |
`build\projects\MyProject\..\..\src\Apps\Reporting\App` |
| Compare with `$skipFolders` | `src\Apps\Reporting\App` |
| **Match?** | **No — string comparison, not path resolution** |
The result: `$downloadAppFolders` is always empty → no artifacts
downloaded from baseline → **all apps recompiled**.
For comparison, the standard layout (apps inside the project) works
because paths start with `.\`:
| Step | Value |
|---|---|
| `$_.SubString(2)` on `.\app` | `app` |
| Prepend project separator (empty for root project) | `app` |
| Compare with `$skipFolders` | `app` |
| **Match?** | **Yes** |
## The fix
Replace the `SubString(2)` hack with proper path resolution. A new
helper `ConvertTo-RepoRelativePath` resolves each project-relative
folder to an absolute path via `Join-Path -Resolve`, then strips the
base folder prefix to produce a clean repo-relative path that matches
`$skipFolders` exactly:
```powershell
# New code
function ConvertTo-RepoRelativePath {
param([string] $folder, [string] $projectPath, [string] $baseFolder)
$fullPath = Join-Path $projectPath $folder -Resolve -ErrorAction SilentlyContinue
if (-not $fullPath) { return $null }
$normalizedBase = $baseFolder.TrimEnd([IO.Path]::DirectorySeparatorChar) + [IO.Path]::DirectorySeparatorChar
if ($fullPath.StartsWith($normalizedBase, [StringComparison]::OrdinalIgnoreCase)) {
return $fullPath.Substring($normalizedBase.Length)
}
return $null
}
```
This works for both layouts:
| Layout | `$settings.appFolders` entry | Resolved absolute |
Repo-relative | Matches `$skipFolders`? |
|---|---|---|---|---|
| Nested project | `..\..\..\src\Apps\Reporting\App` |
`D:\a\repo\src\Apps\Reporting\App` | `src\Apps\Reporting\App` | Yes |
| Standard | `.\app` | `D:\a\repo\app` | `app` | Yes |
## Tests
Two new Pester tests added to `DetermineProjectsToBuild.Test.ps1`:
1. **Nested project with `../` paths** — creates a repo layout where
apps are outside the project folder. **Fails without the fix**
(`Download appFolders: - None`), **passes with the fix**.
2. **Standard layout** — apps inside the project folder. **Passes both
before and after** (backwards compatibility).
## Test plan
- [x] New test fails on old code, passes on new code
- [x] All 28 existing tests continue to pass
- [ ] Validate on a real BCApps PR build
---------
Co-authored-by: Magnus Hartvig Grønbech <[email protected]>
Co-authored-by: Claude Opus 4.6 (1M context) <[email protected]>
Co-authored-by: Maria Zhelezova <[email protected]>
Co-authored-by: Alexander Holstrup <[email protected]>
Co-authored-by: aholstrup1 <[email protected]>1 parent 040d14c commit 6b7ca4d
3 files changed
Lines changed: 230 additions & 9 deletions
File tree
- Actions/DetermineProjectsToBuild
- Tests
Lines changed: 38 additions & 9 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
387 | 387 | | |
388 | 388 | | |
389 | 389 | | |
| 390 | + | |
| 391 | + | |
| 392 | + | |
| 393 | + | |
| 394 | + | |
| 395 | + | |
| 396 | + | |
| 397 | + | |
| 398 | + | |
| 399 | + | |
| 400 | + | |
| 401 | + | |
| 402 | + | |
| 403 | + | |
| 404 | + | |
| 405 | + | |
| 406 | + | |
| 407 | + | |
| 408 | + | |
| 409 | + | |
| 410 | + | |
| 411 | + | |
| 412 | + | |
| 413 | + | |
| 414 | + | |
| 415 | + | |
| 416 | + | |
| 417 | + | |
| 418 | + | |
| 419 | + | |
| 420 | + | |
| 421 | + | |
| 422 | + | |
| 423 | + | |
| 424 | + | |
390 | 425 | | |
391 | 426 | | |
392 | 427 | | |
| |||
430 | 465 | | |
431 | 466 | | |
432 | 467 | | |
433 | | - | |
434 | | - | |
435 | | - | |
436 | | - | |
437 | | - | |
438 | | - | |
439 | | - | |
440 | | - | |
441 | | - | |
| 468 | + | |
| 469 | + | |
| 470 | + | |
442 | 471 | | |
443 | 472 | | |
444 | 473 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
| 3 | + | |
3 | 4 | | |
4 | 5 | | |
5 | 6 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1214 | 1214 | | |
1215 | 1215 | | |
1216 | 1216 | | |
| 1217 | + | |
| 1218 | + | |
| 1219 | + | |
| 1220 | + | |
| 1221 | + | |
| 1222 | + | |
| 1223 | + | |
| 1224 | + | |
| 1225 | + | |
| 1226 | + | |
| 1227 | + | |
| 1228 | + | |
| 1229 | + | |
| 1230 | + | |
| 1231 | + | |
| 1232 | + | |
| 1233 | + | |
| 1234 | + | |
| 1235 | + | |
| 1236 | + | |
| 1237 | + | |
| 1238 | + | |
| 1239 | + | |
| 1240 | + | |
| 1241 | + | |
| 1242 | + | |
| 1243 | + | |
| 1244 | + | |
| 1245 | + | |
| 1246 | + | |
| 1247 | + | |
| 1248 | + | |
| 1249 | + | |
| 1250 | + | |
| 1251 | + | |
| 1252 | + | |
| 1253 | + | |
| 1254 | + | |
| 1255 | + | |
| 1256 | + | |
| 1257 | + | |
| 1258 | + | |
| 1259 | + | |
| 1260 | + | |
| 1261 | + | |
| 1262 | + | |
| 1263 | + | |
| 1264 | + | |
| 1265 | + | |
| 1266 | + | |
| 1267 | + | |
| 1268 | + | |
| 1269 | + | |
| 1270 | + | |
| 1271 | + | |
| 1272 | + | |
| 1273 | + | |
| 1274 | + | |
| 1275 | + | |
| 1276 | + | |
| 1277 | + | |
| 1278 | + | |
| 1279 | + | |
| 1280 | + | |
| 1281 | + | |
| 1282 | + | |
| 1283 | + | |
| 1284 | + | |
| 1285 | + | |
| 1286 | + | |
| 1287 | + | |
| 1288 | + | |
| 1289 | + | |
| 1290 | + | |
| 1291 | + | |
| 1292 | + | |
| 1293 | + | |
| 1294 | + | |
| 1295 | + | |
| 1296 | + | |
| 1297 | + | |
| 1298 | + | |
| 1299 | + | |
| 1300 | + | |
| 1301 | + | |
| 1302 | + | |
| 1303 | + | |
| 1304 | + | |
| 1305 | + | |
| 1306 | + | |
| 1307 | + | |
| 1308 | + | |
| 1309 | + | |
| 1310 | + | |
| 1311 | + | |
| 1312 | + | |
| 1313 | + | |
| 1314 | + | |
| 1315 | + | |
| 1316 | + | |
| 1317 | + | |
| 1318 | + | |
| 1319 | + | |
| 1320 | + | |
| 1321 | + | |
| 1322 | + | |
| 1323 | + | |
| 1324 | + | |
| 1325 | + | |
| 1326 | + | |
| 1327 | + | |
| 1328 | + | |
| 1329 | + | |
| 1330 | + | |
| 1331 | + | |
| 1332 | + | |
| 1333 | + | |
| 1334 | + | |
| 1335 | + | |
| 1336 | + | |
| 1337 | + | |
| 1338 | + | |
| 1339 | + | |
| 1340 | + | |
| 1341 | + | |
| 1342 | + | |
| 1343 | + | |
| 1344 | + | |
| 1345 | + | |
| 1346 | + | |
| 1347 | + | |
| 1348 | + | |
| 1349 | + | |
| 1350 | + | |
| 1351 | + | |
| 1352 | + | |
| 1353 | + | |
| 1354 | + | |
| 1355 | + | |
| 1356 | + | |
| 1357 | + | |
| 1358 | + | |
| 1359 | + | |
| 1360 | + | |
| 1361 | + | |
| 1362 | + | |
| 1363 | + | |
| 1364 | + | |
| 1365 | + | |
| 1366 | + | |
| 1367 | + | |
| 1368 | + | |
| 1369 | + | |
| 1370 | + | |
| 1371 | + | |
| 1372 | + | |
| 1373 | + | |
| 1374 | + | |
| 1375 | + | |
| 1376 | + | |
| 1377 | + | |
| 1378 | + | |
| 1379 | + | |
| 1380 | + | |
| 1381 | + | |
| 1382 | + | |
| 1383 | + | |
| 1384 | + | |
| 1385 | + | |
| 1386 | + | |
| 1387 | + | |
| 1388 | + | |
| 1389 | + | |
| 1390 | + | |
| 1391 | + | |
| 1392 | + | |
| 1393 | + | |
| 1394 | + | |
| 1395 | + | |
| 1396 | + | |
| 1397 | + | |
| 1398 | + | |
| 1399 | + | |
| 1400 | + | |
| 1401 | + | |
| 1402 | + | |
| 1403 | + | |
| 1404 | + | |
| 1405 | + | |
| 1406 | + | |
| 1407 | + | |
0 commit comments