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

Unified Diff: releaseAutomation.py

Issue 29508667: Issue 4354, 4355 - handle dirty/outdated repos on release (Closed)
Patch Set: Created Aug. 7, 2017, 3:40 p.m.
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: releaseAutomation.py
diff --git a/releaseAutomation.py b/releaseAutomation.py
index 5578abf1d948fe185e046cdb70ccd4734fa876ed..82678385338a138fd7e889a3c4f767549bb9c66b 100644
--- a/releaseAutomation.py
+++ b/releaseAutomation.py
@@ -9,6 +9,8 @@ import subprocess
import tarfile
import json
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.
+from itertools import groupby
+
from packager import readMetadata, getDefaultFileName
@@ -45,7 +47,100 @@ def create_sourcearchive(repo, output):
process.wait()
+def repo_has_uncommitted(aborts_process=True):
+ """Checks if the given repository is clean"""
+ uncommitted = False
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.
+ status_mapping = {
+ 'M': 'modified',
+ 'A': 'added',
+ 'R': 'removed',
+ '!': 'missing',
+ '?': 'untracked',
+ }
+
+ # Check for any uncommitted changes
+ buff = subprocess.check_output(['hg', 'status'])
+ if len(buff):
+ uncommitted = True
+ dirty_files = buff.strip().split(os.linesep)
+ 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.
+ grouped_dirty = groupby(dirty_files, key=lambda x: x.split(' ')[0])
+ for dirty_grp in grouped_dirty:
+ print('{}:'.format(status_mapping[dirty_grp[0]]))
+ for dirty in dirty_grp[1]:
+ print(' {}'.format(dirty.split(' ')[1]))
+
+ return uncommitted, aborts_process
+
+
+def repo_has_outgoing(aborts_process=False):
+ """Checks whether there would be outgoing changesets to the given path"""
+ try:
+ buff = subprocess.check_output(['hg', 'outgoing'])
+ print('Detected outgoing changesets:')
+ print(buff)
+ return True, aborts_process
+ except subprocess.CalledProcessError:
+ return False, aborts_process
+
+
+def repo_has_incoming(repo_paths, aborts_process=True):
+ """Checks whether the local repositories are up-to-date"""
+ incoming = False
+
+ for repo_path in repo_paths:
+ try:
+ buff = subprocess.check_output(['hg', 'incoming', '-R', repo_path])
+ print('Detected incoming changesets:')
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.
+ print(buff)
+ incoming = True
+ except subprocess.CalledProcessError:
+ pass
+
+ return incoming, aborts_process
+
+
+def ask_to_continue():
+ """Asks the user if he wants to continue despite facing warnings"""
+ try:
+ 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.
+ except NameError:
+ pass
+
+ print('The above error/s has/have been detected within the repositories.')
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.
+ print('You might want to check whether this is ok or not.')
+ print('Are you sure about continuing the release-process?')
+ 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.
+ choice = input('Please choose (yes / no): ')
+ 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
+ print('Please answer "yes" or "no"!')
+ else:
+ break
+
+ return choice.lower() == 'yes'
+
+
def run(baseDir, type, version, keyFile, downloadsRepo):
+ # run repository-checks and bail out early, in case the user does not
+ # explicitly want to continue OR if the check would cause the process to
+ # abort anyway
+ 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.
+ (repo_has_uncommitted, ()),
+ (repo_has_outgoing, ()),
+ (repo_has_incoming, ((baseDir, downloadsRepo),)),
+ )
+
+ check_results = [func(*args) for func, args in repo_checks]
+
+ if (
+ any(check and aborts for check, aborts in check_results)
+ or (
+ any(check and not aborts for check, aborts in check_results)
+ and not ask_to_continue()
+ )):
+ print('Aborting release.')
+ return 1
+
if type == 'gecko':
import buildtools.packagerGecko as packager
elif type == 'safari':
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld