Skip to content

Commit

Permalink
add a general dart command (#459)
Browse files Browse the repository at this point in the history
This enables things like mono_repo dart fix --apply, mono_repo dart analyze, mono_repo dart run build_runner build etc.

I did bump the min SDK so I could use a switch expression, let me know if you feel strongly about supporting older SDKs. They can still use older versions so I think it's fine though.

Closes #458
  • Loading branch information
jakemac53 authored Sep 26, 2023
1 parent 6a8ec22 commit 5088bdb
Show file tree
Hide file tree
Showing 15 changed files with 246 additions and 163 deletions.
26 changes: 13 additions & 13 deletions .github/workflows/dart.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions analysis_options.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ linter:
- camel_case_types
- cancel_subscriptions
- cascade_invocations
- collection_methods_unrelated_type
- comment_references
- constant_identifier_names
- control_flow_in_finally
Expand All @@ -45,13 +46,11 @@ linter:
- file_names
- hash_and_equals
- implementation_imports
- iterable_contains_unrelated_type
- join_return_with_assignment
- library_names
- library_prefixes
- library_private_types_in_public_api
- lines_longer_than_80_chars
- list_remove_unrelated_type
- literal_only_boolean_expressions
- missing_whitespace_between_adjacent_strings
- no_duplicate_case_values
Expand Down
5 changes: 5 additions & 0 deletions mono_repo/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## 6.6.0

- Added the `dart` command to run arbitrary dart commands across all packages.
- Require the 3.0.0 Dart SDK.

## 6.5.7

- Updated `mono_repo` to use the existing action versions from the generated
Expand Down
9 changes: 5 additions & 4 deletions mono_repo/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ Or, once you've [setup your PATH]:
> mono_repo
```

Prints the following help message:
Prints the following help message:

```
Manage multiple packages in one source repository.
Expand All @@ -39,6 +39,7 @@ Global options:
Available commands:
check Check the state of the repository.
dart Runs the `dart` command with the provided arguments across all packages.
generate Generates the CI configuration for child packages.
list List all packages configured for mono_repo.
presubmit Run the CI presubmits locally.
Expand Down Expand Up @@ -83,12 +84,12 @@ github:
# `pull_request` while adding a single `schedule` entry.
# `on` and `cron` cannot both be set.
cron: '0 0 * * 0' # “At 00:00 (UTC) on Sunday.”

# Specify additional environment variables accessible to all jobs
env:
FOO: BAR

# You can group stages into individual workflows
# You can group stages into individual workflows
#
# Any stages that are omitted here are put in a default workflow
# named `dart.yml`.
Expand Down Expand Up @@ -156,7 +157,7 @@ To configure a package directory to be included it must contain a
`mono_pkg.yaml` file (along with the normal `pubspec.yaml` file).

You can use an empty `mono_pkg.yaml` file to enable the `check` and `pub`
commands.
commands.

To enable `generate` and `presubmit`, you must populate `mono_pkg.yaml` with
details on how you'd like tests to be run.
Expand Down
129 changes: 129 additions & 0 deletions mono_repo/lib/src/commands/dart.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'dart:async';
import 'dart:io';

import 'package:args/args.dart';
import 'package:io/ansi.dart';
import 'package:path/path.dart' as p;

import '../package_config.dart';
import '../root_config.dart';
import 'mono_repo_command.dart';

class DartCommand extends MonoRepoCommand {
@override
final ArgParser argParser = ArgParser.allowAnything();

@override
String get name => 'dart';

@override
String get description =>
'Runs the `dart` command with the provided arguments across all '
'packages.';

@override
Future<void> run() => dart(
rootConfig(),
arguments,
executableForPackage,
);

/// The arguments to pass to the executable.
List<String> get arguments => argResults?.rest ?? const [];

/// The executable to use for a given package.
Executable executableForPackage(PackageConfig config) => Executable.dart;
}

Future<void> dart(
RootConfig rootConfig,
List<String> args,
Executable Function(PackageConfig) executableForPackage,
) async {
final pkgDirs = rootConfig.map((pc) => pc.relativePath).toList();

print(
lightBlue.wrap(
'Running `dart ${args.join(' ')}` across ${pkgDirs.length} '
'package(s).',
),
);

var successCount = 0;
final failSet = <String>{};

for (var config in rootConfig) {
final dir = config.relativePath;

print('');
print(
wrapWith(
'`$dir`: Starting `${args.join(' ')}`',
[styleBold, lightBlue],
),
);
final workingDir = p.join(rootConfig.rootDirectory, dir);

final proc = await Process.start(
executableForPackage(config).path,
args,
mode: ProcessStartMode.inheritStdio,
workingDirectory: workingDir,
);

final exit = await proc.exitCode;

if (exit == 0) {
successCount++;
print(wrapWith('`$dir`: success!', [styleBold, green]));
} else {
failSet.add(dir);
print(wrapWith('`$dir`: failed!', [styleBold, red]));
}

if (rootConfig.length > 1) {
print('');
print('Successes: $successCount');
if (failSet.isNotEmpty) {
print(
'Failures: ${failSet.length}\n'
'${failSet.map((e) => ' $e').join('\n')}',
);
}
final remaining = rootConfig.length - (successCount + failSet.length);
if (remaining > 0) {
print('Remaining: $remaining');
}
}
}
}

/// The path to the root directory of the SDK.
final String _sdkDir = (() {
// The Dart executable is in "/path/to/sdk/bin/dart", so two levels up is
// "/path/to/sdk".
final aboveExecutable = p.dirname(p.dirname(Platform.resolvedExecutable));
assert(FileSystemEntity.isFileSync(p.join(aboveExecutable, 'version')));
return aboveExecutable;
})();

final String _dartPath = p.join(_sdkDir, 'bin', 'dart');

/// The "flutter[.bat]" command.
final String _flutterPath = Platform.isWindows ? 'flutter.bat' : 'flutter';

enum Executable {
dart,
flutter,
}

extension ExecutablePath on Executable {
String get path => switch (this) {
Executable.dart => _dartPath,
Executable.flutter => _flutterPath,
};
}
Loading

0 comments on commit 5088bdb

Please sign in to comment.