Skip to content

Improve calculation of buildPath include and exclude paths#469

Open
PeterJudgeZA wants to merge 1 commit into
kenherring:mainfrom
PeterJudgeZA:issue448
Open

Improve calculation of buildPath include and exclude paths#469
PeterJudgeZA wants to merge 1 commit into
kenherring:mainfrom
PeterJudgeZA:issue448

Conversation

@PeterJudgeZA
Copy link
Copy Markdown

@PeterJudgeZA PeterJudgeZA commented Jan 3, 2026

Per issue #448

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

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.

Comment on lines 598 to +602
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)))
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

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

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.

Copilot uses AI. Check for mistakes.
Comment on lines 608 to +612
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)))
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

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

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.

Copilot uses AI. Check for mistakes.
@@ -0,0 +1,41 @@
import { getDLC, getOEVersion, getOpenEdgeProfileConfig, getBuildPathPatterns } from 'parse/OpenedgeProjectParser'
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

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

Unused imports (getDLC, getOEVersion) add noise and can trigger lint failures when running npm run lint. Remove them or use them in the test.

Suggested change
import { getDLC, getOEVersion, getOpenEdgeProfileConfig, getBuildPathPatterns } from 'parse/OpenedgeProjectParser'
import { getOpenEdgeProfileConfig, getBuildPathPatterns } from 'parse/OpenedgeProjectParser'

Copilot uses AI. Check for mistakes.
suiteSetup('suiteSetup', async () => {
await suiteSetupCommon()
})

Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

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

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.

Suggested change
suiteTeardown('suiteTeardown', () => {
log.group.end()
})

Copilot uses AI. Check for mistakes.
Comment on lines +21 to +22
for (const b of config.buildPath.filter(b => b.type == 'source') ?? []) {
const buildPathPatterns = getBuildPathPatterns(workspaceFolder, b)
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

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

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.

Copilot uses AI. Check for mistakes.
Comment thread src/extension.ts
Comment on lines +1187 to +1197
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(/,$/, "") + '\'')
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

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

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.

Suggested change
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(',') + '\'')

Copilot uses AI. Check for mistakes.
@kenherring kenherring force-pushed the issue448 branch 3 times, most recently from 175f844 to 60cca31 Compare April 2, 2026 08:31
Copy link
Copy Markdown
Owner

@kenherring kenherring left a comment

Choose a reason for hiding this comment

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

@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:

  1. Code coverage
  2. 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.

@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented Apr 4, 2026

Quality Gate Failed Quality Gate failed

Failed conditions
50.0% Coverage on New Code (required ≥ 70%)

See analysis details on SonarQube Cloud

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

🐛 [Bug] Tests not found

3 participants