summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.readthedocs.yml13
-rw-r--r--.renovaterc.json9
-rw-r--r--docs/gl_objects/users.rst4
-rw-r--r--gitlab/tests/objects/test_resource_label_events.py105
-rw-r--r--gitlab/tests/objects/test_users.py17
-rw-r--r--gitlab/v4/objects/__init__.py16
-rwxr-xr-xtools/build_test_env.sh2
-rw-r--r--tools/functional/api/test_users.py20
8 files changed, 185 insertions, 1 deletions
diff --git a/.readthedocs.yml b/.readthedocs.yml
new file mode 100644
index 0000000..69f8c3a
--- /dev/null
+++ b/.readthedocs.yml
@@ -0,0 +1,13 @@
+version: 2
+
+sphinx:
+ configuration: docs/conf.py
+
+formats:
+ - pdf
+ - epub
+
+python:
+ version: 3.8
+ install:
+ - requirements: rtd-requirements.txt
diff --git a/.renovaterc.json b/.renovaterc.json
index 2b6699f..be47e3a 100644
--- a/.renovaterc.json
+++ b/.renovaterc.json
@@ -1,4 +1,7 @@
{
+ "extends": [
+ "config:base"
+ ],
"regexManagers": [
{
"fileMatch": ["^tools/build_test_env.sh$"],
@@ -7,5 +10,11 @@
"datasourceTemplate": "docker",
"versioningTemplate": "loose"
}
+ ],
+ "packageRules": [
+ {
+ "packagePatterns": ["^gitlab\/gitlab-.+$"],
+ "automerge": true
+ }
]
}
diff --git a/docs/gl_objects/users.rst b/docs/gl_objects/users.rst
index 5b1cf3d..9f2d42c 100644
--- a/docs/gl_objects/users.rst
+++ b/docs/gl_objects/users.rst
@@ -80,6 +80,10 @@ Set an external identity for a user::
user.extern_uid = '3'
user.save()
+Delete an external identity by provider name::
+
+ user.identityproviders.delete('oauth2_generic')
+
User custom attributes
======================
diff --git a/gitlab/tests/objects/test_resource_label_events.py b/gitlab/tests/objects/test_resource_label_events.py
new file mode 100644
index 0000000..07f891c
--- /dev/null
+++ b/gitlab/tests/objects/test_resource_label_events.py
@@ -0,0 +1,105 @@
+"""
+GitLab API: https://docs.gitlab.com/ee/api/resource_label_events.html
+"""
+
+import pytest
+import responses
+
+from gitlab.v4.objects import (
+ ProjectIssueResourceLabelEvent,
+ ProjectMergeRequestResourceLabelEvent,
+ GroupEpicResourceLabelEvent,
+)
+
+
+@pytest.fixture()
+def resp_group_epic_request_label_events():
+ epic_content = {"id": 1}
+ events_content = {"id": 1, "resource_type": "Epic"}
+ with responses.RequestsMock() as rsps:
+ rsps.add(
+ method=responses.GET,
+ url="http://localhost/api/v4/groups/1/epics",
+ json=[epic_content],
+ content_type="application/json",
+ status=200,
+ )
+ rsps.add(
+ method=responses.GET,
+ url="http://localhost/api/v4/groups/1/epics/1/resource_label_events",
+ json=[events_content],
+ content_type="application/json",
+ status=200,
+ )
+ yield rsps
+
+
+@pytest.fixture()
+def resp_merge_request_label_events():
+ mr_content = {"iid": 1}
+ events_content = {"id": 1, "resource_type": "MergeRequest"}
+ with responses.RequestsMock() as rsps:
+ rsps.add(
+ method=responses.GET,
+ url="http://localhost/api/v4/projects/1/merge_requests",
+ json=[mr_content],
+ content_type="application/json",
+ status=200,
+ )
+ rsps.add(
+ method=responses.GET,
+ url="http://localhost/api/v4/projects/1/merge_requests/1/resource_label_events",
+ json=[events_content],
+ content_type="application/json",
+ status=200,
+ )
+ yield rsps
+
+
+@pytest.fixture()
+def resp_project_issue_label_events():
+ issue_content = {"iid": 1}
+ events_content = {"id": 1, "resource_type": "Issue"}
+ with responses.RequestsMock() as rsps:
+ rsps.add(
+ method=responses.GET,
+ url="http://localhost/api/v4/projects/1/issues",
+ json=[issue_content],
+ content_type="application/json",
+ status=200,
+ )
+ rsps.add(
+ method=responses.GET,
+ url="http://localhost/api/v4/projects/1/issues/1/resource_label_events",
+ json=[events_content],
+ content_type="application/json",
+ status=200,
+ )
+ yield rsps
+
+
+def test_project_issue_label_events(project, resp_project_issue_label_events):
+ issue = project.issues.list()[0]
+ label_events = issue.resourcelabelevents.list()
+ assert isinstance(label_events, list)
+ label_event = label_events[0]
+ assert isinstance(label_event, ProjectIssueResourceLabelEvent)
+ assert label_event.resource_type == "Issue"
+
+
+def test_merge_request_label_events(project, resp_merge_request_label_events):
+ mr = project.mergerequests.list()[0]
+ label_events = mr.resourcelabelevents.list()
+ assert isinstance(label_events, list)
+ label_event = label_events[0]
+ assert isinstance(label_event, ProjectMergeRequestResourceLabelEvent)
+ assert label_event.resource_type == "MergeRequest"
+
+
+def test_group_epic_request_label_events(group, resp_group_epic_request_label_events):
+ epic = group.epics.list()[0]
+ label_events = epic.resourcelabelevents.list()
+ assert isinstance(label_events, list)
+ label_event = label_events[0]
+ assert isinstance(label_event, GroupEpicResourceLabelEvent)
+ assert label_event.resource_type == "Epic"
diff --git a/gitlab/tests/objects/test_users.py b/gitlab/tests/objects/test_users.py
index ec282cf..f84e877 100644
--- a/gitlab/tests/objects/test_users.py
+++ b/gitlab/tests/objects/test_users.py
@@ -95,6 +95,19 @@ def resp_get_user_status():
yield rsps
+@pytest.fixture
+def resp_delete_user_identity(no_content):
+ with responses.RequestsMock() as rsps:
+ rsps.add(
+ method=responses.DELETE,
+ url="http://localhost/api/v4/users/1/identities/test_provider",
+ json=no_content,
+ content_type="application/json",
+ status=204,
+ )
+ yield rsps
+
+
def test_get_user(gl, resp_get_user):
user = gl.users.get(1)
assert isinstance(user, User)
@@ -118,3 +131,7 @@ def test_user_status(user, resp_get_user_status):
def test_user_activate_deactivate(user, resp_activate):
user.activate()
user.deactivate()
+
+
+def test_delete_user_identity(user, resp_delete_user_identity):
+ user.identityproviders.delete("test_provider")
diff --git a/gitlab/v4/objects/__init__.py b/gitlab/v4/objects/__init__.py
index f9a2c25..016caec 100644
--- a/gitlab/v4/objects/__init__.py
+++ b/gitlab/v4/objects/__init__.py
@@ -217,6 +217,17 @@ class UserStatusManager(GetWithoutIdMixin, RESTManager):
_from_parent_attrs = {"user_id": "id"}
+class UserIdentityProviderManager(DeleteMixin, RESTManager):
+ """Manager for user identities.
+
+ This manager does not actually manage objects but enables
+ functionality for deletion of user identities by provider.
+ """
+
+ _path = "/users/%(user_id)s/identities"
+ _from_parent_attrs = {"user_id": "id"}
+
+
class UserImpersonationToken(ObjectDeleteMixin, RESTObject):
pass
@@ -320,6 +331,7 @@ class User(SaveMixin, ObjectDeleteMixin, RESTObject):
("emails", "UserEmailManager"),
("events", "UserEventManager"),
("gpgkeys", "UserGPGKeyManager"),
+ ("identityproviders", "UserIdentityProviderManager"),
("impersonationtokens", "UserImpersonationTokenManager"),
("keys", "UserKeyManager"),
("memberships", "UserMembershipManager"),
@@ -1210,6 +1222,7 @@ class GroupMergeRequestManager(ListMixin, RESTManager):
"source_branch",
"target_branch",
"search",
+ "wip",
)
_types = {"labels": types.ListAttribute}
@@ -1732,6 +1745,7 @@ class MergeRequestManager(ListMixin, RESTManager):
"source_branch",
"target_branch",
"search",
+ "wip",
)
_types = {"labels": types.ListAttribute}
@@ -3402,6 +3416,7 @@ class ProjectMergeRequestManager(CRUDMixin, RESTManager):
"source_branch",
"target_branch",
"search",
+ "wip",
)
_types = {"labels": types.ListAttribute}
@@ -5475,6 +5490,7 @@ class RunnerManager(CRUDMixin, RESTManager):
"locked",
"run_untagged",
"tag_list",
+ "access_level",
"maximum_timeout",
),
)
diff --git a/tools/build_test_env.sh b/tools/build_test_env.sh
index 24c56f5..e3b6d12 100755
--- a/tools/build_test_env.sh
+++ b/tools/build_test_env.sh
@@ -29,7 +29,7 @@ REUSE_CONTAINER=
NOVENV=
API_VER=4
DEFAULT_GITLAB_IMAGE=gitlab/gitlab-ce
-DEFAULT_GITLAB_TAG=13.3.4-ce.0
+DEFAULT_GITLAB_TAG=13.3.5-ce.0
GITLAB_IMAGE="${GITLAB_IMAGE:-$DEFAULT_GITLAB_IMAGE}"
GITLAB_TAG="${GITLAB_TAG:-$DEFAULT_GITLAB_TAG}"
VENV_CMD="python3 -m venv"
diff --git a/tools/functional/api/test_users.py b/tools/functional/api/test_users.py
new file mode 100644
index 0000000..f70da4a
--- /dev/null
+++ b/tools/functional/api/test_users.py
@@ -0,0 +1,20 @@
+"""
+GitLab API:
+https://docs.gitlab.com/ee/api/users.html
+https://docs.gitlab.com/ee/api/users.html#delete-authentication-identity-from-user
+"""
+
+
+def test_user_identities(gl, user):
+ provider = "test_provider"
+
+ user.provider = provider
+ user.extern_uid = "1"
+ user.save()
+
+ assert provider in [item["provider"] for item in user.identities]
+
+ user.identityproviders.delete(provider)
+ user = gl.users.get(user.id)
+
+ assert provider not in [item["provider"] for item in user.identities]