FEDX-7266: Support glob patterns in dependency_validator workspace resolution - #195
FEDX-7266: Support glob patterns in dependency_validator workspace resolution#195engops-wk wants to merge 6 commits into
Conversation
Co-authored-by: Dustin Pauze <dustin.pauze@workiva.com>
| root, | ||
| pubspec.workspace ?? [], | ||
| )) | ||
| makeGlob('$root/$subpackage**'), |
There was a problem hiding this comment.
There is no separator before **, so packages/foo also excludes sibling dirs sharing the prefix (e.g. packages/foo_helpers, which glob resolution intentionally skips when it has no pubspec.yaml) from the root package's scan — silently hiding missing/unused deps. Use makeGlob('${p.join(root, subpackage)}/**').
| ); | ||
|
|
||
| test( | ||
| 'validates each glob-matched subpackage', |
There was a problem hiding this comment.
Both glob tests create exactly one subpackage, so "validates each glob-matched subpackage" never proves the glob expands to multiple members — and the positive test above passes identically if the glob resolves to zero members. Please add coverage with 2+ glob-matched packages plus a non-package dir under the glob, and a mixed literal + glob workspace: list.
| for (final entity in glob.listSync(root: root)) { | ||
| if (entity is! Directory) continue; | ||
| if (!File(p.join(entity.path, 'pubspec.yaml')).existsSync()) continue; | ||
| yield p.relative(entity.path, from: root); |
There was a problem hiding this comment.
Results are neither deduplicated nor ordered: workspace: ['packages/*', 'packages/foo'] validates packages/foo twice, and listSync order is filesystem-dependent, so recursion order and log output are nondeterministic. Please return a deduplicated, sorted List<String> (normalize to posix separators so Windows packages\foo doesn't diverge from a literal packages/foo).
|
|
||
| final subpackageGlobs = [ | ||
| for (final subpackage in pubspec.workspace ?? []) | ||
| for (final subpackage in resolveWorkspaceMembers( |
There was a problem hiding this comment.
resolveWorkspaceMembers is a lazy sync* generator called twice per checkPackage, so the filesystem is walked twice and the two call sites can disagree if a member's pubspec.yaml appears/disappears between them (recursion vs. exclusion globs). Resolve once into a local final members = resolveWorkspaceMembers(...) list near the pubspec parse and reuse it at both sites.
| ) sync* { | ||
| for (final workspacePath in workspacePaths) { | ||
| if (hasGlobWildcards(workspacePath)) { | ||
| final glob = makeGlob(workspacePath); |
There was a problem hiding this comment.
makeGlob throws a FormatException on malformed patterns (e.g. packages/[a), so a typo'd workspace: entry now crashes the tool with a stack trace instead of a readable error. Wrap this in a try/catch that logger.shouts invalid glob syntax: "$workspacePath" and fails the run, matching how checkPackage handles invalid exclude globs.
| ); | ||
| final subpackagePubspec = Pubspec( | ||
| 'subpackage', | ||
| p.basename(subpackagePath), |
There was a problem hiding this comment.
test/utils.dart is imported by pubspec_to_json.dart-based tests but package:path is not declared in this package's dev_dependencies (it's a regular dependency) — fine here, but note resolveWorkspaceMembers returning p.relative output means CHANGELOG/README still document only literal workspace: entries. Please add an "Unreleased" CHANGELOG entry and a README note under "Pub Workspaces" showing workspace: ['packages/*'].
engops-wk
left a comment
There was a problem hiding this comment.
Review round 1 — CHANGES REQUESTED (posted as a comment; GitHub blocks REQUEST_CHANGES on one's own PR)
The direction is right: mirroring pub's glob expansion in a small, testable helper (resolveWorkspaceMembers) rather than sprinkling glob logic through checkPackage is the correct architectural choice, and threading workspaceMembers/subpackagePath through the checkWorkspace test harness keeps integration coverage cheap to extend. But this cannot merge yet.
CI is red — blocking regardless of code review
CI (.github/workflows/ci.yaml, Dart SDK 3.7.2) runs three required jobs from Workiva/gha-dart-oss@v0.1.14, and the PR is failing before review:
unit-tests(test-unit.yaml) — failing.dart testis not green, so the PR's claim of "Passing CI (dart test)" is not accurate today.checks(checks.yaml) — failing. This job runsdart analyze/dart format --set-exit-if-changed/dependency_validatoron this repo itself; formatting of the new blocks inlib/src/utils.dartandtest/utils_test.dartis the most likely culprit.build(build.yaml) must also be green (this repo generatespubspec_config.g.dartviabuild_runner).
Please paste the failing job logs (or a link) with the fix so round 2 can verify the actual failure rather than guess, and run dart analyze, dart format ., and dart test locally before pushing. Also reconcile the PR checklist — every box, including "Tests pass locally," is unchecked.
Correctness / robustness issues
- Missing-separator glob bug in
lib/src/dependency_validator.dart(makeGlob('$root/$subpackage**')) over-excludes prefix-sibling directories from the root package's scan — a silent false negative in the tool's core output. Pre-existing, but far more likely to bite now that members share a parent likepackages/. - No dedup / nondeterministic ordering from
resolveWorkspaceMembers; overlapping literal + glob entries double-validate a package, andlistSyncorder varies by filesystem. - Unhandled
FormatExceptionfrommakeGlobon a malformedworkspace:entry — the tool crashes instead of reportinginvalid glob syntax, whichcheckPackagealready does forexcludeglobs. - Lazy generator invoked twice per
checkPackage, doubling filesystem walks and allowing the recursion set and the exclusion-glob set to disagree.
Test strategy gap
Both new integration tests use a single subpackage, so neither proves multi-member expansion, and the positive case would pass even if the glob resolved to zero members. Add a case with 2+ matched packages, a non-package directory under the glob, and a mixed literal + glob workspace: list.
Docs
User-visible feature with no CHANGELOG.md "Unreleased" entry and no README update under "Pub Workspaces" — future users won't discover glob support.
Happy to re-review as soon as CI is green and the above are addressed.
- Fix subpackage exclusion glob boundary (use p.join with /** suffix) - Resolve workspace members once; return sorted deduplicated List - Handle invalid workspace glob syntax with logger.shout - Expand integration tests for multi-package globs and mixed entries - Document glob support in CHANGELOG and README Co-authored-by: Dustin Pauze <dustin.pauze@workiva.com>
|
@cursor resolve the merge conflicts |
|
Merge conflicts are resolved and pushed to What was conflicting Master added nested-package exclusion ( How it was resolved
Verification
Commit: |
Co-authored-by: Dustin Pauze <dustin.pauze@workiva.com>


Opened by Dustin Pauze with the ai-sdlc workflow for FEDX-7266
Motivation
Flutter/Dart pub workspaces support glob patterns for defining workspace members (e.g.
packages/*), butdependency_validatoronly handled literal paths inworkspace:entries. This meant any workspace configuration using glob patterns would fail to have its sub-packages resolved and validated correctly. (ref: #176)Changes
resolveWorkspaceMembersandhasGlobWildcardshelpers inlib/src/utils.dartto expand glob patterns inworkspace:entries into concrete sub-package directories, filtering to directories that contain apubspec.yaml(matching pub's own workspace resolution behavior).checkPackageinlib/src/dependency_validator.dartto resolve workspace members via the new helper before recursing into sub-packages and building subpackage globs, and to fail gracefully (returnfalse) on invalid glob syntax.README.mdandCHANGELOG.mdto document glob pattern support in workspace configuration.checkWorkspacetest helper (test/utils.dart) to support multiple sub-packages with distinct paths/contents/deps/config, and added unit tests (test/utils_test.dart) and integration tests (test/workspace_test.dart) covering literal paths, glob expansion, filtering non-package directories, deduplication, sort order, invalid glob syntax, and mixed literal/glob workspace entries.Testing/QA Instructions
Run
dart testand confirm all tests pass, including the newresolveWorkspaceMembers/hasGlobWildcardsunit tests and the glob workspace pattern integration tests.Manually verify against a workspace using
workspace: - packages/*that only directories with apubspec.yamlare validated as sub-packages, that dependency issues in glob-matched sub-packages are still detected, and that invalid glob syntax produces a warning rather than a crash.I have updated the CHANGELOG.md
I have added/updated tests for this change
I have verified this change manually
Intent
dependency_validator didn't support glob patterns (e.g.
packages/*) inworkspace:entries, even though Dart pub workspaces support them. This change adds glob expansion for workspace member resolution sodependency_validatormatches pub's actual workspace resolution behavior, enabling proper validation of sub-packages defined via glob patterns.How To QA
dart testand confirm all tests pass, including new resolveWorkspaceMembers, hasGlobWildcards, and glob workspace pattern tests in test/utils_test.dart and test/workspace_test.dartworkspace: - packages/*in pubspec.yaml and multiple sub-packages in packages/ directory (including one directory without pubspec.yaml). Run dependency_validator from workspace root and confirm it recurses into real sub-packages but skips non-package directoriespackages/[a) and confirm the tool logs a warning about invalid syntax and does not crashpackages/fooandpackages/*) resolves without duplicate validation of packages/foo