def create_import_request(git_source_url, project=None, repository=None, organization=None, detect=None): """Create a git import request (currently only supports import from public git source) :param repository: Name or ID of the repository to create the import request in. :type repository: str :param git_source_url: Url of the source git repository :type git_source_url: str """ organization, project, repository = resolve_instance_project_and_repo( detect=detect, organization=organization, project=project, repo=repository, repo_required=True) client = get_git_client(organization) gitImportGitSource = GitImportGitSource(overwrite=False, url=git_source_url) gitImportRequestParameter = GitImportRequestParameters( delete_service_endpoint_after_import_is_done=False, git_source=gitImportGitSource, service_endpoint_id=None, tfvc_source=None) gitImportRequest = GitImportRequest(parameters=gitImportRequestParameter) importRequest = client.create_import_request( import_request=gitImportRequest, project=project, repository_id=repository) return _wait_for_import_request(client, project, repository, importRequest.import_request_id)
def delete_ref(name, object_id=None, repository=None, organization=None, project=None, detect=None): """Delete a reference. :param str name: Name of the reference to delete (example: heads/my_branch). :param str object_id: Id of the reference to delete. :param str repository: Name or ID of the repository. :param str project: Name or ID of the project. :param str detect: Automatically detect organization and project. Default is "on". """ organization, project, repository = resolve_instance_project_and_repo( detect=detect, organization=organization, project=project, repo=repository) client = get_git_client(organization) if object_id is None: ref = client.get_refs(repository_id=repository, project=project, filter=name) if not ref or len(ref) != 1: logger.error('ref not found') raise CLIError("Failed to find object_id for ref " + name + ". Please provide object_id.") object_id = ref[0].object_id ref_update = GitRefUpdate(name=resolve_git_refs(name), new_object_id='0000000000000000000000000000000000000000', old_object_id=object_id) return client.update_refs(ref_updates=[ref_update], repository_id=repository, project=project)[0]
def checkout(id, remote_name='origin'): # pylint: disable=redefined-builtin """Checkout the PR source branch locally, if no local changes are present :param id: ID of the pull request. :type id: int :param remote_name: Name of git remote against which PR is raised :type remote_name: str """ git_info = get_vsts_info_from_current_remote_url() organization = git_info.uri if not organization: raise CLIError( 'This command should be used from a valid Azure DevOps git repository only' ) client = get_git_client(organization) pr = client.get_pull_request_by_id(id) # favorite the ref refFavoriteRequest = GitRefFavorite(name=pr.source_ref_name, repository_id=pr.repository.id, type=2) try: client.create_favorite(favorite=refFavoriteRequest, project=pr.repository.project.id) except Exception as ex: # pylint: disable=broad-except if 'is already a favorite for user' not in str(ex): raise ex fetch_remote_and_checkout(pr.source_ref_name, remote_name)
def create_ref(name, object_id, repository=None, organization=None, project=None, detect=None): """Create a reference. :param str name: Name of the reference to create (example: heads/my_branch or tags/my_tag). :param str object_id: Id of the object to create the reference from. :param str repository: Name or ID of the repository. :param str organization: Azure Devops organization URL. Example: https://dev.azure.com/MyOrganizationName/ :param str project: Name or ID of the project. :param str detect: Automatically detect organization and project. Default is "on". """ try: organization, project, repository = resolve_instance_project_and_repo( detect=detect, organization=organization, project=project, repo=repository) client = get_git_client(organization) # by default, the create method does not support setting the is_locked value # to True. ref_update = GitRefUpdate( is_locked=False, name=resolve_git_refs(name), new_object_id=object_id, old_object_id='0000000000000000000000000000000000000000') return client.update_refs(ref_updates=[ref_update], repository_id=repository, project=project)[0] except VstsServiceError as ex: raise CLIError(ex)
def delete_ref(name, object_id, repository=None, organization=None, project=None, detect=None): """Delete a reference. :param str name: Name of the reference to delete (example: heads/my_branch). :param str object_id: Id of the reference to delete. :param str repository: Name or ID of the repository. :param str project: Name or ID of the project. :param str detect: Automatically detect organization and project. Default is "on". """ organization, project, repository = resolve_instance_project_and_repo( detect=detect, organization=organization, project=project, repo=repository) client = get_git_client(organization) ref_update = GitRefUpdate( name=resolve_git_refs(name), new_object_id='0000000000000000000000000000000000000000', old_object_id=object_id) return client.update_refs(ref_updates=[ref_update], repository_id=repository, project=project)[0]
def show_repo(repo, organization=None, project=None, detect=None, open=False): # pylint: disable=redefined-builtin """Get the details of a Git repository. :param repo: ID or name of the repository. :type repo: str :param organization: Azure Devops organization URL. Example: https://dev.azure.com/MyOrganizationName/ :type organization: str :param project: Name or ID of the team project. :type project: str :param detect: Automatically detect organization, project and repository. Default is "on". :type detect: str :param open: Open the repository page in your web browser. :type open: bool :rtype: :class:`<GitRepository> <git.v4_0.models.GitRepository>` """ try: organization, project, repo = resolve_instance_project_and_repo( detect=detect, organization=organization, project=project, project_required=True, repo=repo) git_client = get_git_client(organization) repository = git_client.get_repository(project=project, repository_id=repo) if open: _open_repository(repository, organization) return repository except VstsServiceError as ex: raise CLIError(ex)
def create_repo(name, organization=None, project=None, detect=None, open=False): # pylint: disable=redefined-builtin """Create a Git repository in a team project. :param name: Name for the new repository. :type name: str :param organization: Azure Devops organization URL. Example: https://dev.azure.com/MyOrganizationName/ :type organization: str :param project: Name or ID of the team project. :type project: str :param detect: Automatically detect organization and project. Default is "on". :type detect: str :param open: Open the repository page in your web browser. :type open: bool :rtype: :class:`<GitRepository> <git.v4_0.models.GitRepository>` """ try: organization, project = resolve_instance_and_project( detect=detect, organization=organization, project=project) git_client = get_git_client(organization) create_options = GitRepositoryCreateOptions() create_options.name = name repository = git_client.create_repository( git_repository_to_create=create_options, project=project) if open: _open_repository(repository, organization) return repository except VstsServiceError as ex: raise CLIError(ex)
def list_pull_request_statuses(pull_request_id, iteration_id=None, repository=None, organization=None, project=None, detect=None): """Get all the statuses associated with a pull request. :param int pull_request_id: ID of the pull request. :param int iteration_id: ID of the iteration to associate status with. Minimum value is 1. :param str repository: Name or ID of the repository. :param str organization: The URI for the AZDO account (https://dev.azure.com/<account>/) :param str project: Name or ID of the project. :param str detect: When 'On' unsupplied arg values will be detected from the current working directory's repo. """ try: team_instance, project, repository = resolve_instance_project_and_repo( detect=detect, organization=organization, project=project, repo=repository) git_client = get_git_client(team_instance) if iteration_id is not None: return git_client.get_pull_request_iteration_status(repository_id=repository, pull_request_id=pull_request_id, iteration_id=iteration_id, project=project) return git_client.get_pull_request_statuses(repository_id=repository, pull_request_id=pull_request_id, project=project) except Exception as ex: raise ex
def create_ref(name, object_id, repository=None, organization=None, project=None, detect=None): """Create a reference. :param str name: Name of the reference to create (example: heads/my_branch or tags/my_tag). :param str object_id: Id of the object to create the reference from. :param str repository: Name or ID of the repository. :param str project: Name or ID of the project. :param str detect: Automatically detect organization and project. Default is "on". """ organization, project, repository = resolve_instance_project_and_repo( detect=detect, organization=organization, project=project, repo=repository) client = get_git_client(organization) # by default, the create method does not support setting the is_locked value # to True. ref_update = GitRefUpdate(is_locked=False, name=resolve_git_refs(name), new_object_id=object_id, old_object_id='0000000000000000000000000000000000000000') response = client.update_refs(ref_updates=[ref_update], repository_id=repository, project=project)[0] if response.success is False: raise CLIError(response.custom_message) return response
def delete_ref(name, object_id, repository=None, organization=None, project=None, detect=None): """Delete a reference. :param str name: Name of the reference to delete (example: heads/my_branch). :param str object_id: Id of the reference to delete. :param str repository: Name or ID of the repository. :param str organization: Azure Devops organization URL. Example: https://dev.azure.com/MyOrganizationName/ :param str project: Name or ID of the project. :param str detect: Automatically detect organization and project. Default is "on". """ try: organization, project, repository = resolve_instance_project_and_repo( detect=detect, organization=organization, project=project, repo=repository) client = get_git_client(organization) ref_update = GitRefUpdate( name=resolve_git_refs(name), new_object_id='0000000000000000000000000000000000000000', old_object_id=object_id) return client.update_refs(ref_updates=[ref_update], repository_id=repository, project=project)[0] except VstsServiceError as ex: raise CLIError(ex)
def list_pull_requests(repository=None, creator=None, include_links=False, reviewer=None, source_branch=None, status=None, target_branch=None, project=None, skip=None, top=None, organization=None, detect=None): """List pull requests. :param repository: Name or ID of the repository. :type repository: str :param creator: Limit results to pull requests created by this user. :type creator: str :param include_links: Include _links for each pull request. :type include_links: bool :param reviewer: Limit results to pull requests where this user is a reviewer. :type reviewer: str :param source_branch: Limit results to pull requests that originate from this source branch. :type source_branch: str :param status: Limit results to pull requests with this status. :type status: str :param target_branch: Limit results to pull requests that target this branch. :type target_branch: str :param skip: Number of pull requests to skip. :type skip: int :param top: Maximum number of pull requests to list. :type top: int :rtype: list of :class:`VssJsonCollectionWrapper <v5_0.git.models.VssJsonCollectionWrapper>` """ organization, project, repository = resolve_instance_project_and_repo( detect=detect, organization=organization, project=project, repo=repository) search_criteria = GitPullRequestSearchCriteria( creator_id=resolve_identity_as_id(creator, organization), include_links=include_links, reviewer_id=resolve_identity_as_id(reviewer, organization), source_ref_name=resolve_git_ref_heads(source_branch), status=status, target_ref_name=resolve_git_ref_heads(target_branch)) client = get_git_client(organization) if repository is None: pr_list = client.get_pull_requests_by_project( project=project, search_criteria=search_criteria, skip=skip, top=top) else: pr_list = client.get_pull_requests(project=project, repository_id=repository, search_criteria=search_criteria, skip=skip, top=top) return pr_list
def list_repos(organization=None, project=None, detect=None): """List Git repositories of a team project. """ organization, project = resolve_instance_and_project( detect=detect, organization=organization, project=project) git_client = get_git_client(organization) repository = git_client.get_repositories(project=project) return repository
def remove_pull_request_work_items(id, work_items, organization=None, detect=None): # pylint: disable=redefined-builtin """Unlink one or more work items from a pull request. :param id: ID of the pull request. :type id: int :param work_items: IDs of the work items to unlink. Space separated. :type work_items: list of int :rtype: list of :class:`AssociatedWorkItem <v5_0.git.models.AssociatedWorkItem>` """ # pylint: disable=too-many-nested-blocks organization = resolve_instance(detect=detect, organization=organization) client = get_git_client(organization) existing_pr = client.get_pull_request_by_id(id) if work_items is not None and work_items: work_items = list(set(work_items)) # make distinct wit_client = get_work_item_tracking_client(organization) work_items_full = wit_client.get_work_items(ids=work_items, expand=1) if work_items_full: url = 'vstfs:///Git/PullRequestId/{project}%2F{repo}%2F{id}'.format( project=existing_pr.repository.project.id, repo=existing_pr.repository.id, id=id) for work_item in work_items_full: if work_item.relations is not None: index = 0 for relation in work_item.relations: if relation.url == url: patch_document = [] patch_test_operation = JsonPatchOperation() patch_test_operation.op = 'test' patch_test_operation.path = '/rev' patch_test_operation.value = work_item.rev patch_document.append(patch_test_operation) patch_operation = JsonPatchOperation() patch_operation.op = 1 patch_operation.path = '/relations/{index}'.format( index=index) patch_document.append(patch_operation) wit_client.update_work_item( document=patch_document, id=work_item.id) else: index += 1 refs = client.get_pull_request_work_item_refs( project=existing_pr.repository.project.id, repository_id=existing_pr.repository.id, pull_request_id=id) if refs: ids = [] for ref in refs: ids.append(ref.id) if ids: return wit_client.get_work_items(ids=ids) return None
def _resolve_repository_as_id(repository, organization, project): if is_uuid(repository): return repository git_client = get_git_client(organization) repositories = git_client.get_repositories(project=project, include_links=False, include_all_urls=False) for found_repository in repositories: if found_repository.name.lower() == repository.lower(): return found_repository.id return None
def list_repos(organization=None, project=None, detect=None): """List Git repositories of a team project. :rtype: list of :class:`<GitRepository> <git.v4_0.models.GitRepository>` """ organization, project = resolve_instance_and_project( detect=detect, organization=organization, project=project) git_client = get_git_client(organization) repository = git_client.get_repositories(project=project) return repository
def _update_pull_request_status(pull_request_id, new_status, organization=None, detect=None): organization = resolve_instance(detect=detect, organization=organization) client = get_git_client(organization) existing_pr = client.get_pull_request_by_id(pull_request_id) pr = GitPullRequest(status=new_status) if new_status == 'completed': pr.last_merge_source_commit = existing_pr.last_merge_source_commit pr = client.update_pull_request(git_pull_request_to_update=pr, project=existing_pr.repository.project.name, repository_id=existing_pr.repository.name, pull_request_id=pull_request_id) return pr
def delete_repo(id, organization=None, project=None, detect=None): # pylint: disable=redefined-builtin """Delete a Git repository in a team project. :param id: ID of the repository. :type id: str """ organization, project = resolve_instance_and_project( detect=detect, organization=organization, project=project) git_client = get_git_client(organization) delete_response = git_client.delete_repository(project=project, repository_id=id) print('Deleted repository {}'.format(id)) return delete_response
def _update_ref(name, locked, repository, organization, project, detect): organization, project, repository = resolve_instance_project_and_repo( detect=detect, organization=organization, project=project, repo=repository) client = get_git_client(organization) ref_update = GitRefUpdate(is_locked=locked) return client.update_ref(new_ref_info=ref_update, repository_id=repository, filter=name, project=project)
def list_pull_request_reviewers(id, organization=None, detect=None): # pylint: disable=redefined-builtin """List reviewers of a pull request. :param id: ID of the pull request. :type id: int :rtype: list of :class:`IdentityRefWithVote <v5_0.git.models.IdentityRefWithVote>` """ organization = resolve_instance(detect=detect, organization=organization) client = get_git_client(organization) pr = client.get_pull_request_by_id(id) return client.get_pull_request_reviewers(project=pr.repository.project.id, repository_id=pr.repository.id, pull_request_id=id)
def queue_pr_policy(id, evaluation_id, organization=None, detect=None): # pylint: disable=redefined-builtin """Queue an evaluation of a policy for a pull request. :param id: ID of the pull request. :type id: int :param evaluation_id: ID of the policy evaluation to queue. :type evaluation_id: str :rtype: :class:`PolicyEvaluationRecord <policy.v4_0.models.PolicyEvaluationRecord>` """ organization = resolve_instance(detect=detect, organization=organization) git_client = get_git_client(organization) pr = git_client.get_pull_request_by_id(id) policy_client = get_policy_client(organization) return policy_client.requeue_policy_evaluation( project=pr.repository.project.id, evaluation_id=evaluation_id)
def _update_ref(name, locked, repository, organization, project, detect): try: organization, project, repository = resolve_instance_project_and_repo( detect=detect, organization=organization, project=project, repo=repository) client = get_git_client(organization) ref_update = GitRefUpdate(is_locked=locked) return client.update_ref(new_ref_info=ref_update, repository_id=repository, filter=name, project=project) except VstsServiceError as ex: raise CLIError(ex)
def list_refs(filter=None, repository=None, organization=None, project=None, detect=None): """List the references. :param str filter: A filter to apply to the refs (starts with). Example: head or heads/ for the branches. :param str repository: Name or ID of the repository. :param str project: Name or ID of the project. :param str detect: Automatically detect organization and project. Default is "on". """ organization, project, repository = resolve_instance_project_and_repo( detect=detect, organization=organization, project=project, repo=repository) client = get_git_client(organization) return client.get_refs(repository_id=repository, project=project, filter=filter)
def update_repo(repository, default_branch=None, name=None, organization=None, project=None, detect=None): """Update the Git repository. :param repository: Name or ID of the repository. :type repository: str :param organization: Azure Devops organization URL. Example: https://dev.azure.com/MyOrganizationName/ :type organization: str :param project: Name or ID of the team project. :type project: str :param name: New name for the repository. :type name: str :param default_branch: Default branch to be set for the repository. Example: 'refs/heads/live' or 'live'. :type default_branch: str :param detect: Automatically detect organization, project and repository. Default is "on". :type detect: str """ if not default_branch and not name: raise CLIError( "Either --default-branch or --name (for rename) must be provided to update repository." ) try: organization, project, repository = resolve_instance_project_and_repo( detect=detect, organization=organization, project=project, project_required=True, repo=repository) git_client = get_git_client(organization) # Get the repo to be updated repository = git_client.get_repository(project=project, repository_id=repository) if default_branch: default_branch = resolve_git_ref_heads(default_branch) repository.default_branch = default_branch if name: repository.name = name repository = git_client.update_repository( project=project, repository_id=repository.id, new_repository_info=repository) return repository except VstsServiceError as ex: raise CLIError(ex)
def add_pull_request_work_items(id, work_items, organization=None, detect=None): # pylint: disable=redefined-builtin """Link one or more work items to a pull request. :param id: ID of the pull request. :type id: int :param work_items: IDs of the work items to link. Space separated. :type work_items: list of int :rtype: list of :class:`AssociatedWorkItem <v5_0.git.models.AssociatedWorkItem>` """ organization = resolve_instance(detect=detect, organization=organization) client = get_git_client(organization) existing_pr = client.get_pull_request_by_id(id) if work_items is not None and work_items: work_items = list(set(work_items)) # make distinct wit_client = get_work_item_tracking_client(organization) pr_url = 'vstfs:///Git/PullRequestId/{project}%2F{repo}%2F{id}'.format( project=existing_pr.repository.project.id, repo=existing_pr.repository.id, id=id) for work_item_id in work_items: patch_document = [] patch_operation = JsonPatchOperation() patch_operation.op = 0 patch_operation.path = '/relations/-' patch_operation.value = WorkItemRelation() patch_operation.value.attributes = {'name': 'Pull Request'} patch_operation.value.rel = 'ArtifactLink' patch_operation.value.url = pr_url patch_document.append(patch_operation) try: wit_client.update_work_item(document=patch_document, id=work_item_id) except AzureDevOpsClientRequestError as ex: logger.debug(ex, exc_info=True) message = ex.args[0] if message != 'Relation already exists.': raise CLIError(ex) refs = client.get_pull_request_work_item_refs( project=existing_pr.repository.project.id, repository_id=existing_pr.repository.id, pull_request_id=id) ids = [] for ref in refs: ids.append(ref.id) return wit_client.get_work_items(ids=ids)
def create_pull_request_reviewers(id, reviewers, organization=None, detect=None): # pylint: disable=redefined-builtin """Add one or more reviewers to a pull request. :param id: ID of the pull request. :type id: int :param reviewers: Users or groups to include as reviewers on a pull request. Space separated. :type reviewers: list of str :rtype: list of :class:`IdentityRefWithVote <v5_0.git.models.IdentityRefWithVote>` """ organization = resolve_instance(detect=detect, organization=organization) client = get_git_client(organization) pr = client.get_pull_request_by_id(id) resolved_reviewers = _resolve_reviewers_as_refs(reviewers, organization) identities = client.create_pull_request_reviewers(reviewers=resolved_reviewers, project=pr.repository.project.id, repository_id=pr.repository.id, pull_request_id=id) return identities
def list_repos(organization=None, project=None, detect=None): """List Git repositories of a team project. :param organization: Azure Devops organization URL. Example: https://dev.azure.com/MyOrganizationName/ :type organization: str :param project: Name or ID of the team project. :type project: str :param detect: Automatically detect organization and project. Default is "on". :type detect: str :rtype: list of :class:`<GitRepository> <git.v4_0.models.GitRepository>` """ try: organization, project = resolve_instance_and_project( detect=detect, organization=organization, project=project) git_client = get_git_client(organization) repository = git_client.get_repositories(project=project) return repository except VstsServiceError as ex: raise CLIError(ex)
def vote_pull_request(id, vote, organization=None, detect=None): # pylint: disable=redefined-builtin """Vote on a pull request. :param id: ID of the pull request. :type id: int :param vote: New vote value for the pull request. :type vote: int :rtype: :class:`IdentityRefWithVote <v5_0.git.models.IdentityRefWithVote>` """ organization = resolve_instance(detect=detect, organization=organization) client = get_git_client(organization) pr = client.get_pull_request_by_id(id) resolved_reviewer = IdentityRefWithVote(id=resolve_identity_as_id(ME, organization)) resolved_reviewer.vote = _convert_vote_to_int(vote) created_reviewer = client.create_pull_request_reviewer(project=pr.repository.project.id, repository_id=pr.repository.id, pull_request_id=id, reviewer_id=resolved_reviewer.id, reviewer=resolved_reviewer) return created_reviewer
def show_pull_request(id, open=False, organization=None, detect=None): # pylint: disable=redefined-builtin """Get the details of a pull request. :param id: ID of the pull request. :type id: int :param open: Open the pull request in your web browser. :type open: bool :rtype: :class:`GitPullRequest <v5_0.git.models.GitPullRequest>` """ organization = resolve_instance(detect=detect, organization=organization) client = get_git_client(organization) pr = client.get_pull_request_by_id(id) pr = client.get_pull_request(project=pr.repository.project.id, repository_id=pr.repository.id, pull_request_id=id, include_commits=False, include_work_item_refs=True) if open: _open_pull_request(pr, organization) return pr
def create_import_request(git_source_url, project=None, repository=None, organization=None, detect=None): """Create a git import request (currently only supports import from public git source) :param project: Name or ID of the team project. :type project: str :param repository: Name or ID of the repository to create the import request in. :type repository: str :param git_source_url: Url of the source git repository :type git_source_url: str :param organization: Azure Devops organization URL. Example: https://dev.azure.com/MyOrganizationName/ :type organization: str :param detect: Automatically detect organization, project, repository if these values are not specified. Default is "on". :type detect: str """ try: organization, project, repository = resolve_instance_project_and_repo( detect=detect, organization=organization, project=project, repo=repository) client = get_git_client(organization) gitImportGitSource = GitImportGitSource(overwrite=False, url=git_source_url) gitImportRequestParameter = GitImportRequestParameters( delete_service_endpoint_after_import_is_done=False, git_source=gitImportGitSource, service_endpoint_id=None, tfvc_source=None) gitImportRequest = GitImportRequest( parameters=gitImportRequestParameter) importRequest = client.create_import_request( import_request=gitImportRequest, project=project, repository_id=repository) return _wait_for_import_request(client, project, repository, importRequest.import_request_id) except VstsServiceError as ex: raise CLIError(ex)
def list_pr_policies(id, organization=None, detect=None, top=None, skip=None): # pylint: disable=redefined-builtin """List policies of a pull request. :param id: ID of the pull request. :type id: int :param top: Maximum number of policies to list. :type top: int :param skip: Number of policies to skip. :type skip: int :rtype: list of :class:`PolicyEvaluationRecord <policy.v4_0.models.PolicyEvaluationRecord>` """ organization = resolve_instance(detect=detect, organization=organization) git_client = get_git_client(organization) pr = git_client.get_pull_request_by_id(id) policy_client = get_policy_client(organization) artifact_id = "vstfs:///CodeReview/CodeReviewId/{project_id}/{pull_request_id}".format( project_id=pr.repository.project.id, pull_request_id=id) return policy_client.get_policy_evaluations(project=pr.repository.project.id, artifact_id=artifact_id, top=top, skip=skip)