fix: scope ADO known-issues WIQL query by area-path, defaulting to {project}#178
Conversation
…ation
Adds an optional `area-path` key to the `azure-devops` connector configuration.
When set, the WIQL query used to collect known issues is filtered with
`AND [System.AreaPath] UNDER '{areaPath}'`, restricting results to work items
that belong to the specified area and its descendants.
This prevents work items from unrelated repositories or products in the same
ADO project from appearing as known issues in the generated report.
Changes:
- AzureDevOpsConnectorConfig: add AreaPath property
- BuildMarkConfigReader: parse area-path key
- AzureDevOpsRepoConnector: propagate AreaPath through LookupData and apply
in CollectKnownIssuesAsync WIQL query (with single-quote escaping)
- MockAzureDevOpsHttpMessageHandler: capture LastWiqlRequestBody for assertions
- Tests: add area-path scoping test and configuration parsing test
- Docs: update connector-config, azure-devops-repo-connector,
azure-devops-connector-config verification, and user guide
Agent-Logs-Url: https://github.com/demaconsulting/BuildMark/sessions/0b4cb8c6-f635-495f-95a5-ca708c7601b7
Co-authored-by: Malcolmnixon <1863707+Malcolmnixon@users.noreply.github.com>
Agent-Logs-Url: https://github.com/demaconsulting/BuildMark/sessions/0b4cb8c6-f635-495f-95a5-ca708c7601b7 Co-authored-by: Malcolmnixon <1863707+Malcolmnixon@users.noreply.github.com>
|
@copilot Why add area-path when we already have project and repository, and area-path looks like it's just project and repository? |
In Azure DevOps,
So auto-computing If this convention ( |
@copilot Yes, make it the default - and also this will need some serious explaining in the user-guide |
…ide docs Agent-Logs-Url: https://github.com/demaconsulting/BuildMark/sessions/40a09882-35b4-4613-b7eb-c99a6c4848f1 Co-authored-by: Malcolmnixon <1863707+Malcolmnixon@users.noreply.github.com>
…L doc Agent-Logs-Url: https://github.com/demaconsulting/BuildMark/sessions/40a09882-35b4-4613-b7eb-c99a6c4848f1 Co-authored-by: Malcolmnixon <1863707+Malcolmnixon@users.noreply.github.com>
Done in commit
The user guide now has a dedicated Area Path scoping subsection that explains:
|
There was a problem hiding this comment.
Pull request overview
This PR introduces Area Path scoping for Azure DevOps (ADO) known-issues collection so that WIQL queries no longer pull unrelated open bugs across an entire ADO project when multiple repositories share the same project.
Changes:
- Add
AzureDevOpsConnectorConfig.AreaPathand parse the newarea-pathYAML key. - Default known-issues WIQL scoping to
{project}\{repository}, with support for override and (intended) opt-out via empty string. - Add unit tests + mock infrastructure to assert the generated WIQL request body, and update documentation to describe the new behavior.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| test/DemaConsulting.BuildMark.Tests/RepoConnectors/AzureDevOps/MockAzureDevOpsHttpMessageHandler.cs | Captures last WIQL request body to enable assertions in tests. |
| test/DemaConsulting.BuildMark.Tests/RepoConnectors/AzureDevOps/AzureDevOpsRepoConnectorTests.cs | Adds tests verifying WIQL scoping behavior (explicit, default, and empty). |
| test/DemaConsulting.BuildMark.Tests/Configuration/ConfigurationTests.cs | Adds a config-reader test for parsing area-path. |
| src/DemaConsulting.BuildMark/RepoConnectors/AzureDevOps/AzureDevOpsRepoConnector.cs | Implements effective area-path computation and appends System.AreaPath UNDER ... to WIQL when enabled. |
| src/DemaConsulting.BuildMark/Configuration/BuildMarkConfigReader.cs | Parses the new area-path key in azure-devops connector configuration. |
| src/DemaConsulting.BuildMark/Configuration/AzureDevOpsConnectorConfig.cs | Adds the AreaPath property with documented semantics (null/default, empty/disable, explicit/override). |
| docs/verification/build-mark/configuration/azure-devops-connector-config.md | Documents verification scenarios for parsing and WIQL scoping behavior. |
| docs/user_guide/configuration.md | Adds user-facing documentation explaining Area Path scoping and examples. |
| docs/design/build-mark/repo-connectors/azure-devops/azure-devops-repo-connector.md | Updates design steps to describe default/override/disable behavior. |
| docs/design/build-mark/configuration/connector-config.md | Updates connector config schema documentation with AreaPath. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
@copilot The "{project}{repository}" is not a good default AreaPath. By default Azure DevOps only creates AreaPath for projects, not for repositories. Please change the default to the project and update the requirements, design, verification, code, and tests to match. |
|
@copilot Additionally an invalid area-path results in Azure DevOps returning a 400 error which doesn't get handled correctly by BuildMark. Please improve the handling of the 400 error and also consider updating the user-guide. |
Agent-Logs-Url: https://github.com/demaconsulting/BuildMark/sessions/4aae84bd-0fd2-4ac0-b9b5-03414b9b975d Co-authored-by: Malcolmnixon <1863707+Malcolmnixon@users.noreply.github.com>
Done in commit The default is now the project name only — Azure DevOps creates a root area path for every project automatically, so this works out-of-the-box without any configuration. Also fixed the Updated scoping table:
|
…ception/NotSupportedException Agent-Logs-Url: https://github.com/demaconsulting/BuildMark/sessions/50caf613-b7b6-4b69-ac5d-aa55faa79ece Co-authored-by: Malcolmnixon <1863707+Malcolmnixon@users.noreply.github.com>
Done in commit
rather than a generic HTTP failure. If the body can't be parsed (non-JSON or unexpected schema), the exception includes the HTTP status code and reason phrase as a fallback. The user guide now has an Invalid area paths paragraph explaining the error output and pointing users to check the area path spelling in ADO project settings. |
|
@copilot Please fix the lint issues |
…ector-config.md) Agent-Logs-Url: https://github.com/demaconsulting/BuildMark/sessions/20f8768c-ccc7-470d-93b4-46986c149097 Co-authored-by: Malcolmnixon <1863707+Malcolmnixon@users.noreply.github.com>
Done in commit
|
|
@copilot Did you really add a Behaviour (British English) to the .cspell.yaml dictionary rather than actually fixing the typo? |
…); remove from cspell dictionary Agent-Logs-Url: https://github.com/demaconsulting/BuildMark/sessions/78b4cd43-ff0f-452c-8b86-f0660c456692 Co-authored-by: Malcolmnixon <1863707+Malcolmnixon@users.noreply.github.com>
Fixed in commit |
|
@copilot apply changes based on the comments in this thread |
…on-scalar values Agent-Logs-Url: https://github.com/demaconsulting/BuildMark/sessions/1a9fa631-b3f2-43bf-bdc0-940ebd29d737 Co-authored-by: Malcolmnixon <1863707+Malcolmnixon@users.noreply.github.com>
Done in commit |
When an ADO project contains multiple repositories, the known-issues WIQL query returned all open bugs across the entire project, causing unrelated work items to appear in generated reports.
Description
Adds an optional
area-pathkey to theazure-devopsconnector configuration to scope the WIQL known-issues query. Whenarea-pathis not configured, the connector defaults to the ADO project name — Azure DevOps creates a root area path for every project by default, so this works correctly without any configuration for the vast majority of teams. Users whose work items live in a sub-area can override this, and an explicit empty string (area-path: "") disables filtering entirely for a project-wide query.In Azure DevOps,
Area Pathis an independent organizational hierarchy for work items that does not automatically correspond to repository names. A single area path can cover multiple repositories, and one repository's bugs may span multiple area paths. The default project-level area path covers the overwhelming majority of cases;area-pathis exposed as an override for teams whose structure requires sub-area scoping.area-pathconnector optionAzureDevOpsConnectorConfig: addsAreaPathproperty (null→ default{project}; empty string → no filter; explicit value → scoped to that path)BuildMarkConfigReader: parses thearea-pathkey withinazure-devops:blocks; validates that the value is aYamlScalarNodeand produces a configuration error for non-scalar values (e.g.area-path: [foo]); preserves an explicit empty string so that filtering can be disabled without being normalized tonullAzureDevOpsRepoConnector: computes the effective area path (_config?.AreaPath ?? project); when non-empty, appendsAND [System.AreaPath] UNDER '{areaPath}'to the WIQL query (with single-quote escaping)AzureDevOpsRestClient:QueryWorkItemsAsyncnow detects non-2xx responses from the WIQL endpoint, parses the ADO JSON error body (AzureDevOpsApiError), and throws anInvalidOperationExceptionwith the ADO error message rather than a generic HTTP failureUsage
Default (no
area-pathneeded — scoped to the project root area automatically):Override for sub-area scoping:
Disable area-path filtering (project-wide query):
Tests & infrastructure
MockAzureDevOpsHttpMessageHandler: capturesLastWiqlRequestBodyfor assertion; addsAddWiqlErrorResponsehelper for testing 400 error responsesWithAreaPath_ScopesWiqlQueryToAreaPath: asserts explicit area path is used in WIQLWithoutAreaPath_DefaultsToProject: asserts default scoping uses the project nameWithEmptyAreaPath_DisablesAreaPathFilter: asserts noSystem.AreaPathfilter when emptyAzureDevOpsConnectorAreaPath_ReturnsParsedConfiguration: verifies YAML parsing round-tripAzureDevOpsConnectorEmptyAreaPath_ReturnsParsedConfiguration: verifies empty string is preserved as""(notnull) through YAML parsingWithInvalidAreaPath_ThrowsWithAdoErrorMessage: asserts that a 400 response surfaces the ADO error message in the thrown exceptionBuildMarkConfigReader_ReadAsync_AzureDevOpsNonScalarAreaPath_ReturnsErrorIssue: asserts that a non-scalararea-pathvalue (e.g. a YAML sequence) produces a configuration error rather than silently disabling filteringDocumentation
connector-config.md:AreaPathproperty description updated to describe default and escape hatchazure-devops-repo-connector.md: step 13 updated to describe default/override/disable logicazure-devops-connector-config.md: all test scenarios documentedconfiguration.md: Area Path scoping subsection with concept explanation, scoping table, examples, and an Invalid area paths paragraph describing the error outputType of Change
Pre-Submission Checklist
Before submitting this pull request, ensure you have completed the following:
Build and Test
pwsh ./build.ps1Code Quality
Quality Checks
Please run the following checks before submitting:
pwsh ./lint.ps1Testing
Documentation
Additional Notes
area-pathdefaults to the ADO project name. Azure DevOps creates a root area path for every project by default, so this restricts known issues to the configured project's own work items without requiring any configuration. Teams that organize bugs into sub-areas per repository or product can override the default (e.g.area-path: MyProject\MyRepo); teams that want no filtering at all can setarea-path: "".When an invalid
area-pathis configured, Azure DevOps returns a 400 Bad Request with a descriptive JSON error body. BuildMark now extracts and surfaces that message directly (e.g.Error: No area nodes were found under 'MyProject\BadPath'. Verify the area path exists.) rather than propagating a generic HTTP failure.When a non-scalar value is provided for
area-path(e.g. a YAML sequence or mapping),BuildMarkConfigReadernow produces a clear configuration error ("Azure DevOps area-path must be a scalar string value.") rather than silently treating the value as an empty string and disabling area-path filtering.