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, 2:13 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
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'])
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!')
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(path, 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', path]) 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))
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
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 '
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:
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'):
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
121 103
122 104
123 def run(baseDir, type, version, keyFile, downloadsRepo, path='default'): 105 def can_safely_release(*repo_paths):
124 # run repository-checks and bail out early, in case the user does not 106 """Run repository-checks in order to bail out early if necessary"""
125 # explicitly want to continue OR if the check would cause the process to 107 if repo_has_uncommitted():
126 # abort anyway 108 return False
127 repo_checks = ( 109 if repo_has_incoming(*repo_paths):
128 (repo_has_uncommitted, ()), 110 return False
129 (repo_has_outgoing, (path,)), 111 if repo_has_outgoing():
130 (repo_has_incoming, ((baseDir, downloadsRepo),)), 112 return continue_with_outgoing()
131 )
132 113
133 check_results = [func(*args) for func, args in repo_checks]
134 114
135 if ( 115 def run(baseDir, type, version, keyFile, downloadsRepo):
136 any(check and aborts for check, aborts in check_results) 116 if not can_safely_release(baseDir, downloadsRepo):
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