Warn if git version is not high enough for supporting all features (#3332)
diff --git a/lib/src/git.dart b/lib/src/git.dart
index 5fa7536..dc45edc 100644
--- a/lib/src/git.dart
+++ b/lib/src/git.dart
@@ -6,7 +6,9 @@
import 'dart:async';
import 'package:path/path.dart' as p;
+import 'package:pub_semver/pub_semver.dart';
+import 'command_runner.dart';
import 'exceptions.dart';
import 'io.dart';
import 'log.dart' as log;
@@ -121,13 +123,34 @@
return null;
}
+/// '--recourse-submodules' was introduced in Git 2.14
+/// (https://git-scm.com/book/en/v2/Git-Tools-Submodules).
+final _minSupportedGitVersion = Version(2, 14, 0);
+
/// Checks whether [command] is the Git command for this computer.
bool _tryGitCommand(String command) {
// If "git --version" prints something familiar, git is working.
try {
var result = runProcessSync(command, ['--version']);
- var regexp = RegExp('^git version');
- return result.stdout.length == 1 && regexp.hasMatch(result.stdout.single);
+
+ if (result.stdout.length != 1) return false;
+ final output = result.stdout.single;
+ final match = RegExp(r'^git version (\d+)\.(\d+)\.').matchAsPrefix(output);
+
+ if (match == null) return false;
+ // Git seems to use many parts in the version number. We just check the
+ // first two.
+ final major = int.parse(match[1]!);
+ final minor = int.parse(match[2]!);
+ if (Version(major, minor, 0) < _minSupportedGitVersion) {
+ // We just warn here, as some features might work with older versions of
+ // git.
+ log.warning('''
+You have a very old version of git (version ${output.substring('git version '.length)}),
+for $topLevelProgram it is recommended to use git version 2.14 or newer.
+''');
+ }
+ return true;
} on RunProcessException catch (err) {
// If the process failed, they probably don't have it.
log.error('Git command is not "$command": $err');
diff --git a/test/get/git/git_not_installed_test.dart b/test/get/git/git_not_installed_test.dart
index f00d795..e146f0e 100644
--- a/test/get/git/git_not_installed_test.dart
+++ b/test/get/git/git_not_installed_test.dart
@@ -13,42 +13,84 @@
import '../../descriptor.dart' as d;
import '../../test_pub.dart';
+/// Create temporary folder 'bin/' containing a 'git' script in [sandbox]
+/// By adding the bin/ folder to the search `$PATH` we can prevent `pub` from
+/// detecting the installed 'git' binary and we can test that it prints
+/// a useful error message.
+Future<void> setUpFakeGitScript(
+ {required String bash, required String batch}) async {
+ await d.dir('bin', [
+ if (!Platform.isWindows) d.file('git', bash),
+ if (Platform.isWindows) d.file('git.bat', batch),
+ ]).create();
+ if (!Platform.isWindows) {
+ // Make the script executable.
+
+ await runProcess('chmod', ['+x', p.join(sandbox, 'bin', 'git')]);
+ }
+}
+
+/// Returns an environment where PATH is extended with `$sandbox/bin`.
+Map<String, String> extendedPathEnv() {
+ final separator = Platform.isWindows ? ';' : ':';
+ final binFolder = p.join(sandbox, 'bin');
+
+ return {
+ // Override 'PATH' to ensure that we can't detect a working "git" binary
+ 'PATH': '$binFolder$separator${Platform.environment['PATH']}',
+ };
+}
+
void main() {
test('reports failure if Git is not installed', () async {
- // Create temporary folder 'bin/' containing a 'git' script in [sandbox]
- // By adding the bin/ folder to the search `$PATH` we can prevent `pub` from
- // detecting the installed 'git' binary and we can test that it prints
- // a useful error message.
- await d.dir('bin', [
- d.file('git', '''
+ await setUpFakeGitScript(bash: '''
#!/bin/bash -e
echo "not git"
exit 1
-'''),
- d.file('git.bat', '''
+''', batch: '''
echo "not git"
-''')
- ]).create();
- final binFolder = p.join(sandbox, 'bin');
- // chmod the git script
- if (!Platform.isWindows) {
- await runProcess('chmod', ['+x', p.join(sandbox, 'bin', 'git')]);
- }
+''');
+ await d.appDir({
+ 'foo': {'git': '../foo.git'}
+ }).create();
+
+ await pubGet(
+ environment: extendedPathEnv(),
+ error: contains('Cannot find a Git executable'),
+ exitCode: 1,
+ );
+ });
+
+ test('warns if git version is too old', () async {
+ await setUpFakeGitScript(bash: '''
+#!/bin/bash -e
+if [ "\$1" == "--version" ]
+then
+ echo "git version 2.13.1.616"
+ exit 1
+else
+ PATH=${Platform.environment['PATH']} git \$*
+fi
+''', batch: '''
+if "%1"=="--version" (
+ echo "git version 2.13.1.616"
+) else (
+ set path="${Platform.environment['PATH']}"
+ git %*
+)
+''');
+
+ await d.git('foo.git', [d.libPubspec('foo', '1.0.0')]).create();
await d.appDir({
'foo': {'git': '../foo.git'}
}).create();
- final separator = Platform.isWindows ? ';' : ':';
-
await pubGet(
- environment: {
- // Override 'PATH' to ensure that we can't detect a working "git" binary
- 'PATH': '$binFolder$separator${Platform.environment['PATH']}',
- },
- // We wish to verify that this error message is printed.
- error: contains('Cannot find a Git executable'),
- exitCode: 1, // exit code is non-zero.
+ environment: extendedPathEnv(),
+ warning:
+ contains('You have a very old version of git (version 2.13.1.616)'),
+ exitCode: 0,
);
});
}