def push_derived( self, name: str, hoster: Optional[Hoster] = None, overwrite_existing: Optional[bool] = False, owner: Optional[str] = None, tags: Optional[Union[Dict[str, bytes], List[str]]] = None, stop_revision: Optional[bytes] = None, ) -> Tuple[Branch, str]: """Push a derived branch. Args: name: Branch name hoster: Optional hoster to use overwrite_existing: Whether to overwrite an existing branch tags: Tags list to push owner: Owner name Returns: tuple with remote_branch and public_branch_url """ if hoster is None: hoster = get_hoster(self.main_branch) return push_derived_changes( self.local_tree.branch, self.main_branch, hoster, name, overwrite_existing=overwrite_existing, owner=owner, tags=tags, stop_revision=stop_revision, )
def push( self, hoster: Optional[Hoster] = None, dry_run: bool = False, tags: Optional[Union[Dict[str, bytes], List[str]]] = None, stop_revision: Optional[bytes] = None, ) -> None: if hoster is None: try: hoster = get_hoster(self.main_branch) except UnsupportedHoster: if isinstance(self.main_branch.control_transport, LocalTransport): hoster = None else: raise return push_changes( self.local_tree.branch, self.main_branch, hoster=hoster, additional_colocated_branches=self.additional_colocated_branches, dry_run=dry_run, tags=tags, stop_revision=stop_revision, )
def push( self, hoster: Optional[Hoster] = None, dry_run: bool = False, tags: Optional[Union[Dict[str, bytes], List[str]]] = None, stop_revision: Optional[bytes] = None, ) -> None: if hoster is None: try: hoster = get_hoster(self.main_branch) except UnsupportedHoster: if not isinstance(self.main_branch.control_transport, LocalTransport): logging.warning( 'Unable to find hoster for %s to determine push url, ' 'trying anyway.', self.main_branch.user_url) hoster = None return push_changes( self.local_tree.branch, self.main_branch, hoster=hoster, additional_colocated_branches=self._inverse_additional_colocated_branches(), dry_run=dry_run, tags=tags, stop_revision=stop_revision, )
def push_to_salsa(local_tree, orig_branch, user, name, dry_run=False): from breezy import urlutils from breezy.branch import Branch from breezy.errors import PermissionDenied from breezy.propose import UnsupportedHoster, get_hoster, HosterLoginRequired from breezy.plugins.gitlab.hoster import GitLab if dry_run: logging.info("Creating and pushing to salsa project %s/%s", user, name) return try: salsa = GitLab.probe_from_url("https://salsa.debian.org/") except HosterLoginRequired: logging.warning("No login for salsa known, not pushing branch.") return try: orig_hoster = get_hoster(orig_branch) except UnsupportedHoster: logging.debug("Original branch %r not hosted on salsa.") from_project = None else: if orig_hoster == salsa: from_project = urlutils.from_string( orig_branch.controldir.user_url).path else: from_project = None if from_project is not None: salsa.fork_project(from_project, owner=user) else: try: salsa.create_project("%s/%s" % (user, name)) except PermissionDenied as e: logging.info('No permission to create new project under %s: %s', user, e) return target_branch = Branch.open("git+ssh://[email protected]/%s/%s.git" % (user, name)) additional_colocated_branches = pick_additional_colocated_branches( local_tree.branch) return push_changes( local_tree.branch, target_branch, hoster=salsa, additional_colocated_branches=additional_colocated_branches, dry_run=dry_run, )
def propose( self, name: str, description: str, hoster: Optional[Hoster] = None, existing_proposal: Optional[MergeProposal] = None, overwrite_existing: Optional[bool] = None, labels: Optional[List[str]] = None, dry_run: bool = False, commit_message: Optional[str] = None, reviewers: Optional[List[str]] = None, tags: Optional[Union[Dict[str, bytes], List[str]]] = None, owner: Optional[str] = None, allow_collaboration: bool = False, stop_revision: Optional[bytes] = None, ) -> MergeProposal: if hoster is None: hoster = get_hoster(self.main_branch) return propose_changes( self.local_tree.branch, self.main_branch, hoster=hoster, name=name, mp_description=description, resume_branch=self.resume_branch, resume_proposal=existing_proposal, overwrite_existing=(overwrite_existing or False), labels=labels, dry_run=dry_run, commit_message=commit_message, reviewers=reviewers, owner=owner, additional_colocated_branches=self.additional_colocated_branches, tags=tags, allow_collaboration=allow_collaboration, stop_revision=stop_revision, )
def publish_changes( local_branch: Branch, main_branch: Branch, resume_branch: Optional[Branch], mode: str, name: str, get_proposal_description: Callable[[str, Optional[MergeProposal]], str], get_proposal_commit_message: Callable[ [Optional[MergeProposal]], Optional[str] ] = None, dry_run: bool = False, hoster: Optional[Hoster] = None, allow_create_proposal: bool = True, labels: Optional[List[str]] = None, overwrite_existing: Optional[bool] = True, existing_proposal: Optional[MergeProposal] = None, reviewers: Optional[List[str]] = None, tags: Optional[Union[List[str], Dict[str, bytes]]] = None, derived_owner: Optional[str] = None, allow_collaboration: bool = False, stop_revision: Optional[bytes] = None, ) -> PublishResult: """Publish a set of changes. Args: ws: Workspace to push from mode: Mode to use ('push', 'push-derived', 'propose') name: Branch name to push get_proposal_description: Function to retrieve proposal description get_proposal_commit_message: Function to retrieve proposal commit message dry_run: Whether to dry run hoster: Hoster, if known allow_create_proposal: Whether to allow creating proposals labels: Labels to set for any merge proposals overwrite_existing: Whether to overwrite existing (but unrelated) branch existing_proposal: Existing proposal to update reviewers: List of reviewers for merge proposal tags: Tags to push (None for default behaviour) derived_owner: Name of any derived branch allow_collaboration: Whether to allow target branch owners to modify source branch. """ if mode not in SUPPORTED_MODES: raise ValueError("invalid mode %r" % mode) if stop_revision is None: stop_revision = local_branch.last_revision() if stop_revision == main_branch.last_revision(): if existing_proposal is not None: logging.info("closing existing merge proposal - no new revisions") existing_proposal.close() return PublishResult(mode) if resume_branch and resume_branch.last_revision() == stop_revision: # No new revisions added on this iteration, but changes since main # branch. We may not have gotten round to updating/creating the # merge proposal last time. logging.info("No changes added; making sure merge proposal is up to date.") if hoster is None: hoster = get_hoster(main_branch) if mode == MODE_PUSH_DERIVED: (remote_branch, public_url) = push_derived_changes( local_branch, main_branch, hoster=hoster, name=name, overwrite_existing=overwrite_existing, tags=tags, owner=derived_owner, stop_revision=stop_revision, ) return PublishResult(mode) if mode in (MODE_PUSH, MODE_ATTEMPT_PUSH): try: # breezy would do this check too, but we want to be *really* sure. with local_branch.lock_read(): graph = local_branch.repository.get_graph() if not graph.is_ancestor(main_branch.last_revision(), stop_revision): raise errors.DivergedBranches(main_branch, local_branch) push_changes( local_branch, main_branch, hoster=hoster, dry_run=dry_run, tags=tags, stop_revision=stop_revision, ) except errors.PermissionDenied: if mode == MODE_ATTEMPT_PUSH: logging.info("push access denied, falling back to propose") mode = MODE_PROPOSE else: logging.info("permission denied during push") raise else: return PublishResult(mode=mode) assert mode == "propose" if not resume_branch and not allow_create_proposal: raise InsufficientChangesForNewProposal() mp_description = get_proposal_description( getattr(hoster, "merge_proposal_description_format", "plain"), existing_proposal if resume_branch else None, ) if get_proposal_commit_message is not None: commit_message = get_proposal_commit_message( existing_proposal if resume_branch else None ) (proposal, is_new) = propose_changes( local_branch, main_branch, hoster=hoster, name=name, mp_description=mp_description, resume_branch=resume_branch, resume_proposal=existing_proposal, overwrite_existing=overwrite_existing, labels=labels, dry_run=dry_run, commit_message=commit_message, reviewers=reviewers, tags=tags, owner=derived_owner, allow_collaboration=allow_collaboration, stop_revision=stop_revision, ) return PublishResult(mode, proposal, is_new)