Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(181)

Side by Side Diff: tools/push-to-trunk/auto_roll.py

Issue 181453002: Reset trunk to 3.24.35.4 (Closed) Base URL: https://v8.googlecode.com/svn/trunk
Patch Set: Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « tools/merge-to-branch.sh ('k') | tools/push-to-trunk/common_includes.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright 2013 the V8 project authors. All rights reserved. 2 # Copyright 2013 the V8 project authors. All rights reserved.
3 # Redistribution and use in source and binary forms, with or without 3 # Redistribution and use in source and binary forms, with or without
4 # modification, are permitted provided that the following conditions are 4 # modification, are permitted provided that the following conditions are
5 # met: 5 # met:
6 # 6 #
7 # * Redistributions of source code must retain the above copyright 7 # * Redistributions of source code must retain the above copyright
8 # notice, this list of conditions and the following disclaimer. 8 # notice, this list of conditions and the following disclaimer.
9 # * Redistributions in binary form must reproduce the above 9 # * Redistributions in binary form must reproduce the above
10 # copyright notice, this list of conditions and the following 10 # copyright notice, this list of conditions and the following
11 # disclaimer in the documentation and/or other materials provided 11 # disclaimer in the documentation and/or other materials provided
12 # with the distribution. 12 # with the distribution.
13 # * Neither the name of Google Inc. nor the names of its 13 # * Neither the name of Google Inc. nor the names of its
14 # contributors may be used to endorse or promote products derived 14 # contributors may be used to endorse or promote products derived
15 # from this software without specific prior written permission. 15 # from this software without specific prior written permission.
16 # 16 #
17 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 28
29 import argparse
30 import json 29 import json
30 import optparse
31 import os 31 import os
32 import re 32 import re
33 import sys 33 import sys
34 import urllib 34 import urllib
35 35
36 from common_includes import * 36 from common_includes import *
37 import push_to_trunk 37 import push_to_trunk
38 from push_to_trunk import PushToTrunkOptions 38 from push_to_trunk import PushToTrunkOptions
39 from push_to_trunk import RunPushToTrunk 39 from push_to_trunk import RunPushToTrunk
40 40
41 SETTINGS_LOCATION = "SETTINGS_LOCATION" 41 SETTINGS_LOCATION = "SETTINGS_LOCATION"
42 42
43 CONFIG = { 43 CONFIG = {
44 PERSISTFILE_BASENAME: "/tmp/v8-auto-roll-tempfile", 44 PERSISTFILE_BASENAME: "/tmp/v8-auto-roll-tempfile",
45 DOT_GIT_LOCATION: ".git", 45 DOT_GIT_LOCATION: ".git",
46 SETTINGS_LOCATION: "~/.auto-roll", 46 SETTINGS_LOCATION: "~/.auto-roll",
47 } 47 }
48 48
49 49
50 class AutoRollOptions(CommonOptions): 50 class AutoRollOptions(CommonOptions):
51 def __init__(self, options): 51 def __init__(self, options):
52 super(AutoRollOptions, self).__init__(options) 52 super(AutoRollOptions, self).__init__(options)
53 self.requires_editor = False 53 self.requires_editor = False
54 self.status_password = options.status_password 54 self.status_password = options.status_password
55 self.r = options.r
55 self.c = options.c 56 self.c = options.c
56 self.push = getattr(options, 'push', False) 57 self.push = getattr(options, 'push', False)
57 self.author = getattr(options, 'a', None)
58 58
59 59
60 class Preparation(Step): 60 class Preparation(Step):
61 MESSAGE = "Preparation." 61 MESSAGE = "Preparation."
62 62
63 def RunStep(self): 63 def RunStep(self):
64 self.InitialEnvironmentChecks() 64 self.InitialEnvironmentChecks()
65 self.CommonPrepare() 65 self.CommonPrepare()
66 66
67 67
68 class CheckAutoRollSettings(Step): 68 class CheckAutoRollSettings(Step):
69 MESSAGE = "Checking settings file." 69 MESSAGE = "Checking settings file."
70 70
71 def RunStep(self): 71 def RunStep(self):
72 settings_file = os.path.realpath(self.Config(SETTINGS_LOCATION)) 72 settings_file = os.path.realpath(self.Config(SETTINGS_LOCATION))
73 if os.path.exists(settings_file): 73 if os.path.exists(settings_file):
74 settings_dict = json.loads(FileToText(settings_file)) 74 settings_dict = json.loads(FileToText(settings_file))
75 if settings_dict.get("enable_auto_roll") is False: 75 if settings_dict.get("enable_auto_roll") is False:
76 self.Die("Push to trunk disabled by auto-roll settings file: %s" 76 self.Die("Push to trunk disabled by auto-roll settings file: %s"
77 % settings_file) 77 % settings_file)
78 78
79 79
80 class CheckTreeStatus(Step): 80 class CheckTreeStatus(Step):
81 MESSAGE = "Checking v8 tree status message." 81 MESSAGE = "Checking v8 tree status message."
82 82
83 def RunStep(self): 83 def RunStep(self):
84 status_url = "https://v8-status.appspot.com/current?format=json" 84 status_url = "https://v8-status.appspot.com/current?format=json"
85 status_json = self.ReadURL(status_url, wait_plan=[5, 20, 300, 300]) 85 status_json = self.ReadURL(status_url, wait_plan=[5, 20, 300, 300])
86 self["tree_message"] = json.loads(status_json)["message"] 86 message = json.loads(status_json)["message"]
87 if re.search(r"nopush|no push", self["tree_message"], flags=re.I): 87 if re.search(r"nopush|no push", message, flags=re.I):
88 self.Die("Push to trunk disabled by tree state: %s" 88 self.Die("Push to trunk disabled by tree state: %s" % message)
89 % self["tree_message"]) 89 self.Persist("tree_message", message)
90 90
91 91
92 class FetchLatestRevision(Step): 92 class FetchLatestRevision(Step):
93 MESSAGE = "Fetching latest V8 revision." 93 MESSAGE = "Fetching latest V8 revision."
94 94
95 def RunStep(self): 95 def RunStep(self):
96 match = re.match(r"^r(\d+) ", self.GitSVNLog()) 96 log = self.Git("svn log -1 --oneline").strip()
97 match = re.match(r"^r(\d+) ", log)
97 if not match: 98 if not match:
98 self.Die("Could not extract current svn revision from log.") 99 self.Die("Could not extract current svn revision from log.")
99 self["latest"] = match.group(1) 100 self.Persist("latest", match.group(1))
100 101
101 102
102 class CheckLastPush(Step): 103 class CheckLastPush(Step):
103 MESSAGE = "Checking last V8 push to trunk." 104 MESSAGE = "Checking last V8 push to trunk."
104 105
105 def RunStep(self): 106 def RunStep(self):
106 last_push_hash = self.FindLastTrunkPush() 107 self.RestoreIfUnset("latest")
107 last_push = int(self.GitSVNFindSVNRev(last_push_hash)) 108 log = self.Git("svn log -1 --oneline ChangeLog").strip()
108 109 match = re.match(r"^r(\d+) \| Prepare push to trunk", log)
109 # TODO(machenbach): This metric counts all revisions. It could be 110 if match:
110 # improved by counting only the revisions on bleeding_edge. 111 latest = int(self._state["latest"])
111 if int(self["latest"]) - last_push < 10: 112 last_push = int(match.group(1))
112 # This makes sure the script doesn't push twice in a row when the cron 113 # TODO(machebach): This metric counts all revisions. It could be
113 # job retries several times. 114 # improved by counting only the revisions on bleeding_edge.
114 self.Die("Last push too recently: %d" % last_push) 115 if latest - last_push < 10:
116 # This makes sure the script doesn't push twice in a row when the cron
117 # job retries several times.
118 self.Die("Last push too recently: %d" % last_push)
115 119
116 120
117 class FetchLKGR(Step): 121 class FetchLKGR(Step):
118 MESSAGE = "Fetching V8 LKGR." 122 MESSAGE = "Fetching V8 LKGR."
119 123
120 def RunStep(self): 124 def RunStep(self):
121 lkgr_url = "https://v8-status.appspot.com/lkgr" 125 lkgr_url = "https://v8-status.appspot.com/lkgr"
122 # Retry several times since app engine might have issues. 126 # Retry several times since app engine might have issues.
123 self["lkgr"] = self.ReadURL(lkgr_url, wait_plan=[5, 20, 300, 300]) 127 self.Persist("lkgr", self.ReadURL(lkgr_url, wait_plan=[5, 20, 300, 300]))
124 128
125 129
126 class PushToTrunk(Step): 130 class PushToTrunk(Step):
127 MESSAGE = "Pushing to trunk if possible." 131 MESSAGE = "Pushing to trunk if possible."
128 132
129 def PushTreeStatus(self, message): 133 def PushTreeStatus(self, message):
130 if not self._options.status_password: 134 if not self._options.status_password:
131 print "Skipping tree status update without password file." 135 print "Skipping tree status update without password file."
132 return 136 return
133 params = { 137 params = {
134 "message": message, 138 "message": message,
135 "username": "v8-auto-roll@chromium.org", 139 "username": "v8-auto-roll@chromium.org",
136 "password": FileToText(self._options.status_password).strip(), 140 "password": FileToText(self._options.status_password).strip(),
137 } 141 }
138 params = urllib.urlencode(params) 142 params = urllib.urlencode(params)
139 print "Pushing tree status: '%s'" % message 143 print "Pushing tree status: '%s'" % message
140 self.ReadURL("https://v8-status.appspot.com/status", params, 144 self.ReadURL("https://v8-status.appspot.com/status", params,
141 wait_plan=[5, 20]) 145 wait_plan=[5, 20])
142 146
143 def RunStep(self): 147 def RunStep(self):
144 latest = int(self["latest"]) 148 self.RestoreIfUnset("latest")
145 lkgr = int(self["lkgr"]) 149 self.RestoreIfUnset("lkgr")
150 self.RestoreIfUnset("tree_message")
151 latest = int(self._state["latest"])
152 lkgr = int(self._state["lkgr"])
146 if latest == lkgr: 153 if latest == lkgr:
147 print "ToT (r%d) is clean. Pushing to trunk." % latest 154 print "ToT (r%d) is clean. Pushing to trunk." % latest
148 self.PushTreeStatus("Tree is closed (preparing to push)") 155 self.PushTreeStatus("Tree is closed (preparing to push)")
149 156
157 # TODO(machenbach): Call push to trunk script.
150 # TODO(machenbach): Update the script before calling it. 158 # TODO(machenbach): Update the script before calling it.
151 try: 159 try:
152 if self._options.push: 160 if self._options.push:
153 self._side_effect_handler.Call( 161 self._side_effect_handler.Call(
154 RunPushToTrunk, 162 RunPushToTrunk,
155 push_to_trunk.CONFIG, 163 push_to_trunk.CONFIG,
156 PushToTrunkOptions.MakeForcedOptions(self._options.author, 164 PushToTrunkOptions.MakeForcedOptions(self._options.r,
157 self._options.reviewer,
158 self._options.c), 165 self._options.c),
159 self._side_effect_handler) 166 self._side_effect_handler)
160 finally: 167 finally:
161 self.PushTreeStatus(self["tree_message"]) 168 self.PushTreeStatus(self._state["tree_message"])
162 else: 169 else:
163 print("ToT (r%d) is ahead of the LKGR (r%d). Skipping push to trunk." 170 print("ToT (r%d) is ahead of the LKGR (r%d). Skipping push to trunk."
164 % (latest, lkgr)) 171 % (latest, lkgr))
165 172
166 173
167 def RunAutoRoll(config, 174 def RunAutoRoll(config,
168 options, 175 options,
169 side_effect_handler=DEFAULT_SIDE_EFFECT_HANDLER): 176 side_effect_handler=DEFAULT_SIDE_EFFECT_HANDLER):
170 step_classes = [ 177 step_classes = [
171 Preparation, 178 Preparation,
172 CheckAutoRollSettings, 179 CheckAutoRollSettings,
173 CheckTreeStatus, 180 CheckTreeStatus,
174 FetchLatestRevision, 181 FetchLatestRevision,
175 CheckLastPush, 182 CheckLastPush,
176 FetchLKGR, 183 FetchLKGR,
177 PushToTrunk, 184 PushToTrunk,
178 ] 185 ]
179 RunScript(step_classes, config, options, side_effect_handler) 186 RunScript(step_classes, config, options, side_effect_handler)
180 187
181 188
182 def BuildOptions(): 189 def BuildOptions():
183 parser = argparse.ArgumentParser() 190 result = optparse.OptionParser()
184 parser.add_argument("-a", "--author", dest="a", 191 result.add_option("-c", "--chromium", dest="c",
185 help="The author email used for rietveld.") 192 help=("Specify the path to your Chromium src/ "
186 parser.add_argument("-c", "--chromium", dest="c", 193 "directory to automate the V8 roll."))
187 help=("The path to your Chromium src/ directory to " 194 result.add_option("-p", "--push",
188 "automate the V8 roll.")) 195 help="Push to trunk if possible. Dry run if unspecified.",
189 parser.add_argument("-p", "--push", 196 default=False, action="store_true")
190 help="Push to trunk if possible. Dry run if unspecified.", 197 result.add_option("-r", "--reviewer", dest="r",
191 default=False, action="store_true") 198 help=("Specify the account name to be used for reviews."))
192 parser.add_argument("-r", "--reviewer", 199 result.add_option("-s", "--step", dest="s",
193 help="The account name to be used for reviews.") 200 help="Specify the step where to start work. Default: 0.",
194 parser.add_argument("-s", "--step", dest="s", 201 default=0, type="int")
195 help="Specify the step where to start work. Default: 0.", 202 result.add_option("--status-password",
196 default=0, type=int) 203 help="A file with the password to the status app.")
197 parser.add_argument("--status-password", 204 return result
198 help="A file with the password to the status app.")
199 return parser
200 205
201 206
202 def Main(): 207 def Main():
203 parser = BuildOptions() 208 parser = BuildOptions()
204 options = parser.parse_args() 209 (options, args) = parser.parse_args()
205 if not options.a or not options.c or not options.reviewer: 210 if not options.c or not options.r:
206 print "You need to specify author, chromium src location and reviewer." 211 print "You need to specify the chromium src location and a reviewer."
207 parser.print_help() 212 parser.print_help()
208 return 1 213 return 1
209 RunAutoRoll(CONFIG, AutoRollOptions(options)) 214 RunAutoRoll(CONFIG, AutoRollOptions(options))
210 215
211 if __name__ == "__main__": 216 if __name__ == "__main__":
212 sys.exit(Main()) 217 sys.exit(Main())
OLDNEW
« no previous file with comments | « tools/merge-to-branch.sh ('k') | tools/push-to-trunk/common_includes.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698