Home | History | Annotate | Download | only in release
      1 #!/usr/bin/env python
      2 # Copyright 2014 the V8 project authors. All rights reserved.
      3 # Use of this source code is governed by a BSD-style license that can be
      4 # found in the LICENSE file.
      5 
      6 import argparse
      7 import os
      8 import sys
      9 
     10 from common_includes import *
     11 
     12 ROLL_SUMMARY = ("Summary of changes available at:\n"
     13                 "https://chromium.googlesource.com/v8/v8/+log/%s..%s")
     14 
     15 ISSUE_MSG = (
     16 """Please follow these instructions for assigning/CC'ing issues:
     17 https://github.com/v8/v8/wiki/Triaging%20issues
     18 
     19 Please close rolling in case of a roll revert:
     20 https://v8-roll.appspot.com/
     21 This only works with a Google account.
     22 
     23 CQ_INCLUDE_TRYBOTS=master.tryserver.blink:linux_trusty_blink_rel;master.tryserver.chromium.linux:linux_optional_gpu_tests_rel;master.tryserver.chromium.mac:mac_optional_gpu_tests_rel;master.tryserver.chromium.win:win_optional_gpu_tests_rel""")
     24 
     25 class Preparation(Step):
     26   MESSAGE = "Preparation."
     27 
     28   def RunStep(self):
     29     self['json_output']['monitoring_state'] = 'preparation'
     30     # Update v8 remote tracking branches.
     31     self.GitFetchOrigin()
     32     self.Git("fetch origin +refs/tags/*:refs/tags/*")
     33 
     34 
     35 class DetectLastRoll(Step):
     36   MESSAGE = "Detect commit ID of the last Chromium roll."
     37 
     38   def RunStep(self):
     39     self['json_output']['monitoring_state'] = 'detect_last_roll'
     40     self["last_roll"] = self._options.last_roll
     41     if not self["last_roll"]:
     42       # Interpret the DEPS file to retrieve the v8 revision.
     43       # TODO(machenbach): This should be part or the roll-deps api of
     44       # depot_tools.
     45       Var = lambda var: '%s'
     46       exec(FileToText(os.path.join(self._options.chromium, "DEPS")))
     47 
     48       # The revision rolled last.
     49       self["last_roll"] = vars['v8_revision']
     50     self["last_version"] = self.GetVersionTag(self["last_roll"])
     51     assert self["last_version"], "The last rolled v8 revision is not tagged."
     52 
     53 
     54 class DetectRevisionToRoll(Step):
     55   MESSAGE = "Detect commit ID of the V8 revision to roll."
     56 
     57   def RunStep(self):
     58     self['json_output']['monitoring_state'] = 'detect_revision'
     59     self["roll"] = self._options.revision
     60     if self["roll"]:
     61       # If the revision was passed on the cmd line, continue script execution
     62       # in the next step.
     63       return False
     64 
     65     # The revision that should be rolled. Check for the latest of the most
     66     # recent releases based on commit timestamp.
     67     revisions = self.GetRecentReleases(
     68         max_age=self._options.max_age * DAY_IN_SECONDS)
     69     assert revisions, "Didn't find any recent release."
     70 
     71     # There must be some progress between the last roll and the new candidate
     72     # revision (i.e. we don't go backwards). The revisions are ordered newest
     73     # to oldest. It is possible that the newest timestamp has no progress
     74     # compared to the last roll, i.e. if the newest release is a cherry-pick
     75     # on a release branch. Then we look further.
     76     for revision in revisions:
     77       version = self.GetVersionTag(revision)
     78       assert version, "Internal error. All recent releases should have a tag"
     79 
     80       if SortingKey(self["last_version"]) < SortingKey(version):
     81         self["roll"] = revision
     82         break
     83     else:
     84       print("There is no newer v8 revision than the one in Chromium (%s)."
     85             % self["last_roll"])
     86       self['json_output']['monitoring_state'] = 'up_to_date'
     87       return True
     88 
     89 
     90 class PrepareRollCandidate(Step):
     91   MESSAGE = "Robustness checks of the roll candidate."
     92 
     93   def RunStep(self):
     94     self['json_output']['monitoring_state'] = 'prepare_candidate'
     95     self["roll_title"] = self.GitLog(n=1, format="%s",
     96                                      git_hash=self["roll"])
     97 
     98     # Make sure the last roll and the roll candidate are releases.
     99     version = self.GetVersionTag(self["roll"])
    100     assert version, "The revision to roll is not tagged."
    101     version = self.GetVersionTag(self["last_roll"])
    102     assert version, "The revision used as last roll is not tagged."
    103 
    104 
    105 class SwitchChromium(Step):
    106   MESSAGE = "Switch to Chromium checkout."
    107 
    108   def RunStep(self):
    109     self['json_output']['monitoring_state'] = 'switch_chromium'
    110     cwd = self._options.chromium
    111     self.InitialEnvironmentChecks(cwd)
    112     # Check for a clean workdir.
    113     if not self.GitIsWorkdirClean(cwd=cwd):  # pragma: no cover
    114       self.Die("Workspace is not clean. Please commit or undo your changes.")
    115     # Assert that the DEPS file is there.
    116     if not os.path.exists(os.path.join(cwd, "DEPS")):  # pragma: no cover
    117       self.Die("DEPS file not present.")
    118 
    119 
    120 class UpdateChromiumCheckout(Step):
    121   MESSAGE = "Update the checkout and create a new branch."
    122 
    123   def RunStep(self):
    124     self['json_output']['monitoring_state'] = 'update_chromium'
    125     cwd = self._options.chromium
    126     self.GitCheckout("master", cwd=cwd)
    127     self.DeleteBranch("work-branch", cwd=cwd)
    128     self.GitPull(cwd=cwd)
    129 
    130     # Update v8 remotes.
    131     self.GitFetchOrigin()
    132 
    133     self.GitCreateBranch("work-branch", cwd=cwd)
    134 
    135 
    136 class UploadCL(Step):
    137   MESSAGE = "Create and upload CL."
    138 
    139   def RunStep(self):
    140     self['json_output']['monitoring_state'] = 'upload'
    141     cwd = self._options.chromium
    142     # Patch DEPS file.
    143     if self.Command("roll-dep-svn", "v8 %s" %
    144                     self["roll"], cwd=cwd) is None:
    145       self.Die("Failed to create deps for %s" % self["roll"])
    146 
    147     message = []
    148     message.append("Update V8 to %s." % self["roll_title"].lower())
    149 
    150     message.append(
    151         ROLL_SUMMARY % (self["last_roll"][:8], self["roll"][:8]))
    152 
    153     message.append(ISSUE_MSG)
    154 
    155     message.append("TBR=%s" % self._options.reviewer)
    156     self.GitCommit("\n\n".join(message),  author=self._options.author, cwd=cwd)
    157     if not self._options.dry_run:
    158       self.GitUpload(author=self._options.author,
    159                      force=True,
    160                      bypass_hooks=True,
    161                      cq=self._options.use_commit_queue,
    162                      cwd=cwd)
    163       print "CL uploaded."
    164     else:
    165       print "Dry run - don't upload."
    166 
    167     self.GitCheckout("master", cwd=cwd)
    168     self.GitDeleteBranch("work-branch", cwd=cwd)
    169 
    170 class CleanUp(Step):
    171   MESSAGE = "Done!"
    172 
    173   def RunStep(self):
    174     self['json_output']['monitoring_state'] = 'success'
    175     print("Congratulations, you have successfully rolled %s into "
    176           "Chromium."
    177           % self["roll"])
    178 
    179     # Clean up all temporary files.
    180     Command("rm", "-f %s*" % self._config["PERSISTFILE_BASENAME"])
    181 
    182 
    183 class AutoRoll(ScriptsBase):
    184   def _PrepareOptions(self, parser):
    185     parser.add_argument("-c", "--chromium", required=True,
    186                         help=("The path to your Chromium src/ "
    187                               "directory to automate the V8 roll."))
    188     parser.add_argument("--last-roll",
    189                         help="The git commit ID of the last rolled version. "
    190                              "Auto-detected if not specified.")
    191     parser.add_argument("--max-age", default=7, type=int,
    192                         help="Maximum age in days of the latest release.")
    193     parser.add_argument("--revision",
    194                         help="Revision to roll. Auto-detected if not "
    195                              "specified."),
    196     parser.add_argument("--roll", help="Deprecated.",
    197                         default=True, action="store_true")
    198     parser.add_argument("--use-commit-queue",
    199                         help="Check the CQ bit on upload.",
    200                         default=True, action="store_true")
    201 
    202   def _ProcessOptions(self, options):  # pragma: no cover
    203     if not options.author or not options.reviewer:
    204       print "A reviewer (-r) and an author (-a) are required."
    205       return False
    206 
    207     options.requires_editor = False
    208     options.force = True
    209     options.manual = False
    210     return True
    211 
    212   def _Config(self):
    213     return {
    214       "PERSISTFILE_BASENAME": "/tmp/v8-chromium-roll-tempfile",
    215     }
    216 
    217   def _Steps(self):
    218     return [
    219       Preparation,
    220       DetectLastRoll,
    221       DetectRevisionToRoll,
    222       PrepareRollCandidate,
    223       SwitchChromium,
    224       UpdateChromiumCheckout,
    225       UploadCL,
    226       CleanUp,
    227     ]
    228 
    229 
    230 if __name__ == "__main__":  # pragma: no cover
    231   sys.exit(AutoRoll().Run())
    232