[flutter_conductor] Refactor conductor core (#91694)
This commit is contained in:
parent
4b1b65118e
commit
1bf621ba03
@ -10,7 +10,7 @@ import './globals.dart';
|
|||||||
|
|
||||||
/// A wrapper around git process calls that can be mocked for unit testing.
|
/// A wrapper around git process calls that can be mocked for unit testing.
|
||||||
class Git {
|
class Git {
|
||||||
Git(this.processManager) : assert(processManager != null);
|
const Git(this.processManager);
|
||||||
|
|
||||||
final ProcessManager processManager;
|
final ProcessManager processManager;
|
||||||
|
|
||||||
|
@ -114,9 +114,6 @@ class StartCommand extends Command<void> {
|
|||||||
final ProcessManager processManager;
|
final ProcessManager processManager;
|
||||||
final Stdio stdio;
|
final Stdio stdio;
|
||||||
|
|
||||||
/// Git revision for the currently running Conductor.
|
|
||||||
late final String conductorVersion;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get name => 'start';
|
String get name => 'start';
|
||||||
|
|
||||||
@ -125,14 +122,6 @@ class StartCommand extends Command<void> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> run() async {
|
Future<void> run() async {
|
||||||
final Git git = Git(processManager);
|
|
||||||
conductorVersion = (await git.getOutput(
|
|
||||||
<String>['rev-parse', 'HEAD'],
|
|
||||||
'look up the current revision.',
|
|
||||||
workingDirectory: flutterRoot.path,
|
|
||||||
)).trim();
|
|
||||||
|
|
||||||
assert(conductorVersion.isNotEmpty);
|
|
||||||
final ArgResults argumentResults = argResults!;
|
final ArgResults argumentResults = argResults!;
|
||||||
if (!platform.isMacOS && !platform.isLinux) {
|
if (!platform.isMacOS && !platform.isLinux) {
|
||||||
throw ConductorException(
|
throw ConductorException(
|
||||||
@ -140,14 +129,6 @@ class StartCommand extends Command<void> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
final File stateFile = checkouts.fileSystem.file(
|
|
||||||
getValueFromEnvOrArgs(kStateOption, argumentResults, platform.environment),
|
|
||||||
);
|
|
||||||
if (stateFile.existsSync()) {
|
|
||||||
throw ConductorException(
|
|
||||||
'Error! A persistent state file already found at ${argResults![kStateOption]}.\n\n'
|
|
||||||
'Run `conductor clean` to cancel a previous release.');
|
|
||||||
}
|
|
||||||
final String frameworkUpstream = getValueFromEnvOrArgs(
|
final String frameworkUpstream = getValueFromEnvOrArgs(
|
||||||
kFrameworkUpstreamOption,
|
kFrameworkUpstreamOption,
|
||||||
argumentResults,
|
argumentResults,
|
||||||
@ -199,7 +180,96 @@ class StartCommand extends Command<void> {
|
|||||||
argumentResults,
|
argumentResults,
|
||||||
platform.environment,
|
platform.environment,
|
||||||
)!;
|
)!;
|
||||||
|
final File stateFile = checkouts.fileSystem.file(
|
||||||
|
getValueFromEnvOrArgs(kStateOption, argumentResults, platform.environment),
|
||||||
|
);
|
||||||
|
|
||||||
|
final StartContext context = StartContext(
|
||||||
|
candidateBranch: candidateBranch,
|
||||||
|
checkouts: checkouts,
|
||||||
|
dartRevision: dartRevision,
|
||||||
|
engineCherrypickRevisions: engineCherrypickRevisions,
|
||||||
|
engineMirror: engineMirror,
|
||||||
|
engineUpstream: engineUpstream,
|
||||||
|
flutterRoot: flutterRoot,
|
||||||
|
frameworkCherrypickRevisions: frameworkCherrypickRevisions,
|
||||||
|
frameworkMirror: frameworkMirror,
|
||||||
|
frameworkUpstream: frameworkUpstream,
|
||||||
|
incrementLetter: incrementLetter,
|
||||||
|
processManager: processManager,
|
||||||
|
releaseChannel: releaseChannel,
|
||||||
|
stateFile: stateFile,
|
||||||
|
stdio: stdio,
|
||||||
|
);
|
||||||
|
return context.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Context for starting a new release.
|
||||||
|
///
|
||||||
|
/// This is a frontend-agnostic implementation.
|
||||||
|
class StartContext {
|
||||||
|
StartContext({
|
||||||
|
required this.candidateBranch,
|
||||||
|
required this.checkouts,
|
||||||
|
required this.dartRevision,
|
||||||
|
required this.engineCherrypickRevisions,
|
||||||
|
required this.engineMirror,
|
||||||
|
required this.engineUpstream,
|
||||||
|
required this.frameworkCherrypickRevisions,
|
||||||
|
required this.frameworkMirror,
|
||||||
|
required this.frameworkUpstream,
|
||||||
|
required this.flutterRoot,
|
||||||
|
required this.incrementLetter,
|
||||||
|
required this.processManager,
|
||||||
|
required this.releaseChannel,
|
||||||
|
required this.stateFile,
|
||||||
|
required this.stdio,
|
||||||
|
}) : git = Git(processManager);
|
||||||
|
|
||||||
|
final String candidateBranch;
|
||||||
|
final Checkouts checkouts;
|
||||||
|
final String? dartRevision;
|
||||||
|
final List<String> engineCherrypickRevisions;
|
||||||
|
final String engineMirror;
|
||||||
|
final String engineUpstream;
|
||||||
|
final List<String> frameworkCherrypickRevisions;
|
||||||
|
final String frameworkMirror;
|
||||||
|
final String frameworkUpstream;
|
||||||
|
final Directory flutterRoot;
|
||||||
|
final String incrementLetter;
|
||||||
|
final Git git;
|
||||||
|
final ProcessManager processManager;
|
||||||
|
final String releaseChannel;
|
||||||
|
final File stateFile;
|
||||||
|
final Stdio stdio;
|
||||||
|
|
||||||
|
/// Git revision for the currently running Conductor.
|
||||||
|
Future<String> get conductorVersion async {
|
||||||
|
if (_conductorVersion != null) {
|
||||||
|
return Future<String>.value(_conductorVersion);
|
||||||
|
}
|
||||||
|
_conductorVersion = (await git.getOutput(
|
||||||
|
<String>['rev-parse', 'HEAD'],
|
||||||
|
'look up the current revision.',
|
||||||
|
workingDirectory: flutterRoot.path,
|
||||||
|
)).trim();
|
||||||
|
if (_conductorVersion == null || _conductorVersion!.isEmpty) {
|
||||||
|
throw ConductorException(
|
||||||
|
'Failed to determine the git revision of the Flutter SDK\n'
|
||||||
|
'Working directory: ${flutterRoot.path}'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return _conductorVersion!;
|
||||||
|
}
|
||||||
|
String? _conductorVersion;
|
||||||
|
|
||||||
|
Future<void> run() async {
|
||||||
|
if (stateFile.existsSync()) {
|
||||||
|
throw ConductorException(
|
||||||
|
'Error! A persistent state file already found at ${stateFile.path}.\n\n'
|
||||||
|
'Run `conductor clean` to cancel a previous release.');
|
||||||
|
}
|
||||||
if (!releaseCandidateBranchRegex.hasMatch(candidateBranch)) {
|
if (!releaseCandidateBranchRegex.hasMatch(candidateBranch)) {
|
||||||
throw ConductorException(
|
throw ConductorException(
|
||||||
'Invalid release candidate branch "$candidateBranch". Text should '
|
'Invalid release candidate branch "$candidateBranch". Text should '
|
||||||
@ -233,8 +303,8 @@ class StartCommand extends Command<void> {
|
|||||||
final String workingBranchName = 'cherrypicks-$candidateBranch';
|
final String workingBranchName = 'cherrypicks-$candidateBranch';
|
||||||
await engine.newBranch(workingBranchName);
|
await engine.newBranch(workingBranchName);
|
||||||
|
|
||||||
if (dartRevision != null && dartRevision.isNotEmpty) {
|
if (dartRevision != null && dartRevision!.isNotEmpty) {
|
||||||
await engine.updateDartRevision(dartRevision);
|
await engine.updateDartRevision(dartRevision!);
|
||||||
await engine.commit('Update Dart SDK to $dartRevision', addFirst: true);
|
await engine.commit('Update Dart SDK to $dartRevision', addFirst: true);
|
||||||
}
|
}
|
||||||
final List<pb.Cherrypick> engineCherrypicks = (await _sortCherrypicks(
|
final List<pb.Cherrypick> engineCherrypicks = (await _sortCherrypicks(
|
||||||
@ -349,7 +419,7 @@ class StartCommand extends Command<void> {
|
|||||||
|
|
||||||
state.currentPhase = ReleasePhase.APPLY_ENGINE_CHERRYPICKS;
|
state.currentPhase = ReleasePhase.APPLY_ENGINE_CHERRYPICKS;
|
||||||
|
|
||||||
state.conductorVersion = conductorVersion;
|
state.conductorVersion = await conductorVersion;
|
||||||
|
|
||||||
stdio.printTrace('Writing state to file ${stateFile.path}...');
|
stdio.printTrace('Writing state to file ${stateFile.path}...');
|
||||||
|
|
||||||
|
@ -82,7 +82,21 @@ void main() {
|
|||||||
operatingSystem: 'windows',
|
operatingSystem: 'windows',
|
||||||
);
|
);
|
||||||
await expectLater(
|
await expectLater(
|
||||||
() async => runner.run(<String>['start']),
|
() async => runner.run(<String>[
|
||||||
|
'start',
|
||||||
|
'--$kFrameworkMirrorOption',
|
||||||
|
frameworkMirror,
|
||||||
|
'--$kEngineMirrorOption',
|
||||||
|
engineMirror,
|
||||||
|
'--$kCandidateOption',
|
||||||
|
candidateBranch,
|
||||||
|
'--$kReleaseOption',
|
||||||
|
'dev',
|
||||||
|
'--$kStateOption',
|
||||||
|
'/path/to/statefile.json',
|
||||||
|
'--$kIncrementOption',
|
||||||
|
'y',
|
||||||
|
]),
|
||||||
throwsExceptionWith(
|
throwsExceptionWith(
|
||||||
'Error! This tool is only supported on macOS and Linux',
|
'Error! This tool is only supported on macOS and Linux',
|
||||||
),
|
),
|
||||||
@ -236,12 +250,12 @@ void main() {
|
|||||||
|
|
||||||
final CommandRunner<void> runner = createRunner(
|
final CommandRunner<void> runner = createRunner(
|
||||||
commands: <FakeCommand>[
|
commands: <FakeCommand>[
|
||||||
|
...engineCommands,
|
||||||
|
...frameworkCommands,
|
||||||
const FakeCommand(
|
const FakeCommand(
|
||||||
command: <String>['git', 'rev-parse', 'HEAD'],
|
command: <String>['git', 'rev-parse', 'HEAD'],
|
||||||
stdout: revision,
|
stdout: revision,
|
||||||
),
|
),
|
||||||
...engineCommands,
|
|
||||||
...frameworkCommands,
|
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -420,12 +434,12 @@ void main() {
|
|||||||
|
|
||||||
final CommandRunner<void> runner = createRunner(
|
final CommandRunner<void> runner = createRunner(
|
||||||
commands: <FakeCommand>[
|
commands: <FakeCommand>[
|
||||||
|
...engineCommands,
|
||||||
|
...frameworkCommands,
|
||||||
const FakeCommand(
|
const FakeCommand(
|
||||||
command: <String>['git', 'rev-parse', 'HEAD'],
|
command: <String>['git', 'rev-parse', 'HEAD'],
|
||||||
stdout: revision,
|
stdout: revision,
|
||||||
),
|
),
|
||||||
...engineCommands,
|
|
||||||
...frameworkCommands,
|
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user