Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: report all dependencies in list command #313

Merged
merged 1 commit into from
Jun 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions packages/melos/lib/src/commands/list.dart
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ mixin _ListMixin on _Melos {
void _listGraph(MelosWorkspace workspace) {
final jsonGraph = <String, List<String>>{};
for (final package in workspace.filteredPackages.values) {
jsonGraph[package.name] = package.dependenciesInWorkspace.keys.toList();
jsonGraph[package.name] =
package.allDependenciesInWorkspace.keys.toList();
}

const encoder = JsonEncoder.withIndent(' ');
Expand Down Expand Up @@ -139,8 +140,8 @@ mixin _ListMixin on _Melos {
'flutter_package': package.isFlutterPackage,
'flutter_app': package.isFlutterApp,
'flutter_plugin': package.isFlutterPlugin,
'dependencies': package.dependenciesInWorkspace.keys.toList(),
'dependents': package.dependentsInWorkspace.keys.toList(),
'dependencies': package.allDependenciesInWorkspace.keys.toList(),
'dependents': package.allDependentsInWorkspace.keys.toList(),
});

if (package.isFlutterApp) {
Expand Down Expand Up @@ -220,6 +221,12 @@ mixin _ListMixin on _Melos {
' ${package.name} -> ${dep.name} [style="dashed"; color="${getColor(dep.name)}"];',
);
}

for (final dep in package.dependencyOverridesInWorkspace.values) {
buffer.add(
' ${package.name} -> ${dep.name} [style="dotted"; color="${getColor(dep.name)}"];',
);
}
}

final groupedPackages = workspace.filteredPackages.values
Expand Down
30 changes: 19 additions & 11 deletions packages/melos/lib/src/package.dart
Original file line number Diff line number Diff line change
Expand Up @@ -667,37 +667,45 @@ class Package {
late final allDependentsInWorkspace = {
...dependentsInWorkspace,
...devDependentsInWorkspace,
...dependentsOverridesInWorkspace,
};

/// The dependencies listen in `dev_dependencies:` inside the package's `pubspec.yaml`
/// that are part of the melos workspace
late final Map<String, Package> devDependenciesInWorkspace =
_packagesInWorkspaceForNames(devDependencies);

/// The dependencies listen in `dependencies:` inside the package's `pubspec.yaml`
/// that are part of the melos workspace
/// The dependencies listed in `dependencies:` inside the package's
/// `pubspec.yaml` that are part of the melos workspace
late final Map<String, Package> dependenciesInWorkspace =
_packagesInWorkspaceForNames(dependencies);

/// The dependencies listen in `dependency_overrides:` inside the package's `pubspec.yaml`
/// that are part of the melos workspace
/// The dependencies listed in `dev_dependencies:` inside the package's
/// `pubspec.yaml` that are part of the melos workspace
late final Map<String, Package> devDependenciesInWorkspace =
_packagesInWorkspaceForNames(devDependencies);

/// The dependencies listed in `dependency_overrides:` inside the package's
/// `pubspec.yaml` that are part of the melos workspace
late final Map<String, Package> dependencyOverridesInWorkspace =
_packagesInWorkspaceForNames(dependencyOverrides);

/// The packages that depends on this package.
/// The packages that depend on this package as a dependency.
late final Map<String, Package> dependentsInWorkspace = {
for (final entry in _packageMap.entries)
if (entry.value.dependenciesInWorkspace.containsKey(name))
entry.key: entry.value,
};

/// The packages that depends on this package.
/// The packages that depend on this package as a dev dependency..
late final Map<String, Package> devDependentsInWorkspace = {
for (final entry in _packageMap.entries)
if (entry.value.devDependenciesInWorkspace.containsKey(name))
entry.key: entry.value,
};

/// The packages that depend on this package as a dependency override.
late final Map<String, Package> dependentsOverridesInWorkspace = {
for (final entry in _packageMap.entries)
if (entry.value.dependencyOverridesInWorkspace.containsKey(name))
entry.key: entry.value,
};

late final Map<String, Package> allTransitiveDependenciesInWorkspace =
_transitivelyRelatedPackages(
root: this,
Expand Down
160 changes: 160 additions & 0 deletions packages/melos/test/commands/list_test.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import 'dart:convert';

import 'package:melos/src/commands/runner.dart';
import 'package:melos/src/common/glob.dart';
import 'package:melos/src/common/platform.dart';
Expand Down Expand Up @@ -145,7 +147,9 @@ long_name 0.0.0 packages/long_name PRIVATE
);
}),
);
});

group('parsable', () {
test(
'relativePaths flag prints relative paths only if true',
withMockFs(() async {
Expand Down Expand Up @@ -209,5 +213,161 @@ packages/c
skip: currentPlatform.isWindows,
);
});

group('graph', () {
test(
'reports all dependencies in workspace',
withMockFs(() async {
final workspaceDir = createMockWorkspaceFs(
packages: [
MockPackageFs(name: 'a'),
MockPackageFs(name: 'b'),
MockPackageFs(name: 'c'),
MockPackageFs(
name: 'd',
dependencies: ['a'],
devDependencies: ['b'],
dependencyOverrides: ['c'],
),
],
);

final config = await MelosWorkspaceConfig.fromDirectory(workspaceDir);
final melos = Melos(logger: logger, config: config);
await melos.list(
kind: ListOutputKind.graph,
);

expect(
logger.output,
'''
{
"a": [],
"b": [],
"c": [],
"d": [
"a",
"b",
"c"
]
}
''',
);
}),
);
});

group('json', () {
test(
'reports all dependencies in workspace',
withMockFs(() async {
final workspaceDir = createMockWorkspaceFs(
packages: [
MockPackageFs(name: 'a'),
MockPackageFs(name: 'b'),
MockPackageFs(name: 'c'),
MockPackageFs(
name: 'd',
dependencies: ['a'],
devDependencies: ['b'],
dependencyOverrides: ['c'],
),
],
);

final config = await MelosWorkspaceConfig.fromDirectory(workspaceDir);
final melos = Melos(logger: logger, config: config);
await melos.list(
kind: ListOutputKind.json,
long: true,
);
final json = (jsonDecode(logger.output) as List<Object?>)
.cast<Map<String, Object?>>();

expect(
json.map(
(pkg) => {
'name': pkg['name'],
'dependencies': pkg['dependencies'],
'dependents': pkg['dependents'],
},
),
[
{
'name': 'a',
'dependencies': <String>[],
'dependents': ['d'],
},
{
'name': 'b',
'dependencies': <String>[],
'dependents': ['d'],
},
{
'name': 'c',
'dependencies': <String>[],
'dependents': ['d'],
},
{
'name': 'd',
'dependencies': ['a', 'b', 'c'],
'dependents': <String>[],
},
],
);
}),
);
});

group('gviz', () {
test(
'reports all dependencies in workspace',
withMockFs(() async {
final workspaceDir = createMockWorkspaceFs(
packages: [
MockPackageFs(name: 'a'),
MockPackageFs(name: 'b'),
MockPackageFs(name: 'c'),
MockPackageFs(
name: 'd',
dependencies: ['a'],
devDependencies: ['b'],
dependencyOverrides: ['c'],
),
],
);

final config = await MelosWorkspaceConfig.fromDirectory(workspaceDir);
final melos = Melos(logger: logger, config: config);
await melos.list(
kind: ListOutputKind.gviz,
);

expect(
logger.output,
'''
digraph packages {
size="10"; ratio=fill;
a [shape="box"; color="#ff5307"];
b [shape="box"; color="#e03cc2"];
c [shape="box"; color="#fa533c"];
d [shape="box"; color="#80dce6"];
d -> a [style="filled"; color="#ff5307"];
d -> b [style="dashed"; color="#e03cc2"];
d -> c [style="dotted"; color="#fa533c"];
subgraph "cluster packages" {
label="packages";
color="#6b4949";
a;
b;
c;
d;
}
}
''',
);
}),
);
});
});
}
33 changes: 29 additions & 4 deletions packages/melos/test/mock_workspace_fs.dart
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,12 @@ void _createPackage(MockPackageFs package, String workspaceRoot) {
'''
dependencies:
${_yamlMap(package.dependencyMap, indent: 2)}

dev_dependencies:
${_yamlMap(package.devDependencyMap, indent: 2)}

dependency_overrides:
${_yamlMap(package.dependencyOverridesMap, indent: 2)}
''',
);

Expand All @@ -129,11 +135,15 @@ class MockPackageFs {
required this.name,
String? path,
List<String>? dependencies,
List<String>? devDependencies,
List<String>? dependencyOverrides,
this.version,
this.publishToNone = false,
bool generateExample = false,
}) : _path = path,
dependencies = dependencies ?? const [],
devDependencies = devDependencies ?? const [],
dependencyOverrides = dependencyOverrides ?? const [],
createExamplePackage = generateExample;

/// Name of the package (must be a valid Dart package name)
Expand All @@ -148,13 +158,28 @@ class MockPackageFs {
/// `true` if this package's yaml has a `publish_to: none` setting.
final bool publishToNone;

/// A list of package names this one depends on
/// A list of package names that are dependencies of this one.
final List<String> dependencies;

/// A list of package names that are dev dependencies of this one.
final List<String> devDependencies;

/// A list of package names that are dependency overrides of this one.
final List<String> dependencyOverrides;

/// A mapping of dependency names to their versions (always "any")
Map<String, String> get dependencyMap {
return Map.fromEntries(dependencies.map((name) => MapEntry(name, 'any')));
}
Map<String, String> get dependencyMap =>
Map.fromEntries(dependencies.map((name) => MapEntry(name, 'any')));

/// A mapping of dev dependency names to their versions (always "any")
Map<String, String> get devDependencyMap => Map.fromEntries(
devDependencies.map((name) => MapEntry(name, 'any')),
);

/// A mapping of dependency overrides names to their versions (always "any")
Map<String, String> get dependencyOverridesMap => Map.fromEntries(
dependencyOverrides.map((name) => MapEntry(name, 'any')),
);

/// `true` if an example package should be generated
final bool createExamplePackage;
Expand Down