[flutter_conductor] Support publishing to multiple channels (#94770)
diff --git a/dev/conductor/core/lib/src/globals.dart b/dev/conductor/core/lib/src/globals.dart
index 9c010c8..b0a5d25 100644
--- a/dev/conductor/core/lib/src/globals.dart
+++ b/dev/conductor/core/lib/src/globals.dart
@@ -16,7 +16,7 @@
const List<String> kReleaseChannels = <String>[...kBaseReleaseChannels, FrameworkRepository.defaultBranch];
-const List<String> KReleaseIncrements = <String>['y', 'z', 'm', 'n'];
+const List<String> kReleaseIncrements = <String>['y', 'z', 'm', 'n'];
const String kReleaseDocumentationUrl = 'https://github.com/flutter/flutter/wiki/Flutter-Cherrypick-Process';
@@ -28,6 +28,10 @@
r'flutter-(\d+)\.(\d+)-candidate\.(\d+)',
);
+/// Whether all releases published to the beta channel should be mirrored to
+/// dev.
+const bool kSynchronizeDevWithBeta = true;
+
/// Cast a dynamic to String and trim.
String stdoutToString(dynamic input) {
final String str = input as String;
diff --git a/dev/conductor/core/lib/src/next.dart b/dev/conductor/core/lib/src/next.dart
index 9ece748..575ce03 100644
--- a/dev/conductor/core/lib/src/next.dart
+++ b/dev/conductor/core/lib/src/next.dart
@@ -48,7 +48,7 @@
String get description => 'Proceed to the next release phase.';
@override
- Future<void> run() async {
+ Future<void> run() {
final File stateFile = checkouts.fileSystem.file(argResults![kStateOption]);
if (!stateFile.existsSync()) {
throw ConductorException(
@@ -57,7 +57,7 @@
}
final pb.ConductorState state = state_import.readStateFromFile(stateFile);
- await NextContext(
+ return NextContext(
autoAccept: argResults![kYesFlag] as bool,
checkouts: checkouts,
force: argResults![kForceFlag] as bool,
@@ -324,29 +324,37 @@
previousCheckoutLocation: state.framework.checkoutPath,
);
final String headRevision = await framework.reverseParse('HEAD');
- if (autoAccept == false) {
- // dryRun: true means print out git command
- await framework.pushRef(
+ final List<String> releaseRefs = <String>[state.releaseChannel];
+ if (kSynchronizeDevWithBeta && state.releaseChannel == 'beta') {
+ releaseRefs.add('dev');
+ }
+ for (final String releaseRef in releaseRefs) {
+ if (autoAccept == false) {
+ // dryRun: true means print out git command
+ await framework.pushRef(
fromRef: headRevision,
- toRef: state.releaseChannel,
+ toRef: releaseRef,
remote: state.framework.upstream.url,
force: force,
dryRun: true,
- );
+ );
- final bool response = await prompt('Are you ready to publish this release?');
- if (!response) {
- stdio.printError('Aborting command.');
- updateState(state, stdio.logs);
- return;
+ final bool response = await prompt(
+ 'Are you ready to publish version ${state.releaseVersion} to $releaseRef?',
+ );
+ if (!response) {
+ stdio.printError('Aborting command.');
+ updateState(state, stdio.logs);
+ return;
+ }
}
- }
- await framework.pushRef(
+ await framework.pushRef(
fromRef: headRevision,
- toRef: state.releaseChannel,
+ toRef: releaseRef,
remote: state.framework.upstream.url,
force: force,
- );
+ );
+ }
break;
case pb.ReleasePhase.VERIFY_RELEASE:
stdio.printStatus(
diff --git a/dev/conductor/core/lib/src/start.dart b/dev/conductor/core/lib/src/start.dart
index 4135441..3227396 100644
--- a/dev/conductor/core/lib/src/start.dart
+++ b/dev/conductor/core/lib/src/start.dart
@@ -93,7 +93,7 @@
kIncrementOption,
help: 'Specifies which part of the x.y.z version number to increment. Required.',
valueHelp: 'level',
- allowed: KReleaseIncrements,
+ allowed: kReleaseIncrements,
allowedHelp: <String, String>{
'y': 'Indicates the first dev release after a beta release.',
'z': 'Indicates a hotfix to a stable release.',
diff --git a/dev/conductor/core/lib/src/version.dart b/dev/conductor/core/lib/src/version.dart
index 85b21fd..8c29e61 100644
--- a/dev/conductor/core/lib/src/version.dart
+++ b/dev/conductor/core/lib/src/version.dart
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-import './globals.dart' show ConductorException, KReleaseIncrements, releaseCandidateBranchRegex;
+import './globals.dart' show ConductorException, kReleaseIncrements, releaseCandidateBranchRegex;
/// Possible string formats that `flutter --version` can return.
enum VersionType {
@@ -262,7 +262,7 @@
/// Will throw a [ConductorException] if the version is not possible given the
/// [candidateBranch] and [incrementLetter].
void ensureValid(String candidateBranch, String incrementLetter) {
- if (!KReleaseIncrements.contains(incrementLetter)) {
+ if (!kReleaseIncrements.contains(incrementLetter)) {
throw ConductorException('Invalid incrementLetter: $incrementLetter');
}
final RegExpMatch? branchMatch = releaseCandidateBranchRegex.firstMatch(candidateBranch);
diff --git a/dev/conductor/core/test/common.dart b/dev/conductor/core/test/common.dart
index 93821b9..b661271 100644
--- a/dev/conductor/core/test/common.dart
+++ b/dev/conductor/core/test/common.dart
@@ -48,7 +48,7 @@
@override
String readLineSync() {
if (stdin.isEmpty) {
- throw Exception('Unexpected call to readLineSync!');
+ throw Exception('Unexpected call to readLineSync! Last stdout was ${logs.last}');
}
return stdin.removeAt(0);
}
diff --git a/dev/conductor/core/test/next_test.dart b/dev/conductor/core/test/next_test.dart
index 1eb1703..edfb98c 100644
--- a/dev/conductor/core/test/next_test.dart
+++ b/dev/conductor/core/test/next_test.dart
@@ -967,6 +967,8 @@
test('updates currentPhase if user responds yes', () async {
stdio.stdin.add('y');
+ // for kSynchronizeDevWithBeta
+ stdio.stdin.add('y');
final FakeProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
const FakeCommand(
command: <String>['git', 'fetch', 'upstream'],
@@ -981,6 +983,10 @@
const FakeCommand(
command: <String>['git', 'push', FrameworkRepository.defaultUpstream, '$revision1:$releaseChannel'],
),
+ // for kSynchronizeDevWithBeta
+ const FakeCommand(
+ command: <String>['git', 'push', FrameworkRepository.defaultUpstream, '$revision1:dev'],
+ ),
]);
writeStateToFile(
fileSystem.file(stateFile),