Detect duplicate names in workspace packages (#4232)
diff --git a/lib/src/entrypoint.dart b/lib/src/entrypoint.dart
index a9315fb..562d6af 100644
--- a/lib/src/entrypoint.dart
+++ b/lib/src/entrypoint.dart
@@ -123,7 +123,7 @@
);
for (final package in root.transitiveWorkspace) {
if (identical(pubspecsMet.entries.first.value, package.pubspec)) {
- validateWorkspaceGraph(root);
+ validateWorkspace(root);
return (root: root, work: package);
}
}
diff --git a/lib/src/package.dart b/lib/src/package.dart
index e1c5208..1cf3034 100644
--- a/lib/src/package.dart
+++ b/lib/src/package.dart
@@ -361,8 +361,10 @@
}
/// Reports an error if the graph of the workspace rooted at [root] is not a
-/// tree.
-void validateWorkspaceGraph(Package root) {
+/// tree. Or if a package name occurs twice.
+void validateWorkspace(Package root) {
+ if (root.workspaceChildren.isEmpty) return;
+
final includedFrom = <String, String>{};
final stack = [root];
@@ -382,4 +384,17 @@
}
stack.addAll(current.workspaceChildren);
}
+
+ // Check that the workspace doesn't contain two packages with the same name!
+ final namesSeen = <String, Package>{};
+ for (final package in root.transitiveWorkspace) {
+ final collision = namesSeen[package.name];
+ if (collision != null) {
+ fail('''
+Workspace members must have unique names.
+`${collision.pubspecPath}` and `${package.pubspecPath}` are both called "${package.name}".
+''');
+ }
+ namesSeen[package.name] = package;
+ }
}
diff --git a/lib/src/package_config.dart b/lib/src/package_config.dart
index 5c40123..d10990f 100644
--- a/lib/src/package_config.dart
+++ b/lib/src/package_config.dart
@@ -50,7 +50,17 @@
this.generator,
this.generatorVersion,
Map<String, dynamic>? additionalProperties,
- }) : additionalProperties = additionalProperties ?? {};
+ }) : additionalProperties = additionalProperties ?? {} {
+ final names = <String>{};
+ // Sanity check:
+ for (final p in packages) {
+ if (!names.add(p.name)) {
+ throw ArgumentError(
+ 'Duplicate name ${p.name} in generated package config',
+ );
+ }
+ }
+ }
/// Create [PackageConfig] from JSON [data].
///
diff --git a/test/workspace_test.dart b/test/workspace_test.dart
index e381fb5..d0fa09d 100644
--- a/test/workspace_test.dart
+++ b/test/workspace_test.dart
@@ -1163,6 +1163,41 @@
'Because myapp depends on both a 2.0.0 and a, version solving failed.',
);
});
+
+ test('Reports error if two members of workspace has same name', () async {
+ final server = await servePackages();
+ server.serve('dev_dep', '1.0.0');
+ await dir(appPath, [
+ libPubspec(
+ 'myapp',
+ '1.2.3',
+ extras: {
+ 'workspace': ['a', 'b'],
+ },
+ sdk: '^3.5.0',
+ ),
+ dir('a', [
+ libPubspec(
+ 'a',
+ '1.0.0',
+ resolutionWorkspace: true,
+ ),
+ ]),
+ dir('b', [
+ libPubspec(
+ 'a', // Has same name as sibling.
+ '1.0.0',
+ resolutionWorkspace: true,
+ ),
+ ]),
+ ]).create();
+ await pubGet(
+ environment: {'_PUB_TEST_SDK_VERSION': '3.5.0'},
+ error: '''
+Workspace members must have unique names.
+`a${s}pubspec.yaml` and `b${s}pubspec.yaml` are both called "a".''',
+ );
+ });
}
final s = p.separator;