Added support for git cl upload automatic trybot determination.

This is part of my intern project, which is detailed here:
  "https://docs.google.com/a/google.com/document/d/10bkzag1UUbtESPkEWHYaZtGMEEbCN5Zad72PuoRpwZE/edit#"

The idea is to have "git cl upload" annotate the CL description with a
flag like "CQ_TRYBOTS=...", which CQ will then look at to determine which
trybots to run the the given CL.

The CL for the change for CQ is at "https://chromereviews.googleplex.com/51757013/".

R=dpranke@google.com, iannucci@google.com
BUG=378097

Review URL: https://codereview.chromium.org/348473003

git-svn-id: svn://svn.chromium.org/chrome/trunk/tools/depot_tools@280039 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/tests/git_cl_test.py b/tests/git_cl_test.py
index 1e70e1b..570904c 100755
--- a/tests/git_cl_test.py
+++ b/tests/git_cl_test.py
@@ -10,6 +10,7 @@
 import stat
 import sys
 import unittest
+import re
 
 sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
 
@@ -18,7 +19,7 @@
 import git_cl
 import git_common
 import subprocess2
-
+import presubmit_support
 
 class PresubmitMock(object):
   def __init__(self, *args, **kwargs):
@@ -750,6 +751,117 @@
       actual.append(obj.description)
     self.assertEqual(expected, actual)
 
+  def test_trybots_from_PRESUBMIT(self):
+    TEST_MASTER = 'testMaster'
+    TEST_BUILDER = 'testBuilder'
+    MASTERS = {TEST_MASTER:{TEST_BUILDER:['a']}}
+    self.mock(presubmit_support, 'DoGetTryMasters',
+              lambda *args: MASTERS)
+
+    change_mock = ChangeMock()
+    changelist_mock = ChangelistMock(change_mock)
+    self.mock(git_cl, 'is_dirty_git_tree', lambda x: False)
+    self.mock(git_cl, 'print_stats', lambda *arg: True)
+    self.mock(git_cl, 'Changelist',  lambda *args: changelist_mock)
+    self.mock(git_cl, 'CreateDescriptionFromLog', lambda arg: 'Commit message')
+    self.mock(git_cl.ChangeDescription, 'prompt', lambda self: None)
+
+    self.calls = [
+        ((['git', 'config', 'rietveld.autoupdate',],),
+         ''),
+        ((['git', 'config', 'gerrit.host',],),
+         ''),
+        ((['git', 'rev-parse', '--show-cdup',],),
+         ''),
+        ((['git', 'config', 'rietveld.private',],),
+         ''),
+        ((['git', 'config', '--local', '--get-regexp', '^svn-remote\\.'],),
+         ''),
+        ((['git', 'config', 'rietveld.project',],),
+         ''),
+        ((['git', 'rev-parse', 'HEAD',],),
+         ''),
+        ]
+
+    stored_description = []
+    def check_upload(args):
+      i = 0
+      for arg in args:
+        if arg == '--message':
+          break
+        i += 1
+
+      self.assertTrue(i < len(args))
+      stored_description.append(args[i+1])
+      return 1, 2
+    self.mock(git_cl.upload, 'RealMain', check_upload)
+
+    git_cl.main(['upload', '--bypass-hooks', '--auto-bots'])
+    found = re.search("CQ_TRYBOTS=(.*?)$", stored_description[0])
+    self.assertTrue(found)
+    self.assertEqual(found.group(1), '%s:%s' % (TEST_MASTER, TEST_BUILDER))
+
+
+class ChangelistMock(object):
+  def __init__(self, change_mock):
+    self.change_mock = change_mock
+
+  # Disable "Method could be a function"
+  # pylint: disable=R0201
+  def GetChange(self, *args):
+    return self.change_mock
+
+  def GetIssue(self):
+    return None
+
+  def GetBranch(self):
+    return []
+
+  def GetCommonAncestorWithUpstream(self):
+    return []
+
+  def GetCCList(self):
+    return []
+
+  def GetGitBaseUrlFromConfig(self):
+    return ''
+
+  def GetRemoteUrl(self):
+    return ''
+
+  def GetRietveldServer(self):
+    return None
+
+  def SetWatchers(self, *args):
+    pass
+
+  def SetIssue(self, issue):
+    pass
+
+  def SetPatchset(self, issue):
+    pass
+
+
+class ChangeMock(object):
+  def __init__(self):
+    self.stored_description = None
+
+  # Disable "Method could be a function"
+  # pylint: disable=R0201
+  def SetDescriptionText(self, desc):
+    self.stored_description = desc
+
+  def FullDescriptionText(self):
+    return 'HIHI TEST DESCRIPTION'
+
+  def RepositoryRoot(self):
+    return []
+
+  def AffectedFiles(self):
+    return []
+
+  def LocalPaths(self):
+    return None
 
 if __name__ == '__main__':
   git_cl.logging.basicConfig(