Update conductor to support monorepos (#161704)
Fixes https://github.com/flutter/flutter/issues/161616 Tested this PR with the 3.29.0 stable release: - https://github.com/flutter/flutter/pull/162899
This commit is contained in:
parent
7f783e3587
commit
6a412a5f71
@ -85,79 +85,7 @@ class NextContext extends Context {
|
||||
CherrypickState.ABANDONED,
|
||||
];
|
||||
switch (state.currentPhase) {
|
||||
case pb.ReleasePhase.APPLY_ENGINE_CHERRYPICKS:
|
||||
final Remote upstream = Remote.upstream(state.engine.upstream.url);
|
||||
final EngineRepository engine = EngineRepository(
|
||||
checkouts,
|
||||
initialRef: state.engine.workingBranch,
|
||||
upstreamRemote: upstream,
|
||||
previousCheckoutLocation: state.engine.checkoutPath,
|
||||
);
|
||||
if (!state_import.requiresEnginePR(state)) {
|
||||
stdio.printStatus('This release has no engine cherrypicks. No Engine PR is necessary.\n');
|
||||
break;
|
||||
}
|
||||
|
||||
final List<pb.Cherrypick> unappliedCherrypicks = <pb.Cherrypick>[
|
||||
for (final pb.Cherrypick cherrypick in state.engine.cherrypicks)
|
||||
if (!finishedStates.contains(cherrypick.state)) cherrypick,
|
||||
];
|
||||
|
||||
if (unappliedCherrypicks.isEmpty) {
|
||||
stdio.printStatus('All engine cherrypicks have been auto-applied by the conductor.\n');
|
||||
} else {
|
||||
if (unappliedCherrypicks.length == 1) {
|
||||
stdio.printStatus(
|
||||
'There was ${unappliedCherrypicks.length} cherrypick that was not auto-applied.',
|
||||
);
|
||||
} else {
|
||||
stdio.printStatus(
|
||||
'There were ${unappliedCherrypicks.length} cherrypicks that were not auto-applied.',
|
||||
);
|
||||
}
|
||||
stdio.printStatus(
|
||||
'These must be applied manually in the directory '
|
||||
'${state.engine.checkoutPath} before proceeding.\n',
|
||||
);
|
||||
}
|
||||
if (!autoAccept) {
|
||||
final bool response = await prompt(
|
||||
'Are you ready to push your engine branch to the repository '
|
||||
'${state.engine.mirror.url}?',
|
||||
);
|
||||
if (!response) {
|
||||
stdio.printError('Aborting command.');
|
||||
updateState(state, stdio.logs);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
await pushWorkingBranch(engine, state.engine);
|
||||
case pb.ReleasePhase.VERIFY_ENGINE_CI:
|
||||
stdio.printStatus('You must validate post-submit CI for your engine PR and merge it');
|
||||
if (!autoAccept) {
|
||||
final bool response = await prompt(
|
||||
'Has CI passed for the engine PR?\n\n'
|
||||
'${state_import.luciConsoleLink(state.engine.candidateBranch, 'engine')}',
|
||||
);
|
||||
if (!response) {
|
||||
stdio.printError('Aborting command.');
|
||||
updateState(state, stdio.logs);
|
||||
return;
|
||||
}
|
||||
}
|
||||
case pb.ReleasePhase.APPLY_FRAMEWORK_CHERRYPICKS:
|
||||
final Remote engineUpstreamRemote = Remote.upstream(state.engine.upstream.url);
|
||||
final EngineRepository engine = EngineRepository(
|
||||
checkouts,
|
||||
// We explicitly want to check out the merged version from upstream
|
||||
initialRef: '${engineUpstreamRemote.name}/${state.engine.candidateBranch}',
|
||||
upstreamRemote: engineUpstreamRemote,
|
||||
previousCheckoutLocation: state.engine.checkoutPath,
|
||||
);
|
||||
|
||||
final String engineRevision = await engine.reverseParse('HEAD');
|
||||
|
||||
final Remote upstream = Remote.upstream(state.framework.upstream.url);
|
||||
final FrameworkRepository framework = FrameworkRepository(
|
||||
checkouts,
|
||||
@ -166,7 +94,7 @@ class NextContext extends Context {
|
||||
previousCheckoutLocation: state.framework.checkoutPath,
|
||||
);
|
||||
stdio.printStatus('Writing candidate branch...');
|
||||
bool needsCommit = await framework.updateCandidateBranchVersion(
|
||||
final bool needsCommit = await framework.updateCandidateBranchVersion(
|
||||
state.framework.candidateBranch,
|
||||
);
|
||||
if (needsCommit) {
|
||||
@ -181,20 +109,6 @@ class NextContext extends Context {
|
||||
..state = pb.CherrypickState.COMPLETED,
|
||||
);
|
||||
}
|
||||
stdio.printStatus('Rolling new engine hash $engineRevision to framework checkout...');
|
||||
needsCommit = await framework.updateEngineRevision(engineRevision);
|
||||
if (needsCommit) {
|
||||
final String revision = await framework.commit(
|
||||
'Update Engine revision to $engineRevision for ${state.releaseChannel} release ${state.releaseVersion}',
|
||||
addFirst: true,
|
||||
);
|
||||
// append to list of cherrypicks so we know a PR is required
|
||||
state.framework.cherrypicks.add(
|
||||
pb.Cherrypick.create()
|
||||
..appliedRevision = revision
|
||||
..state = pb.CherrypickState.COMPLETED,
|
||||
);
|
||||
}
|
||||
|
||||
final List<pb.Cherrypick> unappliedCherrypicks = <pb.Cherrypick>[
|
||||
for (final pb.Cherrypick cherrypick in state.framework.cherrypicks)
|
||||
|
@ -3,11 +3,25 @@
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
# //flutter/dev/tools/lib/proto
|
||||
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
||||
set -euo pipefail
|
||||
|
||||
function follow_links() (
|
||||
cd -P "$(dirname -- "$1")"
|
||||
file="$PWD/$(basename -- "$1")"
|
||||
while [[ -h "$file" ]]; do
|
||||
cd -P "$(dirname -- "$file")"
|
||||
file="$(readlink -- "$file")"
|
||||
cd -P "$(dirname -- "$file")"
|
||||
file="$PWD/$(basename -- "$file")"
|
||||
done
|
||||
echo "$file"
|
||||
)
|
||||
|
||||
PROG_NAME="$(follow_links "${BASH_SOURCE[0]}")"
|
||||
DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
|
||||
|
||||
# Ensure dart-sdk is cached
|
||||
"$DIR/../../../../bin/dart" --version
|
||||
"$DIR/../../../../../../bin/dart" --version
|
||||
|
||||
if ! type protoc >/dev/null 2>&1; then
|
||||
PROTOC_LINK='https://grpc.io/docs/protoc-installation/'
|
||||
@ -22,13 +36,13 @@ if ! type dart >/dev/null 2>&1; then
|
||||
fi
|
||||
|
||||
# Use null-safe protoc_plugin
|
||||
dart pub global activate protoc_plugin 20.0.0
|
||||
dart pub global activate protoc_plugin 21.1.2
|
||||
|
||||
protoc --dart_out="$DIR" --proto_path="$DIR" "$DIR/conductor_state.proto"
|
||||
|
||||
for SOURCE_FILE in $(ls "$DIR"/*.pb*.dart); do
|
||||
# Format in place file
|
||||
dart format --output=write --line-length 120 "$SOURCE_FILE"
|
||||
dart format --output=write "$SOURCE_FILE"
|
||||
|
||||
# Create temp copy with the license header prepended
|
||||
cp "$DIR/license_header.txt" "${SOURCE_FILE}.tmp"
|
||||
|
@ -8,7 +8,7 @@
|
||||
//
|
||||
// @dart = 2.12
|
||||
|
||||
// ignore_for_file: annotate_overrides, camel_case_types
|
||||
// ignore_for_file: annotate_overrides, camel_case_types, comment_references
|
||||
// ignore_for_file: constant_identifier_names, library_prefixes
|
||||
// ignore_for_file: non_constant_identifier_names, prefer_final_fields
|
||||
// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
|
||||
@ -22,8 +22,21 @@ import 'conductor_state.pbenum.dart';
|
||||
|
||||
export 'conductor_state.pbenum.dart';
|
||||
|
||||
/// A git remote
|
||||
class Remote extends $pb.GeneratedMessage {
|
||||
factory Remote() => create();
|
||||
factory Remote({
|
||||
$core.String? name,
|
||||
$core.String? url,
|
||||
}) {
|
||||
final $result = create();
|
||||
if (name != null) {
|
||||
$result.name = name;
|
||||
}
|
||||
if (url != null) {
|
||||
$result.url = url;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
Remote._() : super();
|
||||
factory Remote.fromBuffer($core.List<$core.int> i,
|
||||
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
|
||||
@ -86,7 +99,23 @@ class Remote extends $pb.GeneratedMessage {
|
||||
}
|
||||
|
||||
class Cherrypick extends $pb.GeneratedMessage {
|
||||
factory Cherrypick() => create();
|
||||
factory Cherrypick({
|
||||
$core.String? trunkRevision,
|
||||
$core.String? appliedRevision,
|
||||
CherrypickState? state,
|
||||
}) {
|
||||
final $result = create();
|
||||
if (trunkRevision != null) {
|
||||
$result.trunkRevision = trunkRevision;
|
||||
}
|
||||
if (appliedRevision != null) {
|
||||
$result.appliedRevision = appliedRevision;
|
||||
}
|
||||
if (state != null) {
|
||||
$result.state = state;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
Cherrypick._() : super();
|
||||
factory Cherrypick.fromBuffer($core.List<$core.int> i,
|
||||
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
|
||||
@ -127,6 +156,7 @@ class Cherrypick extends $pb.GeneratedMessage {
|
||||
_defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<Cherrypick>(create);
|
||||
static Cherrypick? _defaultInstance;
|
||||
|
||||
/// The revision on trunk to cherrypick.
|
||||
@$pb.TagNumber(1)
|
||||
$core.String get trunkRevision => $_getSZ(0);
|
||||
@$pb.TagNumber(1)
|
||||
@ -139,6 +169,7 @@ class Cherrypick extends $pb.GeneratedMessage {
|
||||
@$pb.TagNumber(1)
|
||||
void clearTrunkRevision() => clearField(1);
|
||||
|
||||
/// Once applied, the actual commit revision of the cherrypick.
|
||||
@$pb.TagNumber(2)
|
||||
$core.String get appliedRevision => $_getSZ(1);
|
||||
@$pb.TagNumber(2)
|
||||
@ -165,7 +196,47 @@ class Cherrypick extends $pb.GeneratedMessage {
|
||||
}
|
||||
|
||||
class Repository extends $pb.GeneratedMessage {
|
||||
factory Repository() => create();
|
||||
factory Repository({
|
||||
$core.String? candidateBranch,
|
||||
$core.String? startingGitHead,
|
||||
$core.String? currentGitHead,
|
||||
$core.String? checkoutPath,
|
||||
Remote? upstream,
|
||||
Remote? mirror,
|
||||
$core.Iterable<Cherrypick>? cherrypicks,
|
||||
$core.String? dartRevision,
|
||||
$core.String? workingBranch,
|
||||
}) {
|
||||
final $result = create();
|
||||
if (candidateBranch != null) {
|
||||
$result.candidateBranch = candidateBranch;
|
||||
}
|
||||
if (startingGitHead != null) {
|
||||
$result.startingGitHead = startingGitHead;
|
||||
}
|
||||
if (currentGitHead != null) {
|
||||
$result.currentGitHead = currentGitHead;
|
||||
}
|
||||
if (checkoutPath != null) {
|
||||
$result.checkoutPath = checkoutPath;
|
||||
}
|
||||
if (upstream != null) {
|
||||
$result.upstream = upstream;
|
||||
}
|
||||
if (mirror != null) {
|
||||
$result.mirror = mirror;
|
||||
}
|
||||
if (cherrypicks != null) {
|
||||
$result.cherrypicks.addAll(cherrypicks);
|
||||
}
|
||||
if (dartRevision != null) {
|
||||
$result.dartRevision = dartRevision;
|
||||
}
|
||||
if (workingBranch != null) {
|
||||
$result.workingBranch = workingBranch;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
Repository._() : super();
|
||||
factory Repository.fromBuffer($core.List<$core.int> i,
|
||||
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
|
||||
@ -210,6 +281,9 @@ class Repository extends $pb.GeneratedMessage {
|
||||
_defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<Repository>(create);
|
||||
static Repository? _defaultInstance;
|
||||
|
||||
/// The development git branch the release is based on.
|
||||
///
|
||||
/// Must be of the form /flutter-(\d+)\.(\d+)-candidate\.(\d+)/
|
||||
@$pb.TagNumber(1)
|
||||
$core.String get candidateBranch => $_getSZ(0);
|
||||
@$pb.TagNumber(1)
|
||||
@ -222,6 +296,7 @@ class Repository extends $pb.GeneratedMessage {
|
||||
@$pb.TagNumber(1)
|
||||
void clearCandidateBranch() => clearField(1);
|
||||
|
||||
/// The commit hash at the tip of the branch before cherrypicks were applied.
|
||||
@$pb.TagNumber(2)
|
||||
$core.String get startingGitHead => $_getSZ(1);
|
||||
@$pb.TagNumber(2)
|
||||
@ -234,6 +309,8 @@ class Repository extends $pb.GeneratedMessage {
|
||||
@$pb.TagNumber(2)
|
||||
void clearStartingGitHead() => clearField(2);
|
||||
|
||||
/// The difference in commits between this and [startingGitHead] is the number
|
||||
/// of cherrypicks that have been currently applied.
|
||||
@$pb.TagNumber(3)
|
||||
$core.String get currentGitHead => $_getSZ(2);
|
||||
@$pb.TagNumber(3)
|
||||
@ -246,6 +323,7 @@ class Repository extends $pb.GeneratedMessage {
|
||||
@$pb.TagNumber(3)
|
||||
void clearCurrentGitHead() => clearField(3);
|
||||
|
||||
/// Path to the git checkout on local disk.
|
||||
@$pb.TagNumber(4)
|
||||
$core.String get checkoutPath => $_getSZ(3);
|
||||
@$pb.TagNumber(4)
|
||||
@ -258,6 +336,7 @@ class Repository extends $pb.GeneratedMessage {
|
||||
@$pb.TagNumber(4)
|
||||
void clearCheckoutPath() => clearField(4);
|
||||
|
||||
/// The remote commits will be fetched from.
|
||||
@$pb.TagNumber(5)
|
||||
Remote get upstream => $_getN(4);
|
||||
@$pb.TagNumber(5)
|
||||
@ -272,6 +351,9 @@ class Repository extends $pb.GeneratedMessage {
|
||||
@$pb.TagNumber(5)
|
||||
Remote ensureUpstream() => $_ensure(4);
|
||||
|
||||
/// The remote cherrypicks will be pushed to create a Pull Request.
|
||||
///
|
||||
/// This should be a mirror owned by the user conducting the release.
|
||||
@$pb.TagNumber(6)
|
||||
Remote get mirror => $_getN(5);
|
||||
@$pb.TagNumber(6)
|
||||
@ -286,9 +368,11 @@ class Repository extends $pb.GeneratedMessage {
|
||||
@$pb.TagNumber(6)
|
||||
Remote ensureMirror() => $_ensure(5);
|
||||
|
||||
/// Desired cherrypicks.
|
||||
@$pb.TagNumber(7)
|
||||
$core.List<Cherrypick> get cherrypicks => $_getList(6);
|
||||
|
||||
/// For the repository that has a dart_revision in a DEPS file.
|
||||
@$pb.TagNumber(8)
|
||||
$core.String get dartRevision => $_getSZ(7);
|
||||
@$pb.TagNumber(8)
|
||||
@ -301,6 +385,10 @@ class Repository extends $pb.GeneratedMessage {
|
||||
@$pb.TagNumber(8)
|
||||
void clearDartRevision() => clearField(8);
|
||||
|
||||
/// Name of local and remote branch for applying cherrypicks.
|
||||
///
|
||||
/// When the pull request is merged, all commits here will be squashed to a
|
||||
/// single commit on the [candidateBranch].
|
||||
@$pb.TagNumber(9)
|
||||
$core.String get workingBranch => $_getSZ(8);
|
||||
@$pb.TagNumber(9)
|
||||
@ -315,7 +403,51 @@ class Repository extends $pb.GeneratedMessage {
|
||||
}
|
||||
|
||||
class ConductorState extends $pb.GeneratedMessage {
|
||||
factory ConductorState() => create();
|
||||
factory ConductorState({
|
||||
$core.String? releaseChannel,
|
||||
$core.String? releaseVersion,
|
||||
Repository? engine,
|
||||
Repository? framework,
|
||||
$fixnum.Int64? createdDate,
|
||||
$fixnum.Int64? lastUpdatedDate,
|
||||
$core.Iterable<$core.String>? logs,
|
||||
ReleasePhase? currentPhase,
|
||||
$core.String? conductorVersion,
|
||||
ReleaseType? releaseType,
|
||||
}) {
|
||||
final $result = create();
|
||||
if (releaseChannel != null) {
|
||||
$result.releaseChannel = releaseChannel;
|
||||
}
|
||||
if (releaseVersion != null) {
|
||||
$result.releaseVersion = releaseVersion;
|
||||
}
|
||||
if (engine != null) {
|
||||
$result.engine = engine;
|
||||
}
|
||||
if (framework != null) {
|
||||
$result.framework = framework;
|
||||
}
|
||||
if (createdDate != null) {
|
||||
$result.createdDate = createdDate;
|
||||
}
|
||||
if (lastUpdatedDate != null) {
|
||||
$result.lastUpdatedDate = lastUpdatedDate;
|
||||
}
|
||||
if (logs != null) {
|
||||
$result.logs.addAll(logs);
|
||||
}
|
||||
if (currentPhase != null) {
|
||||
$result.currentPhase = currentPhase;
|
||||
}
|
||||
if (conductorVersion != null) {
|
||||
$result.conductorVersion = conductorVersion;
|
||||
}
|
||||
if (releaseType != null) {
|
||||
$result.releaseType = releaseType;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
ConductorState._() : super();
|
||||
factory ConductorState.fromBuffer($core.List<$core.int> i,
|
||||
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
|
||||
@ -336,7 +468,7 @@ class ConductorState extends $pb.GeneratedMessage {
|
||||
..pPS(8, _omitFieldNames ? '' : 'logs')
|
||||
..e<ReleasePhase>(9, _omitFieldNames ? '' : 'currentPhase', $pb.PbFieldType.OE,
|
||||
protoName: 'currentPhase',
|
||||
defaultOrMaker: ReleasePhase.APPLY_ENGINE_CHERRYPICKS,
|
||||
defaultOrMaker: ReleasePhase.APPLY_FRAMEWORK_CHERRYPICKS,
|
||||
valueOf: ReleasePhase.valueOf,
|
||||
enumValues: ReleasePhase.values)
|
||||
..aOS(10, _omitFieldNames ? '' : 'conductorVersion', protoName: 'conductorVersion')
|
||||
@ -368,6 +500,7 @@ class ConductorState extends $pb.GeneratedMessage {
|
||||
_defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<ConductorState>(create);
|
||||
static ConductorState? _defaultInstance;
|
||||
|
||||
/// One of 'stable', 'beta', or 'dev'
|
||||
@$pb.TagNumber(1)
|
||||
$core.String get releaseChannel => $_getSZ(0);
|
||||
@$pb.TagNumber(1)
|
||||
@ -380,6 +513,7 @@ class ConductorState extends $pb.GeneratedMessage {
|
||||
@$pb.TagNumber(1)
|
||||
void clearReleaseChannel() => clearField(1);
|
||||
|
||||
/// The name of the release.
|
||||
@$pb.TagNumber(2)
|
||||
$core.String get releaseVersion => $_getSZ(1);
|
||||
@$pb.TagNumber(2)
|
||||
@ -447,6 +581,7 @@ class ConductorState extends $pb.GeneratedMessage {
|
||||
@$pb.TagNumber(8)
|
||||
$core.List<$core.String> get logs => $_getList(6);
|
||||
|
||||
/// The current [ReleasePhase] that has yet to be completed.
|
||||
@$pb.TagNumber(9)
|
||||
ReleasePhase get currentPhase => $_getN(7);
|
||||
@$pb.TagNumber(9)
|
||||
@ -459,6 +594,8 @@ class ConductorState extends $pb.GeneratedMessage {
|
||||
@$pb.TagNumber(9)
|
||||
void clearCurrentPhase() => clearField(9);
|
||||
|
||||
/// A string used to validate that the current conductor is the same version
|
||||
/// that created the [ConductorState] object.
|
||||
@$pb.TagNumber(10)
|
||||
$core.String get conductorVersion => $_getSZ(8);
|
||||
@$pb.TagNumber(10)
|
||||
|
@ -8,7 +8,7 @@
|
||||
//
|
||||
// @dart = 2.12
|
||||
|
||||
// ignore_for_file: annotate_overrides, camel_case_types
|
||||
// ignore_for_file: annotate_overrides, camel_case_types, comment_references
|
||||
// ignore_for_file: constant_identifier_names, library_prefixes
|
||||
// ignore_for_file: non_constant_identifier_names, prefer_final_fields
|
||||
// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
|
||||
@ -18,22 +18,16 @@ import 'dart:core' as $core;
|
||||
import 'package:protobuf/protobuf.dart' as $pb;
|
||||
|
||||
class ReleasePhase extends $pb.ProtobufEnum {
|
||||
static const ReleasePhase APPLY_ENGINE_CHERRYPICKS =
|
||||
ReleasePhase._(0, _omitEnumNames ? '' : 'APPLY_ENGINE_CHERRYPICKS');
|
||||
static const ReleasePhase VERIFY_ENGINE_CI =
|
||||
ReleasePhase._(1, _omitEnumNames ? '' : 'VERIFY_ENGINE_CI');
|
||||
static const ReleasePhase APPLY_FRAMEWORK_CHERRYPICKS =
|
||||
ReleasePhase._(2, _omitEnumNames ? '' : 'APPLY_FRAMEWORK_CHERRYPICKS');
|
||||
ReleasePhase._(0, _omitEnumNames ? '' : 'APPLY_FRAMEWORK_CHERRYPICKS');
|
||||
static const ReleasePhase PUBLISH_VERSION =
|
||||
ReleasePhase._(3, _omitEnumNames ? '' : 'PUBLISH_VERSION');
|
||||
ReleasePhase._(1, _omitEnumNames ? '' : 'PUBLISH_VERSION');
|
||||
static const ReleasePhase VERIFY_RELEASE =
|
||||
ReleasePhase._(5, _omitEnumNames ? '' : 'VERIFY_RELEASE');
|
||||
ReleasePhase._(2, _omitEnumNames ? '' : 'VERIFY_RELEASE');
|
||||
static const ReleasePhase RELEASE_COMPLETED =
|
||||
ReleasePhase._(6, _omitEnumNames ? '' : 'RELEASE_COMPLETED');
|
||||
ReleasePhase._(3, _omitEnumNames ? '' : 'RELEASE_COMPLETED');
|
||||
|
||||
static const $core.List<ReleasePhase> values = <ReleasePhase>[
|
||||
APPLY_ENGINE_CHERRYPICKS,
|
||||
VERIFY_ENGINE_CI,
|
||||
APPLY_FRAMEWORK_CHERRYPICKS,
|
||||
PUBLISH_VERSION,
|
||||
VERIFY_RELEASE,
|
||||
@ -67,6 +61,9 @@ class CherrypickState extends $pb.ProtobufEnum {
|
||||
const CherrypickState._($core.int v, $core.String n) : super(v, n);
|
||||
}
|
||||
|
||||
/// The type of release that is being created.
|
||||
///
|
||||
/// This determines how the version will be calculated.
|
||||
class ReleaseType extends $pb.ProtobufEnum {
|
||||
static const ReleaseType STABLE_INITIAL =
|
||||
ReleaseType._(0, _omitEnumNames ? '' : 'STABLE_INITIAL');
|
||||
|
@ -8,7 +8,7 @@
|
||||
//
|
||||
// @dart = 2.12
|
||||
|
||||
// ignore_for_file: annotate_overrides, camel_case_types
|
||||
// ignore_for_file: annotate_overrides, camel_case_types, comment_references
|
||||
// ignore_for_file: constant_identifier_names, library_prefixes
|
||||
// ignore_for_file: non_constant_identifier_names, prefer_final_fields
|
||||
// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
|
||||
@ -21,24 +21,17 @@ import 'dart:typed_data' as $typed_data;
|
||||
const ReleasePhase$json = {
|
||||
'1': 'ReleasePhase',
|
||||
'2': [
|
||||
{'1': 'APPLY_ENGINE_CHERRYPICKS', '2': 0},
|
||||
{'1': 'VERIFY_ENGINE_CI', '2': 1},
|
||||
{'1': 'APPLY_FRAMEWORK_CHERRYPICKS', '2': 2},
|
||||
{'1': 'PUBLISH_VERSION', '2': 3},
|
||||
{'1': 'VERIFY_RELEASE', '2': 5},
|
||||
{'1': 'RELEASE_COMPLETED', '2': 6},
|
||||
],
|
||||
'4': [
|
||||
{'1': 4, '2': 4},
|
||||
{'1': 'APPLY_FRAMEWORK_CHERRYPICKS', '2': 0},
|
||||
{'1': 'PUBLISH_VERSION', '2': 1},
|
||||
{'1': 'VERIFY_RELEASE', '2': 2},
|
||||
{'1': 'RELEASE_COMPLETED', '2': 3},
|
||||
],
|
||||
};
|
||||
|
||||
/// Descriptor for `ReleasePhase`. Decode as a `google.protobuf.EnumDescriptorProto`.
|
||||
final $typed_data.Uint8List releasePhaseDescriptor = $convert
|
||||
.base64Decode('CgxSZWxlYXNlUGhhc2USHAoYQVBQTFlfRU5HSU5FX0NIRVJSWVBJQ0tTEAASFAoQVkVSSUZZX0'
|
||||
'VOR0lORV9DSRABEh8KG0FQUExZX0ZSQU1FV09SS19DSEVSUllQSUNLUxACEhMKD1BVQkxJU0hf'
|
||||
'VkVSU0lPThADEhIKDlZFUklGWV9SRUxFQVNFEAUSFQoRUkVMRUFTRV9DT01QTEVURUQQBiIECA'
|
||||
'QQBA==');
|
||||
.base64Decode('CgxSZWxlYXNlUGhhc2USHwobQVBQTFlfRlJBTUVXT1JLX0NIRVJSWVBJQ0tTEAASEwoPUFVCTE'
|
||||
'lTSF9WRVJTSU9OEAESEgoOVkVSSUZZX1JFTEVBU0UQAhIVChFSRUxFQVNFX0NPTVBMRVRFRBAD');
|
||||
|
||||
@$core.Deprecated('Use cherrypickStateDescriptor instead')
|
||||
const CherrypickState$json = {
|
||||
|
@ -8,7 +8,7 @@
|
||||
//
|
||||
// @dart = 2.12
|
||||
|
||||
// ignore_for_file: annotate_overrides, camel_case_types
|
||||
// ignore_for_file: annotate_overrides, camel_case_types, comment_references
|
||||
// ignore_for_file: constant_identifier_names
|
||||
// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
|
||||
// ignore_for_file: non_constant_identifier_names, prefer_final_fields
|
||||
|
@ -9,24 +9,16 @@ message Remote {
|
||||
}
|
||||
|
||||
enum ReleasePhase {
|
||||
// Release was started with `conductor start` and repositories cloned.
|
||||
APPLY_ENGINE_CHERRYPICKS = 0;
|
||||
|
||||
// Verify engine CI is green before opening framework PR.
|
||||
VERIFY_ENGINE_CI = 1;
|
||||
|
||||
APPLY_FRAMEWORK_CHERRYPICKS = 2;
|
||||
APPLY_FRAMEWORK_CHERRYPICKS = 0;
|
||||
|
||||
// Git tag applied to framework RC branch HEAD and pushed upstream.
|
||||
PUBLISH_VERSION = 3;
|
||||
|
||||
reserved 4; // Formerly PUBLISH_CHANNEL, merged into PUBLISH_VERSION.
|
||||
PUBLISH_VERSION = 1;
|
||||
|
||||
// Package artifacts verified to exist on cloud storage.
|
||||
VERIFY_RELEASE = 5;
|
||||
VERIFY_RELEASE = 2;
|
||||
|
||||
// There is no further work to be done.
|
||||
RELEASE_COMPLETED = 6;
|
||||
RELEASE_COMPLETED = 3;
|
||||
}
|
||||
|
||||
enum CherrypickState {
|
||||
@ -100,7 +92,7 @@ message Repository {
|
||||
// Desired cherrypicks.
|
||||
repeated Cherrypick cherrypicks = 7;
|
||||
|
||||
// Only for engine repositories.
|
||||
// For the repository that has a dart_revision in a DEPS file.
|
||||
string dartRevision = 8;
|
||||
|
||||
// Name of local and remote branch for applying cherrypicks.
|
||||
|
@ -683,33 +683,9 @@ class FrameworkRepository extends Repository {
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Update this framework's engine version file.
|
||||
///
|
||||
/// Returns [true] if the version file was updated and a commit is needed.
|
||||
Future<bool> updateEngineRevision(
|
||||
String newEngine, {
|
||||
@visibleForTesting File? engineVersionFile,
|
||||
}) async {
|
||||
assert(newEngine.isNotEmpty);
|
||||
engineVersionFile ??= (await checkoutDirectory)
|
||||
.childDirectory('bin')
|
||||
.childDirectory('internal')
|
||||
.childFile('engine.version');
|
||||
assert(engineVersionFile.existsSync());
|
||||
final String oldEngine = engineVersionFile.readAsStringSync();
|
||||
if (oldEngine.trim() == newEngine.trim()) {
|
||||
stdio.printTrace(
|
||||
'Tried to update the engine revision but version file is already up to date at: $newEngine',
|
||||
);
|
||||
return false;
|
||||
}
|
||||
stdio.printStatus('Updating engine revision from $oldEngine to $newEngine');
|
||||
engineVersionFile.writeAsStringSync(
|
||||
// Version files have trailing newlines
|
||||
'${newEngine.trim()}\n',
|
||||
flush: true,
|
||||
);
|
||||
return true;
|
||||
/// Update the `dart_revision` entry in the DEPS file.
|
||||
Future<void> updateDartRevision(String newRevision, {@visibleForTesting File? depsFile}) async {
|
||||
return _updateDartRevision(this, newRevision, depsFile: depsFile);
|
||||
}
|
||||
}
|
||||
|
||||
@ -770,63 +746,45 @@ class HostFrameworkRepository extends FrameworkRepository {
|
||||
}
|
||||
}
|
||||
|
||||
class EngineRepository extends Repository {
|
||||
EngineRepository(
|
||||
this.checkouts, {
|
||||
super.name = 'engine',
|
||||
String super.initialRef = EngineRepository.defaultBranch,
|
||||
super.upstreamRemote = const Remote.upstream(EngineRepository.defaultUpstream),
|
||||
super.localUpstream,
|
||||
super.previousCheckoutLocation,
|
||||
super.mirrorRemote,
|
||||
List<String>? additionalRequiredLocalBranches,
|
||||
}) : super(
|
||||
fileSystem: checkouts.fileSystem,
|
||||
parentDirectory: checkouts.directory,
|
||||
platform: checkouts.platform,
|
||||
processManager: checkouts.processManager,
|
||||
stdio: checkouts.stdio,
|
||||
requiredLocalBranches: additionalRequiredLocalBranches ?? const <String>[],
|
||||
);
|
||||
|
||||
final Checkouts checkouts;
|
||||
|
||||
static const String defaultUpstream = 'git@github.com:flutter/engine.git';
|
||||
static const String defaultBranch = 'main';
|
||||
|
||||
/// Update the `dart_revision` entry in the DEPS file.
|
||||
Future<void> updateDartRevision(String newRevision, {@visibleForTesting File? depsFile}) async {
|
||||
assert(newRevision.length == 40);
|
||||
depsFile ??= (await checkoutDirectory).childFile('DEPS');
|
||||
final String fileContent = depsFile.readAsStringSync();
|
||||
final RegExp dartPattern = RegExp("[ ]+'dart_revision': '([a-z0-9]{40})',");
|
||||
final Iterable<RegExpMatch> allMatches = dartPattern.allMatches(fileContent);
|
||||
if (allMatches.length != 1) {
|
||||
throw ConductorException(
|
||||
'Unexpected content in the DEPS file at ${depsFile.path}\n'
|
||||
'Expected to find pattern ${dartPattern.pattern} 1 times, but got '
|
||||
'${allMatches.length}.',
|
||||
);
|
||||
}
|
||||
final String updatedFileContent = fileContent.replaceFirst(
|
||||
dartPattern,
|
||||
" 'dart_revision': '$newRevision',",
|
||||
);
|
||||
|
||||
depsFile.writeAsStringSync(updatedFileContent, flush: true);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Repository> cloneRepository(String? cloneName) async {
|
||||
assert(localUpstream);
|
||||
cloneName ??= 'clone-of-$name';
|
||||
return EngineRepository(
|
||||
checkouts,
|
||||
name: cloneName,
|
||||
upstreamRemote: Remote.upstream('file://${(await checkoutDirectory).path}/'),
|
||||
);
|
||||
}
|
||||
}
|
||||
//class EngineRepository extends Repository {
|
||||
// EngineRepository(
|
||||
// this.checkouts, {
|
||||
// super.name = 'engine',
|
||||
// String super.initialRef = EngineRepository.defaultBranch,
|
||||
// super.upstreamRemote = const Remote.upstream(EngineRepository.defaultUpstream),
|
||||
// super.localUpstream,
|
||||
// super.previousCheckoutLocation,
|
||||
// super.mirrorRemote,
|
||||
// List<String>? additionalRequiredLocalBranches,
|
||||
// }) : super(
|
||||
// fileSystem: checkouts.fileSystem,
|
||||
// parentDirectory: checkouts.directory,
|
||||
// platform: checkouts.platform,
|
||||
// processManager: checkouts.processManager,
|
||||
// stdio: checkouts.stdio,
|
||||
// requiredLocalBranches: additionalRequiredLocalBranches ?? const <String>[],
|
||||
// );
|
||||
//
|
||||
// final Checkouts checkouts;
|
||||
//
|
||||
// static const String defaultUpstream = 'git@github.com:flutter/engine.git';
|
||||
// static const String defaultBranch = 'main';
|
||||
//
|
||||
// /// Update the `dart_revision` entry in the DEPS file.
|
||||
// Future<void> updateDartRevision(String newRevision, {@visibleForTesting File? depsFile}) =>
|
||||
// _updateDartRevision(this, newRevision, depsFile: depsFile);
|
||||
//
|
||||
// @override
|
||||
// Future<Repository> cloneRepository(String? cloneName) async {
|
||||
// assert(localUpstream);
|
||||
// cloneName ??= 'clone-of-$name';
|
||||
// return EngineRepository(
|
||||
// checkouts,
|
||||
// name: cloneName,
|
||||
// upstreamRemote: Remote.upstream('file://${(await checkoutDirectory).path}/'),
|
||||
// );
|
||||
// }
|
||||
//}
|
||||
|
||||
/// An enum of all the repositories that the Conductor supports.
|
||||
enum RepositoryType { framework, engine }
|
||||
@ -851,3 +809,28 @@ class Checkouts {
|
||||
final ProcessManager processManager;
|
||||
final Stdio stdio;
|
||||
}
|
||||
|
||||
Future<void> _updateDartRevision(
|
||||
Repository repo,
|
||||
String newRevision, {
|
||||
@visibleForTesting File? depsFile,
|
||||
}) async {
|
||||
assert(newRevision.length == 40);
|
||||
depsFile ??= (await repo.checkoutDirectory).childFile('DEPS');
|
||||
final String fileContent = depsFile.readAsStringSync();
|
||||
final RegExp dartPattern = RegExp("[ ]+'dart_revision': '([a-z0-9]{40})',");
|
||||
final Iterable<RegExpMatch> allMatches = dartPattern.allMatches(fileContent);
|
||||
if (allMatches.length != 1) {
|
||||
throw ConductorException(
|
||||
'Unexpected content in the DEPS file at ${depsFile.path}\n'
|
||||
'Expected to find pattern ${dartPattern.pattern} 1 times, but got '
|
||||
'${allMatches.length}.',
|
||||
);
|
||||
}
|
||||
final String updatedFileContent = fileContent.replaceFirst(
|
||||
dartPattern,
|
||||
" 'dart_revision': '$newRevision',",
|
||||
);
|
||||
|
||||
depsFile.writeAsStringSync(updatedFileContent, flush: true);
|
||||
}
|
||||
|
@ -65,12 +65,6 @@ class StartCommand extends Command<void> {
|
||||
help: 'Configurable Framework repo upstream remote. Primarily for testing.',
|
||||
hide: true,
|
||||
);
|
||||
argParser.addOption(
|
||||
kEngineUpstreamOption,
|
||||
defaultsTo: EngineRepository.defaultUpstream,
|
||||
help: 'Configurable Engine repo upstream remote. Primarily for testing.',
|
||||
hide: true,
|
||||
);
|
||||
argParser.addOption(
|
||||
kStateOption,
|
||||
defaultsTo: defaultPath,
|
||||
@ -119,9 +113,6 @@ class StartCommand extends Command<void> {
|
||||
allowNull: true,
|
||||
) ??
|
||||
'git@github.com:$githubUsername/flutter.git';
|
||||
final String engineUpstream =
|
||||
getValueFromEnvOrArgs(kEngineUpstreamOption, argumentResults, platform.environment)!;
|
||||
final String engineMirror = 'git@github.com:$githubUsername/engine.git';
|
||||
final String candidateBranch =
|
||||
getValueFromEnvOrArgs(kCandidateOption, argumentResults, platform.environment)!;
|
||||
final String releaseChannel =
|
||||
@ -151,8 +142,6 @@ class StartCommand extends Command<void> {
|
||||
candidateBranch: candidateBranch,
|
||||
checkouts: checkouts,
|
||||
dartRevision: dartRevision,
|
||||
engineMirror: engineMirror,
|
||||
engineUpstream: engineUpstream,
|
||||
conductorVersion: conductorVersion,
|
||||
frameworkMirror: frameworkMirror,
|
||||
frameworkUpstream: frameworkUpstream,
|
||||
@ -183,8 +172,6 @@ class StartContext extends Context {
|
||||
StartContext({
|
||||
required this.candidateBranch,
|
||||
required this.dartRevision,
|
||||
required this.engineMirror,
|
||||
required this.engineUpstream,
|
||||
required this.frameworkMirror,
|
||||
required this.frameworkUpstream,
|
||||
required this.conductorVersion,
|
||||
@ -196,12 +183,6 @@ class StartContext extends Context {
|
||||
this.force = false,
|
||||
this.versionOverride,
|
||||
}) : git = Git(processManager),
|
||||
engine = EngineRepository(
|
||||
checkouts,
|
||||
initialRef: 'upstream/$candidateBranch',
|
||||
upstreamRemote: Remote.upstream(engineUpstream),
|
||||
mirrorRemote: Remote.mirror(engineMirror),
|
||||
),
|
||||
framework = FrameworkRepository(
|
||||
checkouts,
|
||||
initialRef: 'upstream/$candidateBranch',
|
||||
@ -211,8 +192,6 @@ class StartContext extends Context {
|
||||
|
||||
final String candidateBranch;
|
||||
final String? dartRevision;
|
||||
final String engineMirror;
|
||||
final String engineUpstream;
|
||||
final String frameworkMirror;
|
||||
final String frameworkUpstream;
|
||||
final String conductorVersion;
|
||||
@ -225,7 +204,6 @@ class StartContext extends Context {
|
||||
/// If validations should be overridden.
|
||||
final bool force;
|
||||
|
||||
final EngineRepository engine;
|
||||
final FrameworkRepository framework;
|
||||
|
||||
/// Determine which part of the version to increment in the next release.
|
||||
@ -272,71 +250,8 @@ class StartContext extends Context {
|
||||
// Create a new branch so that we don't accidentally push to upstream
|
||||
// candidateBranch.
|
||||
final String workingBranchName = 'cherrypicks-$candidateBranch';
|
||||
await engine.newBranch(workingBranchName);
|
||||
|
||||
if (dartRevision != null && dartRevision!.isNotEmpty) {
|
||||
await engine.updateDartRevision(dartRevision!);
|
||||
await engine.commit('Update Dart SDK to $dartRevision', addFirst: true);
|
||||
}
|
||||
|
||||
final String engineHead = await engine.reverseParse('HEAD');
|
||||
state.engine =
|
||||
(pb.Repository.create()
|
||||
..candidateBranch = candidateBranch
|
||||
..workingBranch = workingBranchName
|
||||
..startingGitHead = engineHead
|
||||
..currentGitHead = engineHead
|
||||
..checkoutPath = (await engine.checkoutDirectory).path
|
||||
..upstream =
|
||||
(pb.Remote.create()
|
||||
..name = 'upstream'
|
||||
..url = engine.upstreamRemote.url)
|
||||
..mirror =
|
||||
(pb.Remote.create()
|
||||
..name = 'mirror'
|
||||
..url = engine.mirrorRemote!.url));
|
||||
if (dartRevision != null && dartRevision!.isNotEmpty) {
|
||||
state.engine.dartRevision = dartRevision!;
|
||||
}
|
||||
|
||||
await framework.newBranch(workingBranchName);
|
||||
|
||||
// Get framework version
|
||||
final Version lastVersion = Version.fromString(
|
||||
await framework.getFullTag(framework.upstreamRemote.name, candidateBranch, exact: false),
|
||||
);
|
||||
|
||||
final String frameworkHead = await framework.reverseParse('HEAD');
|
||||
final String branchPoint = await framework.branchPoint(
|
||||
'${framework.upstreamRemote.name}/$candidateBranch',
|
||||
'${framework.upstreamRemote.name}/${FrameworkRepository.defaultBranch}',
|
||||
);
|
||||
final bool atBranchPoint = branchPoint == frameworkHead;
|
||||
|
||||
final ReleaseType releaseType = computeReleaseType(lastVersion, atBranchPoint);
|
||||
state.releaseType = releaseType;
|
||||
|
||||
try {
|
||||
lastVersion.ensureValid(candidateBranch, releaseType);
|
||||
} on ConductorException catch (e) {
|
||||
// Let the user know, but resume execution
|
||||
stdio.printError(e.message);
|
||||
}
|
||||
|
||||
Version nextVersion;
|
||||
if (versionOverride != null) {
|
||||
nextVersion = versionOverride!;
|
||||
} else {
|
||||
nextVersion = calculateNextVersion(lastVersion, releaseType);
|
||||
nextVersion = await ensureBranchPointTagged(
|
||||
branchPoint: branchPoint,
|
||||
requestedVersion: nextVersion,
|
||||
framework: framework,
|
||||
);
|
||||
}
|
||||
|
||||
state.releaseVersion = nextVersion.toString();
|
||||
|
||||
state.framework =
|
||||
(pb.Repository.create()
|
||||
..candidateBranch = candidateBranch
|
||||
@ -353,7 +268,46 @@ class StartContext extends Context {
|
||||
..name = 'mirror'
|
||||
..url = framework.mirrorRemote!.url));
|
||||
|
||||
state.currentPhase = ReleasePhase.APPLY_ENGINE_CHERRYPICKS;
|
||||
if (dartRevision != null && dartRevision!.isNotEmpty) {
|
||||
// In the monorepo, the DEPS file is in flutter/flutter
|
||||
state.framework.dartRevision = dartRevision!;
|
||||
}
|
||||
|
||||
// Get framework version
|
||||
final Version lastVersion = Version.fromString(
|
||||
await framework.getFullTag(framework.upstreamRemote.name, candidateBranch, exact: false),
|
||||
);
|
||||
|
||||
final String branchPoint = await framework.branchPoint(
|
||||
'${framework.upstreamRemote.name}/$candidateBranch',
|
||||
'${framework.upstreamRemote.name}/${FrameworkRepository.defaultBranch}',
|
||||
);
|
||||
final bool atBranchPoint = branchPoint == frameworkHead;
|
||||
|
||||
final ReleaseType releaseType = computeReleaseType(lastVersion, atBranchPoint);
|
||||
state.releaseType = releaseType;
|
||||
|
||||
Version nextVersion;
|
||||
if (versionOverride != null) {
|
||||
nextVersion = versionOverride!;
|
||||
} else {
|
||||
nextVersion = calculateNextVersion(lastVersion, releaseType);
|
||||
nextVersion = await ensureBranchPointTagged(
|
||||
branchPoint: branchPoint,
|
||||
requestedVersion: nextVersion,
|
||||
framework: framework,
|
||||
);
|
||||
}
|
||||
|
||||
await framework.newBranch(workingBranchName);
|
||||
if (dartRevision != null && dartRevision!.isNotEmpty) {
|
||||
await framework.updateDartRevision(dartRevision!);
|
||||
await framework.commit('Update Dart SDK to $dartRevision', addFirst: true);
|
||||
}
|
||||
|
||||
state.releaseVersion = nextVersion.toString();
|
||||
|
||||
state.currentPhase = ReleasePhase.APPLY_FRAMEWORK_CHERRYPICKS;
|
||||
|
||||
state.conductorVersion = conductorVersion;
|
||||
|
||||
|
@ -82,26 +82,6 @@ String presentState(pb.ConductorState state) {
|
||||
buffer.writeln(
|
||||
'Last updated at: ${DateTime.fromMillisecondsSinceEpoch(state.lastUpdatedDate.toInt())}',
|
||||
);
|
||||
buffer.writeln();
|
||||
buffer.writeln('Engine Repo');
|
||||
buffer.writeln('\tCandidate branch: ${state.engine.candidateBranch}');
|
||||
buffer.writeln('\tStarting git HEAD: ${state.engine.startingGitHead}');
|
||||
buffer.writeln('\tCurrent git HEAD: ${state.engine.currentGitHead}');
|
||||
buffer.writeln('\tPath to checkout: ${state.engine.checkoutPath}');
|
||||
buffer.writeln(
|
||||
'\tPost-submit LUCI dashboard: ${luciConsoleLink(state.engine.candidateBranch, 'engine')}',
|
||||
);
|
||||
if (state.engine.cherrypicks.isNotEmpty) {
|
||||
buffer.writeln('${state.engine.cherrypicks.length} Engine Cherrypicks:');
|
||||
for (final pb.Cherrypick cherrypick in state.engine.cherrypicks) {
|
||||
buffer.writeln('\t${cherrypick.trunkRevision} - ${cherrypick.state}');
|
||||
}
|
||||
} else {
|
||||
buffer.writeln('0 Engine cherrypicks.');
|
||||
}
|
||||
if (state.engine.dartRevision.isNotEmpty) {
|
||||
buffer.writeln('New Dart SDK revision: ${state.engine.dartRevision}');
|
||||
}
|
||||
buffer.writeln('Framework Repo');
|
||||
buffer.writeln('\tCandidate branch: ${state.framework.candidateBranch}');
|
||||
buffer.writeln('\tStarting git HEAD: ${state.framework.startingGitHead}');
|
||||
@ -118,6 +98,9 @@ String presentState(pb.ConductorState state) {
|
||||
} else {
|
||||
buffer.writeln('0 Framework cherrypicks.');
|
||||
}
|
||||
if (state.framework.dartRevision.isNotEmpty) {
|
||||
buffer.writeln('New Dart SDK revision: ${state.engine.dartRevision}');
|
||||
}
|
||||
buffer.writeln();
|
||||
if (state.currentPhase == ReleasePhase.VERIFY_RELEASE) {
|
||||
buffer.writeln(
|
||||
@ -156,43 +139,6 @@ String presentPhases(ReleasePhase currentPhase) {
|
||||
|
||||
String phaseInstructions(pb.ConductorState state) {
|
||||
switch (state.currentPhase) {
|
||||
case ReleasePhase.APPLY_ENGINE_CHERRYPICKS:
|
||||
if (state.engine.cherrypicks.isEmpty) {
|
||||
return <String>[
|
||||
'There are no engine cherrypicks, so issue `conductor next` to continue',
|
||||
'to the next step.',
|
||||
'\n',
|
||||
'******************************************************',
|
||||
'* Create a new entry in http://go/release-eng-retros *',
|
||||
'******************************************************',
|
||||
].join('\n');
|
||||
}
|
||||
return <String>[
|
||||
'You must now manually apply the following engine cherrypicks to the checkout',
|
||||
'at ${state.engine.checkoutPath} in order:',
|
||||
for (final pb.Cherrypick cherrypick in state.engine.cherrypicks)
|
||||
'\t${cherrypick.trunkRevision}',
|
||||
'See ${globals.kReleaseDocumentationUrl} for more information.',
|
||||
].join('\n');
|
||||
case ReleasePhase.VERIFY_ENGINE_CI:
|
||||
if (!requiresEnginePR(state)) {
|
||||
return 'You must verify engine CI has passed: '
|
||||
'${luciConsoleLink(state.engine.candidateBranch, 'engine')}';
|
||||
}
|
||||
// User's working branch was pushed to their mirror, but a PR needs to be
|
||||
// opened on GitHub.
|
||||
final String newPrLink = globals.getNewPrLink(
|
||||
userName: githubAccount(state.engine.mirror.url),
|
||||
repoName: 'engine',
|
||||
state: state,
|
||||
);
|
||||
final String consoleLink = luciConsoleLink(state.engine.candidateBranch, 'engine');
|
||||
return <String>[
|
||||
'Your working branch ${state.engine.workingBranch} was pushed to your mirror.',
|
||||
'You must now open a pull request at $newPrLink, verify pre-submit CI',
|
||||
'builds on your engine pull request are successful, merge your pull request,',
|
||||
'validate post-submit CI at $consoleLink.',
|
||||
].join('\n');
|
||||
case ReleasePhase.APPLY_FRAMEWORK_CHERRYPICKS:
|
||||
final List<pb.Cherrypick> outstandingCherrypicks =
|
||||
state.framework.cherrypicks.where((pb.Cherrypick cp) {
|
||||
@ -280,8 +226,6 @@ ReleasePhase getNextPhase(ReleasePhase currentPhase) {
|
||||
switch (currentPhase) {
|
||||
case ReleasePhase.PUBLISH_VERSION:
|
||||
return ReleasePhase.VERIFY_RELEASE;
|
||||
case ReleasePhase.APPLY_ENGINE_CHERRYPICKS:
|
||||
case ReleasePhase.VERIFY_ENGINE_CI:
|
||||
case ReleasePhase.APPLY_FRAMEWORK_CHERRYPICKS:
|
||||
case ReleasePhase.VERIFY_RELEASE:
|
||||
case ReleasePhase.RELEASE_COMPLETED:
|
||||
|
@ -22,11 +22,8 @@ void main() {
|
||||
const String checkoutsParentDirectory = '$flutterRoot/dev/conductor';
|
||||
const String candidateBranch = 'flutter-1.2-candidate.3';
|
||||
const String workingBranch = 'cherrypicks-$candidateBranch';
|
||||
const String remoteUrl = 'https://github.com/org/repo.git';
|
||||
const String revision1 = 'd3af60d18e01fcb36e0c0fa06c8502e4935ed095';
|
||||
const String revision2 = 'f99555c1e1392bf2a8135056b9446680c2af4ddf';
|
||||
const String revision3 = 'ffffffffffffffffffffffffffffffffffffffff';
|
||||
const String revision4 = '280e23318a0d8341415c66aa32581352a421d974';
|
||||
const String releaseVersion = '1.2.0-3.0.pre';
|
||||
const String releaseChannel = 'beta';
|
||||
const String stateFile = '/state-file.json';
|
||||
@ -73,226 +70,6 @@ void main() {
|
||||
);
|
||||
});
|
||||
|
||||
group('APPLY_ENGINE_CHERRYPICKS to VERIFY_ENGINE_CI', () {
|
||||
test('confirms to stdout when all engine cherrypicks were auto-applied', () async {
|
||||
stdio.stdin.add('n');
|
||||
final File ciYaml = fileSystem.file('$checkoutsParentDirectory/engine/.ci.yaml')
|
||||
..createSync(recursive: true);
|
||||
_initializeCiYamlFile(ciYaml);
|
||||
final FakeProcessManager processManager = FakeProcessManager.empty();
|
||||
final FakePlatform platform = FakePlatform(
|
||||
environment: <String, String>{
|
||||
'HOME': <String>['path', 'to', 'home'].join(localPathSeparator),
|
||||
},
|
||||
operatingSystem: localOperatingSystem,
|
||||
pathSeparator: localPathSeparator,
|
||||
);
|
||||
final pb.ConductorState state =
|
||||
(pb.ConductorState.create()
|
||||
..releaseChannel = releaseChannel
|
||||
..engine =
|
||||
(pb.Repository.create()
|
||||
..candidateBranch = candidateBranch
|
||||
..cherrypicks.add(
|
||||
pb.Cherrypick.create()
|
||||
..trunkRevision = 'abc123'
|
||||
..state = pb.CherrypickState.COMPLETED,
|
||||
)
|
||||
..checkoutPath = fileSystem.path.join(checkoutsParentDirectory, 'engine')
|
||||
..workingBranch = workingBranch
|
||||
..upstream =
|
||||
(pb.Remote.create()
|
||||
..name = 'upstream'
|
||||
..url = remoteUrl)
|
||||
..mirror =
|
||||
(pb.Remote.create()
|
||||
..name = 'mirror'
|
||||
..url = remoteUrl))
|
||||
..currentPhase = ReleasePhase.APPLY_ENGINE_CHERRYPICKS);
|
||||
writeStateToFile(fileSystem.file(stateFile), state, <String>[]);
|
||||
final Checkouts checkouts = Checkouts(
|
||||
fileSystem: fileSystem,
|
||||
parentDirectory: fileSystem.directory(checkoutsParentDirectory)
|
||||
..createSync(recursive: true),
|
||||
platform: platform,
|
||||
processManager: processManager,
|
||||
stdio: stdio,
|
||||
);
|
||||
final CommandRunner<void> runner = createRunner(checkouts: checkouts);
|
||||
await runner.run(<String>['next', '--$kStateOption', stateFile]);
|
||||
|
||||
expect(processManager, hasNoRemainingExpectations);
|
||||
expect(
|
||||
stdio.stdout,
|
||||
contains('All engine cherrypicks have been auto-applied by the conductor'),
|
||||
);
|
||||
});
|
||||
|
||||
test('updates lastPhase if user responds yes', () async {
|
||||
const String remoteUrl = 'https://github.com/org/repo.git';
|
||||
const String releaseChannel = 'beta';
|
||||
stdio.stdin.add('y');
|
||||
final FakeProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
|
||||
const FakeCommand(command: <String>['git', 'fetch', 'upstream']),
|
||||
FakeCommand(
|
||||
command: const <String>['git', 'checkout', workingBranch],
|
||||
onRun: (_) {
|
||||
final File file = fileSystem.file('$checkoutsParentDirectory/engine/.ci.yaml')
|
||||
..createSync(recursive: true);
|
||||
_initializeCiYamlFile(file);
|
||||
},
|
||||
),
|
||||
const FakeCommand(
|
||||
command: <String>['git', 'push', 'mirror', 'HEAD:refs/heads/$workingBranch'],
|
||||
),
|
||||
]);
|
||||
final FakePlatform platform = FakePlatform(
|
||||
environment: <String, String>{
|
||||
'HOME': <String>['path', 'to', 'home'].join(localPathSeparator),
|
||||
},
|
||||
operatingSystem: localOperatingSystem,
|
||||
pathSeparator: localPathSeparator,
|
||||
);
|
||||
final pb.ConductorState state =
|
||||
(pb.ConductorState.create()
|
||||
..currentPhase = ReleasePhase.APPLY_ENGINE_CHERRYPICKS
|
||||
..engine =
|
||||
(pb.Repository.create()
|
||||
..candidateBranch = candidateBranch
|
||||
..checkoutPath = fileSystem.path.join(checkoutsParentDirectory, 'engine')
|
||||
..cherrypicks.add(
|
||||
pb.Cherrypick.create()
|
||||
..trunkRevision = revision2
|
||||
..state = pb.CherrypickState.PENDING,
|
||||
)
|
||||
..workingBranch = workingBranch
|
||||
..upstream =
|
||||
(pb.Remote.create()
|
||||
..name = 'upstream'
|
||||
..url = remoteUrl)
|
||||
..mirror =
|
||||
(pb.Remote.create()
|
||||
..name = 'mirror'
|
||||
..url = remoteUrl))
|
||||
..releaseChannel = releaseChannel
|
||||
..releaseVersion = releaseVersion);
|
||||
writeStateToFile(fileSystem.file(stateFile), state, <String>[]);
|
||||
// engine dir is expected to already exist
|
||||
fileSystem
|
||||
.directory(checkoutsParentDirectory)
|
||||
.childDirectory('engine')
|
||||
.createSync(recursive: true);
|
||||
final Checkouts checkouts = Checkouts(
|
||||
fileSystem: fileSystem,
|
||||
parentDirectory: fileSystem.directory(checkoutsParentDirectory),
|
||||
platform: platform,
|
||||
processManager: processManager,
|
||||
stdio: stdio,
|
||||
);
|
||||
final CommandRunner<void> runner = createRunner(checkouts: checkouts);
|
||||
await runner.run(<String>['next', '--$kStateOption', stateFile]);
|
||||
|
||||
final pb.ConductorState finalState = readStateFromFile(fileSystem.file(stateFile));
|
||||
|
||||
expect(processManager, hasNoRemainingExpectations);
|
||||
expect(
|
||||
stdio.stdout,
|
||||
contains(
|
||||
'You must now open a pull request at https://github.com/flutter/engine/compare/flutter-1.2-candidate.3...org:cherrypicks-flutter-1.2-candidate.3?expand=1',
|
||||
),
|
||||
);
|
||||
expect(
|
||||
stdio.stdout,
|
||||
contains(
|
||||
'Are you ready to push your engine branch to the repository $remoteUrl? (y/n) ',
|
||||
),
|
||||
);
|
||||
expect(finalState.currentPhase, ReleasePhase.VERIFY_ENGINE_CI);
|
||||
expect(stdio.error, isEmpty);
|
||||
});
|
||||
});
|
||||
|
||||
group('VERIFY_ENGINE_CI to APPLY_FRAMEWORK_CHERRYPICKS', () {
|
||||
late pb.ConductorState state;
|
||||
late FakeProcessManager processManager;
|
||||
late FakePlatform platform;
|
||||
|
||||
setUp(() {
|
||||
state =
|
||||
(pb.ConductorState.create()
|
||||
..releaseChannel = releaseChannel
|
||||
..engine =
|
||||
(pb.Repository.create()
|
||||
..cherrypicks.add(
|
||||
pb.Cherrypick.create()
|
||||
..trunkRevision = 'abc123'
|
||||
..state = pb.CherrypickState.PENDING,
|
||||
)
|
||||
..candidateBranch = 'flutter-1.0-candidate.0')
|
||||
..currentPhase = ReleasePhase.VERIFY_ENGINE_CI);
|
||||
|
||||
processManager = FakeProcessManager.empty();
|
||||
|
||||
platform = FakePlatform(
|
||||
environment: <String, String>{
|
||||
'HOME': <String>['path', 'to', 'home'].join(localPathSeparator),
|
||||
},
|
||||
operatingSystem: localOperatingSystem,
|
||||
pathSeparator: localPathSeparator,
|
||||
);
|
||||
});
|
||||
|
||||
test('does not update currentPhase if user responds no', () async {
|
||||
stdio.stdin.add('n');
|
||||
writeStateToFile(fileSystem.file(stateFile), state, <String>[]);
|
||||
final Checkouts checkouts = Checkouts(
|
||||
fileSystem: fileSystem,
|
||||
parentDirectory: fileSystem.directory(checkoutsParentDirectory)
|
||||
..createSync(recursive: true),
|
||||
platform: platform,
|
||||
processManager: processManager,
|
||||
stdio: stdio,
|
||||
);
|
||||
final CommandRunner<void> runner = createRunner(checkouts: checkouts);
|
||||
await runner.run(<String>['next', '--$kStateOption', stateFile]);
|
||||
|
||||
final pb.ConductorState finalState = readStateFromFile(fileSystem.file(stateFile));
|
||||
|
||||
expect(processManager, hasNoRemainingExpectations);
|
||||
expect(stdio.stdout, contains('Has CI passed for the engine PR?'));
|
||||
expect(finalState.currentPhase, ReleasePhase.VERIFY_ENGINE_CI);
|
||||
expect(stdio.error.contains('Aborting command.'), true);
|
||||
});
|
||||
|
||||
test('updates currentPhase if user responds yes', () async {
|
||||
stdio.stdin.add('y');
|
||||
final FakePlatform platform = FakePlatform(
|
||||
environment: <String, String>{
|
||||
'HOME': <String>['path', 'to', 'home'].join(localPathSeparator),
|
||||
},
|
||||
operatingSystem: localOperatingSystem,
|
||||
pathSeparator: localPathSeparator,
|
||||
);
|
||||
writeStateToFile(fileSystem.file(stateFile), state, <String>[]);
|
||||
final Checkouts checkouts = Checkouts(
|
||||
fileSystem: fileSystem,
|
||||
parentDirectory: fileSystem.directory(checkoutsParentDirectory)
|
||||
..createSync(recursive: true),
|
||||
platform: platform,
|
||||
processManager: processManager,
|
||||
stdio: stdio,
|
||||
);
|
||||
final CommandRunner<void> runner = createRunner(checkouts: checkouts);
|
||||
await runner.run(<String>['next', '--$kStateOption', stateFile]);
|
||||
|
||||
final pb.ConductorState finalState = readStateFromFile(fileSystem.file(stateFile));
|
||||
|
||||
expect(processManager, hasNoRemainingExpectations);
|
||||
expect(stdio.stdout, contains('Has CI passed for the engine PR?'));
|
||||
expect(finalState.currentPhase, ReleasePhase.APPLY_FRAMEWORK_CHERRYPICKS);
|
||||
});
|
||||
});
|
||||
|
||||
group('APPLY_FRAMEWORK_CHERRYPICKS to PUBLISH_VERSION', () {
|
||||
const String mirrorRemoteUrl = 'https://github.com/org/repo.git';
|
||||
const String upstreamRemoteUrl = 'https://github.com/mirror/repo.git';
|
||||
@ -359,218 +136,9 @@ void main() {
|
||||
engineRevisionFile.writeAsStringSync(oldEngineVersion, flush: true);
|
||||
});
|
||||
|
||||
test(
|
||||
'with no dart, engine or framework cherrypicks, updates engine revision if version mismatch',
|
||||
() async {
|
||||
stdio.stdin.add('n');
|
||||
processManager.addCommands(<FakeCommand>[
|
||||
const FakeCommand(command: <String>['git', 'fetch', 'upstream']),
|
||||
// we want merged upstream commit, not local working commit
|
||||
const FakeCommand(command: <String>['git', 'checkout', 'upstream/$candidateBranch']),
|
||||
const FakeCommand(command: <String>['git', 'rev-parse', 'HEAD'], stdout: revision1),
|
||||
const FakeCommand(command: <String>['git', 'fetch', 'upstream']),
|
||||
FakeCommand(
|
||||
command: const <String>['git', 'checkout', workingBranch],
|
||||
onRun: (_) {
|
||||
final File file = fileSystem.file('$checkoutsParentDirectory/framework/.ci.yaml')
|
||||
..createSync();
|
||||
_initializeCiYamlFile(file);
|
||||
},
|
||||
),
|
||||
const FakeCommand(
|
||||
command: <String>['git', 'status', '--porcelain'],
|
||||
stdout: 'MM bin/internal/release-candidate-branch.version',
|
||||
),
|
||||
const FakeCommand(command: <String>['git', 'add', '--all']),
|
||||
const FakeCommand(
|
||||
command: <String>[
|
||||
'git',
|
||||
'commit',
|
||||
'--message',
|
||||
'Create candidate branch version $candidateBranch for $releaseChannel',
|
||||
],
|
||||
),
|
||||
const FakeCommand(command: <String>['git', 'rev-parse', 'HEAD'], stdout: revision3),
|
||||
const FakeCommand(
|
||||
command: <String>['git', 'status', '--porcelain'],
|
||||
stdout: 'MM bin/internal/engine.version',
|
||||
),
|
||||
const FakeCommand(command: <String>['git', 'add', '--all']),
|
||||
const FakeCommand(
|
||||
command: <String>[
|
||||
'git',
|
||||
'commit',
|
||||
'--message',
|
||||
'Update Engine revision to $revision1 for $releaseChannel release $releaseVersion',
|
||||
],
|
||||
),
|
||||
const FakeCommand(command: <String>['git', 'rev-parse', 'HEAD'], stdout: revision4),
|
||||
]);
|
||||
final pb.ConductorState state =
|
||||
(pb.ConductorState.create()
|
||||
..releaseChannel = releaseChannel
|
||||
..releaseVersion = releaseVersion
|
||||
..currentPhase = ReleasePhase.APPLY_FRAMEWORK_CHERRYPICKS
|
||||
..framework =
|
||||
(pb.Repository.create()
|
||||
..candidateBranch = candidateBranch
|
||||
..checkoutPath = frameworkCheckoutPath
|
||||
..mirror =
|
||||
(pb.Remote.create()
|
||||
..name = 'mirror'
|
||||
..url = mirrorRemoteUrl)
|
||||
..upstream =
|
||||
(pb.Remote.create()
|
||||
..name = 'upstream'
|
||||
..url = upstreamRemoteUrl)
|
||||
..workingBranch = workingBranch)
|
||||
..engine =
|
||||
(pb.Repository.create()
|
||||
..candidateBranch = candidateBranch
|
||||
..checkoutPath = engineCheckoutPath
|
||||
..upstream =
|
||||
(pb.Remote.create()
|
||||
..name = 'upstream'
|
||||
..url = engineUpstreamRemoteUrl)
|
||||
..currentGitHead = revision1));
|
||||
writeStateToFile(fileSystem.file(stateFile), state, <String>[]);
|
||||
final Checkouts checkouts = Checkouts(
|
||||
fileSystem: fileSystem,
|
||||
parentDirectory: fileSystem.directory(checkoutsParentDirectory)
|
||||
..createSync(recursive: true),
|
||||
platform: platform,
|
||||
processManager: processManager,
|
||||
stdio: stdio,
|
||||
);
|
||||
final CommandRunner<void> runner = createRunner(checkouts: checkouts);
|
||||
await runner.run(<String>['next', '--$kStateOption', stateFile]);
|
||||
|
||||
expect(processManager, hasNoRemainingExpectations);
|
||||
expect(
|
||||
stdio.stdout,
|
||||
contains('release-candidate-branch.version containing $candidateBranch'),
|
||||
);
|
||||
expect(
|
||||
stdio.stdout,
|
||||
contains('Updating engine revision from $oldEngineVersion to $revision1'),
|
||||
);
|
||||
expect(stdio.stdout, contains('Are you ready to push your framework branch'));
|
||||
},
|
||||
);
|
||||
|
||||
test(
|
||||
'with no engine cherrypicks but a dart revision update, updates engine revision',
|
||||
() async {
|
||||
stdio.stdin.add('n');
|
||||
processManager.addCommands(<FakeCommand>[
|
||||
const FakeCommand(command: <String>['git', 'fetch', 'upstream']),
|
||||
// we want merged upstream commit, not local working commit
|
||||
const FakeCommand(command: <String>['git', 'checkout', 'upstream/$candidateBranch']),
|
||||
const FakeCommand(command: <String>['git', 'rev-parse', 'HEAD'], stdout: revision1),
|
||||
const FakeCommand(command: <String>['git', 'fetch', 'upstream']),
|
||||
FakeCommand(
|
||||
command: const <String>['git', 'checkout', workingBranch],
|
||||
onRun: (_) {
|
||||
final File file = fileSystem.file('$checkoutsParentDirectory/framework/.ci.yaml')
|
||||
..createSync();
|
||||
_initializeCiYamlFile(file);
|
||||
},
|
||||
),
|
||||
const FakeCommand(
|
||||
command: <String>['git', 'status', '--porcelain'],
|
||||
stdout: 'MM bin/internal/release-candidate-branch.version',
|
||||
),
|
||||
const FakeCommand(command: <String>['git', 'add', '--all']),
|
||||
const FakeCommand(
|
||||
command: <String>[
|
||||
'git',
|
||||
'commit',
|
||||
'--message',
|
||||
'Create candidate branch version $candidateBranch for $releaseChannel',
|
||||
],
|
||||
),
|
||||
const FakeCommand(command: <String>['git', 'rev-parse', 'HEAD'], stdout: revision3),
|
||||
const FakeCommand(
|
||||
command: <String>['git', 'status', '--porcelain'],
|
||||
stdout: 'MM bin/internal/engine.version',
|
||||
),
|
||||
const FakeCommand(command: <String>['git', 'add', '--all']),
|
||||
const FakeCommand(
|
||||
command: <String>[
|
||||
'git',
|
||||
'commit',
|
||||
'--message',
|
||||
'Update Engine revision to $revision1 for $releaseChannel release $releaseVersion',
|
||||
],
|
||||
),
|
||||
const FakeCommand(command: <String>['git', 'rev-parse', 'HEAD'], stdout: revision4),
|
||||
]);
|
||||
final pb.ConductorState state =
|
||||
(pb.ConductorState.create()
|
||||
..releaseChannel = releaseChannel
|
||||
..releaseVersion = releaseVersion
|
||||
..currentPhase = ReleasePhase.APPLY_FRAMEWORK_CHERRYPICKS
|
||||
..framework =
|
||||
(pb.Repository.create()
|
||||
..candidateBranch = candidateBranch
|
||||
..checkoutPath = frameworkCheckoutPath
|
||||
..mirror =
|
||||
(pb.Remote.create()
|
||||
..name = 'mirror'
|
||||
..url = mirrorRemoteUrl)
|
||||
..upstream =
|
||||
(pb.Remote.create()
|
||||
..name = 'upstream'
|
||||
..url = upstreamRemoteUrl)
|
||||
..workingBranch = workingBranch)
|
||||
..engine =
|
||||
(pb.Repository.create()
|
||||
..candidateBranch = candidateBranch
|
||||
..checkoutPath = engineCheckoutPath
|
||||
..upstream =
|
||||
(pb.Remote.create()
|
||||
..name = 'upstream'
|
||||
..url = engineUpstreamRemoteUrl)
|
||||
..dartRevision = 'abc123'));
|
||||
writeStateToFile(fileSystem.file(stateFile), state, <String>[]);
|
||||
final Checkouts checkouts = Checkouts(
|
||||
fileSystem: fileSystem,
|
||||
parentDirectory: fileSystem.directory(checkoutsParentDirectory)
|
||||
..createSync(recursive: true),
|
||||
platform: platform,
|
||||
processManager: processManager,
|
||||
stdio: stdio,
|
||||
);
|
||||
final CommandRunner<void> runner = createRunner(checkouts: checkouts);
|
||||
await runner.run(<String>['next', '--$kStateOption', stateFile]);
|
||||
|
||||
expect(processManager, hasNoRemainingExpectations);
|
||||
expect(
|
||||
stdio.stdout,
|
||||
contains('release-candidate-branch.version containing $candidateBranch'),
|
||||
);
|
||||
expect(
|
||||
stdio.stdout,
|
||||
contains('Updating engine revision from $oldEngineVersion to $revision1'),
|
||||
);
|
||||
expect(stdio.stdout, contains('Are you ready to push your framework branch'));
|
||||
},
|
||||
);
|
||||
|
||||
test('does not update state.currentPhase if user responds no', () async {
|
||||
stdio.stdin.add('n');
|
||||
processManager.addCommands(<FakeCommand>[
|
||||
const FakeCommand(command: <String>['git', 'fetch', 'upstream']),
|
||||
// we want merged upstream commit, not local working commit
|
||||
FakeCommand(
|
||||
command: const <String>['git', 'checkout', 'upstream/$candidateBranch'],
|
||||
onRun: (_) {
|
||||
final File file = fileSystem.file('$checkoutsParentDirectory/framework/.ci.yaml')
|
||||
..createSync();
|
||||
_initializeCiYamlFile(file);
|
||||
},
|
||||
),
|
||||
const FakeCommand(command: <String>['git', 'rev-parse', 'HEAD'], stdout: revision1),
|
||||
const FakeCommand(command: <String>['git', 'fetch', 'upstream']),
|
||||
const FakeCommand(command: <String>['git', 'checkout', workingBranch]),
|
||||
const FakeCommand(
|
||||
@ -587,20 +155,6 @@ void main() {
|
||||
],
|
||||
),
|
||||
const FakeCommand(command: <String>['git', 'rev-parse', 'HEAD'], stdout: revision3),
|
||||
const FakeCommand(
|
||||
command: <String>['git', 'status', '--porcelain'],
|
||||
stdout: 'MM bin/internal/engine.version',
|
||||
),
|
||||
const FakeCommand(command: <String>['git', 'add', '--all']),
|
||||
const FakeCommand(
|
||||
command: <String>[
|
||||
'git',
|
||||
'commit',
|
||||
'--message',
|
||||
'Update Engine revision to $revision1 for $releaseChannel release $releaseVersion',
|
||||
],
|
||||
),
|
||||
const FakeCommand(command: <String>['git', 'rev-parse', 'HEAD'], stdout: revision4),
|
||||
]);
|
||||
writeStateToFile(fileSystem.file(stateFile), state, <String>[]);
|
||||
final Checkouts checkouts = Checkouts(
|
||||
@ -616,6 +170,7 @@ void main() {
|
||||
|
||||
final pb.ConductorState finalState = readStateFromFile(fileSystem.file(stateFile));
|
||||
|
||||
expect(processManager, hasNoRemainingExpectations);
|
||||
expect(
|
||||
stdio.stdout,
|
||||
contains(
|
||||
@ -631,11 +186,6 @@ void main() {
|
||||
processManager.addCommands(<FakeCommand>[
|
||||
// Engine repo
|
||||
const FakeCommand(command: <String>['git', 'fetch', 'upstream']),
|
||||
// we want merged upstream commit, not local working commit
|
||||
const FakeCommand(command: <String>['git', 'checkout', 'upstream/$candidateBranch']),
|
||||
const FakeCommand(command: <String>['git', 'rev-parse', 'HEAD'], stdout: revision1),
|
||||
// Framework repo
|
||||
const FakeCommand(command: <String>['git', 'fetch', 'upstream']),
|
||||
FakeCommand(
|
||||
command: const <String>['git', 'checkout', workingBranch],
|
||||
onRun: (_) {
|
||||
@ -658,20 +208,6 @@ void main() {
|
||||
],
|
||||
),
|
||||
const FakeCommand(command: <String>['git', 'rev-parse', 'HEAD'], stdout: revision3),
|
||||
const FakeCommand(
|
||||
command: <String>['git', 'status', '--porcelain'],
|
||||
stdout: 'MM bin/internal/engine.version',
|
||||
),
|
||||
const FakeCommand(command: <String>['git', 'add', '--all']),
|
||||
const FakeCommand(
|
||||
command: <String>[
|
||||
'git',
|
||||
'commit',
|
||||
'--message',
|
||||
'Update Engine revision to $revision1 for $releaseChannel release $releaseVersion',
|
||||
],
|
||||
),
|
||||
const FakeCommand(command: <String>['git', 'rev-parse', 'HEAD'], stdout: revision4),
|
||||
const FakeCommand(
|
||||
command: <String>['git', 'push', 'mirror', 'HEAD:refs/heads/$workingBranch'],
|
||||
),
|
||||
@ -691,10 +227,6 @@ void main() {
|
||||
final pb.ConductorState finalState = readStateFromFile(fileSystem.file(stateFile));
|
||||
|
||||
expect(finalState.currentPhase, ReleasePhase.PUBLISH_VERSION);
|
||||
expect(
|
||||
stdio.stdout,
|
||||
contains('Rolling new engine hash $revision1 to framework checkout...'),
|
||||
);
|
||||
expect(stdio.stdout, contains('There was 1 cherrypick that was not auto-applied'));
|
||||
expect(
|
||||
stdio.stdout,
|
||||
@ -723,10 +255,6 @@ void main() {
|
||||
(pb.Repository.create()
|
||||
..candidateBranch = candidateBranch
|
||||
..upstream = (pb.Remote.create()..url = FrameworkRepository.defaultUpstream))
|
||||
..engine =
|
||||
(pb.Repository.create()
|
||||
..candidateBranch = candidateBranch
|
||||
..upstream = (pb.Remote.create()..url = EngineRepository.defaultUpstream))
|
||||
..releaseVersion = releaseVersion);
|
||||
});
|
||||
|
||||
|
@ -43,7 +43,7 @@ void main() {
|
||||
stdio: stdio,
|
||||
);
|
||||
|
||||
final EngineRepository repo = EngineRepository(checkouts);
|
||||
final FrameworkRepository repo = FrameworkRepository(checkouts);
|
||||
final File depsFile = fileSystem.file('/DEPS');
|
||||
depsFile.writeAsStringSync(generateMockDeps(previousDartRevision));
|
||||
await repo.updateDartRevision(nextDartRevision, depsFile: depsFile);
|
||||
@ -62,7 +62,7 @@ void main() {
|
||||
stdio: stdio,
|
||||
);
|
||||
|
||||
final EngineRepository repo = EngineRepository(checkouts);
|
||||
final FrameworkRepository repo = FrameworkRepository(checkouts);
|
||||
final File depsFile = fileSystem.file('/DEPS');
|
||||
depsFile.writeAsStringSync('''
|
||||
vars = {
|
||||
@ -85,11 +85,11 @@ vars = {
|
||||
'--origin',
|
||||
'upstream',
|
||||
'--',
|
||||
EngineRepository.defaultUpstream,
|
||||
fileSystem.path.join(rootDir, 'flutter_conductor_checkouts', 'engine'),
|
||||
FrameworkRepository.defaultUpstream,
|
||||
fileSystem.path.join(rootDir, 'flutter_conductor_checkouts', 'framework'),
|
||||
],
|
||||
),
|
||||
const FakeCommand(command: <String>['git', 'checkout', EngineRepository.defaultBranch]),
|
||||
const FakeCommand(command: <String>['git', 'checkout', FrameworkRepository.defaultBranch]),
|
||||
const FakeCommand(command: <String>['git', 'rev-parse', 'HEAD'], stdout: commit1),
|
||||
const FakeCommand(command: <String>['git', 'status', '--porcelain']),
|
||||
const FakeCommand(command: <String>['git', 'commit', '--message', message]),
|
||||
@ -104,7 +104,7 @@ vars = {
|
||||
stdio: stdio,
|
||||
);
|
||||
|
||||
final EngineRepository repo = EngineRepository(checkouts);
|
||||
final FrameworkRepository repo = FrameworkRepository(checkouts);
|
||||
expect(
|
||||
() async => repo.commit(message),
|
||||
throwsExceptionWith('Tried to commit with message $message but no changes were present'),
|
||||
@ -123,11 +123,11 @@ vars = {
|
||||
'--origin',
|
||||
'upstream',
|
||||
'--',
|
||||
EngineRepository.defaultUpstream,
|
||||
fileSystem.path.join(rootDir, 'flutter_conductor_checkouts', 'engine'),
|
||||
FrameworkRepository.defaultUpstream,
|
||||
fileSystem.path.join(rootDir, 'flutter_conductor_checkouts', 'framework'),
|
||||
],
|
||||
),
|
||||
const FakeCommand(command: <String>['git', 'checkout', EngineRepository.defaultBranch]),
|
||||
const FakeCommand(command: <String>['git', 'checkout', FrameworkRepository.defaultBranch]),
|
||||
const FakeCommand(command: <String>['git', 'rev-parse', 'HEAD'], stdout: commit1),
|
||||
const FakeCommand(
|
||||
command: <String>['git', 'status', '--porcelain'],
|
||||
@ -145,7 +145,7 @@ vars = {
|
||||
stdio: stdio,
|
||||
);
|
||||
|
||||
final EngineRepository repo = EngineRepository(checkouts);
|
||||
final FrameworkRepository repo = FrameworkRepository(checkouts);
|
||||
await repo.commit(message);
|
||||
expect(processManager.hasRemainingExpectations, false);
|
||||
});
|
||||
@ -174,41 +174,6 @@ vars = {
|
||||
},
|
||||
);
|
||||
|
||||
test('updateEngineRevision() returns false if newCommit is the same as version file', () async {
|
||||
const String commit1 = 'abc123';
|
||||
const String commit2 = 'def456';
|
||||
final File engineVersionFile = fileSystem.file('/engine.version')..writeAsStringSync(commit2);
|
||||
processManager.addCommands(<FakeCommand>[
|
||||
FakeCommand(
|
||||
command: <String>[
|
||||
'git',
|
||||
'clone',
|
||||
'--origin',
|
||||
'upstream',
|
||||
'--',
|
||||
FrameworkRepository.defaultUpstream,
|
||||
fileSystem.path.join(rootDir, 'flutter_conductor_checkouts', 'framework'),
|
||||
],
|
||||
),
|
||||
const FakeCommand(command: <String>['git', 'rev-parse', 'HEAD'], stdout: commit1),
|
||||
]);
|
||||
|
||||
final Checkouts checkouts = Checkouts(
|
||||
fileSystem: fileSystem,
|
||||
parentDirectory: fileSystem.directory(rootDir),
|
||||
platform: platform,
|
||||
processManager: processManager,
|
||||
stdio: stdio,
|
||||
);
|
||||
|
||||
final FrameworkRepository repo = FrameworkRepository(checkouts);
|
||||
final bool didUpdate = await repo.updateEngineRevision(
|
||||
commit2,
|
||||
engineVersionFile: engineVersionFile,
|
||||
);
|
||||
expect(didUpdate, false);
|
||||
});
|
||||
|
||||
test(
|
||||
'framework repo set as localUpstream ensures requiredLocalBranches exist locally',
|
||||
() async {
|
||||
@ -262,49 +227,6 @@ vars = {
|
||||
},
|
||||
);
|
||||
|
||||
test('engine repo set as localUpstream ensures requiredLocalBranches exist locally', () async {
|
||||
const String commit = 'deadbeef';
|
||||
const String candidateBranch = 'flutter-1.2-candidate.3';
|
||||
bool createdCandidateBranch = false;
|
||||
processManager.addCommands(<FakeCommand>[
|
||||
FakeCommand(
|
||||
command: <String>[
|
||||
'git',
|
||||
'clone',
|
||||
'--origin',
|
||||
'upstream',
|
||||
'--',
|
||||
EngineRepository.defaultUpstream,
|
||||
fileSystem.path.join(rootDir, 'flutter_conductor_checkouts', 'engine'),
|
||||
],
|
||||
),
|
||||
FakeCommand(
|
||||
command: const <String>['git', 'checkout', candidateBranch, '--'],
|
||||
onRun: (_) => createdCandidateBranch = true,
|
||||
),
|
||||
const FakeCommand(command: <String>['git', 'checkout', EngineRepository.defaultBranch]),
|
||||
const FakeCommand(command: <String>['git', 'rev-parse', 'HEAD'], stdout: commit),
|
||||
]);
|
||||
final Checkouts checkouts = Checkouts(
|
||||
fileSystem: fileSystem,
|
||||
parentDirectory: fileSystem.directory(rootDir),
|
||||
platform: platform,
|
||||
processManager: processManager,
|
||||
stdio: stdio,
|
||||
);
|
||||
|
||||
final Repository repo = EngineRepository(
|
||||
checkouts,
|
||||
additionalRequiredLocalBranches: <String>[candidateBranch],
|
||||
localUpstream: true,
|
||||
);
|
||||
// call this so that repo.lazilyInitialize() is called.
|
||||
await repo.checkoutDirectory;
|
||||
|
||||
expect(processManager.hasRemainingExpectations, false);
|
||||
expect(createdCandidateBranch, true);
|
||||
});
|
||||
|
||||
test('.listRemoteBranches() parses git output', () async {
|
||||
const String remoteName = 'mirror';
|
||||
const String lsRemoteOutput = '''
|
||||
@ -326,11 +248,14 @@ Extraneous debug information that should be ignored.
|
||||
'--origin',
|
||||
'upstream',
|
||||
'--',
|
||||
EngineRepository.defaultUpstream,
|
||||
'${rootDir}flutter_conductor_checkouts/engine',
|
||||
FrameworkRepository.defaultUpstream,
|
||||
'${rootDir}flutter_conductor_checkouts/framework',
|
||||
],
|
||||
),
|
||||
FakeCommand(command: <String>['git', 'checkout', 'main']),
|
||||
FakeCommand(command: <String>['git', 'checkout', 'stable', '--']),
|
||||
FakeCommand(command: <String>['git', 'checkout', 'beta', '--']),
|
||||
FakeCommand(command: <String>['git', 'checkout', 'master', '--']),
|
||||
FakeCommand(command: <String>['git', 'checkout', 'master']),
|
||||
FakeCommand(command: <String>['git', 'rev-parse', 'HEAD'], stdout: revision),
|
||||
FakeCommand(
|
||||
command: <String>['git', 'ls-remote', '--heads', remoteName],
|
||||
@ -345,7 +270,7 @@ Extraneous debug information that should be ignored.
|
||||
stdio: stdio,
|
||||
);
|
||||
|
||||
final Repository repo = EngineRepository(checkouts, localUpstream: true);
|
||||
final Repository repo = FrameworkRepository(checkouts, localUpstream: true);
|
||||
final List<String> branchNames = await repo.listRemoteBranches(remoteName);
|
||||
expect(
|
||||
branchNames,
|
||||
|
@ -25,7 +25,6 @@ void main() {
|
||||
const String checkoutsParentDirectory = '$flutterRoot/dev/tools/';
|
||||
const String githubUsername = 'user';
|
||||
const String frameworkMirror = 'git@github.com:$githubUsername/flutter.git';
|
||||
const String engineMirror = 'git@github.com:$githubUsername/engine.git';
|
||||
const String candidateBranch = 'flutter-1.2-candidate.3';
|
||||
const String releaseChannel = 'beta';
|
||||
const String revision = 'abcd1234';
|
||||
@ -117,7 +116,6 @@ void main() {
|
||||
expect(context.frameworkUpstream, FrameworkRepository.defaultUpstream);
|
||||
expect(context.frameworkMirror, contains(githubUsername));
|
||||
expect(context.frameworkMirror, contains('/flutter.git'));
|
||||
expect(context.engineUpstream, EngineRepository.defaultUpstream);
|
||||
});
|
||||
|
||||
test('overridden mirror', () async {
|
||||
@ -202,50 +200,8 @@ void main() {
|
||||
const String nextVersion = '1.2.0-1.1.pre';
|
||||
const String candidateBranch = 'flutter-1.2-candidate.1';
|
||||
|
||||
final Directory engine = fileSystem
|
||||
.directory(checkoutsParentDirectory)
|
||||
.childDirectory('flutter_conductor_checkouts')
|
||||
.childDirectory('engine');
|
||||
|
||||
final File depsFile = engine.childFile('DEPS');
|
||||
|
||||
final List<FakeCommand> engineCommands = <FakeCommand>[
|
||||
FakeCommand(
|
||||
command: <String>[
|
||||
'git',
|
||||
'clone',
|
||||
'--origin',
|
||||
'upstream',
|
||||
'--',
|
||||
EngineRepository.defaultUpstream,
|
||||
engine.path,
|
||||
],
|
||||
onRun: (_) {
|
||||
// Create the DEPS file which the tool will update
|
||||
engine.createSync(recursive: true);
|
||||
depsFile.writeAsStringSync(generateMockDeps(previousDartRevision));
|
||||
},
|
||||
),
|
||||
const FakeCommand(command: <String>['git', 'remote', 'add', 'mirror', engineMirror]),
|
||||
const FakeCommand(command: <String>['git', 'fetch', 'mirror']),
|
||||
const FakeCommand(command: <String>['git', 'checkout', 'upstream/$candidateBranch']),
|
||||
const FakeCommand(command: <String>['git', 'rev-parse', 'HEAD'], stdout: revision2),
|
||||
const FakeCommand(
|
||||
command: <String>['git', 'checkout', '-b', 'cherrypicks-$candidateBranch'],
|
||||
),
|
||||
const FakeCommand(
|
||||
command: <String>['git', 'status', '--porcelain'],
|
||||
stdout: 'MM path/to/DEPS',
|
||||
),
|
||||
const FakeCommand(command: <String>['git', 'add', '--all']),
|
||||
const FakeCommand(
|
||||
command: <String>['git', 'commit', '--message', 'Update Dart SDK to $nextDartRevision'],
|
||||
),
|
||||
const FakeCommand(command: <String>['git', 'rev-parse', 'HEAD'], stdout: revision2),
|
||||
const FakeCommand(command: <String>['git', 'rev-parse', 'HEAD'], stdout: revision2),
|
||||
];
|
||||
|
||||
final List<FakeCommand> frameworkCommands = <FakeCommand>[
|
||||
final List<FakeCommand> commands = <FakeCommand>[
|
||||
// clone and rev-parse framework
|
||||
FakeCommand(
|
||||
command: <String>[
|
||||
'git',
|
||||
@ -260,14 +216,35 @@ void main() {
|
||||
'framework',
|
||||
),
|
||||
],
|
||||
onRun: (_) {
|
||||
// ensure this is a monorepo checkout
|
||||
fileSystem
|
||||
.directory(
|
||||
fileSystem.path.join(
|
||||
checkoutsParentDirectory,
|
||||
'flutter_conductor_checkouts',
|
||||
'framework',
|
||||
'engine',
|
||||
),
|
||||
)
|
||||
.createSync(recursive: true);
|
||||
fileSystem
|
||||
.file(
|
||||
fileSystem.path.join(
|
||||
checkoutsParentDirectory,
|
||||
'flutter_conductor_checkouts',
|
||||
'framework',
|
||||
'DEPS',
|
||||
),
|
||||
)
|
||||
.writeAsStringSync(generateMockDeps(previousDartRevision));
|
||||
},
|
||||
),
|
||||
const FakeCommand(command: <String>['git', 'remote', 'add', 'mirror', frameworkMirror]),
|
||||
const FakeCommand(command: <String>['git', 'fetch', 'mirror']),
|
||||
const FakeCommand(command: <String>['git', 'checkout', 'upstream/$candidateBranch']),
|
||||
const FakeCommand(command: <String>['git', 'rev-parse', 'HEAD'], stdout: revision3),
|
||||
const FakeCommand(
|
||||
command: <String>['git', 'checkout', '-b', 'cherrypicks-$candidateBranch'],
|
||||
),
|
||||
const FakeCommand(command: <String>['git', 'rev-parse', 'HEAD'], stdout: revision3),
|
||||
const FakeCommand(
|
||||
command: <String>[
|
||||
'git',
|
||||
@ -279,7 +256,7 @@ void main() {
|
||||
],
|
||||
stdout: '$previousVersion-42-gabc123',
|
||||
),
|
||||
const FakeCommand(command: <String>['git', 'rev-parse', 'HEAD'], stdout: revision3),
|
||||
//const FakeCommand(command: <String>['git', 'rev-parse', 'HEAD'], stdout: revision3),
|
||||
const FakeCommand(
|
||||
command: <String>['git', 'merge-base', 'upstream/$candidateBranch', 'upstream/master'],
|
||||
stdout: branchPointRevision,
|
||||
@ -288,11 +265,24 @@ void main() {
|
||||
const FakeCommand(
|
||||
command: <String>['git', 'describe', '--exact-match', '--tags', branchPointRevision],
|
||||
),
|
||||
|
||||
const FakeCommand(
|
||||
command: <String>['git', 'checkout', '-b', 'cherrypicks-$candidateBranch'],
|
||||
),
|
||||
|
||||
// update DEPS
|
||||
const FakeCommand(
|
||||
command: <String>['git', 'status', '--porcelain'],
|
||||
stdout: 'MM path/to/DEPS',
|
||||
),
|
||||
const FakeCommand(command: <String>['git', 'add', '--all']),
|
||||
const FakeCommand(
|
||||
command: <String>['git', 'commit', '--message', 'Update Dart SDK to $nextDartRevision'],
|
||||
),
|
||||
const FakeCommand(command: <String>['git', 'rev-parse', 'HEAD'], stdout: revision2),
|
||||
];
|
||||
|
||||
final CommandRunner<void> runner = createRunner(
|
||||
commands: <FakeCommand>[...engineCommands, ...frameworkCommands],
|
||||
);
|
||||
final CommandRunner<void> runner = createRunner(commands: commands);
|
||||
|
||||
final String stateFilePath = fileSystem.path.join(
|
||||
platform.environment['HOME']!,
|
||||
@ -327,14 +317,10 @@ void main() {
|
||||
expect(state.isInitialized(), true);
|
||||
expect(state.releaseChannel, releaseChannel);
|
||||
expect(state.releaseVersion, nextVersion);
|
||||
expect(state.engine.candidateBranch, candidateBranch);
|
||||
expect(state.engine.startingGitHead, revision2);
|
||||
expect(state.engine.dartRevision, nextDartRevision);
|
||||
expect(state.engine.upstream.url, 'git@github.com:flutter/engine.git');
|
||||
expect(state.framework.candidateBranch, candidateBranch);
|
||||
expect(state.framework.startingGitHead, revision3);
|
||||
expect(state.framework.upstream.url, 'git@github.com:flutter/flutter.git');
|
||||
expect(state.currentPhase, ReleasePhase.APPLY_ENGINE_CHERRYPICKS);
|
||||
expect(state.currentPhase, ReleasePhase.APPLY_FRAMEWORK_CHERRYPICKS);
|
||||
expect(state.conductorVersion, conductorVersion);
|
||||
});
|
||||
|
||||
@ -348,50 +334,8 @@ void main() {
|
||||
const String candidateBranch = 'flutter-1.2-candidate.1';
|
||||
const String versionOverride = '42.0.0-42.0.pre';
|
||||
|
||||
final Directory engine = fileSystem
|
||||
.directory(checkoutsParentDirectory)
|
||||
.childDirectory('flutter_conductor_checkouts')
|
||||
.childDirectory('engine');
|
||||
|
||||
final File depsFile = engine.childFile('DEPS');
|
||||
|
||||
final List<FakeCommand> engineCommands = <FakeCommand>[
|
||||
FakeCommand(
|
||||
command: <String>[
|
||||
'git',
|
||||
'clone',
|
||||
'--origin',
|
||||
'upstream',
|
||||
'--',
|
||||
EngineRepository.defaultUpstream,
|
||||
engine.path,
|
||||
],
|
||||
onRun: (_) {
|
||||
// Create the DEPS file which the tool will update
|
||||
engine.createSync(recursive: true);
|
||||
depsFile.writeAsStringSync(generateMockDeps(previousDartRevision));
|
||||
},
|
||||
),
|
||||
const FakeCommand(command: <String>['git', 'remote', 'add', 'mirror', engineMirror]),
|
||||
const FakeCommand(command: <String>['git', 'fetch', 'mirror']),
|
||||
const FakeCommand(command: <String>['git', 'checkout', 'upstream/$candidateBranch']),
|
||||
const FakeCommand(command: <String>['git', 'rev-parse', 'HEAD'], stdout: revision2),
|
||||
const FakeCommand(
|
||||
command: <String>['git', 'checkout', '-b', 'cherrypicks-$candidateBranch'],
|
||||
),
|
||||
const FakeCommand(
|
||||
command: <String>['git', 'status', '--porcelain'],
|
||||
stdout: 'MM path/to/DEPS',
|
||||
),
|
||||
const FakeCommand(command: <String>['git', 'add', '--all']),
|
||||
const FakeCommand(
|
||||
command: <String>['git', 'commit', '--message', 'Update Dart SDK to $nextDartRevision'],
|
||||
),
|
||||
const FakeCommand(command: <String>['git', 'rev-parse', 'HEAD'], stdout: revision2),
|
||||
const FakeCommand(command: <String>['git', 'rev-parse', 'HEAD'], stdout: revision2),
|
||||
];
|
||||
|
||||
final List<FakeCommand> frameworkCommands = <FakeCommand>[
|
||||
final List<FakeCommand> commands = <FakeCommand>[
|
||||
// clone and rev-parse framework
|
||||
FakeCommand(
|
||||
command: <String>[
|
||||
'git',
|
||||
@ -406,14 +350,35 @@ void main() {
|
||||
'framework',
|
||||
),
|
||||
],
|
||||
onRun: (_) {
|
||||
// ensure this is a monorepo checkout
|
||||
fileSystem
|
||||
.directory(
|
||||
fileSystem.path.join(
|
||||
checkoutsParentDirectory,
|
||||
'flutter_conductor_checkouts',
|
||||
'framework',
|
||||
'engine',
|
||||
),
|
||||
)
|
||||
.createSync(recursive: true);
|
||||
fileSystem
|
||||
.file(
|
||||
fileSystem.path.join(
|
||||
checkoutsParentDirectory,
|
||||
'flutter_conductor_checkouts',
|
||||
'framework',
|
||||
'DEPS',
|
||||
),
|
||||
)
|
||||
.writeAsStringSync(generateMockDeps(previousDartRevision));
|
||||
},
|
||||
),
|
||||
const FakeCommand(command: <String>['git', 'remote', 'add', 'mirror', frameworkMirror]),
|
||||
const FakeCommand(command: <String>['git', 'fetch', 'mirror']),
|
||||
const FakeCommand(command: <String>['git', 'checkout', 'upstream/$candidateBranch']),
|
||||
const FakeCommand(command: <String>['git', 'rev-parse', 'HEAD'], stdout: revision3),
|
||||
const FakeCommand(
|
||||
command: <String>['git', 'checkout', '-b', 'cherrypicks-$candidateBranch'],
|
||||
),
|
||||
const FakeCommand(command: <String>['git', 'rev-parse', 'HEAD'], stdout: revision3),
|
||||
const FakeCommand(
|
||||
command: <String>[
|
||||
'git',
|
||||
@ -425,16 +390,26 @@ void main() {
|
||||
],
|
||||
stdout: '$previousVersion-42-gabc123',
|
||||
),
|
||||
const FakeCommand(command: <String>['git', 'rev-parse', 'HEAD'], stdout: revision3),
|
||||
const FakeCommand(
|
||||
command: <String>['git', 'merge-base', 'upstream/$candidateBranch', 'upstream/master'],
|
||||
stdout: branchPointRevision,
|
||||
),
|
||||
|
||||
const FakeCommand(
|
||||
command: <String>['git', 'checkout', '-b', 'cherrypicks-$candidateBranch'],
|
||||
),
|
||||
const FakeCommand(
|
||||
command: <String>['git', 'status', '--porcelain'],
|
||||
stdout: 'MM path/to/DEPS',
|
||||
),
|
||||
const FakeCommand(command: <String>['git', 'add', '--all']),
|
||||
const FakeCommand(
|
||||
command: <String>['git', 'commit', '--message', 'Update Dart SDK to $nextDartRevision'],
|
||||
),
|
||||
const FakeCommand(command: <String>['git', 'rev-parse', 'HEAD'], stdout: revision2),
|
||||
];
|
||||
|
||||
final CommandRunner<void> runner = createRunner(
|
||||
commands: <FakeCommand>[...engineCommands, ...frameworkCommands],
|
||||
);
|
||||
final CommandRunner<void> runner = createRunner(commands: commands);
|
||||
|
||||
final String stateFilePath = fileSystem.path.join(
|
||||
platform.environment['HOME']!,
|
||||
@ -466,156 +441,6 @@ void main() {
|
||||
expect(state.releaseVersion, versionOverride);
|
||||
});
|
||||
|
||||
test('logs to STDERR but does not fail on an unexpected candidate branch', () async {
|
||||
stdio.stdin.add('y'); // accept prompt from ensureBranchPointTagged()
|
||||
const String revision2 = 'def789';
|
||||
const String revision3 = '123abc';
|
||||
const String previousDartRevision = '171876a4e6cf56ee6da1f97d203926bd7afda7ef';
|
||||
const String nextDartRevision = 'f6c91128be6b77aef8351e1e3a9d07c85bc2e46e';
|
||||
// This is significantly behind the candidate branch name
|
||||
const String previousVersion = '0.9.0-1.0.pre';
|
||||
// This is what this release will be
|
||||
const String nextVersion = '0.9.0-1.1.pre';
|
||||
|
||||
final Directory engine = fileSystem
|
||||
.directory(checkoutsParentDirectory)
|
||||
.childDirectory('flutter_conductor_checkouts')
|
||||
.childDirectory('engine');
|
||||
|
||||
final File depsFile = engine.childFile('DEPS');
|
||||
|
||||
final List<FakeCommand> engineCommands = <FakeCommand>[
|
||||
FakeCommand(
|
||||
command: <String>[
|
||||
'git',
|
||||
'clone',
|
||||
'--origin',
|
||||
'upstream',
|
||||
'--',
|
||||
EngineRepository.defaultUpstream,
|
||||
engine.path,
|
||||
],
|
||||
onRun: (_) {
|
||||
// Create the DEPS file which the tool will update
|
||||
engine.createSync(recursive: true);
|
||||
depsFile.writeAsStringSync(generateMockDeps(previousDartRevision));
|
||||
},
|
||||
),
|
||||
const FakeCommand(command: <String>['git', 'remote', 'add', 'mirror', engineMirror]),
|
||||
const FakeCommand(command: <String>['git', 'fetch', 'mirror']),
|
||||
const FakeCommand(command: <String>['git', 'checkout', 'upstream/$candidateBranch']),
|
||||
const FakeCommand(command: <String>['git', 'rev-parse', 'HEAD'], stdout: revision2),
|
||||
const FakeCommand(
|
||||
command: <String>['git', 'checkout', '-b', 'cherrypicks-$candidateBranch'],
|
||||
),
|
||||
const FakeCommand(
|
||||
command: <String>['git', 'status', '--porcelain'],
|
||||
stdout: 'MM path/to/DEPS',
|
||||
),
|
||||
const FakeCommand(command: <String>['git', 'add', '--all']),
|
||||
const FakeCommand(
|
||||
command: <String>['git', 'commit', '--message', 'Update Dart SDK to $nextDartRevision'],
|
||||
),
|
||||
const FakeCommand(command: <String>['git', 'rev-parse', 'HEAD'], stdout: revision2),
|
||||
const FakeCommand(command: <String>['git', 'rev-parse', 'HEAD'], stdout: revision2),
|
||||
];
|
||||
|
||||
final List<FakeCommand> frameworkCommands = <FakeCommand>[
|
||||
FakeCommand(
|
||||
command: <String>[
|
||||
'git',
|
||||
'clone',
|
||||
'--origin',
|
||||
'upstream',
|
||||
'--',
|
||||
FrameworkRepository.defaultUpstream,
|
||||
fileSystem.path.join(
|
||||
checkoutsParentDirectory,
|
||||
'flutter_conductor_checkouts',
|
||||
'framework',
|
||||
),
|
||||
],
|
||||
),
|
||||
const FakeCommand(command: <String>['git', 'remote', 'add', 'mirror', frameworkMirror]),
|
||||
const FakeCommand(command: <String>['git', 'fetch', 'mirror']),
|
||||
const FakeCommand(command: <String>['git', 'checkout', 'upstream/$candidateBranch']),
|
||||
const FakeCommand(command: <String>['git', 'rev-parse', 'HEAD'], stdout: revision3),
|
||||
const FakeCommand(
|
||||
command: <String>['git', 'checkout', '-b', 'cherrypicks-$candidateBranch'],
|
||||
),
|
||||
const FakeCommand(
|
||||
command: <String>[
|
||||
'git',
|
||||
'describe',
|
||||
'--match',
|
||||
'*.*.*',
|
||||
'--tags',
|
||||
'refs/remotes/upstream/$candidateBranch',
|
||||
],
|
||||
stdout: '$previousVersion-42-gabc123',
|
||||
),
|
||||
const FakeCommand(command: <String>['git', 'rev-parse', 'HEAD'], stdout: revision3),
|
||||
const FakeCommand(
|
||||
command: <String>['git', 'merge-base', 'upstream/$candidateBranch', 'upstream/master'],
|
||||
stdout: branchPointRevision,
|
||||
),
|
||||
// check if commit is tagged, 0 exit code means it is tagged
|
||||
const FakeCommand(
|
||||
command: <String>['git', 'describe', '--exact-match', '--tags', branchPointRevision],
|
||||
),
|
||||
];
|
||||
|
||||
final CommandRunner<void> runner = createRunner(
|
||||
commands: <FakeCommand>[...engineCommands, ...frameworkCommands],
|
||||
);
|
||||
|
||||
final String stateFilePath = fileSystem.path.join(
|
||||
platform.environment['HOME']!,
|
||||
kStateFileName,
|
||||
);
|
||||
|
||||
await runner.run(<String>[
|
||||
'start',
|
||||
'--$kCandidateOption',
|
||||
candidateBranch,
|
||||
'--$kReleaseOption',
|
||||
releaseChannel,
|
||||
'--$kStateOption',
|
||||
stateFilePath,
|
||||
'--$kDartRevisionOption',
|
||||
nextDartRevision,
|
||||
'--$kGithubUsernameOption',
|
||||
githubUsername,
|
||||
]);
|
||||
|
||||
final File stateFile = fileSystem.file(stateFilePath);
|
||||
|
||||
final pb.ConductorState state = pb.ConductorState();
|
||||
state.mergeFromProto3Json(jsonDecode(stateFile.readAsStringSync()));
|
||||
|
||||
expect(stdio.error, isNot(contains('Tried to tag the branch point, however')));
|
||||
expect(processManager, hasNoRemainingExpectations);
|
||||
expect(state.isInitialized(), true);
|
||||
expect(state.releaseChannel, releaseChannel);
|
||||
expect(state.releaseVersion, nextVersion);
|
||||
expect(state.engine.candidateBranch, candidateBranch);
|
||||
expect(state.engine.startingGitHead, revision2);
|
||||
expect(state.engine.dartRevision, nextDartRevision);
|
||||
expect(state.engine.upstream.url, 'git@github.com:flutter/engine.git');
|
||||
expect(state.framework.candidateBranch, candidateBranch);
|
||||
expect(state.framework.startingGitHead, revision3);
|
||||
expect(state.framework.upstream.url, 'git@github.com:flutter/flutter.git');
|
||||
expect(state.currentPhase, ReleasePhase.APPLY_ENGINE_CHERRYPICKS);
|
||||
expect(state.conductorVersion, conductorVersion);
|
||||
expect(state.releaseType, ReleaseType.BETA_HOTFIX);
|
||||
expect(
|
||||
stdio.error,
|
||||
contains(
|
||||
'Parsed version $previousVersion.42 has a different x value than candidate branch $candidateBranch',
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
test('can convert from dev style version to stable version', () async {
|
||||
const String revision2 = 'def789';
|
||||
const String revision3 = '123abc';
|
||||
@ -624,50 +449,8 @@ void main() {
|
||||
const String previousVersion = '1.2.0-3.0.pre';
|
||||
const String nextVersion = '1.2.0';
|
||||
|
||||
final Directory engine = fileSystem
|
||||
.directory(checkoutsParentDirectory)
|
||||
.childDirectory('flutter_conductor_checkouts')
|
||||
.childDirectory('engine');
|
||||
|
||||
final File depsFile = engine.childFile('DEPS');
|
||||
|
||||
final List<FakeCommand> engineCommands = <FakeCommand>[
|
||||
FakeCommand(
|
||||
command: <String>[
|
||||
'git',
|
||||
'clone',
|
||||
'--origin',
|
||||
'upstream',
|
||||
'--',
|
||||
EngineRepository.defaultUpstream,
|
||||
engine.path,
|
||||
],
|
||||
onRun: (_) {
|
||||
// Create the DEPS file which the tool will update
|
||||
engine.createSync(recursive: true);
|
||||
depsFile.writeAsStringSync(generateMockDeps(previousDartRevision));
|
||||
},
|
||||
),
|
||||
const FakeCommand(command: <String>['git', 'remote', 'add', 'mirror', engineMirror]),
|
||||
const FakeCommand(command: <String>['git', 'fetch', 'mirror']),
|
||||
const FakeCommand(command: <String>['git', 'checkout', 'upstream/$candidateBranch']),
|
||||
const FakeCommand(command: <String>['git', 'rev-parse', 'HEAD'], stdout: revision2),
|
||||
const FakeCommand(
|
||||
command: <String>['git', 'checkout', '-b', 'cherrypicks-$candidateBranch'],
|
||||
),
|
||||
const FakeCommand(
|
||||
command: <String>['git', 'status', '--porcelain'],
|
||||
stdout: 'MM path/to/DEPS',
|
||||
),
|
||||
const FakeCommand(command: <String>['git', 'add', '--all']),
|
||||
const FakeCommand(
|
||||
command: <String>['git', 'commit', '--message', 'Update Dart SDK to $nextDartRevision'],
|
||||
),
|
||||
const FakeCommand(command: <String>['git', 'rev-parse', 'HEAD'], stdout: revision2),
|
||||
const FakeCommand(command: <String>['git', 'rev-parse', 'HEAD'], stdout: revision2),
|
||||
];
|
||||
|
||||
final List<FakeCommand> frameworkCommands = <FakeCommand>[
|
||||
final List<FakeCommand> commands = <FakeCommand>[
|
||||
// rev-parse framework
|
||||
FakeCommand(
|
||||
command: <String>[
|
||||
'git',
|
||||
@ -682,14 +465,35 @@ void main() {
|
||||
'framework',
|
||||
),
|
||||
],
|
||||
onRun: (_) {
|
||||
// ensure this is a monorepo checkout
|
||||
fileSystem
|
||||
.directory(
|
||||
fileSystem.path.join(
|
||||
checkoutsParentDirectory,
|
||||
'flutter_conductor_checkouts',
|
||||
'framework',
|
||||
'engine',
|
||||
),
|
||||
)
|
||||
.createSync(recursive: true);
|
||||
fileSystem
|
||||
.file(
|
||||
fileSystem.path.join(
|
||||
checkoutsParentDirectory,
|
||||
'flutter_conductor_checkouts',
|
||||
'framework',
|
||||
'DEPS',
|
||||
),
|
||||
)
|
||||
.writeAsStringSync(generateMockDeps(previousDartRevision));
|
||||
},
|
||||
),
|
||||
const FakeCommand(command: <String>['git', 'remote', 'add', 'mirror', frameworkMirror]),
|
||||
const FakeCommand(command: <String>['git', 'fetch', 'mirror']),
|
||||
const FakeCommand(command: <String>['git', 'checkout', 'upstream/$candidateBranch']),
|
||||
const FakeCommand(command: <String>['git', 'rev-parse', 'HEAD'], stdout: revision3),
|
||||
const FakeCommand(
|
||||
command: <String>['git', 'checkout', '-b', 'cherrypicks-$candidateBranch'],
|
||||
),
|
||||
const FakeCommand(command: <String>['git', 'rev-parse', 'HEAD'], stdout: revision3),
|
||||
const FakeCommand(
|
||||
command: <String>[
|
||||
'git',
|
||||
@ -701,7 +505,6 @@ void main() {
|
||||
],
|
||||
stdout: '$previousVersion-42-gabc123',
|
||||
),
|
||||
const FakeCommand(command: <String>['git', 'rev-parse', 'HEAD'], stdout: revision3),
|
||||
const FakeCommand(
|
||||
command: <String>['git', 'merge-base', 'upstream/$candidateBranch', 'upstream/master'],
|
||||
stdout: branchPointRevision,
|
||||
@ -710,11 +513,22 @@ void main() {
|
||||
const FakeCommand(
|
||||
command: <String>['git', 'describe', '--exact-match', '--tags', branchPointRevision],
|
||||
),
|
||||
|
||||
const FakeCommand(
|
||||
command: <String>['git', 'checkout', '-b', 'cherrypicks-$candidateBranch'],
|
||||
),
|
||||
const FakeCommand(
|
||||
command: <String>['git', 'status', '--porcelain'],
|
||||
stdout: 'MM path/to/DEPS',
|
||||
),
|
||||
const FakeCommand(command: <String>['git', 'add', '--all']),
|
||||
const FakeCommand(
|
||||
command: <String>['git', 'commit', '--message', 'Update Dart SDK to $nextDartRevision'],
|
||||
),
|
||||
const FakeCommand(command: <String>['git', 'rev-parse', 'HEAD'], stdout: revision2),
|
||||
];
|
||||
|
||||
final CommandRunner<void> runner = createRunner(
|
||||
commands: <FakeCommand>[...engineCommands, ...frameworkCommands],
|
||||
);
|
||||
final CommandRunner<void> runner = createRunner(commands: commands);
|
||||
|
||||
final String stateFilePath = fileSystem.path.join(
|
||||
platform.environment['HOME']!,
|
||||
@ -740,23 +554,21 @@ void main() {
|
||||
final pb.ConductorState state = pb.ConductorState();
|
||||
state.mergeFromProto3Json(jsonDecode(stateFile.readAsStringSync()));
|
||||
|
||||
expect(processManager.hasRemainingExpectations, false);
|
||||
expect(processManager, hasNoRemainingExpectations);
|
||||
expect(state.isInitialized(), true);
|
||||
expect(state.releaseChannel, 'stable');
|
||||
expect(state.releaseVersion, nextVersion);
|
||||
expect(state.engine.candidateBranch, candidateBranch);
|
||||
expect(state.engine.startingGitHead, revision2);
|
||||
expect(state.engine.dartRevision, nextDartRevision);
|
||||
expect(state.framework.dartRevision, nextDartRevision);
|
||||
expect(state.framework.candidateBranch, candidateBranch);
|
||||
expect(state.framework.startingGitHead, revision3);
|
||||
expect(state.currentPhase, ReleasePhase.APPLY_ENGINE_CHERRYPICKS);
|
||||
expect(state.currentPhase, ReleasePhase.APPLY_FRAMEWORK_CHERRYPICKS);
|
||||
expect(state.conductorVersion, conductorVersion);
|
||||
expect(state.releaseType, ReleaseType.STABLE_INITIAL);
|
||||
});
|
||||
test('StartContext gets engine and framework checkout directories after run', () async {
|
||||
|
||||
test('StartContext gets framework checkout directory after run', () async {
|
||||
stdio.stdin.add('y');
|
||||
const String revision2 = 'def789';
|
||||
const String revision3 = '123abc';
|
||||
const String branchPointRevision = 'deadbeef';
|
||||
const String previousDartRevision = '171876a4e6cf56ee6da1f97d203926bd7afda7ef';
|
||||
const String nextDartRevision = 'f6c91128be6b77aef8351e1e3a9d07c85bc2e46e';
|
||||
@ -764,55 +576,13 @@ void main() {
|
||||
// This is a git tag applied to the branch point, not an actual release
|
||||
const String branchPointTag = '1.2.0-3.0.pre';
|
||||
|
||||
final Directory engine = fileSystem
|
||||
.directory(checkoutsParentDirectory)
|
||||
.childDirectory('flutter_conductor_checkouts')
|
||||
.childDirectory('engine');
|
||||
|
||||
final Directory framework = fileSystem
|
||||
.directory(checkoutsParentDirectory)
|
||||
.childDirectory('flutter_conductor_checkouts')
|
||||
.childDirectory('framework');
|
||||
|
||||
final File depsFile = engine.childFile('DEPS');
|
||||
|
||||
final List<FakeCommand> engineCommands = <FakeCommand>[
|
||||
FakeCommand(
|
||||
command: <String>[
|
||||
'git',
|
||||
'clone',
|
||||
'--origin',
|
||||
'upstream',
|
||||
'--',
|
||||
EngineRepository.defaultUpstream,
|
||||
engine.path,
|
||||
],
|
||||
onRun: (_) {
|
||||
// Create the DEPS file which the tool will update
|
||||
engine.createSync(recursive: true);
|
||||
depsFile.writeAsStringSync(generateMockDeps(previousDartRevision));
|
||||
},
|
||||
),
|
||||
const FakeCommand(command: <String>['git', 'remote', 'add', 'mirror', engineMirror]),
|
||||
const FakeCommand(command: <String>['git', 'fetch', 'mirror']),
|
||||
const FakeCommand(command: <String>['git', 'checkout', 'upstream/$candidateBranch']),
|
||||
const FakeCommand(command: <String>['git', 'rev-parse', 'HEAD'], stdout: revision2),
|
||||
const FakeCommand(
|
||||
command: <String>['git', 'checkout', '-b', 'cherrypicks-$candidateBranch'],
|
||||
),
|
||||
const FakeCommand(
|
||||
command: <String>['git', 'status', '--porcelain'],
|
||||
stdout: 'MM path/to/DEPS',
|
||||
),
|
||||
const FakeCommand(command: <String>['git', 'add', '--all']),
|
||||
const FakeCommand(
|
||||
command: <String>['git', 'commit', '--message', 'Update Dart SDK to $nextDartRevision'],
|
||||
),
|
||||
const FakeCommand(command: <String>['git', 'rev-parse', 'HEAD'], stdout: revision2),
|
||||
const FakeCommand(command: <String>['git', 'rev-parse', 'HEAD'], stdout: revision2),
|
||||
];
|
||||
|
||||
final List<FakeCommand> frameworkCommands = <FakeCommand>[
|
||||
final List<FakeCommand> commands = <FakeCommand>[
|
||||
// checkout and rev-parse framework
|
||||
FakeCommand(
|
||||
command: <String>[
|
||||
'git',
|
||||
@ -823,13 +593,41 @@ void main() {
|
||||
FrameworkRepository.defaultUpstream,
|
||||
framework.path,
|
||||
],
|
||||
onRun: (_) {
|
||||
// ensure this is a monorepo checkout
|
||||
fileSystem
|
||||
.directory(
|
||||
fileSystem.path.join(
|
||||
checkoutsParentDirectory,
|
||||
'flutter_conductor_checkouts',
|
||||
'framework',
|
||||
'engine',
|
||||
),
|
||||
)
|
||||
.createSync(recursive: true);
|
||||
fileSystem
|
||||
.file(
|
||||
fileSystem.path.join(
|
||||
checkoutsParentDirectory,
|
||||
'flutter_conductor_checkouts',
|
||||
'framework',
|
||||
'DEPS',
|
||||
),
|
||||
)
|
||||
.writeAsStringSync(generateMockDeps(previousDartRevision));
|
||||
},
|
||||
),
|
||||
const FakeCommand(command: <String>['git', 'remote', 'add', 'mirror', frameworkMirror]),
|
||||
const FakeCommand(command: <String>['git', 'fetch', 'mirror']),
|
||||
const FakeCommand(command: <String>['git', 'checkout', 'upstream/$candidateBranch']),
|
||||
const FakeCommand(command: <String>['git', 'rev-parse', 'HEAD'], stdout: revision3),
|
||||
const FakeCommand(
|
||||
command: <String>['git', 'checkout', '-b', 'cherrypicks-$candidateBranch'],
|
||||
command: <String>['git', 'rev-parse', 'HEAD'],
|
||||
stdout: branchPointRevision,
|
||||
),
|
||||
|
||||
const FakeCommand(
|
||||
command: <String>['git', 'rev-parse', 'HEAD'],
|
||||
stdout: branchPointRevision,
|
||||
),
|
||||
const FakeCommand(
|
||||
command: <String>[
|
||||
@ -842,11 +640,6 @@ void main() {
|
||||
],
|
||||
stdout: '$previousVersion-42-gabc123',
|
||||
),
|
||||
// HEAD and branch point are same
|
||||
const FakeCommand(
|
||||
command: <String>['git', 'rev-parse', 'HEAD'],
|
||||
stdout: branchPointRevision,
|
||||
),
|
||||
const FakeCommand(
|
||||
command: <String>['git', 'merge-base', 'upstream/$candidateBranch', 'upstream/master'],
|
||||
stdout: branchPointRevision,
|
||||
@ -857,10 +650,25 @@ void main() {
|
||||
// non-zero exit code means branch point is NOT tagged
|
||||
exitCode: 128,
|
||||
),
|
||||
|
||||
const FakeCommand(command: <String>['git', 'tag', branchPointTag, branchPointRevision]),
|
||||
const FakeCommand(
|
||||
command: <String>['git', 'push', FrameworkRepository.defaultUpstream, branchPointTag],
|
||||
),
|
||||
|
||||
const FakeCommand(
|
||||
command: <String>['git', 'checkout', '-b', 'cherrypicks-$candidateBranch'],
|
||||
),
|
||||
|
||||
const FakeCommand(
|
||||
command: <String>['git', 'status', '--porcelain'],
|
||||
stdout: 'MM path/to/DEPS',
|
||||
),
|
||||
const FakeCommand(command: <String>['git', 'add', '--all']),
|
||||
const FakeCommand(
|
||||
command: <String>['git', 'commit', '--message', 'Update Dart SDK to $nextDartRevision'],
|
||||
),
|
||||
const FakeCommand(command: <String>['git', 'rev-parse', 'HEAD'], stdout: revision2),
|
||||
];
|
||||
|
||||
final String operatingSystem = const LocalPlatform().operatingSystem;
|
||||
@ -876,10 +684,7 @@ void main() {
|
||||
);
|
||||
final File stateFile = fileSystem.file(stateFilePath);
|
||||
|
||||
processManager = FakeProcessManager.list(<FakeCommand>[
|
||||
...engineCommands,
|
||||
...frameworkCommands,
|
||||
]);
|
||||
processManager = FakeProcessManager.list(<FakeCommand>[...commands]);
|
||||
checkouts = Checkouts(
|
||||
fileSystem: fileSystem,
|
||||
parentDirectory: fileSystem.directory(checkoutsParentDirectory),
|
||||
@ -892,8 +697,6 @@ void main() {
|
||||
candidateBranch: candidateBranch,
|
||||
checkouts: checkouts,
|
||||
dartRevision: nextDartRevision,
|
||||
engineMirror: engineMirror,
|
||||
engineUpstream: EngineRepository.defaultUpstream,
|
||||
frameworkMirror: frameworkMirror,
|
||||
frameworkUpstream: FrameworkRepository.defaultUpstream,
|
||||
releaseChannel: releaseChannel,
|
||||
@ -908,7 +711,6 @@ void main() {
|
||||
final pb.ConductorState state = pb.ConductorState();
|
||||
state.mergeFromProto3Json(jsonDecode(stateFile.readAsStringSync()));
|
||||
|
||||
expect((await startContext.engine.checkoutDirectory).path, equals(engine.path));
|
||||
expect((await startContext.framework.checkoutDirectory).path, equals(framework.path));
|
||||
expect(state.releaseType, ReleaseType.BETA_INITIAL);
|
||||
expect(processManager, hasNoRemainingExpectations);
|
||||
|
Loading…
x
Reference in New Issue
Block a user