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,
|
CherrypickState.ABANDONED,
|
||||||
];
|
];
|
||||||
switch (state.currentPhase) {
|
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:
|
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 Remote upstream = Remote.upstream(state.framework.upstream.url);
|
||||||
final FrameworkRepository framework = FrameworkRepository(
|
final FrameworkRepository framework = FrameworkRepository(
|
||||||
checkouts,
|
checkouts,
|
||||||
@ -166,7 +94,7 @@ class NextContext extends Context {
|
|||||||
previousCheckoutLocation: state.framework.checkoutPath,
|
previousCheckoutLocation: state.framework.checkoutPath,
|
||||||
);
|
);
|
||||||
stdio.printStatus('Writing candidate branch...');
|
stdio.printStatus('Writing candidate branch...');
|
||||||
bool needsCommit = await framework.updateCandidateBranchVersion(
|
final bool needsCommit = await framework.updateCandidateBranchVersion(
|
||||||
state.framework.candidateBranch,
|
state.framework.candidateBranch,
|
||||||
);
|
);
|
||||||
if (needsCommit) {
|
if (needsCommit) {
|
||||||
@ -181,20 +109,6 @@ class NextContext extends Context {
|
|||||||
..state = pb.CherrypickState.COMPLETED,
|
..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>[
|
final List<pb.Cherrypick> unappliedCherrypicks = <pb.Cherrypick>[
|
||||||
for (final pb.Cherrypick cherrypick in state.framework.cherrypicks)
|
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
|
# Use of this source code is governed by a BSD-style license that can be
|
||||||
# found in the LICENSE file.
|
# found in the LICENSE file.
|
||||||
|
|
||||||
# //flutter/dev/tools/lib/proto
|
set -euo pipefail
|
||||||
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
|
||||||
|
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
|
# Ensure dart-sdk is cached
|
||||||
"$DIR/../../../../bin/dart" --version
|
"$DIR/../../../../../../bin/dart" --version
|
||||||
|
|
||||||
if ! type protoc >/dev/null 2>&1; then
|
if ! type protoc >/dev/null 2>&1; then
|
||||||
PROTOC_LINK='https://grpc.io/docs/protoc-installation/'
|
PROTOC_LINK='https://grpc.io/docs/protoc-installation/'
|
||||||
@ -22,13 +36,13 @@ if ! type dart >/dev/null 2>&1; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Use null-safe protoc_plugin
|
# 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"
|
protoc --dart_out="$DIR" --proto_path="$DIR" "$DIR/conductor_state.proto"
|
||||||
|
|
||||||
for SOURCE_FILE in $(ls "$DIR"/*.pb*.dart); do
|
for SOURCE_FILE in $(ls "$DIR"/*.pb*.dart); do
|
||||||
# Format in place file
|
# 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
|
# Create temp copy with the license header prepended
|
||||||
cp "$DIR/license_header.txt" "${SOURCE_FILE}.tmp"
|
cp "$DIR/license_header.txt" "${SOURCE_FILE}.tmp"
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
//
|
//
|
||||||
// @dart = 2.12
|
// @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: constant_identifier_names, library_prefixes
|
||||||
// ignore_for_file: non_constant_identifier_names, prefer_final_fields
|
// ignore_for_file: non_constant_identifier_names, prefer_final_fields
|
||||||
// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
|
// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
|
||||||
@ -22,8 +22,21 @@ import 'conductor_state.pbenum.dart';
|
|||||||
|
|
||||||
export 'conductor_state.pbenum.dart';
|
export 'conductor_state.pbenum.dart';
|
||||||
|
|
||||||
|
/// A git remote
|
||||||
class Remote extends $pb.GeneratedMessage {
|
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();
|
Remote._() : super();
|
||||||
factory Remote.fromBuffer($core.List<$core.int> i,
|
factory Remote.fromBuffer($core.List<$core.int> i,
|
||||||
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
|
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
|
||||||
@ -86,7 +99,23 @@ class Remote extends $pb.GeneratedMessage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class Cherrypick 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();
|
Cherrypick._() : super();
|
||||||
factory Cherrypick.fromBuffer($core.List<$core.int> i,
|
factory Cherrypick.fromBuffer($core.List<$core.int> i,
|
||||||
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
|
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
|
||||||
@ -127,6 +156,7 @@ class Cherrypick extends $pb.GeneratedMessage {
|
|||||||
_defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<Cherrypick>(create);
|
_defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<Cherrypick>(create);
|
||||||
static Cherrypick? _defaultInstance;
|
static Cherrypick? _defaultInstance;
|
||||||
|
|
||||||
|
/// The revision on trunk to cherrypick.
|
||||||
@$pb.TagNumber(1)
|
@$pb.TagNumber(1)
|
||||||
$core.String get trunkRevision => $_getSZ(0);
|
$core.String get trunkRevision => $_getSZ(0);
|
||||||
@$pb.TagNumber(1)
|
@$pb.TagNumber(1)
|
||||||
@ -139,6 +169,7 @@ class Cherrypick extends $pb.GeneratedMessage {
|
|||||||
@$pb.TagNumber(1)
|
@$pb.TagNumber(1)
|
||||||
void clearTrunkRevision() => clearField(1);
|
void clearTrunkRevision() => clearField(1);
|
||||||
|
|
||||||
|
/// Once applied, the actual commit revision of the cherrypick.
|
||||||
@$pb.TagNumber(2)
|
@$pb.TagNumber(2)
|
||||||
$core.String get appliedRevision => $_getSZ(1);
|
$core.String get appliedRevision => $_getSZ(1);
|
||||||
@$pb.TagNumber(2)
|
@$pb.TagNumber(2)
|
||||||
@ -165,7 +196,47 @@ class Cherrypick extends $pb.GeneratedMessage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class Repository 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();
|
Repository._() : super();
|
||||||
factory Repository.fromBuffer($core.List<$core.int> i,
|
factory Repository.fromBuffer($core.List<$core.int> i,
|
||||||
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
|
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
|
||||||
@ -210,6 +281,9 @@ class Repository extends $pb.GeneratedMessage {
|
|||||||
_defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<Repository>(create);
|
_defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<Repository>(create);
|
||||||
static Repository? _defaultInstance;
|
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)
|
@$pb.TagNumber(1)
|
||||||
$core.String get candidateBranch => $_getSZ(0);
|
$core.String get candidateBranch => $_getSZ(0);
|
||||||
@$pb.TagNumber(1)
|
@$pb.TagNumber(1)
|
||||||
@ -222,6 +296,7 @@ class Repository extends $pb.GeneratedMessage {
|
|||||||
@$pb.TagNumber(1)
|
@$pb.TagNumber(1)
|
||||||
void clearCandidateBranch() => clearField(1);
|
void clearCandidateBranch() => clearField(1);
|
||||||
|
|
||||||
|
/// The commit hash at the tip of the branch before cherrypicks were applied.
|
||||||
@$pb.TagNumber(2)
|
@$pb.TagNumber(2)
|
||||||
$core.String get startingGitHead => $_getSZ(1);
|
$core.String get startingGitHead => $_getSZ(1);
|
||||||
@$pb.TagNumber(2)
|
@$pb.TagNumber(2)
|
||||||
@ -234,6 +309,8 @@ class Repository extends $pb.GeneratedMessage {
|
|||||||
@$pb.TagNumber(2)
|
@$pb.TagNumber(2)
|
||||||
void clearStartingGitHead() => clearField(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)
|
@$pb.TagNumber(3)
|
||||||
$core.String get currentGitHead => $_getSZ(2);
|
$core.String get currentGitHead => $_getSZ(2);
|
||||||
@$pb.TagNumber(3)
|
@$pb.TagNumber(3)
|
||||||
@ -246,6 +323,7 @@ class Repository extends $pb.GeneratedMessage {
|
|||||||
@$pb.TagNumber(3)
|
@$pb.TagNumber(3)
|
||||||
void clearCurrentGitHead() => clearField(3);
|
void clearCurrentGitHead() => clearField(3);
|
||||||
|
|
||||||
|
/// Path to the git checkout on local disk.
|
||||||
@$pb.TagNumber(4)
|
@$pb.TagNumber(4)
|
||||||
$core.String get checkoutPath => $_getSZ(3);
|
$core.String get checkoutPath => $_getSZ(3);
|
||||||
@$pb.TagNumber(4)
|
@$pb.TagNumber(4)
|
||||||
@ -258,6 +336,7 @@ class Repository extends $pb.GeneratedMessage {
|
|||||||
@$pb.TagNumber(4)
|
@$pb.TagNumber(4)
|
||||||
void clearCheckoutPath() => clearField(4);
|
void clearCheckoutPath() => clearField(4);
|
||||||
|
|
||||||
|
/// The remote commits will be fetched from.
|
||||||
@$pb.TagNumber(5)
|
@$pb.TagNumber(5)
|
||||||
Remote get upstream => $_getN(4);
|
Remote get upstream => $_getN(4);
|
||||||
@$pb.TagNumber(5)
|
@$pb.TagNumber(5)
|
||||||
@ -272,6 +351,9 @@ class Repository extends $pb.GeneratedMessage {
|
|||||||
@$pb.TagNumber(5)
|
@$pb.TagNumber(5)
|
||||||
Remote ensureUpstream() => $_ensure(4);
|
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)
|
@$pb.TagNumber(6)
|
||||||
Remote get mirror => $_getN(5);
|
Remote get mirror => $_getN(5);
|
||||||
@$pb.TagNumber(6)
|
@$pb.TagNumber(6)
|
||||||
@ -286,9 +368,11 @@ class Repository extends $pb.GeneratedMessage {
|
|||||||
@$pb.TagNumber(6)
|
@$pb.TagNumber(6)
|
||||||
Remote ensureMirror() => $_ensure(5);
|
Remote ensureMirror() => $_ensure(5);
|
||||||
|
|
||||||
|
/// Desired cherrypicks.
|
||||||
@$pb.TagNumber(7)
|
@$pb.TagNumber(7)
|
||||||
$core.List<Cherrypick> get cherrypicks => $_getList(6);
|
$core.List<Cherrypick> get cherrypicks => $_getList(6);
|
||||||
|
|
||||||
|
/// For the repository that has a dart_revision in a DEPS file.
|
||||||
@$pb.TagNumber(8)
|
@$pb.TagNumber(8)
|
||||||
$core.String get dartRevision => $_getSZ(7);
|
$core.String get dartRevision => $_getSZ(7);
|
||||||
@$pb.TagNumber(8)
|
@$pb.TagNumber(8)
|
||||||
@ -301,6 +385,10 @@ class Repository extends $pb.GeneratedMessage {
|
|||||||
@$pb.TagNumber(8)
|
@$pb.TagNumber(8)
|
||||||
void clearDartRevision() => clearField(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)
|
@$pb.TagNumber(9)
|
||||||
$core.String get workingBranch => $_getSZ(8);
|
$core.String get workingBranch => $_getSZ(8);
|
||||||
@$pb.TagNumber(9)
|
@$pb.TagNumber(9)
|
||||||
@ -315,7 +403,51 @@ class Repository extends $pb.GeneratedMessage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class ConductorState 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();
|
ConductorState._() : super();
|
||||||
factory ConductorState.fromBuffer($core.List<$core.int> i,
|
factory ConductorState.fromBuffer($core.List<$core.int> i,
|
||||||
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
|
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
|
||||||
@ -336,7 +468,7 @@ class ConductorState extends $pb.GeneratedMessage {
|
|||||||
..pPS(8, _omitFieldNames ? '' : 'logs')
|
..pPS(8, _omitFieldNames ? '' : 'logs')
|
||||||
..e<ReleasePhase>(9, _omitFieldNames ? '' : 'currentPhase', $pb.PbFieldType.OE,
|
..e<ReleasePhase>(9, _omitFieldNames ? '' : 'currentPhase', $pb.PbFieldType.OE,
|
||||||
protoName: 'currentPhase',
|
protoName: 'currentPhase',
|
||||||
defaultOrMaker: ReleasePhase.APPLY_ENGINE_CHERRYPICKS,
|
defaultOrMaker: ReleasePhase.APPLY_FRAMEWORK_CHERRYPICKS,
|
||||||
valueOf: ReleasePhase.valueOf,
|
valueOf: ReleasePhase.valueOf,
|
||||||
enumValues: ReleasePhase.values)
|
enumValues: ReleasePhase.values)
|
||||||
..aOS(10, _omitFieldNames ? '' : 'conductorVersion', protoName: 'conductorVersion')
|
..aOS(10, _omitFieldNames ? '' : 'conductorVersion', protoName: 'conductorVersion')
|
||||||
@ -368,6 +500,7 @@ class ConductorState extends $pb.GeneratedMessage {
|
|||||||
_defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<ConductorState>(create);
|
_defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<ConductorState>(create);
|
||||||
static ConductorState? _defaultInstance;
|
static ConductorState? _defaultInstance;
|
||||||
|
|
||||||
|
/// One of 'stable', 'beta', or 'dev'
|
||||||
@$pb.TagNumber(1)
|
@$pb.TagNumber(1)
|
||||||
$core.String get releaseChannel => $_getSZ(0);
|
$core.String get releaseChannel => $_getSZ(0);
|
||||||
@$pb.TagNumber(1)
|
@$pb.TagNumber(1)
|
||||||
@ -380,6 +513,7 @@ class ConductorState extends $pb.GeneratedMessage {
|
|||||||
@$pb.TagNumber(1)
|
@$pb.TagNumber(1)
|
||||||
void clearReleaseChannel() => clearField(1);
|
void clearReleaseChannel() => clearField(1);
|
||||||
|
|
||||||
|
/// The name of the release.
|
||||||
@$pb.TagNumber(2)
|
@$pb.TagNumber(2)
|
||||||
$core.String get releaseVersion => $_getSZ(1);
|
$core.String get releaseVersion => $_getSZ(1);
|
||||||
@$pb.TagNumber(2)
|
@$pb.TagNumber(2)
|
||||||
@ -447,6 +581,7 @@ class ConductorState extends $pb.GeneratedMessage {
|
|||||||
@$pb.TagNumber(8)
|
@$pb.TagNumber(8)
|
||||||
$core.List<$core.String> get logs => $_getList(6);
|
$core.List<$core.String> get logs => $_getList(6);
|
||||||
|
|
||||||
|
/// The current [ReleasePhase] that has yet to be completed.
|
||||||
@$pb.TagNumber(9)
|
@$pb.TagNumber(9)
|
||||||
ReleasePhase get currentPhase => $_getN(7);
|
ReleasePhase get currentPhase => $_getN(7);
|
||||||
@$pb.TagNumber(9)
|
@$pb.TagNumber(9)
|
||||||
@ -459,6 +594,8 @@ class ConductorState extends $pb.GeneratedMessage {
|
|||||||
@$pb.TagNumber(9)
|
@$pb.TagNumber(9)
|
||||||
void clearCurrentPhase() => clearField(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)
|
@$pb.TagNumber(10)
|
||||||
$core.String get conductorVersion => $_getSZ(8);
|
$core.String get conductorVersion => $_getSZ(8);
|
||||||
@$pb.TagNumber(10)
|
@$pb.TagNumber(10)
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
//
|
//
|
||||||
// @dart = 2.12
|
// @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: constant_identifier_names, library_prefixes
|
||||||
// ignore_for_file: non_constant_identifier_names, prefer_final_fields
|
// ignore_for_file: non_constant_identifier_names, prefer_final_fields
|
||||||
// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
|
// 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;
|
import 'package:protobuf/protobuf.dart' as $pb;
|
||||||
|
|
||||||
class ReleasePhase extends $pb.ProtobufEnum {
|
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 =
|
static const ReleasePhase APPLY_FRAMEWORK_CHERRYPICKS =
|
||||||
ReleasePhase._(2, _omitEnumNames ? '' : 'APPLY_FRAMEWORK_CHERRYPICKS');
|
ReleasePhase._(0, _omitEnumNames ? '' : 'APPLY_FRAMEWORK_CHERRYPICKS');
|
||||||
static const ReleasePhase PUBLISH_VERSION =
|
static const ReleasePhase PUBLISH_VERSION =
|
||||||
ReleasePhase._(3, _omitEnumNames ? '' : 'PUBLISH_VERSION');
|
ReleasePhase._(1, _omitEnumNames ? '' : 'PUBLISH_VERSION');
|
||||||
static const ReleasePhase VERIFY_RELEASE =
|
static const ReleasePhase VERIFY_RELEASE =
|
||||||
ReleasePhase._(5, _omitEnumNames ? '' : 'VERIFY_RELEASE');
|
ReleasePhase._(2, _omitEnumNames ? '' : 'VERIFY_RELEASE');
|
||||||
static const ReleasePhase RELEASE_COMPLETED =
|
static const ReleasePhase RELEASE_COMPLETED =
|
||||||
ReleasePhase._(6, _omitEnumNames ? '' : 'RELEASE_COMPLETED');
|
ReleasePhase._(3, _omitEnumNames ? '' : 'RELEASE_COMPLETED');
|
||||||
|
|
||||||
static const $core.List<ReleasePhase> values = <ReleasePhase>[
|
static const $core.List<ReleasePhase> values = <ReleasePhase>[
|
||||||
APPLY_ENGINE_CHERRYPICKS,
|
|
||||||
VERIFY_ENGINE_CI,
|
|
||||||
APPLY_FRAMEWORK_CHERRYPICKS,
|
APPLY_FRAMEWORK_CHERRYPICKS,
|
||||||
PUBLISH_VERSION,
|
PUBLISH_VERSION,
|
||||||
VERIFY_RELEASE,
|
VERIFY_RELEASE,
|
||||||
@ -67,6 +61,9 @@ class CherrypickState extends $pb.ProtobufEnum {
|
|||||||
const CherrypickState._($core.int v, $core.String n) : super(v, n);
|
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 {
|
class ReleaseType extends $pb.ProtobufEnum {
|
||||||
static const ReleaseType STABLE_INITIAL =
|
static const ReleaseType STABLE_INITIAL =
|
||||||
ReleaseType._(0, _omitEnumNames ? '' : 'STABLE_INITIAL');
|
ReleaseType._(0, _omitEnumNames ? '' : 'STABLE_INITIAL');
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
//
|
//
|
||||||
// @dart = 2.12
|
// @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: constant_identifier_names, library_prefixes
|
||||||
// ignore_for_file: non_constant_identifier_names, prefer_final_fields
|
// ignore_for_file: non_constant_identifier_names, prefer_final_fields
|
||||||
// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
|
// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
|
||||||
@ -21,24 +21,17 @@ import 'dart:typed_data' as $typed_data;
|
|||||||
const ReleasePhase$json = {
|
const ReleasePhase$json = {
|
||||||
'1': 'ReleasePhase',
|
'1': 'ReleasePhase',
|
||||||
'2': [
|
'2': [
|
||||||
{'1': 'APPLY_ENGINE_CHERRYPICKS', '2': 0},
|
{'1': 'APPLY_FRAMEWORK_CHERRYPICKS', '2': 0},
|
||||||
{'1': 'VERIFY_ENGINE_CI', '2': 1},
|
{'1': 'PUBLISH_VERSION', '2': 1},
|
||||||
{'1': 'APPLY_FRAMEWORK_CHERRYPICKS', '2': 2},
|
{'1': 'VERIFY_RELEASE', '2': 2},
|
||||||
{'1': 'PUBLISH_VERSION', '2': 3},
|
{'1': 'RELEASE_COMPLETED', '2': 3},
|
||||||
{'1': 'VERIFY_RELEASE', '2': 5},
|
|
||||||
{'1': 'RELEASE_COMPLETED', '2': 6},
|
|
||||||
],
|
|
||||||
'4': [
|
|
||||||
{'1': 4, '2': 4},
|
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Descriptor for `ReleasePhase`. Decode as a `google.protobuf.EnumDescriptorProto`.
|
/// Descriptor for `ReleasePhase`. Decode as a `google.protobuf.EnumDescriptorProto`.
|
||||||
final $typed_data.Uint8List releasePhaseDescriptor = $convert
|
final $typed_data.Uint8List releasePhaseDescriptor = $convert
|
||||||
.base64Decode('CgxSZWxlYXNlUGhhc2USHAoYQVBQTFlfRU5HSU5FX0NIRVJSWVBJQ0tTEAASFAoQVkVSSUZZX0'
|
.base64Decode('CgxSZWxlYXNlUGhhc2USHwobQVBQTFlfRlJBTUVXT1JLX0NIRVJSWVBJQ0tTEAASEwoPUFVCTE'
|
||||||
'VOR0lORV9DSRABEh8KG0FQUExZX0ZSQU1FV09SS19DSEVSUllQSUNLUxACEhMKD1BVQkxJU0hf'
|
'lTSF9WRVJTSU9OEAESEgoOVkVSSUZZX1JFTEVBU0UQAhIVChFSRUxFQVNFX0NPTVBMRVRFRBAD');
|
||||||
'VkVSU0lPThADEhIKDlZFUklGWV9SRUxFQVNFEAUSFQoRUkVMRUFTRV9DT01QTEVURUQQBiIECA'
|
|
||||||
'QQBA==');
|
|
||||||
|
|
||||||
@$core.Deprecated('Use cherrypickStateDescriptor instead')
|
@$core.Deprecated('Use cherrypickStateDescriptor instead')
|
||||||
const CherrypickState$json = {
|
const CherrypickState$json = {
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
//
|
//
|
||||||
// @dart = 2.12
|
// @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: constant_identifier_names
|
||||||
// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
|
// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
|
||||||
// ignore_for_file: non_constant_identifier_names, prefer_final_fields
|
// ignore_for_file: non_constant_identifier_names, prefer_final_fields
|
||||||
|
@ -9,24 +9,16 @@ message Remote {
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum ReleasePhase {
|
enum ReleasePhase {
|
||||||
// Release was started with `conductor start` and repositories cloned.
|
APPLY_FRAMEWORK_CHERRYPICKS = 0;
|
||||||
APPLY_ENGINE_CHERRYPICKS = 0;
|
|
||||||
|
|
||||||
// Verify engine CI is green before opening framework PR.
|
|
||||||
VERIFY_ENGINE_CI = 1;
|
|
||||||
|
|
||||||
APPLY_FRAMEWORK_CHERRYPICKS = 2;
|
|
||||||
|
|
||||||
// Git tag applied to framework RC branch HEAD and pushed upstream.
|
// Git tag applied to framework RC branch HEAD and pushed upstream.
|
||||||
PUBLISH_VERSION = 3;
|
PUBLISH_VERSION = 1;
|
||||||
|
|
||||||
reserved 4; // Formerly PUBLISH_CHANNEL, merged into PUBLISH_VERSION.
|
|
||||||
|
|
||||||
// Package artifacts verified to exist on cloud storage.
|
// Package artifacts verified to exist on cloud storage.
|
||||||
VERIFY_RELEASE = 5;
|
VERIFY_RELEASE = 2;
|
||||||
|
|
||||||
// There is no further work to be done.
|
// There is no further work to be done.
|
||||||
RELEASE_COMPLETED = 6;
|
RELEASE_COMPLETED = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum CherrypickState {
|
enum CherrypickState {
|
||||||
@ -100,7 +92,7 @@ message Repository {
|
|||||||
// Desired cherrypicks.
|
// Desired cherrypicks.
|
||||||
repeated Cherrypick cherrypicks = 7;
|
repeated Cherrypick cherrypicks = 7;
|
||||||
|
|
||||||
// Only for engine repositories.
|
// For the repository that has a dart_revision in a DEPS file.
|
||||||
string dartRevision = 8;
|
string dartRevision = 8;
|
||||||
|
|
||||||
// Name of local and remote branch for applying cherrypicks.
|
// Name of local and remote branch for applying cherrypicks.
|
||||||
|
@ -683,33 +683,9 @@ class FrameworkRepository extends Repository {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update this framework's engine version file.
|
/// Update the `dart_revision` entry in the DEPS file.
|
||||||
///
|
Future<void> updateDartRevision(String newRevision, {@visibleForTesting File? depsFile}) async {
|
||||||
/// Returns [true] if the version file was updated and a commit is needed.
|
return _updateDartRevision(this, newRevision, depsFile: depsFile);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -770,63 +746,45 @@ class HostFrameworkRepository extends FrameworkRepository {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class EngineRepository extends Repository {
|
//class EngineRepository extends Repository {
|
||||||
EngineRepository(
|
// EngineRepository(
|
||||||
this.checkouts, {
|
// this.checkouts, {
|
||||||
super.name = 'engine',
|
// super.name = 'engine',
|
||||||
String super.initialRef = EngineRepository.defaultBranch,
|
// String super.initialRef = EngineRepository.defaultBranch,
|
||||||
super.upstreamRemote = const Remote.upstream(EngineRepository.defaultUpstream),
|
// super.upstreamRemote = const Remote.upstream(EngineRepository.defaultUpstream),
|
||||||
super.localUpstream,
|
// super.localUpstream,
|
||||||
super.previousCheckoutLocation,
|
// super.previousCheckoutLocation,
|
||||||
super.mirrorRemote,
|
// super.mirrorRemote,
|
||||||
List<String>? additionalRequiredLocalBranches,
|
// List<String>? additionalRequiredLocalBranches,
|
||||||
}) : super(
|
// }) : super(
|
||||||
fileSystem: checkouts.fileSystem,
|
// fileSystem: checkouts.fileSystem,
|
||||||
parentDirectory: checkouts.directory,
|
// parentDirectory: checkouts.directory,
|
||||||
platform: checkouts.platform,
|
// platform: checkouts.platform,
|
||||||
processManager: checkouts.processManager,
|
// processManager: checkouts.processManager,
|
||||||
stdio: checkouts.stdio,
|
// stdio: checkouts.stdio,
|
||||||
requiredLocalBranches: additionalRequiredLocalBranches ?? const <String>[],
|
// requiredLocalBranches: additionalRequiredLocalBranches ?? const <String>[],
|
||||||
);
|
// );
|
||||||
|
//
|
||||||
final Checkouts checkouts;
|
// final Checkouts checkouts;
|
||||||
|
//
|
||||||
static const String defaultUpstream = 'git@github.com:flutter/engine.git';
|
// static const String defaultUpstream = 'git@github.com:flutter/engine.git';
|
||||||
static const String defaultBranch = 'main';
|
// static const String defaultBranch = 'main';
|
||||||
|
//
|
||||||
/// Update the `dart_revision` entry in the DEPS file.
|
// /// Update the `dart_revision` entry in the DEPS file.
|
||||||
Future<void> updateDartRevision(String newRevision, {@visibleForTesting File? depsFile}) async {
|
// Future<void> updateDartRevision(String newRevision, {@visibleForTesting File? depsFile}) =>
|
||||||
assert(newRevision.length == 40);
|
// _updateDartRevision(this, newRevision, depsFile: depsFile);
|
||||||
depsFile ??= (await checkoutDirectory).childFile('DEPS');
|
//
|
||||||
final String fileContent = depsFile.readAsStringSync();
|
// @override
|
||||||
final RegExp dartPattern = RegExp("[ ]+'dart_revision': '([a-z0-9]{40})',");
|
// Future<Repository> cloneRepository(String? cloneName) async {
|
||||||
final Iterable<RegExpMatch> allMatches = dartPattern.allMatches(fileContent);
|
// assert(localUpstream);
|
||||||
if (allMatches.length != 1) {
|
// cloneName ??= 'clone-of-$name';
|
||||||
throw ConductorException(
|
// return EngineRepository(
|
||||||
'Unexpected content in the DEPS file at ${depsFile.path}\n'
|
// checkouts,
|
||||||
'Expected to find pattern ${dartPattern.pattern} 1 times, but got '
|
// name: cloneName,
|
||||||
'${allMatches.length}.',
|
// upstreamRemote: Remote.upstream('file://${(await checkoutDirectory).path}/'),
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
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}/'),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An enum of all the repositories that the Conductor supports.
|
/// An enum of all the repositories that the Conductor supports.
|
||||||
enum RepositoryType { framework, engine }
|
enum RepositoryType { framework, engine }
|
||||||
@ -851,3 +809,28 @@ class Checkouts {
|
|||||||
final ProcessManager processManager;
|
final ProcessManager processManager;
|
||||||
final Stdio stdio;
|
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.',
|
help: 'Configurable Framework repo upstream remote. Primarily for testing.',
|
||||||
hide: true,
|
hide: true,
|
||||||
);
|
);
|
||||||
argParser.addOption(
|
|
||||||
kEngineUpstreamOption,
|
|
||||||
defaultsTo: EngineRepository.defaultUpstream,
|
|
||||||
help: 'Configurable Engine repo upstream remote. Primarily for testing.',
|
|
||||||
hide: true,
|
|
||||||
);
|
|
||||||
argParser.addOption(
|
argParser.addOption(
|
||||||
kStateOption,
|
kStateOption,
|
||||||
defaultsTo: defaultPath,
|
defaultsTo: defaultPath,
|
||||||
@ -119,9 +113,6 @@ class StartCommand extends Command<void> {
|
|||||||
allowNull: true,
|
allowNull: true,
|
||||||
) ??
|
) ??
|
||||||
'git@github.com:$githubUsername/flutter.git';
|
'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 =
|
final String candidateBranch =
|
||||||
getValueFromEnvOrArgs(kCandidateOption, argumentResults, platform.environment)!;
|
getValueFromEnvOrArgs(kCandidateOption, argumentResults, platform.environment)!;
|
||||||
final String releaseChannel =
|
final String releaseChannel =
|
||||||
@ -151,8 +142,6 @@ class StartCommand extends Command<void> {
|
|||||||
candidateBranch: candidateBranch,
|
candidateBranch: candidateBranch,
|
||||||
checkouts: checkouts,
|
checkouts: checkouts,
|
||||||
dartRevision: dartRevision,
|
dartRevision: dartRevision,
|
||||||
engineMirror: engineMirror,
|
|
||||||
engineUpstream: engineUpstream,
|
|
||||||
conductorVersion: conductorVersion,
|
conductorVersion: conductorVersion,
|
||||||
frameworkMirror: frameworkMirror,
|
frameworkMirror: frameworkMirror,
|
||||||
frameworkUpstream: frameworkUpstream,
|
frameworkUpstream: frameworkUpstream,
|
||||||
@ -183,8 +172,6 @@ class StartContext extends Context {
|
|||||||
StartContext({
|
StartContext({
|
||||||
required this.candidateBranch,
|
required this.candidateBranch,
|
||||||
required this.dartRevision,
|
required this.dartRevision,
|
||||||
required this.engineMirror,
|
|
||||||
required this.engineUpstream,
|
|
||||||
required this.frameworkMirror,
|
required this.frameworkMirror,
|
||||||
required this.frameworkUpstream,
|
required this.frameworkUpstream,
|
||||||
required this.conductorVersion,
|
required this.conductorVersion,
|
||||||
@ -196,12 +183,6 @@ class StartContext extends Context {
|
|||||||
this.force = false,
|
this.force = false,
|
||||||
this.versionOverride,
|
this.versionOverride,
|
||||||
}) : git = Git(processManager),
|
}) : git = Git(processManager),
|
||||||
engine = EngineRepository(
|
|
||||||
checkouts,
|
|
||||||
initialRef: 'upstream/$candidateBranch',
|
|
||||||
upstreamRemote: Remote.upstream(engineUpstream),
|
|
||||||
mirrorRemote: Remote.mirror(engineMirror),
|
|
||||||
),
|
|
||||||
framework = FrameworkRepository(
|
framework = FrameworkRepository(
|
||||||
checkouts,
|
checkouts,
|
||||||
initialRef: 'upstream/$candidateBranch',
|
initialRef: 'upstream/$candidateBranch',
|
||||||
@ -211,8 +192,6 @@ class StartContext extends Context {
|
|||||||
|
|
||||||
final String candidateBranch;
|
final String candidateBranch;
|
||||||
final String? dartRevision;
|
final String? dartRevision;
|
||||||
final String engineMirror;
|
|
||||||
final String engineUpstream;
|
|
||||||
final String frameworkMirror;
|
final String frameworkMirror;
|
||||||
final String frameworkUpstream;
|
final String frameworkUpstream;
|
||||||
final String conductorVersion;
|
final String conductorVersion;
|
||||||
@ -225,7 +204,6 @@ class StartContext extends Context {
|
|||||||
/// If validations should be overridden.
|
/// If validations should be overridden.
|
||||||
final bool force;
|
final bool force;
|
||||||
|
|
||||||
final EngineRepository engine;
|
|
||||||
final FrameworkRepository framework;
|
final FrameworkRepository framework;
|
||||||
|
|
||||||
/// Determine which part of the version to increment in the next release.
|
/// 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
|
// Create a new branch so that we don't accidentally push to upstream
|
||||||
// candidateBranch.
|
// candidateBranch.
|
||||||
final String workingBranchName = 'cherrypicks-$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 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 =
|
state.framework =
|
||||||
(pb.Repository.create()
|
(pb.Repository.create()
|
||||||
..candidateBranch = candidateBranch
|
..candidateBranch = candidateBranch
|
||||||
@ -353,7 +268,46 @@ class StartContext extends Context {
|
|||||||
..name = 'mirror'
|
..name = 'mirror'
|
||||||
..url = framework.mirrorRemote!.url));
|
..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;
|
state.conductorVersion = conductorVersion;
|
||||||
|
|
||||||
|
@ -82,26 +82,6 @@ String presentState(pb.ConductorState state) {
|
|||||||
buffer.writeln(
|
buffer.writeln(
|
||||||
'Last updated at: ${DateTime.fromMillisecondsSinceEpoch(state.lastUpdatedDate.toInt())}',
|
'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('Framework Repo');
|
||||||
buffer.writeln('\tCandidate branch: ${state.framework.candidateBranch}');
|
buffer.writeln('\tCandidate branch: ${state.framework.candidateBranch}');
|
||||||
buffer.writeln('\tStarting git HEAD: ${state.framework.startingGitHead}');
|
buffer.writeln('\tStarting git HEAD: ${state.framework.startingGitHead}');
|
||||||
@ -118,6 +98,9 @@ String presentState(pb.ConductorState state) {
|
|||||||
} else {
|
} else {
|
||||||
buffer.writeln('0 Framework cherrypicks.');
|
buffer.writeln('0 Framework cherrypicks.');
|
||||||
}
|
}
|
||||||
|
if (state.framework.dartRevision.isNotEmpty) {
|
||||||
|
buffer.writeln('New Dart SDK revision: ${state.engine.dartRevision}');
|
||||||
|
}
|
||||||
buffer.writeln();
|
buffer.writeln();
|
||||||
if (state.currentPhase == ReleasePhase.VERIFY_RELEASE) {
|
if (state.currentPhase == ReleasePhase.VERIFY_RELEASE) {
|
||||||
buffer.writeln(
|
buffer.writeln(
|
||||||
@ -156,43 +139,6 @@ String presentPhases(ReleasePhase currentPhase) {
|
|||||||
|
|
||||||
String phaseInstructions(pb.ConductorState state) {
|
String phaseInstructions(pb.ConductorState state) {
|
||||||
switch (state.currentPhase) {
|
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:
|
case ReleasePhase.APPLY_FRAMEWORK_CHERRYPICKS:
|
||||||
final List<pb.Cherrypick> outstandingCherrypicks =
|
final List<pb.Cherrypick> outstandingCherrypicks =
|
||||||
state.framework.cherrypicks.where((pb.Cherrypick cp) {
|
state.framework.cherrypicks.where((pb.Cherrypick cp) {
|
||||||
@ -280,8 +226,6 @@ ReleasePhase getNextPhase(ReleasePhase currentPhase) {
|
|||||||
switch (currentPhase) {
|
switch (currentPhase) {
|
||||||
case ReleasePhase.PUBLISH_VERSION:
|
case ReleasePhase.PUBLISH_VERSION:
|
||||||
return ReleasePhase.VERIFY_RELEASE;
|
return ReleasePhase.VERIFY_RELEASE;
|
||||||
case ReleasePhase.APPLY_ENGINE_CHERRYPICKS:
|
|
||||||
case ReleasePhase.VERIFY_ENGINE_CI:
|
|
||||||
case ReleasePhase.APPLY_FRAMEWORK_CHERRYPICKS:
|
case ReleasePhase.APPLY_FRAMEWORK_CHERRYPICKS:
|
||||||
case ReleasePhase.VERIFY_RELEASE:
|
case ReleasePhase.VERIFY_RELEASE:
|
||||||
case ReleasePhase.RELEASE_COMPLETED:
|
case ReleasePhase.RELEASE_COMPLETED:
|
||||||
|
@ -22,11 +22,8 @@ void main() {
|
|||||||
const String checkoutsParentDirectory = '$flutterRoot/dev/conductor';
|
const String checkoutsParentDirectory = '$flutterRoot/dev/conductor';
|
||||||
const String candidateBranch = 'flutter-1.2-candidate.3';
|
const String candidateBranch = 'flutter-1.2-candidate.3';
|
||||||
const String workingBranch = 'cherrypicks-$candidateBranch';
|
const String workingBranch = 'cherrypicks-$candidateBranch';
|
||||||
const String remoteUrl = 'https://github.com/org/repo.git';
|
|
||||||
const String revision1 = 'd3af60d18e01fcb36e0c0fa06c8502e4935ed095';
|
const String revision1 = 'd3af60d18e01fcb36e0c0fa06c8502e4935ed095';
|
||||||
const String revision2 = 'f99555c1e1392bf2a8135056b9446680c2af4ddf';
|
|
||||||
const String revision3 = 'ffffffffffffffffffffffffffffffffffffffff';
|
const String revision3 = 'ffffffffffffffffffffffffffffffffffffffff';
|
||||||
const String revision4 = '280e23318a0d8341415c66aa32581352a421d974';
|
|
||||||
const String releaseVersion = '1.2.0-3.0.pre';
|
const String releaseVersion = '1.2.0-3.0.pre';
|
||||||
const String releaseChannel = 'beta';
|
const String releaseChannel = 'beta';
|
||||||
const String stateFile = '/state-file.json';
|
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', () {
|
group('APPLY_FRAMEWORK_CHERRYPICKS to PUBLISH_VERSION', () {
|
||||||
const String mirrorRemoteUrl = 'https://github.com/org/repo.git';
|
const String mirrorRemoteUrl = 'https://github.com/org/repo.git';
|
||||||
const String upstreamRemoteUrl = 'https://github.com/mirror/repo.git';
|
const String upstreamRemoteUrl = 'https://github.com/mirror/repo.git';
|
||||||
@ -359,218 +136,9 @@ void main() {
|
|||||||
engineRevisionFile.writeAsStringSync(oldEngineVersion, flush: true);
|
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 {
|
test('does not update state.currentPhase if user responds no', () async {
|
||||||
stdio.stdin.add('n');
|
stdio.stdin.add('n');
|
||||||
processManager.addCommands(<FakeCommand>[
|
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', 'fetch', 'upstream']),
|
||||||
const FakeCommand(command: <String>['git', 'checkout', workingBranch]),
|
const FakeCommand(command: <String>['git', 'checkout', workingBranch]),
|
||||||
const FakeCommand(
|
const FakeCommand(
|
||||||
@ -587,20 +155,6 @@ void main() {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
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', '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>[]);
|
writeStateToFile(fileSystem.file(stateFile), state, <String>[]);
|
||||||
final Checkouts checkouts = Checkouts(
|
final Checkouts checkouts = Checkouts(
|
||||||
@ -616,6 +170,7 @@ void main() {
|
|||||||
|
|
||||||
final pb.ConductorState finalState = readStateFromFile(fileSystem.file(stateFile));
|
final pb.ConductorState finalState = readStateFromFile(fileSystem.file(stateFile));
|
||||||
|
|
||||||
|
expect(processManager, hasNoRemainingExpectations);
|
||||||
expect(
|
expect(
|
||||||
stdio.stdout,
|
stdio.stdout,
|
||||||
contains(
|
contains(
|
||||||
@ -631,11 +186,6 @@ void main() {
|
|||||||
processManager.addCommands(<FakeCommand>[
|
processManager.addCommands(<FakeCommand>[
|
||||||
// Engine repo
|
// Engine repo
|
||||||
const FakeCommand(command: <String>['git', 'fetch', 'upstream']),
|
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(
|
FakeCommand(
|
||||||
command: const <String>['git', 'checkout', workingBranch],
|
command: const <String>['git', 'checkout', workingBranch],
|
||||||
onRun: (_) {
|
onRun: (_) {
|
||||||
@ -658,20 +208,6 @@ void main() {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
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', '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(
|
const FakeCommand(
|
||||||
command: <String>['git', 'push', 'mirror', 'HEAD:refs/heads/$workingBranch'],
|
command: <String>['git', 'push', 'mirror', 'HEAD:refs/heads/$workingBranch'],
|
||||||
),
|
),
|
||||||
@ -691,10 +227,6 @@ void main() {
|
|||||||
final pb.ConductorState finalState = readStateFromFile(fileSystem.file(stateFile));
|
final pb.ConductorState finalState = readStateFromFile(fileSystem.file(stateFile));
|
||||||
|
|
||||||
expect(finalState.currentPhase, ReleasePhase.PUBLISH_VERSION);
|
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, contains('There was 1 cherrypick that was not auto-applied'));
|
||||||
expect(
|
expect(
|
||||||
stdio.stdout,
|
stdio.stdout,
|
||||||
@ -723,10 +255,6 @@ void main() {
|
|||||||
(pb.Repository.create()
|
(pb.Repository.create()
|
||||||
..candidateBranch = candidateBranch
|
..candidateBranch = candidateBranch
|
||||||
..upstream = (pb.Remote.create()..url = FrameworkRepository.defaultUpstream))
|
..upstream = (pb.Remote.create()..url = FrameworkRepository.defaultUpstream))
|
||||||
..engine =
|
|
||||||
(pb.Repository.create()
|
|
||||||
..candidateBranch = candidateBranch
|
|
||||||
..upstream = (pb.Remote.create()..url = EngineRepository.defaultUpstream))
|
|
||||||
..releaseVersion = releaseVersion);
|
..releaseVersion = releaseVersion);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ void main() {
|
|||||||
stdio: stdio,
|
stdio: stdio,
|
||||||
);
|
);
|
||||||
|
|
||||||
final EngineRepository repo = EngineRepository(checkouts);
|
final FrameworkRepository repo = FrameworkRepository(checkouts);
|
||||||
final File depsFile = fileSystem.file('/DEPS');
|
final File depsFile = fileSystem.file('/DEPS');
|
||||||
depsFile.writeAsStringSync(generateMockDeps(previousDartRevision));
|
depsFile.writeAsStringSync(generateMockDeps(previousDartRevision));
|
||||||
await repo.updateDartRevision(nextDartRevision, depsFile: depsFile);
|
await repo.updateDartRevision(nextDartRevision, depsFile: depsFile);
|
||||||
@ -62,7 +62,7 @@ void main() {
|
|||||||
stdio: stdio,
|
stdio: stdio,
|
||||||
);
|
);
|
||||||
|
|
||||||
final EngineRepository repo = EngineRepository(checkouts);
|
final FrameworkRepository repo = FrameworkRepository(checkouts);
|
||||||
final File depsFile = fileSystem.file('/DEPS');
|
final File depsFile = fileSystem.file('/DEPS');
|
||||||
depsFile.writeAsStringSync('''
|
depsFile.writeAsStringSync('''
|
||||||
vars = {
|
vars = {
|
||||||
@ -85,11 +85,11 @@ vars = {
|
|||||||
'--origin',
|
'--origin',
|
||||||
'upstream',
|
'upstream',
|
||||||
'--',
|
'--',
|
||||||
EngineRepository.defaultUpstream,
|
FrameworkRepository.defaultUpstream,
|
||||||
fileSystem.path.join(rootDir, 'flutter_conductor_checkouts', 'engine'),
|
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', 'rev-parse', 'HEAD'], stdout: commit1),
|
||||||
const FakeCommand(command: <String>['git', 'status', '--porcelain']),
|
const FakeCommand(command: <String>['git', 'status', '--porcelain']),
|
||||||
const FakeCommand(command: <String>['git', 'commit', '--message', message]),
|
const FakeCommand(command: <String>['git', 'commit', '--message', message]),
|
||||||
@ -104,7 +104,7 @@ vars = {
|
|||||||
stdio: stdio,
|
stdio: stdio,
|
||||||
);
|
);
|
||||||
|
|
||||||
final EngineRepository repo = EngineRepository(checkouts);
|
final FrameworkRepository repo = FrameworkRepository(checkouts);
|
||||||
expect(
|
expect(
|
||||||
() async => repo.commit(message),
|
() async => repo.commit(message),
|
||||||
throwsExceptionWith('Tried to commit with message $message but no changes were present'),
|
throwsExceptionWith('Tried to commit with message $message but no changes were present'),
|
||||||
@ -123,11 +123,11 @@ vars = {
|
|||||||
'--origin',
|
'--origin',
|
||||||
'upstream',
|
'upstream',
|
||||||
'--',
|
'--',
|
||||||
EngineRepository.defaultUpstream,
|
FrameworkRepository.defaultUpstream,
|
||||||
fileSystem.path.join(rootDir, 'flutter_conductor_checkouts', 'engine'),
|
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', 'rev-parse', 'HEAD'], stdout: commit1),
|
||||||
const FakeCommand(
|
const FakeCommand(
|
||||||
command: <String>['git', 'status', '--porcelain'],
|
command: <String>['git', 'status', '--porcelain'],
|
||||||
@ -145,7 +145,7 @@ vars = {
|
|||||||
stdio: stdio,
|
stdio: stdio,
|
||||||
);
|
);
|
||||||
|
|
||||||
final EngineRepository repo = EngineRepository(checkouts);
|
final FrameworkRepository repo = FrameworkRepository(checkouts);
|
||||||
await repo.commit(message);
|
await repo.commit(message);
|
||||||
expect(processManager.hasRemainingExpectations, false);
|
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(
|
test(
|
||||||
'framework repo set as localUpstream ensures requiredLocalBranches exist locally',
|
'framework repo set as localUpstream ensures requiredLocalBranches exist locally',
|
||||||
() async {
|
() 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 {
|
test('.listRemoteBranches() parses git output', () async {
|
||||||
const String remoteName = 'mirror';
|
const String remoteName = 'mirror';
|
||||||
const String lsRemoteOutput = '''
|
const String lsRemoteOutput = '''
|
||||||
@ -326,11 +248,14 @@ Extraneous debug information that should be ignored.
|
|||||||
'--origin',
|
'--origin',
|
||||||
'upstream',
|
'upstream',
|
||||||
'--',
|
'--',
|
||||||
EngineRepository.defaultUpstream,
|
FrameworkRepository.defaultUpstream,
|
||||||
'${rootDir}flutter_conductor_checkouts/engine',
|
'${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', 'rev-parse', 'HEAD'], stdout: revision),
|
||||||
FakeCommand(
|
FakeCommand(
|
||||||
command: <String>['git', 'ls-remote', '--heads', remoteName],
|
command: <String>['git', 'ls-remote', '--heads', remoteName],
|
||||||
@ -345,7 +270,7 @@ Extraneous debug information that should be ignored.
|
|||||||
stdio: stdio,
|
stdio: stdio,
|
||||||
);
|
);
|
||||||
|
|
||||||
final Repository repo = EngineRepository(checkouts, localUpstream: true);
|
final Repository repo = FrameworkRepository(checkouts, localUpstream: true);
|
||||||
final List<String> branchNames = await repo.listRemoteBranches(remoteName);
|
final List<String> branchNames = await repo.listRemoteBranches(remoteName);
|
||||||
expect(
|
expect(
|
||||||
branchNames,
|
branchNames,
|
||||||
|
@ -25,7 +25,6 @@ void main() {
|
|||||||
const String checkoutsParentDirectory = '$flutterRoot/dev/tools/';
|
const String checkoutsParentDirectory = '$flutterRoot/dev/tools/';
|
||||||
const String githubUsername = 'user';
|
const String githubUsername = 'user';
|
||||||
const String frameworkMirror = 'git@github.com:$githubUsername/flutter.git';
|
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 candidateBranch = 'flutter-1.2-candidate.3';
|
||||||
const String releaseChannel = 'beta';
|
const String releaseChannel = 'beta';
|
||||||
const String revision = 'abcd1234';
|
const String revision = 'abcd1234';
|
||||||
@ -117,7 +116,6 @@ void main() {
|
|||||||
expect(context.frameworkUpstream, FrameworkRepository.defaultUpstream);
|
expect(context.frameworkUpstream, FrameworkRepository.defaultUpstream);
|
||||||
expect(context.frameworkMirror, contains(githubUsername));
|
expect(context.frameworkMirror, contains(githubUsername));
|
||||||
expect(context.frameworkMirror, contains('/flutter.git'));
|
expect(context.frameworkMirror, contains('/flutter.git'));
|
||||||
expect(context.engineUpstream, EngineRepository.defaultUpstream);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('overridden mirror', () async {
|
test('overridden mirror', () async {
|
||||||
@ -202,50 +200,8 @@ void main() {
|
|||||||
const String nextVersion = '1.2.0-1.1.pre';
|
const String nextVersion = '1.2.0-1.1.pre';
|
||||||
const String candidateBranch = 'flutter-1.2-candidate.1';
|
const String candidateBranch = 'flutter-1.2-candidate.1';
|
||||||
|
|
||||||
final Directory engine = fileSystem
|
final List<FakeCommand> commands = <FakeCommand>[
|
||||||
.directory(checkoutsParentDirectory)
|
// clone and rev-parse framework
|
||||||
.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(
|
FakeCommand(
|
||||||
command: <String>[
|
command: <String>[
|
||||||
'git',
|
'git',
|
||||||
@ -260,14 +216,35 @@ void main() {
|
|||||||
'framework',
|
'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', 'remote', 'add', 'mirror', frameworkMirror]),
|
||||||
const FakeCommand(command: <String>['git', 'fetch', 'mirror']),
|
const FakeCommand(command: <String>['git', 'fetch', 'mirror']),
|
||||||
const FakeCommand(command: <String>['git', 'checkout', 'upstream/$candidateBranch']),
|
const FakeCommand(command: <String>['git', 'checkout', 'upstream/$candidateBranch']),
|
||||||
const FakeCommand(command: <String>['git', 'rev-parse', 'HEAD'], stdout: revision3),
|
const FakeCommand(command: <String>['git', 'rev-parse', 'HEAD'], stdout: revision3),
|
||||||
const FakeCommand(
|
const FakeCommand(command: <String>['git', 'rev-parse', 'HEAD'], stdout: revision3),
|
||||||
command: <String>['git', 'checkout', '-b', 'cherrypicks-$candidateBranch'],
|
|
||||||
),
|
|
||||||
const FakeCommand(
|
const FakeCommand(
|
||||||
command: <String>[
|
command: <String>[
|
||||||
'git',
|
'git',
|
||||||
@ -279,7 +256,7 @@ void main() {
|
|||||||
],
|
],
|
||||||
stdout: '$previousVersion-42-gabc123',
|
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(
|
const FakeCommand(
|
||||||
command: <String>['git', 'merge-base', 'upstream/$candidateBranch', 'upstream/master'],
|
command: <String>['git', 'merge-base', 'upstream/$candidateBranch', 'upstream/master'],
|
||||||
stdout: branchPointRevision,
|
stdout: branchPointRevision,
|
||||||
@ -288,11 +265,24 @@ void main() {
|
|||||||
const FakeCommand(
|
const FakeCommand(
|
||||||
command: <String>['git', 'describe', '--exact-match', '--tags', branchPointRevision],
|
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(
|
final CommandRunner<void> runner = createRunner(commands: commands);
|
||||||
commands: <FakeCommand>[...engineCommands, ...frameworkCommands],
|
|
||||||
);
|
|
||||||
|
|
||||||
final String stateFilePath = fileSystem.path.join(
|
final String stateFilePath = fileSystem.path.join(
|
||||||
platform.environment['HOME']!,
|
platform.environment['HOME']!,
|
||||||
@ -327,14 +317,10 @@ void main() {
|
|||||||
expect(state.isInitialized(), true);
|
expect(state.isInitialized(), true);
|
||||||
expect(state.releaseChannel, releaseChannel);
|
expect(state.releaseChannel, releaseChannel);
|
||||||
expect(state.releaseVersion, nextVersion);
|
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.candidateBranch, candidateBranch);
|
||||||
expect(state.framework.startingGitHead, revision3);
|
expect(state.framework.startingGitHead, revision3);
|
||||||
expect(state.framework.upstream.url, 'git@github.com:flutter/flutter.git');
|
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);
|
expect(state.conductorVersion, conductorVersion);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -348,50 +334,8 @@ void main() {
|
|||||||
const String candidateBranch = 'flutter-1.2-candidate.1';
|
const String candidateBranch = 'flutter-1.2-candidate.1';
|
||||||
const String versionOverride = '42.0.0-42.0.pre';
|
const String versionOverride = '42.0.0-42.0.pre';
|
||||||
|
|
||||||
final Directory engine = fileSystem
|
final List<FakeCommand> commands = <FakeCommand>[
|
||||||
.directory(checkoutsParentDirectory)
|
// clone and rev-parse framework
|
||||||
.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(
|
FakeCommand(
|
||||||
command: <String>[
|
command: <String>[
|
||||||
'git',
|
'git',
|
||||||
@ -406,14 +350,35 @@ void main() {
|
|||||||
'framework',
|
'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', 'remote', 'add', 'mirror', frameworkMirror]),
|
||||||
const FakeCommand(command: <String>['git', 'fetch', 'mirror']),
|
const FakeCommand(command: <String>['git', 'fetch', 'mirror']),
|
||||||
const FakeCommand(command: <String>['git', 'checkout', 'upstream/$candidateBranch']),
|
const FakeCommand(command: <String>['git', 'checkout', 'upstream/$candidateBranch']),
|
||||||
const FakeCommand(command: <String>['git', 'rev-parse', 'HEAD'], stdout: revision3),
|
const FakeCommand(command: <String>['git', 'rev-parse', 'HEAD'], stdout: revision3),
|
||||||
const FakeCommand(
|
const FakeCommand(command: <String>['git', 'rev-parse', 'HEAD'], stdout: revision3),
|
||||||
command: <String>['git', 'checkout', '-b', 'cherrypicks-$candidateBranch'],
|
|
||||||
),
|
|
||||||
const FakeCommand(
|
const FakeCommand(
|
||||||
command: <String>[
|
command: <String>[
|
||||||
'git',
|
'git',
|
||||||
@ -425,16 +390,26 @@ void main() {
|
|||||||
],
|
],
|
||||||
stdout: '$previousVersion-42-gabc123',
|
stdout: '$previousVersion-42-gabc123',
|
||||||
),
|
),
|
||||||
const FakeCommand(command: <String>['git', 'rev-parse', 'HEAD'], stdout: revision3),
|
|
||||||
const FakeCommand(
|
const FakeCommand(
|
||||||
command: <String>['git', 'merge-base', 'upstream/$candidateBranch', 'upstream/master'],
|
command: <String>['git', 'merge-base', 'upstream/$candidateBranch', 'upstream/master'],
|
||||||
stdout: branchPointRevision,
|
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(
|
final CommandRunner<void> runner = createRunner(commands: commands);
|
||||||
commands: <FakeCommand>[...engineCommands, ...frameworkCommands],
|
|
||||||
);
|
|
||||||
|
|
||||||
final String stateFilePath = fileSystem.path.join(
|
final String stateFilePath = fileSystem.path.join(
|
||||||
platform.environment['HOME']!,
|
platform.environment['HOME']!,
|
||||||
@ -466,156 +441,6 @@ void main() {
|
|||||||
expect(state.releaseVersion, versionOverride);
|
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 {
|
test('can convert from dev style version to stable version', () async {
|
||||||
const String revision2 = 'def789';
|
const String revision2 = 'def789';
|
||||||
const String revision3 = '123abc';
|
const String revision3 = '123abc';
|
||||||
@ -624,50 +449,8 @@ void main() {
|
|||||||
const String previousVersion = '1.2.0-3.0.pre';
|
const String previousVersion = '1.2.0-3.0.pre';
|
||||||
const String nextVersion = '1.2.0';
|
const String nextVersion = '1.2.0';
|
||||||
|
|
||||||
final Directory engine = fileSystem
|
final List<FakeCommand> commands = <FakeCommand>[
|
||||||
.directory(checkoutsParentDirectory)
|
// rev-parse framework
|
||||||
.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(
|
FakeCommand(
|
||||||
command: <String>[
|
command: <String>[
|
||||||
'git',
|
'git',
|
||||||
@ -682,14 +465,35 @@ void main() {
|
|||||||
'framework',
|
'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', 'remote', 'add', 'mirror', frameworkMirror]),
|
||||||
const FakeCommand(command: <String>['git', 'fetch', 'mirror']),
|
const FakeCommand(command: <String>['git', 'fetch', 'mirror']),
|
||||||
const FakeCommand(command: <String>['git', 'checkout', 'upstream/$candidateBranch']),
|
const FakeCommand(command: <String>['git', 'checkout', 'upstream/$candidateBranch']),
|
||||||
const FakeCommand(command: <String>['git', 'rev-parse', 'HEAD'], stdout: revision3),
|
const FakeCommand(command: <String>['git', 'rev-parse', 'HEAD'], stdout: revision3),
|
||||||
const FakeCommand(
|
const FakeCommand(command: <String>['git', 'rev-parse', 'HEAD'], stdout: revision3),
|
||||||
command: <String>['git', 'checkout', '-b', 'cherrypicks-$candidateBranch'],
|
|
||||||
),
|
|
||||||
const FakeCommand(
|
const FakeCommand(
|
||||||
command: <String>[
|
command: <String>[
|
||||||
'git',
|
'git',
|
||||||
@ -701,7 +505,6 @@ void main() {
|
|||||||
],
|
],
|
||||||
stdout: '$previousVersion-42-gabc123',
|
stdout: '$previousVersion-42-gabc123',
|
||||||
),
|
),
|
||||||
const FakeCommand(command: <String>['git', 'rev-parse', 'HEAD'], stdout: revision3),
|
|
||||||
const FakeCommand(
|
const FakeCommand(
|
||||||
command: <String>['git', 'merge-base', 'upstream/$candidateBranch', 'upstream/master'],
|
command: <String>['git', 'merge-base', 'upstream/$candidateBranch', 'upstream/master'],
|
||||||
stdout: branchPointRevision,
|
stdout: branchPointRevision,
|
||||||
@ -710,11 +513,22 @@ void main() {
|
|||||||
const FakeCommand(
|
const FakeCommand(
|
||||||
command: <String>['git', 'describe', '--exact-match', '--tags', branchPointRevision],
|
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(
|
final CommandRunner<void> runner = createRunner(commands: commands);
|
||||||
commands: <FakeCommand>[...engineCommands, ...frameworkCommands],
|
|
||||||
);
|
|
||||||
|
|
||||||
final String stateFilePath = fileSystem.path.join(
|
final String stateFilePath = fileSystem.path.join(
|
||||||
platform.environment['HOME']!,
|
platform.environment['HOME']!,
|
||||||
@ -740,23 +554,21 @@ void main() {
|
|||||||
final pb.ConductorState state = pb.ConductorState();
|
final pb.ConductorState state = pb.ConductorState();
|
||||||
state.mergeFromProto3Json(jsonDecode(stateFile.readAsStringSync()));
|
state.mergeFromProto3Json(jsonDecode(stateFile.readAsStringSync()));
|
||||||
|
|
||||||
expect(processManager.hasRemainingExpectations, false);
|
expect(processManager, hasNoRemainingExpectations);
|
||||||
expect(state.isInitialized(), true);
|
expect(state.isInitialized(), true);
|
||||||
expect(state.releaseChannel, 'stable');
|
expect(state.releaseChannel, 'stable');
|
||||||
expect(state.releaseVersion, nextVersion);
|
expect(state.releaseVersion, nextVersion);
|
||||||
expect(state.engine.candidateBranch, candidateBranch);
|
expect(state.framework.dartRevision, nextDartRevision);
|
||||||
expect(state.engine.startingGitHead, revision2);
|
|
||||||
expect(state.engine.dartRevision, nextDartRevision);
|
|
||||||
expect(state.framework.candidateBranch, candidateBranch);
|
expect(state.framework.candidateBranch, candidateBranch);
|
||||||
expect(state.framework.startingGitHead, revision3);
|
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.conductorVersion, conductorVersion);
|
||||||
expect(state.releaseType, ReleaseType.STABLE_INITIAL);
|
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');
|
stdio.stdin.add('y');
|
||||||
const String revision2 = 'def789';
|
const String revision2 = 'def789';
|
||||||
const String revision3 = '123abc';
|
|
||||||
const String branchPointRevision = 'deadbeef';
|
const String branchPointRevision = 'deadbeef';
|
||||||
const String previousDartRevision = '171876a4e6cf56ee6da1f97d203926bd7afda7ef';
|
const String previousDartRevision = '171876a4e6cf56ee6da1f97d203926bd7afda7ef';
|
||||||
const String nextDartRevision = 'f6c91128be6b77aef8351e1e3a9d07c85bc2e46e';
|
const String nextDartRevision = 'f6c91128be6b77aef8351e1e3a9d07c85bc2e46e';
|
||||||
@ -764,55 +576,13 @@ void main() {
|
|||||||
// This is a git tag applied to the branch point, not an actual release
|
// This is a git tag applied to the branch point, not an actual release
|
||||||
const String branchPointTag = '1.2.0-3.0.pre';
|
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
|
final Directory framework = fileSystem
|
||||||
.directory(checkoutsParentDirectory)
|
.directory(checkoutsParentDirectory)
|
||||||
.childDirectory('flutter_conductor_checkouts')
|
.childDirectory('flutter_conductor_checkouts')
|
||||||
.childDirectory('framework');
|
.childDirectory('framework');
|
||||||
|
|
||||||
final File depsFile = engine.childFile('DEPS');
|
final List<FakeCommand> commands = <FakeCommand>[
|
||||||
|
// checkout and rev-parse framework
|
||||||
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(
|
FakeCommand(
|
||||||
command: <String>[
|
command: <String>[
|
||||||
'git',
|
'git',
|
||||||
@ -823,13 +593,41 @@ void main() {
|
|||||||
FrameworkRepository.defaultUpstream,
|
FrameworkRepository.defaultUpstream,
|
||||||
framework.path,
|
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', 'remote', 'add', 'mirror', frameworkMirror]),
|
||||||
const FakeCommand(command: <String>['git', 'fetch', 'mirror']),
|
const FakeCommand(command: <String>['git', 'fetch', 'mirror']),
|
||||||
const FakeCommand(command: <String>['git', 'checkout', 'upstream/$candidateBranch']),
|
const FakeCommand(command: <String>['git', 'checkout', 'upstream/$candidateBranch']),
|
||||||
const FakeCommand(command: <String>['git', 'rev-parse', 'HEAD'], stdout: revision3),
|
|
||||||
const FakeCommand(
|
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(
|
const FakeCommand(
|
||||||
command: <String>[
|
command: <String>[
|
||||||
@ -842,11 +640,6 @@ void main() {
|
|||||||
],
|
],
|
||||||
stdout: '$previousVersion-42-gabc123',
|
stdout: '$previousVersion-42-gabc123',
|
||||||
),
|
),
|
||||||
// HEAD and branch point are same
|
|
||||||
const FakeCommand(
|
|
||||||
command: <String>['git', 'rev-parse', 'HEAD'],
|
|
||||||
stdout: branchPointRevision,
|
|
||||||
),
|
|
||||||
const FakeCommand(
|
const FakeCommand(
|
||||||
command: <String>['git', 'merge-base', 'upstream/$candidateBranch', 'upstream/master'],
|
command: <String>['git', 'merge-base', 'upstream/$candidateBranch', 'upstream/master'],
|
||||||
stdout: branchPointRevision,
|
stdout: branchPointRevision,
|
||||||
@ -857,10 +650,25 @@ void main() {
|
|||||||
// non-zero exit code means branch point is NOT tagged
|
// non-zero exit code means branch point is NOT tagged
|
||||||
exitCode: 128,
|
exitCode: 128,
|
||||||
),
|
),
|
||||||
|
|
||||||
const FakeCommand(command: <String>['git', 'tag', branchPointTag, branchPointRevision]),
|
const FakeCommand(command: <String>['git', 'tag', branchPointTag, branchPointRevision]),
|
||||||
const FakeCommand(
|
const FakeCommand(
|
||||||
command: <String>['git', 'push', FrameworkRepository.defaultUpstream, branchPointTag],
|
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;
|
final String operatingSystem = const LocalPlatform().operatingSystem;
|
||||||
@ -876,10 +684,7 @@ void main() {
|
|||||||
);
|
);
|
||||||
final File stateFile = fileSystem.file(stateFilePath);
|
final File stateFile = fileSystem.file(stateFilePath);
|
||||||
|
|
||||||
processManager = FakeProcessManager.list(<FakeCommand>[
|
processManager = FakeProcessManager.list(<FakeCommand>[...commands]);
|
||||||
...engineCommands,
|
|
||||||
...frameworkCommands,
|
|
||||||
]);
|
|
||||||
checkouts = Checkouts(
|
checkouts = Checkouts(
|
||||||
fileSystem: fileSystem,
|
fileSystem: fileSystem,
|
||||||
parentDirectory: fileSystem.directory(checkoutsParentDirectory),
|
parentDirectory: fileSystem.directory(checkoutsParentDirectory),
|
||||||
@ -892,8 +697,6 @@ void main() {
|
|||||||
candidateBranch: candidateBranch,
|
candidateBranch: candidateBranch,
|
||||||
checkouts: checkouts,
|
checkouts: checkouts,
|
||||||
dartRevision: nextDartRevision,
|
dartRevision: nextDartRevision,
|
||||||
engineMirror: engineMirror,
|
|
||||||
engineUpstream: EngineRepository.defaultUpstream,
|
|
||||||
frameworkMirror: frameworkMirror,
|
frameworkMirror: frameworkMirror,
|
||||||
frameworkUpstream: FrameworkRepository.defaultUpstream,
|
frameworkUpstream: FrameworkRepository.defaultUpstream,
|
||||||
releaseChannel: releaseChannel,
|
releaseChannel: releaseChannel,
|
||||||
@ -908,7 +711,6 @@ void main() {
|
|||||||
final pb.ConductorState state = pb.ConductorState();
|
final pb.ConductorState state = pb.ConductorState();
|
||||||
state.mergeFromProto3Json(jsonDecode(stateFile.readAsStringSync()));
|
state.mergeFromProto3Json(jsonDecode(stateFile.readAsStringSync()));
|
||||||
|
|
||||||
expect((await startContext.engine.checkoutDirectory).path, equals(engine.path));
|
|
||||||
expect((await startContext.framework.checkoutDirectory).path, equals(framework.path));
|
expect((await startContext.framework.checkoutDirectory).path, equals(framework.path));
|
||||||
expect(state.releaseType, ReleaseType.BETA_INITIAL);
|
expect(state.releaseType, ReleaseType.BETA_INITIAL);
|
||||||
expect(processManager, hasNoRemainingExpectations);
|
expect(processManager, hasNoRemainingExpectations);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user