Reland fix --version (#52141)

This commit is contained in:
Dan Field 2020-03-06 21:38:35 -08:00 committed by GitHub
parent db1f33fd70
commit e13e17009d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 158 additions and 6 deletions

View file

@ -6,6 +6,7 @@ import 'dart:async';
import '../base/common.dart';
import '../doctor.dart';
import '../globals.dart' as globals;
import '../runner/flutter_command.dart';
class DoctorCommand extends FlutterCommand {
@ -42,6 +43,7 @@ class DoctorCommand extends FlutterCommand {
@override
Future<FlutterCommandResult> runCommand() async {
globals.flutterVersion.fetchTagsAndUpdate();
if (argResults.wasParsed('check-for-remote-artifacts')) {
final String engineRevision = stringArg('check-for-remote-artifacts');
if (engineRevision.startsWith(RegExp(r'[a-f0-9]{1,40}'))) {

View file

@ -322,6 +322,7 @@ class FlutterCommandRunner extends CommandRunner<void> {
if (topLevelResults['version'] as bool) {
globals.flutterUsage.sendCommand('version');
globals.flutterVersion.fetchTagsAndUpdate();
String status;
if (machineFlag) {
status = const JsonEncoder.withIndent(' ').convert(globals.flutterVersion.toJson());

View file

@ -23,6 +23,9 @@ enum Channel {
stable,
}
/// The flutter GitHub repository.
const String _flutterGit = 'https://github.com/flutter/flutter.git';
/// Retrieve a human-readable name for a given [channel].
///
/// Requires [FlutterVersion.officialChannels] to be correctly ordered.
@ -42,13 +45,29 @@ Channel getChannelForName(String name) {
}
class FlutterVersion {
/// Parses the Flutter version from currently available tags in the local
/// repo.
///
/// Call [fetchTagsAndUpdate] to update the version based on the latest tags
/// available upstream.
FlutterVersion([this._clock = const SystemClock(), this._workingDirectory]) {
_frameworkRevision = _runGit(
gitLog(<String>['-n', '1', '--pretty=format:%H']).join(' '),
processUtils,
_workingDirectory,
);
_gitTagVersion = GitTagVersion.determine(processUtils, _workingDirectory);
_gitTagVersion = GitTagVersion.determine(processUtils, workingDirectory: _workingDirectory, fetchTags: false);
_frameworkVersion = gitTagVersion.frameworkVersionFor(_frameworkRevision);
}
/// Fetchs tags from the upstream Flutter repository and re-calculates the
/// version.
///
/// This carries a performance penalty, and should only be called when the
/// user explicitly wants to get the version, e.g. for `flutter --version` or
/// `flutter doctor`.
void fetchTagsAndUpdate() {
_gitTagVersion = GitTagVersion.determine(processUtils, workingDirectory: _workingDirectory, fetchTags: true);
_frameworkVersion = gitTagVersion.frameworkVersionFor(_frameworkRevision);
}
@ -233,7 +252,7 @@ class FlutterVersion {
'remote',
'add',
_versionCheckRemote,
'https://github.com/flutter/flutter.git',
_flutterGit,
]);
await _run(<String>['git', 'fetch', _versionCheckRemote, branch]);
return _latestGitCommitDate(
@ -701,7 +720,10 @@ class GitTagVersion {
/// The git hash (or an abbreviation thereof) for this commit.
final String hash;
static GitTagVersion determine(ProcessUtils processUtils, [String workingDirectory]) {
static GitTagVersion determine(ProcessUtils processUtils, {String workingDirectory, bool fetchTags = false}) {
if (fetchTags) {
_runGit('git fetch $_flutterGit --tags', processUtils, workingDirectory);
}
return parse(_runGit('git describe --match v*.*.* --first-parent --long --tags', processUtils, workingDirectory));
}

View file

@ -4,12 +4,17 @@
import 'dart:async';
import 'package:args/command_runner.dart';
import 'package:file/memory.dart';
import 'package:flutter_tools/src/artifacts.dart';
import 'package:flutter_tools/src/base/common.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/base/terminal.dart';
import 'package:flutter_tools/src/base/user_messages.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/commands/doctor.dart';
import 'package:flutter_tools/src/doctor.dart';
import 'package:flutter_tools/src/features.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
@ -722,6 +727,50 @@ void main() {
FeatureFlags: () => TestFeatureFlags(isWebEnabled: true),
ProcessManager: () => MockProcessManager(),
});
testUsingContext('Fetches tags to get the right version', () async {
Cache.disableLocking();
final DoctorCommand doctorCommand = DoctorCommand();
final CommandRunner<void> commandRunner = createTestCommandRunner(doctorCommand);
await commandRunner.run(<String>['doctor']);
verify(mockFlutterVersion.fetchTagsAndUpdate()).called(1);
Cache.enableLocking();
}, overrides: <Type, Generator>{
ProcessManager: () => FakeProcessManager.any(),
FileSystem: () => MemoryFileSystem.test(),
FlutterVersion: () => mockFlutterVersion,
Doctor: () => NoOpDoctor(),
}, initializeFlutterRoot: false);
}
class NoOpDoctor implements Doctor {
@override
bool get canLaunchAnything => true;
@override
bool get canListAnything => true;
@override
Future<bool> checkRemoteArtifacts(String engineRevision) async => true;
@override
Future<bool> diagnose({ bool androidLicenses = false, bool verbose = true, bool showColor = true }) async => true;
@override
List<ValidatorTask> startValidatorTasks() => <ValidatorTask>[];
@override
Future<void> summary() => null;
@override
List<DoctorValidator> get validators => <DoctorValidator>[];
@override
List<Workflow> get workflows => <Workflow>[];
}
class MockUsage extends Mock implements Usage {}
@ -1062,4 +1111,3 @@ class VsCodeValidatorTestTargets extends VsCodeValidator {
}
class MockProcessManager extends Mock implements ProcessManager {}
class MockFlutterVersion extends Mock implements FlutterVersion {}

View file

@ -88,6 +88,18 @@ void main() {
Platform: () => platform,
}, initializeFlutterRoot: false);
testUsingContext('Fetches tags when --version is used', () async {
final MockFlutterVersion version = globals.flutterVersion as MockFlutterVersion;
await runner.run(<String>['--version']);
verify(version.fetchTagsAndUpdate()).called(1);
}, overrides: <Type, Generator>{
FileSystem: () => fs,
ProcessManager: () => FakeProcessManager.any(),
Platform: () => platform,
}, initializeFlutterRoot: false);
testUsingContext('throw tool exit if the version file cannot be written', () async {
final MockFlutterVersion version = globals.flutterVersion as MockFlutterVersion;
when(version.ensureVersionFile()).thenThrow(const FileSystemException());
@ -165,6 +177,8 @@ void main() {
workingDirectory: Cache.flutterRoot)).thenReturn(result);
when(processManager.runSync(FlutterVersion.gitLog('-n 1 --pretty=format:%ar'.split(' ')),
workingDirectory: Cache.flutterRoot)).thenReturn(result);
when(processManager.runSync('git fetch https://github.com/flutter/flutter.git --tags'.split(' '),
workingDirectory: Cache.flutterRoot)).thenReturn(result);
when(processManager.runSync('git describe --match v*.*.* --first-parent --long --tags'.split(' '),
workingDirectory: Cache.flutterRoot)).thenReturn(result);
when(processManager.runSync(FlutterVersion.gitLog('-n 1 --pretty=format:%ad --date=iso'.split(' ')),

View file

@ -7,6 +7,7 @@ import 'dart:convert';
import 'package:collection/collection.dart' show ListEquality;
import 'package:flutter_tools/src/base/context.dart';
import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/base/process.dart';
import 'package:flutter_tools/src/base/time.dart';
import 'package:flutter_tools/src/base/utils.dart';
import 'package:flutter_tools/src/cache.dart';
@ -411,6 +412,60 @@ void main() {
'Could not interpret results of "git describe": v1.2.3-4-gxabcdef\n',
);
});
testUsingContext('determine does not call fetch --tags', () {
final MockProcessUtils processUtils = MockProcessUtils();
when(processUtils.runSync(
<String>['git', 'fetch', 'https://github.com/flutter/flutter.git', '--tags'],
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment'),
)).thenReturn(RunResult(ProcessResult(105, 0, '', ''), <String>['git', 'fetch']));
when(processUtils.runSync(
<String>['git', 'describe', '--match', 'v*.*.*', '--first-parent', '--long', '--tags'],
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment'),
)).thenReturn(RunResult(ProcessResult(106, 0, 'v0.1.2-3-1234abcd', ''), <String>['git', 'describe']));
GitTagVersion.determine(processUtils, workingDirectory: '.');
verifyNever(processUtils.runSync(
<String>['git', 'fetch', 'https://github.com/flutter/flutter.git', '--tags'],
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment'),
));
verify(processUtils.runSync(
<String>['git', 'describe', '--match', 'v*.*.*', '--first-parent', '--long', '--tags'],
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment'),
)).called(1);
});
testUsingContext('determine calls fetch --tags', () {
final MockProcessUtils processUtils = MockProcessUtils();
when(processUtils.runSync(
<String>['git', 'fetch', 'https://github.com/flutter/flutter.git', '--tags'],
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment'),
)).thenReturn(RunResult(ProcessResult(105, 0, '', ''), <String>['git', 'fetch']));
when(processUtils.runSync(
<String>['git', 'describe', '--match', 'v*.*.*', '--first-parent', '--long', '--tags'],
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment'),
)).thenReturn(RunResult(ProcessResult(106, 0, 'v0.1.2-3-1234abcd', ''), <String>['git', 'describe']));
GitTagVersion.determine(processUtils, workingDirectory: '.', fetchTags: true);
verify(processUtils.runSync(
<String>['git', 'fetch', 'https://github.com/flutter/flutter.git', '--tags'],
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment'),
)).called(1);
verify(processUtils.runSync(
<String>['git', 'describe', '--match', 'v*.*.*', '--first-parent', '--long', '--tags'],
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment'),
)).called(1);
});
}
void _expectVersionMessage(String message) {
@ -489,6 +544,8 @@ void fakeData(
// Careful here! argsAre accepts 9 arguments and FlutterVersion.gitLog adds 4.
} else if (remoteCommitDate != null && listArgsAre(FlutterVersion.gitLog(<String>['__flutter_version_check__/$channel', '-n', '1', '--pretty=format:%ad', '--date=iso']))) {
return success(remoteCommitDate.toString());
} else if (argsAre('git', 'fetch', 'https://github.com/flutter/flutter.git', '--tags')) {
return success('');
}
throw StateError('Unexpected call to ProcessManager.run(${invocation.positionalArguments}, ${invocation.namedArguments})');
@ -519,13 +576,18 @@ void fakeData(
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment'),
)).thenReturn(ProcessResult(104, 0, '1 second ago', ''));
when(pm.runSync(
<String>['git', 'fetch', 'https://github.com/flutter/flutter', '--tags'],
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment'),
)).thenReturn(ProcessResult(105, 0, '', ''));
when(pm.runSync(
<String>['git', 'describe', '--match', 'v*.*.*', '--first-parent', '--long', '--tags'],
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment'),
)).thenReturn(ProcessResult(105, 0, 'v0.1.2-3-1234abcd', ''));
)).thenReturn(ProcessResult(106, 0, 'v0.1.2-3-1234abcd', ''));
}
class MockProcessManager extends Mock implements ProcessManager {}
class MockProcessUtils extends Mock implements ProcessUtils {}
class MockCache extends Mock implements Cache {}

View file

@ -647,6 +647,9 @@ class FakeHttpHeaders extends HttpHeaders {
}
class FakeFlutterVersion implements FlutterVersion {
@override
void fetchTagsAndUpdate() { }
@override
String get channel => 'master';