Unverified Commit ce1acf5d authored by Christopher Fujino's avatar Christopher Fujino Committed by GitHub

[flutter_conductor] implement requiredLocalBranches (#93580)

parent b2114efa
...@@ -46,12 +46,6 @@ Future<void> main(List<String> args) async { ...@@ -46,12 +46,6 @@ Future<void> main(List<String> args) async {
)).trim(); )).trim();
<Command<void>>[ <Command<void>>[
RollDevCommand(
checkouts: checkouts,
fileSystem: fileSystem,
platform: platform,
stdio: stdio,
),
CodesignCommand( CodesignCommand(
checkouts: checkouts, checkouts: checkouts,
flutterRoot: _localFlutterRoot, flutterRoot: _localFlutterRoot,
......
...@@ -11,7 +11,6 @@ export 'src/git.dart'; ...@@ -11,7 +11,6 @@ export 'src/git.dart';
export 'src/globals.dart'; export 'src/globals.dart';
export 'src/next.dart' hide kStateOption, kYesFlag; export 'src/next.dart' hide kStateOption, kYesFlag;
export 'src/repository.dart'; export 'src/repository.dart';
export 'src/roll_dev.dart';
export 'src/start.dart' hide kStateOption; export 'src/start.dart' hide kStateOption;
export 'src/state.dart'; export 'src/state.dart';
export 'src/status.dart' hide kStateOption; export 'src/status.dart' hide kStateOption;
......
...@@ -33,7 +33,12 @@ class Git { ...@@ -33,7 +33,12 @@ class Git {
bool allowNonZeroExitCode = false, bool allowNonZeroExitCode = false,
required String workingDirectory, required String workingDirectory,
}) async { }) async {
final ProcessResult result = await _run(args, workingDirectory); late final ProcessResult result;
try {
result = await _run(args, workingDirectory);
} on ProcessException {
_reportFailureAndExit(args, workingDirectory, result, explanation);
}
if (result.exitCode != 0 && !allowNonZeroExitCode) { if (result.exitCode != 0 && !allowNonZeroExitCode) {
_reportFailureAndExit(args, workingDirectory, result, explanation); _reportFailureAndExit(args, workingDirectory, result, explanation);
} }
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
import 'package:args/args.dart'; import 'package:args/args.dart';
import 'proto/conductor_state.pb.dart' as pb; import 'proto/conductor_state.pb.dart' as pb;
import 'repository.dart';
const String gsutilBinary = 'gsutil.py'; const String gsutilBinary = 'gsutil.py';
...@@ -15,7 +16,7 @@ const List<String> kReleaseChannels = <String>[ ...@@ -15,7 +16,7 @@ const List<String> kReleaseChannels = <String>[
'stable', 'stable',
'beta', 'beta',
'dev', 'dev',
'master', FrameworkRepository.defaultBranch,
]; ];
const String kReleaseDocumentationUrl = 'https://github.com/flutter/flutter/wiki/Flutter-Cherrypick-Process'; const String kReleaseDocumentationUrl = 'https://github.com/flutter/flutter/wiki/Flutter-Cherrypick-Process';
......
...@@ -56,17 +56,24 @@ abstract class Repository { ...@@ -56,17 +56,24 @@ abstract class Repository {
required this.platform, required this.platform,
required this.fileSystem, required this.fileSystem,
required this.parentDirectory, required this.parentDirectory,
required this.requiredLocalBranches,
this.initialRef, this.initialRef,
this.localUpstream = false, this.localUpstream = false,
this.previousCheckoutLocation, this.previousCheckoutLocation,
this.mirrorRemote, this.mirrorRemote,
}) : git = Git(processManager), }) : git = Git(processManager),
assert(localUpstream != null),
assert(upstreamRemote.url.isNotEmpty); assert(upstreamRemote.url.isNotEmpty);
final String name; final String name;
final Remote upstreamRemote; final Remote upstreamRemote;
/// Branches that must exist locally in this [Repository].
///
/// If this [Repository] is used as a local upstream for another, the
/// downstream may try to fetch these branches, and git will fail if they do
/// not exist.
final List<String> requiredLocalBranches;
/// Remote for user's mirror. /// Remote for user's mirror.
/// ///
/// This value can be null, in which case attempting to access it will lead to /// This value can be null, in which case attempting to access it will lead to
...@@ -117,11 +124,13 @@ abstract class Repository { ...@@ -117,11 +124,13 @@ abstract class Repository {
workingDirectory: _checkoutDirectory!.path, workingDirectory: _checkoutDirectory!.path,
); );
} }
return _checkoutDirectory!; return _checkoutDirectory!;
} }
_checkoutDirectory = parentDirectory.childDirectory(name); _checkoutDirectory = parentDirectory.childDirectory(name);
await lazilyInitialize(_checkoutDirectory!); await lazilyInitialize(_checkoutDirectory!);
return _checkoutDirectory!; return _checkoutDirectory!;
} }
...@@ -162,7 +171,7 @@ abstract class Repository { ...@@ -162,7 +171,7 @@ abstract class Repository {
if (localUpstream) { if (localUpstream) {
// These branches must exist locally for the repo that depends on it // These branches must exist locally for the repo that depends on it
// to fetch and push to. // to fetch and push to.
for (final String channel in kReleaseChannels) { for (final String channel in requiredLocalBranches) {
await git.run( await git.run(
<String>['checkout', channel, '--'], <String>['checkout', channel, '--'],
'check out branch $channel locally', 'check out branch $channel locally',
...@@ -173,7 +182,7 @@ abstract class Repository { ...@@ -173,7 +182,7 @@ abstract class Repository {
if (initialRef != null) { if (initialRef != null) {
await git.run( await git.run(
<String>['checkout', '${upstreamRemote.name}/$initialRef'], <String>['checkout', initialRef!],
'Checking out initialRef $initialRef', 'Checking out initialRef $initialRef',
workingDirectory: checkoutDirectory.path, workingDirectory: checkoutDirectory.path,
); );
...@@ -463,8 +472,9 @@ class FrameworkRepository extends Repository { ...@@ -463,8 +472,9 @@ class FrameworkRepository extends Repository {
name: RemoteName.upstream, url: FrameworkRepository.defaultUpstream), name: RemoteName.upstream, url: FrameworkRepository.defaultUpstream),
bool localUpstream = false, bool localUpstream = false,
String? previousCheckoutLocation, String? previousCheckoutLocation,
String? initialRef, String initialRef = FrameworkRepository.defaultBranch,
Remote? mirrorRemote, Remote? mirrorRemote,
List<String>? additionalRequiredLocalBranches,
}) : super( }) : super(
name: name, name: name,
upstreamRemote: upstreamRemote, upstreamRemote: upstreamRemote,
...@@ -477,6 +487,10 @@ class FrameworkRepository extends Repository { ...@@ -477,6 +487,10 @@ class FrameworkRepository extends Repository {
processManager: checkouts.processManager, processManager: checkouts.processManager,
stdio: checkouts.stdio, stdio: checkouts.stdio,
previousCheckoutLocation: previousCheckoutLocation, previousCheckoutLocation: previousCheckoutLocation,
requiredLocalBranches: <String>[
...?additionalRequiredLocalBranches,
...kReleaseChannels,
],
); );
/// A [FrameworkRepository] with the host conductor's repo set as upstream. /// A [FrameworkRepository] with the host conductor's repo set as upstream.
...@@ -487,6 +501,7 @@ class FrameworkRepository extends Repository { ...@@ -487,6 +501,7 @@ class FrameworkRepository extends Repository {
Checkouts checkouts, { Checkouts checkouts, {
String name = 'framework', String name = 'framework',
String? previousCheckoutLocation, String? previousCheckoutLocation,
String initialRef = FrameworkRepository.defaultBranch,
required String upstreamPath, required String upstreamPath,
}) { }) {
return FrameworkRepository( return FrameworkRepository(
...@@ -497,13 +512,12 @@ class FrameworkRepository extends Repository { ...@@ -497,13 +512,12 @@ class FrameworkRepository extends Repository {
url: 'file://$upstreamPath/', url: 'file://$upstreamPath/',
), ),
previousCheckoutLocation: previousCheckoutLocation, previousCheckoutLocation: previousCheckoutLocation,
initialRef: initialRef,
); );
} }
final Checkouts checkouts; final Checkouts checkouts;
static const String defaultUpstream = static const String defaultUpstream = 'git@github.com:flutter/flutter.git';
'git@github.com:flutter/flutter.git';
static const String defaultBranch = 'master'; static const String defaultBranch = 'master';
Future<CiYaml> get ciYaml async { Future<CiYaml> get ciYaml async {
...@@ -717,6 +731,7 @@ class EngineRepository extends Repository { ...@@ -717,6 +731,7 @@ class EngineRepository extends Repository {
bool localUpstream = false, bool localUpstream = false,
String? previousCheckoutLocation, String? previousCheckoutLocation,
Remote? mirrorRemote, Remote? mirrorRemote,
List<String>? additionalRequiredLocalBranches,
}) : super( }) : super(
name: name, name: name,
upstreamRemote: upstreamRemote, upstreamRemote: upstreamRemote,
...@@ -729,6 +744,7 @@ class EngineRepository extends Repository { ...@@ -729,6 +744,7 @@ class EngineRepository extends Repository {
processManager: checkouts.processManager, processManager: checkouts.processManager,
stdio: checkouts.stdio, stdio: checkouts.stdio,
previousCheckoutLocation: previousCheckoutLocation, previousCheckoutLocation: previousCheckoutLocation,
requiredLocalBranches: additionalRequiredLocalBranches ?? const <String>[],
); );
final Checkouts checkouts; final Checkouts checkouts;
...@@ -739,7 +755,7 @@ class EngineRepository extends Repository { ...@@ -739,7 +755,7 @@ class EngineRepository extends Repository {
} }
static const String defaultUpstream = 'git@github.com:flutter/engine.git'; static const String defaultUpstream = 'git@github.com:flutter/engine.git';
static const String defaultBranch = 'master'; 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( Future<void> updateDartRevision(
......
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:args/args.dart';
import 'package:args/command_runner.dart';
import 'package:file/file.dart';
import 'package:meta/meta.dart';
import 'package:platform/platform.dart';
import './repository.dart';
import './stdio.dart';
import './version.dart';
const String kIncrement = 'increment';
const String kCandidateBranch = 'candidate-branch';
const String kRemoteName = 'remote';
const String kJustPrint = 'just-print';
const String kYes = 'yes';
const String kForce = 'force';
const String kSkipTagging = 'skip-tagging';
/// Create a new dev release without cherry picks.
class RollDevCommand extends Command<void> {
RollDevCommand({
required this.checkouts,
required this.fileSystem,
required this.platform,
required this.stdio,
}) {
argParser.addOption(
kIncrement,
help: 'Specifies which part of the x.y.z version number to increment. Required.',
valueHelp: 'level',
allowed: <String>['y', 'z', 'm'],
allowedHelp: <String, String>{
'y': 'Indicates the first dev release after a beta release.',
'z': 'Indicates a hotfix to a stable release.',
'm': 'Indicates a standard dev release.',
},
);
argParser.addOption(
kCandidateBranch,
help: 'Specifies which git branch to roll to the dev branch. Required.',
valueHelp: 'branch',
);
argParser.addFlag(
kForce,
abbr: 'f',
help: 'Force push. Necessary when the previous release had cherry-picks.',
negatable: false,
);
argParser.addFlag(
kJustPrint,
negatable: false,
help:
"Don't actually roll the dev channel; "
'just print the would-be version and quit.',
);
argParser.addFlag(
kSkipTagging,
negatable: false,
help: 'Do not create tag and push to remote, only update release branch. '
'For recovering when the script fails trying to git push to the release branch.'
);
argParser.addFlag(
kYes,
negatable: false,
abbr: 'y',
help: 'Skip the confirmation prompt.',
);
argParser.addOption(
kRemoteName,
help: 'Specifies which git remote to fetch from.',
defaultsTo: 'upstream',
);
}
final Checkouts checkouts;
final FileSystem fileSystem;
final Platform platform;
final Stdio stdio;
@override
String get name => 'roll-dev';
@override
String get description =>
'For publishing a dev release without cherry picks.';
@override
Future<void> run() async {
await rollDev(
argResults: argResults!,
repository: FrameworkRepository(checkouts),
stdio: stdio,
usage: argParser.usage,
);
}
}
/// Main script execution.
///
/// Returns true if publishing was successful, else false.
@visibleForTesting
Future<bool> rollDev({
required String usage,
required ArgResults argResults,
required Stdio stdio,
required FrameworkRepository repository,
}) async {
final String remoteName = argResults[kRemoteName] as String;
final String? level = argResults[kIncrement] as String?;
final String candidateBranch = argResults[kCandidateBranch] as String;
final bool justPrint = argResults[kJustPrint] as bool;
final bool autoApprove = argResults[kYes] as bool;
final bool force = argResults[kForce] as bool;
final bool skipTagging = argResults[kSkipTagging] as bool;
if (level == null || candidateBranch == null) {
throw Exception(
'roll_dev.dart --$kIncrement=level --$kCandidateBranch=branch • update the version tags '
'and roll a new dev build.\n$usage');
}
final String remoteUrl = await repository.remoteUrl(remoteName);
if (!(await repository.gitCheckoutClean())) {
throw Exception(
'Your git repository is not clean. Try running "git clean -fd". Warning, '
'this will delete files! Run with -n to find out which ones.');
}
await repository.fetch(remoteName);
// Verify [commit] is valid
final String commit = await repository.reverseParse(candidateBranch);
stdio.printStatus('remoteName is $remoteName');
// Get the name of the last dev release
final Version lastVersion = Version.fromString(
await repository.getFullTag(remoteName, 'dev'),
);
final Version version =
skipTagging ? lastVersion : Version.fromCandidateBranch(candidateBranch);
final String tagName = version.toString();
if ((await repository.reverseParse(lastVersion.toString())).contains(commit.trim())) {
throw Exception(
'Commit $commit is already on the dev branch as $lastVersion.');
}
if (justPrint) {
stdio.printStatus(tagName);
return false;
}
if (skipTagging && !(await repository.isCommitTagged(commit))) {
throw Exception(
'The $kSkipTagging flag is only supported for tagged commits.');
}
if (!force && !(await repository.isAncestor(commit, lastVersion.toString()))) {
throw Exception(
'The previous dev tag $lastVersion is not a direct ancestor of $commit.\n'
'The flag "$kForce" is required to force push a new release past a cherry-pick.');
}
final String hash = await repository.reverseParse(commit);
// [commit] can be a prefix for [hash].
assert(hash.startsWith(commit));
// PROMPT
if (autoApprove) {
stdio.printStatus(
'Publishing Flutter $version ($hash) to the "dev" channel.');
} else {
stdio.printStatus('Your tree is ready to publish Flutter $version '
'($hash) to the "dev" channel.');
stdio.write('Are you? [yes/no] ');
if (stdio.readLineSync() != 'yes') {
stdio.printError('The dev roll has been aborted.');
return false;
}
}
if (!skipTagging) {
await repository.tag(commit, version.toString(), remoteName);
}
await repository.pushRef(
fromRef: commit,
remote: remoteName,
toRef: 'dev',
force: force,
);
stdio.printStatus(
'Flutter version $version has been rolled to the "dev" channel at $remoteUrl.',
);
return true;
}
...@@ -455,7 +455,7 @@ class StartContext { ...@@ -455,7 +455,7 @@ class StartContext {
} }
final String branchPoint = await framework.branchPoint( final String branchPoint = await framework.branchPoint(
candidateBranch, candidateBranch,
kFrameworkDefaultBranch, FrameworkRepository.defaultBranch,
); );
stdio.printStatus('Applying the tag $requestedVersion at the branch point $branchPoint'); stdio.printStatus('Applying the tag $requestedVersion at the branch point $branchPoint');
await framework.tag( await framework.tag(
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
import 'package:args/command_runner.dart'; import 'package:args/command_runner.dart';
import 'package:conductor_core/src/codesign.dart' show CodesignCommand; import 'package:conductor_core/src/codesign.dart' show CodesignCommand;
import 'package:conductor_core/src/globals.dart'; import 'package:conductor_core/src/globals.dart';
import 'package:conductor_core/src/repository.dart' show Checkouts; import 'package:conductor_core/src/repository.dart' show Checkouts, FrameworkRepository;
import 'package:file/file.dart'; import 'package:file/file.dart';
import 'package:file/local.dart'; import 'package:file/local.dart';
import 'package:platform/platform.dart'; import 'package:platform/platform.dart';
...@@ -35,9 +35,24 @@ void main() { ...@@ -35,9 +35,24 @@ void main() {
fileSystem.file(platform.executable), fileSystem.file(platform.executable),
); );
final CommandRunner<void> runner = CommandRunner<void>('codesign-test', '') final String currentHead = (processManager.runSync(
..addCommand( <String>['git', 'rev-parse', 'HEAD'],
CodesignCommand(checkouts: checkouts, flutterRoot: flutterRoot)); workingDirectory: flutterRoot.path,
).stdout as String).trim();
final FrameworkRepository framework = FrameworkRepository.localRepoAsUpstream(
checkouts,
upstreamPath: flutterRoot.path,
initialRef: currentHead,
);
final CommandRunner<void> runner = CommandRunner<void>('codesign-test', '');
runner.addCommand(
CodesignCommand(
checkouts: checkouts,
framework: framework,
flutterRoot: flutterRoot,
),
);
try { try {
await runner.run(<String>[ await runner.run(<String>[
......
...@@ -112,6 +112,11 @@ void main() { ...@@ -112,6 +112,11 @@ void main() {
'file://$flutterRoot/', 'file://$flutterRoot/',
'${checkoutsParentDirectory}flutter_conductor_checkouts/framework', '${checkoutsParentDirectory}flutter_conductor_checkouts/framework',
]), ]),
const FakeCommand(command: <String>[
'git',
'checkout',
FrameworkRepository.defaultBranch,
]),
const FakeCommand(command: <String>[ const FakeCommand(command: <String>[
'git', 'git',
'rev-parse', 'rev-parse',
...@@ -196,6 +201,11 @@ void main() { ...@@ -196,6 +201,11 @@ void main() {
'file://$flutterRoot/', 'file://$flutterRoot/',
'${checkoutsParentDirectory}flutter_conductor_checkouts/framework', '${checkoutsParentDirectory}flutter_conductor_checkouts/framework',
]), ]),
const FakeCommand(command: <String>[
'git',
'checkout',
FrameworkRepository.defaultBranch,
]),
const FakeCommand(command: <String>[ const FakeCommand(command: <String>[
'git', 'git',
'rev-parse', 'rev-parse',
...@@ -284,6 +294,11 @@ void main() { ...@@ -284,6 +294,11 @@ void main() {
'file://$flutterRoot/', 'file://$flutterRoot/',
'${checkoutsParentDirectory}flutter_conductor_checkouts/framework', '${checkoutsParentDirectory}flutter_conductor_checkouts/framework',
]), ]),
const FakeCommand(command: <String>[
'git',
'checkout',
FrameworkRepository.defaultBranch,
]),
const FakeCommand(command: <String>[ const FakeCommand(command: <String>[
'git', 'git',
'rev-parse', 'rev-parse',
...@@ -371,6 +386,11 @@ void main() { ...@@ -371,6 +386,11 @@ void main() {
'file://$flutterRoot/', 'file://$flutterRoot/',
'${checkoutsParentDirectory}flutter_conductor_checkouts/framework', '${checkoutsParentDirectory}flutter_conductor_checkouts/framework',
]), ]),
const FakeCommand(command: <String>[
'git',
'checkout',
FrameworkRepository.defaultBranch,
]),
const FakeCommand(command: <String>[ const FakeCommand(command: <String>[
'git', 'git',
'rev-parse', 'rev-parse',
...@@ -430,6 +450,11 @@ void main() { ...@@ -430,6 +450,11 @@ void main() {
'file://$flutterRoot/', 'file://$flutterRoot/',
'${checkoutsParentDirectory}flutter_conductor_checkouts/framework', '${checkoutsParentDirectory}flutter_conductor_checkouts/framework',
]), ]),
const FakeCommand(command: <String>[
'git',
'checkout',
FrameworkRepository.defaultBranch,
]),
const FakeCommand(command: <String>[ const FakeCommand(command: <String>[
'git', 'git',
'rev-parse', 'rev-parse',
......
...@@ -13,24 +13,27 @@ void main() { ...@@ -13,24 +13,27 @@ void main() {
group('repository', () { group('repository', () {
late FakePlatform platform; late FakePlatform platform;
const String rootDir = '/'; const String rootDir = '/';
late MemoryFileSystem fileSystem;
late FakeProcessManager processManager;
late TestStdio stdio;
setUp(() { setUp(() {
final String pathSeparator = const LocalPlatform().pathSeparator; final String pathSeparator = const LocalPlatform().pathSeparator;
fileSystem = MemoryFileSystem.test();
platform = FakePlatform( platform = FakePlatform(
environment: <String, String>{ environment: <String, String>{
'HOME': <String>['path', 'to', 'home'].join(pathSeparator), 'HOME': <String>['path', 'to', 'home'].join(pathSeparator),
}, },
pathSeparator: pathSeparator, pathSeparator: pathSeparator,
); );
processManager = FakeProcessManager.empty();
stdio = TestStdio();
}); });
test('canCherryPick returns true if git cherry-pick returns 0', () async { test('canCherryPick returns true if git cherry-pick returns 0', () async {
const String commit = 'abc123'; const String commit = 'abc123';
final TestStdio stdio = TestStdio(); processManager.addCommands(<FakeCommand>[
final MemoryFileSystem fileSystem = MemoryFileSystem.test();
final FakeProcessManager processManager =
FakeProcessManager.list(<FakeCommand>[
FakeCommand(command: <String>[ FakeCommand(command: <String>[
'git', 'git',
'clone', 'clone',
...@@ -41,6 +44,11 @@ void main() { ...@@ -41,6 +44,11 @@ void main() {
fileSystem.path fileSystem.path
.join(rootDir, 'flutter_conductor_checkouts', 'framework'), .join(rootDir, 'flutter_conductor_checkouts', 'framework'),
]), ]),
const FakeCommand(command: <String>[
'git',
'checkout',
FrameworkRepository.defaultBranch,
]),
const FakeCommand(command: <String>[ const FakeCommand(command: <String>[
'git', 'git',
'rev-parse', 'rev-parse',
...@@ -78,10 +86,7 @@ void main() { ...@@ -78,10 +86,7 @@ void main() {
test('canCherryPick returns false if git cherry-pick returns non-zero', () async { test('canCherryPick returns false if git cherry-pick returns non-zero', () async {
const String commit = 'abc123'; const String commit = 'abc123';
final TestStdio stdio = TestStdio(); processManager.addCommands(<FakeCommand>[
final MemoryFileSystem fileSystem = MemoryFileSystem.test();
final FakeProcessManager processManager =
FakeProcessManager.list(<FakeCommand>[
FakeCommand(command: <String>[ FakeCommand(command: <String>[
'git', 'git',
'clone', 'clone',
...@@ -92,6 +97,11 @@ void main() { ...@@ -92,6 +97,11 @@ void main() {
fileSystem.path fileSystem.path
.join(rootDir, 'flutter_conductor_checkouts', 'framework'), .join(rootDir, 'flutter_conductor_checkouts', 'framework'),
]), ]),
const FakeCommand(command: <String>[
'git',
'checkout',
FrameworkRepository.defaultBranch,
]),
const FakeCommand(command: <String>[ const FakeCommand(command: <String>[
'git', 'git',
'rev-parse', 'rev-parse',
...@@ -133,10 +143,7 @@ void main() { ...@@ -133,10 +143,7 @@ void main() {
test('cherryPick() applies the commit', () async { test('cherryPick() applies the commit', () async {
const String commit = 'abc123'; const String commit = 'abc123';
final TestStdio stdio = TestStdio(); processManager.addCommands(<FakeCommand>[
final MemoryFileSystem fileSystem = MemoryFileSystem.test();
final FakeProcessManager processManager =
FakeProcessManager.list(<FakeCommand>[
FakeCommand(command: <String>[ FakeCommand(command: <String>[
'git', 'git',
'clone', 'clone',
...@@ -147,6 +154,11 @@ void main() { ...@@ -147,6 +154,11 @@ void main() {
fileSystem.path fileSystem.path
.join(rootDir, 'flutter_conductor_checkouts', 'framework'), .join(rootDir, 'flutter_conductor_checkouts', 'framework'),
]), ]),
const FakeCommand(command: <String>[
'git',
'checkout',
FrameworkRepository.defaultBranch,
]),
const FakeCommand(command: <String>[ const FakeCommand(command: <String>[
'git', 'git',
'rev-parse', 'rev-parse',
...@@ -178,9 +190,6 @@ void main() { ...@@ -178,9 +190,6 @@ void main() {
test('updateDartRevision() updates the DEPS file', () async { test('updateDartRevision() updates the DEPS file', () async {
const String previousDartRevision = '171876a4e6cf56ee6da1f97d203926bd7afda7ef'; const String previousDartRevision = '171876a4e6cf56ee6da1f97d203926bd7afda7ef';
const String nextDartRevision = 'f6c91128be6b77aef8351e1e3a9d07c85bc2e46e'; const String nextDartRevision = 'f6c91128be6b77aef8351e1e3a9d07c85bc2e46e';
final TestStdio stdio = TestStdio();
final MemoryFileSystem fileSystem = MemoryFileSystem.test();
final FakeProcessManager processManager = FakeProcessManager.empty();
final Checkouts checkouts = Checkouts( final Checkouts checkouts = Checkouts(
fileSystem: fileSystem, fileSystem: fileSystem,
...@@ -200,9 +209,6 @@ void main() { ...@@ -200,9 +209,6 @@ void main() {
test('updateDartRevision() throws exception on malformed DEPS file', () { test('updateDartRevision() throws exception on malformed DEPS file', () {
const String nextDartRevision = 'f6c91128be6b77aef8351e1e3a9d07c85bc2e46e'; const String nextDartRevision = 'f6c91128be6b77aef8351e1e3a9d07c85bc2e46e';
final TestStdio stdio = TestStdio();
final MemoryFileSystem fileSystem = MemoryFileSystem.test();
final FakeProcessManager processManager = FakeProcessManager.empty();
final Checkouts checkouts = Checkouts( final Checkouts checkouts = Checkouts(
fileSystem: fileSystem, fileSystem: fileSystem,
...@@ -227,9 +233,7 @@ vars = { ...@@ -227,9 +233,7 @@ vars = {
const String commit1 = 'abc123'; const String commit1 = 'abc123';
const String commit2 = 'def456'; const String commit2 = 'def456';
const String message = 'This is a commit message.'; const String message = 'This is a commit message.';
final TestStdio stdio = TestStdio(); processManager.addCommands(<FakeCommand>[
final MemoryFileSystem fileSystem = MemoryFileSystem.test();
final FakeProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
FakeCommand(command: <String>[ FakeCommand(command: <String>[
'git', 'git',
'clone', 'clone',
...@@ -243,7 +247,7 @@ vars = { ...@@ -243,7 +247,7 @@ vars = {
const FakeCommand(command: <String>[ const FakeCommand(command: <String>[
'git', 'git',
'checkout', 'checkout',
'upstream/master', EngineRepository.defaultBranch,
]), ]),
const FakeCommand(command: <String>[ const FakeCommand(command: <String>[
'git', 'git',
...@@ -282,13 +286,11 @@ vars = { ...@@ -282,13 +286,11 @@ vars = {
); );
}); });
test('commit() passes correct commit message', () { test('commit() passes correct commit message', () async {
const String commit1 = 'abc123'; const String commit1 = 'abc123';
const String commit2 = 'def456'; const String commit2 = 'def456';
const String message = 'This is a commit message.'; const String message = 'This is a commit message.';
final TestStdio stdio = TestStdio(); processManager.addCommands(<FakeCommand>[
final MemoryFileSystem fileSystem = MemoryFileSystem.test();
final FakeProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
FakeCommand(command: <String>[ FakeCommand(command: <String>[
'git', 'git',
'clone', 'clone',
...@@ -302,7 +304,7 @@ vars = { ...@@ -302,7 +304,7 @@ vars = {
const FakeCommand(command: <String>[ const FakeCommand(command: <String>[
'git', 'git',
'checkout', 'checkout',
'upstream/master', EngineRepository.defaultBranch,
]), ]),
const FakeCommand(command: <String>[ const FakeCommand(command: <String>[
'git', 'git',
...@@ -334,16 +336,15 @@ vars = { ...@@ -334,16 +336,15 @@ vars = {
); );
final EngineRepository repo = EngineRepository(checkouts); final EngineRepository repo = EngineRepository(checkouts);
repo.commit(message); await repo.commit(message);
expect(processManager.hasRemainingExpectations, false);
}); });
test('updateEngineRevision() returns false if newCommit is the same as version file', () async { test('updateEngineRevision() returns false if newCommit is the same as version file', () async {
const String commit1 = 'abc123'; const String commit1 = 'abc123';
const String commit2 = 'def456'; const String commit2 = 'def456';
final TestStdio stdio = TestStdio();
final MemoryFileSystem fileSystem = MemoryFileSystem.test();
final File engineVersionFile = fileSystem.file('/engine.version')..writeAsStringSync(commit2); final File engineVersionFile = fileSystem.file('/engine.version')..writeAsStringSync(commit2);
final FakeProcessManager processManager = FakeProcessManager.list(<FakeCommand>[ processManager.addCommands(<FakeCommand>[
FakeCommand(command: <String>[ FakeCommand(command: <String>[
'git', 'git',
'clone', 'clone',
...@@ -375,7 +376,6 @@ vars = { ...@@ -375,7 +376,6 @@ vars = {
}); });
test('CiYaml(file) will throw if file does not exist', () { test('CiYaml(file) will throw if file does not exist', () {
final MemoryFileSystem fileSystem = MemoryFileSystem.test();
final File file = fileSystem.file('/non/existent/file.txt'); final File file = fileSystem.file('/non/existent/file.txt');
expect( expect(
...@@ -386,10 +386,8 @@ vars = { ...@@ -386,10 +386,8 @@ vars = {
test('ciYaml.enableBranch() will prepend the given branch to the yaml list of enabled_branches', () async { test('ciYaml.enableBranch() will prepend the given branch to the yaml list of enabled_branches', () async {
const String commit1 = 'abc123'; const String commit1 = 'abc123';
final TestStdio stdio = TestStdio();
final MemoryFileSystem fileSystem = MemoryFileSystem.test();
final File ciYaml = fileSystem.file('/flutter_conductor_checkouts/framework/.ci.yaml'); final File ciYaml = fileSystem.file('/flutter_conductor_checkouts/framework/.ci.yaml');
final ProcessManager processManager = FakeProcessManager.list(<FakeCommand>[ processManager.addCommands(<FakeCommand>[
FakeCommand( FakeCommand(
command: <String>[ command: <String>[
'git', 'git',
...@@ -407,12 +405,17 @@ vars = { ...@@ -407,12 +405,17 @@ vars = {
# Friendly note # Friendly note
enabled_branches: enabled_branches:
- master - ${FrameworkRepository.defaultBranch}
- dev - dev
- beta - beta
- stable - stable
'''); ''');
}), }),
const FakeCommand(command: <String>[
'git',
'checkout',
FrameworkRepository.defaultBranch,
]),
const FakeCommand(command: <String>[ const FakeCommand(command: <String>[
'git', 'git',
'rev-parse', 'rev-parse',
...@@ -430,13 +433,13 @@ enabled_branches: ...@@ -430,13 +433,13 @@ enabled_branches:
final FrameworkRepository framework = FrameworkRepository(checkouts); final FrameworkRepository framework = FrameworkRepository(checkouts);
expect( expect(
(await framework.ciYaml).enabledBranches, (await framework.ciYaml).enabledBranches,
<String>['master', 'dev', 'beta', 'stable'], <String>[FrameworkRepository.defaultBranch, 'dev', 'beta', 'stable'],
); );
(await framework.ciYaml).enableBranch('foo'); (await framework.ciYaml).enableBranch('foo');
expect( expect(
(await framework.ciYaml).enabledBranches, (await framework.ciYaml).enabledBranches,
<String>['foo', 'master', 'dev', 'beta', 'stable'], <String>['foo', FrameworkRepository.defaultBranch, 'dev', 'beta', 'stable'],
); );
expect( expect(
...@@ -446,7 +449,7 @@ enabled_branches: ...@@ -446,7 +449,7 @@ enabled_branches:
enabled_branches: enabled_branches:
- foo - foo
- master - ${FrameworkRepository.defaultBranch}
- dev - dev
- beta - beta
- stable - stable
...@@ -456,10 +459,8 @@ enabled_branches: ...@@ -456,10 +459,8 @@ enabled_branches:
test('ciYaml.enableBranch() will throw if the input branch is already present in the yaml file', () { test('ciYaml.enableBranch() will throw if the input branch is already present in the yaml file', () {
const String commit1 = 'abc123'; const String commit1 = 'abc123';
final TestStdio stdio = TestStdio();
final MemoryFileSystem fileSystem = MemoryFileSystem.test();
final File ciYaml = fileSystem.file('/flutter_conductor_checkouts/framework/.ci.yaml'); final File ciYaml = fileSystem.file('/flutter_conductor_checkouts/framework/.ci.yaml');
final ProcessManager processManager = FakeProcessManager.list(<FakeCommand>[ processManager.addCommands(<FakeCommand>[
FakeCommand( FakeCommand(
command: <String>[ command: <String>[
'git', 'git',
...@@ -475,12 +476,17 @@ enabled_branches: ...@@ -475,12 +476,17 @@ enabled_branches:
ciYaml.createSync(recursive: true); ciYaml.createSync(recursive: true);
ciYaml.writeAsStringSync(''' ciYaml.writeAsStringSync('''
enabled_branches: enabled_branches:
- master - ${FrameworkRepository.defaultBranch}
- dev - dev
- beta - beta
- stable - stable
'''); ''');
}), }),
const FakeCommand(command: <String>[
'git',
'checkout',
FrameworkRepository.defaultBranch,
]),
const FakeCommand(command: <String>[ const FakeCommand(command: <String>[
'git', 'git',
'rev-parse', 'rev-parse',
...@@ -497,10 +503,114 @@ enabled_branches: ...@@ -497,10 +503,114 @@ enabled_branches:
final FrameworkRepository framework = FrameworkRepository(checkouts); final FrameworkRepository framework = FrameworkRepository(checkouts);
expect( expect(
() async => (await framework.ciYaml).enableBranch('master'), () async => (await framework.ciYaml).enableBranch(FrameworkRepository.defaultBranch),
throwsExceptionWith('.ci.yaml already contains the branch master'), throwsExceptionWith('.ci.yaml already contains the branch ${FrameworkRepository.defaultBranch}'),
); );
}); });
test('framework 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',
'--',
FrameworkRepository.defaultUpstream,
fileSystem.path.join(rootDir, 'flutter_conductor_checkouts', 'framework'),
]),
FakeCommand(
command: const <String>['git', 'checkout', candidateBranch, '--'],
onRun: () => createdCandidateBranch = true,
),
const FakeCommand(
command: <String>['git', 'checkout', 'stable', '--'],
),
const FakeCommand(
command: <String>['git', 'checkout', 'beta', '--'],
),
const FakeCommand(
command: <String>['git', 'checkout', 'dev', '--'],
),
const FakeCommand(
command: <String>['git', 'checkout', FrameworkRepository.defaultBranch, '--'],
),
const FakeCommand(
command: <String>['git', 'checkout', FrameworkRepository.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 = FrameworkRepository(
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('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);
});
}); });
} }
......
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:conductor_core/src/repository.dart';
import 'package:conductor_core/src/roll_dev.dart';
import 'package:file/memory.dart';
import 'package:platform/platform.dart';
import './common.dart';
const String _kUpstreamRemote = 'git@github.com:flutter/flutter.git';
void main() {
group('rollDev()', () {
const String usage = 'usage info...';
const String level = 'm';
const String commit = 'abcde012345';
const String remote = 'origin';
const String lastVersion = '1.2.0-0.0.pre';
const String nextVersion = '1.2.0-2.0.pre';
const String candidateBranch = 'flutter-1.2-candidate.2';
const String checkoutsParentDirectory = '/path/to/directory/';
late FakeArgResults fakeArgResults;
late MemoryFileSystem fileSystem;
late TestStdio stdio;
late FrameworkRepository repo;
late Checkouts checkouts;
late FakePlatform platform;
late FakeProcessManager processManager;
setUp(() {
stdio = TestStdio();
fileSystem = MemoryFileSystem.test();
platform = FakePlatform();
processManager = FakeProcessManager.list(<FakeCommand>[]);
checkouts = Checkouts(
fileSystem: fileSystem,
parentDirectory: fileSystem.directory(checkoutsParentDirectory),
platform: platform,
processManager: processManager,
stdio: stdio,
);
repo = FrameworkRepository(checkouts);
});
test('throws Exception if level not provided', () {
fakeArgResults = FakeArgResults(
level: null,
candidateBranch: candidateBranch,
remote: remote,
);
expect(
() async => rollDev(
argResults: fakeArgResults,
repository: repo,
stdio: stdio,
usage: usage,
),
throwsExceptionWith(usage),
);
});
test('throws exception if git checkout not clean', () {
processManager.addCommands(<FakeCommand>[
const FakeCommand(command: <String>[
'git',
'clone',
'--origin',
'upstream',
'--',
_kUpstreamRemote,
'${checkoutsParentDirectory}flutter_conductor_checkouts/framework',
]),
const FakeCommand(command: <String>[
'git',
'rev-parse',
'HEAD',
], stdout: commit),
const FakeCommand(command: <String>[
'git',
'remote',
'get-url',
remote,
], stdout: _kUpstreamRemote),
const FakeCommand(command: <String>[
'git',
'status',
'--porcelain',
], stdout: ' M dev/conductor/bin/conductor.dart'),
]);
fakeArgResults = FakeArgResults(
level: level,
candidateBranch: candidateBranch,
remote: remote,
);
expect(
() async => rollDev(
argResults: fakeArgResults,
repository: repo,
stdio: stdio,
usage: usage,
),
throwsExceptionWith('Your git repository is not clean.'),
);
});
test('does not reset or tag if --just-print is specified', () async {
processManager.addCommands(<FakeCommand>[
const FakeCommand(command: <String>[
'git',
'clone',
'--origin',
'upstream',
'--',
_kUpstreamRemote,
'${checkoutsParentDirectory}flutter_conductor_checkouts/framework',
]),
const FakeCommand(command: <String>[
'git',
'rev-parse',
'HEAD',
], stdout: commit),
const FakeCommand(command: <String>[
'git',
'remote',
'get-url',
remote,
], stdout: _kUpstreamRemote),
const FakeCommand(command: <String>[
'git',
'status',
'--porcelain',
]),
const FakeCommand(command: <String>[
'git',
'fetch',
remote,
'--tags',
]),
const FakeCommand(command: <String>[
'git',
'rev-parse',
candidateBranch,
], stdout: commit),
const FakeCommand(command: <String>[
'git',
'describe',
'--match',
'*.*.*',
'--exact-match',
'--tags',
'refs/remotes/$remote/dev',
], stdout: lastVersion),
const FakeCommand(command: <String>[
'git',
'rev-parse',
lastVersion,
], stdout: 'zxy321'),
]);
fakeArgResults = FakeArgResults(
level: level,
candidateBranch: candidateBranch,
remote: remote,
justPrint: true,
);
expect(
await rollDev(
usage: usage,
argResults: fakeArgResults,
repository: repo,
stdio: stdio,
),
false,
);
expect(stdio.logs.join().contains(nextVersion), true);
});
test("exits with exception if --skip-tagging is provided but commit isn't already tagged", () {
processManager.addCommands(<FakeCommand>[
const FakeCommand(command: <String>[
'git',
'clone',
'--origin',
'upstream',
'--',
_kUpstreamRemote,
'${checkoutsParentDirectory}flutter_conductor_checkouts/framework',
]),
const FakeCommand(command: <String>[
'git',
'rev-parse',
'HEAD',
], stdout: commit),
const FakeCommand(command: <String>[
'git',
'remote',
'get-url',
remote,
], stdout: _kUpstreamRemote),
const FakeCommand(command: <String>[
'git',
'status',
'--porcelain',
]),
const FakeCommand(command: <String>[
'git',
'fetch',
remote,
'--tags',
]),
const FakeCommand(command: <String>[
'git',
'rev-parse',
candidateBranch,
], stdout: commit),
const FakeCommand(command: <String>[
'git',
'describe',
'--match',
'*.*.*',
'--exact-match',
'--tags',
'refs/remotes/$remote/dev',
], stdout: lastVersion),
const FakeCommand(command: <String>[
'git',
'rev-parse',
lastVersion,
], stdout: 'zxy321'),
const FakeCommand(command: <String>[
'git',
'describe',
'--exact-match',
'--tags',
commit,
], exitCode: 1),
]);
const String exceptionMessage =
'The $kSkipTagging flag is only supported '
'for tagged commits.';
fakeArgResults = FakeArgResults(
level: level,
candidateBranch: candidateBranch,
remote: remote,
skipTagging: true,
);
expect(
() async => rollDev(
usage: usage,
argResults: fakeArgResults,
repository: repo,
stdio: stdio,
),
throwsExceptionWith(exceptionMessage),
);
});
test('throws exception if desired commit is already tip of dev branch', () {
processManager.addCommands(<FakeCommand>[
const FakeCommand(command: <String>[
'git',
'clone',
'--origin',
'upstream',
'--',
_kUpstreamRemote,
'${checkoutsParentDirectory}flutter_conductor_checkouts/framework',
]),
const FakeCommand(command: <String>[
'git',
'rev-parse',
'HEAD',
], stdout: commit),
const FakeCommand(command: <String>[
'git',
'remote',
'get-url',
remote,
], stdout: _kUpstreamRemote),
const FakeCommand(command: <String>[
'git',
'status',
'--porcelain',
]),
const FakeCommand(command: <String>[
'git',
'fetch',
remote,
'--tags',
]),
const FakeCommand(command: <String>[
'git',
'rev-parse',
candidateBranch,
], stdout: commit),
const FakeCommand(command: <String>[
'git',
'describe',
'--match',
'*.*.*',
'--exact-match',
'--tags',
'refs/remotes/$remote/dev',
], stdout: lastVersion),
// [commit] is already [lastVersion]
const FakeCommand(command: <String>[
'git',
'rev-parse',
lastVersion,
], stdout: commit),
]);
fakeArgResults = FakeArgResults(
level: level,
candidateBranch: candidateBranch,
remote: remote,
justPrint: true,
);
expect(
() async => rollDev(
usage: usage,
argResults: fakeArgResults,
repository: repo,
stdio: stdio,
),
throwsExceptionWith(
'Commit $commit is already on the dev branch as $lastVersion',
),
);
});
test(
'does not tag if last release is not direct ancestor of desired '
'commit and --force not supplied', () {
processManager.addCommands(<FakeCommand>[
const FakeCommand(command: <String>[
'git',
'clone',
'--origin',
'upstream',
'--',
_kUpstreamRemote,
'${checkoutsParentDirectory}flutter_conductor_checkouts/framework',
]),
const FakeCommand(command: <String>[
'git',
'rev-parse',
'HEAD',
], stdout: commit),
const FakeCommand(command: <String>[
'git',
'remote',
'get-url',
remote,
], stdout: _kUpstreamRemote),
const FakeCommand(command: <String>[
'git',
'status',
'--porcelain',
]),
const FakeCommand(command: <String>[
'git',
'fetch',
remote,
'--tags',
]),
const FakeCommand(command: <String>[
'git',
'rev-parse',
candidateBranch,
], stdout: commit),
const FakeCommand(command: <String>[
'git',
'describe',
'--match',
'*.*.*',
'--exact-match',
'--tags',
'refs/remotes/$remote/dev',
], stdout: lastVersion),
const FakeCommand(command: <String>[
'git',
'rev-parse',
lastVersion,
], stdout: 'zxy321'),
const FakeCommand(command: <String>[
'git',
'merge-base',
'--is-ancestor',
lastVersion,
commit,
], exitCode: 1),
]);
fakeArgResults = FakeArgResults(
level: level,
candidateBranch: candidateBranch,
remote: remote,
);
const String errorMessage = 'The previous dev tag $lastVersion is not a '
'direct ancestor of $commit.';
expect(
() async => rollDev(
argResults: fakeArgResults,
repository: repo,
stdio: stdio,
usage: usage,
),
throwsExceptionWith(errorMessage),
);
});
test('does not tag but updates branch if --skip-tagging provided', () async {
processManager.addCommands(<FakeCommand>[
const FakeCommand(command: <String>[
'git',
'clone',
'--origin',
'upstream',
'--',
_kUpstreamRemote,
'${checkoutsParentDirectory}flutter_conductor_checkouts/framework',
]),
const FakeCommand(command: <String>[
'git',
'rev-parse',
'HEAD',
], stdout: commit),
const FakeCommand(command: <String>[
'git',
'remote',
'get-url',
remote,
], stdout: _kUpstreamRemote),
const FakeCommand(command: <String>[
'git',
'status',
'--porcelain',
]),
const FakeCommand(command: <String>[
'git',
'fetch',
remote,
'--tags',
]),
const FakeCommand(command: <String>[
'git',
'rev-parse',
candidateBranch,
], stdout: commit),
const FakeCommand(command: <String>[
'git',
'describe',
'--match',
'*.*.*',
'--exact-match',
'--tags',
'refs/remotes/$remote/dev',
], stdout: lastVersion),
const FakeCommand(command: <String>[
'git',
'rev-parse',
lastVersion,
], stdout: 'zxy321'),
const FakeCommand(command: <String>[
'git',
'describe',
'--exact-match',
'--tags',
commit,
]),
const FakeCommand(command: <String>[
'git',
'merge-base',
'--is-ancestor',
lastVersion,
commit,
]),
const FakeCommand(command: <String>[
'git',
'rev-parse',
commit,
], stdout: commit),
const FakeCommand(command: <String>[
'git',
'push',
remote,
'$commit:dev',
]),
]);
fakeArgResults = FakeArgResults(
level: level,
candidateBranch: candidateBranch,
remote: remote,
skipTagging: true,
);
expect(
await rollDev(
usage: usage,
argResults: fakeArgResults,
repository: repo,
stdio: stdio,
),
true,
);
});
test('successfully tags and publishes release', () async {
processManager.addCommands(<FakeCommand>[
const FakeCommand(command: <String>[
'git',
'clone',
'--origin',
'upstream',
'--',
_kUpstreamRemote,
'${checkoutsParentDirectory}flutter_conductor_checkouts/framework',
]),
const FakeCommand(command: <String>[
'git',
'rev-parse',
'HEAD',
], stdout: commit),
const FakeCommand(command: <String>[
'git',
'remote',
'get-url',
remote,
], stdout: _kUpstreamRemote),
const FakeCommand(command: <String>[
'git',
'status',
'--porcelain',
]),
const FakeCommand(command: <String>[
'git',
'fetch',
remote,
'--tags',
]),
const FakeCommand(command: <String>[
'git',
'rev-parse',
candidateBranch,
], stdout: commit),
const FakeCommand(command: <String>[
'git',
'describe',
'--match',
'*.*.*',
'--exact-match',
'--tags',
'refs/remotes/$remote/dev',
], stdout: lastVersion),
const FakeCommand(command: <String>[
'git',
'rev-parse',
lastVersion,
], stdout: 'zxy321'),
const FakeCommand(command: <String>[
'git',
'merge-base',
'--is-ancestor',
lastVersion,
commit,
]),
const FakeCommand(command: <String>[
'git',
'rev-parse',
commit,
], stdout: commit),
const FakeCommand(command: <String>[
'git',
'tag',
nextVersion,
commit,
]),
const FakeCommand(command: <String>[
'git',
'push',
remote,
nextVersion,
]),
const FakeCommand(command: <String>[
'git',
'push',
remote,
'$commit:dev',
]),
]);
fakeArgResults = FakeArgResults(
level: level,
candidateBranch: candidateBranch,
remote: remote,
);
expect(
await rollDev(
usage: usage,
argResults: fakeArgResults,
repository: repo,
stdio: stdio,
),
true,
);
});
test('successfully publishes release with --force', () async {
processManager.addCommands(<FakeCommand>[
const FakeCommand(command: <String>[
'git',
'clone',
'--origin',
'upstream',
'--',
_kUpstreamRemote,
'${checkoutsParentDirectory}flutter_conductor_checkouts/framework',
]),
const FakeCommand(command: <String>[
'git',
'rev-parse',
'HEAD',
], stdout: commit),
const FakeCommand(command: <String>[
'git',
'remote',
'get-url',
remote,
], stdout: _kUpstreamRemote),
const FakeCommand(command: <String>[
'git',
'status',
'--porcelain',
]),
const FakeCommand(command: <String>[
'git',
'fetch',
remote,
'--tags',
]),
const FakeCommand(command: <String>[
'git',
'rev-parse',
candidateBranch,
], stdout: commit),
const FakeCommand(command: <String>[
'git',
'describe',
'--match',
'*.*.*',
'--exact-match',
'--tags',
'refs/remotes/$remote/dev',
], stdout: lastVersion),
const FakeCommand(command: <String>[
'git',
'rev-parse',
lastVersion,
], stdout: 'zxy321'),
const FakeCommand(command: <String>[
'git',
'rev-parse',
commit,
], stdout: commit),
const FakeCommand(command: <String>[
'git',
'tag',
nextVersion,
commit,
]),
const FakeCommand(command: <String>[
'git',
'push',
remote,
nextVersion,
]),
const FakeCommand(command: <String>[
'git',
'push',
'--force',
remote,
'$commit:dev',
]),
]);
fakeArgResults = FakeArgResults(
level: level,
candidateBranch: candidateBranch,
remote: remote,
force: true,
);
expect(
await rollDev(
argResults: fakeArgResults,
repository: repo,
stdio: stdio,
usage: usage,
),
true,
);
expect(processManager.hasRemainingExpectations, false);
});
}, onPlatform: <String, dynamic>{
'windows': const Skip('Flutter Conductor only supported on macos/linux'),
});
}
...@@ -163,7 +163,7 @@ void main() { ...@@ -163,7 +163,7 @@ void main() {
command: <String>['git', 'fetch', 'mirror'], command: <String>['git', 'fetch', 'mirror'],
), ),
const FakeCommand( const FakeCommand(
command: <String>['git', 'checkout', 'upstream/$candidateBranch'], command: <String>['git', 'checkout', candidateBranch],
), ),
const FakeCommand( const FakeCommand(
command: <String>['git', 'rev-parse', 'HEAD'], command: <String>['git', 'rev-parse', 'HEAD'],
...@@ -220,7 +220,7 @@ void main() { ...@@ -220,7 +220,7 @@ void main() {
command: <String>['git', 'fetch', 'mirror'], command: <String>['git', 'fetch', 'mirror'],
), ),
const FakeCommand( const FakeCommand(
command: <String>['git', 'checkout', 'upstream/$candidateBranch'], command: <String>['git', 'checkout', candidateBranch],
), ),
const FakeCommand( const FakeCommand(
command: <String>['git', 'rev-parse', 'HEAD'], command: <String>['git', 'rev-parse', 'HEAD'],
...@@ -348,7 +348,7 @@ void main() { ...@@ -348,7 +348,7 @@ void main() {
command: <String>['git', 'fetch', 'mirror'], command: <String>['git', 'fetch', 'mirror'],
), ),
const FakeCommand( const FakeCommand(
command: <String>['git', 'checkout', 'upstream/$candidateBranch'], command: <String>['git', 'checkout', candidateBranch],
), ),
const FakeCommand( const FakeCommand(
command: <String>['git', 'rev-parse', 'HEAD'], command: <String>['git', 'rev-parse', 'HEAD'],
...@@ -405,7 +405,7 @@ void main() { ...@@ -405,7 +405,7 @@ void main() {
command: <String>['git', 'fetch', 'mirror'], command: <String>['git', 'fetch', 'mirror'],
), ),
const FakeCommand( const FakeCommand(
command: <String>['git', 'checkout', 'upstream/$candidateBranch'], command: <String>['git', 'checkout', candidateBranch],
), ),
const FakeCommand( const FakeCommand(
command: <String>['git', 'rev-parse', 'HEAD'], command: <String>['git', 'rev-parse', 'HEAD'],
...@@ -541,7 +541,7 @@ void main() { ...@@ -541,7 +541,7 @@ void main() {
command: <String>['git', 'fetch', 'mirror'], command: <String>['git', 'fetch', 'mirror'],
), ),
const FakeCommand( const FakeCommand(
command: <String>['git', 'checkout', 'upstream/$candidateBranch'], command: <String>['git', 'checkout', candidateBranch],
), ),
const FakeCommand( const FakeCommand(
command: <String>['git', 'rev-parse', 'HEAD'], command: <String>['git', 'rev-parse', 'HEAD'],
...@@ -598,7 +598,7 @@ void main() { ...@@ -598,7 +598,7 @@ void main() {
command: <String>['git', 'fetch', 'mirror'], command: <String>['git', 'fetch', 'mirror'],
), ),
const FakeCommand( const FakeCommand(
command: <String>['git', 'checkout', 'upstream/$candidateBranch'], command: <String>['git', 'checkout', candidateBranch],
), ),
const FakeCommand( const FakeCommand(
command: <String>['git', 'rev-parse', 'HEAD'], command: <String>['git', 'rev-parse', 'HEAD'],
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment