chore(shorebird_cli): remove run command (#3208)

This commit is contained in:
Bryan Oltman
2025-07-03 07:43:22 -07:00
committed by GitHub
parent e033ebbd0a
commit 7b4a42c579
4 changed files with 0 additions and 292 deletions
@@ -11,5 +11,4 @@ export 'patches/patches.dart';
export 'preview_command.dart';
export 'release/release.dart';
export 'releases/releases.dart';
export 'run_command.dart';
export 'upgrade_command.dart';
@@ -1,95 +0,0 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:shorebird_cli/src/doctor.dart';
import 'package:shorebird_cli/src/logging/logging.dart';
import 'package:shorebird_cli/src/shorebird_command.dart';
import 'package:shorebird_cli/src/shorebird_process.dart';
import 'package:shorebird_cli/src/shorebird_validator.dart';
/// {@template run_command}
/// `shorebird run`
/// Run the Flutter application.
/// {@endtemplate}
class RunCommand extends ShorebirdCommand {
/// {@macro run_command}
RunCommand() {
argParser
..addOption('device-id', abbr: 'd', help: 'Target device id or name.')
..addOption(
'target',
abbr: 't',
help: 'The main entrypoint file of the application.',
)
..addMultiOption(
'dart-define',
help:
'Additional key-value pairs that will be available as constants '
'''from the String.fromEnvironment, bool.fromEnvironment, and int.fromEnvironment '''
'constructors.\n'
'''Multiple defines can be passed by repeating "--dart-define" multiple times.''',
splitCommas: false,
valueHelp: 'foo=bar',
)
..addOption(
'flavor',
help: 'The product flavor to use when building the app.',
);
}
@override
String get description => 'Run the Flutter application.';
@override
String get name => 'run';
@override
bool get hidden => true;
@override
Future<int> run() async {
logger.warn('''
This command is deprecated and will be removed in a future release.
Please use "shorebird preview" instead.''');
// TODO(bryanoltman): check run target and run either
// doctor.iosValidators or doctor.androidValidators as appropriate.
try {
await shorebirdValidator.validatePreconditions(
checkUserIsAuthenticated: true,
validators: doctor.generalValidators,
);
} on PreconditionFailedException catch (e) {
return e.exitCode.code;
}
logger.info('Running app...');
final deviceId = results['device-id'] as String?;
final flavor = results['flavor'] as String?;
final target = results['target'] as String?;
final dartDefines = results['dart-define'] as List<String>?;
final flutter = await process.start('flutter', [
'run',
// Eventually we should support running in both debug and release mode.
'--release',
if (deviceId != null) '--device-id=$deviceId',
if (flavor != null) '--flavor=$flavor',
if (target != null) '--target=$target',
if (dartDefines != null) ...dartDefines.map((e) => '--dart-define=$e'),
...results.rest,
]);
flutter.stdout.listen((event) {
logger.info(utf8.decode(event));
});
flutter.stderr.listen((event) {
logger.err(utf8.decode(event));
});
unawaited(flutter.stdin.addStream(stdin));
return flutter.exitCode;
}
}
@@ -81,7 +81,6 @@ class ShorebirdCliCommandRunner extends CompletionCommandRunner<int> {
addCommand(PreviewCommand());
addCommand(ReleaseCommand());
addCommand(ReleasesCommand());
addCommand(RunCommand());
addCommand(UpgradeCommand());
}
@@ -1,195 +0,0 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:args/args.dart';
import 'package:mason_logger/mason_logger.dart';
import 'package:mocktail/mocktail.dart';
import 'package:scoped_deps/scoped_deps.dart';
import 'package:shorebird_cli/src/commands/run_command.dart';
import 'package:shorebird_cli/src/doctor.dart';
import 'package:shorebird_cli/src/logging/logging.dart';
import 'package:shorebird_cli/src/shorebird_process.dart';
import 'package:shorebird_cli/src/shorebird_validator.dart';
import 'package:shorebird_cli/src/validators/validators.dart';
import 'package:test/test.dart';
import '../mocks.dart';
void main() {
group(RunCommand, () {
late ArgResults argResults;
late Doctor doctor;
late ShorebirdLogger logger;
late Process process;
late ShorebirdProcess shorebirdProcess;
late IOSink ioSink;
late ShorebirdValidator shorebirdValidator;
late Validator validator;
late RunCommand command;
R runWithOverrides<R>(R Function() body) {
return runScoped(
body,
values: {
doctorRef.overrideWith(() => doctor),
loggerRef.overrideWith(() => logger),
processRef.overrideWith(() => shorebirdProcess),
shorebirdValidatorRef.overrideWith(() => shorebirdValidator),
},
);
}
setUpAll(() {
registerFallbackValue(const Stream<List<int>>.empty());
});
setUp(() {
argResults = MockArgResults();
doctor = MockDoctor();
logger = MockShorebirdLogger();
process = MockProcess();
shorebirdProcess = MockShorebirdProcess();
ioSink = MockIOSink();
shorebirdValidator = MockShorebirdValidator();
validator = MockValidator();
when(
() => shorebirdProcess.start(any(), any()),
).thenAnswer((_) async => process);
when(() => argResults.rest).thenReturn([]);
when(() => doctor.generalValidators).thenReturn([validator]);
when(() => logger.progress(any())).thenReturn(MockProgress());
when(() => ioSink.addStream(any())).thenAnswer((_) async {});
when(
() => shorebirdValidator.validatePreconditions(
checkUserIsAuthenticated: any(named: 'checkUserIsAuthenticated'),
validators: any(named: 'validators'),
),
).thenAnswer((_) async {});
command = runWithOverrides(RunCommand.new)..testArgResults = argResults;
});
test('command is hidden', () {
expect(command.hidden, isTrue);
});
test('has a description', () {
expect(command.description, isNotEmpty);
});
test('logs deprecation warning', () async {
runWithOverrides(command.run).ignore();
verify(
() => logger.warn('''
This command is deprecated and will be removed in a future release.
Please use "shorebird preview" instead.'''),
).called(1);
});
test('exits when validation fails', () async {
final exception = ValidationFailedException();
when(
() => shorebirdValidator.validatePreconditions(
checkUserIsAuthenticated: any(named: 'checkUserIsAuthenticated'),
validators: any(named: 'validators'),
),
).thenThrow(exception);
await expectLater(
runWithOverrides(command.run),
completion(equals(exception.exitCode.code)),
);
verify(
() => shorebirdValidator.validatePreconditions(
checkUserIsAuthenticated: true,
validators: [validator],
),
).called(1);
});
test('exits with code when running the app fails', () async {
final progress = MockProgress();
when(() => logger.progress(any())).thenReturn(progress);
const error = 'oops something went wrong';
const expectedExitCode = 1;
when(() => process.stdout).thenAnswer((_) => const Stream.empty());
when(() => process.stdin).thenAnswer((_) => ioSink);
when(
() => process.stderr,
).thenAnswer((_) => Stream.value(utf8.encode(error)));
when(() => process.exitCode).thenAnswer((_) async => expectedExitCode);
final exitCode = await runWithOverrides(command.run);
await expectLater(exitCode, equals(expectedExitCode));
verify(() => logger.err(error)).called(1);
});
test('exits with code 0 when running the app succeeds', () async {
final progress = MockProgress();
when(() => logger.progress(any())).thenReturn(progress);
const output = 'some output';
when(
() => process.stdout,
).thenAnswer((_) => Stream.value(utf8.encode(output)));
when(() => process.stdin).thenAnswer((_) => ioSink);
when(() => process.stderr).thenAnswer((_) => const Stream.empty());
when(
() => process.exitCode,
).thenAnswer((_) async => ExitCode.success.code);
final exitCode = await runWithOverrides(command.run);
await expectLater(exitCode, equals(ExitCode.success.code));
verify(() => logger.info(output)).called(1);
verify(() => ioSink.addStream(any())).called(1);
});
test('passes additional args when specified', () async {
final progress = MockProgress();
when(() => logger.progress(any())).thenReturn(progress);
const deviceId = 'test-device-id';
const flavor = 'development';
const target = './lib/main_development.dart';
const dartDefines = ['FOO=BAR', 'BAZ=QUX'];
when(() => argResults['device-id']).thenReturn(deviceId);
when(() => argResults['flavor']).thenReturn(flavor);
when(() => argResults['target']).thenReturn(target);
when(() => argResults['dart-define']).thenReturn(dartDefines);
when(() => process.stdout).thenAnswer((_) => const Stream.empty());
when(() => process.stdin).thenAnswer((_) => ioSink);
when(() => process.stderr).thenAnswer((_) => const Stream.empty());
when(
() => process.exitCode,
).thenAnswer((_) async => ExitCode.success.code);
final exitCode = await runWithOverrides(command.run);
final args =
verify(
() => shorebirdProcess.start(any(), captureAny()),
).captured.first
as List<String>;
expect(
args,
equals([
'run',
'--release',
'--device-id=$deviceId',
'--flavor=$flavor',
'--target=$target',
'--dart-define=${dartDefines[0]}',
'--dart-define=${dartDefines[1]}',
]),
);
await expectLater(exitCode, equals(ExitCode.success.code));
});
});
}