Improve calculation of buildPath include and exclude paths#469
Improve calculation of buildPath include and exclude paths#469PeterJudgeZA wants to merge 1 commit into
Conversation
109837d to
c8caa05
Compare
There was a problem hiding this comment.
Pull request overview
Fixes test discovery issues in multi-project workspaces (issue #448) by improving how buildPath include/exclude globs from openedge-project.json are converted into VSCode RelativePatterns, and adds debug logging/tests to validate matching behavior.
Changes:
- Adjust buildPath include/exclude pattern construction to use
workspace.asRelativePath(..., false)for better multi-root workspace compatibility. - Add a new parsing test + fixture for comma-delimited buildPath includes/excludes.
- Enhance debug logging when a file does not match any include/exclude pattern.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 6 comments.
| File | Description |
|---|---|
| test_projects/BuildPathParser/openedge-project.test.json | Adds a minimal openedge-project fixture with buildPath includes/excludes for testing. |
| test/parse/BuildPathParser.test.ts | Adds unit test coverage for getBuildPathPatterns() output patterns. |
| src/parse/OpenedgeProjectParser.ts | Updates logic that converts buildPath includes/excludes into RelativePatterns. |
| src/extension.ts | Adds extra debug logging for non-matching glob patterns during file inclusion checks. |
| const lines = FileUtils.readLinesFromFileSync(FileUtils.toUri(buildPath.includesFile)) | ||
| includes.push(...lines.map(p => new RelativePattern(workspaceFolder, workspace.asRelativePath(buildPath.path) + '/' + p))) | ||
| includes.push(...lines.map(p => new RelativePattern(workspaceFolder, workspace.asRelativePath(`${buildPath.pathUri.fsPath}/${p}`, false)))) | ||
| } else { | ||
| for (const p of buildPath.includes?.split(',') ?? []) { | ||
| includes.push(new RelativePattern(workspaceFolder, workspace.asRelativePath(buildPath.pathUri) + '/' + p)) | ||
| includes.push(new RelativePattern(workspaceFolder, workspace.asRelativePath(`${buildPath.pathUri.fsPath}/${p}`, false))) |
There was a problem hiding this comment.
Patterns are built via ${buildPath.pathUri.fsPath}/${p}. Because fsPath uses OS-specific separators (backslashes on Windows), concatenating with '/' can yield mixed separators and broken glob matching. Prefer Uri.joinPath(buildPath.pathUri, p.trim()) (then workspace.asRelativePath(..., false)) and skip empty entries.
| const lines = FileUtils.readLinesFromFileSync(FileUtils.toUri(buildPath.excludesFile)) | ||
| excludes.push(...lines.map(p => new RelativePattern(workspaceFolder, workspace.asRelativePath(buildPath.path) + '/' + p))) | ||
| excludes.push(...lines.map(p => new RelativePattern(workspaceFolder, workspace.asRelativePath(`${buildPath.pathUri.fsPath}/${p}`, false)))) | ||
| } else { | ||
| for (const p of buildPath.excludes?.split(',') ?? []) { | ||
| excludes.push(new RelativePattern(workspaceFolder, workspace.asRelativePath(buildPath.pathUri) + '/' + p)) | ||
| excludes.push(new RelativePattern(workspaceFolder, workspace.asRelativePath(`${buildPath.pathUri.fsPath}/${p}`, false))) |
There was a problem hiding this comment.
Excludes patterns are also built using ${buildPath.pathUri.fsPath}/${p}, which can produce mixed separators on Windows and break minimatch. Use Uri.joinPath(buildPath.pathUri, p.trim()) (plus workspace.asRelativePath(..., false)) and filter out blank patterns before creating RelativePatterns.
| @@ -0,0 +1,41 @@ | |||
| import { getDLC, getOEVersion, getOpenEdgeProfileConfig, getBuildPathPatterns } from 'parse/OpenedgeProjectParser' | |||
There was a problem hiding this comment.
Unused imports (getDLC, getOEVersion) add noise and can trigger lint failures when running npm run lint. Remove them or use them in the test.
| import { getDLC, getOEVersion, getOpenEdgeProfileConfig, getBuildPathPatterns } from 'parse/OpenedgeProjectParser' | |
| import { getOpenEdgeProfileConfig, getBuildPathPatterns } from 'parse/OpenedgeProjectParser' |
| suiteSetup('suiteSetup', async () => { | ||
| await suiteSetupCommon() | ||
| }) | ||
|
|
There was a problem hiding this comment.
This suite calls suiteSetupCommon(), which starts a log group, but there is no corresponding suiteTeardown to call log.group.end(). Add a suiteTeardown (as done in other parse tests) to avoid leaking log groups across suites in CI output.
| suiteTeardown('suiteTeardown', () => { | |
| log.group.end() | |
| }) |
| for (const b of config.buildPath.filter(b => b.type == 'source') ?? []) { | ||
| const buildPathPatterns = getBuildPathPatterns(workspaceFolder, b) |
There was a problem hiding this comment.
workspaceFolder can be undefined (other parse tests guard this). Add an explicit check before passing it into getBuildPathPatterns(...) so test failures are clearer and don't surface as a runtime TypeError.
| let allPatterns = '' | ||
| for (const pattern of patterns.map(pattern => pattern.pattern)) { | ||
| if (minimatch(relativePath, pattern, { magicalBraces: true })) { | ||
| log.debug('file ' + relativePath + ' matches \'' + pattern + '\'') | ||
| return true | ||
| } else { | ||
| allPatterns += pattern + ',' | ||
| } | ||
| } | ||
| if (allPatterns.length > 0) { | ||
| log.debug('file ' + relativePath + ' does not match \'' + allPatterns.replace(/,$/, "") + '\'') |
There was a problem hiding this comment.
doesFileMatch now builds allPatterns via string concatenation inside the loop and then trims a trailing comma. Since this is called frequently during workspace scans, consider collecting patterns and logging patterns.map(p => p.pattern).join(',') once after the loop when no match is found.
| let allPatterns = '' | |
| for (const pattern of patterns.map(pattern => pattern.pattern)) { | |
| if (minimatch(relativePath, pattern, { magicalBraces: true })) { | |
| log.debug('file ' + relativePath + ' matches \'' + pattern + '\'') | |
| return true | |
| } else { | |
| allPatterns += pattern + ',' | |
| } | |
| } | |
| if (allPatterns.length > 0) { | |
| log.debug('file ' + relativePath + ' does not match \'' + allPatterns.replace(/,$/, "") + '\'') | |
| const patternStrings = patterns.map(pattern => pattern.pattern) | |
| for (const pattern of patternStrings) { | |
| if (minimatch(relativePath, pattern, { magicalBraces: true })) { | |
| log.debug('file ' + relativePath + ' matches \'' + pattern + '\'') | |
| return true | |
| } | |
| } | |
| if (patternStrings.length > 0) { | |
| log.debug('file ' + relativePath + ' does not match \'' + patternStrings.join(',') + '\'') |
175f844 to
60cca31
Compare
kenherring
left a comment
There was a problem hiding this comment.
@PeterJudgeZA sorry for all the noise on this PR. This repo hasn't had many forked PRs so figuring out how to get the builds right was a little messy.
There are two things needed to get this PR merged:
- Code coverage
- Use a map or array or similar data structure rather than a comma delimited list
Concept looks good to me. Really appreciate the pull request and sorry again for all the noise I made trying to get actions to cooperate.
|


Per issue #448