def setUp(self): self.repo = filesystem_mock.MockFileSystem( files={ '/OWNERS': '\n'.join([ 'per-file [email protected]', 'per-file [email protected]', '*****@*****.**', ]), '/approved.cc': '', '/reviewed.h': '', '/bar/insufficient_reviewers.py': '', '/bar/everyone/OWNERS': '*', '/bar/everyone/foo.txt': '', }) self.root = '/' self.fopen = self.repo.open_for_reading mock.patch('owners_client.DepotToolsClient._GetOriginalOwnersFiles', return_value={}).start() self.addCleanup(mock.patch.stopall) self.client = owners_client.DepotToolsClient('host', '/', 'branch', self.fopen, self.repo)
def SplitCl(description_file, comment_file, changelist, cmd_upload, dry_run, cq_dry_run, enable_auto_submit, repository_root): """"Splits a branch into smaller branches and uploads CLs. Args: description_file: File containing the description of uploaded CLs. comment_file: File containing the comment of uploaded CLs. changelist: The Changelist class. cmd_upload: The function associated with the git cl upload command. dry_run: Whether this is a dry run (no branches or CLs created). cq_dry_run: If CL uploads should also do a cq dry run. enable_auto_submit: If CL uploads should also enable auto submit. Returns: 0 in case of success. 1 in case of error. """ description = AddUploadedByGitClSplitToDescription( gclient_utils.FileRead(description_file)) comment = gclient_utils.FileRead(comment_file) if comment_file else None try: EnsureInGitRepository() cl = changelist() upstream = cl.GetCommonAncestorWithUpstream() files = [ (action.strip(), f) for action, f in scm.GIT.CaptureStatus(repository_root, upstream) ] if not files: print('Cannot split an empty CL.') return 1 author = git.run('config', 'user.email').strip() or None refactor_branch = git.current_branch() assert refactor_branch, "Can't run from detached branch." refactor_branch_upstream = git.upstream(refactor_branch) assert refactor_branch_upstream, \ "Branch %s must have an upstream." % refactor_branch client = owners_client.DepotToolsClient( root=repository_root, branch=refactor_branch_upstream) files_split_by_owners = GetFilesSplitByOwners(files) num_cls = len(files_split_by_owners) print('Will split current branch (' + refactor_branch + ') into ' + str(num_cls) + ' CLs.\n') if cq_dry_run and num_cls > CL_SPLIT_FORCE_LIMIT: print( 'This will generate "%r" CLs. This many CLs can potentially generate' ' too much load on the build infrastructure. Please email' ' [email protected] to ensure that this won\'t break anything.' ' The infra team reserves the right to cancel your jobs if they are' ' overloading the CQ.' % num_cls) answer = gclient_utils.AskForData('Proceed? (y/n):') if answer.lower() != 'y': return 0 for cl_index, (directory, files) in \ enumerate(files_split_by_owners.items(), 1): # Use '/' as a path separator in the branch name and the CL description # and comment. directory = directory.replace(os.path.sep, '/') file_paths = [f for _, f in files] reviewers = client.SuggestOwners( file_paths, exclude=[author, owners_client.OwnersClient.EVERYONE]) if dry_run: PrintClInfo(cl_index, num_cls, directory, file_paths, description, reviewers) else: UploadCl(refactor_branch, refactor_branch_upstream, directory, files, description, comment, reviewers, changelist, cmd_upload, cq_dry_run, enable_auto_submit, repository_root) # Go back to the original branch. git.run('checkout', refactor_branch) except subprocess2.CalledProcessError as cpe: sys.stderr.write(cpe.stderr) return 1 return 0
def __init__(self, files, local_root, author, reviewers, fopen, os_path, email_postfix='@chromium.org', disable_color=False, override_files=None, ignore_author=False): self.email_postfix = email_postfix if os.name == 'nt' or disable_color: self.COLOR_LINK = '' self.COLOR_BOLD = '' self.COLOR_GREY = '' self.COLOR_RESET = '' self.os_path = os_path self.author = author filtered_files = files reviewers = list(reviewers) if author and not ignore_author: reviewers.append(author) # Eliminate files that existing reviewers can review. self.client = owners_client.DepotToolsClient( root=local_root, branch=git_common.current_branch(), fopen=fopen, os_path=os_path) approval_status = self.client.GetFilesApprovalStatus( filtered_files, reviewers, []) filtered_files = [ f for f in filtered_files if approval_status[f] != owners_client.OwnersClient.APPROVED ] # If some files are eliminated. if len(filtered_files) != len(files): files = filtered_files self.files_to_owners = self.client.BatchListOwners(files) self.owners_to_files = {} self._map_owners_to_files() self.original_files_to_owners = copy.deepcopy(self.files_to_owners) # This is the queue that will be shown in the interactive questions. # It is initially sorted by the score in descending order. In the # interactive questions a user can choose to "defer" its decision, then the # owner will be put to the end of the queue and shown later. self.owners_queue = [] self.unreviewed_files = set() self.reviewed_by = {} self.selected_owners = set() self.deselected_owners = set() self.reset()