LEFT | RIGHT |
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 Loading... |
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 Loading... |
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]) |
LEFT | RIGHT |