def list_pr_policies(pull_request_id, team_instance=None, detect=None, top=None, skip=None): """List policies of a pull request. :param pull_request_id: ID of the pull request. :type pull_request_id: int :param team_instance: VSTS account or TFS collection URL. Example: https://myaccount.visualstudio.com :type team_instance: str :param detect: Automatically detect instance. Default is "on". :type detect: str :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>` """ try: team_instance = resolve_instance(detect=detect, team_instance=team_instance) git_client = get_git_client(team_instance) pr = git_client.get_pull_request_by_id(pull_request_id) policy_client = get_policy_client(team_instance) artifact_id = "vstfs:///CodeReview/CodeReviewId/{project_id}/{pull_request_id}".format( project_id=pr.repository.project.id, pull_request_id=pull_request_id) return policy_client.get_policy_evaluations( project=pr.repository.project.id, artifact_id=artifact_id, top=top, skip=skip) except Exception as ex: handle_command_exception(ex)
def show_pull_request(pull_request_id, open_browser=False, team_instance=None, detect=None): """Get the details of a pull request. :param pull_request_id: ID of the pull request. :type pull_request_id: int :param open_browser: Open the pull request in your web browser. :type open_browser: bool :param team_instance: VSTS account or TFS collection URL. Example: https://myaccount.visualstudio.com :type team_instance: str :param detect: Automatically detect instance. Default is "on". :type detect: str :rtype: :class:`GitPullRequest <git.v4_0.models.GitPullRequest>` """ try: team_instance = resolve_instance(detect=detect, team_instance=team_instance) client = get_git_client(team_instance) pr = client.get_pull_request_by_id(pull_request_id) pr = client.get_pull_request(project=pr.repository.project.id, repository_id=pr.repository.id, pull_request_id=pull_request_id, include_commits=False, include_work_item_refs=True) if open_browser: _open_pull_request(pr, team_instance) return pr except Exception as ex: handle_command_exception(ex)
def delete_pull_request_reviewers(pull_request_id, reviewers, team_instance=None, detect=None): """Remove one or more reviewers from a pull request. :param pull_request_id: ID of the pull request. :type pull_request_id: int :param reviewers: Users or groups to remove as reviewers on a pull request. Space separated. :type reviewers: list of str :param team_instance: VSTS account or TFS collection URL. Example: https://myaccount.visualstudio.com :type team_instance: str :param detect: Automatically detect instance. Default is "on". :type detect: str :rtype: list of :class:`IdentityRefWithVote <git.v4_0.models.IdentityRefWithVote>` """ try: team_instance = resolve_instance(detect=detect, team_instance=team_instance) client = get_git_client(team_instance) pr = client.get_pull_request_by_id(pull_request_id) resolved_reviewers = _resolve_reviewers_as_ids(reviewers, team_instance) for reviewer in resolved_reviewers: client.delete_pull_request_reviewer( project=pr.repository.project.id, repository_id=pr.repository.id, pull_request_id=pull_request_id, reviewer_id=reviewer) return client.get_pull_request_reviewers( project=pr.repository.project.id, repository_id=pr.repository.id, pull_request_id=pull_request_id) except Exception as ex: handle_command_exception(ex)
def create_repo(name, team_instance=None, project=None, detect=None, open_browser=False): """Create a Git repository in a team project. :param name: Name for the new repository. :type name: int :param team_instance: VSTS account or TFS collection URL. Example: https://myaccount.visualstudio.com :type team_instance: str :param project: Name or ID of the team project. :type project: str :param detect: Automatically detect instance and project. Default is "on". :type detect: str :param open_browser: Open the repository page in your web browser. :type open_browser: bool :rtype: :class:`<GitRepository> <git.v4_0.models.GitRepository>` """ try: team_instance, project = resolve_instance_and_project( detect=detect, team_instance=team_instance, project=project) git_client = get_git_client(team_instance) create_options = GitRepositoryCreateOptions() create_options.name = name repository = git_client.create_repository( git_repository_to_create=create_options, project=project) if open_browser: _open_repository(repository, team_instance) return repository except Exception as ex: handle_command_exception(ex)
def queue_pr_policy(pull_request_id, evaluation_id, team_instance=None, detect=None): """Queue an evaluation of a policy for a pull request. :param pull_request_id: ID of the pull request. :type pull_request_id: int :param evaluation_id: ID of the policy evaluation to queue. :type evaluation_id: str :param team_instance: VSTS account or TFS collection URL. Example: https://myaccount.visualstudio.com :type team_instance: str :param detect: Automatically detect instance. Default is "on". :type detect: str :rtype: :class:`PolicyEvaluationRecord <policy.v4_0.models.PolicyEvaluationRecord>` """ try: team_instance = resolve_instance(detect=detect, team_instance=team_instance) git_client = get_git_client(team_instance) pr = git_client.get_pull_request_by_id(pull_request_id) policy_client = get_policy_client(team_instance) return policy_client.requeue_policy_evaluation( project=pr.repository.project.id, evaluation_id=evaluation_id) except Exception as ex: handle_command_exception(ex)
def show_work_item(work_item_id, open_browser=False, team_instance=None, detect=None): """Show details for a work item. :param work_item_id: The ID of the work item :type work_item_id: int :param open_browser: Open the work item in the default web browser. :type open_browser: bool :param team_instance: The URI for the VSTS account (https://<account>.visualstudio.com) or your TFS project collection. :type team_instance: str :param detect: When 'On' unsupplied arg values will be detected from the current working directory's repo. :type detect: str :rtype: :class:`<WorkItem> <work-item-tracking.v4_0.models.WorkItem>` """ try: team_instance = resolve_instance(detect=detect, team_instance=team_instance) client = get_work_item_tracking_client(team_instance) work_item = client.get_work_item(work_item_id) if open_browser: _open_work_item(work_item, team_instance) return work_item except Exception as ex: handle_command_exception(ex)
def list_pull_request_work_items(pull_request_id, team_instance=None, detect=None): """List linked work items for a pull request. :param pull_request_id: ID of the pull request. :type pull_request_id: int :param team_instance: VSTS account or TFS collection URL. Example: https://myaccount.visualstudio.com :type team_instance: str :param detect: Automatically detect instance. Default is "on". :type detect: str :rtype: list of :class:`AssociatedWorkItem <git.v4_0.models.AssociatedWorkItem>` """ try: team_instance = resolve_instance(detect=detect, team_instance=team_instance) client = get_git_client(team_instance) pr = client.get_pull_request_by_id(pull_request_id) refs = client.get_pull_request_work_items( project=pr.repository.project.id, repository_id=pr.repository.id, pull_request_id=pull_request_id) if refs: ids = [] for ref in refs: ids.append(ref.id) wit_client = get_work_item_tracking_client(team_instance) return wit_client.get_work_items(ids=ids) except Exception as ex: handle_command_exception(ex)
def build_show(build_id, open_browser=False, team_instance=None, project=None, detect=None): """Get the details of a build. :param build_id: ID of the build. :type build_id: int :param open_browser: Open the build results page in your web browser. :type open_browser: bool :param team_instance: VSTS account or TFS collection URL. Example: https://myaccount.visualstudio.com :type team_instance: str :param project: Name or ID of the team project. :type project: str :param detect: Automatically detect instance and project. Default is "on". :type detect: str :rtype: :class:`<Build> <build.v4_0.models.Build>` """ try: team_instance, project = resolve_instance_and_project( detect=detect, team_instance=team_instance, project=project) client = get_build_client(team_instance) build = client.get_build(build_id=build_id, project=project) if open_browser: _open_build(build, team_instance) return build except Exception as ex: handle_command_exception(ex)
def show_project(project_id=None, name=None, team_instance=None, detect=None, open_browser=False): """Show team project. :param project_id: The id (UUID) of the project to show. Required if the --name argument is not specified. :type project_id: str :param name: Name of the project to show. Ignored if the --id argument is specified. :type name: str :param team_instance: The URI for the VSTS account (https://<account>.visualstudio.com) or your TFS project collection. :type team_instance: str :param detect: When 'On' unsupplied arg values will be detected from the current working directory's repo. :type detect: str :param open_browser: Open the team project in the default web browser. :type open_browser: bool :rtype: :class:`<TeamProject> <core.v4_0.models.TeamProject>` """ try: if project_id is None and name is None: raise CLIError('Either the --name argument or the --id argument needs to be specified.') if project_id is not None: identifier = project_id else: identifier = name team_instance = resolve_instance(detect=detect, team_instance=team_instance) core_client = get_core_client(team_instance) team_project = core_client.get_project(project_id=identifier, include_capabilities=True) if open_browser: _open_project(team_project) return team_project except Exception as ex: handle_command_exception(ex)
def vote_pull_request(pull_request_id, vote, team_instance=None, detect=None): """Vote on a pull request. :param pull_request_id: ID of the pull request. :type pull_request_id: int :param vote: New vote value for the pull request. :type vote: int :param team_instance: VSTS account or TFS collection URL. Example: https://myaccount.visualstudio.com :type team_instance: str :param detect: Automatically detect instance. Default is "on". :type detect: str :rtype: :class:`IdentityRefWithVote <git.v4_0.models.IdentityRefWithVote>` """ try: team_instance = resolve_instance(detect=detect, team_instance=team_instance) client = get_git_client(team_instance) pr = client.get_pull_request_by_id(pull_request_id) resolved_reviewer = IdentityRefWithVote( id=resolve_identity_as_id(ME, team_instance)) 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=pull_request_id, reviewer_id=resolved_reviewer.id, reviewer=resolved_reviewer) except Exception as ex: handle_command_exception(ex) return created_reviewer
def build_list(definition_ids=None, branch=None, team_instance=None, project=None, detect=None, top=None, result=None, status=None, reason=None, tags=None, requested_for=None): """List build results. :param definition_ids: IDs (space separated) of definitions to list builds for. :type definition_ids: list of int :param branch: Filter by builds for this branch. :type branch: str :param team_instance: VSTS account or TFS collection URL. Example: https://myaccount.visualstudio.com :type team_instance: str :param project: Name or ID of the team project. :type project: str :param detect: Automatically detect instance and project. Default is "on". :type detect: str :param top: Maximum number of builds to list. :type top: int :param result: Limit to builds with this result. :type result: str :param status: Limit to builds with this status. :type status: str :param reason: Limit to builds with this reason. :type reason: str :param tags: Limit to builds with each of the specified tags. Space separated. :type tags: list of str :param requested_for: Limit to builds requested for this user or group. :type requested_for: str :rtype: :class:`<Build> <build.v4_0.models.Build>` """ try: team_instance, project = resolve_instance_and_project( detect=detect, team_instance=team_instance, project=project) client = get_build_client(team_instance) if definition_ids is not None and definition_ids: definition_ids = list(set(definition_ids)) # make distinct if tags is not None and tags: tags = list(set(tags)) # make distinct builds = client.get_builds(definitions=definition_ids, project=project, branch_name=resolve_git_ref_heads(branch), top=top, result_filter=result, status_filter=status, reason_filter=reason, tag_filters=tags, requested_for=resolve_identity_as_id( requested_for, team_instance)) return builds except Exception as ex: handle_command_exception(ex)
def add_pull_request_work_items(pull_request_id, work_items, team_instance=None, detect=None): """Link one or more work items to a pull request. :param pull_request_id: ID of the pull request. :type pull_request_id: int :param work_items: IDs of the work items to link. Space separated. :type work_items: list of int :param team_instance: VSTS account or TFS collection URL. Example: https://myaccount.visualstudio.com :type team_instance: str :param detect: Automatically detect instance. Default is "on". :type detect: str :rtype: list of :class:`AssociatedWorkItem <git.v4_0.models.AssociatedWorkItem>` """ try: team_instance = resolve_instance(detect=detect, team_instance=team_instance) client = get_git_client(team_instance) existing_pr = client.get_pull_request_by_id(pull_request_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(team_instance) pr_url = 'vstfs:///Git/PullRequestId/{project}%2F{repo}%2F{id}'.format( project=existing_pr.repository.project.id, repo=existing_pr.repository.id, id=pull_request_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 VstsClientRequestError as ex: logging.exception(ex) message = ex.args[0] if message != 'Relation already exists.': raise CLIError(ex) refs = client.get_pull_request_work_items( project=existing_pr.repository.project.id, repository_id=existing_pr.repository.id, pull_request_id=pull_request_id) ids = [] for ref in refs: ids.append(ref.id) return wit_client.get_work_items(ids=ids) except Exception as ex: handle_command_exception(ex)
def build_definition_list(name=None, top=None, team_instance=None, project=None, repository=None, detect=None): """List build definitions. :param name: Limit results to definitions with this name or starting with this name. Examples: "FabCI" or "Fab*" :type name: bool :param top: Maximum number of definitions to list. :type top: int :param team_instance: VSTS account or TFS collection URL. Example: https://myaccount.visualstudio.com :type team_instance: str :param project: Name or ID of the team project. :type project: str :param repository: Limit results to definitions associated with this repository. :type repository: str :param detect: Automatically detect values for instance and project. Default is "on". :type detect: str :rtype: [BuildDefinitionReference] """ try: team_instance, project, repository = resolve_instance_project_and_repo( detect=detect, team_instance=team_instance, project=project, repo=repository) client = get_build_client(team_instance) query_order = 'DefinitionNameAscending' repository_type = None if repository is not None: resolved_repository = _resolve_repository_as_id( repository, team_instance, project) if resolved_repository is None: raise ValueError( "Could not find a repository with name, '{}', in project, '{}'." .format(repository, project)) else: repository_type = 'TfsGit' else: resolved_repository = None definition_references = client.get_definitions( project=project, name=name, repository_id=resolved_repository, repository_type=repository_type, top=top, query_order=query_order) return definition_references except Exception as ex: handle_command_exception(ex)
def credential_clear(team_instance=None): """Clear the credential for a particular account :param team_instance: The URI for the VSTS account (https://<account>.visualstudio.com) or your TFS project collection. :type team_instance: str """ try: disable_command_version_checking() if team_instance is not None: team_instance = get_base_url(team_instance) clear_credential(team_instance) print('The credential was successfully cleared.') except Exception as ex: handle_command_exception(ex)
def build_queue(definition_id=None, definition_name=None, source_branch=None, open_browser=False, team_instance=None, project=None, detect=None): """Request (queue) a build. :param definition_id: ID of the definition to queue. Required if --name is not supplied. :type definition_id: int :param definition_name: Name of the definition to queue. Ignored if --id is supplied. :type definition_name: str :param source_branch: Branch to build. Example: "dev". :type source_branch: str :param open_browser: Open the build results page in your web browser. :type open_browser: bool :param team_instance: VSTS account or TFS collection URL. Example: https://myaccount.visualstudio.com :type team_instance: str :param project: Name or ID of the team project. :type project: str :param detect: Automatically detect instance and project. Default is "on". :type detect: str :rtype: :class:`<Build> <build.v4_0.models.Build>` """ try: team_instance, project = resolve_instance_and_project( detect=detect, team_instance=team_instance, project=project) if definition_id is None and definition_name is None: raise ValueError( 'Either the --definition-id argument or the --definition-name argument ' + 'must be supplied for this command.') client = get_build_client(team_instance) if definition_id is None: definition_id = get_definition_id_from_name( definition_name, client, project) definition_reference = DefinitionReference(id=definition_id) build = Build(definition=definition_reference) if source_branch is not None: build.source_branch = resolve_git_ref_heads(source_branch) queued_build = client.queue_build(build=build, project=project) if open_browser: _open_build(queued_build, team_instance) return queued_build except Exception as ex: handle_command_exception(ex)
def list_repos(team_instance=None, project=None, detect=None): """List Git repositories of a team project. :param team_instance: VSTS account or TFS collection URL. Example: https://myaccount.visualstudio.com :type team_instance: str :param project: Name or ID of the team project. :type project: str :param detect: Automatically detect instance and project. Default is "on". :type detect: str :rtype: list of :class:`<GitRepository> <git.v4_0.models.GitRepository>` """ try: team_instance, project = resolve_instance_and_project( detect=detect, team_instance=team_instance, project=project) git_client = get_git_client(team_instance) repository = git_client.get_repositories(project=project) return repository except Exception as ex: handle_command_exception(ex)
def _update_pull_request_status(pull_request_id, new_status, team_instance=None, detect=None): try: team_instance = resolve_instance(detect=detect, team_instance=team_instance) client = get_git_client(team_instance) 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) except Exception as ex: handle_command_exception(ex) return pr
def list_projects(team_instance=None, top=None, skip=None, detect=None): """List team projects :param team_instance: The URI for the VSTS account (https://<account>.visualstudio.com) or your TFS project collection. :type team_instance: str :param top: Maximum number of results to list. :type top: int :param skip: Number of results to skip. :type skip: int :param detect: When 'On' unsupplied arg values will be detected from the current working directory's repo. :type detect: str :rtype: list of :class:`<TeamProject> <core.v4_0.models.TeamProject>` """ try: team_instance = resolve_instance(detect=detect, team_instance=team_instance) core_client = get_core_client(team_instance) team_projects = core_client.get_projects(state_filter='all', top=top, skip=skip) return team_projects except Exception as ex: handle_command_exception(ex)
def build_definition_show(definition_id=None, name=None, open_browser=False, team_instance=None, project=None, detect=None): """Get the details of a build definition. :param definition_id: ID of the definition. :type definition_id: int :param name: Name of the definition. Ignored if --id is supplied. :type name: str :param open_browser: Open the definition summary page in your web browser. :type open_browser: bool :param team_instance: VSTS account or TFS collection URL. Example: https://myaccount.visualstudio.com :type team_instance: str :param project: Name or ID of the team project. :type project: str :param detect: Automatically detect values for instance and project. Default is "on". :type detect: str :rtype: BuildDefinitionReference """ try: team_instance, project = resolve_instance_and_project( detect=detect, team_instance=team_instance, project=project) client = get_build_client(team_instance) if definition_id is None: if name is not None: definition_id = get_definition_id_from_name( name, client, project) else: raise ValueError( "Either the --id argument or the --name argument must be supplied for this command." ) build_definition = client.get_definition(definition_id=definition_id, project=project) if open_browser: _open_definition(build_definition, team_instance) return build_definition except Exception as ex: handle_command_exception(ex)
def show_repo(repo_id=None, name=None, team_instance=None, project=None, detect=None, open_browser=False): """Get the details of a Git repository. :param repo_id: ID of the repository. Required if --name is not specified. :type repo_id: int :param name: Name of the repository. Ignored if --id is specified. :type name: int :param team_instance: VSTS account or TFS collection URL. Example: https://myaccount.visualstudio.com :type team_instance: str :param project: Name or ID of the team project. :type project: str :param detect: Automatically detect instance and project. Default is "on". :type detect: str :param open_browser: Open the repository page in your web browser. :type open_browser: bool :rtype: :class:`<GitRepository> <git.v4_0.models.GitRepository>` """ try: if repo_id is None and name is None: raise CLIError( 'Either the --name argument or the --id argument needs to be specified.' ) if repo_id is not None: identifier = repo_id else: identifier = name team_instance, project = resolve_instance_and_project( detect=detect, team_instance=team_instance, project=project) git_client = get_git_client(team_instance) repository = git_client.get_repository(project=project, repository_id=identifier) if open_browser: _open_repository(repository, team_instance) return repository except Exception as ex: handle_command_exception(ex)
def list_pull_request_reviewers(pull_request_id, team_instance=None, detect=None): """List reviewers of a pull request. :param pull_request_id: ID of the pull request. :type pull_request_id: int :param team_instance: VSTS account or TFS collection URL. Example: https://myaccount.visualstudio.com :type team_instance: str :param detect: Automatically detect instance. Default is "on". :type detect: str :rtype: list of :class:`IdentityRefWithVote <git.v4_0.models.IdentityRefWithVote>` """ try: team_instance = resolve_instance(detect=detect, team_instance=team_instance) client = get_git_client(team_instance) pr = client.get_pull_request_by_id(pull_request_id) return client.get_pull_request_reviewers( project=pr.repository.project.id, repository_id=pr.repository.id, pull_request_id=pull_request_id) except Exception as ex: handle_command_exception(ex)
def credential_set(token, team_instance=None): """Set the credential (PAT) to use for a particular account :param token: PAT token for the VSTS account or your TFS project collection. :type token: str :param team_instance: The URI for the VSTS account (https://<account>.visualstudio.com) or your TFS project collection. :type team_instance: str """ try: disable_command_version_checking() credentials = BasicAuthentication('', token) if team_instance is not None: team_instance = get_base_url(team_instance) logging.info("Creating connection with personal access token.") connection = _get_vss_connection(team_instance, credentials) location_client = connection.get_client('vsts.location.v4_0.location_client.LocationClient') try: location_client.get_connection_data() except Exception as ex2: logging.exception(ex2) raise ValueError("Failed to authenticate using the supplied token.") set_credential(team_instance=team_instance, token=token) except Exception as ex: handle_command_exception(ex)
def remove_pull_request_work_items(pull_request_id, work_items, team_instance=None, detect=None): """Unlink one or more work items from a pull request. :param pull_request_id: ID of the pull request. :type pull_request_id: int :param work_items: IDs of the work items to unlink. Space separated. :type work_items: list of int :param team_instance: VSTS account or TFS collection URL. Example: https://myaccount.visualstudio.com :type team_instance: str :param detect: Automatically detect instance. Default is "on". :type detect: str :rtype: list of :class:`AssociatedWorkItem <git.v4_0.models.AssociatedWorkItem>` """ try: team_instance = resolve_instance(detect=detect, team_instance=team_instance) client = get_git_client(team_instance) existing_pr = client.get_pull_request_by_id(pull_request_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(team_instance) 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=pull_request_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_items( project=existing_pr.repository.project.id, repository_id=existing_pr.repository.id, pull_request_id=pull_request_id) if refs: ids = [] for ref in refs: ids.append(ref.id) if ids: return wit_client.get_work_items(ids=ids) except Exception as ex: handle_command_exception(ex)
def create_work_item(work_item_type, title, description=None, assigned_to=None, state=None, area=None, iteration=None, reason=None, discussion=None, fields=None, open_browser=False, team_instance=None, project=None, detect=None): """Create a work item. :param work_item_type: Name of the work item type (e.g. Bug). :type work_item_type: str :param title: Title of the work item. :type title: str :param description: Description of the work item. :type description: str :param assigned_to: Name of the person the work item is assigned-to (e.g. fabrikam). :type assigned_to: str :param state: State of the work item (e.g. active) :type state: str :param area: Area the work item is assigned to (e.g. Demos) :type area: str :param iteration: Iteration path of the work item (e.g. Demos\Iteration 1). :type iteration: str :param reason: Reason for the state work item. :type reason: str :param discussion: Comment to add to a discussion in a work item. :type discussion: str :param fields: Space separated "field=value" pairs for custom fields you would like to set. :type fields: [str] :param open_browser: Open the work item in the default web browser. :type open_browser: bool :param team_instance: The URI for the VSTS account (https://<account>.visualstudio.com) or your TFS project collection. :type team_instance: str :param project: Name or ID of the team project. :type project: str :param detect: When 'On' unsupplied arg values will be detected from the current working directory's repo. :type detect: str :rtype: :class:`<WorkItem> <work-item-tracking.v4_0.models.WorkItem>` """ try: team_instance, project = resolve_instance_and_project( detect=detect, team_instance=team_instance, project=project, project_required=True) patch_document = [] if title is not None: patch_document.append( _create_work_item_field_patch_operation( 'add', 'System.Title', title)) else: raise ValueError('--title is a required argument.') if description is not None: patch_document.append( _create_work_item_field_patch_operation( 'add', 'System.Description', description)) if assigned_to is not None: # 'assigned to' does not take an identity id. Display name works. if assigned_to == '': resolved_assigned_to = '' else: resolved_assigned_to = resolve_identity_as_display_name( assigned_to, team_instance) if resolved_assigned_to is not None: patch_document.append( _create_work_item_field_patch_operation( 'add', 'System.AssignedTo', resolved_assigned_to)) if state is not None: patch_document.append( _create_work_item_field_patch_operation( 'add', 'System.State', state)) if area is not None: patch_document.append( _create_work_item_field_patch_operation( 'add', 'System.AreaPath', area)) if iteration is not None: patch_document.append( _create_work_item_field_patch_operation( 'add', 'System.IterationPath', iteration)) if reason is not None: patch_document.append( _create_work_item_field_patch_operation( 'add', 'System.Reason', reason)) if discussion is not None: patch_document.append( _create_work_item_field_patch_operation( 'add', 'System.History', discussion)) if fields is not None and fields: for field in fields: kvp = field.split('=') if len(kvp) == 2: patch_document.append( _create_work_item_field_patch_operation( 'add', kvp[0], kvp[1])) else: raise ValueError( 'The --fields argument should consist of space separated "field=value" pairs.' ) client = get_work_item_tracking_client(team_instance) work_item = client.create_work_item(document=patch_document, project=project, type=work_item_type) if open_browser: _open_work_item(work_item, team_instance) return work_item except VstsServiceError as ex: _handle_vsts_service_error(ex) except Exception as ex: handle_command_exception(ex)
def build_queue(definition_id=None, definition_name=None, branch=None, variables=None, open_browser=False, team_instance=None, project=None, detect=None, source_branch=None): """Request (queue) a build. :param definition_id: ID of the definition to queue. Required if --name is not supplied. :type definition_id: int :param definition_name: Name of the definition to queue. Ignored if --id is supplied. :type definition_name: str :param branch: Branch to build. Required if there is not a default branch set up on the definition. Example: "dev". :type branch: str :param variables: Space separated "name=value" pairs for the variables you would like to set. :type variables: [str] :param open_browser: Open the build results page in your web browser. :type open_browser: bool :param team_instance: VSTS account or TFS collection URL. Example: https://myaccount.visualstudio.com :type team_instance: str :param project: Name or ID of the team project. :type project: str :param detect: Automatically detect instance and project. Default is "on". :type detect: str :param source_branch: Obsolete. Use --branch instead. :type source_branch: str :rtype: :class:`<Build> <build.v4_0.models.Build>` """ try: if branch is None: branch = source_branch team_instance, project = resolve_instance_and_project( detect=detect, team_instance=team_instance, project=project) if definition_id is None and definition_name is None: raise ValueError( 'Either the --definition-id argument or the --definition-name argument ' + 'must be supplied for this command.') client = get_build_client(team_instance) if definition_id is None: definition_id = get_definition_id_from_name( definition_name, client, project) definition_reference = DefinitionReference(id=definition_id) build = Build(definition=definition_reference) build.source_branch = resolve_git_ref_heads(branch) if variables is not None and variables: build.parameters = {} for variable in variables: kvp = variable.split('=') if len(kvp) == 2: build.parameters[kvp[0]] = kvp[1] else: raise ValueError( 'The --variables argument should consist of space separated "name=value" pairs.' ) queued_build = client.queue_build(build=build, project=project) if open_browser: _open_build(queued_build, team_instance) return queued_build except Exception as ex: handle_command_exception(ex)
def query_work_items(wiql=None, query_id=None, path=None, team_instance=None, project=None, detect=None): """Query for a list of work items. :param wiql: The query in Work Item Query Language format. Ignored if --id or --path is specified. :type wiql: str :param query_id: The UUID of an existing query. Required unless --path or --wiql are specified. :type query_id: str :param path: The path of an existing query. Ignored if --id is specified. :type path: str :param team_instance: The URI for the VSTS account (https://<account>.visualstudio.com) or your TFS project collection. :type team_instance: str :param project: Name or ID of the team project. :type project: str :param detect: When 'On' unsupplied arg values will be detected from the current working directory's repo. :type detect: str :rtype: :class:`<WorkItem> <work-item-tracking.v4_0.models.WorkItem>` """ try: if wiql is None and path is None and query_id is None: raise CLIError( "Either the --wiql, --id, or --path argument must be specified." ) team_instance, project = resolve_instance_and_project( detect=detect, team_instance=team_instance, project=project, project_required=False) client = get_work_item_tracking_client(team_instance) if query_id is None and path is not None: if project is None: raise CLIError( "The --project argument must be specified for this query.") query = client.get_query(project=project, query=path) query_id = query.id if query_id is not None: query_result = client.query_by_id(id=query_id) else: wiql_object = Wiql() wiql_object.query = wiql query_result = client.query_by_wiql(wiql=wiql_object) if query_result.work_items: _last_query_result[ _LAST_QUERY_RESULT_KEY] = query_result # store query result for table view safety_buffer = 100 # a buffer in the max url length to protect going over the limit remaining_url_length = 2048 - safety_buffer remaining_url_length -= len(team_instance) # following subtracts relative url, the asof parameter and beginning of id and field parameters. # asof value length will vary, but this should be the longest possible remaining_url_length -=\ len('/_apis/wit/workItems?ids=&fields=&asOf=2017-11-07T17%3A05%3A34.06699999999999999Z') fields = [] fields_length_in_url = 0 if query_result.columns: for field_ref in query_result.columns: fields.append(field_ref.reference_name) if fields_length_in_url > 0: fields_length_in_url += 3 # add 3 for %2C delimiter fields_length_in_url += len( uri_quote(field_ref.reference_name)) if fields_length_in_url > 800: logging.info( "Not retrieving all fields due to max url length.") break remaining_url_length -= fields_length_in_url max_work_items = 1000 current_batch = [] work_items = [] work_item_url_length = 0 for work_item_ref in query_result.work_items: if len(work_items) >= max_work_items: logging.info("Only retrieving the first %s work items.", max_work_items) break if work_item_url_length > 0: work_item_url_length += 3 # add 3 for %2C delimiter work_item_url_length += len(str(work_item_ref.id)) current_batch.append(work_item_ref.id) if remaining_url_length - work_item_url_length <= 0: # url is near max length, go ahead and send first request for details. # url can go over by an id length because we have a safety buffer current_batched_items = client.get_work_items( ids=current_batch, as_of=query_result.as_of, fields=fields) for work_item in current_batched_items: work_items.append(work_item) current_batch = [] work_item_url_length = 0 if current_batch: current_batched_items = client.get_work_items( ids=current_batch, as_of=query_result.as_of, fields=fields) for work_item in current_batched_items: work_items.append(work_item) # put items in the same order they appeared in the initial query results work_items = sorted(work_items, key=_get_sort_key_from_last_query_results) return work_items except Exception as ex: handle_command_exception(ex)
def create_pull_request(project=None, repository=None, source_branch=None, target_branch=None, title=None, description=None, auto_complete=False, squash=False, delete_source_branch=False, bypass_policy=False, bypass_policy_reason=None, merge_commit_message=None, reviewers=None, work_items=None, open_browser=False, team_instance=None, detect=None): """Create a pull request. :param project: Name or ID of the team project. :type project: str :param repository: Name or ID of the repository to create the pull request in. :type repository: str :param source_branch: Name of the source branch. Example: "dev". :type source_branch: str :param target_branch: Name of the target branch. If not specified, defaults to the default branch of the target repository. :type target_branch: str :param title: Title for the new pull request. :type title: str :param description: Description for the new pull request. Can include markdown. :type description: str :param auto_complete: Set the pull request to complete automatically when all policies have passed and the source branch can be merged into the target branch. :type auto_complete: bool :param squash: Squash the commits in the source branch when merging into the target branch. :type squash: bool :param delete_source_branch: Delete the source branch after the pull request has been completed and merged into the target branch. :type delete_source_branch: bool :param bypass_policy: Bypass required policies (if any) and completes the pull request once it can be merged. :type bypass_policy: bool :param bypass_policy_reason: Reason for bypassing the required policies. :type bypass_policy_reason: str :param merge_commit_message: Message displayed when commits are merged. :type merge_commit_message: str :param reviewers: Additional users or groups to include as reviewers on the new pull request. Space separated. :type reviewers: list of str :param work_items: IDs of the work items to link to the new pull request. Space separated. :type work_items: list of str :param open_browser: Open the pull request in your web browser. :type open_browser: bool :param team_instance: VSTS account or TFS collection URL. Example: https://myaccount.visualstudio.com :type team_instance: str :param detect: Automatically detect instance, project, repository, source and target branches if these values are not specified. Default is "on". :type detect: str :rtype: :class:`GitPullRequest <git.v4_0.models.GitPullRequest>` """ try: team_instance, project, repository = resolve_instance_project_and_repo( detect=detect, team_instance=team_instance, project=project, repo=repository) if should_detect(detect): if source_branch is None: source_branch = get_current_branch_name() if source_branch is None: raise ValueError( 'The source branch could not be detected, please ' + 'provide the --source-branch argument.') if target_branch is None: if project is not None: target_branch = _get_default_branch( team_instance, project, repository) if target_branch is None: raise ValueError( 'The target branch could not be detected, please ' + 'provide the --target-branch argument.') else: if source_branch is None: raise ValueError('--source-branch is a required argument.') if target_branch is None: raise ValueError('--target-branch is a required argument.') client = get_git_client(team_instance) pr = GitPullRequest(description=description, source_ref_name=source_branch, target_ref_name=target_branch) if title is not None: pr.title = title else: pr.title = 'Merge ' + source_branch + ' to ' + target_branch pr.source_ref_name = resolve_git_ref_heads(source_branch) pr.target_ref_name = resolve_git_ref_heads(target_branch) if pr.source_ref_name == pr.target_ref_name: raise CLIError( 'The source branch, "{}", can not be the same as the target branch.' .format(pr.source_ref_name)) pr.reviewers = _resolve_reviewers_as_refs(reviewers, team_instance) if work_items is not None and len(work_items) > 0: resolved_work_items = [] for work_item in work_items: resolved_work_items.append(ResourceRef(id=work_item)) pr.work_item_refs = resolved_work_items pr = client.create_pull_request(git_pull_request_to_create=pr, project=project, repository_id=repository) title_from_commit = None if title is None: # if title wasn't specified and only one commit, we will set the PR title to the comment of that commit commits = client.get_pull_request_commits( repository_id=repository, pull_request_id=pr.pull_request_id, project=project) if len(commits) == 1: title_from_commit = commits[0].comment set_completion_options = (bypass_policy is not None or bypass_policy_reason is not None or bypass_policy or squash or merge_commit_message is not None or delete_source_branch) if auto_complete or set_completion_options or title_from_commit is not None: pr_for_update = GitPullRequest() if auto_complete: # auto-complete will not get set on create, so a subsequent update is required. pr_for_update.auto_complete_set_by = IdentityRef( id=resolve_identity_as_id(ME, team_instance)) if set_completion_options: completion_options = GitPullRequestCompletionOptions() completion_options.bypass_policy = bypass_policy completion_options.bypass_reason = bypass_policy_reason completion_options.delete_source_branch = delete_source_branch completion_options.squash_merge = squash completion_options.merge_commit_message = merge_commit_message pr_for_update.completion_options = completion_options if title_from_commit is not None: pr_for_update.title = title_from_commit pr = client.update_pull_request( git_pull_request_to_update=pr_for_update, project=pr.repository.project.id, repository_id=pr.repository.id, pull_request_id=pr.pull_request_id) if open_browser: _open_pull_request(pr, team_instance) except Exception as ex: handle_command_exception(ex) return pr
def update_pull_request(pull_request_id, title=None, description=None, auto_complete=None, squash=None, delete_source_branch=None, bypass_policy=None, bypass_policy_reason=None, merge_commit_message=None, team_instance=None, detect=None): """Update a pull request. :param pull_request_id: ID of the pull request. :type pull_request_id: int :param title: New title for the pull request. :type title: str :param description: New description for the pull request. :type description: str :param auto_complete: Set the pull request to complete automatically when all policies have passed and the source branch can be merged into the target branch. :type auto_complete: str :param squash: Squash the commits in the source branch when merging into the target branch. :type squash: str :param delete_source_branch: Delete the source branch after the pull request has been completed and merged into the target branch. :type delete_source_branch: str :param bypass_policy: Bypass required policies (if any) and completes the pull request once it can be merged. :type bypass_policy: str :param bypass_policy_reason: Reason for bypassing the required policies. :type bypass_policy_reason: str :param merge_commit_message: Message displayed when commits are merged. :type merge_commit_message: str :param team_instance: VSTS account or TFS collection URL. Example: https://myaccount.visualstudio.com :type team_instance: str :param detect: Automatically detect instance. Default is "on". :type detect: str :rtype: :class:`GitPullRequest <git.v4_0.models.GitPullRequest>` """ try: team_instance = resolve_instance(detect=detect, team_instance=team_instance) client = get_git_client(team_instance) existing_pr = client.get_pull_request_by_id(pull_request_id) pr = GitPullRequest(title=title, description=description) if (bypass_policy is not None or bypass_policy_reason is not None or bypass_policy is not None or squash is not None or merge_commit_message is not None or delete_source_branch is not None): completion_options = existing_pr.completion_options if completion_options is None: completion_options = GitPullRequestCompletionOptions() if bypass_policy is not None: completion_options.bypass_policy = resolve_on_off_switch( bypass_policy) if bypass_policy_reason is not None: completion_options.bypass_reason = bypass_policy_reason if delete_source_branch is not None: completion_options.delete_source_branch = resolve_on_off_switch( delete_source_branch) if squash is not None: completion_options.squash_merge = resolve_on_off_switch(squash) if merge_commit_message is not None: completion_options.merge_commit_message = merge_commit_message pr.completion_options = completion_options if auto_complete is not None: if resolve_on_off_switch(auto_complete): pr.auto_complete_set_by = IdentityRef( id=resolve_identity_as_id(ME, team_instance)) else: pr.auto_complete_set_by = IdentityRef(id=EMPTY_UUID) 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) except Exception as ex: handle_command_exception(ex) return pr
def create_project(name, team_instance=None, process=None, source_control='git', description=None, detect=None, open_browser=False): """Create a team project. :param name: Name of the new project. :type name: str :param team_instance: The URI for the VSTS account (https://<account>.visualstudio.com) or your TFS project collection. :type team_instance: str :param process: Process to use. Default if not specified. :type process: str :param source_control: Source control type of the initial code repository created. Valid options: git (the default) and tfvc. :type source_control: str :param description: Description for the new project. :type description: str :param detect: When 'On' unsupplied arg values will be detected from the current working directory's repo. :type detect: str :param open_browser: Open the team project in the default web browser. :type open_browser: bool :rtype: :class:`<TeamProject> <core.v4_0.models.TeamProject>` """ try: team_instance = resolve_instance(detect=detect, team_instance=team_instance) team_project = TeamProject() team_project.name = name team_project.description = description # private is the only allowed value by vsts right now. team_project.visibility = 'private' core_client = get_core_client(team_instance) # get process template id process_id = None process_list = core_client.get_processes() if process is not None: process_lower = process.lower() for process in process_list: if process.name.lower() == process_lower: process_id = process.id break if process_id is None: raise CLIError('Could not find a process template with name: "{}"'.format(name)) if process_id is None: for process in process_list: if process.is_default: process_id = process.id break if process_id is None: raise CLIError('Could not find a default process template: "{}"'.format(name)) # build capabilities version_control_capabilities = {VERSION_CONTROL_CAPABILITY_ATTRIBUTE_NAME: source_control} process_capabilities = {PROCESS_TEMPLATE_CAPABILITY_TEMPLATE_TYPE_ID_ATTRIBUTE_NAME: process_id} team_project.capabilities = {VERSION_CONTROL_CAPABILITY_NAME: version_control_capabilities, PROCESS_TEMPLATE_CAPABILITY_NAME: process_capabilities} # queue project creation operation_reference = core_client.queue_create_project(project_to_create=team_project) operation = wait_for_long_running_operation(team_instance, operation_reference.id, 1) status = operation.status.lower() if status == 'failed': raise CLIError('Project creation failed.') elif status == 'cancelled': raise CLIError('Project creation was cancelled.') team_project = core_client.get_project(project_id=name, include_capabilities=True) if open_browser: _open_project(team_project) return team_project except Exception as ex: handle_command_exception(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, team_instance=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 project: Name or ID of the project. :type project: str :param skip: Number of pull requests to skip. :type skip: int :param top: Maximum number of pull requests to list. :type top: int :param team_instance: VSTS account or TFS collection URL. Example: https://myaccount.visualstudio.com :type team_instance: str :param detect: Automatically detect instance and project. Default is "on". :type detect: str :rtype: list of :class:`VssJsonCollectionWrapper <git.v4_0.models.VssJsonCollectionWrapper>` """ try: team_instance, project, repository = resolve_instance_project_and_repo( detect=detect, team_instance=team_instance, project=project, repo=repository) search_criteria = GitPullRequestSearchCriteria( creator_id=resolve_identity_as_id(creator, team_instance), include_links=include_links, reviewer_id=resolve_identity_as_id(reviewer, team_instance), source_ref_name=resolve_git_ref_heads(source_branch), status=status, target_ref_name=resolve_git_ref_heads(target_branch)) client = get_git_client(team_instance) 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) except Exception as ex: handle_command_exception(ex) return pr_list