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

Side by Side Diff: git_cl.py

Issue 1991563005: Add "archive" command to git_cl.py. (Closed) Base URL: https://chromium.googlesource.com/chromium/tools/depot_tools.git@master
Patch Set: Created 4 years, 7 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
« no previous file with comments | « no previous file | no next file » | 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 (c) 2012 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 # Copyright (C) 2008 Evan Martin <martine@danga.com> 6 # Copyright (C) 2008 Evan Martin <martine@danga.com>
7 7
8 """A git-command for integrating reviews on Rietveld and Gerrit.""" 8 """A git-command for integrating reviews on Rietveld and Gerrit."""
9 9
10 from distutils.version import LooseVersion 10 from distutils.version import LooseVersion
(...skipping 2911 matching lines...) Expand 10 before | Expand all | Expand 10 after
2922 def fetch_cl_status(branch, auth_config=None): 2922 def fetch_cl_status(branch, auth_config=None):
2923 """Fetches information for an issue and returns (branch, issue, status).""" 2923 """Fetches information for an issue and returns (branch, issue, status)."""
2924 cl = Changelist(branchref=branch, auth_config=auth_config) 2924 cl = Changelist(branchref=branch, auth_config=auth_config)
2925 url = cl.GetIssueURL() 2925 url = cl.GetIssueURL()
2926 status = cl.GetStatus() 2926 status = cl.GetStatus()
2927 2927
2928 if url and (not status or status == 'error'): 2928 if url and (not status or status == 'error'):
2929 # The issue probably doesn't exist anymore. 2929 # The issue probably doesn't exist anymore.
2930 url += ' (broken)' 2930 url += ' (broken)'
2931 2931
2932 return (branch, url, status) 2932 return (branch, cl.GetIssue(), url, status)
2933 2933
2934 def get_cl_statuses( 2934 def get_cl_statuses(
2935 branches, fine_grained, max_processes=None, auth_config=None): 2935 branches, fine_grained, max_processes=None, auth_config=None):
2936 """Returns a blocking iterable of (branch, issue, status) for given branches. 2936 """Returns a blocking iterable of (branch, issue ID, issue URL, status) for
2937 given branches.
2937 2938
2938 If fine_grained is true, this will fetch CL statuses from the server. 2939 If fine_grained is true, this will fetch CL statuses from the server.
2939 Otherwise, simply indicate if there's a matching url for the given branches. 2940 Otherwise, simply indicate if there's a matching url for the given branches.
2940 2941
2941 If max_processes is specified, it is used as the maximum number of processes 2942 If max_processes is specified, it is used as the maximum number of processes
2942 to spawn to fetch CL status from the server. Otherwise 1 process per branch is 2943 to spawn to fetch CL status from the server. Otherwise 1 process per branch is
2943 spawned. 2944 spawned.
2944 2945
2945 See GetStatus() for a list of possible statuses. 2946 See GetStatus() for a list of possible statuses.
2946 """ 2947 """
2947 def fetch(branch): 2948 def fetch(branch):
2948 if not branch: 2949 if not branch:
2949 return None 2950 return None
2950 2951
2951 return fetch_cl_status(branch, auth_config=auth_config) 2952 return fetch_cl_status(branch, auth_config=auth_config)
2952 2953
2953 # Silence upload.py otherwise it becomes unwieldly. 2954 # Silence upload.py otherwise it becomes unwieldly.
2954 upload.verbosity = 0 2955 upload.verbosity = 0
2955 2956
2956 if fine_grained: 2957 if fine_grained:
2957 # Process one branch synchronously to work through authentication, then 2958 # Process one branch synchronously to work through authentication, then
2958 # spawn processes to process all the other branches in parallel. 2959 # spawn processes to process all the other branches in parallel.
2959 if branches: 2960 if branches:
2960 2961
2961 yield fetch(branches[0]) 2962 yield fetch(branches[0])
2962 2963
2963 branches_to_fetch = branches[1:] 2964 branches_to_fetch = branches[1:]
2965 if len(branches_to_fetch) == 0:
2966 # Exit early if there was only one branch to fetch.
2967 return
tandrii(chromium) 2016/05/20 20:56:19 are you sure this works? I thought return can't be
Kevin M 2016/05/20 22:18:14 "return" from a generator raises a StopIteration.
2968
2964 pool = ThreadPool( 2969 pool = ThreadPool(
2965 min(max_processes, len(branches_to_fetch)) 2970 min(max_processes, len(branches_to_fetch))
2966 if max_processes is not None 2971 if max_processes is not None
2967 else len(branches_to_fetch)) 2972 else len(branches_to_fetch))
2968 2973
2969 fetched_branches = set() 2974 fetched_branches = set()
2970 it = pool.imap_unordered(fetch, branches_to_fetch).__iter__() 2975 it = pool.imap_unordered(fetch, branches_to_fetch).__iter__()
2971 while True: 2976 while True:
2972 try: 2977 try:
2973 row = it.next(timeout=5) 2978 row = it.next(timeout=5)
2974 except multiprocessing.TimeoutError: 2979 except multiprocessing.TimeoutError:
2975 break 2980 break
2976 2981
2977 fetched_branches.add(row[0]) 2982 fetched_branches.add(row[0])
2978 yield row 2983 yield row
2979 2984
2980 # Add any branches that failed to fetch. 2985 # Add any branches that failed to fetch.
2981 for b in set(branches_to_fetch) - fetched_branches: 2986 for b in set(branches_to_fetch) - fetched_branches:
2982 cl = Changelist(branchref=b, auth_config=auth_config) 2987 cl = Changelist(branchref=b, auth_config=auth_config)
2983 yield (b, cl.GetIssueURL() if b else None, 'error') 2988 yield (b, cl.GetIssue(), cl.GetIssueURL() if b else None, 'error')
2984 2989
2985 else: 2990 else:
2986 # Do not use GetApprovingReviewers(), since it requires an HTTP request. 2991 # Do not use GetApprovingReviewers(), since it requires an HTTP request.
2987 for b in branches: 2992 for b in branches:
2988 cl = Changelist(branchref=b, auth_config=auth_config) 2993 cl = Changelist(branchref=b, auth_config=auth_config)
2989 url = cl.GetIssueURL() if b else None 2994 url = cl.GetIssueURL() if b else None
2990 yield (b, url, 'waiting' if url else 'error') 2995 yield (b, cl.GetIssue(), url, 'waiting' if url else 'error')
2991 2996
2992 2997
2993 def upload_branch_deps(cl, args): 2998 def upload_branch_deps(cl, args):
2994 """Uploads CLs of local branches that are dependents of the current branch. 2999 """Uploads CLs of local branches that are dependents of the current branch.
2995 3000
2996 If the local branch dependency tree looks like: 3001 If the local branch dependency tree looks like:
2997 test1 -> test2.1 -> test3.1 3002 test1 -> test2.1 -> test3.1
2998 -> test3.2 3003 -> test3.2
2999 -> test2.2 -> test3.3 3004 -> test2.2 -> test3.3
3000 3005
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
3082 3087
3083 print 3088 print
3084 print 'Upload complete for dependent branches!' 3089 print 'Upload complete for dependent branches!'
3085 for dependent_branch in dependents: 3090 for dependent_branch in dependents:
3086 upload_status = 'failed' if failures.get(dependent_branch) else 'succeeded' 3091 upload_status = 'failed' if failures.get(dependent_branch) else 'succeeded'
3087 print ' %s : %s' % (dependent_branch, upload_status) 3092 print ' %s : %s' % (dependent_branch, upload_status)
3088 print 3093 print
3089 3094
3090 return 0 3095 return 0
3091 3096
3097 def CMDcleanup(parser, args):
3098 """Archives closed branches from the Git using tags and removes them from
3099 the Git branch list."""
3100 parser.add_option(
3101 '-j', '--maxjobs', action='store', type=int,
3102 help='The maximum number of jobs to use when retrieving review status')
3103
3104 parser.add_option(
3105 '-y', action='store_true', dest='no_prompt', default=False,
tandrii(chromium) 2016/05/20 20:56:19 -f, --force to be inline with other cmds.
Kevin M 2016/05/20 22:18:14 Done.
3106 help='Bypasses the confirmation prompt.')
3107
3108 auth.add_auth_options(parser)
3109 options, args = parser.parse_args(args)
3110 if args:
3111 parser.error('Unsupported args: %s' % args)
3112 auth_config = auth.extract_auth_config_from_options(options)
3113
3114 branches = RunGit(['for-each-ref', '--format=%(refname)', 'refs/heads'])
3115 if not branches:
3116 print('No local branch found.')
tandrii(chromium) 2016/05/20 20:56:19 nit: why parenthesis here and not below?
Kevin M 2016/05/20 22:18:14 C++ habits, I guess. Done.
3117 return 0
3118
3119 print 'Finding all branches associated with closed issues...'
3120 changes = (
3121 Changelist(branchref=b, auth_config=auth_config)
3122 for b in branches.splitlines())
3123 branches = [c.GetBranch() for c in changes]
martiniss 2016/05/20 03:11:55 Any reason to not combine this and the previous li
Kevin M 2016/05/20 16:54:41 No reason other than avoiding nested list comprehe
3124 alignment = max(5, max(len(b) for b in branches))
3125 branch_statuses = get_cl_statuses(branches,
3126 fine_grained=True,
3127 max_processes=options.maxjobs,
3128 auth_config=auth_config)
3129 proposal = [(branch, 'submitted-%s-%s' % (branch, issue_id))
3130 for branch, issue_id, _, status in branch_statuses
3131 if status == 'closed']
3132
3133 if len(proposal) == 0:
3134 print 'No closed branches found.'
3135 return 0
3136
3137 print '\nBranches with closed issues that will be tagged and deleted:'
3138 print "%*s | %s" % (alignment, "Branch name", "Archival tag name")
3139 for next_item in proposal:
3140 print '%*s %s' % (alignment, next_item[0], next_item[1])
3141
3142 prompt = None
3143 if not options.no_prompt:
3144 prompt = raw_input('\nProceed with deletion (Y/N)? ')
3145 if prompt == 'Y' or prompt == 'y' or options.no_prompt:
3146 for next_item in proposal:
3147 branch, tagname = next_item
3148 RunGit(['tag', tagname, branch])
martiniss 2016/05/20 03:11:55 What is the purpose of tagging the branch? Bookkee
Kevin M 2016/05/20 16:54:41 The tags allow you to access your local Git commit
3149 RunGit(['branch', '-D', branch])
3150 print '\nJob\'s done!'
3151 else:
3152 print 'Aborted.'
3153
3154 return 0
3092 3155
3093 def CMDstatus(parser, args): 3156 def CMDstatus(parser, args):
3094 """Show status of changelists. 3157 """Show status of changelists.
3095 3158
3096 Colors are used to tell the state of the CL unless --fast is used: 3159 Colors are used to tell the state of the CL unless --fast is used:
3097 - Red not sent for review or broken 3160 - Red not sent for review or broken
3098 - Blue waiting for review 3161 - Blue waiting for review
3099 - Yellow waiting for you to reply to review 3162 - Yellow waiting for you to reply to review
3100 - Green LGTM'ed 3163 - Green LGTM'ed
3101 - Magenta in the commit queue 3164 - Magenta in the commit queue
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
3149 print 'Branches associated with reviews:' 3212 print 'Branches associated with reviews:'
3150 output = get_cl_statuses(branches, 3213 output = get_cl_statuses(branches,
3151 fine_grained=not options.fast, 3214 fine_grained=not options.fast,
3152 max_processes=options.maxjobs, 3215 max_processes=options.maxjobs,
3153 auth_config=auth_config) 3216 auth_config=auth_config)
3154 3217
3155 branch_statuses = {} 3218 branch_statuses = {}
3156 alignment = max(5, max(len(ShortBranchName(b)) for b in branches)) 3219 alignment = max(5, max(len(ShortBranchName(b)) for b in branches))
3157 for branch in sorted(branches): 3220 for branch in sorted(branches):
3158 while branch not in branch_statuses: 3221 while branch not in branch_statuses:
3159 b, i, status = output.next() 3222 b, _, i, status = output.next()
3160 branch_statuses[b] = (i, status) 3223 branch_statuses[b] = (i, status)
3161 issue_url, status = branch_statuses.pop(branch) 3224 issue_url, status = branch_statuses.pop(branch)
3162 color = color_for_status(status) 3225 color = color_for_status(status)
3163 reset = Fore.RESET 3226 reset = Fore.RESET
3164 if not setup_color.IS_TTY: 3227 if not setup_color.IS_TTY:
3165 color = '' 3228 color = ''
3166 reset = '' 3229 reset = ''
3167 status_str = '(%s)' % status if status else '' 3230 status_str = '(%s)' % status if status else ''
3168 print ' %*s : %s%s %s%s' % ( 3231 print ' %*s : %s%s %s%s' % (
3169 alignment, ShortBranchName(branch), color, issue_url, status_str, 3232 alignment, ShortBranchName(branch), color, issue_url, status_str,
(...skipping 1731 matching lines...) Expand 10 before | Expand all | Expand 10 after
4901 if __name__ == '__main__': 4964 if __name__ == '__main__':
4902 # These affect sys.stdout so do it outside of main() to simplify mocks in 4965 # These affect sys.stdout so do it outside of main() to simplify mocks in
4903 # unit testing. 4966 # unit testing.
4904 fix_encoding.fix_encoding() 4967 fix_encoding.fix_encoding()
4905 setup_color.init() 4968 setup_color.init()
4906 try: 4969 try:
4907 sys.exit(main(sys.argv[1:])) 4970 sys.exit(main(sys.argv[1:]))
4908 except KeyboardInterrupt: 4971 except KeyboardInterrupt:
4909 sys.stderr.write('interrupted\n') 4972 sys.stderr.write('interrupted\n')
4910 sys.exit(1) 4973 sys.exit(1)
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698