From f6bb03457c540464e649c0d41f966436570a701c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20GATELLIER?= <26511053+lgatellier@users.noreply.github.com> Date: Tue, 8 Aug 2023 23:25:55 +0200 Subject: [PATCH 1/3] feat(api): Add support for new runner creation API --- gitlab/v4/objects/users.py | 28 ++++++++++++++++++++++++++++ tests/unit/conftest.py | 24 ++++++++++++++++++++++++ tests/unit/objects/test_users.py | 19 +++++++++++++++++++ 3 files changed, 71 insertions(+) diff --git a/gitlab/v4/objects/users.py b/gitlab/v4/objects/users.py index 7395313c8..e2f10574e 100644 --- a/gitlab/v4/objects/users.py +++ b/gitlab/v4/objects/users.py @@ -36,6 +36,8 @@ "CurrentUserGPGKeyManager", "CurrentUserKey", "CurrentUserKeyManager", + "CurrentUserRunner", + "CurrentUserRunnerManager", "CurrentUserStatus", "CurrentUserStatusManager", "CurrentUser", @@ -111,6 +113,31 @@ def get( return cast(CurrentUserKey, super().get(id=id, lazy=lazy, **kwargs)) +class CurrentUserRunner(RESTObject): + pass + + +class CurrentUserRunnerManager(CreateMixin, RESTManager): + _path = "/user/runners" + _obj_cls = CurrentUserRunner + _types = {"tag_list": types.CommaSeparatedListAttribute} + _create_attrs = RequiredOptional( + required=("runner_type",), + optional=( + "group_id", + "project_id", + "description", + "paused", + "locked", + "run_untagged", + "tag_list", + "access_level", + "maximum_timeout", + "maintenance_note", + ), + ) + + class CurrentUserStatus(SaveMixin, RESTObject): _id_attr = None _repr_attr = "message" @@ -132,6 +159,7 @@ class CurrentUser(RESTObject): emails: CurrentUserEmailManager gpgkeys: CurrentUserGPGKeyManager keys: CurrentUserKeyManager + runners: CurrentUserRunnerManager status: CurrentUserStatusManager diff --git a/tests/unit/conftest.py b/tests/unit/conftest.py index d72637196..bbfd4c230 100644 --- a/tests/unit/conftest.py +++ b/tests/unit/conftest.py @@ -1,4 +1,5 @@ import pytest +import responses import gitlab from tests.unit import helpers @@ -59,6 +60,23 @@ def gl_retry(): ) +@pytest.fixture +def resp_get_current_user(): + with responses.RequestsMock() as rsps: + rsps.add( + method=responses.GET, + url="http://localhost/api/v4/user", + json={ + "id": 1, + "username": "username", + "web_url": "http://localhost/username", + }, + content_type="application/json", + status=200, + ) + yield rsps + + # Todo: parametrize, but check what tests it's really useful for @pytest.fixture def gl_trailing(): @@ -129,6 +147,12 @@ def user(gl): return gl.users.get(1, lazy=True) +@pytest.fixture +def current_user(gl, resp_get_current_user): + gl.auth() + return gl.user + + @pytest.fixture def migration(gl): return gl.bulk_imports.get(1, lazy=True) diff --git a/tests/unit/objects/test_users.py b/tests/unit/objects/test_users.py index 6da68adec..ba82ae6fd 100644 --- a/tests/unit/objects/test_users.py +++ b/tests/unit/objects/test_users.py @@ -241,6 +241,19 @@ def resp_starred_projects(): yield rsps +@pytest.fixture +def resp_runner_create(): + with responses.RequestsMock() as rsps: + rsps.add( + method=responses.POST, + url="http://localhost/api/v4/user/runners", + json={"id": "6", "token": "6337ff461c94fd3fa32ba3b1ff4125"}, + content_type="application/json", + status=200, + ) + yield rsps + + def test_get_user(gl, resp_get_user): user = gl.users.get(1) assert isinstance(user, User) @@ -304,3 +317,9 @@ def test_list_starred_projects(user, resp_starred_projects): projects = user.starred_projects.list() assert isinstance(projects[0], StarredProject) assert projects[0].id == project_content["id"] + + +def test_create_user_runner(current_user, resp_runner_create): + runner = current_user.runners.create({"runner_type": "instance_type"}) + assert runner.id == "6" + assert runner.token == "6337ff461c94fd3fa32ba3b1ff4125" From ad7a58a958420963d792b498b224c470c7194018 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20GATELLIER?= <26511053+lgatellier@users.noreply.github.com> Date: Tue, 8 Aug 2023 23:49:32 +0200 Subject: [PATCH 2/3] docs(users): Add new runner creation examples --- docs/gl_objects/runners.rst | 8 ++++++ docs/gl_objects/users.rst | 57 +++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+) diff --git a/docs/gl_objects/runners.rst b/docs/gl_objects/runners.rst index 10bdba245..bc121b04c 100644 --- a/docs/gl_objects/runners.rst +++ b/docs/gl_objects/runners.rst @@ -71,6 +71,14 @@ Register a new runner:: runner = gl.runners.create({'token': secret_token}) +.. note:: + + A new runner registration workflow has been introduced since GitLab 16.0. This new + workflow comes with a new API endpoint to create runner, which does not use + registration tokens. + + The new endpoint can be called using ``user.runners.create()``. + Update a runner:: runner = gl.runners.get(runner_id) diff --git a/docs/gl_objects/users.rst b/docs/gl_objects/users.rst index 37354e278..a6278d231 100644 --- a/docs/gl_objects/users.rst +++ b/docs/gl_objects/users.rst @@ -456,3 +456,60 @@ Get the users activities:: query_parameters={'from': '2018-07-01'}, get_all=True, ) + +Create new runner +================= + +References +---------- + +* New runner registration API endpoint (see `Migrating to the new runner registration workflow `_) + +* v4 API: + + + :class:`gitlab.v4.objects.CurrentUserRunner` + + :class:`gitlab.v4.objects.CurrentUserRunnerManager` + + :attr:`gitlab.Gitlab.user.runners` + +* GitLab API : https://docs.gitlab.com/ee/api/users.html#create-a-runner + +Examples +-------- + +Create an instance-wide runner:: + + runner = gl.user.runners.create({ + "runner_type": "instance_type", + "description": "My brand new runner", + "paused": True, + "locked": False, + "run_untagged": True + "tag_list": ["linux", "docker", "testing"], + "access_level": "not_protected" + }) + +Create a group runner:: + + runner = gl.user.runners.create({ + "runner_type": "group_type", + "group_id": 12345678, + "description": "My brand new runner", + "paused": True, + "locked": False, + "run_untagged": True + "tag_list": ["linux", "docker", "testing"], + "access_level": "not_protected" + }) + +Create a project runner:: + + runner = gl.user.runners.create({ + "runner_type": "project_type", + "project_id": 987564321, + "description": "My brand new runner", + "paused": True, + "locked": False, + "run_untagged": True + "tag_list": ["linux", "docker", "testing"], + "access_level": "not_protected" + }) \ No newline at end of file From 366894bf70940aa81e168a764ab9f48a835b1caa Mon Sep 17 00:00:00 2001 From: Nejc Habjan Date: Sun, 27 Aug 2023 13:29:35 +0200 Subject: [PATCH 3/3] chore: apply minor review suggestions --- docs/gl_objects/runners.rst | 4 ++-- tests/unit/objects/test_users.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/gl_objects/runners.rst b/docs/gl_objects/runners.rst index bc121b04c..113ce2585 100644 --- a/docs/gl_objects/runners.rst +++ b/docs/gl_objects/runners.rst @@ -74,10 +74,10 @@ Register a new runner:: .. note:: A new runner registration workflow has been introduced since GitLab 16.0. This new - workflow comes with a new API endpoint to create runner, which does not use + workflow comes with a new API endpoint to create runners, which does not use registration tokens. - The new endpoint can be called using ``user.runners.create()``. + The new endpoint can be called using ``gl.user.runners.create() after authenticating with `gl.auth()```. Update a runner:: diff --git a/tests/unit/objects/test_users.py b/tests/unit/objects/test_users.py index ba82ae6fd..0bbcc7637 100644 --- a/tests/unit/objects/test_users.py +++ b/tests/unit/objects/test_users.py @@ -249,7 +249,7 @@ def resp_runner_create(): url="http://localhost/api/v4/user/runners", json={"id": "6", "token": "6337ff461c94fd3fa32ba3b1ff4125"}, content_type="application/json", - status=200, + status=201, ) yield rsps