######
Groups
######

Groups
======

Reference
---------

* v4 API:

  + :class:`gitlab.v4.objects.Group`
  + :class:`gitlab.v4.objects.GroupManager`
  + :attr:`gitlab.Gitlab.groups`

* GitLab API: https://docs.gitlab.com/api/groups

Examples
--------

List the groups::

    groups = gl.groups.list(get_all=True)

Get a group's detail::

    group = gl.groups.get(group_id)

List a group's projects::

    projects = group.projects.list(get_all=True)

List a group's shared projects::

    projects = group.shared_projects.list(get_all=True)

.. note::

   ``GroupProject`` and ``SharedProject`` objects returned by these two API calls
   are very limited, and do not provide all the features of ``Project`` objects.
   If you need to manipulate projects, create a new ``Project`` object::

       first_group_project = group.projects.list(get_all=False)[0]
       manageable_project = gl.projects.get(first_group_project.id, lazy=True)

You can filter and sort the result using the following parameters:

* ``archived``: limit by archived status
* ``visibility``: limit by visibility. Allowed values are ``public``,
  ``internal`` and ``private``
* ``search``: limit to groups matching the given value
* ``order_by``: sort by criteria. Allowed values are ``id``, ``name``, ``path``,
  ``created_at``, ``updated_at`` and ``last_activity_at``
* ``sort``: sort order: ``asc`` or ``desc``
* ``ci_enabled_first``: return CI enabled groups first
* ``include_subgroups``: include projects in subgroups

Create a group::

    group = gl.groups.create({'name': 'group1', 'path': 'group1'})

.. warning::

   On GitLab.com, creating top-level groups is currently
   `not permitted using the API <https://docs.gitlab.com/api/groups#new-group>`_.
   You can only use the API to create subgroups.

Create a subgroup under an existing group::

    subgroup = gl.groups.create({'name': 'subgroup1', 'path': 'subgroup1', 'parent_id': parent_group_id})

Update a group::

    group.description = 'My awesome group'
    group.save()

Set the avatar image for a group::

    # the avatar image can be passed as data (content of the file) or as a file
    # object opened in binary mode
    group.avatar = open('path/to/file.png', 'rb')
    group.save()

Remove the avatar image for a group::

    group.avatar = ""
    group.save()

Remove a group::

    gl.groups.delete(group_id)
    # or
    group.delete()

Restore a Group marked for deletion (Premium only):::

    group.restore()


Share/unshare the group with a group::

    group.share(group2.id, gitlab.const.AccessLevel.DEVELOPER)
    group.unshare(group2.id)

Import / Export
===============

You can export groups from gitlab, and re-import them to create new groups.

Reference
---------

* v4 API:

  + :class:`gitlab.v4.objects.GroupExport`
  + :class:`gitlab.v4.objects.GroupExportManager`
  + :attr:`gitlab.v4.objects.Group.exports`
  + :class:`gitlab.v4.objects.GroupImport`
  + :class:`gitlab.v4.objects.GroupImportManager`
  + :attr:`gitlab.v4.objects.Group.imports`
  + :attr:`gitlab.v4.objects.GroupManager.import_group`

* GitLab API: https://docs.gitlab.com/api/group_import_export

Examples
--------

A group export is an asynchronous operation. To retrieve the archive
generated by GitLab you need to:

#. Create an export using the API
#. Wait for the export to be done
#. Download the result

.. warning::

   Unlike the Project Export API, GitLab does not provide an export_status
   for Group Exports. It is up to the user to ensure the export is finished.

   However, Group Exports only contain metadata, so they are much faster
   than Project Exports.

::

    # Create the export
    group = gl.groups.get(my_group)
    export = group.exports.create()

    # Wait for the export to finish
    time.sleep(3)

    # Download the result
    with open('/tmp/export.tgz', 'wb') as f:
        export.download(streamed=True, action=f.write)

Import the group::

    with open('/tmp/export.tgz', 'rb') as f:
        gl.groups.import_group(f, path='imported-group', name="Imported Group")

Subgroups
=========

Reference
---------

* v4 API:

  + :class:`gitlab.v4.objects.GroupSubgroup`
  + :class:`gitlab.v4.objects.GroupSubgroupManager`
  + :attr:`gitlab.v4.objects.Group.subgroups`

Examples
--------

List the subgroups for a group::

    subgroups = group.subgroups.list(get_all=True)

.. note::

    The ``GroupSubgroup`` objects don't expose the same API as the ``Group``
    objects.  If you need to manipulate a subgroup as a group, create a new
    ``Group`` object::

        real_group = gl.groups.get(subgroup_id, lazy=True)
        real_group.issues.list(get_all=True)

Descendant Groups
=================

Reference
---------

* v4 API:

  + :class:`gitlab.v4.objects.GroupDescendantGroup`
  + :class:`gitlab.v4.objects.GroupDescendantGroupManager`
  + :attr:`gitlab.v4.objects.Group.descendant_groups`

Examples
--------

List the descendant groups of a group::

    descendant_groups = group.descendant_groups.list(get_all=True)

.. note::

    Like the ``GroupSubgroup`` objects described above, ``GroupDescendantGroup``
    objects do not expose the same API as the ``Group`` objects. Create a new
    ``Group`` object instead if needed, as shown in the subgroup example.

Group custom attributes
=======================

Reference
---------

* v4 API:

  + :class:`gitlab.v4.objects.GroupCustomAttribute`
  + :class:`gitlab.v4.objects.GroupCustomAttributeManager`
  + :attr:`gitlab.v4.objects.Group.customattributes`

* GitLab API: https://docs.gitlab.com/api/custom_attributes

Examples
--------

List custom attributes for a group::

    attrs = group.customattributes.list(get_all=True)

Get a custom attribute for a group::

    attr = group.customattributes.get(attr_key)

Set (create or update) a custom attribute for a group::

    attr = group.customattributes.set(attr_key, attr_value)

Delete a custom attribute for a group::

    attr.delete()
    # or
    group.customattributes.delete(attr_key)

Search groups by custom attribute::

    group.customattributes.set('role': 'admin')
    gl.groups.list(custom_attributes={'role': 'admin'}, get_all=True)

Group members
=============

The following constants define the supported access levels:

* ``gitlab.const.AccessLevel.GUEST = 10``
* ``gitlab.const.AccessLevel.REPORTER = 20``
* ``gitlab.const.AccessLevel.DEVELOPER = 30``
* ``gitlab.const.AccessLevel.MAINTAINER = 40``
* ``gitlab.const.AccessLevel.OWNER = 50``

Reference
---------

* v4 API:

  + :class:`gitlab.v4.objects.GroupMember`
  + :class:`gitlab.v4.objects.GroupMemberManager`
  + :class:`gitlab.v4.objects.GroupMemberAllManager`
  + :class:`gitlab.v4.objects.GroupBillableMember`
  + :class:`gitlab.v4.objects.GroupBillableMemberManager`
  + :attr:`gitlab.v4.objects.Group.members`
  + :attr:`gitlab.v4.objects.Group.members_all`
  + :attr:`gitlab.v4.objects.Group.billable_members`

* GitLab API: https://docs.gitlab.com/api/members

Billable group members are only available in GitLab EE.

Examples
--------

List only direct group members::

    members = group.members.list(get_all=True)

List the group members recursively (including inherited members through
ancestor groups)::

    members = group.members_all.list(get_all=True)

Get only direct group member::

    members = group.members.get(member_id)

Get a member of a group, including members inherited through ancestor groups::

    members = group.members_all.get(member_id)

Add a member to the group::

    member = group.members.create({'user_id': user_id,
                                   'access_level': gitlab.const.AccessLevel.GUEST})

Update a member (change the access level)::

    member.access_level = gitlab.const.AccessLevel.DEVELOPER
    member.save()

Remove a member from the group::

    group.members.delete(member_id)
    # or
    member.delete()

List billable members of a group (top-level groups only)::

    billable_members = group.billable_members.list(get_all=True)

Remove a billable member from the group::

    group.billable_members.delete(member_id)
    # or
    billable_member.delete()

List memberships of a billable member::

    billable_member.memberships.list(get_all=True)

LDAP group links
================

Add an LDAP group link to an existing GitLab group::

    ldap_link = group.ldap_group_links.create({
        'provider': 'ldapmain',
        'group_access': gitlab.const.AccessLevel.DEVELOPER,
        'cn: 'ldap_group_cn'
    })

List a group's LDAP group links::

    group.ldap_group_links.list(get_all=True)

Remove a link::

    ldap_link.delete()
    # or by explicitly providing the CN or filter
    group.ldap_group_links.delete(provider='ldapmain', cn='ldap_group_cn')
    group.ldap_group_links.delete(provider='ldapmain', filter='(cn=Common Name)')

Sync the LDAP groups::

    group.ldap_sync()

You can use the ``ldapgroups`` manager to list available LDAP groups::

    # listing (supports pagination)
    ldap_groups = gl.ldapgroups.list(get_all=True)

    # filter using a group name
    ldap_groups = gl.ldapgroups.list(search='foo', get_all=True)

    # list the groups for a specific LDAP provider
    ldap_groups = gl.ldapgroups.list(search='foo', provider='ldapmain', get_all=True)

SAML group links
================

Add a SAML group link to an existing GitLab group::

    saml_link = group.saml_group_links.create({
        "saml_group_name": "<your_saml_group_name>",
        "access_level": <chosen_access_level>
    })

List a group's SAML group links::

    group.saml_group_links.list(get_all=True)

Get a SAML group link::

    group.saml_group_links.get("<your_saml_group_name>")

Remove a link::

    saml_link.delete()

Groups hooks
============

Reference
---------

* v4 API:

  + :class:`gitlab.v4.objects.GroupHook`
  + :class:`gitlab.v4.objects.GroupHookManager`
  + :attr:`gitlab.v4.objects.Group.hooks`

* GitLab API: https://docs.gitlab.com/api/groups#hooks

Examples
--------

List the group hooks::

    hooks = group.hooks.list(get_all=True)

Get a group hook::

    hook = group.hooks.get(hook_id)

Create a group hook::

    hook = group.hooks.create({'url': 'http://my/action/url', 'push_events': 1})

Update a group hook::

    hook.push_events = 0
    hook.save()

Test a group hook::

    hook.test("push_events")

Delete a group hook::

    group.hooks.delete(hook_id)
    # or
    hook.delete()

Group push rules
==================

Reference
---------

* v4 API:

  + :class:`gitlab.v4.objects.GroupPushRules`
  + :class:`gitlab.v4.objects.GroupPushRulesManager`
  + :attr:`gitlab.v4.objects.Group.pushrules`

* GitLab API: https://docs.gitlab.com/api/groups#push-rules

Examples
---------

Create group push rules (at least one rule is necessary)::

    group.pushrules.create({'deny_delete_tag': True})

Get group push rules::

    pr = group.pushrules.get()

Edit group push rules::

    pr.branch_name_regex = '^(master|develop|support-\d+|release-\d+\..+|hotfix-.+|feature-.+)$'
    pr.save()

Delete group push rules::

    pr.delete()

Group Service Account
=====================

Reference
---------

* v4 API:

  + :class:`gitlab.v4.objects.GroupServiceAccount`
  + :class:`gitlab.v4.objects.GroupServiceAccountManager`
  + :attr:`gitlab.v4.objects.Group.serviceaccounts`

* GitLab API: https://docs.gitlab.com/api/groups#service-accounts

Examples
---------

Create group service account (only allowed at top level group)::

    group.serviceaccount.create({'name': 'group-service-account', 'username': 'group-service-account'})
