From b2e5e3c20207583fcd2fbb7db5f149b0c3e9dd12 Mon Sep 17 00:00:00 2001
From: Christoph Alt <typ@ohnebild.com>
Date: Tue, 4 Oct 2022 18:31:22 +0200
Subject: [PATCH] added support for gitlab api

---
 cbutil/__init__.py       |  1 +
 cbutil/get_job_info.py   |  3 ++-
 cbutil/gitlab_api.py     | 53 ++++++++++++++++++++++++++++++++++++++++
 tests/test_gitlab_api.py | 42 +++++++++++++++++++++++++++++++
 4 files changed, 98 insertions(+), 1 deletion(-)
 create mode 100644 cbutil/gitlab_api.py
 create mode 100644 tests/test_gitlab_api.py

diff --git a/cbutil/__init__.py b/cbutil/__init__.py
index 8d2139f..6bd35ff 100644
--- a/cbutil/__init__.py
+++ b/cbutil/__init__.py
@@ -4,3 +4,4 @@ from .postprocessing import *
 from .util import read_file_line_wise, time_conversion, file_time_to_sec, get_from_nested_dict
 from .data_points import DataPoint, data_point_factory
 from .get_job_info import get_url_from_env, get_job_datapoints
+from .gitlab_api import get_git_infos_from_api
diff --git a/cbutil/get_job_info.py b/cbutil/get_job_info.py
index 1a58d5a..7bb4db3 100644
--- a/cbutil/get_job_info.py
+++ b/cbutil/get_job_info.py
@@ -5,6 +5,7 @@ import dotenv
 import requests
 
 from cbutil.data_points import DataPoint, data_point_factory
+from cbutil.gitlab_api import add_pagination
 
 logger = logging.getLogger(__file__)
 
@@ -35,7 +36,7 @@ def get_job_info(url: str):
         for job in jobs.json():
             yield job
         if (next_page := jobs.headers['x-next-page']):
-            next_url = f"{url}?page={next_page}"
+            next_url = add_pagination(url, next_page)
         else:
             break
 
diff --git a/cbutil/gitlab_api.py b/cbutil/gitlab_api.py
new file mode 100644
index 0000000..1aeab19
--- /dev/null
+++ b/cbutil/gitlab_api.py
@@ -0,0 +1,53 @@
+import requests
+from typing import Union
+import logging
+from cbutil.util import remove_newline
+
+logger = logging.getLogger(__file__)
+
+Project_id = Union[str, int]
+
+
+def url_encode(project_id: Project_id) -> str:
+    if isinstance(project_id, str):
+        return project_id.replace("/", "%2F")
+    else:
+        return project_id
+
+
+def add_pagination(url: str, page, *, per_page=20) -> str:
+    return f"{url}?per_page={per_page}&page={page}"
+
+
+def get_api_url(instance_url: str, project_id: Project_id) -> str:
+    return f"{instance_url}/api/v4/projects/{url_encode(project_id)}"
+
+
+def get_api_url_commits(base_api_url: str) -> str:
+    return f"{base_api_url}/repository/commits"
+
+
+def get_last_commit(instance_url: str, project_id: Project_id, branch: str = ''):
+    url = get_api_url_commits(get_api_url(instance_url, project_id))
+    url = add_pagination(url, page=1, per_page=1)
+    params = {'ref_name': branch if branch else 'master'}
+    commit = requests.get(url, params=params)
+    logger.info(f"requesting {url} with params")
+    if commit.status_code != 200:
+        commit.raise_for_status()
+    return commit.json()[0]
+
+
+def get_commit_infos_from_api(commit: dict) -> dict:
+    return commit['id'], remove_newline(commit['message'])
+
+
+def get_git_infos_from_api(instance_url, project_id: Project_id,
+                           *,
+                           branch='main',
+                           commit_key="commit",
+                           commit_msg_key="commit_message"):
+    last_commit = get_last_commit(instance_url, project_id, branch=branch)
+    commit, commit_msg = get_commit_infos_from_api(last_commit)
+    commit_msg = remove_newline(commit_msg)
+    return {commit_key: commit, commit_msg_key: commit_msg}
diff --git a/tests/test_gitlab_api.py b/tests/test_gitlab_api.py
new file mode 100644
index 0000000..4592870
--- /dev/null
+++ b/tests/test_gitlab_api.py
@@ -0,0 +1,42 @@
+from cbutil.gitlab_api import add_pagination, get_last_commit, get_git_infos_from_api, url_encode
+import os
+import pytest
+
+
+def test_url_encode():
+    assert 'walberla%2Fwalberla' == url_encode('walberla/walberla')
+    assert 'walberla%2Fwalberla' == url_encode('walberla%2Fwalberla')
+    assert 123 == url_encode(123)
+
+
+def test_pagination():
+    base_url = "http://base.url/"
+    assert add_pagination(base_url, 1) == f"{base_url}?per_page=20&page=1"
+    assert add_pagination(base_url, 1, per_page=1) == f"{base_url}?per_page=1&page=1"
+
+
+def get_local_infos(branch_name):
+    with os.popen(f'git rev-parse origin/{branch_name}') as rev:
+        expected = rev.read().strip()
+    return expected
+
+
+@pytest.mark.parametrize("project_id", ['ob28imeq%2Fcb-util', 976])
+def test_get_last_commit(project_id):
+    branch_name = 'main'
+    instance_url = 'https://i10git.cs.fau.de/'
+    expected = get_local_infos(branch_name)
+
+    last_commit = get_last_commit(instance_url, project_id, branch=branch_name)
+    assert last_commit['id'] == expected
+
+
+@pytest.mark.parametrize("project_id", ['ob28imeq%2Fcb-util', 976])
+def test_get_get_git_infos(project_id):
+    branch_name = 'main'
+    instance_url = 'https://i10git.cs.fau.de/'
+    expected = get_local_infos(branch_name)
+
+    git_infos = get_git_infos_from_api(instance_url, project_id)
+
+    assert git_infos['commit'] == expected
-- 
GitLab