Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Delta Between Two Patch Sets: releaseAutomation.py

Issue 29508667: Issue 4354, 4355 - handle dirty/outdated repos on release (Closed)
Left Patch Set: Created Aug. 7, 2017, 3:40 p.m.
Right Patch Set: Created Aug. 16, 2017, 11:24 a.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « no previous file | no next file » | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 # This Source Code Form is subject to the terms of the Mozilla Public 1 # This Source Code Form is subject to the terms of the Mozilla Public
2 # License, v. 2.0. If a copy of the MPL was not distributed with this 2 # License, v. 2.0. If a copy of the MPL was not distributed with this
3 # file, You can obtain one at http://mozilla.org/MPL/2.0/. 3 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
4
5 from __future__ import print_function
4 6
5 import os 7 import os
6 import re 8 import re
7 import codecs 9 import codecs
8 import subprocess 10 import subprocess
9 import tarfile 11 import tarfile
10 import json 12 import json
11
Vasily Kuznetsov 2017/08/08 18:10:12 There's no need for this empty line. The imports f
tlucas 2017/08/09 08:12:35 Acknowledged.
tlucas 2017/08/15 14:40:12 Done.
12 from itertools import groupby
13 13
14 from packager import readMetadata, getDefaultFileName 14 from packager import readMetadata, getDefaultFileName
15 15
16 16
17 def get_dependencies(prefix, repos): 17 def get_dependencies(prefix, repos):
18 from ensure_dependencies import read_deps, safe_join 18 from ensure_dependencies import read_deps, safe_join
19 repo = repos[prefix] 19 repo = repos[prefix]
20 deps = read_deps(repo) 20 deps = read_deps(repo)
21 if deps: 21 if deps:
22 for subpath in deps: 22 for subpath in deps:
(...skipping 17 matching lines...) Expand all
40 if os.path.basename(fileinfo.name) in ('.hgtags', '.hgig nore'): 40 if os.path.basename(fileinfo.name) in ('.hgtags', '.hgig nore'):
41 continue 41 continue
42 filedata = repoarchive.extractfile(fileinfo) 42 filedata = repoarchive.extractfile(fileinfo)
43 fileinfo.name = re.sub(r'^[^/]+/', prefix, fileinfo.name ) 43 fileinfo.name = re.sub(r'^[^/]+/', prefix, fileinfo.name )
44 archive.addfile(fileinfo, filedata) 44 archive.addfile(fileinfo, filedata)
45 finally: 45 finally:
46 process.stdout.close() 46 process.stdout.close()
47 process.wait() 47 process.wait()
48 48
49 49
50 def repo_has_uncommitted(aborts_process=True): 50 def repo_has_uncommitted():
51 """Checks if the given repository is clean""" 51 """Checks if the given repository is clean"""
52 uncommitted = False 52 buff = subprocess.check_output(['hg', 'status'])
Vasily Kuznetsov 2017/08/08 18:10:12 You're spending quite some effort reformatting the
tlucas 2017/08/09 08:12:35 Acknowledged.
tlucas 2017/08/15 14:40:12 Done.
53 status_mapping = {
54 'M': 'modified',
55 'A': 'added',
56 'R': 'removed',
57 '!': 'missing',
58 '?': 'untracked',
59 }
60 53
61 # Check for any uncommitted changes
62 buff = subprocess.check_output(['hg', 'status'])
63 if len(buff): 54 if len(buff):
64 uncommitted = True
65 dirty_files = buff.strip().split(os.linesep)
66 print('Dirty / uncommitted changes in repository!') 55 print('Dirty / uncommitted changes in repository!')
Vasily Kuznetsov 2017/08/08 18:10:11 Using print as a function only seems to work under
tlucas 2017/08/09 08:12:35 Acknowledged.
tlucas 2017/08/15 14:40:12 Done.
67 grouped_dirty = groupby(dirty_files, key=lambda x: x.split(' ')[0]) 56 return True
68 for dirty_grp in grouped_dirty:
69 print('{}:'.format(status_mapping[dirty_grp[0]]))
70 for dirty in dirty_grp[1]:
71 print(' {}'.format(dirty.split(' ')[1]))
72 57
73 return uncommitted, aborts_process 58 return False
74 59
75 60
76 def repo_has_outgoing(aborts_process=False): 61 def repo_has_outgoing():
77 """Checks whether there would be outgoing changesets to the given path""" 62 """Checks whether there would be outgoing changesets to the given path"""
78 try: 63 try:
79 buff = subprocess.check_output(['hg', 'outgoing']) 64 subprocess.check_output(['hg', 'outgoing'])
80 print('Detected outgoing changesets:') 65 print('Detected outgoing changesets!')
81 print(buff) 66 return True
82 return True, aborts_process 67 except subprocess.CalledProcessError as e:
83 except subprocess.CalledProcessError: 68 if e.returncode == 1:
84 return False, aborts_process 69 return False
70 raise
85 71
86 72
87 def repo_has_incoming(repo_paths, aborts_process=True): 73 def repo_has_incoming(*repo_paths):
88 """Checks whether the local repositories are up-to-date""" 74 """Checks whether the local repositories are up-to-date"""
89 incoming = False 75 incoming = False
90 76
91 for repo_path in repo_paths: 77 for repo_path in repo_paths:
92 try: 78 try:
93 buff = subprocess.check_output(['hg', 'incoming', '-R', repo_path]) 79 subprocess.check_output(['hg', 'incoming', '-R', repo_path])
94 print('Detected incoming changesets:') 80 print('Detected incoming changesets in "{}"'.format(repo_path))
Vasily Kuznetsov 2017/08/08 18:10:12 Here we're printing the incoming changesets but ac
tlucas 2017/08/09 08:12:35 Acknowledged.
tlucas 2017/08/15 14:40:12 Done.
95 print(buff)
96 incoming = True 81 incoming = True
97 except subprocess.CalledProcessError: 82 except subprocess.CalledProcessError as e:
98 pass 83 if e.returncode != 1:
84 raise
99 85
100 return incoming, aborts_process 86 return incoming
101 87
102 88
103 def ask_to_continue(): 89 def continue_with_outgoing():
104 """Asks the user if he wants to continue despite facing warnings""" 90 """Asks the user if they want to continue despite facing warnings"""
105 try:
106 input = raw_input
Vasily Kuznetsov 2017/08/08 18:10:11 AFAIK, this compatibility trick doesn't work (unde
tlucas 2017/08/09 08:12:34 I tested a snippet of this, but not in function-sc
Vasily Kuznetsov 2017/08/09 17:09:09 Yes, I think it would be the best to ignore Python
tlucas 2017/08/15 14:40:12 Done.
107 except NameError:
108 pass
109 91
110 print('The above error/s has/have been detected within the repositories.') 92 print('If you proceed with the release, they will be included in the '
Vasily Kuznetsov 2017/08/08 18:10:11 I know that you took this from the ticket, but I'm
tlucas 2017/08/09 08:12:35 I like it (and it was actually me, who added this
tlucas 2017/08/15 14:40:12 Done.
111 print('You might want to check whether this is ok or not.') 93 'release and pushed.')
112 print('Are you sure about continuing the release-process?') 94 print('Are you sure about continuing the release process?')
95
113 while True: 96 while True:
Vasily Kuznetsov 2017/08/08 18:10:11 What do you think about rewriting this loop, and t
tlucas 2017/08/09 08:12:35 Acknowledged.
tlucas 2017/08/15 14:40:12 Done.
114 choice = input('Please choose (yes / no): ') 97 choice = raw_input('Please choose (yes / no): ').lower().strip()
115 if choice.lower() not in ('yes', 'no'):
Vasily Kuznetsov 2017/08/08 18:10:11 ('yes', 'no') should be a set (this is error A102
tlucas 2017/08/09 08:12:35 This is removed while following your proposed appr
tlucas 2017/08/15 14:40:12 Done. Kept the reminder on what to specifically en
116 print('Please answer "yes" or "no"!')
117 else:
118 break
119 98
120 return choice.lower() == 'yes' 99 if choice == 'yes':
100 return True
101 if choice == 'no':
102 return False
103
104
105 def can_safely_release(*repo_paths):
106 """Run repository-checks in order to bail out early if necessary"""
107 if repo_has_uncommitted():
108 return False
109 if repo_has_incoming(*repo_paths):
110 return False
111 if repo_has_outgoing():
112 return continue_with_outgoing()
121 113
122 114
123 def run(baseDir, type, version, keyFile, downloadsRepo): 115 def run(baseDir, type, version, keyFile, downloadsRepo):
124 # run repository-checks and bail out early, in case the user does not 116 if not can_safely_release(baseDir, downloadsRepo):
125 # explicitly want to continue OR if the check would cause the process to
126 # abort anyway
127 repo_checks = (
Vasily Kuznetsov 2017/08/08 18:10:11 I think the new code in this function is unnecessa
tlucas 2017/08/09 08:12:35 Acknowledged. I'll also rename the function accord
tlucas 2017/08/15 14:40:12 Done.
128 (repo_has_uncommitted, ()),
129 (repo_has_outgoing, ()),
130 (repo_has_incoming, ((baseDir, downloadsRepo),)),
131 )
132
133 check_results = [func(*args) for func, args in repo_checks]
134
135 if (
136 any(check and aborts for check, aborts in check_results)
137 or (
138 any(check and not aborts for check, aborts in check_results)
139 and not ask_to_continue()
140 )):
141 print('Aborting release.') 117 print('Aborting release.')
142 return 1 118 return 1
143 119
144 if type == 'gecko': 120 if type == 'gecko':
145 import buildtools.packagerGecko as packager 121 import buildtools.packagerGecko as packager
146 elif type == 'safari': 122 elif type == 'safari':
147 import buildtools.packagerSafari as packager 123 import buildtools.packagerSafari as packager
148 elif type == 'edge': 124 elif type == 'edge':
149 import buildtools.packagerEdge as packager 125 import buildtools.packagerEdge as packager
150 elif type == 'chrome': 126 elif type == 'chrome':
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
211 create_sourcearchive(baseDir, archivePath) 187 create_sourcearchive(baseDir, archivePath)
212 downloads.append(archivePath) 188 downloads.append(archivePath)
213 189
214 # Now add the downloads and commit 190 # Now add the downloads and commit
215 subprocess.check_call(['hg', 'add', '-R', downloadsRepo] + downloads) 191 subprocess.check_call(['hg', 'add', '-R', downloadsRepo] + downloads)
216 subprocess.check_call(['hg', 'commit', '-R', downloadsRepo, '-m', 'Releasing %s %s' % (extensionName, version)]) 192 subprocess.check_call(['hg', 'commit', '-R', downloadsRepo, '-m', 'Releasing %s %s' % (extensionName, version)])
217 193
218 # Push all changes 194 # Push all changes
219 subprocess.check_call(['hg', 'push', '-R', baseDir]) 195 subprocess.check_call(['hg', 'push', '-R', baseDir])
220 subprocess.check_call(['hg', 'push', '-R', downloadsRepo]) 196 subprocess.check_call(['hg', 'push', '-R', downloadsRepo])
LEFTRIGHT
« no previous file | no next file » | Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Toggle Comments ('s')

Powered by Google App Engine
This is Rietveld