Unverified Commit 5d587f95 authored by Christopher Fujino's avatar Christopher Fujino Committed by GitHub

[flutter_conductor] Refactor next command (#91768)

parent 7a7d9a27
......@@ -4,12 +4,12 @@
import 'package:args/command_runner.dart';
import 'package:file/file.dart' show File;
import 'package:meta/meta.dart' show visibleForTesting;
import 'package:meta/meta.dart' show visibleForTesting, visibleForOverriding;
import './globals.dart';
import './proto/conductor_state.pb.dart' as pb;
import './proto/conductor_state.pbenum.dart';
import './repository.dart';
import './state.dart';
import './state.dart' as state_import;
import './stdio.dart';
const String kStateOption = 'state-file';
......@@ -21,7 +21,7 @@ class NextCommand extends Command<void> {
NextCommand({
required this.checkouts,
}) {
final String defaultPath = defaultStateFilePath(checkouts.platform);
final String defaultPath = state_import.defaultStateFilePath(checkouts.platform);
argParser.addOption(
kStateOption,
defaultsTo: defaultPath,
......@@ -48,38 +48,33 @@ class NextCommand extends Command<void> {
@override
Future<void> run() async {
await runNext(
await NextContext(
autoAccept: argResults![kYesFlag] as bool,
checkouts: checkouts,
force: argResults![kForceFlag] as bool,
stateFile: checkouts.fileSystem.file(argResults![kStateOption]),
);
).run();
}
}
@visibleForTesting
bool prompt(String message, Stdio stdio) {
stdio.write('${message.trim()} (y/n) ');
final String response = stdio.readLineSync().trim();
final String firstChar = response[0].toUpperCase();
if (firstChar == 'Y') {
return true;
}
if (firstChar == 'N') {
return false;
}
throw ConductorException(
'Unknown user input (expected "y" or "n"): $response',
);
}
/// Utility class for proceeding to the next step in a release.
///
/// Any calls to functions that cause side effects are wrapped in methods to
/// allow overriding in unit tests.
class NextContext {
NextContext({
required this.autoAccept,
required this.force,
required this.checkouts,
required this.stateFile,
});
final bool autoAccept;
final bool force;
final Checkouts checkouts;
final File stateFile;
@visibleForTesting
Future<void> runNext({
required bool autoAccept,
required bool force,
required Checkouts checkouts,
required File stateFile,
}) async {
Future<void> run() async {
final Stdio stdio = checkouts.stdio;
const List<CherrypickState> finishedStates = <CherrypickState>[
CherrypickState.COMPLETED,
......@@ -121,7 +116,7 @@ Future<void> runNext({
));
}
if (!requiresEnginePR(state)) {
if (!state_import.requiresEnginePR(state)) {
stdio.printStatus(
'This release has no engine cherrypicks. No Engine PR is necessary.\n',
);
......@@ -390,10 +385,37 @@ Future<void> runNext({
case pb.ReleasePhase.RELEASE_COMPLETED:
throw ConductorException('This release is finished.');
}
final ReleasePhase nextPhase = getNextPhase(state.currentPhase);
final ReleasePhase nextPhase = state_import.getNextPhase(state.currentPhase);
stdio.printStatus('\nUpdating phase from ${state.currentPhase} to $nextPhase...\n');
state.currentPhase = nextPhase;
stdio.printStatus(phaseInstructions(state));
stdio.printStatus(state_import.phaseInstructions(state));
writeStateToFile(stateFile, state, stdio.logs);
}
/// Persist the state to a file.
@visibleForOverriding
void writeStateToFile(File file, pb.ConductorState state, [List<String> logs = const <String>[]]) {
state_import.writeStateToFile(file, state, logs);
}
@visibleForTesting
bool prompt(String message, Stdio stdio) {
stdio.write('${message.trim()} (y/n) ');
final String response = stdio.readLineSync().trim();
final String firstChar = response[0].toUpperCase();
if (firstChar == 'Y') {
return true;
}
if (firstChar == 'N') {
return false;
}
throw ConductorException(
'Unknown user input (expected "y" or "n"): $response',
);
}
/// Read the state from a file.
@visibleForOverriding
pb.ConductorState readStateFromFile(File file) => state_import.readStateFromFile(file);
}
......@@ -1052,6 +1052,34 @@ void main() {
}, onPlatform: <String, dynamic>{
'windows': const Skip('Flutter Conductor only supported on macos/linux'),
});
group('prompt', () {
test('throws if user inputs character that is not "y" or "n"', () {
final FileSystem fileSystem = MemoryFileSystem.test();
final TestStdio stdio = TestStdio(
stdin: <String>['x'],
verbose: true,
);
final Checkouts checkouts = Checkouts(
fileSystem: fileSystem,
parentDirectory: fileSystem.directory('/'),
platform: FakePlatform(),
processManager: FakeProcessManager.empty(),
stdio: stdio,
);
final NextContext context = NextContext(
autoAccept: false,
force: false,
checkouts: checkouts,
stateFile: fileSystem.file('/statefile.json'),
);
expect(
() => context.prompt('Asking a question?', stdio),
throwsExceptionWith('Unknown user input (expected "y" or "n")'),
);
});
});
}
void _initializeCiYamlFile(
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment