diff --git a/docs/gl_objects/projects.rst b/docs/gl_objects/projects.rst index fa8342631..9bd98b125 100644 --- a/docs/gl_objects/projects.rst +++ b/docs/gl_objects/projects.rst @@ -608,6 +608,10 @@ Get a service:: # display its status (enabled/disabled) print(service.active) +List active project services:: + + service = project.services.list() + List the code names of available services (doesn't return objects):: services = project.services.available() diff --git a/gitlab/tests/objects/test_projects.py b/gitlab/tests/objects/test_projects.py index 48347f92f..6a2840ad4 100644 --- a/gitlab/tests/objects/test_projects.py +++ b/gitlab/tests/objects/test_projects.py @@ -161,6 +161,102 @@ def resp_update_remote_mirror(url, request): return response(200, content, headers, None, 5, request) +@urlmatch( + scheme="http", + netloc="localhost", + path="/api/v4/projects/1/services/pipelines-email", + method="put", +) +def resp_update_service(url, request): + """Mock for Service update PUT response.""" + content = """{ + "id": 100152, + "title": "Pipelines emails", + "slug": "pipelines-email", + "created_at": "2019-01-14T08:46:43.637+01:00", + "updated_at": "2019-07-01T14:10:36.156+02:00", + "active": true, + "commit_events": true, + "push_events": true, + "issues_events": true, + "confidential_issues_events": true, + "merge_requests_events": true, + "tag_push_events": true, + "note_events": true, + "confidential_note_events": true, + "pipeline_events": true, + "wiki_page_events": true, + "job_events": true, + "comment_on_event_enabled": true, + "project_id": 1 + }""" + content = content.encode("utf-8") + return response(200, content, headers, None, 5, request) + + +@urlmatch( + scheme="http", + netloc="localhost", + path="/api/v4/projects/1/services/pipelines-email", + method="get", +) +def resp_get_service(url, request): + """Mock for Service GET response.""" + content = """{ + "id": 100152, + "title": "Pipelines emails", + "slug": "pipelines-email", + "created_at": "2019-01-14T08:46:43.637+01:00", + "updated_at": "2019-07-01T14:10:36.156+02:00", + "active": true, + "commit_events": true, + "push_events": true, + "issues_events": true, + "confidential_issues_events": true, + "merge_requests_events": true, + "tag_push_events": true, + "note_events": true, + "confidential_note_events": true, + "pipeline_events": true, + "wiki_page_events": true, + "job_events": true, + "comment_on_event_enabled": true, + "project_id": 1 + }""" + content = content.encode("utf-8") + return response(200, content, headers, None, 5, request) + + +@urlmatch( + scheme="http", netloc="localhost", path="/api/v4/projects/1/services", method="get", +) +def resp_get_active_services(url, request): + """Mock for active Services GET response.""" + content = """[{ + "id": 100152, + "title": "Pipelines emails", + "slug": "pipelines-email", + "created_at": "2019-01-14T08:46:43.637+01:00", + "updated_at": "2019-07-01T14:10:36.156+02:00", + "active": true, + "commit_events": true, + "push_events": true, + "issues_events": true, + "confidential_issues_events": true, + "merge_requests_events": true, + "tag_push_events": true, + "note_events": true, + "confidential_note_events": true, + "pipeline_events": true, + "wiki_page_events": true, + "job_events": true, + "comment_on_event_enabled": true, + "project_id": 1 + }]""" + content = content.encode("utf-8") + return response(200, content, headers, None, 5, request) + + class TestProject(unittest.TestCase): """Base class for GitLab Project tests.""" @@ -169,7 +265,7 @@ def setUp(self): "http://localhost", private_token="private_token", ssl_verify=True, - api_version=4, + api_version="4", ) self.project = self.gl.projects.get(1, lazy=True) @@ -356,3 +452,31 @@ def test_update_project_remote_mirror(self): mirror.save() self.assertEqual(mirror.update_status, "finished") self.assertTrue(mirror.only_protected_branches) + + +class TestProjectServices(TestProject): + @with_httmock(resp_get_active_services) + def test_list_active_services(self): + services = self.project.services.list() + self.assertIsInstance(services, list) + self.assertIsInstance(services[0], ProjectService) + self.assertTrue(services[0].active) + self.assertTrue(services[0].push_events) + + def test_list_available_services(self): + services = self.project.services.available() + self.assertIsInstance(services, list) + self.assertIsInstance(services[0], str) + + @with_httmock(resp_get_service) + def test_get_service(self): + service = self.project.services.get("pipelines-email") + self.assertIsInstance(service, ProjectService) + self.assertEqual(service.push_events, True) + + @with_httmock(resp_get_service, resp_update_service) + def test_update_service(self): + service = self.project.services.get("pipelines-email") + service.issues_events = True + service.save() + self.assertEqual(service.issues_events, True) diff --git a/gitlab/v4/objects.py b/gitlab/v4/objects.py index 29b10fc1d..a76332c7f 100644 --- a/gitlab/v4/objects.py +++ b/gitlab/v4/objects.py @@ -3995,58 +3995,234 @@ class ProjectService(SaveMixin, ObjectDeleteMixin, RESTObject): pass -class ProjectServiceManager(GetMixin, UpdateMixin, DeleteMixin, RESTManager): +class ProjectServiceManager(GetMixin, UpdateMixin, DeleteMixin, ListMixin, RESTManager): _path = "/projects/%(project_id)s/services" _from_parent_attrs = {"project_id": "id"} _obj_cls = ProjectService _service_attrs = { - "asana": (("api_key",), ("restrict_to_branch",)), - "assembla": (("token",), ("subdomain",)), - "bamboo": (("bamboo_url", "build_key", "username", "password"), tuple()), - "buildkite": (("token", "project_url"), ("enable_ssl_verification",)), - "campfire": (("token",), ("subdomain", "room")), + "asana": (("api_key",), ("restrict_to_branch", "push_events")), + "assembla": (("token",), ("subdomain", "push_events")), + "bamboo": ( + ("bamboo_url", "build_key", "username", "password"), + ("push_events",), + ), + "bugzilla": ( + ("new_issue_url", "issues_url", "project_url"), + ("description", "title", "push_events"), + ), + "buildkite": ( + ("token", "project_url"), + ("enable_ssl_verification", "push_events"), + ), + "campfire": (("token",), ("subdomain", "room", "push_events")), + "circuit": ( + ("webhook",), + ( + "notify_only_broken_pipelines", + "branches_to_be_notified", + "push_events", + "issues_events", + "confidential_issues_events", + "merge_requests_events", + "tag_push_events", + "note_events", + "confidential_note_events", + "pipeline_events", + "wiki_page_events", + ), + ), "custom-issue-tracker": ( ("new_issue_url", "issues_url", "project_url"), - ("description", "title"), + ("description", "title", "push_events"), + ), + "drone-ci": ( + ("token", "drone_url"), + ( + "enable_ssl_verification", + "push_events", + "merge_requests_events", + "tag_push_events", + ), ), - "drone-ci": (("token", "drone_url"), ("enable_ssl_verification",)), "emails-on-push": ( ("recipients",), - ("disable_diffs", "send_from_committer_email"), + ( + "disable_diffs", + "send_from_committer_email", + "push_events", + "tag_push_events", + "branches_to_be_notified", + ), ), - "builds-email": (("recipients",), ("add_pusher", "notify_only_broken_builds")), "pipelines-email": ( ("recipients",), - ("add_pusher", "notify_only_broken_builds"), + ( + "add_pusher", + "notify_only_broken_builds", + "branches_to_be_notified", + "notify_only_default_branch", + "pipeline_events", + ), ), "external-wiki": (("external_wiki_url",), tuple()), - "flowdock": (("token",), tuple()), - "gemnasium": (("api_key", "token"), tuple()), - "hipchat": (("token",), ("color", "notify", "room", "api_version", "server")), + "flowdock": (("token",), ("push_events",)), + "github": (("token", "repository_url"), ("static_context",)), + "hangouts-chat": ( + ("webhook",), + ( + "notify_only_broken_pipelines", + "notify_only_default_branch", + "branches_to_be_notified", + "push_events", + "issues_events", + "confidential_issues_events", + "merge_requests_events", + "tag_push_events", + "note_events", + "confidential_note_events", + "pipeline_events", + "wiki_page_events", + ), + ), + "hipchat": ( + ("token",), + ( + "color", + "notify", + "room", + "api_version", + "server", + "push_events", + "issues_events", + "confidential_issues_events", + "merge_requests_events", + "tag_push_events", + "note_events", + "confidential_note_events", + "pipeline_events", + ), + ), "irker": ( ("recipients",), - ("default_irc_uri", "server_port", "server_host", "colorize_messages"), + ( + "default_irc_uri", + "server_port", + "server_host", + "colorize_messages", + "push_events", + ), ), "jira": ( - ("url", "project_key"), + ("url", "username", "password",), ( - "new_issue_url", - "project_url", - "issues_url", "api_url", - "description", - "username", - "password", + "active", "jira_issue_transition_id", + "commit_events", + "merge_requests_events", + "comment_on_event_enabled", + ), + ), + "slack-slash-commands": (("token",), tuple()), + "mattermost-slash-commands": (("token",), ("username",)), + "packagist": ( + ("username", "token"), + ("server", "push_events", "merge_requests_events", "tag_push_events"), + ), + "mattermost": ( + ("webhook",), + ( + "username", + "channel", + "notify_only_broken_pipelines", + "notify_only_default_branch", + "branches_to_be_notified", + "push_events", + "issues_events", + "confidential_issues_events", + "merge_requests_events", + "tag_push_events", + "note_events", + "confidential_note_events", + "pipeline_events", + "wiki_page_events", + "push_channel", + "issue_channel", + "confidential_issue_channel" "merge_request_channel", + "note_channel", + "confidential_note_channel", + "tag_push_channel", + "pipeline_channel", + "wiki_page_channel", ), ), - "mattermost": (("webhook",), ("username", "channel")), - "pivotaltracker": (("token",), tuple()), - "pushover": (("api_key", "user_key", "priority"), ("device", "sound")), - "redmine": (("new_issue_url", "project_url", "issues_url"), ("description",)), - "slack": (("webhook",), ("username", "channel")), - "teamcity": (("teamcity_url", "build_type", "username", "password"), tuple()), + "pivotaltracker": (("token",), ("restrict_to_branch", "push_events")), + "prometheus": (("api_url",), tuple()), + "pushover": ( + ("api_key", "user_key", "priority"), + ("device", "sound", "push_events"), + ), + "redmine": ( + ("new_issue_url", "project_url", "issues_url"), + ("description", "push_events"), + ), + "slack": ( + ("webhook",), + ( + "username", + "channel", + "notify_only_broken_pipelines", + "notify_only_default_branch", + "branches_to_be_notified", + "commit_events", + "confidential_issue_channel", + "confidential_issues_events", + "confidential_note_channel", + "confidential_note_events", + "deployment_channel", + "deployment_events", + "issue_channel", + "issues_events", + "job_events", + "merge_request_channel", + "merge_requests_events", + "note_channel", + "note_events", + "pipeline_channel", + "pipeline_events", + "push_channel", + "push_events", + "tag_push_channel", + "tag_push_events", + "wiki_page_channel", + "wiki_page_events", + ), + ), + "microsoft-teams": ( + ("webhook",), + ( + "notify_only_broken_pipelines", + "notify_only_default_branch", + "branches_to_be_notified", + "push_events", + "issues_events", + "confidential_issues_events", + "merge_requests_events", + "tag_push_events", + "note_events", + "confidential_note_events", + "pipeline_events", + "wiki_page_events", + ), + ), + "teamcity": ( + ("teamcity_url", "build_type", "username", "password"), + ("push_events",), + ), + "jenkins": (("jenkins_url", "project_name"), ("username", "password")), + "mock-ci": (("mock_service_url",), tuple()), + "youtrack": (("issues_url", "project_url"), ("description", "push_events")), } def get(self, id, **kwargs):