示例#1
0
def list_groups(scope='project',
                project=None,
                continuation_token=None,
                subject_types=None,
                organization=None,
                detect=None):
    """ List all the groups in a project or organization
    :param scope: List groups at project or organization level.
    :type scope: str
    :param continuation_token : If there are more results that can't be returned in a single page, the result set
                                will contain a continuation token for retrieval of the next set of results.
    :type continuation_token: str
    :param subject_types: A comma separated list of user subject subtypes to reduce the retrieved results.
                          You can give initial part of descriptor [before the dot] as a filter e.g. vssgp,aadgp
    :type subject_types: [str]
    :rtype: :class:`<PagedGraphGroups> <azure.devops.v5_0.graph.models.PagedGraphGroups>`
    """
    if scope == 'project':
        organization, project = resolve_instance_and_project(
            detect=detect, organization=organization, project=project)
    else:
        organization = resolve_instance(detect=detect,
                                        organization=organization)
    client = get_graph_client(organization)
    scope_descriptor = None
    if project is not None:
        project_id = get_project_id_from_name(organization, project)
        scope_descriptor = get_descriptor_from_storage_key(project_id, client)
    if subject_types is not None:
        subject_types = subject_types.split(',')
    group_list_response = client.list_groups(
        scope_descriptor=scope_descriptor,
        continuation_token=continuation_token,
        subject_types=subject_types)
    return group_list_response
示例#2
0
def add_membership(member_id, group_id, organization=None, detect=None):
    """Add membership.
    :param member_id: Descriptor of the group or Email Id of the user to be added.
    User should already be a part of the organization. Use `az devops user add` command to add an user to organization.
    :type member_id: str
    :param group_id: Descriptor of the group to which member needs to be added.
    :type group_id: str
    :rtype: :class:`<GraphMembership> <azure.devops.v5_0.graph.models.GraphMembership>`
    """
    organization = resolve_instance(detect=detect, organization=organization)
    client = get_graph_client(organization)
    subject_descriptor = member_id
    if '@' in member_id or '.' not in member_id:
        member_id = resolve_identity_as_id(member_id, organization)
        subject_descriptor = get_descriptor_from_storage_key(member_id, client)
    membership_details = client.add_membership(
        subject_descriptor=subject_descriptor, container_descriptor=group_id)
    lookup_keys = []
    container = GraphSubjectLookupKey(membership_details.container_descriptor)
    subject = GraphSubjectLookupKey(membership_details.member_descriptor)
    lookup_keys.append(container)
    lookup_keys.append(subject)
    subject_lookup = GraphSubjectLookup(lookup_keys=lookup_keys)
    membership_details = client.lookup_subjects(subject_lookup=subject_lookup)
    return membership_details
def list_memberships(id, relationship='members', organization=None, detect=None):  # pylint: disable=redefined-builtin
    """List memberships for a group or user.
    :param id: Group descriptor or User Email whose membership details are required.
    :type id: str
    :rtype: [GraphMembership]
    """
    organization = resolve_instance(detect=detect, organization=organization)
    subject_descriptor = id
    client = get_graph_client(organization)
    if '@' in id or '.' not in id:
        id = resolve_identity_as_id(id, organization)
        subject_descriptor = get_descriptor_from_storage_key(id, client)
    direction = 'down'
    if relationship == 'memberof':
        direction = 'up'
    membership_list = client.list_memberships(subject_descriptor=subject_descriptor, direction=direction)
    lookup_keys = []
    for members in membership_list:
        if relationship == 'memberof':
            key = GraphSubjectLookupKey(members.container_descriptor)
        else:
            key = GraphSubjectLookupKey(members.member_descriptor)
        lookup_keys.append(key)
    subject_lookup = GraphSubjectLookup(lookup_keys=lookup_keys)
    members_details = client.lookup_subjects(subject_lookup=subject_lookup)
    return members_details
def download_package(feed,
                     name,
                     version,
                     path,
                     organization=None,
                     detect=None):
    """(PREVIEW) Download a package.
    :param feed: Name or ID of the feed.
    :type feed: str
    :param name: Name of the package, e.g. 'foo-package'.
    :type name: str
    :param version: Version of the package, e.g. 1.0.0.
    :type version: str
    :param path: Directory to place the package contents.
    :type path: str
    :param organization: Azure Devops organization URL. Example: https://dev.azure.com/MyOrganizationName/
    :type organization: str
    :param detect: Automatically detect organization. Default is "on".
    :type detect: str
    """
    try:
        colorama.init(
        )  # Needed for humanfriendly spinner to display correctly
        logger.warning(_UNIVERSAL_PREVIEW_MESSAGE)
        organization = resolve_instance(detect=detect,
                                        organization=organization)
        artifact_tool = ArtifactToolInvoker(
            ProgressReportingExternalToolInvoker(), ArtifactToolUpdater())
        return artifact_tool.download_universal(organization, feed, name,
                                                version, path)
    except VstsServiceError as ex:
        raise CLIError(ex)
def update_user_entitlement(user,
                            license_type,
                            organization=None,
                            detect=None):
    """Update license type for a user.
    :param user: Email ID or ID of the user.
    :type user: str
    :param license_type: License type for the user.
    :type license_type: str
    :rtype: UserEntitlementsPatchResponse
    """
    patch_document = []
    value = {}
    value['accountLicenseType'] = license_type
    patch_document.append(
        _create_patch_operation('replace', '/accessLevel', value))
    organization = resolve_instance(detect=detect, organization=organization)
    if '@' in user:
        user = resolve_identity_as_id(user, organization)
    client = get_member_entitlement_management_client(organization)
    user_entitlement_update = client.update_user_entitlement(
        document=patch_document, user_id=user)
    if user_entitlement_update.is_success is False and \
            user_entitlement_update.operation_results[0].errors[0] is not None:
        raise CLIError(
            user_entitlement_update.operation_results[0].errors[0]['value'])
    return user_entitlement_update.user_entitlement
def show_namespace(namespace_id, organization=None, detect=None):
    """ Show details of permissions available in each namespace.
    """
    organization = resolve_instance(detect=detect, organization=organization)
    client = get_security_client(organization)
    response = _get_permission_types(client, namespace_id)
    return response
def add_user_entitlement(email_id,
                         license_type,
                         send_email_invite='true',
                         organization=None,
                         detect=None):
    """Add user.
    :param email_id: Email ID of the user.
    :type email_id: str
    :param license_type: License type for the user.
    :type license_type: str
    :rtype: UserEntitlementsPatchResponse
    """
    do_not_send_invite = False
    do_not_send_invite = not resolve_true_false(send_email_invite)
    organization = resolve_instance(detect=detect, organization=organization)
    client = get_member_entitlement_management_client(organization)
    user_access_level = AccessLevel()
    user_access_level.account_license_type = license_type
    graph_user = GraphUser()
    graph_user.subject_kind = 'user'
    graph_user.principal_name = email_id
    value = {}
    value['accessLevel'] = user_access_level
    value['extensions'] = []
    value['projectEntitlements'] = []
    value['user'] = graph_user
    patch_document = []
    patch_document.append(_create_patch_operation('add', '', value))
    user_entitlement = client.update_user_entitlements(
        document=patch_document,
        do_not_send_invite_for_new_users=do_not_send_invite)
    if user_entitlement.have_results_succeeded is False and user_entitlement.results[
            0].errors[0] is not None:
        raise CLIError(user_entitlement.results[0].errors[0]['value'])
    return user_entitlement.results[0].result
def uninstall_extension(publisher_id, extension_id, organization=None, detect=None):
    """ Uninstall an extension
    """
    organization = resolve_instance(detect=detect, organization=organization)
    extension_client = get_extension_client(organization)
    return extension_client.uninstall_extension_by_name(publisher_name=publisher_id,
                                                        extension_name=extension_id)
def update_permissions(namespace_id, subject, token, merge=True, allow_bit=0, deny_bit=0,
                       organization=None, detect=None):
    """ Assign allow or deny permission to given user/group.
    """
    if allow_bit == 0 and deny_bit == 0:
        raise CLIError('Either --allow-bit or --deny-bit parameter should be provided.')
    organization = resolve_instance(detect=detect, organization=organization)
    client = get_security_client(organization)
    subject = _resolve_subject_as_identity_descriptor(subject, organization)
    container_object = {}
    aces_list = []
    ace_object = AccessControlEntry(descriptor=subject, allow=allow_bit, deny=deny_bit)
    aces_list.append(ace_object)
    container_object['token'] = token
    if merge:
        container_object['merge'] = True
    else:
        container_object['merge'] = False
    container_object['accessControlEntries'] = aces_list
    client.set_access_control_entries(security_namespace_id=namespace_id, container=container_object)
    allow_bit = allow_bit & (~deny_bit)
    changed_bits = allow_bit + deny_bit
    list_response = _query_permissions(client, namespace_id, subject, token, False)
    permissions_types = _get_permission_types(client, namespace_id)
    resolved_permissions_response = _resolve_bits(list_response, permissions_types, changed_bits)
    response = _update_json(list_response, resolved_permissions_response)
    return response
示例#10
0
def delete_project(id, organization=None, detect=None):  # pylint: disable=redefined-builtin
    """Delete team project.
    :param id: The id (UUID) of the project to delete.
    :type id: str
    :param organization: Azure Devops organization URL. Example: https://dev.azure.com/MyOrganizationName/
    :type organization: str
    :param detect: When 'On' unsupplied arg values will be detected from the current working
                   directory's repo.
    :type detect: str
    """
    try:
        organization = resolve_instance(detect=detect,
                                        organization=organization)
        core_client = get_core_client(organization)
        operation_reference = core_client.queue_delete_project(project_id=id)
        operation = wait_for_long_running_operation(organization,
                                                    operation_reference.id, 1)
        status = operation.status.lower()
        if status == 'failed':
            raise CLIError('Project deletion failed.')
        elif status == 'cancelled':
            raise CLIError('Project deletion was cancelled.')
        print('Deleted project {}'.format(id))
        return operation
    except VstsServiceError as ex:
        raise CLIError(ex)
示例#11
0
def publish_package(feed,
                    name,
                    version,
                    path,
                    description=None,
                    organization=None,
                    detect=None):
    """Publish a package to a feed.
    :param feed: Name or ID of the feed.
    :type feed: str
    :param name: Name of the package, e.g. 'foo-package'.
    :type name: str
    :param version: Version of the package, e.g. '1.0.0'.
    :type version: str
    :param description: Description of the package.
    :type description: str
    :param path: Directory containing the package contents.
    :type path: str
    """
    colorama.init()  # Needed for humanfriendly spinner to display correctly
    organization = resolve_instance(detect=detect, organization=organization)
    artifact_tool = ArtifactToolInvoker(ProgressReportingExternalToolInvoker(),
                                        ArtifactToolUpdater())
    return artifact_tool.publish_universal(organization, feed, name, version,
                                           description, path)
示例#12
0
def show_work_item(id, open=False, organization=None, detect=None):  # pylint: disable=redefined-builtin
    """Show details for a work item.
    :param id: The ID of the work item
    :type id: int
    :param open: Open the work item in the default web browser.
    :type open: bool
    :param organization: Azure Devops organization URL. Example: https://dev.azure.com/MyOrganizationName/
    :type organization: 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:
        organization = resolve_instance(detect=detect,
                                        organization=organization)
        try:
            client = get_work_item_tracking_client(organization)
            work_item = client.get_work_item(id)
        except VstsServiceError as ex:
            _handle_vsts_service_error(ex)

        if open:
            _open_work_item(work_item, organization)
        return work_item
    except VstsServiceError as ex:
        raise CLIError(ex)
示例#13
0
def show_work_item(id, as_of=None, expand='all', fields=None, open=False, organization=None, detect=None):  # pylint: disable=redefined-builtin
    """Show details for a work item.
    :param id: The ID of the work item
    :type id: int
    :param as_of: Work item details as of a particular date and time. Provide a date or date time string.
    Assumes local time zone. Example: '2019-01-20', '2019-01-20 00:20:00'.
    For UTC, append 'UTC' to the date time string, '2019-01-20 00:20:00 UTC'.
    :type as_of:string
    :param expand: The expand parameters for work item attributes.
    :type expand:str
    :param fields: Comma-separated list of requested fields. Example:System.Id,System.AreaPath.
    Refer https://aka.ms/azure-devops-cli-field-api for more details on fields.
    :type fields: str
    :param open: Open the work item in the default web browser.
    :type open: bool
    :rtype: :class:`<WorkItem> <v5_0.work-item-tracking.models.WorkItem>`
    """
    organization = resolve_instance(detect=detect, organization=organization)
    try:
        client = get_work_item_tracking_client(organization)
        as_of_iso = None
        if as_of:
            as_of_iso = convert_date_string_to_iso8601(value=as_of, argument='as-of')
        if fields:
            fields = fields.split(',')
        work_item = client.get_work_item(id, as_of=as_of_iso, fields=fields, expand=expand)
    except AzureDevOpsServiceError as ex:
        _handle_vsts_service_error(ex)

    if open:
        _open_work_item(work_item, organization)
    return work_item
def list_agents(pool_id,
                agent_name=None,
                include_capabilities=None,
                include_assigned_request=None,
                include_last_completed_request=None,
                demands=None,
                organization=None,
                detect=None):
    """ (PREVIEW) Get a list of agents in a pool
    :param pool_id: The agent pool containing the agents.
    :type pool_id: int
    :param agent_name: Filter on agent name.
    :type agent_name: str
    :param include_capabilities: Whether to include the agents' capabilities in the response.
    :type include_capabilities: bool
    :param include_assigned_request: Whether to include details about the agents' current work.
    :type include_assigned_request: bool
    :param include_last_completed_request: Whether to include details about the agents' most recent completed work.
    :type include_last_completed_request: bool
    :param demands: Filter by demands the agents can satisfy. Comma separated list.
    :type demands: str
    """
    organization = resolve_instance(organization=organization, detect=detect)
    task_agent_client = get_new_task_agent_client(organization=organization)
    if demands:
        demands = list(map(str, demands.split(',')))
    return task_agent_client.get_agents(
        pool_id=pool_id,
        agent_name=agent_name,
        include_capabilities=include_capabilities,
        include_last_completed_request=include_last_completed_request,
        include_assigned_request=include_assigned_request,
        property_filters=None,
        demands=demands)
def show_agent(pool_id,
               agent_id,
               include_capabilities=None,
               include_assigned_request=None,
               include_last_completed_request=None,
               organization=None,
               detect=None):
    """ (PREVIEW) Show agent details
    :param pool_id: The agent pool containing the agent.
    :type pool_id: int
    :param agent_id: The agent ID to get information about.
    :type agent_id: str
    :param include_capabilities: Whether to include the agents' capabilities in the response.
    :type include_capabilities: bool
    :param include_assigned_request: Whether to include details about the agents' current work.
    :type include_assigned_request: bool
    :param include_last_completed_request: Whether to include details about the agents' most recent completed work.
    :type include_last_completed_request: bool
    """
    organization = resolve_instance(organization=organization, detect=detect)
    task_agent_client = get_new_task_agent_client(organization=organization)
    return task_agent_client.get_agent(
        pool_id=pool_id,
        agent_id=agent_id,
        include_capabilities=include_capabilities,
        include_assigned_request=include_assigned_request,
        include_last_completed_request=include_last_completed_request,
        property_filters=None)
def get_extension(publisher_id, extension_id, organization=None, detect=None):
    """ Get detail of single extension
    """
    organization = resolve_instance(detect=detect, organization=organization)
    extension_client = get_extension_client(organization)
    return extension_client.get_installed_extension_by_name(publisher_name=publisher_id,
                                                            extension_name=extension_id)
示例#17
0
def update_group(id,
                 name=None,
                 description=None,
                 organization=None,
                 detect=None):  # pylint: disable=redefined-builtin
    """Update name AND/OR description for an Azure DevOps group.
    :param id: Descriptor of the group.
    :type id: str
    :param name: New name for Azure DevOps group.
    :type name: str
    :param description: New description for Azure DevOps group.
    :type description: str
    :rtype: :class:`<GraphGroup> <azure.devops.v5_0.graph.models.GraphGroup>`
    """
    if name is None and description is None:
        raise CLIError('Either name or description argument must be provided.')
    patch_document = []
    if name is not None:
        patch_document.append(
            _create_patch_operation('replace', '/displayName', name))
    if description is not None:
        patch_document.append(
            _create_patch_operation('replace', '/description', description))
    organization = resolve_instance(detect=detect, organization=organization)
    client = get_graph_client(organization)
    update_group_details = client.update_group(group_descriptor=id,
                                               patch_document=patch_document)
    return update_group_details
示例#18
0
def list_projects(organization=None,
                  top=None,
                  skip=None,
                  state_filter='all',
                  continuation_token=None,
                  get_default_team_image_url=None,
                  detect=None):
    """List team projects
    :param top: Maximum number of results to list.
    :type top: int
    :param skip: Number of results to skip.
    :type skip: int
    :rtype: list of :class:`<TeamProject> <v5_0.core.models.TeamProject>`
    """
    logger.debug('Opening web page: %s', 'Test CLI Release')

    logger.debug('__________________________________________________________________________________________________')

    organization = resolve_instance(detect=detect, organization=organization)
    core_client = get_core_client_v51(organization)
    team_projects = core_client.get_projects(state_filter=state_filter,
                                             top=top,
                                             skip=skip,
                                             continuation_token=continuation_token,
                                             get_default_team_image_url=get_default_team_image_url)
    return team_projects
def _update_extension_state(disable,
                            enable,
                            publisher_name,
                            extension_name,
                            organization=None,
                            detect=None):
    organization = resolve_instance(detect=detect, organization=organization)
    extension_client = get_extension_client(organization)
    current_extension = extension_client.get_installed_extension_by_name(
        publisher_name=publisher_name, extension_name=extension_name)

    state_from_service = str(current_extension.install_state.flags)
    logger.info('state received from service')
    logger.info(state_from_service)

    if disable:
        flags = [x.strip() for x in state_from_service.split(',')]
        if 'disabled' in flags:
            raise CLIError('Extension is already in disabled state')
        flags.append('disabled')
        updated_state = ', '.join(flags)

    if enable:
        flags = [x.strip() for x in state_from_service.split(',')]
        if 'disabled' not in flags:
            raise CLIError('Extension is already in enabled state')
        flags.remove('disabled')
        updated_state = ', '.join(flags)

    current_extension.install_state.flags = updated_state

    return extension_client.update_installed_extension(current_extension)
示例#20
0
def download_package(feed,
                     name,
                     version,
                     path,
                     file_filter=None,
                     organization=None,
                     detect=None):
    """Download a package.
    :param feed: Name or ID of the feed.
    :type feed: str
    :param name: Name of the package, e.g. 'foo-package'.
    :type name: str
    :param version: Version of the package, e.g. 1.0.0.
    :type version: str
    :param path: Directory to place the package contents.
    :type path: str
    :param file_filter: Wildcard filter for file download.
    :type file_filter: str
    """
    colorama.init()  # Needed for humanfriendly spinner to display correctly
    organization = resolve_instance(detect=detect, organization=organization)
    artifact_tool = ArtifactToolInvoker(ProgressReportingExternalToolInvoker(),
                                        ArtifactToolUpdater())
    return artifact_tool.download_universal(organization, feed, name, version,
                                            path, file_filter)
示例#21
0
def add_relation(id,
                 relation_type,
                 target_id=None,
                 target_url=None,
                 organization=None,
                 detect=None):  # pylint: disable=redefined-builtin
    """ Add relation(s) to work item.
    """

    if target_id is None and target_url is None:
        raise CLIError('--target-id or --target-url must be provided')

    organization = resolve_instance(detect=detect, organization=organization)
    patch_document = []
    client = get_work_item_tracking_client(organization)

    relation_types_from_service = client.get_relation_types()
    relation_type_system_name = get_system_relation_name(
        relation_types_from_service, relation_type)

    patch_document = []
    if target_id is not None:
        target_work_item_ids = target_id.split(',')
        work_item_query_clause = []
        for target_work_item_id in target_work_item_ids:
            work_item_query_clause.append(
                '[System.Id] = {}'.format(target_work_item_id))

        wiql_query_format = 'SELECT [System.Id] FROM WorkItems WHERE ({})'
        wiql_query_to_get_target_work_items = wiql_query_format.format(
            ' OR '.join(work_item_query_clause))

        wiql_object = Wiql()
        wiql_object.query = wiql_query_to_get_target_work_items
        target_work_items = client.query_by_wiql(wiql=wiql_object).work_items

        if len(target_work_items) != len(target_work_item_ids):
            raise CLIError('Id(s) supplied in --target-id is not valid')

        for target_work_item in target_work_items:
            op = _create_patch_operation('add', '/relations/-',
                                         relation_type_system_name,
                                         target_work_item.url)
            patch_document.append(op)

    if target_url is not None:
        target_urls = target_url.split(',')

        for url in target_urls:
            op = _create_patch_operation('add', '/relations/-',
                                         relation_type_system_name, url)
            patch_document.append(op)

    client.update_work_item(document=patch_document, id=id)
    work_item = client.get_work_item(id, expand='All')
    work_item = fill_friendly_name_for_relations_in_work_item(
        relation_types_from_service, work_item)

    return work_item
示例#22
0
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
示例#23
0
def create_group(name=None,
                 description=None,
                 origin_id=None,
                 email_id=None,
                 groups=None,
                 scope='project',
                 project=None,
                 organization=None,
                 detect=None):
    """
    :param name: Name of Azure DevOps group.
    :type name: str
    :param description: Description of Azure DevOps group.
    :type description: str
    :param origin_id: Create new group using the OriginID as a reference to an existing group
                      from an external AD or AAD backed provider. Required if name or email-id is missing.
    :type origin_id: str
    :param email_id: Create new group using the mail address as a reference to an existing group
                     from an external AD or AAD backed provider. Required if name or origin-id is missing.
    :type email_id: str
    :param groups: A comma separated list of descriptors referencing groups you want the newly created
                   group to join.
    :type groups: [str]
    :param scope: Create group at project or organization level.
    :type scope: str
    :rtype: :class:`<GraphGroup> <azure.devops.v5_0.graph.models.GraphGroup>`
    """
    if scope == 'project':
        organization, project = resolve_instance_and_project(
            detect=detect, organization=organization, project=project)
    else:
        organization = resolve_instance(detect=detect,
                                        organization=organization)
    client = get_graph_client(organization)
    if name is not None and origin_id is None and email_id is None:
        group_creation_context = GraphGroupVstsCreationContext(
            display_name=name, description=description)
    elif origin_id is not None and email_id is None and name is None:
        group_creation_context = GraphGroupOriginIdCreationContext(
            origin_id=origin_id)
    elif email_id is not None and name is None and origin_id is None:
        group_creation_context = GraphGroupMailAddressCreationContext(
            mail_address=email_id)
    else:
        raise CLIError(
            'Provide exactly one argument out of name, origin-id or email-id.')
    scope_descriptor = None
    if project is not None:
        project_id = get_project_id_from_name(organization, project)
        scope_descriptor = get_descriptor_from_storage_key(project_id, client)
    if groups is not None:
        groups = groups.split(',')
    group_details = client.create_group(
        creation_context=group_creation_context,
        scope_descriptor=scope_descriptor,
        group_descriptors=groups)
    return group_details
def reset_all_permissions(namespace_id, subject, token, organization=None, detect=None):
    """ Clear all permissions of this token for a user/group.
    """
    organization = resolve_instance(detect=detect, organization=organization)
    client = get_security_client(organization)
    subject = _resolve_subject_as_identity_descriptor(subject, organization)
    response = client.remove_access_control_entries(security_namespace_id=namespace_id,
                                                    token=token, descriptors=subject)
    return response
def list_namespaces(local_only=False, organization=None, detect=None):
    """ List all available namespaces for an organization.
    :param local_only: If true, retrieve only local security namespaces.
    :type local_only: bool
    """
    organization = resolve_instance(detect=detect, organization=organization)
    client = get_security_client(organization)
    response = client.query_security_namespaces(local_only=local_only)
    return response
def delete_group(id, organization=None, detect=None):  # pylint: disable=redefined-builtin
    """Delete an Azure DevOps group.
    :param id: Descriptor of the group.
    :type id: str
    """
    organization = resolve_instance(detect=detect, organization=organization)
    client = get_graph_client(organization)
    delete_group_details = client.delete_group(group_descriptor=id)
    return delete_group_details
def get_user_entitlements(top=100, skip=None, organization=None, detect=None):
    """List users in an organization [except for users which are added via AAD groups].
    :param int top: Maximum number of users to return. Max value is 10000.
    :param int skip: Offset: Number of records to skip.
    :rtype: [UserEntitlement]
    """
    organization = resolve_instance(detect=detect, organization=organization)
    client = get_member_entitlement_management_client(organization)
    user_entitlements = client.get_user_entitlements(top=top, skip=skip)
    return user_entitlements
def get_group(id, organization=None, detect=None):  # pylint: disable=redefined-builtin
    """Show group details.
    :param id: Descriptor of the group.
    :type id: str
    :rtype: :class:`<GraphGroup> <azure.devops.v5_0.graph.models.GraphGroup>`
    """
    organization = resolve_instance(detect=detect, organization=organization)
    client = get_graph_client(organization)
    group_details = client.get_group(group_descriptor=id)
    return group_details
def delete_user_entitlement(user, organization=None, detect=None):
    """Remove user from an organization.
    :param user: Email ID or ID of the user.
    :type user: str
    """
    organization = resolve_instance(detect=detect, organization=organization)
    if '@' in user:
        user = resolve_identity_as_id(user, organization)
    client = get_member_entitlement_management_client(organization)
    delete_user_entitlement_details = client.delete_user_entitlement(user_id=user)
    return delete_user_entitlement_details
def show_work_item(id, organization=None, detect=None):  # pylint: disable=redefined-builtin
    """ Get work item, fill relations with friendly name
    """
    organization = resolve_instance(detect=detect, organization=organization)
    client = get_work_item_tracking_client(organization)

    work_item = client.get_work_item(id, expand='All')
    relation_types_from_service = client.get_relation_types()
    work_item = fill_friendly_name_for_relations_in_work_item(
        relation_types_from_service, work_item)
    return work_item