changed subprocesses to async from sync (#89668)
* changed subprocess to async from sync
This commit is contained in:
parent
cd4b47ab3f
commit
f47eac9c58
6
dev/conductor/dart_test.yaml
Normal file
6
dev/conductor/dart_test.yaml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
# codesign_integration_test takes longer than the default timeout which is 30s
|
||||||
|
# since it has to clone both the engine and framework repos, and that test is running
|
||||||
|
# asynchronously. The async function is being awaited more than 30s which counts as inactivity
|
||||||
|
# The default timeout needs to be extended to accomodate codesign_integration_test
|
||||||
|
|
||||||
|
timeout: 5m
|
@ -38,9 +38,9 @@ class CandidatesCommand extends Command<void> {
|
|||||||
String get description => 'List release candidates.';
|
String get description => 'List release candidates.';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void run() {
|
Future<void> run() async {
|
||||||
final ArgResults results = argResults!;
|
final ArgResults results = argResults!;
|
||||||
git.run(
|
await git.run(
|
||||||
<String>['fetch', results[kRemote] as String],
|
<String>['fetch', results[kRemote] as String],
|
||||||
'Fetch from remote ${results[kRemote]}',
|
'Fetch from remote ${results[kRemote]}',
|
||||||
workingDirectory: flutterRoot.path,
|
workingDirectory: flutterRoot.path,
|
||||||
@ -52,10 +52,10 @@ class CandidatesCommand extends Command<void> {
|
|||||||
upstreamPath: flutterRoot.path,
|
upstreamPath: flutterRoot.path,
|
||||||
);
|
);
|
||||||
|
|
||||||
final Version currentVersion = framework.flutterVersion();
|
final Version currentVersion = await framework.flutterVersion();
|
||||||
stdio.printStatus('currentVersion = $currentVersion');
|
stdio.printStatus('currentVersion = $currentVersion');
|
||||||
|
|
||||||
final List<String> branches = git.getOutput(
|
final List<String> branches = (await git.getOutput(
|
||||||
<String>[
|
<String>[
|
||||||
'branch',
|
'branch',
|
||||||
'--no-color',
|
'--no-color',
|
||||||
@ -65,7 +65,7 @@ class CandidatesCommand extends Command<void> {
|
|||||||
],
|
],
|
||||||
'List all remote branches',
|
'List all remote branches',
|
||||||
workingDirectory: flutterRoot.path,
|
workingDirectory: flutterRoot.path,
|
||||||
).split('\n');
|
)).split('\n');
|
||||||
|
|
||||||
// Pattern for extracting only the branch name via sub-group 1
|
// Pattern for extracting only the branch name via sub-group 1
|
||||||
final RegExp remotePattern = RegExp('${results[kRemote]}\\/(.*)');
|
final RegExp remotePattern = RegExp('${results[kRemote]}\\/(.*)');
|
||||||
|
@ -89,7 +89,7 @@ class CodesignCommand extends Command<void> {
|
|||||||
'For codesigning and verifying the signatures of engine binaries.';
|
'For codesigning and verifying the signatures of engine binaries.';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void run() {
|
Future<void> run() async {
|
||||||
if (!platform.isMacOS) {
|
if (!platform.isMacOS) {
|
||||||
throw ConductorException(
|
throw ConductorException(
|
||||||
'Error! Expected operating system "macos", actual operating system is: '
|
'Error! Expected operating system "macos", actual operating system is: '
|
||||||
@ -112,21 +112,21 @@ class CodesignCommand extends Command<void> {
|
|||||||
'the desired revision and run that version of the conductor.\n');
|
'the desired revision and run that version of the conductor.\n');
|
||||||
revision = argResults![kRevision] as String;
|
revision = argResults![kRevision] as String;
|
||||||
} else {
|
} else {
|
||||||
revision = (processManager.runSync(
|
revision = ((await processManager.run(
|
||||||
<String>['git', 'rev-parse', 'HEAD'],
|
<String>['git', 'rev-parse', 'HEAD'],
|
||||||
workingDirectory: framework.checkoutDirectory.path,
|
workingDirectory: (await framework.checkoutDirectory).path,
|
||||||
).stdout as String).trim();
|
)).stdout as String).trim();
|
||||||
assert(revision.isNotEmpty);
|
assert(revision.isNotEmpty);
|
||||||
}
|
}
|
||||||
|
|
||||||
framework.checkout(revision);
|
await framework.checkout(revision);
|
||||||
|
|
||||||
// Ensure artifacts present
|
// Ensure artifacts present
|
||||||
framework.runFlutter(<String>['precache', '--android', '--ios', '--macos']);
|
await framework.runFlutter(<String>['precache', '--android', '--ios', '--macos']);
|
||||||
|
|
||||||
verifyExist();
|
await verifyExist();
|
||||||
if (argResults![kSignatures] as bool) {
|
if (argResults![kSignatures] as bool) {
|
||||||
verifySignatures();
|
await verifySignatures();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,7 +134,8 @@ class CodesignCommand extends Command<void> {
|
|||||||
///
|
///
|
||||||
/// This list should be kept in sync with the actual contents of Flutter's
|
/// This list should be kept in sync with the actual contents of Flutter's
|
||||||
/// cache.
|
/// cache.
|
||||||
List<String> get binariesWithEntitlements {
|
Future<List<String>> get binariesWithEntitlements async {
|
||||||
|
final String frameworkCacheDirectory = await framework.cacheDirectory;
|
||||||
return <String>[
|
return <String>[
|
||||||
'artifacts/engine/android-arm-profile/darwin-x64/gen_snapshot',
|
'artifacts/engine/android-arm-profile/darwin-x64/gen_snapshot',
|
||||||
'artifacts/engine/android-arm-release/darwin-x64/gen_snapshot',
|
'artifacts/engine/android-arm-release/darwin-x64/gen_snapshot',
|
||||||
@ -165,7 +166,7 @@ class CodesignCommand extends Command<void> {
|
|||||||
'dart-sdk/bin/utils/gen_snapshot',
|
'dart-sdk/bin/utils/gen_snapshot',
|
||||||
]
|
]
|
||||||
.map((String relativePath) =>
|
.map((String relativePath) =>
|
||||||
fileSystem.path.join(framework.cacheDirectory, relativePath))
|
fileSystem.path.join(frameworkCacheDirectory, relativePath))
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -173,7 +174,8 @@ class CodesignCommand extends Command<void> {
|
|||||||
///
|
///
|
||||||
/// This list should be kept in sync with the actual contents of Flutter's
|
/// This list should be kept in sync with the actual contents of Flutter's
|
||||||
/// cache.
|
/// cache.
|
||||||
List<String> get binariesWithoutEntitlements {
|
Future<List<String>> get binariesWithoutEntitlements async {
|
||||||
|
final String frameworkCacheDirectory = await framework.cacheDirectory;
|
||||||
return <String>[
|
return <String>[
|
||||||
'artifacts/engine/darwin-x64-profile/FlutterMacOS.framework/Versions/A/FlutterMacOS',
|
'artifacts/engine/darwin-x64-profile/FlutterMacOS.framework/Versions/A/FlutterMacOS',
|
||||||
'artifacts/engine/darwin-x64-release/FlutterMacOS.framework/Versions/A/FlutterMacOS',
|
'artifacts/engine/darwin-x64-release/FlutterMacOS.framework/Versions/A/FlutterMacOS',
|
||||||
@ -188,7 +190,7 @@ class CodesignCommand extends Command<void> {
|
|||||||
'artifacts/ios-deploy/ios-deploy',
|
'artifacts/ios-deploy/ios-deploy',
|
||||||
]
|
]
|
||||||
.map((String relativePath) =>
|
.map((String relativePath) =>
|
||||||
fileSystem.path.join(framework.cacheDirectory, relativePath))
|
fileSystem.path.join(frameworkCacheDirectory, relativePath))
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,12 +202,13 @@ class CodesignCommand extends Command<void> {
|
|||||||
/// [binariesWithEntitlements] or [binariesWithoutEntitlements] lists should
|
/// [binariesWithEntitlements] or [binariesWithoutEntitlements] lists should
|
||||||
/// be updated accordingly.
|
/// be updated accordingly.
|
||||||
@visibleForTesting
|
@visibleForTesting
|
||||||
void verifyExist() {
|
Future<void> verifyExist() async {
|
||||||
final Set<String> foundFiles = <String>{};
|
final Set<String> foundFiles = <String>{};
|
||||||
for (final String binaryPath in findBinaryPaths(framework.cacheDirectory)) {
|
for (final String binaryPath
|
||||||
if (binariesWithEntitlements.contains(binaryPath)) {
|
in await findBinaryPaths(await framework.cacheDirectory)) {
|
||||||
|
if ((await binariesWithEntitlements).contains(binaryPath)) {
|
||||||
foundFiles.add(binaryPath);
|
foundFiles.add(binaryPath);
|
||||||
} else if (binariesWithoutEntitlements.contains(binaryPath)) {
|
} else if ((await binariesWithoutEntitlements).contains(binaryPath)) {
|
||||||
foundFiles.add(binaryPath);
|
foundFiles.add(binaryPath);
|
||||||
} else {
|
} else {
|
||||||
throw ConductorException(
|
throw ConductorException(
|
||||||
@ -214,7 +217,7 @@ class CodesignCommand extends Command<void> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final List<String> allExpectedFiles =
|
final List<String> allExpectedFiles =
|
||||||
binariesWithEntitlements + binariesWithoutEntitlements;
|
(await binariesWithEntitlements) + (await binariesWithoutEntitlements);
|
||||||
if (foundFiles.length < allExpectedFiles.length) {
|
if (foundFiles.length < allExpectedFiles.length) {
|
||||||
final List<String> unfoundFiles = allExpectedFiles
|
final List<String> unfoundFiles = allExpectedFiles
|
||||||
.where(
|
.where(
|
||||||
@ -237,19 +240,19 @@ class CodesignCommand extends Command<void> {
|
|||||||
|
|
||||||
/// Verify code signatures and entitlements of all binaries in the cache.
|
/// Verify code signatures and entitlements of all binaries in the cache.
|
||||||
@visibleForTesting
|
@visibleForTesting
|
||||||
void verifySignatures() {
|
Future<void> verifySignatures() async {
|
||||||
final List<String> unsignedBinaries = <String>[];
|
final List<String> unsignedBinaries = <String>[];
|
||||||
final List<String> wrongEntitlementBinaries = <String>[];
|
final List<String> wrongEntitlementBinaries = <String>[];
|
||||||
final List<String> unexpectedBinaries = <String>[];
|
final List<String> unexpectedBinaries = <String>[];
|
||||||
|
for (final String binaryPath
|
||||||
for (final String binaryPath in findBinaryPaths(framework.cacheDirectory)) {
|
in await findBinaryPaths(await framework.cacheDirectory)) {
|
||||||
bool verifySignature = false;
|
bool verifySignature = false;
|
||||||
bool verifyEntitlements = false;
|
bool verifyEntitlements = false;
|
||||||
if (binariesWithEntitlements.contains(binaryPath)) {
|
if ((await binariesWithEntitlements).contains(binaryPath)) {
|
||||||
verifySignature = true;
|
verifySignature = true;
|
||||||
verifyEntitlements = true;
|
verifyEntitlements = true;
|
||||||
}
|
}
|
||||||
if (binariesWithoutEntitlements.contains(binaryPath)) {
|
if ((await binariesWithoutEntitlements).contains(binaryPath)) {
|
||||||
verifySignature = true;
|
verifySignature = true;
|
||||||
}
|
}
|
||||||
if (!verifySignature && !verifyEntitlements) {
|
if (!verifySignature && !verifyEntitlements) {
|
||||||
@ -258,7 +261,7 @@ class CodesignCommand extends Command<void> {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
stdio.printTrace('Verifying the code signature of $binaryPath');
|
stdio.printTrace('Verifying the code signature of $binaryPath');
|
||||||
final io.ProcessResult codeSignResult = processManager.runSync(
|
final io.ProcessResult codeSignResult = await processManager.run(
|
||||||
<String>[
|
<String>[
|
||||||
'codesign',
|
'codesign',
|
||||||
'-vvv',
|
'-vvv',
|
||||||
@ -275,7 +278,7 @@ class CodesignCommand extends Command<void> {
|
|||||||
}
|
}
|
||||||
if (verifyEntitlements) {
|
if (verifyEntitlements) {
|
||||||
stdio.printTrace('Verifying entitlements of $binaryPath');
|
stdio.printTrace('Verifying entitlements of $binaryPath');
|
||||||
if (!hasExpectedEntitlements(binaryPath)) {
|
if (!(await hasExpectedEntitlements(binaryPath))) {
|
||||||
wrongEntitlementBinaries.add(binaryPath);
|
wrongEntitlementBinaries.add(binaryPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -330,11 +333,12 @@ class CodesignCommand extends Command<void> {
|
|||||||
List<String>? _allBinaryPaths;
|
List<String>? _allBinaryPaths;
|
||||||
|
|
||||||
/// Find every binary file in the given [rootDirectory].
|
/// Find every binary file in the given [rootDirectory].
|
||||||
List<String> findBinaryPaths(String rootDirectory) {
|
Future<List<String>> findBinaryPaths(String rootDirectory) async {
|
||||||
if (_allBinaryPaths != null) {
|
if (_allBinaryPaths != null) {
|
||||||
return _allBinaryPaths!;
|
return _allBinaryPaths!;
|
||||||
}
|
}
|
||||||
final io.ProcessResult result = processManager.runSync(
|
final List<String> allBinaryPaths = <String>[];
|
||||||
|
final io.ProcessResult result = await processManager.run(
|
||||||
<String>[
|
<String>[
|
||||||
'find',
|
'find',
|
||||||
rootDirectory,
|
rootDirectory,
|
||||||
@ -346,13 +350,19 @@ class CodesignCommand extends Command<void> {
|
|||||||
.split('\n')
|
.split('\n')
|
||||||
.where((String s) => s.isNotEmpty)
|
.where((String s) => s.isNotEmpty)
|
||||||
.toList();
|
.toList();
|
||||||
_allBinaryPaths = allFiles.where(isBinary).toList();
|
|
||||||
|
await Future.forEach(allFiles, (String filePath) async {
|
||||||
|
if (await isBinary(filePath)) {
|
||||||
|
allBinaryPaths.add(filePath);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
_allBinaryPaths = allBinaryPaths;
|
||||||
return _allBinaryPaths!;
|
return _allBinaryPaths!;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check mime-type of file at [filePath] to determine if it is binary.
|
/// Check mime-type of file at [filePath] to determine if it is binary.
|
||||||
bool isBinary(String filePath) {
|
Future<bool> isBinary(String filePath) async {
|
||||||
final io.ProcessResult result = processManager.runSync(
|
final io.ProcessResult result = await processManager.run(
|
||||||
<String>[
|
<String>[
|
||||||
'file',
|
'file',
|
||||||
'--mime-type',
|
'--mime-type',
|
||||||
@ -364,8 +374,8 @@ class CodesignCommand extends Command<void> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Check if the binary has the expected entitlements.
|
/// Check if the binary has the expected entitlements.
|
||||||
bool hasExpectedEntitlements(String binaryPath) {
|
Future<bool> hasExpectedEntitlements(String binaryPath) async {
|
||||||
final io.ProcessResult entitlementResult = processManager.runSync(
|
final io.ProcessResult entitlementResult = await processManager.run(
|
||||||
<String>[
|
<String>[
|
||||||
'codesign',
|
'codesign',
|
||||||
'--display',
|
'--display',
|
||||||
@ -386,7 +396,7 @@ class CodesignCommand extends Command<void> {
|
|||||||
final String output = entitlementResult.stdout as String;
|
final String output = entitlementResult.stdout as String;
|
||||||
for (final String entitlement in expectedEntitlements) {
|
for (final String entitlement in expectedEntitlements) {
|
||||||
final bool entitlementExpected =
|
final bool entitlementExpected =
|
||||||
binariesWithEntitlements.contains(binaryPath);
|
(await binariesWithEntitlements).contains(binaryPath);
|
||||||
if (output.contains(entitlement) != entitlementExpected) {
|
if (output.contains(entitlement) != entitlementExpected) {
|
||||||
stdio.printError(
|
stdio.printError(
|
||||||
'File "$binaryPath" ${entitlementExpected ? 'does not have expected' : 'has unexpected'} '
|
'File "$binaryPath" ${entitlementExpected ? 'does not have expected' : 'has unexpected'} '
|
||||||
|
@ -14,34 +14,34 @@ class Git {
|
|||||||
|
|
||||||
final ProcessManager processManager;
|
final ProcessManager processManager;
|
||||||
|
|
||||||
String getOutput(
|
Future<String> getOutput(
|
||||||
List<String> args,
|
List<String> args,
|
||||||
String explanation, {
|
String explanation, {
|
||||||
required String workingDirectory,
|
required String workingDirectory,
|
||||||
bool allowFailures = false,
|
bool allowFailures = false,
|
||||||
}) {
|
}) async {
|
||||||
final ProcessResult result = _run(args, workingDirectory);
|
final ProcessResult result = await _run(args, workingDirectory);
|
||||||
if (result.exitCode == 0) {
|
if (result.exitCode == 0) {
|
||||||
return stdoutToString(result.stdout);
|
return stdoutToString(result.stdout);
|
||||||
}
|
}
|
||||||
_reportFailureAndExit(args, workingDirectory, result, explanation);
|
_reportFailureAndExit(args, workingDirectory, result, explanation);
|
||||||
}
|
}
|
||||||
|
|
||||||
int run(
|
Future<int> run(
|
||||||
List<String> args,
|
List<String> args,
|
||||||
String explanation, {
|
String explanation, {
|
||||||
bool allowNonZeroExitCode = false,
|
bool allowNonZeroExitCode = false,
|
||||||
required String workingDirectory,
|
required String workingDirectory,
|
||||||
}) {
|
}) async {
|
||||||
final ProcessResult result = _run(args, workingDirectory);
|
final ProcessResult result = await _run(args, workingDirectory);
|
||||||
if (result.exitCode != 0 && !allowNonZeroExitCode) {
|
if (result.exitCode != 0 && !allowNonZeroExitCode) {
|
||||||
_reportFailureAndExit(args, workingDirectory, result, explanation);
|
_reportFailureAndExit(args, workingDirectory, result, explanation);
|
||||||
}
|
}
|
||||||
return result.exitCode;
|
return result.exitCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
ProcessResult _run(List<String> args, String workingDirectory) {
|
Future<ProcessResult> _run(List<String> args, String workingDirectory) async {
|
||||||
return processManager.runSync(
|
return processManager.run(
|
||||||
<String>['git', ...args],
|
<String>['git', ...args],
|
||||||
workingDirectory: workingDirectory,
|
workingDirectory: workingDirectory,
|
||||||
environment: <String, String>{'GIT_TRACE': '1'},
|
environment: <String, String>{'GIT_TRACE': '1'},
|
||||||
|
@ -47,8 +47,8 @@ class NextCommand extends Command<void> {
|
|||||||
String get description => 'Proceed to the next release phase.';
|
String get description => 'Proceed to the next release phase.';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void run() {
|
Future<void> run() async {
|
||||||
runNext(
|
await runNext(
|
||||||
autoAccept: argResults![kYesFlag] as bool,
|
autoAccept: argResults![kYesFlag] as bool,
|
||||||
checkouts: checkouts,
|
checkouts: checkouts,
|
||||||
force: argResults![kForceFlag] as bool,
|
force: argResults![kForceFlag] as bool,
|
||||||
@ -74,12 +74,12 @@ bool prompt(String message, Stdio stdio) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@visibleForTesting
|
@visibleForTesting
|
||||||
void runNext({
|
Future<void> runNext({
|
||||||
required bool autoAccept,
|
required bool autoAccept,
|
||||||
required bool force,
|
required bool force,
|
||||||
required Checkouts checkouts,
|
required Checkouts checkouts,
|
||||||
required File stateFile,
|
required File stateFile,
|
||||||
}) {
|
}) async {
|
||||||
final Stdio stdio = checkouts.stdio;
|
final Stdio stdio = checkouts.stdio;
|
||||||
const List<CherrypickState> finishedStates = <CherrypickState>[
|
const List<CherrypickState> finishedStates = <CherrypickState>[
|
||||||
CherrypickState.COMPLETED,
|
CherrypickState.COMPLETED,
|
||||||
@ -106,10 +106,11 @@ void runNext({
|
|||||||
previousCheckoutLocation: state.engine.checkoutPath,
|
previousCheckoutLocation: state.engine.checkoutPath,
|
||||||
);
|
);
|
||||||
// check if the candidate branch is enabled in .ci.yaml
|
// check if the candidate branch is enabled in .ci.yaml
|
||||||
if (!engine.ciYaml.enabledBranches.contains(state.engine.candidateBranch)) {
|
final CiYaml engineCiYaml = await engine.ciYaml;
|
||||||
engine.ciYaml.enableBranch(state.engine.candidateBranch);
|
if (!engineCiYaml.enabledBranches.contains(state.engine.candidateBranch)) {
|
||||||
|
engineCiYaml.enableBranch(state.engine.candidateBranch);
|
||||||
// commit
|
// commit
|
||||||
final String revision = engine.commit(
|
final String revision = await engine.commit(
|
||||||
'add branch ${state.engine.candidateBranch} to enabled_branches in .ci.yaml',
|
'add branch ${state.engine.candidateBranch} to enabled_branches in .ci.yaml',
|
||||||
addFirst: true,
|
addFirst: true,
|
||||||
);
|
);
|
||||||
@ -158,7 +159,7 @@ void runNext({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
engine.pushRef(
|
await engine.pushRef(
|
||||||
fromRef: 'HEAD',
|
fromRef: 'HEAD',
|
||||||
// Explicitly create new branch
|
// Explicitly create new branch
|
||||||
toRef: 'refs/heads/${state.engine.workingBranch}',
|
toRef: 'refs/heads/${state.engine.workingBranch}',
|
||||||
@ -211,7 +212,7 @@ void runNext({
|
|||||||
previousCheckoutLocation: state.engine.checkoutPath,
|
previousCheckoutLocation: state.engine.checkoutPath,
|
||||||
);
|
);
|
||||||
|
|
||||||
final String engineRevision = engine.reverseParse('HEAD');
|
final String engineRevision = await engine.reverseParse('HEAD');
|
||||||
|
|
||||||
final Remote upstream = Remote(
|
final Remote upstream = Remote(
|
||||||
name: RemoteName.upstream,
|
name: RemoteName.upstream,
|
||||||
@ -225,10 +226,10 @@ void runNext({
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Check if the current candidate branch is enabled
|
// Check if the current candidate branch is enabled
|
||||||
if (!framework.ciYaml.enabledBranches.contains(state.framework.candidateBranch)) {
|
if (!(await framework.ciYaml).enabledBranches.contains(state.framework.candidateBranch)) {
|
||||||
framework.ciYaml.enableBranch(state.framework.candidateBranch);
|
(await framework.ciYaml).enableBranch(state.framework.candidateBranch);
|
||||||
// commit
|
// commit
|
||||||
final String revision = framework.commit(
|
final String revision = await framework.commit(
|
||||||
'add branch ${state.framework.candidateBranch} to enabled_branches in .ci.yaml',
|
'add branch ${state.framework.candidateBranch} to enabled_branches in .ci.yaml',
|
||||||
addFirst: true,
|
addFirst: true,
|
||||||
);
|
);
|
||||||
@ -240,9 +241,9 @@ void runNext({
|
|||||||
}
|
}
|
||||||
|
|
||||||
stdio.printStatus('Rolling new engine hash $engineRevision to framework checkout...');
|
stdio.printStatus('Rolling new engine hash $engineRevision to framework checkout...');
|
||||||
final bool needsCommit = framework.updateEngineRevision(engineRevision);
|
final bool needsCommit = await framework.updateEngineRevision(engineRevision);
|
||||||
if (needsCommit) {
|
if (needsCommit) {
|
||||||
final String revision = framework.commit(
|
final String revision = await framework.commit(
|
||||||
'Update Engine revision to $engineRevision for ${state.releaseChannel} release ${state.releaseVersion}',
|
'Update Engine revision to $engineRevision for ${state.releaseChannel} release ${state.releaseVersion}',
|
||||||
addFirst: true,
|
addFirst: true,
|
||||||
);
|
);
|
||||||
@ -293,7 +294,7 @@ void runNext({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
framework.pushRef(
|
await framework.pushRef(
|
||||||
fromRef: 'HEAD',
|
fromRef: 'HEAD',
|
||||||
// Explicitly create new branch
|
// Explicitly create new branch
|
||||||
toRef: 'refs/heads/${state.framework.workingBranch}',
|
toRef: 'refs/heads/${state.framework.workingBranch}',
|
||||||
@ -314,7 +315,7 @@ void runNext({
|
|||||||
upstreamRemote: upstream,
|
upstreamRemote: upstream,
|
||||||
previousCheckoutLocation: state.framework.checkoutPath,
|
previousCheckoutLocation: state.framework.checkoutPath,
|
||||||
);
|
);
|
||||||
final String headRevision = framework.reverseParse('HEAD');
|
final String headRevision = await framework.reverseParse('HEAD');
|
||||||
if (autoAccept == false) {
|
if (autoAccept == false) {
|
||||||
final bool response = prompt(
|
final bool response = prompt(
|
||||||
'Are you ready to tag commit $headRevision as ${state.releaseVersion}\n'
|
'Are you ready to tag commit $headRevision as ${state.releaseVersion}\n'
|
||||||
@ -327,7 +328,7 @@ void runNext({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
framework.tag(headRevision, state.releaseVersion, upstream.name);
|
await framework.tag(headRevision, state.releaseVersion, upstream.name);
|
||||||
break;
|
break;
|
||||||
case pb.ReleasePhase.PUBLISH_CHANNEL:
|
case pb.ReleasePhase.PUBLISH_CHANNEL:
|
||||||
final Remote upstream = Remote(
|
final Remote upstream = Remote(
|
||||||
@ -341,10 +342,10 @@ void runNext({
|
|||||||
upstreamRemote: upstream,
|
upstreamRemote: upstream,
|
||||||
previousCheckoutLocation: state.framework.checkoutPath,
|
previousCheckoutLocation: state.framework.checkoutPath,
|
||||||
);
|
);
|
||||||
final String headRevision = framework.reverseParse('HEAD');
|
final String headRevision = await framework.reverseParse('HEAD');
|
||||||
if (autoAccept == false) {
|
if (autoAccept == false) {
|
||||||
// dryRun: true means print out git command
|
// dryRun: true means print out git command
|
||||||
framework.pushRef(
|
await framework.pushRef(
|
||||||
fromRef: headRevision,
|
fromRef: headRevision,
|
||||||
toRef: state.releaseChannel,
|
toRef: state.releaseChannel,
|
||||||
remote: state.framework.upstream.url,
|
remote: state.framework.upstream.url,
|
||||||
@ -362,7 +363,7 @@ void runNext({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
framework.pushRef(
|
await framework.pushRef(
|
||||||
fromRef: headRevision,
|
fromRef: headRevision,
|
||||||
toRef: state.releaseChannel,
|
toRef: state.releaseChannel,
|
||||||
remote: state.framework.upstream.url,
|
remote: state.framework.upstream.url,
|
||||||
|
@ -58,34 +58,11 @@ abstract class Repository {
|
|||||||
required this.parentDirectory,
|
required this.parentDirectory,
|
||||||
this.initialRef,
|
this.initialRef,
|
||||||
this.localUpstream = false,
|
this.localUpstream = false,
|
||||||
String? previousCheckoutLocation,
|
this.previousCheckoutLocation,
|
||||||
this.mirrorRemote,
|
this.mirrorRemote,
|
||||||
}) : git = Git(processManager),
|
}) : git = Git(processManager),
|
||||||
assert(localUpstream != null),
|
assert(localUpstream != null),
|
||||||
assert(upstreamRemote.url.isNotEmpty) {
|
assert(upstreamRemote.url.isNotEmpty);
|
||||||
if (previousCheckoutLocation != null) {
|
|
||||||
_checkoutDirectory = fileSystem.directory(previousCheckoutLocation);
|
|
||||||
if (!_checkoutDirectory!.existsSync()) {
|
|
||||||
throw ConductorException(
|
|
||||||
'Provided previousCheckoutLocation $previousCheckoutLocation does not exist on disk!');
|
|
||||||
}
|
|
||||||
if (initialRef != null) {
|
|
||||||
assert(initialRef != '');
|
|
||||||
git.run(
|
|
||||||
<String>['fetch', upstreamRemote.name],
|
|
||||||
'Fetch ${upstreamRemote.name} to ensure we have latest refs',
|
|
||||||
workingDirectory: _checkoutDirectory!.path,
|
|
||||||
);
|
|
||||||
// Note: if [initialRef] is a remote ref the checkout will be left in a
|
|
||||||
// detached HEAD state.
|
|
||||||
git.run(
|
|
||||||
<String>['checkout', initialRef!],
|
|
||||||
'Checking out initialRef $initialRef',
|
|
||||||
workingDirectory: _checkoutDirectory!.path,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final String name;
|
final String name;
|
||||||
final Remote upstreamRemote;
|
final Remote upstreamRemote;
|
||||||
@ -109,22 +86,47 @@ abstract class Repository {
|
|||||||
final bool localUpstream;
|
final bool localUpstream;
|
||||||
|
|
||||||
Directory? _checkoutDirectory;
|
Directory? _checkoutDirectory;
|
||||||
|
String? previousCheckoutLocation;
|
||||||
|
|
||||||
/// Directory for the repository checkout.
|
/// Directory for the repository checkout.
|
||||||
///
|
///
|
||||||
/// Since cloning a repository takes a long time, we do not ensure it is
|
/// Since cloning a repository takes a long time, we do not ensure it is
|
||||||
/// cloned on the filesystem until this getter is accessed.
|
/// cloned on the filesystem until this getter is accessed.
|
||||||
Directory get checkoutDirectory {
|
Future<Directory> get checkoutDirectory async {
|
||||||
if (_checkoutDirectory != null) {
|
if (_checkoutDirectory != null) {
|
||||||
return _checkoutDirectory!;
|
return _checkoutDirectory!;
|
||||||
}
|
}
|
||||||
|
if (previousCheckoutLocation != null) {
|
||||||
|
_checkoutDirectory = fileSystem.directory(previousCheckoutLocation);
|
||||||
|
if (!_checkoutDirectory!.existsSync()) {
|
||||||
|
throw ConductorException(
|
||||||
|
'Provided previousCheckoutLocation $previousCheckoutLocation does not exist on disk!');
|
||||||
|
}
|
||||||
|
if (initialRef != null) {
|
||||||
|
assert(initialRef != '');
|
||||||
|
await git.run(
|
||||||
|
<String>['fetch', upstreamRemote.name],
|
||||||
|
'Fetch ${upstreamRemote.name} to ensure we have latest refs',
|
||||||
|
workingDirectory: _checkoutDirectory!.path,
|
||||||
|
);
|
||||||
|
// Note: if [initialRef] is a remote ref the checkout will be left in a
|
||||||
|
// detached HEAD state.
|
||||||
|
await git.run(
|
||||||
|
<String>['checkout', initialRef!],
|
||||||
|
'Checking out initialRef $initialRef',
|
||||||
|
workingDirectory: _checkoutDirectory!.path,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return _checkoutDirectory!;
|
||||||
|
}
|
||||||
|
|
||||||
_checkoutDirectory = parentDirectory.childDirectory(name);
|
_checkoutDirectory = parentDirectory.childDirectory(name);
|
||||||
lazilyInitialize(_checkoutDirectory!);
|
await lazilyInitialize(_checkoutDirectory!);
|
||||||
return _checkoutDirectory!;
|
return _checkoutDirectory!;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ensure the repository is cloned to disk and initialized with proper state.
|
/// Ensure the repository is cloned to disk and initialized with proper state.
|
||||||
void lazilyInitialize(Directory checkoutDirectory) {
|
Future<void> lazilyInitialize(Directory checkoutDirectory) async {
|
||||||
if (checkoutDirectory.existsSync()) {
|
if (checkoutDirectory.existsSync()) {
|
||||||
stdio.printTrace('Deleting $name from ${checkoutDirectory.path}...');
|
stdio.printTrace('Deleting $name from ${checkoutDirectory.path}...');
|
||||||
checkoutDirectory.deleteSync(recursive: true);
|
checkoutDirectory.deleteSync(recursive: true);
|
||||||
@ -133,7 +135,7 @@ abstract class Repository {
|
|||||||
stdio.printTrace(
|
stdio.printTrace(
|
||||||
'Cloning $name from ${upstreamRemote.url} to ${checkoutDirectory.path}...',
|
'Cloning $name from ${upstreamRemote.url} to ${checkoutDirectory.path}...',
|
||||||
);
|
);
|
||||||
git.run(
|
await git.run(
|
||||||
<String>[
|
<String>[
|
||||||
'clone',
|
'clone',
|
||||||
'--origin',
|
'--origin',
|
||||||
@ -146,12 +148,12 @@ abstract class Repository {
|
|||||||
workingDirectory: parentDirectory.path,
|
workingDirectory: parentDirectory.path,
|
||||||
);
|
);
|
||||||
if (mirrorRemote != null) {
|
if (mirrorRemote != null) {
|
||||||
git.run(
|
await git.run(
|
||||||
<String>['remote', 'add', mirrorRemote!.name, mirrorRemote!.url],
|
<String>['remote', 'add', mirrorRemote!.name, mirrorRemote!.url],
|
||||||
'Adding remote ${mirrorRemote!.url} as ${mirrorRemote!.name}',
|
'Adding remote ${mirrorRemote!.url} as ${mirrorRemote!.name}',
|
||||||
workingDirectory: checkoutDirectory.path,
|
workingDirectory: checkoutDirectory.path,
|
||||||
);
|
);
|
||||||
git.run(
|
await git.run(
|
||||||
<String>['fetch', mirrorRemote!.name],
|
<String>['fetch', mirrorRemote!.name],
|
||||||
'Fetching git remote ${mirrorRemote!.name}',
|
'Fetching git remote ${mirrorRemote!.name}',
|
||||||
workingDirectory: checkoutDirectory.path,
|
workingDirectory: checkoutDirectory.path,
|
||||||
@ -161,7 +163,7 @@ abstract class Repository {
|
|||||||
// 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 kReleaseChannels) {
|
||||||
git.run(
|
await git.run(
|
||||||
<String>['checkout', channel, '--'],
|
<String>['checkout', channel, '--'],
|
||||||
'check out branch $channel locally',
|
'check out branch $channel locally',
|
||||||
workingDirectory: checkoutDirectory.path,
|
workingDirectory: checkoutDirectory.path,
|
||||||
@ -170,82 +172,82 @@ abstract class Repository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (initialRef != null) {
|
if (initialRef != null) {
|
||||||
git.run(
|
await git.run(
|
||||||
<String>['checkout', '${upstreamRemote.name}/$initialRef'],
|
<String>['checkout', '${upstreamRemote.name}/$initialRef'],
|
||||||
'Checking out initialRef $initialRef',
|
'Checking out initialRef $initialRef',
|
||||||
workingDirectory: checkoutDirectory.path,
|
workingDirectory: checkoutDirectory.path,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
final String revision = reverseParse('HEAD');
|
final String revision = await reverseParse('HEAD');
|
||||||
stdio.printTrace(
|
stdio.printTrace(
|
||||||
'Repository $name is checked out at revision "$revision".',
|
'Repository $name is checked out at revision "$revision".',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The URL of the remote named [remoteName].
|
/// The URL of the remote named [remoteName].
|
||||||
String remoteUrl(String remoteName) {
|
Future<String> remoteUrl(String remoteName) async {
|
||||||
assert(remoteName != null);
|
assert(remoteName != null);
|
||||||
return git.getOutput(
|
return git.getOutput(
|
||||||
<String>['remote', 'get-url', remoteName],
|
<String>['remote', 'get-url', remoteName],
|
||||||
'verify the URL of the $remoteName remote',
|
'verify the URL of the $remoteName remote',
|
||||||
workingDirectory: checkoutDirectory.path,
|
workingDirectory: (await checkoutDirectory).path,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Verify the repository's git checkout is clean.
|
/// Verify the repository's git checkout is clean.
|
||||||
bool gitCheckoutClean() {
|
Future<bool> gitCheckoutClean() async {
|
||||||
final String output = git.getOutput(
|
final String output = await git.getOutput(
|
||||||
<String>['status', '--porcelain'],
|
<String>['status', '--porcelain'],
|
||||||
'check that the git checkout is clean',
|
'check that the git checkout is clean',
|
||||||
workingDirectory: checkoutDirectory.path,
|
workingDirectory: (await checkoutDirectory).path,
|
||||||
);
|
);
|
||||||
return output == '';
|
return output == '';
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the revision for the branch point between two refs.
|
/// Return the revision for the branch point between two refs.
|
||||||
String branchPoint(String firstRef, String secondRef) {
|
Future<String> branchPoint(String firstRef, String secondRef) async {
|
||||||
return git.getOutput(
|
return (await git.getOutput(
|
||||||
<String>['merge-base', firstRef, secondRef],
|
<String>['merge-base', firstRef, secondRef],
|
||||||
'determine the merge base between $firstRef and $secondRef',
|
'determine the merge base between $firstRef and $secondRef',
|
||||||
workingDirectory: checkoutDirectory.path,
|
workingDirectory: (await checkoutDirectory).path,
|
||||||
).trim();
|
)).trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fetch all branches and associated commits and tags from [remoteName].
|
/// Fetch all branches and associated commits and tags from [remoteName].
|
||||||
void fetch(String remoteName) {
|
Future<void> fetch(String remoteName) async {
|
||||||
git.run(
|
await git.run(
|
||||||
<String>['fetch', remoteName, '--tags'],
|
<String>['fetch', remoteName, '--tags'],
|
||||||
'fetch $remoteName --tags',
|
'fetch $remoteName --tags',
|
||||||
workingDirectory: checkoutDirectory.path,
|
workingDirectory: (await checkoutDirectory).path,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create (and checkout) a new branch based on the current HEAD.
|
/// Create (and checkout) a new branch based on the current HEAD.
|
||||||
///
|
///
|
||||||
/// Runs `git checkout -b $branchName`.
|
/// Runs `git checkout -b $branchName`.
|
||||||
void newBranch(String branchName) {
|
Future<void> newBranch(String branchName) async {
|
||||||
git.run(
|
await git.run(
|
||||||
<String>['checkout', '-b', branchName],
|
<String>['checkout', '-b', branchName],
|
||||||
'create & checkout new branch $branchName',
|
'create & checkout new branch $branchName',
|
||||||
workingDirectory: checkoutDirectory.path,
|
workingDirectory: (await checkoutDirectory).path,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check out the given ref.
|
/// Check out the given ref.
|
||||||
void checkout(String ref) {
|
Future<void> checkout(String ref) async {
|
||||||
git.run(
|
await git.run(
|
||||||
<String>['checkout', ref],
|
<String>['checkout', ref],
|
||||||
'checkout ref',
|
'checkout ref',
|
||||||
workingDirectory: checkoutDirectory.path,
|
workingDirectory: (await checkoutDirectory).path,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Obtain the version tag at the tip of a release branch.
|
/// Obtain the version tag at the tip of a release branch.
|
||||||
String getFullTag(
|
Future<String> getFullTag(
|
||||||
String remoteName,
|
String remoteName,
|
||||||
String branchName, {
|
String branchName, {
|
||||||
bool exact = true,
|
bool exact = true,
|
||||||
}) {
|
}) async {
|
||||||
// includes both stable (e.g. 1.2.3) and dev tags (e.g. 1.2.3-4.5.pre)
|
// includes both stable (e.g. 1.2.3) and dev tags (e.g. 1.2.3-4.5.pre)
|
||||||
const String glob = '*.*.*';
|
const String glob = '*.*.*';
|
||||||
// describe the latest dev release
|
// describe the latest dev release
|
||||||
@ -260,34 +262,33 @@ abstract class Repository {
|
|||||||
ref,
|
ref,
|
||||||
],
|
],
|
||||||
'obtain last released version number',
|
'obtain last released version number',
|
||||||
workingDirectory: checkoutDirectory.path,
|
workingDirectory: (await checkoutDirectory).path,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// List commits in reverse chronological order.
|
/// List commits in reverse chronological order.
|
||||||
List<String> revList(List<String> args) {
|
Future<List<String>> revList(List<String> args) async {
|
||||||
return git
|
return (await git.getOutput(<String>['rev-list', ...args],
|
||||||
.getOutput(<String>['rev-list', ...args],
|
|
||||||
'rev-list with args ${args.join(' ')}',
|
'rev-list with args ${args.join(' ')}',
|
||||||
workingDirectory: checkoutDirectory.path)
|
workingDirectory: (await checkoutDirectory).path))
|
||||||
.trim()
|
.trim()
|
||||||
.split('\n');
|
.split('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Look up the commit for [ref].
|
/// Look up the commit for [ref].
|
||||||
String reverseParse(String ref) {
|
Future<String> reverseParse(String ref) async {
|
||||||
final String revisionHash = git.getOutput(
|
final String revisionHash = await git.getOutput(
|
||||||
<String>['rev-parse', ref],
|
<String>['rev-parse', ref],
|
||||||
'look up the commit for the ref $ref',
|
'look up the commit for the ref $ref',
|
||||||
workingDirectory: checkoutDirectory.path,
|
workingDirectory: (await checkoutDirectory).path,
|
||||||
);
|
);
|
||||||
assert(revisionHash.isNotEmpty);
|
assert(revisionHash.isNotEmpty);
|
||||||
return revisionHash;
|
return revisionHash;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Determines if one ref is an ancestor for another.
|
/// Determines if one ref is an ancestor for another.
|
||||||
bool isAncestor(String possibleAncestor, String possibleDescendant) {
|
Future<bool> isAncestor(String possibleAncestor, String possibleDescendant) async {
|
||||||
final int exitcode = git.run(
|
final int exitcode = await git.run(
|
||||||
<String>[
|
<String>[
|
||||||
'merge-base',
|
'merge-base',
|
||||||
'--is-ancestor',
|
'--is-ancestor',
|
||||||
@ -296,83 +297,83 @@ abstract class Repository {
|
|||||||
],
|
],
|
||||||
'verify $possibleAncestor is a direct ancestor of $possibleDescendant.',
|
'verify $possibleAncestor is a direct ancestor of $possibleDescendant.',
|
||||||
allowNonZeroExitCode: true,
|
allowNonZeroExitCode: true,
|
||||||
workingDirectory: checkoutDirectory.path,
|
workingDirectory: (await checkoutDirectory).path,
|
||||||
);
|
);
|
||||||
return exitcode == 0;
|
return exitcode == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Determines if a given commit has a tag.
|
/// Determines if a given commit has a tag.
|
||||||
bool isCommitTagged(String commit) {
|
Future<bool> isCommitTagged(String commit) async {
|
||||||
final int exitcode = git.run(
|
final int exitcode = await git.run(
|
||||||
<String>['describe', '--exact-match', '--tags', commit],
|
<String>['describe', '--exact-match', '--tags', commit],
|
||||||
'verify $commit is already tagged',
|
'verify $commit is already tagged',
|
||||||
allowNonZeroExitCode: true,
|
allowNonZeroExitCode: true,
|
||||||
workingDirectory: checkoutDirectory.path,
|
workingDirectory: (await checkoutDirectory).path,
|
||||||
);
|
);
|
||||||
return exitcode == 0;
|
return exitcode == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Determines if a commit will cherry-pick to current HEAD without conflict.
|
/// Determines if a commit will cherry-pick to current HEAD without conflict.
|
||||||
bool canCherryPick(String commit) {
|
Future<bool> canCherryPick(String commit) async {
|
||||||
assert(
|
assert(
|
||||||
gitCheckoutClean(),
|
await gitCheckoutClean(),
|
||||||
'cannot cherry-pick because git checkout ${checkoutDirectory.path} is not clean',
|
'cannot cherry-pick because git checkout ${(await checkoutDirectory).path} is not clean',
|
||||||
);
|
);
|
||||||
|
|
||||||
final int exitcode = git.run(
|
final int exitcode = await git.run(
|
||||||
<String>['cherry-pick', '--no-commit', commit],
|
<String>['cherry-pick', '--no-commit', commit],
|
||||||
'attempt to cherry-pick $commit without committing',
|
'attempt to cherry-pick $commit without committing',
|
||||||
allowNonZeroExitCode: true,
|
allowNonZeroExitCode: true,
|
||||||
workingDirectory: checkoutDirectory.path,
|
workingDirectory: (await checkoutDirectory).path,
|
||||||
);
|
);
|
||||||
|
|
||||||
final bool result = exitcode == 0;
|
final bool result = exitcode == 0;
|
||||||
|
|
||||||
if (result == false) {
|
if (result == false) {
|
||||||
stdio.printError(git.getOutput(
|
stdio.printError(await git.getOutput(
|
||||||
<String>['diff'],
|
<String>['diff'],
|
||||||
'get diff of failed cherry-pick',
|
'get diff of failed cherry-pick',
|
||||||
workingDirectory: checkoutDirectory.path,
|
workingDirectory: (await checkoutDirectory).path,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
reset('HEAD');
|
await reset('HEAD');
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Cherry-pick a [commit] to the current HEAD.
|
/// Cherry-pick a [commit] to the current HEAD.
|
||||||
///
|
///
|
||||||
/// This method will throw a [GitException] if the command fails.
|
/// This method will throw a [GitException] if the command fails.
|
||||||
void cherryPick(String commit) {
|
Future<void> cherryPick(String commit) async {
|
||||||
assert(
|
assert(
|
||||||
gitCheckoutClean(),
|
await gitCheckoutClean(),
|
||||||
'cannot cherry-pick because git checkout ${checkoutDirectory.path} is not clean',
|
'cannot cherry-pick because git checkout ${(await checkoutDirectory).path} is not clean',
|
||||||
);
|
);
|
||||||
|
|
||||||
git.run(
|
await git.run(
|
||||||
<String>['cherry-pick', commit],
|
<String>['cherry-pick', commit],
|
||||||
'cherry-pick $commit',
|
'cherry-pick $commit',
|
||||||
workingDirectory: checkoutDirectory.path,
|
workingDirectory: (await checkoutDirectory).path,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resets repository HEAD to [ref].
|
/// Resets repository HEAD to [ref].
|
||||||
void reset(String ref) {
|
Future<void> reset(String ref) async {
|
||||||
git.run(
|
await git.run(
|
||||||
<String>['reset', ref, '--hard'],
|
<String>['reset', ref, '--hard'],
|
||||||
'reset to $ref',
|
'reset to $ref',
|
||||||
workingDirectory: checkoutDirectory.path,
|
workingDirectory: (await checkoutDirectory).path,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Push [commit] to the release channel [branch].
|
/// Push [commit] to the release channel [branch].
|
||||||
void pushRef({
|
Future<void> pushRef({
|
||||||
required String fromRef,
|
required String fromRef,
|
||||||
required String remote,
|
required String remote,
|
||||||
required String toRef,
|
required String toRef,
|
||||||
bool force = false,
|
bool force = false,
|
||||||
bool dryRun = false,
|
bool dryRun = false,
|
||||||
}) {
|
}) async {
|
||||||
final List<String> args = <String>[
|
final List<String> args = <String>[
|
||||||
'push',
|
'push',
|
||||||
if (force) '--force',
|
if (force) '--force',
|
||||||
@ -386,47 +387,48 @@ abstract class Repository {
|
|||||||
if (dryRun) {
|
if (dryRun) {
|
||||||
stdio.printStatus('About to execute command: `$command`');
|
stdio.printStatus('About to execute command: `$command`');
|
||||||
} else {
|
} else {
|
||||||
git.run(
|
await git.run(
|
||||||
args,
|
args,
|
||||||
'update the release branch with the commit',
|
'update the release branch with the commit',
|
||||||
workingDirectory: checkoutDirectory.path,
|
workingDirectory: (await checkoutDirectory).path,
|
||||||
);
|
);
|
||||||
stdio.printStatus('Executed command: `$command`');
|
stdio.printStatus('Executed command: `$command`');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String commit(
|
Future<String> commit(
|
||||||
String message, {
|
String message, {
|
||||||
bool addFirst = false,
|
bool addFirst = false,
|
||||||
}) {
|
}) async {
|
||||||
assert(!message.contains("'"));
|
assert(!message.contains("'"));
|
||||||
final bool hasChanges = git.getOutput(
|
final bool hasChanges = (await git.getOutput(
|
||||||
<String>['status', '--porcelain'],
|
<String>['status', '--porcelain'],
|
||||||
'check for uncommitted changes',
|
'check for uncommitted changes',
|
||||||
workingDirectory: checkoutDirectory.path,
|
workingDirectory: (await checkoutDirectory).path,
|
||||||
).trim().isNotEmpty;
|
)).trim().isNotEmpty;
|
||||||
if (!hasChanges) {
|
if (!hasChanges) {
|
||||||
throw ConductorException('Tried to commit with message $message but no changes were present');
|
throw ConductorException(
|
||||||
|
'Tried to commit with message $message but no changes were present');
|
||||||
}
|
}
|
||||||
if (addFirst) {
|
if (addFirst) {
|
||||||
git.run(
|
await git.run(
|
||||||
<String>['add', '--all'],
|
<String>['add', '--all'],
|
||||||
'add all changes to the index',
|
'add all changes to the index',
|
||||||
workingDirectory: checkoutDirectory.path,
|
workingDirectory: (await checkoutDirectory).path,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
git.run(
|
await git.run(
|
||||||
<String>['commit', "--message='$message'"],
|
<String>['commit', "--message='$message'"],
|
||||||
'commit changes',
|
'commit changes',
|
||||||
workingDirectory: checkoutDirectory.path,
|
workingDirectory: (await checkoutDirectory).path,
|
||||||
);
|
);
|
||||||
return reverseParse('HEAD');
|
return reverseParse('HEAD');
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create an empty commit and return the revision.
|
/// Create an empty commit and return the revision.
|
||||||
@visibleForTesting
|
@visibleForTesting
|
||||||
String authorEmptyCommit([String message = 'An empty commit']) {
|
Future<String> authorEmptyCommit([String message = 'An empty commit']) async {
|
||||||
git.run(
|
await git.run(
|
||||||
<String>[
|
<String>[
|
||||||
'-c',
|
'-c',
|
||||||
'user.name=Conductor',
|
'user.name=Conductor',
|
||||||
@ -438,7 +440,7 @@ abstract class Repository {
|
|||||||
"'$message'",
|
"'$message'",
|
||||||
],
|
],
|
||||||
'create an empty commit',
|
'create an empty commit',
|
||||||
workingDirectory: checkoutDirectory.path,
|
workingDirectory: (await checkoutDirectory).path,
|
||||||
);
|
);
|
||||||
return reverseParse('HEAD');
|
return reverseParse('HEAD');
|
||||||
}
|
}
|
||||||
@ -450,7 +452,7 @@ abstract class Repository {
|
|||||||
///
|
///
|
||||||
/// This method is for testing purposes.
|
/// This method is for testing purposes.
|
||||||
@visibleForTesting
|
@visibleForTesting
|
||||||
Repository cloneRepository(String cloneName);
|
Future<Repository> cloneRepository(String cloneName);
|
||||||
}
|
}
|
||||||
|
|
||||||
class FrameworkRepository extends Repository {
|
class FrameworkRepository extends Repository {
|
||||||
@ -500,57 +502,66 @@ class FrameworkRepository extends Repository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final Checkouts checkouts;
|
final Checkouts checkouts;
|
||||||
late final CiYaml ciYaml = CiYaml(checkoutDirectory.childFile('.ci.yaml'));
|
|
||||||
static const String defaultUpstream =
|
static const String defaultUpstream =
|
||||||
'https://github.com/flutter/flutter.git';
|
'https://github.com/flutter/flutter.git';
|
||||||
|
|
||||||
static const String defaultBranch = 'master';
|
static const String defaultBranch = 'master';
|
||||||
|
|
||||||
String get cacheDirectory => fileSystem.path.join(
|
Future<CiYaml> get ciYaml async {
|
||||||
checkoutDirectory.path,
|
final CiYaml ciYaml =
|
||||||
|
CiYaml((await checkoutDirectory).childFile('.ci.yaml'));
|
||||||
|
return ciYaml;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<String> get cacheDirectory async {
|
||||||
|
return fileSystem.path.join(
|
||||||
|
(await checkoutDirectory).path,
|
||||||
'bin',
|
'bin',
|
||||||
'cache',
|
'cache',
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/// Tag [commit] and push the tag to the remote.
|
/// Tag [commit] and push the tag to the remote.
|
||||||
void tag(String commit, String tagName, String remote) {
|
Future<void> tag(String commit, String tagName, String remote) async {
|
||||||
assert(commit.isNotEmpty);
|
assert(commit.isNotEmpty);
|
||||||
assert(tagName.isNotEmpty);
|
assert(tagName.isNotEmpty);
|
||||||
assert(remote.isNotEmpty);
|
assert(remote.isNotEmpty);
|
||||||
stdio.printStatus('About to tag commit $commit as $tagName...');
|
stdio.printStatus('About to tag commit $commit as $tagName...');
|
||||||
git.run(
|
await git.run(
|
||||||
<String>['tag', tagName, commit],
|
<String>['tag', tagName, commit],
|
||||||
'tag the commit with the version label',
|
'tag the commit with the version label',
|
||||||
workingDirectory: checkoutDirectory.path,
|
workingDirectory: (await checkoutDirectory).path,
|
||||||
);
|
);
|
||||||
stdio.printStatus('Tagging successful.');
|
stdio.printStatus('Tagging successful.');
|
||||||
stdio.printStatus('About to push $tagName to remote $remote...');
|
stdio.printStatus('About to push $tagName to remote $remote...');
|
||||||
git.run(
|
await git.run(
|
||||||
<String>['push', remote, tagName],
|
<String>['push', remote, tagName],
|
||||||
'publish the tag to the repo',
|
'publish the tag to the repo',
|
||||||
workingDirectory: checkoutDirectory.path,
|
workingDirectory: (await checkoutDirectory).path,
|
||||||
);
|
);
|
||||||
stdio.printStatus('Tag push successful.');
|
stdio.printStatus('Tag push successful.');
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Repository cloneRepository(String? cloneName) {
|
Future<Repository> cloneRepository(String? cloneName) async {
|
||||||
assert(localUpstream);
|
assert(localUpstream);
|
||||||
cloneName ??= 'clone-of-$name';
|
cloneName ??= 'clone-of-$name';
|
||||||
return FrameworkRepository(
|
return FrameworkRepository(
|
||||||
checkouts,
|
checkouts,
|
||||||
name: cloneName,
|
name: cloneName,
|
||||||
upstreamRemote: Remote(
|
upstreamRemote: Remote(
|
||||||
name: RemoteName.upstream, url: 'file://${checkoutDirectory.path}/'),
|
name: RemoteName.upstream,
|
||||||
|
url: 'file://${(await checkoutDirectory).path}/'),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _ensureToolReady() {
|
Future<void> _ensureToolReady() async {
|
||||||
final File toolsStamp =
|
final File toolsStamp = fileSystem
|
||||||
fileSystem.directory(cacheDirectory).childFile('flutter_tools.stamp');
|
.directory(await cacheDirectory)
|
||||||
|
.childFile('flutter_tools.stamp');
|
||||||
if (toolsStamp.existsSync()) {
|
if (toolsStamp.existsSync()) {
|
||||||
final String toolsStampHash = toolsStamp.readAsStringSync().trim();
|
final String toolsStampHash = toolsStamp.readAsStringSync().trim();
|
||||||
final String repoHeadHash = reverseParse('HEAD');
|
final String repoHeadHash = await reverseParse('HEAD');
|
||||||
if (toolsStampHash == repoHeadHash) {
|
if (toolsStampHash == repoHeadHash) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -558,39 +569,38 @@ class FrameworkRepository extends Repository {
|
|||||||
|
|
||||||
stdio.printTrace('Building tool...');
|
stdio.printTrace('Building tool...');
|
||||||
// Build tool
|
// Build tool
|
||||||
processManager.runSync(<String>[
|
await processManager.run(<String>[
|
||||||
fileSystem.path.join(checkoutDirectory.path, 'bin', 'flutter'),
|
fileSystem.path.join((await checkoutDirectory).path, 'bin', 'flutter'),
|
||||||
'help',
|
'help',
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
io.ProcessResult runFlutter(List<String> args) {
|
Future<io.ProcessResult> runFlutter(List<String> args) async {
|
||||||
_ensureToolReady();
|
await _ensureToolReady();
|
||||||
|
return processManager.run(<String>[
|
||||||
return processManager.runSync(<String>[
|
fileSystem.path.join((await checkoutDirectory).path, 'bin', 'flutter'),
|
||||||
fileSystem.path.join(checkoutDirectory.path, 'bin', 'flutter'),
|
|
||||||
...args,
|
...args,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void checkout(String ref) {
|
Future<void> checkout(String ref) async {
|
||||||
super.checkout(ref);
|
await super.checkout(ref);
|
||||||
// The tool will overwrite old cached artifacts, but not delete unused
|
// The tool will overwrite old cached artifacts, but not delete unused
|
||||||
// artifacts from a previous version. Thus, delete the entire cache and
|
// artifacts from a previous version. Thus, delete the entire cache and
|
||||||
// re-populate.
|
// re-populate.
|
||||||
final Directory cache = fileSystem.directory(cacheDirectory);
|
final Directory cache = fileSystem.directory(await cacheDirectory);
|
||||||
if (cache.existsSync()) {
|
if (cache.existsSync()) {
|
||||||
stdio.printTrace('Deleting cache...');
|
stdio.printTrace('Deleting cache...');
|
||||||
cache.deleteSync(recursive: true);
|
cache.deleteSync(recursive: true);
|
||||||
}
|
}
|
||||||
_ensureToolReady();
|
await _ensureToolReady();
|
||||||
}
|
}
|
||||||
|
|
||||||
Version flutterVersion() {
|
Future<Version> flutterVersion() async {
|
||||||
// Check version
|
// Check version
|
||||||
final io.ProcessResult result =
|
final io.ProcessResult result =
|
||||||
runFlutter(<String>['--version', '--machine']);
|
await runFlutter(<String>['--version', '--machine']);
|
||||||
final Map<String, dynamic> versionJson = jsonDecode(
|
final Map<String, dynamic> versionJson = jsonDecode(
|
||||||
stdoutToString(result.stdout),
|
stdoutToString(result.stdout),
|
||||||
) as Map<String, dynamic>;
|
) as Map<String, dynamic>;
|
||||||
@ -600,12 +610,12 @@ class FrameworkRepository extends Repository {
|
|||||||
/// Update this framework's engine version file.
|
/// Update this framework's engine version file.
|
||||||
///
|
///
|
||||||
/// Returns [true] if the version file was updated and a commit is needed.
|
/// Returns [true] if the version file was updated and a commit is needed.
|
||||||
bool updateEngineRevision(
|
Future<bool> updateEngineRevision(
|
||||||
String newEngine, {
|
String newEngine, {
|
||||||
@visibleForTesting File? engineVersionFile,
|
@visibleForTesting File? engineVersionFile,
|
||||||
}) {
|
}) async {
|
||||||
assert(newEngine.isNotEmpty);
|
assert(newEngine.isNotEmpty);
|
||||||
engineVersionFile ??= checkoutDirectory
|
engineVersionFile ??= (await checkoutDirectory)
|
||||||
.childDirectory('bin')
|
.childDirectory('bin')
|
||||||
.childDirectory('internal')
|
.childDirectory('internal')
|
||||||
.childFile('engine.version');
|
.childFile('engine.version');
|
||||||
@ -649,33 +659,33 @@ class HostFrameworkRepository extends FrameworkRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Directory get checkoutDirectory => _checkoutDirectory!;
|
Future<Directory> get checkoutDirectory async => _checkoutDirectory!;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void newBranch(String branchName) {
|
Future<void> newBranch(String branchName) async {
|
||||||
throw ConductorException(
|
throw ConductorException(
|
||||||
'newBranch not implemented for the host repository');
|
'newBranch not implemented for the host repository');
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void checkout(String ref) {
|
Future<void> checkout(String ref) async {
|
||||||
throw ConductorException(
|
throw ConductorException(
|
||||||
'checkout not implemented for the host repository');
|
'checkout not implemented for the host repository');
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String cherryPick(String commit) {
|
Future<String> cherryPick(String commit) async {
|
||||||
throw ConductorException(
|
throw ConductorException(
|
||||||
'cherryPick not implemented for the host repository');
|
'cherryPick not implemented for the host repository');
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String reset(String ref) {
|
Future<String> reset(String ref) async {
|
||||||
throw ConductorException('reset not implemented for the host repository');
|
throw ConductorException('reset not implemented for the host repository');
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void tag(String commit, String tagName, String remote) {
|
Future<void> tag(String commit, String tagName, String remote) async {
|
||||||
throw ConductorException('tag not implemented for the host repository');
|
throw ConductorException('tag not implemented for the host repository');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -691,7 +701,7 @@ class HostFrameworkRepository extends FrameworkRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String authorEmptyCommit([String message = 'An empty commit']) {
|
Future<String> authorEmptyCommit([String message = 'An empty commit']) async {
|
||||||
throw ConductorException(
|
throw ConductorException(
|
||||||
'authorEmptyCommit not implemented for the host repository',
|
'authorEmptyCommit not implemented for the host repository',
|
||||||
);
|
);
|
||||||
@ -724,18 +734,21 @@ class EngineRepository extends Repository {
|
|||||||
|
|
||||||
final Checkouts checkouts;
|
final Checkouts checkouts;
|
||||||
|
|
||||||
late final CiYaml ciYaml = CiYaml(checkoutDirectory.childFile('.ci.yaml'));
|
Future<CiYaml> get ciYaml async {
|
||||||
|
final CiYaml ciYaml = CiYaml((await checkoutDirectory).childFile('.ci.yaml'));
|
||||||
|
return ciYaml;
|
||||||
|
}
|
||||||
|
|
||||||
static const String defaultUpstream = 'https://github.com/flutter/engine.git';
|
static const String defaultUpstream = 'https://github.com/flutter/engine.git';
|
||||||
static const String defaultBranch = 'master';
|
static const String defaultBranch = 'master';
|
||||||
|
|
||||||
/// Update the `dart_revision` entry in the DEPS file.
|
/// Update the `dart_revision` entry in the DEPS file.
|
||||||
void updateDartRevision(
|
Future<void> updateDartRevision(
|
||||||
String newRevision, {
|
String newRevision, {
|
||||||
@visibleForTesting File? depsFile,
|
@visibleForTesting File? depsFile,
|
||||||
}) {
|
}) async {
|
||||||
assert(newRevision.length == 40);
|
assert(newRevision.length == 40);
|
||||||
depsFile ??= checkoutDirectory.childFile('DEPS');
|
depsFile ??= (await checkoutDirectory).childFile('DEPS');
|
||||||
final String fileContent = depsFile.readAsStringSync();
|
final String fileContent = depsFile.readAsStringSync();
|
||||||
final RegExp dartPattern = RegExp("[ ]+'dart_revision': '([a-z0-9]{40})',");
|
final RegExp dartPattern = RegExp("[ ]+'dart_revision': '([a-z0-9]{40})',");
|
||||||
final Iterable<RegExpMatch> allMatches =
|
final Iterable<RegExpMatch> allMatches =
|
||||||
@ -755,14 +768,15 @@ class EngineRepository extends Repository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Repository cloneRepository(String? cloneName) {
|
Future<Repository> cloneRepository(String? cloneName) async {
|
||||||
assert(localUpstream);
|
assert(localUpstream);
|
||||||
cloneName ??= 'clone-of-$name';
|
cloneName ??= 'clone-of-$name';
|
||||||
return EngineRepository(
|
return EngineRepository(
|
||||||
checkouts,
|
checkouts,
|
||||||
name: cloneName,
|
name: cloneName,
|
||||||
upstreamRemote: Remote(
|
upstreamRemote: Remote(
|
||||||
name: RemoteName.upstream, url: 'file://${checkoutDirectory.path}/'),
|
name: RemoteName.upstream,
|
||||||
|
url: 'file://${(await checkoutDirectory).path}/'),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -90,8 +90,8 @@ class RollDevCommand extends Command<void> {
|
|||||||
'For publishing a dev release without cherry picks.';
|
'For publishing a dev release without cherry picks.';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void run() {
|
Future<void> run() async {
|
||||||
rollDev(
|
await rollDev(
|
||||||
argResults: argResults!,
|
argResults: argResults!,
|
||||||
repository: FrameworkRepository(checkouts),
|
repository: FrameworkRepository(checkouts),
|
||||||
stdio: stdio,
|
stdio: stdio,
|
||||||
@ -104,12 +104,12 @@ class RollDevCommand extends Command<void> {
|
|||||||
///
|
///
|
||||||
/// Returns true if publishing was successful, else false.
|
/// Returns true if publishing was successful, else false.
|
||||||
@visibleForTesting
|
@visibleForTesting
|
||||||
bool rollDev({
|
Future<bool> rollDev({
|
||||||
required String usage,
|
required String usage,
|
||||||
required ArgResults argResults,
|
required ArgResults argResults,
|
||||||
required Stdio stdio,
|
required Stdio stdio,
|
||||||
required FrameworkRepository repository,
|
required FrameworkRepository repository,
|
||||||
}) {
|
}) async {
|
||||||
final String remoteName = argResults[kRemoteName] as String;
|
final String remoteName = argResults[kRemoteName] as String;
|
||||||
final String? level = argResults[kIncrement] as String?;
|
final String? level = argResults[kIncrement] as String?;
|
||||||
final String candidateBranch = argResults[kCandidateBranch] as String;
|
final String candidateBranch = argResults[kCandidateBranch] as String;
|
||||||
@ -124,30 +124,30 @@ bool rollDev({
|
|||||||
'and roll a new dev build.\n$usage');
|
'and roll a new dev build.\n$usage');
|
||||||
}
|
}
|
||||||
|
|
||||||
final String remoteUrl = repository.remoteUrl(remoteName);
|
final String remoteUrl = await repository.remoteUrl(remoteName);
|
||||||
|
|
||||||
if (!repository.gitCheckoutClean()) {
|
if (!(await repository.gitCheckoutClean())) {
|
||||||
throw Exception(
|
throw Exception(
|
||||||
'Your git repository is not clean. Try running "git clean -fd". Warning, '
|
'Your git repository is not clean. Try running "git clean -fd". Warning, '
|
||||||
'this will delete files! Run with -n to find out which ones.');
|
'this will delete files! Run with -n to find out which ones.');
|
||||||
}
|
}
|
||||||
|
|
||||||
repository.fetch(remoteName);
|
await repository.fetch(remoteName);
|
||||||
|
|
||||||
// Verify [commit] is valid
|
// Verify [commit] is valid
|
||||||
final String commit = repository.reverseParse(candidateBranch);
|
final String commit = await repository.reverseParse(candidateBranch);
|
||||||
|
|
||||||
stdio.printStatus('remoteName is $remoteName');
|
stdio.printStatus('remoteName is $remoteName');
|
||||||
// Get the name of the last dev release
|
// Get the name of the last dev release
|
||||||
final Version lastVersion = Version.fromString(
|
final Version lastVersion = Version.fromString(
|
||||||
repository.getFullTag(remoteName, 'dev'),
|
await repository.getFullTag(remoteName, 'dev'),
|
||||||
);
|
);
|
||||||
|
|
||||||
final Version version =
|
final Version version =
|
||||||
skipTagging ? lastVersion : Version.fromCandidateBranch(candidateBranch);
|
skipTagging ? lastVersion : Version.fromCandidateBranch(candidateBranch);
|
||||||
final String tagName = version.toString();
|
final String tagName = version.toString();
|
||||||
|
|
||||||
if (repository.reverseParse(lastVersion.toString()).contains(commit.trim())) {
|
if ((await repository.reverseParse(lastVersion.toString())).contains(commit.trim())) {
|
||||||
throw Exception(
|
throw Exception(
|
||||||
'Commit $commit is already on the dev branch as $lastVersion.');
|
'Commit $commit is already on the dev branch as $lastVersion.');
|
||||||
}
|
}
|
||||||
@ -157,18 +157,18 @@ bool rollDev({
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (skipTagging && !repository.isCommitTagged(commit)) {
|
if (skipTagging && !(await repository.isCommitTagged(commit))) {
|
||||||
throw Exception(
|
throw Exception(
|
||||||
'The $kSkipTagging flag is only supported for tagged commits.');
|
'The $kSkipTagging flag is only supported for tagged commits.');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!force && !repository.isAncestor(commit, lastVersion.toString())) {
|
if (!force && !(await repository.isAncestor(commit, lastVersion.toString()))) {
|
||||||
throw Exception(
|
throw Exception(
|
||||||
'The previous dev tag $lastVersion is not a direct ancestor of $commit.\n'
|
'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.');
|
'The flag "$kForce" is required to force push a new release past a cherry-pick.');
|
||||||
}
|
}
|
||||||
|
|
||||||
final String hash = repository.reverseParse(commit);
|
final String hash = await repository.reverseParse(commit);
|
||||||
|
|
||||||
// [commit] can be a prefix for [hash].
|
// [commit] can be a prefix for [hash].
|
||||||
assert(hash.startsWith(commit));
|
assert(hash.startsWith(commit));
|
||||||
@ -188,10 +188,10 @@ bool rollDev({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!skipTagging) {
|
if (!skipTagging) {
|
||||||
repository.tag(commit, version.toString(), remoteName);
|
await repository.tag(commit, version.toString(), remoteName);
|
||||||
}
|
}
|
||||||
|
|
||||||
repository.pushRef(
|
await repository.pushRef(
|
||||||
fromRef: commit,
|
fromRef: commit,
|
||||||
remote: remoteName,
|
remote: remoteName,
|
||||||
toRef: 'dev',
|
toRef: 'dev',
|
||||||
|
@ -101,14 +101,6 @@ class StartCommand extends Command<void> {
|
|||||||
'n': 'Indicates a hotfix to a dev or beta release.',
|
'n': 'Indicates a hotfix to a dev or beta release.',
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
final Git git = Git(processManager);
|
|
||||||
conductorVersion = git.getOutput(
|
|
||||||
<String>['rev-parse', 'HEAD'],
|
|
||||||
'look up the current revision.',
|
|
||||||
workingDirectory: flutterRoot.path,
|
|
||||||
).trim();
|
|
||||||
|
|
||||||
assert(conductorVersion.isNotEmpty);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final Checkouts checkouts;
|
final Checkouts checkouts;
|
||||||
@ -132,7 +124,15 @@ class StartCommand extends Command<void> {
|
|||||||
String get description => 'Initialize a new Flutter release.';
|
String get description => 'Initialize a new Flutter release.';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void run() {
|
Future<void> run() async {
|
||||||
|
final Git git = Git(processManager);
|
||||||
|
conductorVersion = (await git.getOutput(
|
||||||
|
<String>['rev-parse', 'HEAD'],
|
||||||
|
'look up the current revision.',
|
||||||
|
workingDirectory: flutterRoot.path,
|
||||||
|
)).trim();
|
||||||
|
|
||||||
|
assert(conductorVersion.isNotEmpty);
|
||||||
final ArgResults argumentResults = argResults!;
|
final ArgResults argumentResults = argResults!;
|
||||||
if (!platform.isMacOS && !platform.isLinux) {
|
if (!platform.isMacOS && !platform.isLinux) {
|
||||||
throw ConductorException(
|
throw ConductorException(
|
||||||
@ -231,42 +231,42 @@ class StartCommand extends Command<void> {
|
|||||||
// 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';
|
||||||
engine.newBranch(workingBranchName);
|
await engine.newBranch(workingBranchName);
|
||||||
|
|
||||||
if (dartRevision != null && dartRevision.isNotEmpty) {
|
if (dartRevision != null && dartRevision.isNotEmpty) {
|
||||||
engine.updateDartRevision(dartRevision);
|
await engine.updateDartRevision(dartRevision);
|
||||||
engine.commit('Update Dart SDK to $dartRevision', addFirst: true);
|
await engine.commit('Update Dart SDK to $dartRevision', addFirst: true);
|
||||||
}
|
}
|
||||||
final List<pb.Cherrypick> engineCherrypicks = _sortCherrypicks(
|
final List<pb.Cherrypick> engineCherrypicks = (await _sortCherrypicks(
|
||||||
repository: engine,
|
repository: engine,
|
||||||
cherrypicks: engineCherrypickRevisions,
|
cherrypicks: engineCherrypickRevisions,
|
||||||
upstreamRef: EngineRepository.defaultBranch,
|
upstreamRef: EngineRepository.defaultBranch,
|
||||||
releaseRef: candidateBranch,
|
releaseRef: candidateBranch,
|
||||||
).map((String revision) => pb.Cherrypick(
|
)).map((String revision) => pb.Cherrypick(
|
||||||
trunkRevision: revision,
|
trunkRevision: revision,
|
||||||
state: pb.CherrypickState.PENDING,
|
state: pb.CherrypickState.PENDING,
|
||||||
)).toList();
|
)).toList();
|
||||||
|
|
||||||
for (final pb.Cherrypick cherrypick in engineCherrypicks) {
|
for (final pb.Cherrypick cherrypick in engineCherrypicks) {
|
||||||
final String revision = cherrypick.trunkRevision;
|
final String revision = cherrypick.trunkRevision;
|
||||||
final bool success = engine.canCherryPick(revision);
|
final bool success = await engine.canCherryPick(revision);
|
||||||
stdio.printTrace(
|
stdio.printTrace(
|
||||||
'Attempt to cherrypick $revision ${success ? 'succeeded' : 'failed'}',
|
'Attempt to cherrypick $revision ${success ? 'succeeded' : 'failed'}',
|
||||||
);
|
);
|
||||||
if (success) {
|
if (success) {
|
||||||
engine.cherryPick(revision);
|
await engine.cherryPick(revision);
|
||||||
cherrypick.state = pb.CherrypickState.COMPLETED;
|
cherrypick.state = pb.CherrypickState.COMPLETED;
|
||||||
} else {
|
} else {
|
||||||
cherrypick.state = pb.CherrypickState.PENDING_WITH_CONFLICT;
|
cherrypick.state = pb.CherrypickState.PENDING_WITH_CONFLICT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
final String engineHead = engine.reverseParse('HEAD');
|
final String engineHead = await engine.reverseParse('HEAD');
|
||||||
state.engine = pb.Repository(
|
state.engine = pb.Repository(
|
||||||
candidateBranch: candidateBranch,
|
candidateBranch: candidateBranch,
|
||||||
workingBranch: workingBranchName,
|
workingBranch: workingBranchName,
|
||||||
startingGitHead: engineHead,
|
startingGitHead: engineHead,
|
||||||
currentGitHead: engineHead,
|
currentGitHead: engineHead,
|
||||||
checkoutPath: engine.checkoutDirectory.path,
|
checkoutPath: (await engine.checkoutDirectory).path,
|
||||||
cherrypicks: engineCherrypicks,
|
cherrypicks: engineCherrypicks,
|
||||||
dartRevision: dartRevision,
|
dartRevision: dartRevision,
|
||||||
upstream: pb.Remote(name: 'upstream', url: engine.upstreamRemote.url),
|
upstream: pb.Remote(name: 'upstream', url: engine.upstreamRemote.url),
|
||||||
@ -284,25 +284,25 @@ class StartCommand extends Command<void> {
|
|||||||
url: frameworkMirror,
|
url: frameworkMirror,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
framework.newBranch(workingBranchName);
|
await framework.newBranch(workingBranchName);
|
||||||
final List<pb.Cherrypick> frameworkCherrypicks = _sortCherrypicks(
|
final List<pb.Cherrypick> frameworkCherrypicks = (await _sortCherrypicks(
|
||||||
repository: framework,
|
repository: framework,
|
||||||
cherrypicks: frameworkCherrypickRevisions,
|
cherrypicks: frameworkCherrypickRevisions,
|
||||||
upstreamRef: FrameworkRepository.defaultBranch,
|
upstreamRef: FrameworkRepository.defaultBranch,
|
||||||
releaseRef: candidateBranch,
|
releaseRef: candidateBranch,
|
||||||
).map((String revision) => pb.Cherrypick(
|
)).map((String revision) => pb.Cherrypick(
|
||||||
trunkRevision: revision,
|
trunkRevision: revision,
|
||||||
state: pb.CherrypickState.PENDING,
|
state: pb.CherrypickState.PENDING,
|
||||||
)).toList();
|
)).toList();
|
||||||
|
|
||||||
for (final pb.Cherrypick cherrypick in frameworkCherrypicks) {
|
for (final pb.Cherrypick cherrypick in frameworkCherrypicks) {
|
||||||
final String revision = cherrypick.trunkRevision;
|
final String revision = cherrypick.trunkRevision;
|
||||||
final bool success = framework.canCherryPick(revision);
|
final bool success = await framework.canCherryPick(revision);
|
||||||
stdio.printTrace(
|
stdio.printTrace(
|
||||||
'Attempt to cherrypick $cherrypick ${success ? 'succeeded' : 'failed'}',
|
'Attempt to cherrypick $cherrypick ${success ? 'succeeded' : 'failed'}',
|
||||||
);
|
);
|
||||||
if (success) {
|
if (success) {
|
||||||
framework.cherryPick(revision);
|
await framework.cherryPick(revision);
|
||||||
cherrypick.state = pb.CherrypickState.COMPLETED;
|
cherrypick.state = pb.CherrypickState.COMPLETED;
|
||||||
} else {
|
} else {
|
||||||
cherrypick.state = pb.CherrypickState.PENDING_WITH_CONFLICT;
|
cherrypick.state = pb.CherrypickState.PENDING_WITH_CONFLICT;
|
||||||
@ -310,7 +310,9 @@ class StartCommand extends Command<void> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get framework version
|
// Get framework version
|
||||||
final Version lastVersion = Version.fromString(framework.getFullTag(framework.upstreamRemote.name, candidateBranch, exact: false));
|
final Version lastVersion = Version.fromString(await framework.getFullTag(
|
||||||
|
framework.upstreamRemote.name, candidateBranch,
|
||||||
|
exact: false));
|
||||||
Version nextVersion;
|
Version nextVersion;
|
||||||
if (incrementLetter == 'm') {
|
if (incrementLetter == 'm') {
|
||||||
nextVersion = Version.fromCandidateBranch(candidateBranch);
|
nextVersion = Version.fromCandidateBranch(candidateBranch);
|
||||||
@ -333,13 +335,13 @@ class StartCommand extends Command<void> {
|
|||||||
}
|
}
|
||||||
state.releaseVersion = nextVersion.toString();
|
state.releaseVersion = nextVersion.toString();
|
||||||
|
|
||||||
final String frameworkHead = framework.reverseParse('HEAD');
|
final String frameworkHead = await framework.reverseParse('HEAD');
|
||||||
state.framework = pb.Repository(
|
state.framework = pb.Repository(
|
||||||
candidateBranch: candidateBranch,
|
candidateBranch: candidateBranch,
|
||||||
workingBranch: workingBranchName,
|
workingBranch: workingBranchName,
|
||||||
startingGitHead: frameworkHead,
|
startingGitHead: frameworkHead,
|
||||||
currentGitHead: frameworkHead,
|
currentGitHead: frameworkHead,
|
||||||
checkoutPath: framework.checkoutDirectory.path,
|
checkoutPath: (await framework.checkoutDirectory).path,
|
||||||
cherrypicks: frameworkCherrypicks,
|
cherrypicks: frameworkCherrypicks,
|
||||||
upstream: pb.Remote(name: 'upstream', url: framework.upstreamRemote.url),
|
upstream: pb.Remote(name: 'upstream', url: framework.upstreamRemote.url),
|
||||||
mirror: pb.Remote(name: 'mirror', url: framework.mirrorRemote!.url),
|
mirror: pb.Remote(name: 'mirror', url: framework.mirrorRemote!.url),
|
||||||
@ -357,12 +359,12 @@ class StartCommand extends Command<void> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// To minimize merge conflicts, sort the commits by rev-list order.
|
// To minimize merge conflicts, sort the commits by rev-list order.
|
||||||
List<String> _sortCherrypicks({
|
Future<List<String>> _sortCherrypicks({
|
||||||
required Repository repository,
|
required Repository repository,
|
||||||
required List<String> cherrypicks,
|
required List<String> cherrypicks,
|
||||||
required String upstreamRef,
|
required String upstreamRef,
|
||||||
required String releaseRef,
|
required String releaseRef,
|
||||||
}) {
|
}) async {
|
||||||
if (cherrypicks.isEmpty) {
|
if (cherrypicks.isEmpty) {
|
||||||
return cherrypicks;
|
return cherrypicks;
|
||||||
}
|
}
|
||||||
@ -375,7 +377,7 @@ class StartCommand extends Command<void> {
|
|||||||
final List<String> sortedCherrypicks = <String>[];
|
final List<String> sortedCherrypicks = <String>[];
|
||||||
for (final String cherrypick in cherrypicks) {
|
for (final String cherrypick in cherrypicks) {
|
||||||
try {
|
try {
|
||||||
final String fullRef = repository.reverseParse(cherrypick);
|
final String fullRef = await repository.reverseParse(cherrypick);
|
||||||
validatedCherrypicks.add(fullRef);
|
validatedCherrypicks.add(fullRef);
|
||||||
} on GitException {
|
} on GitException {
|
||||||
// Catch this exception so that we can validate the rest.
|
// Catch this exception so that we can validate the rest.
|
||||||
@ -383,16 +385,16 @@ class StartCommand extends Command<void> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final String branchPoint = repository.branchPoint(
|
final String branchPoint = await repository.branchPoint(
|
||||||
'${repository.upstreamRemote.name}/$upstreamRef',
|
'${repository.upstreamRemote.name}/$upstreamRef',
|
||||||
'${repository.upstreamRemote.name}/$releaseRef',
|
'${repository.upstreamRemote.name}/$releaseRef',
|
||||||
);
|
);
|
||||||
|
|
||||||
// `git rev-list` returns newest first, so reverse this list
|
// `git rev-list` returns newest first, so reverse this list
|
||||||
final List<String> upstreamRevlist = repository.revList(<String>[
|
final List<String> upstreamRevlist = (await repository.revList(<String>[
|
||||||
'--ancestry-path',
|
'--ancestry-path',
|
||||||
'$branchPoint..$upstreamRef',
|
'$branchPoint..$upstreamRef',
|
||||||
]).reversed.toList();
|
])).reversed.toList();
|
||||||
|
|
||||||
stdio.printStatus('upstreamRevList:\n${upstreamRevlist.join('\n')}\n');
|
stdio.printStatus('upstreamRevList:\n${upstreamRevlist.join('\n')}\n');
|
||||||
stdio.printStatus('validatedCherrypicks:\n${validatedCherrypicks.join('\n')}\n');
|
stdio.printStatus('validatedCherrypicks:\n${validatedCherrypicks.join('\n')}\n');
|
||||||
|
@ -56,8 +56,8 @@ void main() {
|
|||||||
);
|
);
|
||||||
final FakeCodesignCommand command = FakeCodesignCommand(
|
final FakeCodesignCommand command = FakeCodesignCommand(
|
||||||
checkouts: checkouts,
|
checkouts: checkouts,
|
||||||
binariesWithEntitlements: binariesWithEntitlements,
|
binariesWithEntitlements: Future<List<String>>.value(binariesWithEntitlements),
|
||||||
binariesWithoutEntitlements: binariesWithoutEntitlements,
|
binariesWithoutEntitlements: Future<List<String>>.value(binariesWithoutEntitlements),
|
||||||
flutterRoot: fileSystem.directory(flutterRoot),
|
flutterRoot: fileSystem.directory(flutterRoot),
|
||||||
);
|
);
|
||||||
runner = CommandRunner<void>('codesign-test', '')
|
runner = CommandRunner<void>('codesign-test', '')
|
||||||
@ -326,8 +326,8 @@ void main() {
|
|||||||
),
|
),
|
||||||
...codesignCheckCommands,
|
...codesignCheckCommands,
|
||||||
]);
|
]);
|
||||||
expect(
|
await expectLater(
|
||||||
() async => runner.run(<String>['codesign', '--$kVerify', '--$kRevision', revision]),
|
() => runner.run(<String>['codesign', '--$kVerify', '--$kRevision', revision]),
|
||||||
throwsExceptionWith('Test failed because unsigned binaries detected.'),
|
throwsExceptionWith('Test failed because unsigned binaries detected.'),
|
||||||
);
|
);
|
||||||
expect(processManager.hasRemainingExpectations, false);
|
expect(processManager.hasRemainingExpectations, false);
|
||||||
@ -413,8 +413,8 @@ void main() {
|
|||||||
),
|
),
|
||||||
...codesignCheckCommands,
|
...codesignCheckCommands,
|
||||||
]);
|
]);
|
||||||
expect(
|
await expectLater(
|
||||||
() async => runner.run(<String>['codesign', '--$kVerify', '--$kRevision', revision]),
|
() => runner.run(<String>['codesign', '--$kVerify', '--$kRevision', revision]),
|
||||||
throwsExceptionWith('Test failed because files found with the wrong entitlements'),
|
throwsExceptionWith('Test failed because files found with the wrong entitlements'),
|
||||||
);
|
);
|
||||||
expect(processManager.hasRemainingExpectations, false);
|
expect(processManager.hasRemainingExpectations, false);
|
||||||
@ -495,8 +495,8 @@ class FakeCodesignCommand extends CodesignCommand {
|
|||||||
}) : super(checkouts: checkouts, flutterRoot: flutterRoot);
|
}) : super(checkouts: checkouts, flutterRoot: flutterRoot);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
final List<String> binariesWithEntitlements;
|
final Future<List<String>> binariesWithEntitlements;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
final List<String> binariesWithoutEntitlements;
|
final Future<List<String>> binariesWithoutEntitlements;
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ void main() {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('canCherryPick returns true if git cherry-pick returns 0', () {
|
test('canCherryPick returns true if git cherry-pick returns 0', () async {
|
||||||
const String commit = 'abc123';
|
const String commit = 'abc123';
|
||||||
|
|
||||||
final TestStdio stdio = TestStdio();
|
final TestStdio stdio = TestStdio();
|
||||||
@ -73,10 +73,10 @@ void main() {
|
|||||||
stdio: stdio,
|
stdio: stdio,
|
||||||
);
|
);
|
||||||
final Repository repository = FrameworkRepository(checkouts);
|
final Repository repository = FrameworkRepository(checkouts);
|
||||||
expect(repository.canCherryPick(commit), true);
|
expect(await repository.canCherryPick(commit), true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('canCherryPick returns false if git cherry-pick returns non-zero', () {
|
test('canCherryPick returns false if git cherry-pick returns non-zero', () async {
|
||||||
const String commit = 'abc123';
|
const String commit = 'abc123';
|
||||||
|
|
||||||
final TestStdio stdio = TestStdio();
|
final TestStdio stdio = TestStdio();
|
||||||
@ -128,10 +128,10 @@ void main() {
|
|||||||
stdio: stdio,
|
stdio: stdio,
|
||||||
);
|
);
|
||||||
final Repository repository = FrameworkRepository(checkouts);
|
final Repository repository = FrameworkRepository(checkouts);
|
||||||
expect(repository.canCherryPick(commit), false);
|
expect(await repository.canCherryPick(commit), false);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('cherryPick() applies the commit', () {
|
test('cherryPick() applies the commit', () async {
|
||||||
const String commit = 'abc123';
|
const String commit = 'abc123';
|
||||||
|
|
||||||
final TestStdio stdio = TestStdio();
|
final TestStdio stdio = TestStdio();
|
||||||
@ -172,11 +172,11 @@ void main() {
|
|||||||
stdio: stdio,
|
stdio: stdio,
|
||||||
);
|
);
|
||||||
final Repository repository = FrameworkRepository(checkouts);
|
final Repository repository = FrameworkRepository(checkouts);
|
||||||
repository.cherryPick(commit);
|
await repository.cherryPick(commit);
|
||||||
expect(processManager.hasRemainingExpectations, false);
|
expect(processManager.hasRemainingExpectations, false);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('updateDartRevision() updates the DEPS file', () {
|
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 TestStdio stdio = TestStdio();
|
||||||
@ -194,7 +194,7 @@ void main() {
|
|||||||
final EngineRepository repo = EngineRepository(checkouts);
|
final EngineRepository repo = EngineRepository(checkouts);
|
||||||
final File depsFile = fileSystem.file('/DEPS');
|
final File depsFile = fileSystem.file('/DEPS');
|
||||||
depsFile.writeAsStringSync(generateMockDeps(previousDartRevision));
|
depsFile.writeAsStringSync(generateMockDeps(previousDartRevision));
|
||||||
repo.updateDartRevision(nextDartRevision, depsFile: depsFile);
|
await repo.updateDartRevision(nextDartRevision, depsFile: depsFile);
|
||||||
final String updatedDepsFileContent = depsFile.readAsStringSync();
|
final String updatedDepsFileContent = depsFile.readAsStringSync();
|
||||||
expect(updatedDepsFileContent, generateMockDeps(nextDartRevision));
|
expect(updatedDepsFileContent, generateMockDeps(nextDartRevision));
|
||||||
});
|
});
|
||||||
@ -219,7 +219,7 @@ void main() {
|
|||||||
vars = {
|
vars = {
|
||||||
}''');
|
}''');
|
||||||
expect(
|
expect(
|
||||||
() => repo.updateDartRevision(nextDartRevision, depsFile: depsFile),
|
() async => repo.updateDartRevision(nextDartRevision, depsFile: depsFile),
|
||||||
throwsExceptionWith('Unexpected content in the DEPS file at'),
|
throwsExceptionWith('Unexpected content in the DEPS file at'),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -278,7 +278,7 @@ vars = {
|
|||||||
|
|
||||||
final EngineRepository repo = EngineRepository(checkouts);
|
final EngineRepository repo = EngineRepository(checkouts);
|
||||||
expect(
|
expect(
|
||||||
() => 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'),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -338,7 +338,7 @@ vars = {
|
|||||||
repo.commit(message);
|
repo.commit(message);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('updateEngineRevision() returns false if newCommit is the same as version file', () {
|
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 TestStdio stdio = TestStdio();
|
||||||
@ -371,7 +371,7 @@ vars = {
|
|||||||
);
|
);
|
||||||
|
|
||||||
final FrameworkRepository repo = FrameworkRepository(checkouts);
|
final FrameworkRepository repo = FrameworkRepository(checkouts);
|
||||||
final bool didUpdate = repo.updateEngineRevision(commit2, engineVersionFile: engineVersionFile);
|
final bool didUpdate = await repo.updateEngineRevision(commit2, engineVersionFile: engineVersionFile);
|
||||||
expect(didUpdate, false);
|
expect(didUpdate, false);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -385,7 +385,7 @@ vars = {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('ciYaml.enableBranch() will prepend the given branch to the yaml list of enabled_branches', () {
|
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 TestStdio stdio = TestStdio();
|
||||||
final MemoryFileSystem fileSystem = MemoryFileSystem.test();
|
final MemoryFileSystem fileSystem = MemoryFileSystem.test();
|
||||||
@ -430,18 +430,18 @@ enabled_branches:
|
|||||||
|
|
||||||
final FrameworkRepository framework = FrameworkRepository(checkouts);
|
final FrameworkRepository framework = FrameworkRepository(checkouts);
|
||||||
expect(
|
expect(
|
||||||
framework.ciYaml.enabledBranches,
|
(await framework.ciYaml).enabledBranches,
|
||||||
<String>['master', 'dev', 'beta', 'stable'],
|
<String>['master', 'dev', 'beta', 'stable'],
|
||||||
);
|
);
|
||||||
|
|
||||||
framework.ciYaml.enableBranch('foo');
|
(await framework.ciYaml).enableBranch('foo');
|
||||||
expect(
|
expect(
|
||||||
framework.ciYaml.enabledBranches,
|
(await framework.ciYaml).enabledBranches,
|
||||||
<String>['foo', 'master', 'dev', 'beta', 'stable'],
|
<String>['foo', 'master', 'dev', 'beta', 'stable'],
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
framework.ciYaml.stringContents,
|
(await framework.ciYaml).stringContents,
|
||||||
'''
|
'''
|
||||||
# Friendly note
|
# Friendly note
|
||||||
|
|
||||||
@ -498,7 +498,7 @@ enabled_branches:
|
|||||||
|
|
||||||
final FrameworkRepository framework = FrameworkRepository(checkouts);
|
final FrameworkRepository framework = FrameworkRepository(checkouts);
|
||||||
expect(
|
expect(
|
||||||
() => framework.ciYaml.enableBranch('master'),
|
() async => (await framework.ciYaml).enableBranch('master'),
|
||||||
throwsExceptionWith('.ci.yaml already contains the branch master'),
|
throwsExceptionWith('.ci.yaml already contains the branch master'),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -51,7 +51,7 @@ void main() {
|
|||||||
remote: remote,
|
remote: remote,
|
||||||
);
|
);
|
||||||
expect(
|
expect(
|
||||||
() => rollDev(
|
() async => rollDev(
|
||||||
argResults: fakeArgResults,
|
argResults: fakeArgResults,
|
||||||
repository: repo,
|
repository: repo,
|
||||||
stdio: stdio,
|
stdio: stdio,
|
||||||
@ -95,7 +95,7 @@ void main() {
|
|||||||
remote: remote,
|
remote: remote,
|
||||||
);
|
);
|
||||||
expect(
|
expect(
|
||||||
() => rollDev(
|
() async => rollDev(
|
||||||
argResults: fakeArgResults,
|
argResults: fakeArgResults,
|
||||||
repository: repo,
|
repository: repo,
|
||||||
stdio: stdio,
|
stdio: stdio,
|
||||||
@ -105,7 +105,7 @@ void main() {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('does not reset or tag if --just-print is specified', () {
|
test('does not reset or tag if --just-print is specified', () async {
|
||||||
processManager.addCommands(<FakeCommand>[
|
processManager.addCommands(<FakeCommand>[
|
||||||
const FakeCommand(command: <String>[
|
const FakeCommand(command: <String>[
|
||||||
'git',
|
'git',
|
||||||
@ -166,7 +166,7 @@ void main() {
|
|||||||
justPrint: true,
|
justPrint: true,
|
||||||
);
|
);
|
||||||
expect(
|
expect(
|
||||||
rollDev(
|
await rollDev(
|
||||||
usage: usage,
|
usage: usage,
|
||||||
argResults: fakeArgResults,
|
argResults: fakeArgResults,
|
||||||
repository: repo,
|
repository: repo,
|
||||||
@ -249,7 +249,7 @@ void main() {
|
|||||||
skipTagging: true,
|
skipTagging: true,
|
||||||
);
|
);
|
||||||
expect(
|
expect(
|
||||||
() => rollDev(
|
() async => rollDev(
|
||||||
usage: usage,
|
usage: usage,
|
||||||
argResults: fakeArgResults,
|
argResults: fakeArgResults,
|
||||||
repository: repo,
|
repository: repo,
|
||||||
@ -320,7 +320,7 @@ void main() {
|
|||||||
justPrint: true,
|
justPrint: true,
|
||||||
);
|
);
|
||||||
expect(
|
expect(
|
||||||
() => rollDev(
|
() async => rollDev(
|
||||||
usage: usage,
|
usage: usage,
|
||||||
argResults: fakeArgResults,
|
argResults: fakeArgResults,
|
||||||
repository: repo,
|
repository: repo,
|
||||||
@ -403,7 +403,7 @@ void main() {
|
|||||||
const String errorMessage = 'The previous dev tag $lastVersion is not a '
|
const String errorMessage = 'The previous dev tag $lastVersion is not a '
|
||||||
'direct ancestor of $commit.';
|
'direct ancestor of $commit.';
|
||||||
expect(
|
expect(
|
||||||
() => rollDev(
|
() async => rollDev(
|
||||||
argResults: fakeArgResults,
|
argResults: fakeArgResults,
|
||||||
repository: repo,
|
repository: repo,
|
||||||
stdio: stdio,
|
stdio: stdio,
|
||||||
@ -413,7 +413,7 @@ void main() {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('does not tag but updates branch if --skip-tagging provided', () {
|
test('does not tag but updates branch if --skip-tagging provided', () async {
|
||||||
processManager.addCommands(<FakeCommand>[
|
processManager.addCommands(<FakeCommand>[
|
||||||
const FakeCommand(command: <String>[
|
const FakeCommand(command: <String>[
|
||||||
'git',
|
'git',
|
||||||
@ -498,7 +498,7 @@ void main() {
|
|||||||
skipTagging: true,
|
skipTagging: true,
|
||||||
);
|
);
|
||||||
expect(
|
expect(
|
||||||
rollDev(
|
await rollDev(
|
||||||
usage: usage,
|
usage: usage,
|
||||||
argResults: fakeArgResults,
|
argResults: fakeArgResults,
|
||||||
repository: repo,
|
repository: repo,
|
||||||
@ -508,7 +508,7 @@ void main() {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('successfully tags and publishes release', () {
|
test('successfully tags and publishes release', () async {
|
||||||
processManager.addCommands(<FakeCommand>[
|
processManager.addCommands(<FakeCommand>[
|
||||||
const FakeCommand(command: <String>[
|
const FakeCommand(command: <String>[
|
||||||
'git',
|
'git',
|
||||||
@ -597,7 +597,7 @@ void main() {
|
|||||||
remote: remote,
|
remote: remote,
|
||||||
);
|
);
|
||||||
expect(
|
expect(
|
||||||
rollDev(
|
await rollDev(
|
||||||
usage: usage,
|
usage: usage,
|
||||||
argResults: fakeArgResults,
|
argResults: fakeArgResults,
|
||||||
repository: repo,
|
repository: repo,
|
||||||
@ -607,7 +607,7 @@ void main() {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('successfully publishes release with --force', () {
|
test('successfully publishes release with --force', () async {
|
||||||
processManager.addCommands(<FakeCommand>[
|
processManager.addCommands(<FakeCommand>[
|
||||||
const FakeCommand(command: <String>[
|
const FakeCommand(command: <String>[
|
||||||
'git',
|
'git',
|
||||||
@ -692,7 +692,7 @@ void main() {
|
|||||||
force: true,
|
force: true,
|
||||||
);
|
);
|
||||||
expect(
|
expect(
|
||||||
rollDev(
|
await rollDev(
|
||||||
argResults: fakeArgResults,
|
argResults: fakeArgResults,
|
||||||
repository: repo,
|
repository: repo,
|
||||||
stdio: stdio,
|
stdio: stdio,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user