[rts] Add -q flag to git cl try, upload, and set_commit

Quick run is only set when the -q flag is passed. It is not set to 0 by
other flags because only Chromium has Quick run and there are other
depot_tools users. We rely on the CQ to set the flag back to 0.

Bug: 1192827
Change-Id: I3310c9f005343f7d3eea56eaad5f19c7ba751921
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/tools/depot_tools/+/2927818
Commit-Queue: Gregory Guterman <guterman@google.com>
Reviewed-by: Edward Lesmes <ehmaldonado@chromium.org>
diff --git a/git_cl.py b/git_cl.py
index 0ae2cd3..4a054be 100755
--- a/git_cl.py
+++ b/git_cl.py
@@ -836,10 +836,11 @@
 class _CQState(object):
   """Enum for states of CL with respect to CQ."""
   NONE = 'none'
+  QUICK_RUN = 'quick_run'
   DRY_RUN = 'dry_run'
   COMMIT = 'commit'
 
-  ALL_STATES = [NONE, DRY_RUN, COMMIT]
+  ALL_STATES = [NONE, QUICK_RUN, DRY_RUN, COMMIT]
 
 
 class _ParsedIssueNumberArgument(object):
@@ -1527,17 +1528,25 @@
   def SetCQState(self, new_state):
     """Updates the CQ state for the latest patchset.
 
-    Issue must have been already uploaded and known.
+    Issue must have been already uploaded and known. Optionally allows for
+    updating Quick-Run (QR) state.
     """
     assert new_state in _CQState.ALL_STATES
     assert self.GetIssue()
     try:
       vote_map = {
         _CQState.NONE: 0,
+        _CQState.QUICK_RUN: 1,
         _CQState.DRY_RUN: 1,
         _CQState.COMMIT: 2,
       }
-      labels = {'Commit-Queue': vote_map[new_state]}
+      if new_state == _CQState.QUICK_RUN:
+        labels = {
+            'Commit-Queue': vote_map[_CQState.DRY_RUN],
+            'Quick-Run': vote_map[_CQState.QUICK_RUN],
+        }
+      else:
+        labels = {'Commit-Queue': vote_map[new_state]}
       notify = False if new_state == _CQState.DRY_RUN else None
       gerrit_util.SetReview(
           self.GetGerritHost(), self._GerritChangeIdentifier(),
@@ -2460,6 +2469,9 @@
       refspec_opts.append('l=Commit-Queue+2')
     elif options.cq_dry_run:
       refspec_opts.append('l=Commit-Queue+1')
+    elif options.cq_quick_run:
+      refspec_opts.append('l=Commit-Queue+1')
+      refspec_opts.append('l=Quick-Run+1')
 
     if change_desc.get_reviewers(tbr_only=True):
       score = gerrit_util.GetCodeReviewTbrScore(
@@ -4216,6 +4228,14 @@
                     action='store_true', default=False,
                     help='Send the patchset to do a CQ dry run right after '
                          'upload.')
+  parser.add_option(
+      '-q',
+      '--cq-quick-run',
+      action='store_true',
+      default=False,
+      help='Send the patchset to do a CQ quick run right after '
+           'upload (https://source.chromium.org/chromium/chromium/src/+/main:do'
+           'cs/cq_quick_run.md) (chromium only).')
   parser.add_option('--set-bot-commit', action='store_true',
                     help=optparse.SUPPRESS_HELP)
   parser.add_option('--preserve-tryjobs', action='store_true',
@@ -4293,10 +4313,11 @@
     options.message = gclient_utils.FileRead(options.message_file)
 
   if ([options.cq_dry_run,
+       options.cq_quick_run,
        options.use_commit_queue,
        options.retry_failed].count(True) > 1):
-    parser.error('Only one of --use-commit-queue, --cq-dry-run, or '
-                 '--retry-failed is allowed.')
+    parser.error('Only one of --use-commit-queue, --cq-dry-run, --cq-quick-run '
+                 'or --retry-failed is allowed.')
 
   if options.skip_title and options.title:
     parser.error('Only one of --title and --skip-title allowed.')
@@ -4572,6 +4593,14 @@
       help='Force a clobber before building; that is don\'t do an '
            'incremental build')
   group.add_option(
+      '-q',
+      '--quick-run',
+      action='store_true',
+      default=False,
+      help='trigger in quick run mode '
+           '(https://source.chromium.org/chromium/chromium/src/+/main:docs/cq_q'
+           'uick_run.md) (chromium only).')
+  group.add_option(
       '--category', default='git_cl_try', help='Specify custom build category.')
   group.add_option(
       '--project',
@@ -4652,6 +4681,9 @@
     if num_builders > 10:
       confirm_or_exit('There are %d builders with failed builds.'
                       % num_builders, action='continue')
+  elif options.quick_run:
+    print('Scheduling CQ quick run on: %s' % cl.GetIssueURL())
+    return cl.SetCQState(_CQState.QUICK_RUN)
   else:
     if options.verbose:
       print('git cl try with no bots now defaults to CQ dry run.')
@@ -4774,6 +4806,13 @@
   """Sets the commit bit to trigger the CQ."""
   parser.add_option('-d', '--dry-run', action='store_true',
                     help='trigger in dry run mode')
+  parser.add_option(
+      '-q',
+      '--quick-run',
+      action='store_true',
+      help='trigger in quick run mode '
+          '(https://source.chromium.org/chromium/chromium/src/+/main:docs/cq_qu'
+          'ick_run.md) (chromium only).')
   parser.add_option('-c', '--clear', action='store_true',
                     help='stop CQ run, if any')
   parser.add_option(
@@ -4783,18 +4822,21 @@
   options, args = parser.parse_args(args)
   if args:
     parser.error('Unrecognized args: %s' % ' '.join(args))
-  if options.dry_run and options.clear:
-    parser.error('Only one of --dry-run and --clear are allowed.')
+  if [options.dry_run, options.quick_run, options.clear].count(True) > 1:
+    parser.error('Only one of --dry-run, --quick-run, and --clear are allowed.')
 
   cl = Changelist(issue=options.issue)
+  if not cl.GetIssue():
+    parser.error('Must upload the issue first.')
+
   if options.clear:
     state = _CQState.NONE
+  elif options.quick_run:
+    state = _CQState.QUICK_RUN
   elif options.dry_run:
     state = _CQState.DRY_RUN
   else:
     state = _CQState.COMMIT
-  if not cl.GetIssue():
-    parser.error('Must upload the issue first.')
   cl.SetCQState(state)
   return 0