Skip to content

feat: add group runners api #1089

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 20, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,11 @@ Before submitting a pull request make sure that the tests still succeed with
your change. Unit tests and functional tests run using the travis service and
passing tests are mandatory to get merge requests accepted.

We're currently in a restructing phase for the unit tests. If you're changing existing
tests, feel free to keep the current format. Otherwise please write new tests with pytest and
using `responses<https://github.com/getsentry/responses>`_. An example for new tests can be found in
tests/objects/test_runner.py

You need to install ``tox`` to run unit tests and documentation builds locally:

.. code-block:: bash
Expand Down
5 changes: 4 additions & 1 deletion docs/gl_objects/runners.rst
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ Verify a registered runner token::
except GitlabVerifyError:
print("Invalid token")

Project runners
Project/Group runners
===============

Reference
Expand All @@ -89,6 +89,9 @@ Reference
+ :class:`gitlab.v4.objects.ProjectRunner`
+ :class:`gitlab.v4.objects.ProjectRunnerManager`
+ :attr:`gitlab.v4.objects.Project.runners`
+ :class:`gitlab.v4.objects.GroupRunner`
+ :class:`gitlab.v4.objects.GroupRunnerManager`
+ :attr:`gitlab.v4.objects.Group.runners`

* GitLab API: https://docs.gitlab.com/ce/api/runners.html

Expand Down
12 changes: 12 additions & 0 deletions gitlab/tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import pytest
import gitlab


@pytest.fixture
def gl():
return gitlab.Gitlab(
"http://localhost",
private_token="private_token",
ssl_verify=True,
api_version=4,
)
277 changes: 277 additions & 0 deletions gitlab/tests/objects/test_runners.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,277 @@
import unittest
import responses
import gitlab
import pytest
import re
from .mocks import * # noqa


runner_detail = {
"active": True,
"architecture": "amd64",
"description": "test-1-20150125",
"id": 6,
"ip_address": "127.0.0.1",
"is_shared": False,
"contacted_at": "2016-01-25T16:39:48.066Z",
"name": "test-runner",
"online": True,
"status": "online",
"platform": "linux",
"projects": [
{
"id": 1,
"name": "GitLab Community Edition",
"name_with_namespace": "GitLab.org / GitLab Community Edition",
"path": "gitlab-foss",
"path_with_namespace": "gitlab-org/gitlab-foss",
}
],
"revision": "5nj35",
"tag_list": ["ruby", "mysql"],
"version": "v13.0.0",
"access_level": "ref_protected",
"maximum_timeout": 3600,
}

runner_shortinfo = {
"active": True,
"description": "test-1-20150125",
"id": 6,
"is_shared": False,
"ip_address": "127.0.0.1",
"name": "test-name",
"online": True,
"status": "online",
}

runner_jobs = [
{
"id": 6,
"ip_address": "127.0.0.1",
"status": "running",
"stage": "test",
"name": "test",
"ref": "master",
"tag": False,
"coverage": "99%",
"created_at": "2017-11-16T08:50:29.000Z",
"started_at": "2017-11-16T08:51:29.000Z",
"finished_at": "2017-11-16T08:53:29.000Z",
"duration": 120,
"user": {
"id": 1,
"name": "John Doe2",
"username": "user2",
"state": "active",
"avatar_url": "http://www.gravatar.com/avatar/c922747a93b40d1ea88262bf1aebee62?s=80&d=identicon",
"web_url": "http://localhost/user2",
"created_at": "2017-11-16T18:38:46.000Z",
"bio": None,
"location": None,
"public_email": "",
"skype": "",
"linkedin": "",
"twitter": "",
"website_url": "",
"organization": None,
},
}
]


@pytest.fixture
def resp_get_runners_jobs():
with responses.RequestsMock() as rsps:
rsps.add(
method=responses.GET,
url="http://localhost/api/v4/runners/6/jobs",
json=runner_jobs,
content_type="application/json",
status=200,
)
yield rsps


@pytest.fixture
def resp_get_runners_list():
with responses.RequestsMock() as rsps:
rsps.add(
method=responses.GET,
url=re.compile(r".*?(/runners(/all)?|/(groups|projects)/1/runners)"),
json=[runner_shortinfo],
content_type="application/json",
status=200,
)
yield rsps


@pytest.fixture
def resp_runner_detail():
with responses.RequestsMock() as rsps:
pattern = re.compile(r".*?/runners/6")
rsps.add(
method=responses.GET,
url=pattern,
json=runner_detail,
content_type="application/json",
status=200,
)
rsps.add(
method=responses.PUT,
url=pattern,
json=runner_detail,
content_type="application/json",
status=200,
)
yield rsps


@pytest.fixture
def resp_runner_register():
with responses.RequestsMock() as rsps:
pattern = re.compile(r".*?/runners")
rsps.add(
method=responses.POST,
url=pattern,
json={"id": "6", "token": "6337ff461c94fd3fa32ba3b1ff4125"},
content_type="application/json",
status=200,
)
yield rsps


@pytest.fixture
def resp_runner_enable():
with responses.RequestsMock() as rsps:
pattern = re.compile(r".*?(projects|groups)/1/runners")
rsps.add(
method=responses.POST,
url=pattern,
json=runner_shortinfo,
content_type="application/json",
status=200,
)
yield rsps


@pytest.fixture
def resp_runner_delete():
with responses.RequestsMock() as rsps:
pattern = re.compile(r".*?/runners/6")
rsps.add(
method=responses.GET,
url=pattern,
json=runner_detail,
content_type="application/json",
status=200,
)
rsps.add(
method=responses.DELETE, url=pattern, status=204,
)
yield rsps


@pytest.fixture
def resp_runner_disable():
with responses.RequestsMock() as rsps:
pattern = re.compile(r".*?/(groups|projects)/1/runners/6")
rsps.add(
method=responses.DELETE, url=pattern, status=204,
)
yield rsps


@pytest.fixture
def resp_runner_verify():
with responses.RequestsMock() as rsps:
pattern = re.compile(r".*?/runners/verify")
rsps.add(
method=responses.POST, url=pattern, status=200,
)
yield rsps


def test_owned_runners_list(gl: gitlab.Gitlab, resp_get_runners_list):
runners = gl.runners.list()
assert runners[0].active == True
assert runners[0].id == 6
assert runners[0].name == "test-name"
assert len(runners) == 1


def test_project_runners_list(gl: gitlab.Gitlab, resp_get_runners_list):
runners = gl.projects.get(1, lazy=True).runners.list()
assert runners[0].active == True
assert runners[0].id == 6
assert runners[0].name == "test-name"
assert len(runners) == 1


def test_group_runners_list(gl: gitlab.Gitlab, resp_get_runners_list):
runners = gl.groups.get(1, lazy=True).runners.list()
assert runners[0].active == True
assert runners[0].id == 6
assert runners[0].name == "test-name"
assert len(runners) == 1


def test_all_runners_list(gl: gitlab.Gitlab, resp_get_runners_list):
runners = gl.runners.all()
assert runners[0].active == True
assert runners[0].id == 6
assert runners[0].name == "test-name"
assert len(runners) == 1


def test_create_runner(gl: gitlab.Gitlab, resp_runner_register):
runner = gl.runners.create({"token": "token"})
assert runner.id == "6"
assert runner.token == "6337ff461c94fd3fa32ba3b1ff4125"


def test_get_update_runner(gl: gitlab.Gitlab, resp_runner_detail):
runner = gl.runners.get(6)
assert runner.active == True
runner.tag_list.append("new")
runner.save()


def test_remove_runner(gl: gitlab.Gitlab, resp_runner_delete):
runner = gl.runners.get(6)
runner.delete()
gl.runners.delete(6)


def test_disable_project_runner(gl: gitlab.Gitlab, resp_runner_disable):
gl.projects.get(1, lazy=True).runners.delete(6)


def test_disable_group_runner(gl: gitlab.Gitlab, resp_runner_disable):
gl.groups.get(1, lazy=True).runners.delete(6)


def test_enable_project_runner(gl: gitlab.Gitlab, resp_runner_enable):
runner = gl.projects.get(1, lazy=True).runners.create({"runner_id": 6})
assert runner.active == True
assert runner.id == 6
assert runner.name == "test-name"


def test_enable_group_runner(gl: gitlab.Gitlab, resp_runner_enable):
runner = gl.groups.get(1, lazy=True).runners.create({"runner_id": 6})
assert runner.active == True
assert runner.id == 6
assert runner.name == "test-name"


def test_verify_runner(gl: gitlab.Gitlab, resp_runner_verify):
gl.runners.verify("token")


def test_runner_jobs(gl: gitlab.Gitlab, resp_get_runners_jobs):
jobs = gl.runners.get(6, lazy=True).jobs.list()
assert jobs[0].duration == 120
assert jobs[0].name == "test"
assert jobs[0].user.get("name") == "John Doe2"
assert len(jobs) == 1
15 changes: 14 additions & 1 deletion gitlab/v4/objects.py
Original file line number Diff line number Diff line change
Expand Up @@ -1308,6 +1308,17 @@ class GroupProjectManager(ListMixin, RESTManager):
)


class GroupRunner(ObjectDeleteMixin, RESTObject):
pass


class GroupRunnerManager(NoUpdateMixin, RESTManager):
_path = "/groups/%(group_id)s/runners"
_obj_cls = GroupRunner
_from_parent_attrs = {"group_id": "id"}
_create_attrs = (("runner_id",), tuple())


class GroupSubgroup(RESTObject):
pass

Expand Down Expand Up @@ -1357,6 +1368,7 @@ class Group(SaveMixin, ObjectDeleteMixin, RESTObject):
("milestones", "GroupMilestoneManager"),
("notificationsettings", "GroupNotificationSettingsManager"),
("projects", "GroupProjectManager"),
("runners", "GroupRunnerManager"),
("subgroups", "GroupSubgroupManager"),
("variables", "GroupVariableManager"),
("clusters", "GroupClusterManager"),
Expand Down Expand Up @@ -5382,7 +5394,8 @@ def all(self, scope=None, **kwargs):
query_data = {}
if scope is not None:
query_data["scope"] = scope
return self.gitlab.http_list(path, query_data, **kwargs)
obj = self.gitlab.http_list(path, query_data, **kwargs)
return [self._obj_cls(self, item) for item in obj]

@cli.register_custom_action("RunnerManager", ("token",))
@exc.on_http_error(exc.GitlabVerifyError)
Expand Down
1 change: 1 addition & 0 deletions test-requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ pytest
pytest-cov
sphinx>=1.3
sphinx_rtd_theme
responses