Skip to content

Commit 78879f8

Browse files
committed
merge master
2 parents de94f66 + 7907e5a commit 78879f8

File tree

9 files changed

+374
-34
lines changed

9 files changed

+374
-34
lines changed

README.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ You need to install ``tox`` to run unit tests and documentation builds locally:
133133
tox
134134
135135
# run tests in one environment only:
136-
tox -epy36
136+
tox -epy38
137137
138138
# build the documentation, the result will be generated in
139139
# build/sphinx/html/
@@ -151,10 +151,10 @@ To run these tests:
151151
.. code-block:: bash
152152
153153
# run the CLI tests:
154-
./tools/functional_tests.sh
154+
tox -e cli_func_v4
155155
156156
# run the python API tests:
157-
./tools/py_functional_tests.sh
157+
tox -e py_func_v4
158158
159159
By default, the tests run against the ``gitlab/gitlab-ce:latest`` image. You can
160160
override both the image and tag with the ``-i`` and ``-t`` options, or by providing

docs/cli.rst

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,10 @@ Configuration
1414
Files
1515
-----
1616

17-
``gitlab`` looks up 2 configuration files by default:
17+
``gitlab`` looks up 3 configuration files by default:
18+
19+
``PYTHON_GITLAB_CFG`` environment variable
20+
An environment variable that contains the path to a configuration file
1821

1922
``/etc/python-gitlab.cfg``
2023
System-wide configuration file

docs/gl_objects/groups.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,13 @@ Update a group::
6161
group.description = 'My awesome group'
6262
group.save()
6363

64+
Set the avatar image for a group::
65+
66+
# the avatar image can be passed as data (content of the file) or as a file
67+
# object opened in binary mode
68+
group.avatar = open('path/to/file.png', 'rb')
69+
group.save()
70+
6471
Remove a group::
6572

6673
gl.groups.delete(group_id)

docs/gl_objects/projects.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -608,6 +608,10 @@ Get a service::
608608
# display its status (enabled/disabled)
609609
print(service.active)
610610

611+
List active project services::
612+
613+
service = project.services.list()
614+
611615
List the code names of available services (doesn't return objects)::
612616

613617
services = project.services.available()

gitlab/base.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,9 @@ def __ne__(self, other):
111111
return self.get_id() != other.get_id()
112112
return super(RESTObject, self) != other
113113

114+
def __dir__(self):
115+
return super(RESTObject, self).__dir__() + list(self.attributes)
116+
114117
def __hash__(self):
115118
if not self.get_id():
116119
return super(RESTObject, self).__hash__()

gitlab/config.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,17 @@
1818
import os
1919
import configparser
2020

21-
_DEFAULT_FILES = ["/etc/python-gitlab.cfg", os.path.expanduser("~/.python-gitlab.cfg")]
21+
22+
def _env_config():
23+
if "PYTHON_GITLAB_CFG" in os.environ:
24+
return [os.environ["PYTHON_GITLAB_CFG"]]
25+
return []
26+
27+
28+
_DEFAULT_FILES = _env_config() + [
29+
"/etc/python-gitlab.cfg",
30+
os.path.expanduser("~/.python-gitlab.cfg"),
31+
]
2232

2333

2434
class ConfigError(Exception):

gitlab/tests/objects/test_projects.py

Lines changed: 126 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,102 @@ def resp_update_remote_mirror(url, request):
161161
return response(200, content, headers, None, 5, request)
162162

163163

164+
@urlmatch(
165+
scheme="http",
166+
netloc="localhost",
167+
path="/api/v4/projects/1/services/pipelines-email",
168+
method="put",
169+
)
170+
def resp_update_service(url, request):
171+
"""Mock for Service update PUT response."""
172+
content = """{
173+
"id": 100152,
174+
"title": "Pipelines emails",
175+
"slug": "pipelines-email",
176+
"created_at": "2019-01-14T08:46:43.637+01:00",
177+
"updated_at": "2019-07-01T14:10:36.156+02:00",
178+
"active": true,
179+
"commit_events": true,
180+
"push_events": true,
181+
"issues_events": true,
182+
"confidential_issues_events": true,
183+
"merge_requests_events": true,
184+
"tag_push_events": true,
185+
"note_events": true,
186+
"confidential_note_events": true,
187+
"pipeline_events": true,
188+
"wiki_page_events": true,
189+
"job_events": true,
190+
"comment_on_event_enabled": true,
191+
"project_id": 1
192+
}"""
193+
content = content.encode("utf-8")
194+
return response(200, content, headers, None, 5, request)
195+
196+
197+
@urlmatch(
198+
scheme="http",
199+
netloc="localhost",
200+
path="/api/v4/projects/1/services/pipelines-email",
201+
method="get",
202+
)
203+
def resp_get_service(url, request):
204+
"""Mock for Service GET response."""
205+
content = """{
206+
"id": 100152,
207+
"title": "Pipelines emails",
208+
"slug": "pipelines-email",
209+
"created_at": "2019-01-14T08:46:43.637+01:00",
210+
"updated_at": "2019-07-01T14:10:36.156+02:00",
211+
"active": true,
212+
"commit_events": true,
213+
"push_events": true,
214+
"issues_events": true,
215+
"confidential_issues_events": true,
216+
"merge_requests_events": true,
217+
"tag_push_events": true,
218+
"note_events": true,
219+
"confidential_note_events": true,
220+
"pipeline_events": true,
221+
"wiki_page_events": true,
222+
"job_events": true,
223+
"comment_on_event_enabled": true,
224+
"project_id": 1
225+
}"""
226+
content = content.encode("utf-8")
227+
return response(200, content, headers, None, 5, request)
228+
229+
230+
@urlmatch(
231+
scheme="http", netloc="localhost", path="/api/v4/projects/1/services", method="get",
232+
)
233+
def resp_get_active_services(url, request):
234+
"""Mock for active Services GET response."""
235+
content = """[{
236+
"id": 100152,
237+
"title": "Pipelines emails",
238+
"slug": "pipelines-email",
239+
"created_at": "2019-01-14T08:46:43.637+01:00",
240+
"updated_at": "2019-07-01T14:10:36.156+02:00",
241+
"active": true,
242+
"commit_events": true,
243+
"push_events": true,
244+
"issues_events": true,
245+
"confidential_issues_events": true,
246+
"merge_requests_events": true,
247+
"tag_push_events": true,
248+
"note_events": true,
249+
"confidential_note_events": true,
250+
"pipeline_events": true,
251+
"wiki_page_events": true,
252+
"job_events": true,
253+
"comment_on_event_enabled": true,
254+
"project_id": 1
255+
}]"""
256+
content = content.encode("utf-8")
257+
return response(200, content, headers, None, 5, request)
258+
259+
164260
class TestProject(unittest.TestCase):
165261
"""Base class for GitLab Project tests."""
166262

@@ -169,7 +265,7 @@ def setUp(self):
169265
"http://localhost",
170266
private_token="private_token",
171267
ssl_verify=True,
172-
api_version=4,
268+
api_version="4",
173269
)
174270
self.project = self.gl.projects.get(1, lazy=True)
175271

@@ -358,6 +454,34 @@ def test_update_project_remote_mirror(self):
358454
self.assertTrue(mirror.only_protected_branches)
359455

360456

457+
class TestProjectServices(TestProject):
458+
@with_httmock(resp_get_active_services)
459+
def test_list_active_services(self):
460+
services = self.project.services.list()
461+
self.assertIsInstance(services, list)
462+
self.assertIsInstance(services[0], ProjectService)
463+
self.assertTrue(services[0].active)
464+
self.assertTrue(services[0].push_events)
465+
466+
def test_list_available_services(self):
467+
services = self.project.services.available()
468+
self.assertIsInstance(services, list)
469+
self.assertIsInstance(services[0], str)
470+
471+
@with_httmock(resp_get_service)
472+
def test_get_service(self):
473+
service = self.project.services.get("pipelines-email")
474+
self.assertIsInstance(service, ProjectService)
475+
self.assertEqual(service.push_events, True)
476+
477+
@with_httmock(resp_get_service, resp_update_service)
478+
def test_update_service(self):
479+
service = self.project.services.get("pipelines-email")
480+
service.issues_events = True
481+
service.save()
482+
self.assertEqual(service.issues_events, True)
483+
484+
361485
class TestProjectPipelineSchedule(TestProject):
362486

363487
def test_project_pipeline_schedule_play(self):
@@ -371,3 +495,4 @@ def test_project_pipeline_schedule_play(self):
371495
print(play_result)
372496
self.assertIsNotNone(play_result)
373497
self.fail('not complete')
498+

gitlab/tests/test_config.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
# You should have received a copy of the GNU Lesser General Public License
1616
# along with this program. If not, see <http://www.gnu.org/licenses/>.
1717

18+
import os
1819
import unittest
1920

2021
import mock
@@ -72,6 +73,16 @@
7273
"""
7374

7475

76+
class TestEnvConfig(unittest.TestCase):
77+
def test_env_present(self):
78+
with mock.patch.dict(os.environ, {"PYTHON_GITLAB_CFG": "/some/path"}):
79+
self.assertEqual(["/some/path"], config._env_config())
80+
81+
def test_env_missing(self):
82+
with mock.patch.dict(os.environ, {}, clear=True):
83+
self.assertEqual([], config._env_config())
84+
85+
7586
class TestConfigParser(unittest.TestCase):
7687
@mock.patch("os.path.exists")
7788
def test_missing_config(self, path_exists):

0 commit comments

Comments
 (0)