Repository: buildbot/buildbot

Issue:
Git step tries to extract the git version, even if output is not from Git
If on a system you have a git command (but somehow it is a rogue one and don't output anything) or if your Twisted spawn_process goes wild (ex on Windows)

you can end up with this error on Buildbot

```
buildbot/steps/source/git.py", line 546, in checkSupport
    version = stdout.strip().split(' ')[2]
exceptions.IndexError: list index out of range
```

Here 
https://github.com/buildbot/buildbot/blob/5f995bf3f82bade2eab9a95cade97e6864b560f2/master/buildbot/steps/source/git.py#L588

all the check for specific git versions should be done only if git is installed, that is the lines should be indented.

-----

To reproduce it, set up a git command which is not git, but a bogus one.

Buildbot should detect that it is not git, and fail with the more appropriate error

```
    raise BuildSlaveTooOldError("git is not installed on slave")
buildbot.interfaces.BuildSlaveTooOldError: git is not installed on slave
```


Discussion:

Resolving patch:
diff --git a/master/buildbot/steps/source/git.py b/master/buildbot/steps/source/git.py
--- a/master/buildbot/steps/source/git.py
+++ b/master/buildbot/steps/source/git.py
@@ -583,9 +583,13 @@ def checkBranchSupport(self):
         stdout = yield self._dovccmd(['--version'], collectStdout=True)
 
         gitInstalled = False
+        version = "0.0.0"
         if 'git' in stdout:
             gitInstalled = True
-        version = stdout.strip().split(' ')[2]
+            try:
+                version = stdout.strip().split(' ')[2]
+            except IndexError:
+                gitInstalled = False
         if LooseVersion(version) < LooseVersion("1.6.5"):
             self.supportsBranch = False
         if LooseVersion(version) < LooseVersion("1.7.8"):


Test patch:
diff --git a/master/buildbot/test/unit/test_steps_source_git.py b/master/buildbot/test/unit/test_steps_source_git.py
--- a/master/buildbot/test/unit/test_steps_source_git.py
+++ b/master/buildbot/test/unit/test_steps_source_git.py
@@ -16,10 +16,12 @@
 from __future__ import absolute_import
 from __future__ import print_function
 
+from twisted.internet import defer
 from twisted.internet import error
 from twisted.python.reflect import namedModule
 from twisted.trial import unittest
 
+from buildbot.interfaces import WorkerTooOldError
 from buildbot.process import remotetransfer
 from buildbot.process.results import FAILURE
 from buildbot.process.results import RETRY
@@ -2415,3 +2417,44 @@ def test_worker_connection_lost(self):
         )
         self.expectOutcome(result=RETRY, state_string="update (retry)")
         return self.runStep()
+
+    def _test_invalidGit(self, _dovccmd):
+        def check(failure):
+            self.assertIsInstance(failure.value, WorkerTooOldError)
+            self.assertEqual(str(failure.value), "git is not installed on worker")
+
+        self.patch(self.stepClass, "_dovccmd", _dovccmd)
+        gitStep = self.setupStep(
+            self.stepClass(repourl='http://github.com/buildbot/buildbot.git',
+                           mode='full', method='clean'))
+
+        gitStep._start_deferred = defer.Deferred()
+        gitStep.startVC("branch", "revision", "patch")
+        d = gitStep._start_deferred.addBoth(check)
+        return d
+
+    def test_noGitCommandInstalled(self):
+        @defer.inlineCallbacks
+        def _dovccmd(command, abandonOnFailure=True, collectStdout=False,
+                     initialStdin=None):
+            """
+            Simulate the case where there is no git command.
+            """
+            yield
+            defer.returnValue("command not found:")
+
+        return self._test_invalidGit(_dovccmd)
+
+    def test_gitCommandOutputShowsNoVersion(self):
+        @defer.inlineCallbacks
+        def _dovccmd(command, abandonOnFailure=True, collectStdout=False,
+                     initialStdin=None):
+            """
+            Instead of outputting something like "git version 2.11",
+            simulate truncated output which has no version string,
+            to exercise error handling.
+            """
+            yield
+            defer.returnValue("git ")
+
+        return self._test_invalidGit(_dovccmd)